All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.molgenis.omx.protocolviewer.ProtocolViewerController Maven / Gradle / Ivy

The newest version!
package org.molgenis.omx.protocolviewer;

import static org.molgenis.omx.protocolviewer.ProtocolViewerController.URI;
import static org.springframework.web.bind.annotation.RequestMethod.GET;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;
import javax.mail.MessagingException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.apache.log4j.Logger;
import org.molgenis.catalog.CatalogItem;
import org.molgenis.catalog.UnknownCatalogException;
import org.molgenis.data.MolgenisDataAccessException;
import org.molgenis.data.MolgenisDataException;
import org.molgenis.data.QueryRule;
import org.molgenis.data.QueryRule.Operator;
import org.molgenis.data.elasticsearch.SearchService;
import org.molgenis.data.elasticsearch.util.SearchRequest;
import org.molgenis.data.elasticsearch.util.SearchResult;
import org.molgenis.data.support.QueryImpl;
import org.molgenis.framework.server.MolgenisSettings;
import org.molgenis.framework.ui.MolgenisPluginController;
import org.molgenis.omx.utils.I18nTools;
import org.molgenis.security.core.utils.SecurityUtils;
import org.molgenis.study.StudyDefinition;
import org.molgenis.study.StudyDefinition.Status;
import org.molgenis.study.UnknownStudyDefinitionException;
import org.molgenis.util.ErrorMessageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

@Controller
@RequestMapping(URI)
public class ProtocolViewerController extends MolgenisPluginController
{
	public static final String ID = "protocolviewer";
	public static final String URI = PLUGIN_URI_PREFIX + ID;
	public static final String KEY_ACTION_DOWNLOAD = "plugin.catalogue.action.download";
	public static final String KEY_ACTION_ORDER = "plugin.catalogue.action.order";
	private static final Logger logger = Logger.getLogger(ProtocolViewerController.class);
	private static final boolean DEFAULT_KEY_ACTION_DOWNLOAD = true;
	private static final boolean DEFAULT_KEY_ACTION_ORDER = true;
	private final ProtocolViewerService protocolViewerService;
	private final MolgenisSettings molgenisSettings;
	private final SearchService searchService;

	@Autowired
	public ProtocolViewerController(ProtocolViewerService protocolViewerService, MolgenisSettings molgenisSettings,
			SearchService searchService)
	{
		super(URI);
		if (protocolViewerService == null) throw new IllegalArgumentException("ProtocolViewerService is null");
		if (molgenisSettings == null) throw new IllegalArgumentException("MolgenisSettings is null");
		if (searchService == null) throw new IllegalArgumentException("SearchService is null");
		this.protocolViewerService = protocolViewerService;
		this.molgenisSettings = molgenisSettings;
		this.searchService = searchService;
	}

	@RequestMapping(method = GET)
	public String init(Model model)
	{
		model.addAttribute("catalogs", Lists.newArrayList(protocolViewerService.getCatalogs()));
		model.addAttribute("enableDownloadAction", getEnableDownloadAction());
		model.addAttribute("enableOrderAction", getEnableOrderAction());
		if (!SecurityUtils.currentUserIsAuthenticated())
		{
			model.addAttribute("infoMessage", "You need to sign in to order catalog items");
		}
		return "view-protocolviewer";
	}

