SurveySessionController.java
/*
* Copyright (C) 2000 - 2024 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "http://www.silverpeas.org/legal/licensing"
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.silverpeas.components.survey.control;
import org.apache.commons.fileupload.FileItem;
import org.silverpeas.components.survey.SurveyException;
import org.silverpeas.components.survey.notification.SurveyUserNotification;
import org.silverpeas.core.ResourceReference;
import org.silverpeas.kernel.SilverpeasException;
import org.silverpeas.core.admin.component.model.ComponentInstLight;
import org.silverpeas.core.admin.service.OrganizationController;
import org.silverpeas.core.admin.user.model.SilverpeasRole;
import org.silverpeas.core.admin.user.model.UserDetail;
import org.silverpeas.core.clipboard.ClipboardException;
import org.silverpeas.core.clipboard.ClipboardSelection;
import org.silverpeas.core.contribution.attachment.AttachmentServiceProvider;
import org.silverpeas.core.contribution.attachment.model.SimpleAttachment;
import org.silverpeas.core.contribution.attachment.model.SimpleDocument;
import org.silverpeas.core.contribution.attachment.model.SimpleDocumentPK;
import org.silverpeas.core.exception.DecodingException;
import org.silverpeas.core.i18n.I18NHelper;
import org.silverpeas.core.notification.user.builder.helper.UserNotificationHelper;
import org.silverpeas.core.pdc.pdc.model.PdcClassification;
import org.silverpeas.core.pdc.pdc.model.PdcException;
import org.silverpeas.core.pdc.pdc.model.PdcPosition;
import org.silverpeas.core.pdc.pdc.service.PdcManager;
import org.silverpeas.core.questioncontainer.answer.model.Answer;
import org.silverpeas.core.questioncontainer.answer.model.AnswerPK;
import org.silverpeas.core.questioncontainer.container.model.QuestionContainerDetail;
import org.silverpeas.core.questioncontainer.container.model.QuestionContainerHeader;
import org.silverpeas.core.questioncontainer.container.model.QuestionContainerPK;
import org.silverpeas.core.questioncontainer.container.model.QuestionContainerSelection;
import org.silverpeas.core.questioncontainer.container.service.QuestionContainerService;
import org.silverpeas.core.questioncontainer.question.model.Question;
import org.silverpeas.core.questioncontainer.question.model.QuestionPK;
import org.silverpeas.core.questioncontainer.result.model.QuestionResult;
import org.silverpeas.core.questioncontainer.result.model.Results;
import org.silverpeas.core.questioncontainer.result.service.QuestionResultService;
import org.silverpeas.core.util.DateUtil;
import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.core.util.csv.CSVRow;
import org.silverpeas.core.util.file.FileRepositoryManager;
import org.silverpeas.core.util.file.FileServerUtils;
import org.silverpeas.core.util.file.FileUploadUtil;
import org.silverpeas.core.util.file.FileUtil;
import org.silverpeas.kernel.logging.SilverLogger;
import org.silverpeas.core.web.export.ExportCSVBuilder;
import org.silverpeas.core.web.http.HttpRequest;
import org.silverpeas.core.web.mvc.controller.AbstractComponentSessionController;
import org.silverpeas.core.web.mvc.controller.ComponentContext;
import org.silverpeas.core.web.mvc.controller.MainSessionController;
import org.silverpeas.core.webapi.pdc.PdcClassificationEntity;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import static org.silverpeas.components.survey.control.DisplayResultView.*;
import static org.silverpeas.core.pdc.pdc.model.PdcClassification.aPdcClassificationOfContent;
/**
* This class contains business layer of survey component
*/
public class SurveySessionController extends AbstractComponentSessionController {
private static final long serialVersionUID = -8522567628476990017L;
private static final String IMAGES_SUB_DIRECTORY_KEY = "imagesSubDirectory";
private static final String ACTION_PARAM = "Action";
private static final String SEND_NEW_QUESTION_ACTION = "SendNewQuestion";
private static final String SEND_UPDATE_QUESTION_ACTION = "SendUpdateQuestion";
private transient QuestionContainerService questionContainerService;
private transient QuestionResultService questionResultService;
private QuestionContainerDetail sessionSurveyUnderConstruction = null;
private QuestionContainerDetail sessionSurvey = null;
private List<Question> sessionQuestions = null;
private Map<String, List<String>> sessionResponses = null;
private String sessionSurveyId = null;
private String sessionSurveyName = null;
public static final int OPENED_SURVEYS_VIEW = 1;
public static final int CLOSED_SURVEYS_VIEW = 2;
public static final int INWAIT_SURVEYS_VIEW = 3;
private int viewType = OPENED_SURVEYS_VIEW;
public static final String DISPLAY_COMMENTS_FOR_NOBODY = "0";
public static final String DISPLAY_COMMENTS_FOR_MANAGERS = "1";
public static final String DISPLAY_COMMENTS_FOR_ALL = "2";
public static final String PARAM_DISPLAY_COMMENTS = "displayComments";
private boolean pollingStationMode = false;
private boolean participationMultipleAllowedForUser = false;
private boolean hasAlreadyParticipated = false;
public static final String COOKIE_NAME = "surpoll";
private List<PdcPosition> newSurveyPositions = null;
private DisplayResultView displayResultView = DisplayResultView.fromString(null);
/**
* Creates new sessionClientController
*
* @param mainSessionCtrl
* @param componentContext
*/
public SurveySessionController(MainSessionController mainSessionCtrl,
ComponentContext componentContext) {
super(mainSessionCtrl, componentContext, "org.silverpeas.survey.multilang.surveyBundle", null,
"org.silverpeas.survey.surveySettings");
questionContainerService = QuestionContainerService.get();
questionResultService = QuestionResultService.get();
}
public QuestionContainerService getQuestionContainerService() {
if (questionContainerService == null) {
questionContainerService = QuestionContainerService.get();
}
return questionContainerService;
}
public QuestionResultService getQuestionResultService() {
if (questionResultService == null) {
questionResultService = QuestionResultService.get();
}
return questionResultService;
}
public boolean isPdcUsed() {
return "yes".equalsIgnoreCase(getComponentParameterValue("usePdc"));
}
/**
* Return if user can participate more than one time
*
* @return true or false
*/
public boolean isParticipationMultipleAllowedForUser() {
return participationMultipleAllowedForUser;
}
/**
* Set user status to know if he can participate more than one time
*
* @param state
*/
public void setParticipationMultipleAllowedForUser(boolean state) {
this.participationMultipleAllowedForUser = state;
}
/**
* Get display comments Mode
*
* @return
*/
public String getDisplayCommentsMode() {
String parameterValue = this.getComponentParameterValue(PARAM_DISPLAY_COMMENTS);
if (parameterValue == null || parameterValue.length() <= 0) {
return DISPLAY_COMMENTS_FOR_ALL;
}
return parameterValue;
}
/**
* Return if participationMultiple is used
*
* @return true or false
*/
public boolean isParticipationMultipleUsed() {
boolean participationMultipleUsed = false;
List<String> userMultipleRole = new ArrayList<>();
userMultipleRole.add("userMultiple");
// if we have people on userMultiple role, multiple participation is used
if (getOrganisationController()
.getUsersIdsByRoleNames(getComponentId(), userMultipleRole).length > 0) {
participationMultipleUsed = true;
}
return participationMultipleUsed;
}
/**
* @return if anonymous mode is authorized
*/
public boolean isAnonymousModeAuthorized() {
return isAnonymousModeEnabled() && userIsAnonymous();
}
/**
* @return if anonymous mode is enabled
*/
public boolean isAnonymousModeEnabled() {
String value = getComponentParameterValue("useAnonymousMode");
return value != null && "yes".equalsIgnoreCase(value);
}
/**
* @return if anonymous user has already participated with this ip
*/
public boolean hasAlreadyParticipated() {
return hasAlreadyParticipated;
}
/**
* Set status of anonymous user (if he has already participated with this ip)
*
* @param state
*/
public void hasAlreadyParticipated(boolean state) {
this.hasAlreadyParticipated = state;
}
/**
* Return if currentUser is anonymous
*
* @return true or false
*/
private boolean userIsAnonymous() {
boolean userIsAnonymous = false;
UserDetail user = getUserDetail();
if (user.isAnonymous() && (getComponentId() != null &&
getOrganisationController().isComponentAvailableToUser(getComponentId(), user.getId()))) {
userIsAnonymous = true;
}
return userIsAnonymous;
}
public void setViewType(int viewType) {
this.viewType = viewType;
}
public int getViewType() {
return viewType;
}
/**
* @return a list of survey of the current instance of component.
* @throws SurveyException
*/
public Collection<QuestionContainerHeader> getSurveys() throws SurveyException {
if (getViewType() == OPENED_SURVEYS_VIEW) {
return getOpenedSurveys();
}
if (getViewType() == CLOSED_SURVEYS_VIEW) {
return getClosedSurveys();
}
if (getViewType() == INWAIT_SURVEYS_VIEW) {
return getInWaitSurveys();
}
return Collections.emptyList();
}
public Collection<QuestionContainerHeader> getOpenedSurveys() throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(null, getSpaceId(), getComponentId());
return getQuestionContainerService().getOpenedQuestionContainers(qcPK);
} catch (Exception e) {
throw new SurveyException("No Opened surveys", e);
}
}
public Collection<QuestionContainerHeader> getClosedSurveys() throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(null, getSpaceId(), getComponentId());
return getQuestionContainerService().getClosedQuestionContainers(qcPK);
} catch (Exception e) {
throw new SurveyException("No closed surveys", e);
}
}
public Collection<QuestionContainerHeader> getInWaitSurveys() throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(null, getSpaceId(), getComponentId());
return getQuestionContainerService().getInWaitQuestionContainers(qcPK);
} catch (Exception e) {
throw new SurveyException("No in-waiting surveys", e);
}
}
/**
* @param surveyId the survey identifier
* @return the question container detail of the survey given in parameter
* @throws SurveyException
*/
public QuestionContainerDetail getSurvey(String surveyId) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
return getQuestionContainerService().getQuestionContainer(qcPK, getUserId());
} catch (Exception e) {
throw new SurveyException("No survey " + surveyId, e);
}
}
public QuestionContainerPK createSurvey(QuestionContainerDetail surveyDetail)
throws SurveyException {
QuestionContainerPK qcPK = new QuestionContainerPK(null, getSpaceId(), getComponentId());
try {
qcPK = getQuestionContainerService().createQuestionContainer(qcPK, surveyDetail, getUserId());
} catch (Exception e) {
throw new SurveyException(
"Cannot create survey with title " + surveyDetail.getHeader().getTitle(), e);
}
// Classify content if needed
classifyContent(surveyDetail, qcPK);
return qcPK;
}
/**
* this method clasify content only when new survey is created Check if a position has been
* defined in header form then persist it
*
* @param surveyDetail the current QuestionContainerDetail
* @param qcPK the QuestionContainerPK with content identifier
*/
private void classifyContent(QuestionContainerDetail surveyDetail, QuestionContainerPK qcPK) {
List<PdcPosition> positions = this.getNewSurveyPositions();
if (positions != null && !positions.isEmpty()) {
PdcClassification classification =
aPdcClassificationOfContent(qcPK.getId(), qcPK.getInstanceId())
.withPositions(this.getNewSurveyPositions());
classification.classifyContent(surveyDetail);
}
}
public QuestionContainerPK createSurvey(QuestionContainerDetail surveyDetail, String componentId)
throws SurveyException {
QuestionContainerPK qcPK = new QuestionContainerPK(null, null, componentId);
try {
qcPK = getQuestionContainerService().createQuestionContainer(qcPK, surveyDetail, getUserId());
} catch (Exception e) {
throw new SurveyException(
"Cannot create survey with title " + surveyDetail.getHeader().getTitle(), e);
}
return qcPK;
}
public void updateSurveyHeader(QuestionContainerHeader surveyHeader, String surveyId)
throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
surveyHeader.setPK(qcPK);
getQuestionContainerService().updateQuestionContainerHeader(surveyHeader);
} catch (Exception e) {
throw new SurveyException(
"Cannot update survey of id " + surveyId + " and title " + surveyHeader.getTitle(), e);
}
}
public void updateQuestions(Collection<Question> questions, String surveyId)
throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService().updateQuestions(qcPK, questions);
} catch (Exception e) {
throw new SurveyException("Cannot update the questions of the suvery " + surveyId, e);
}
}
public void deleteSurvey(String surveyId) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService().deleteQuestionContainer(qcPK);
} catch (Exception e) {
throw new SurveyException("Cannot delete survey " + surveyId, e);
}
}
public void deleteVotes(String surveyId) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService().deleteVotes(qcPK);
} catch (Exception e) {
throw new SurveyException("Cannot delete votes of the survey " + surveyId, e);
}
}
public void deleteResponse(String surveyId) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService().deleteQuestionContainer(qcPK);
} catch (Exception e) {
throw new SurveyException("Cannot delete the responses of the survey " + surveyId, e);
}
}
public Collection<String> getUserByQuestion(ResourceReference questionPK) {
Collection<String> users = new ArrayList<>();
Collection<QuestionResult> results =
getQuestionResultService().getQuestionResultToQuestion(questionPK);
for (final QuestionResult result : results) {
if (result != null) {
users.add(result.getUserId() + "/" + result.getParticipationId());
}
}
return users;
}
public Collection<String> getResultByUser(String userId) {
Collection<QuestionResult> result = new ArrayList<>();
Collection<String> resultId = new ArrayList<>();
QuestionContainerDetail survey = getSessionSurvey();
Collection<Question> questions = survey.getQuestions();
for (final Question question : questions) {
Collection<QuestionResult> questionResult =
getQuestionResultService().getUserQuestionResultsToQuestion(userId,
new ResourceReference(question.getPK()));
result.addAll(questionResult);
}
// Only retrieve response identifiers
for (final QuestionResult question : result) {
resultId.add(question.getAnswerPK().getId());
}
return resultId;
}
public Results getResults() {
QuestionContainerDetail survey = getSessionSurvey();
Collection<Question> questions = survey.getQuestions();
List<ResourceReference> pks = new ArrayList<>();
for (Question question : questions) {
pks.add(new ResourceReference(question.getPK()));
}
return getQuestionResultService().getResultsOfQuestions(pks);
}
public Collection<String> getUserByAnswer(String answerId) {
return getQuestionResultService().getUsersByAnswer(answerId);
}
public void closeSurvey(String surveyId) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService().closeQuestionContainer(qcPK);
} catch (Exception e) {
throw new SurveyException("Cannot close the survey " + surveyId, e);
}
}
public void openSurvey(String surveyId) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService().openQuestionContainer(qcPK);
} catch (Exception e) {
throw new SurveyException("Cannot open the survey " + surveyId, e);
}
}
public void recordReply(String surveyId, Map<String, List<String>> reply) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService().recordReplyToQuestionContainerByUser(qcPK, getUserId(), reply);
} catch (Exception e) {
throw new SurveyException("Cannot record a reply for the survey " + surveyId, e);
}
}
public void recordReply(String surveyId, Map<String, List<String>> reply, String comment,
boolean isAnonymousComment) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
getQuestionContainerService()
.recordReplyToQuestionContainerByUser(qcPK, getUserId(), reply, comment,
isAnonymousComment);
} catch (Exception e) {
throw new SurveyException("Cannot record a reply for the survey " + surveyId, e);
}
}
public Collection<QuestionResult> getSuggestions(String surveyId) throws SurveyException {
try {
QuestionContainerPK qcPK = new QuestionContainerPK(surveyId, getSpaceId(), getComponentId());
return getQuestionContainerService().getSuggestions(qcPK);
} catch (Exception e) {
throw new SurveyException("Cannot get the suggestions for the survey " + surveyId, e);
}
}
public Collection<String> getUsersByAnswer(String answerId) {
return getUserByAnswer(answerId);
}
public Collection<String> getUsersBySurvey(String surveyId) throws SurveyException {
Collection<String> users = new LinkedHashSet<>();
QuestionContainerDetail survey = getSurvey(surveyId);
Collection<Question> questions = survey.getQuestions();
for (Question question : questions) {
ResourceReference questionPK = new ResourceReference(question.getPK());
users.addAll(getUniqueParticipantIdsByQuestion(questionPK));
}
return users;
}
private Collection<String> getUniqueParticipantIdsByQuestion(ResourceReference questionPK) {
Collection<String> users = new LinkedHashSet<>();
Collection<QuestionResult> results =
getQuestionResultService().getQuestionResultToQuestion(questionPK);
for (final QuestionResult result : results) {
if (result != null) {
users.add(result.getUserId());
}
}
return users;
}
@Override
public UserDetail getUserDetail(String userId) {
return getOrganisationController().getUserDetail(userId);
}
public int getSilverObjectId(String objectId) {
int silverObjectId = -1;
try {
QuestionContainerPK qcPK = new QuestionContainerPK(objectId, getSpaceId(), getComponentId());
silverObjectId = getQuestionContainerService().getSilverObjectId(qcPK);
} catch (Exception e) {
SilverLogger.getLogger(this).error(e.getMessage(), e);
}
return silverObjectId;
}
public QuestionContainerDetail getSessionSurveyUnderConstruction() {
return this.sessionSurveyUnderConstruction;
}
public void setSessionSurveyUnderConstruction(QuestionContainerDetail surveyUnderConstruction) {
this.sessionSurveyUnderConstruction = surveyUnderConstruction;
}
public void removeSessionSurveyUnderConstruction() {
setSessionSurveyUnderConstruction(null);
setNewSurveyPositions(null);
}
public QuestionContainerDetail getSessionSurvey() {
return this.sessionSurvey;
}
public void setSessionSurvey(QuestionContainerDetail survey) {
this.sessionSurvey = survey;
}
public void removeSessionSurvey() {
setSessionSurvey(null);
}
public List<Question> getSessionQuestions() {
return this.sessionQuestions;
}
public void setSessionQuestions(List<Question> questions) {
this.sessionQuestions = questions;
}
public void removeSessionQuestions() {
setSessionQuestions(null);
}
public Map<String, List<String>> getSessionResponses() {
return this.sessionResponses;
}
public void setSessionResponses(Map<String, List<String>> responses) {
this.sessionResponses = responses;
}
public void removeSessionResponses() {
setSessionResponses(null);
}
public String getSessionSurveyId() {
return this.sessionSurveyId;
}
public void setSessionSurveyId(String surveyId) {
this.sessionSurveyId = surveyId;
}
public void removeSessionSurveyId() {
setSessionSurveyId(null);
}
public String getSessionSurveyName() {
return this.sessionSurveyName;
}
public void setSessionSurveyName(String surveyName) {
this.sessionSurveyName = surveyName;
}
public void removeSessionSurveyName() {
setSessionSurveyName(null);
}
private void setNewSurveyPositions(List<PdcPosition> positions) {
this.newSurveyPositions = positions;
}
/**
* @return the newSurveyPositions
*/
private List<PdcPosition> getNewSurveyPositions() {
return newSurveyPositions;
}
public boolean isPollingStationMode() {
return pollingStationMode;
}
public void setPollingStationMode(boolean pollingStationMode) {
this.pollingStationMode = pollingStationMode;
}
/**
* @return a list of component instance light of the silverpeas gallery
*/
public List<ComponentInstLight> getGalleries() {
return OrganizationController.get().getComponentsWithParameterValue("viewInWysiwyg", "yes");
}
public ExportCSVBuilder exportSurveyCSV(String surveyId) {
ExportCSVBuilder csvBuilder = new ExportCSVBuilder();
try {
QuestionContainerDetail survey = getSurvey(surveyId);
List<CSVRow> rows = getQuestionContainerService().exportCSV(survey, false);
csvBuilder.addLines(rows);
} catch (Exception e) {
SilverLogger.getLogger(this).error("CSV export of survey " + surveyId + " failed", e);
}
return csvBuilder;
}
public void copySurvey(String surveyId) throws SilverpeasException {
try {
QuestionContainerDetail survey = getSurvey(surveyId);
QuestionContainerSelection questionContainerSelect = new QuestionContainerSelection(survey);
addClipboardSelection(questionContainerSelect);
} catch (ClipboardException | SurveyException e) {
throw new SilverpeasException(e);
}
}
public boolean isPasteEnabled() throws SilverpeasException {
try {
Collection<ClipboardSelection> clipObjects = getClipboardSelectedObjects();
for (ClipboardSelection clipObject : clipObjects) {
if (clipObject != null && clipObject.isDataFlavorSupported(
QuestionContainerSelection.QuestionContainerDetailFlavor)) {
return true;
}
}
} catch (Exception e) {
throw new SilverpeasException(e.getMessage(), e);
}
return false;
}
/**
* Paste surveys which are in the clipboard selection
*
* @throws Exception
*/
public void paste() throws SilverpeasException {
try {
Collection<ClipboardSelection> clipObjects = getClipboardSelectedObjects();
for (ClipboardSelection clipObject : clipObjects) {
if (clipObject != null && clipObject.isDataFlavorSupported(
QuestionContainerSelection.QuestionContainerDetailFlavor)) {
QuestionContainerDetail survey = (QuestionContainerDetail) clipObject.getTransferData(
QuestionContainerSelection.QuestionContainerDetailFlavor);
pasteSurvey(survey);
}
}
clipboardPasteDone();
} catch (Exception e) {
throw new SilverpeasException(e.getMessage(), e);
}
}
/**
* Paste a survey
*
* @param survey the QuestionContanerDetail to paste
* @throws Exception
*/
private void pasteSurvey(QuestionContainerDetail survey)
throws IOException, SurveyException, PdcException {
String componentId;
QuestionContainerPK surveyPk = survey.getHeader().getPK();
if (survey.getHeader().getInstanceId().equals(getComponentId())) {
// in the same component
componentId = survey.getHeader().getInstanceId();
} else {
componentId = getComponentId();
}
Collection<Question> questions = survey.getQuestions();
for (final Question question : questions) {
Collection<Answer> answers = question.getAnswers();
Iterator<Answer> itA = answers.iterator();
int attachmentSuffix = 0;
while (itA.hasNext()) {
Answer answer = itA.next();
String physicalName = answer.getImage();
if (StringUtil.isDefined(physicalName)) {
// copy image
String type =
physicalName.substring(physicalName.indexOf('.') + 1, physicalName.length());
String newPhysicalName =
Long.toString(new Date().getTime()) + attachmentSuffix + "." + type;
attachmentSuffix = attachmentSuffix + 1;
if (survey.getHeader().getInstanceId().equals(getComponentId())) {
// in the same component
String absolutePath = FileRepositoryManager.getAbsolutePath(componentId);
String dir =
absolutePath + getSettings().getString(IMAGES_SUB_DIRECTORY_KEY) + File.separator;
FileRepositoryManager.copyFile(dir + physicalName, dir + newPhysicalName);
} else {
// in other component
String fromAbsolutePath =
FileRepositoryManager.getAbsolutePath(survey.getHeader().getInstanceId());
String toAbsolutePath = FileRepositoryManager.getAbsolutePath(componentId);
String fromDir = fromAbsolutePath + getSettings().getString(IMAGES_SUB_DIRECTORY_KEY) +
File.separator;
String toDir =
toAbsolutePath + getSettings().getString(IMAGES_SUB_DIRECTORY_KEY) + File.separator;
FileRepositoryManager.copyFile(fromDir + physicalName, toDir + newPhysicalName);
}
// update answer
answer.setImage(newPhysicalName);
}
}
}
QuestionContainerPK toQuestionContainerPk = createSurvey(survey, componentId);
// Paste positions on Pdc
final QuestionContainerService service = getQuestionContainerService();
final int fromSilverObjectId = service.getSilverObjectId(surveyPk);
final int toSilverObjectId = service.getSilverObjectId(toQuestionContainerPk);
PdcManager.get()
.copyPositions(fromSilverObjectId, survey.getHeader().getInstanceId(), toSilverObjectId,
componentId);
}
/**
* prepare data inside session controller before sending them to the view layer
*
* @param request the current HttpServletRequest
*/
public void questionsUpdateBusinessModel(HttpServletRequest request) {
String action = request.getParameter(ACTION_PARAM);
String surveyId = request.getParameter("SurveyId");
if ("UpQuestion".equals(action)) {
// Move a question up
int qId = Integer.parseInt(request.getParameter("QId"));
List<Question> qV = this.getSessionQuestions();
Question q1 = qV.get(qId);
Question q2 = qV.get(qId - 1);
qV.set(qId - 1, q1);
qV.set(qId, q2);
this.setSessionQuestions(qV);
} else if ("DownQuestion".equals(action)) {
// Move a question down
int qId = Integer.parseInt(request.getParameter("QId"));
List<Question> qV = this.getSessionQuestions();
Question q1 = qV.get(qId);
Question q2 = qV.get(qId + 1);
qV.set(qId + 1, q1);
qV.set(qId, q2);
this.setSessionQuestions(qV);
} else if ("DeleteQuestion".equals(action)) {
// Delete a question
int qId = Integer.parseInt(request.getParameter("QId"));
List<Question> qV = this.getSessionQuestions();
if (qV != null && qV.size() >= qId + 1) {
qV.remove(qId);
this.setSessionQuestions(qV);
} else {
StringBuilder message = new StringBuilder();
message.append("Trying to delete a wrong question, questionIndexToDelete=").append(qId).
append(", questions list size=").append(qV == null ? "null" : qV.size());
SilverLogger.getLogger(this).warn(message.toString());
}
} else if ("SendQuestions".equals(action)) {
List<Question> qV = this.getSessionQuestions();
surveyId = this.getSessionSurveyId();
try {
this.updateQuestions(qV, surveyId);
request.setAttribute("UpdateSucceed", Boolean.TRUE);
} catch (SurveyException e) {
SilverLogger.getLogger(this).error(e.getMessage(), e);
request.setAttribute("UpdateSucceed", Boolean.FALSE);
}
}
if (StringUtil.isDefined(surveyId)) {
setUpSessionSurvey(surveyId);
}
}
private void setUpSessionSurvey(final String surveyId) {
this.removeSessionSurveyId();
this.removeSessionQuestions();
this.removeSessionSurveyName();
String surveyName = "";
List<Question> questionsV = new ArrayList<>();
QuestionContainerDetail survey = null;
try {
survey = this.getSurvey(surveyId);
Collection<Question> questions = survey.getQuestions();
// Cast Collection to List
questionsV.addAll(questions);
surveyName = survey.getHeader().getTitle();
} catch (SurveyException e) {
SilverLogger.getLogger(this).error(e.getMessage(), e);
}
this.setSessionQuestions(questionsV);
this.setSessionSurveyId(surveyId);
this.setSessionSurveyName(surveyName);
}
/**
* Change this code with an enum list of question style using for
*
* @return a list of question styles
*/
public List<String> getListQuestionStyle() {
List<String> questionStyles = new ArrayList<>();
if (!this.isPollingStationMode()) {
questionStyles.add("open");
}
questionStyles.add("radio");
questionStyles.add("checkbox");
questionStyles.add("list");
return questionStyles;
}
/**
* @param function
* @param request
* @return the view to display
*/
public String manageQuestionBusiness(String function, HttpServletRequest request) {
String surveyImageDirectory = FileServerUtils
.getUrl(this.getComponentId(), "REPLACE_FILE_NAME", "REPLACE_FILE_NAME", "image/gif",
getSettings().getString(IMAGES_SUB_DIRECTORY_KEY));
// Retrieve all the parameter from request
Parameters parameters = fetchAllParameters(request);
if (SEND_UPDATE_QUESTION_ACTION.equals(parameters.getAction()) ||
SEND_NEW_QUESTION_ACTION.equals(parameters.getAction())) {
processQuestionModification(parameters);
} else if ("End".equals(parameters.getAction())) {
processEndSurvey();
}
request.setAttribute("ImageDirectory", surveyImageDirectory);
if (("SendQuestionForm".equals(parameters.getAction())) ||
"UpdateQuestion".equals(parameters.getAction())) {
if ("SendQuestionForm".equals(parameters.getAction())) {
request.setAttribute("NbAnswers", parameters.getAnswerCount());
} else if ("UpdateQuestion".equals(parameters.getAction())) {
request.setAttribute("QuestionId", parameters.getQuestionId());
}
}
// Prepare destination request attribute
String view;
if (SEND_NEW_QUESTION_ACTION.equals(parameters.getAction()) ||
SEND_UPDATE_QUESTION_ACTION.equals(parameters.getAction())) {
request.setAttribute(ACTION_PARAM, "UpdateQuestions");
request.setAttribute("SurveyName", this.getSessionSurveyName());
view = "questionsUpdate.jsp";
} else {
request.setAttribute("Suggestion", parameters.getSuggestion());
request.setAttribute("Style", parameters.getStyle());
request.setAttribute(ACTION_PARAM, parameters.getAction());
view = function;
}
return view;
}
/**
* Refactoring : get code from view JSP and add it inside controller
*
* @param request the HttpServletRequest which contains all the request parameter
*/
public void sendNewSurveyAction(HttpServletRequest request) {
List<FileItem> items = HttpRequest.decorate(request).getFileItems();
String title = FileUploadUtil.getParameter(items, "title");
String description = FileUploadUtil.getParameter(items, "description");
String beginDate = FileUploadUtil.getParameter(items, "beginDate");
String endDate = FileUploadUtil.getParameter(items, "endDate");
String nbQuestions = FileUploadUtil.getParameter(items, "nbQuestions");
String anonymousString = FileUploadUtil.getParameter(items, "anonymous");
String resultMode = FileUploadUtil.getParameter(items, "resultMode");
int resultModeInt = Integer.parseInt(resultMode);
int resultView = QuestionContainerHeader.TWICE_DISPLAY_RESULTS;
if (resultModeInt == QuestionContainerHeader.DELAYED_RESULTS) {
resultView = QuestionContainerHeader.NOTHING_DISPLAY_RESULTS;
}
// Anonymous mode -> force all the survey to be anonymous
if (this.isAnonymousModeEnabled()) {
anonymousString = "on";
}
boolean anonymous =
StringUtil.isDefined(anonymousString) && "on".equalsIgnoreCase(anonymousString);
beginDate = date2SQLDate(beginDate);
if (StringUtil.isDefined(endDate)) {
endDate = date2SQLDate(endDate);
}
QuestionContainerHeader surveyHeader =
new QuestionContainerHeader(null, title, description, null, null, beginDate, endDate,
false, 0, Integer.parseInt(nbQuestions), anonymous, resultModeInt, resultView);
QuestionContainerDetail surveyDetail = new QuestionContainerDetail();
surveyDetail.setHeader(surveyHeader);
// create the positions of the new survey onto the PdC
String positions = FileUploadUtil.getParameter(items, "Positions");
setNewSurveyPositionsFromJSON(positions);
this.setSessionSurveyUnderConstruction(surveyDetail);
}
private String date2SQLDate(String beginDate) {
if (StringUtil.isDefined(beginDate)) {
try {
beginDate = DateUtil.date2SQLDate(beginDate, this.getLanguage());
} catch (ParseException e) {
SilverLogger.getLogger(this).error("Impossible to parse start date " + beginDate, e);
beginDate = null;
}
}
return beginDate;
}
/**
* Set new survey positions (axis classification) from JSON string
*
* @param positions: the JSON string positions
*/
public void setNewSurveyPositionsFromJSON(String positions) {
if (StringUtil.isDefined(positions)) {
PdcClassificationEntity surveyClassification = null;
try {
surveyClassification = PdcClassificationEntity.fromJSON(positions);
} catch (DecodingException e) {
SilverLogger.getLogger(this).error("Problem to read JSON, positions: " + positions, e);
}
if (surveyClassification != null && !surveyClassification.isUndefined()) {
List<PdcPosition> pdcPositions = surveyClassification.getPdcPositions();
this.setNewSurveyPositions(pdcPositions);
}
} else {
this.setNewSurveyPositions(null);
}
}
//pour la notification des résultats
public void initAlertResultParticipants(QuestionContainerDetail surveyDetail)
throws SurveyException {
Collection<String> users = getUsersBySurvey(surveyDetail.getId());
UserDetail[] participants = new UserDetail[users.size()];
UserDetail userDetail;
int i = 0;
for (String idUser : users) {
userDetail = getOrganisationController().getUserDetail(idUser);
participants[i++] = userDetail;
}
UserNotificationHelper.buildAndSend(
new SurveyUserNotification(surveyDetail, getUserDetail(), participants));
}
//pour la notification des résultats
public void initAlertResultUsers(QuestionContainerDetail surveyDetail) {
UserDetail[] users = getOrganisationController().getAllUsers(getComponentId());
UserNotificationHelper.buildAndSend(
new SurveyUserNotification(surveyDetail, getUserDetail(), users));
}
public void saveSynthesisFile(FileItem fileSynthesis) throws SurveyException {
QuestionContainerDetail survey = this.getSessionSurvey();
try {
Date creationDate = new Date();
String filename = fileSynthesis.getName();
SimpleAttachment file = SimpleAttachment.builder(I18NHelper.DEFAULT_LANGUAGE)
.setFilename(FileUtil.getFilename(filename))
.setTitle(filename)
.setDescription("")
.setSize(fileSynthesis.getSize())
.setContentType(FileUtil.getMimeType(filename))
.setCreationData(getUserId(), creationDate)
.build();
SimpleDocument document =
new SimpleDocument(new SimpleDocumentPK(null, survey.getComponentInstanceId()),
survey.getId(), 0, false, file);
AttachmentServiceProvider.getAttachmentService()
.createAttachment(document, fileSynthesis.getInputStream(), true);
} catch (IOException e) {
throw new SurveyException(
"Cannot save into a file the synthesis of the survey " + survey.getId(), e);
}
}
public void updateSynthesisFile(FileItem newFileSynthesis, String idDocument)
throws SurveyException {
removeSynthesisFile(idDocument);
saveSynthesisFile(newFileSynthesis);
}
public void removeSynthesisFile(String idDocument) {
SimpleDocumentPK primaryKey = new SimpleDocumentPK(idDocument);
SimpleDocument document = AttachmentServiceProvider.getAttachmentService()
.searchDocumentById(primaryKey, I18NHelper.DEFAULT_LANGUAGE);
AttachmentServiceProvider.getAttachmentService().deleteAttachment(document);
}
public List<SimpleDocument> getAllSynthesisFile(String surveyId) {
SimpleDocumentPK surveyForeignKey = new SimpleDocumentPK(surveyId, this.getComponentId());
return AttachmentServiceProvider.getAttachmentService()
.listDocumentsByForeignKey(surveyForeignKey.toResourceReference(),
I18NHelper.DEFAULT_LANGUAGE);
}
public QuestionResult getSuggestion(String userId, String questionId, String answerId)
throws SurveyException {
try {
QuestionPK qPK = new QuestionPK(questionId, getSpaceId(), getComponentId());
AnswerPK aPK = new AnswerPK(answerId, getSpaceId(), getComponentId());
return getQuestionContainerService().getSuggestion(userId, qPK, aPK);
} catch (Exception e) {
throw new SurveyException(
"Cannot get the suggestion for user" + userId + ", question " + questionId +
", and answer " + answerId, e);
}
}
private Parameters fetchAllParameters(final HttpServletRequest request) {
Parameters parameters = new Parameters();
try {
List<FileItem> items = HttpRequest.decorate(request).getFileItems();
Answer answer = null;
boolean file = false;
int attachmentSuffix = 0;
for (FileItem item : items) {
if (item.isFormField()) {
answer = fetchFormFieldParameters(parameters, answer, file, item);
} else if (FileHelper.isCorrectFile(item)) {
// it's a file part
// the part actually contained a file
String physicalName = getFilePhysicalName(attachmentSuffix, item);
attachmentSuffix = attachmentSuffix + 1;
long size = saveFile(item, physicalName);
if (size > 0 && answer != null) {
answer.setImage(physicalName);
file = true;
}
} else {
// the field did not contain a file
file = false;
}
}
} catch (RuntimeException | IOException e) {
SilverLogger.getLogger(this).error(e);
}
return parameters;
}
private long saveFile(final FileItem item, final String physicalName) throws IOException {
File dir = new File(FileRepositoryManager.getAbsolutePath(this.getComponentId()) +
getSettings().getString(IMAGES_SUB_DIRECTORY_KEY) + File.separator + physicalName);
FileUploadUtil.saveToFile(dir, item);
return item.getSize();
}
private String getFilePhysicalName(final int attachmentSuffix, final FileItem item) {
String logicalName = item.getName();
String type = logicalName.substring(logicalName.indexOf('.') + 1, logicalName.length());
return Long.toString(new Date().getTime()) + attachmentSuffix + "." + type;
}
private Answer fetchFormFieldParameters(final Parameters parameters, Answer answer,
final boolean file, final FileItem item) throws UnsupportedEncodingException {
String mpName = item.getFieldName();
if (ACTION_PARAM.equals(mpName)) {
parameters.setAction(item.getString());
} else if ("question".equals(mpName)) {
parameters.setQuestion(item.getString(FileUploadUtil.DEFAULT_ENCODING));
} else if ("nbAnswers".equals(mpName)) {
parameters.setAnswerCount(item.getString(FileUploadUtil.DEFAULT_ENCODING));
} else if ("SuggestionAllowed".equals(mpName)) {
parameters.setSuggestion(item.getString(FileUploadUtil.DEFAULT_ENCODING));
answer.setIsOpened(StringUtil.getBooleanValue(parameters.getSuggestion()));
} else if ("questionStyle".equals(mpName)) {
parameters.setStyle(item.getString(FileUploadUtil.DEFAULT_ENCODING));
} else if (mpName.startsWith("answer") || "suggestionLabel".equals(mpName)) {
parameters.setAnswerInput(item.getString(FileUploadUtil.DEFAULT_ENCODING));
answer = new Answer(null, null, parameters.getAnswerInput(), 0, false, "", 0, false, null,
null);
parameters.addAnswer(answer);
} else if (mpName.startsWith("valueImageGallery") &&
StringUtil.isDefined(item.getString(FileUploadUtil.DEFAULT_ENCODING)) && !file) {
// traiter les images venant de la gallery si pas d'image externe
answer.setImage(item.getString(FileUploadUtil.DEFAULT_ENCODING));
} else if ("QuestionId".equals(mpName)) {
parameters.setQuestionId(item.getString(FileUploadUtil.DEFAULT_ENCODING));
}
return answer;
}
private void processEndSurvey() {
QuestionContainerDetail surveyDetail = this.getSessionSurveyUnderConstruction();
// Vector 2 Collection
List<Question> questionsV = this.getSessionQuestions();
surveyDetail.setQuestions(questionsV);
}
private void processQuestionModification(final Parameters parameters) {
// Remove answer for open question
if ("open".equals(parameters.getStyle())) {
parameters.removeAllAnswers();
parameters.addAnswer(new Answer(null, null, "", 0, false, "", 0, false, null, null));
}
// Remove the suggestion answer from the list
if ("0".equals(parameters.getSuggestion())) {
parameters.getAnswers()
.stream()
.filter(Answer::isOpened)
.findFirst()
.ifPresent(parameters::removeAnswer);
}
if (SEND_NEW_QUESTION_ACTION.equals(parameters.getAction())) {
Question questionObject =
new Question(null, null, parameters.getQuestion(), "", "", null, parameters.getStyle(),
0);
questionObject.setAnswers(parameters.getAnswers());
List<Question> questionsV = this.getSessionQuestions();
questionsV.add(questionObject);
this.setSessionQuestions(questionsV);
} else if (SEND_UPDATE_QUESTION_ACTION.equals(parameters.getAction())) {
Question questionObject =
new Question(null, null, parameters.getQuestion(), "", "", null, parameters.getStyle(),
0);
questionObject.setAnswers(parameters.getAnswers());
List<Question> questionsV = this.getSessionQuestions();
questionsV.set(Integer.parseInt(parameters.getQuestionId()), questionObject);
this.setSessionQuestions(questionsV);
}
}
/**
* Get display comments mode status
*
* @param userProfile the user role profile of a user
* @param userId the unique identifier of the user
* @return true or false
*/
public boolean isDisplayCommentsEnabled(String userProfile, String userId) {
SilverpeasRole userRole = userProfile.equals("userMultiple") ?
SilverpeasRole.USER : SilverpeasRole.fromString(userProfile);
String value = getComponentParameterValue(PARAM_DISPLAY_COMMENTS);
return !DISPLAY_COMMENTS_FOR_NOBODY.equals(value) &&
(StringUtil.isDefined(userId) && userId.equals(getUserId())
|| (DISPLAY_COMMENTS_FOR_MANAGERS.equals(value)
&& userRole.isGreaterThanOrEquals(SilverpeasRole.PUBLISHER))
|| DISPLAY_COMMENTS_FOR_ALL.equals(value));
}
/**
* Gets the display result view.
* @return the {@link DisplayResultView} instance representing the result vew.
*/
public DisplayResultView getDisplayResultView() {
return displayResultView;
}
/**
* Sets the display result view according to given identifier or main view.
* <p>
* The result view is set into session.
* </p>
* @param survey the representation of the survey.
* @param identifierOrMainView the name (or full name) or the main part of name of a view.
* @return the {@link DisplayResultView} instance.
*/
public DisplayResultView setSurveyResultViewFromIdentifierOrMainView(
final QuestionContainerDetail survey, final String identifierOrMainView) {
final List<DisplayResultView> potentialViews = fromMainViewOnly(identifierOrMainView);
if (!potentialViews.isEmpty()) {
displayResultView = potentialViews.stream()
.filter(displayResultView::equals)
.findFirst()
.orElseGet(() -> potentialViews.get(0));
} else {
displayResultView = fromString(identifierOrMainView);
}
if (DETAIL.equals(displayResultView) && survey.getHeader().getNbVoters() > 50) {
displayResultView = CLASSIC_GRAPHICAL;
}
return displayResultView;
}
private static class Parameters {
private String action;
private String question;
private String answerCount;
private String suggestion;
private String style;
private String answerInput;
private final List<Answer> answers = new ArrayList<>();
private String questionId;
public void setAction(final String action) {
this.action = action;
}
public void setQuestion(final String question) {
this.question = question;
}
public void setAnswerCount(final String answerCount) {
this.answerCount = answerCount;
}
public void setSuggestion(final String suggestion) {
this.suggestion = suggestion;
}
public void setStyle(final String style) {
this.style = style;
}
public void setQuestionId(final String questionId) {
this.questionId = questionId;
}
public void setAnswerInput(final String answerInput) {
this.answerInput = answerInput;
}
public void addAnswer(final Answer answer) {
this.answers.add(answer);
}
public void removeAnswer(final Answer answer) {
this.answers.remove(answer);
}
public void removeAllAnswers() {
this.answers.clear();
}
public List<Answer> getAnswers() {
return this.answers;
}
public String getAction() {
return action;
}
public String getQuestion() {
return question;
}
public String getAnswerCount() {
return answerCount;
}
public String getSuggestion() {
return suggestion;
}
public String getStyle() {
return style;
}
public String getAnswerInput() {
return answerInput;
}
public String getQuestionId() {
return questionId;
}
}
}