package org.molgenis.questionnaires;
import org.molgenis.data.DataService;
import org.molgenis.data.Entity;
import org.molgenis.data.EntityManager;
import org.molgenis.data.i18n.LanguageService;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.data.meta.model.EntityTypeMetadata;
import org.molgenis.ui.MolgenisPluginController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import static org.molgenis.data.EntityManager.CreationMode.POPULATE;
import static org.molgenis.data.support.QueryImpl.EQ;
import static org.molgenis.questionnaires.QuestionnaireMetaData.ATTR_STATUS;
import static org.molgenis.questionnaires.QuestionnaireStatus.NOT_STARTED;
import static org.molgenis.questionnaires.QuestionnaireStatus.OPEN;
import static org.molgenis.questionnaires.QuestionnaireUtils.findQuestionnairesMetaData;
import static org.molgenis.security.core.runas.RunAsSystemProxy.runAsSystem;
import static org.molgenis.security.core.utils.SecurityUtils.*;
import static org.molgenis.security.owned.OwnedEntityType.OWNER_USERNAME;
@Controller
@RequestMapping(QuestionnairePluginController.URI)
public class QuestionnairePluginController extends MolgenisPluginController
{
public static final String ID = "questionnaires";
public static final String URI = MolgenisPluginController.PLUGIN_URI_PREFIX + ID;
private final DataService dataService;
private final ThankYouTextService thankYouTextService;
private final LanguageService languageService;
private final EntityManager entityManager;
@Autowired
public QuestionnairePluginController(DataService dataService, ThankYouTextService thankYouTextService,
LanguageService languageService, EntityManager entityManager)
{
super(URI);
this.dataService = requireNonNull(dataService);
this.thankYouTextService = requireNonNull(thankYouTextService);
this.languageService = requireNonNull(languageService);
this.entityManager = requireNonNull(entityManager);
}
@RequestMapping(method = RequestMethod.GET)
public String showView(Model model)
{
model.addAttribute("questionnaires", getQuestionnaires());
return "view-my-questionnaires";
}
private List<Questionnaire> getQuestionnaires()
{
List<Questionnaire> questionnaires;
List<Entity> questionnaireMeta = runAsSystem(() -> findQuestionnairesMetaData(dataService).collect(toList()));
questionnaires = questionnaireMeta.stream()
.map(entityType -> entityType.getString(EntityTypeMetadata.FULL_NAME))
.filter(name -> currentUserIsSu() || currentUserHasRole(AUTHORITY_ENTITY_WRITE_PREFIX + name))
.map(name ->
{
// Create entity if not yet exists for current user
EntityType entityType = dataService.getMeta().getEntityType(name);
Entity entity = findQuestionnaireEntity(name);
if (entity == null)
{
entity = createQuestionnaireEntity(entityType, NOT_STARTED, name);
}
return toQuestionnaireModel(entity, entityType);
}).collect(toList());
return questionnaires;
}
@RequestMapping("/{name}")
public String showQuestionnairForm(@PathVariable("name") String name, Model model, HttpServletResponse response)
throws IOException
{
EntityType entityType = dataService.getMeta().getEntityType(name);
if (entityType == null)
{
response.sendError(404);
return null;
}
// Once we showed the questionnaire it's status is 'OPEN'
Entity entity = findQuestionnaireEntity(name);
if (entity == null)
{
entity = createQuestionnaireEntity(entityType, OPEN, name);
}
else if (entity.getString(ATTR_STATUS).equals(NOT_STARTED.toString()))
{
entity.set(ATTR_STATUS, OPEN.toString());
dataService.update(name, entity);
}
model.addAttribute("questionnaire", toQuestionnaireModel(entity, entityType));
return "view-questionnaire";
}
@RequestMapping("/{name}/thanks")
public String showThanks(@PathVariable("name") String name, Model model, HttpServletResponse response)
throws IOException
{
EntityType entityType = dataService.getMeta().getEntityType(name);
if (entityType == null)
{
response.sendError(404);
return null;
}
model.addAttribute("thankYouText", getThankYouText(name));
return "view-thanks";
}
private synchronized Entity createQuestionnaireEntity(EntityType entityType, QuestionnaireStatus status,
String name)
{
Entity entity = findQuestionnaireEntity(name);
if (entity == null)
{
entity = entityManager.create(entityType, POPULATE);
entity.set(OWNER_USERNAME, getCurrentUsername());
entity.set(ATTR_STATUS, status.toString());
dataService.add(entityType.getName(), entity);
}
return entity;
}
private Questionnaire toQuestionnaireModel(Entity entity, EntityType entityType)
{
QuestionnaireStatus status = QuestionnaireStatus.valueOf(entity.getString(ATTR_STATUS));
return new Questionnaire(entityType.getName(),
entityType.getLabel(languageService.getCurrentUserLanguageCode()), status,
entityType.getDescription(languageService.getCurrentUserLanguageCode()), entity.getIdValue());
}
private Entity findQuestionnaireEntity(String name)
{
return dataService.findOne(name, EQ(OWNER_USERNAME, getCurrentUsername()));
}
private String getThankYouText(String questionnaireName)
{
return runAsSystem(() -> thankYouTextService.getThankYouText(questionnaireName));
}
public static class Questionnaire
{
private String name;
private String label;
private QuestionnaireStatus status;
private String description;
private Object id;
Questionnaire(String name, String label, QuestionnaireStatus status, String description, Object id)
{
this.name = name;
this.label = label;
this.status = status;
this.description = description;
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getLabel()
{
return label;
}
public void setLabel(String label)
{
this.label = label;
}
public QuestionnaireStatus getStatus()
{
return status;
}
public void setStatus(QuestionnaireStatus status)
{
this.status = status;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public Object getId()
{
return id;
}
public void setId(Object id)
{
this.id = id;
}
}
}