	// TODO change to catalogId/selection
	@RequestMapping(value = "/selection/{catalogId}", method = GET)
	@ResponseBody
	public SelectedItemsResponse getSelection(@PathVariable Integer catalogId,
			@RequestParam(required = false) Integer start, @RequestParam(required = false) Integer end,
			@RequestParam(value = "excludes[]", required = false) String[] excludedItems)
			throws UnknownStudyDefinitionException, UnknownCatalogException
	{
		Integer total;
		List selectedFeatureUris;
		if (SecurityUtils.currentUserIsAuthenticated())
		{
			StudyDefinition studyDefinition = protocolViewerService.getStudyDefinitionDraftForCurrentUser(catalogId
					.toString());

			if (studyDefinition != null)
			{
				Iterable catalogItems = studyDefinition.getItems();

				// exclude specific items
				if (excludedItems != null)
				{
					List idList = Lists.transform(Arrays.asList(excludedItems), new Function()
					{
						@Override
						public String apply(String id)
						{
							return id.substring(id.lastIndexOf('/') + 1);
						}
					});

					final Set excludedItemsSet = new HashSet(idList);
					catalogItems = Lists.newArrayList(Iterables.filter(catalogItems, new Predicate()
					{
						@Override
						public boolean apply(CatalogItem catalogItem)
						{
							return !excludedItemsSet.contains(catalogItem.getId());
						}
					}));
				}

				// convert to feature uris
				selectedFeatureUris = Lists.newArrayList(Iterables.transform(catalogItems,
						new Function()
						{
							@Override
							public SelectedItemResponse apply(CatalogItem catalogItem)
							{
								String featureUri = "/api/v1/observablefeature/" + catalogItem.getId();
								List protocolUris = Lists.newArrayList(Iterables.transform(
										catalogItem.getPath(), new Function()
										{
											@Override
											public String apply(String pathElement)
											{
												return "/api/v1/protocol/" + pathElement;
											}

										}));

								return new SelectedItemResponse(featureUri, protocolUris);
							}
						}));

				if (start != null && end != null)
				{
					end = Math.min(selectedFeatureUris.size(), end);
					total = selectedFeatureUris.size();
					selectedFeatureUris = selectedFeatureUris.subList(start, end);
				}
				else
				{
					start = 0;
					end = selectedFeatureUris.size();
					total = selectedFeatureUris.size();
				}
			}
			else
			{
				start = 0;
				end = 0;
				total = 0;
				selectedFeatureUris = Collections.emptyList();
			}
		}
		else
		{
			start = 0;
			end = 0;
			total = 0;
			selectedFeatureUris = Collections.emptyList();
		}
		return new SelectedItemsResponse(start, end, total, selectedFeatureUris);
	}

	@RequestMapping(value = "/download/{catalogId}", method = GET)
	public void downloadSelection(HttpServletResponse response, @PathVariable Integer catalogId) throws IOException,
			UnknownCatalogException
	{
		if (!getEnableDownloadAction()) throw new MolgenisDataAccessException("Action not allowed");
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH.mm");
		String fileName = "variables_" + dateFormat.format(new Date()) + ".xls";

		// write response headers
		response.setContentType("application/vnd.ms-excel");
		response.setHeader("Content-Disposition", "attachment; filename=" + fileName);

		protocolViewerService.createStudyDefinitionDraftXlsForCurrentUser(response.getOutputStream(),
				catalogId.toString());
	}

	@RequestMapping(value = "/cart/add/{catalogId}", method = RequestMethod.POST)
	@ResponseStatus(HttpStatus.OK)
	public void addToCart(@Valid @RequestBody CartUpdateRequest cartUpdateRequest, @PathVariable Integer catalogId)
			throws UnknownCatalogException, UnknownStudyDefinitionException
	{
		if (!getEnableOrderAction()) throw new MolgenisDataAccessException("Action not allowed");
		for (String item : cartUpdateRequest.getHref())
		{
			protocolViewerService.addToStudyDefinitionDraftForCurrentUser(item, catalogId.toString());
		}
	}

	@RequestMapping(value = "/cart/remove/{catalogId}", method = RequestMethod.POST)
	@ResponseStatus(HttpStatus.OK)
	public void removeFromCart(@Valid @RequestBody CartUpdateRequest cartUpdateRequest, @PathVariable Integer catalogId)
			throws UnknownCatalogException, UnknownStudyDefinitionException
	{
		if (!getEnableOrderAction()) throw new MolgenisDataAccessException("Action not allowed");
		logger.debug("remove from cart: " + cartUpdateRequest.getHref());
		for (String item : cartUpdateRequest.getHref())
		{
			protocolViewerService.removeFromStudyDefinitionDraftForCurrentUser(item, catalogId.toString());

		}
	}

	@RequestMapping(value = "/order", method = RequestMethod.GET)
	public String getOrderDataForm()
	{
		if (!getEnableOrderAction()) throw new MolgenisDataAccessException("Action not allowed");
		return "orderdata-modal";
	}

	// Spring's StandardServletMultipartResolver can't bind a RequestBody or
	// ModelAttribute
	@RequestMapping(value = "/order", method = RequestMethod.POST, headers = "Content-Type=multipart/form-data")
	@ResponseStatus(HttpStatus.NO_CONTENT)
	public void orderData(@RequestParam Integer catalogId, @RequestParam String name, @RequestParam Part file)
			throws IOException, MessagingException, UnknownCatalogException, UnknownStudyDefinitionException
	{
		if (!getEnableOrderAction()) throw new MolgenisDataAccessException("Action not allowed");
		protocolViewerService.submitStudyDefinitionDraftForCurrentUser(name, file, catalogId.toString());
	}

	@RequestMapping(value = "/orders", method = RequestMethod.GET)
	@ResponseBody
	public StudyDefinitionsResponse getOrders()
	{
		if (!getEnableOrderAction()) throw new MolgenisDataAccessException("Action not allowed");

		Iterable ordersIterable = Iterables.transform(
				protocolViewerService.getStudyDefinitionsForCurrentUser(),
				new Function()
				{
					@Override
					@Nullable
					public StudyDefinitionResponse apply(@Nullable StudyDefinition studyDefinition)
					{
						return studyDefinition != null ? (studyDefinition.getStatus() != Status.DRAFT ? new StudyDefinitionResponse(
								studyDefinition) : null) : null;
					}
				});

		return new StudyDefinitionsResponse(Lists.newArrayList(ordersIterable));
	}

	@RequestMapping(value = "/orders/view", method = RequestMethod.GET)
	public String getOrdersForm()
	{
		if (!getEnableOrderAction()) throw new MolgenisDataAccessException("Action not allowed");
		return "orderlist-modal";
	}

	@RequestMapping(value = "/orders/{orderId}/view", method = RequestMethod.GET)
	public ModelAndView getOrderDetailsForm(@Valid @NotNull @PathVariable Integer orderId)
			throws UnknownStudyDefinitionException
	{
		if (!getEnableOrderAction()) throw new MolgenisDataAccessException("Action not allowed");
		StudyDefinition studyDefinition = protocolViewerService.getStudyDefinitionForCurrentUser(orderId);
		if (studyDefinition == null) throw new MolgenisDataException("invalid order id");

		ModelAndView model = new ModelAndView("orderdetails-modal");
		model.addObject("order", studyDefinition);
		model.addObject("i18n", new I18nTools());
		return model;
	}

	@ExceptionHandler(
	{ UnknownCatalogException.class, UnknownStudyDefinitionException.class, IOException.class,
			MessagingException.class, RuntimeException.class })
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ResponseBody
	public ErrorMessageResponse handleException(Exception e)
	{
		e.printStackTrace();
		logger.error("Error", e);
		return new ErrorMessageResponse(
				Collections.singletonList(new ErrorMessageResponse.ErrorMessage(e.getMessage())));
	}

	@RequestMapping(value = "/items", method = RequestMethod.POST)
	@ResponseBody
	public SearchResult getItemsFromIndex(@RequestBody Map request)
	{
		Object catalogId = request.get("catalogId");
		Object draftItems = request.get("items");
		if (catalogId == null) return new SearchResult("The catalogID cannot be null");
		if (draftItems == null) return new SearchResult("The selected items cannot be null");
		List rules = new ArrayList();
		if (draftItems instanceof List)
		{
			for (Object item : (List) draftItems)
			{
				if (rules.size() > 0) rules.add(new QueryRule(Operator.OR));
				rules.add(new QueryRule("id", Operator.EQUALS, item.toString()));
			}
		}
		return searchService.search(new SearchRequest("protocolTree-" + catalogId.toString(), new QueryImpl(rules)
				.pageSize(Integer.MAX_VALUE), null));
	}

	@RequestMapping(value = "/search", method = RequestMethod.POST)
	@ResponseBody
	public SearchResult searchItems(@RequestBody Map request)
	{
		Object catalogId = request.get("catalogId");
		Object queryString = request.get("queryString");
		if (catalogId == null) return new SearchResult("The catalogID cannot be null");
		if (queryString == null) return new SearchResult("The queryString items cannot be null");
		List rules = new ArrayList();
		for (String term : queryString.toString().split("\\s*"))
		{
			if (rules.size() > 0) rules.add(new QueryRule(Operator.AND));
			rules.add(new QueryRule(Operator.SEARCH, term));
		}
		return searchService.search(new SearchRequest("protocolTree-" + catalogId.toString(), new QueryImpl(rules)
				.pageSize(Integer.MAX_VALUE), null));
	}

	private boolean getEnableDownloadAction()
	{
		return molgenisSettings.getBooleanProperty(KEY_ACTION_DOWNLOAD, DEFAULT_KEY_ACTION_DOWNLOAD);
	}

	private boolean getEnableOrderAction()
	{
		return molgenisSettings.getBooleanProperty(KEY_ACTION_ORDER, DEFAULT_KEY_ACTION_ORDER);
	}

	private static class StudyDefinitionsResponse
	{
		private final List orders;

		public StudyDefinitionsResponse(List orders)
		{
			this.orders = orders;
		}

		@SuppressWarnings("unused")
		public List getOrders()
		{
			return orders;
		}
	}

	private static class StudyDefinitionResponse
	{
		private final Integer id;
		private final String name;
		private String orderDate;
		private final String orderStatus;

		public StudyDefinitionResponse(StudyDefinition studyDefinition)
		{
			this.id = Integer.valueOf(studyDefinition.getId());
			this.name = studyDefinition.getName();
			if (studyDefinition.getDateCreated() != null)
			{
				this.orderDate = new SimpleDateFormat("yyyy-MM-dd").format(studyDefinition.getDateCreated());
			}
			this.orderStatus = studyDefinition.getStatus().toString().toLowerCase();
		}

		@SuppressWarnings("unused")
		public Integer getId()
		{
			return id;
		}

		@SuppressWarnings("unused")
		public String getName()
		{
			return name;
		}

		@SuppressWarnings("unused")
		public String getOrderDate()
		{
			return orderDate;
		}

		@SuppressWarnings("unused")
		public String getOrderStatus()
		{
			return orderStatus;
		}
	}

	private static class SelectedItemsResponse
	{
		private final Integer start;
		private final Integer end;
		private final Integer total;
		private final List items;

		public SelectedItemsResponse(Integer start, Integer end, Integer total, List items)
		{
			this.start = start;
			this.end = end;
			this.total = total;
			this.items = items;
		}

		@SuppressWarnings("unused")
		public Integer getStart()
		{
			return start;
		}

		@SuppressWarnings("unused")
		public Integer getEnd()
		{
			return end;
		}

		@SuppressWarnings("unused")
		public Integer getTotal()
		{
			return total;
		}

		@SuppressWarnings("unused")
		public List getItems()
		{
			return items;
		}
	}

	private static class SelectedItemResponse
	{
		private final String feature;
		private final List path;

		public SelectedItemResponse(String feature, List path)
		{
			this.feature = feature;
			this.path = path;
		}

		@SuppressWarnings("unused")
		public String getFeature()
		{
			return feature;
		}

		@SuppressWarnings("unused")
		public List getPath()
		{
			return path;
		}
	}

	private static final class CartUpdateRequest
	{
		@NotNull
		private List features;

		public List getHref()
		{
			return features;
		}

		@SuppressWarnings("unused")
		public void setHref(List features)
		{
			this.features = features;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy