r3233 - in branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main: java/org/chorem/pollen/ui/actions/poll resources resources/config resources/i18n webapp/WEB-INF/jsp webapp/WEB-INF/jsp/poll
Author: fdesbois Date: 2012-04-05 09:50:32 +0200 (Thu, 05 Apr 2012) New Revision: 3233 Url: http://chorem.org/repositories/revision/pollen/3233 Log: improve CreatePoll/EditPoll/ClonePoll using different actions for loading (LoadPoll) and execution (SavePoll) Added: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/AbstractPollForm.java branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/LoadPoll.java branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/SavePoll.java Removed: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/ClonePoll.java branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/CreatePoll.java branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/EditPoll.java Modified: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/config/struts-poll.xml branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_en_GB.properties branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_fr_FR.properties branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/shiro.ini branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/poll/create.jsp branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/pollListHelper.jsp Copied: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/AbstractPollForm.java (from rev 3232, branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/CreatePoll.java) =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/AbstractPollForm.java (rev 0) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/AbstractPollForm.java 2012-04-05 07:50:32 UTC (rev 3233) @@ -0,0 +1,1096 @@ +package org.chorem.pollen.ui.actions.poll; + +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts2.interceptor.ParameterAware; +import org.chorem.pollen.bean.ChoiceHelper; +import org.chorem.pollen.bean.PollDateChoice; +import org.chorem.pollen.bean.PollImageChoice; +import org.chorem.pollen.business.persistence.Choice; +import org.chorem.pollen.business.persistence.ChoiceImpl; +import org.chorem.pollen.business.persistence.PersonToList; +import org.chorem.pollen.business.persistence.PersonToListImpl; +import org.chorem.pollen.business.persistence.Poll; +import org.chorem.pollen.business.persistence.PollAccount; +import org.chorem.pollen.business.persistence.PollAccountImpl; +import org.chorem.pollen.business.persistence.VotingList; +import org.chorem.pollen.business.persistence.VotingListImpl; +import org.chorem.pollen.common.ChoiceType; +import org.chorem.pollen.common.I18nAble; +import org.chorem.pollen.common.PollType; +import org.chorem.pollen.common.VoteCountingType; +import org.chorem.pollen.services.impl.PollService; +import org.chorem.pollen.ui.actions.FileUploadAware; +import org.chorem.pollen.ui.actions.PollenActionSupport; +import org.nuiton.util.StringUtil; + +import java.io.File; +import java.text.ParseException; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created: 04/04/12 + * + * @author fdesbois <desbois@codelutin.com> + * $Id$ + */ +public abstract class AbstractPollForm extends PollenActionSupport implements ParameterAware, FileUploadAware { + + private static final long serialVersionUID = 1L; + + /** Logger. */ + private static final Log log = LogFactory.getLog(AbstractPollForm.class); + + private static final Pattern TEXT_CHOICE_NAME_PATTERN = + Pattern.compile("textChoice_(\\d+)\\.name"); + + private static final Pattern DATE_CHOICE_NAME_PATTERN = + Pattern.compile("dateChoice_(\\d+)\\.name"); + + private static final Pattern IMAGE_CHOICE_NAME_PATTERN = + Pattern.compile("imageChoice_(\\d+)\\.name"); + + private static final Pattern VOTING_LIST_NAME_PATTERN = + Pattern.compile("votingList_(\\d+)\\.name"); + + private Poll poll; + + private Map<String, String> pollTypes; + + private Map<String, String> voteCountingTypes; + + private Map<String, String> choiceTypes; + + private boolean notification; + + private boolean reminder; + + private boolean limitChoice; + + private int reminderHourCountdown = 2; + + private String textChoiceTokenId; + + private String dateChoiceTokenId; + + private String imageChoiceTokenId; + + private String votingListTokenId; + + private int nbTextChoices; + + private int nbDateChoices; + + private int nbImageChoices; + + private int nbVotingLists; + + /** Uploaded images (for choice type poll). */ + private List<File> imageChoice; + + /** Uploaded images content type (for choice type poll). */ + private List<String> imageChoiceContentType; + + /** Uploaded images name (from use desktop) (for choice type poll). */ + private List<String> imageChoiceFileName; + + private boolean informationsError; + + private boolean optionsError; + + private String actionLabel; + + /** + * All the parameters send by request used to build back choices of the + * poll. + */ + protected Map<String, String[]> parameters; + + private transient PollService pollService; + + protected abstract Poll initPoll(); + + @Override + public String getPageLogo() { + return "Creation"; + } + + public Poll getPoll() { + if (poll == null) { + poll = initPoll(); + } + return poll; + } + + public int getNbTextChoices() { + return nbTextChoices; + } + + public String getTextChoiceTokenId() { + return textChoiceTokenId; + } + + public int getNbDateChoices() { + return nbDateChoices; + } + + public String getDateChoiceTokenId() { + return dateChoiceTokenId; + } + + public int getNbImageChoices() { + return nbImageChoices; + } + + public String getImageChoiceTokenId() { + return imageChoiceTokenId; + } + + public int getNbVotingLists() { + return nbVotingLists; + } + + public String getVotingListTokenId() { + return votingListTokenId; + } + + public Map<String, String> getPollTypes() { + return pollTypes; + } + + public Map<String, String> getVoteCountingTypes() { + return voteCountingTypes; + } + + public Map<String, String> getChoiceTypes() { + return choiceTypes; + } + + public boolean isNotification() { + return notification; + } + + public void setNotification(boolean notification) { + this.notification = notification; + } + + public boolean isReminder() { + return reminder; + } + + public void setReminder(boolean reminder) { + this.reminder = reminder; + } + + public boolean isLimitChoice() { + return limitChoice; + } + + public void setLimitChoice(boolean limitChoice) { + this.limitChoice = limitChoice; + } + + public int getReminderHourCountdown() { + return reminderHourCountdown; + } + + public void setReminderHourCountdown(int reminderHourCountdown) { + this.reminderHourCountdown = reminderHourCountdown; + } + + @Override + public void setFiles(String paramName, List<File> files) { + this.imageChoice = Lists.newArrayList(files); + } + + @Override + public void setFileContentTypes(String paramName, List<String> contentTypes) { + this.imageChoiceContentType = Lists.newArrayList(contentTypes); + } + + @Override + public void setFileNames(String paramName, List<String> fileNames) { + this.imageChoiceFileName = Lists.newArrayList(fileNames); + } + + public List<File> getImageChoice() { + if (imageChoice == null) { + imageChoice = Lists.newArrayList(); + } + return imageChoice; + } + + public List<String> getImageChoiceContentType() { + if (imageChoiceContentType == null) { + imageChoiceContentType = Lists.newArrayList(); + } + return imageChoiceContentType; + } + + public List<String> getImageChoiceFileName() { + if (imageChoiceFileName == null) { + imageChoiceFileName = Lists.newArrayList(); + } + return imageChoiceFileName; + } + + public boolean isInformationsError() { + return informationsError; + } + + public boolean isOptionsError() { + return optionsError; + } + + public boolean isFreePoll() { + PollType pollType = poll.getPollType(); + return pollType == PollType.FREE; + } + + public boolean isGroupPoll() { + PollType pollType = poll.getPollType(); + return pollType == PollType.GROUP; + } + + public String getPollVoteUrl() { + return getPollService().getPollVoteUrl(poll); + } + + public String getPollEditUrl() { + return getPollService().getPollEditUrl(poll); + } + + public int getSelectedTab() { + int result; + if (isInformationsError()) { + result = 0; + } else { + if (isOptionsError()) { + result = 1; + } else { + result = 0; + } + } + return result; + } + + public String getActionLabel() { + return actionLabel; + } + + protected int getNbChoices() { + //TODO tchemit-2012-03-05 use a default value from configuration + return 5; + } + + protected int getDefaultNbVotingLists() { + return 1; + } + + protected boolean isEdit() { + return getPoll().getTopiaId() != null; + } + + public void prepareFormPage() throws Exception { + + // remove all stuff from session + getPollenSession().clearDynamicData(); + + actionLabel = isEdit() ? _("pollen.action.editPoll") : _("pollen.action.createPoll"); + + pollTypes = decorateToName(PollType.values()); + choiceTypes = decorateToName(ChoiceType.values()); + voteCountingTypes = decorateToName(VoteCountingType.values()); + + nbTextChoices = nbDateChoices = nbImageChoices = getNbChoices(); + nbVotingLists = getDefaultNbVotingLists(); + + String tokenSuffix = getServiceContext().createPollenUrlId(); + + textChoiceTokenId = DisplayTextChoice.CHOICE_TOKEN + "_" + + tokenSuffix; + + dateChoiceTokenId = DisplayDateChoice.CHOICE_TOKEN + "_" + + tokenSuffix; + + imageChoiceTokenId = DisplayImageChoice.CHOICE_TOKEN + "_" + + tokenSuffix; + + ChoiceType pollChoiceType; + // Retrieve choiceType from parameters, the poll object will be updated after prepare + String choiceTypeParam = getNonEmptyParameterValue("poll.choiceType"); + if (choiceTypeParam == null) { + + // Default value will be initiliazed on poll instanciation + pollChoiceType = getPoll().getChoiceType(); + + } else { + pollChoiceType = ChoiceType.valueOf(choiceTypeParam); + } + + if (log.isInfoEnabled()) { + log.info("choice type " + pollChoiceType); + } + + Map<Integer, Choice> choices = null; + String tokenId = null; + + switch (pollChoiceType) { + case TEXT: + choices = buildTextChoices(nbTextChoices); + tokenId = textChoiceTokenId; + break; + case DATE: + choices = buildDateChoices(nbDateChoices); + tokenId = dateChoiceTokenId; + break; + case IMAGE: + choices = buildImageChoices(nbImageChoices); + tokenId = imageChoiceTokenId; + break; + } + getPollenSession().putDynamicData(tokenId, choices); + + // load votingLists + + votingListTokenId = DisplayVotingList.VOTING_LIST_TOKEN + "_" + + tokenSuffix; + Map<Integer, VotingList> votingLists = buildVotingLists(nbVotingLists); + getPollenSession().putDynamicData(votingListTokenId, votingLists); + } + + @Override + public void validate() { + + Preconditions.checkNotNull(poll); + + informationsError = false; + + // poll must have a title + if (StringUtils.isEmpty(poll.getTitle())) { + addFieldError("poll.title", _("pollen.error.poll.required.title")); + } + + + // validate choices + Map<Integer, Choice> orderedChoices = getOrderedChoices(); + + if (MapUtils.isEmpty(orderedChoices)) { + + // poll must have at least one choice + addFieldError("poll.choices", + _("pollen.error.poll.required.one.choice")); + } else { +// +// //TODO tchemit improve this (from different cases text-date-image) +// // check there is no choice with same name +// boolean duplicateNameDetected = false; +// Set<String> names = Sets.newHashSet(); +// for (Choice choice : orderedChoices.values()) { +// String choiceName = choice.getName(); +// if (!names.add(choiceName)) { +// duplicateNameDetected = true; +// break; +// } +// } +// if (duplicateNameDetected) { +// addFieldError("poll.choices", +// _("pollen.error.poll.detected.duplicate.choice.name")); +// } + + ChoiceType choiceType = poll.getChoiceType(); + int inputChoicesSize = orderedChoices.size(); + Set<Object> choiceValues = + Sets.newHashSet(ChoiceHelper.toValues(orderedChoices.values(), choiceType)); + + if (inputChoicesSize > choiceValues.size()) { + addFieldError("poll.choices", + _("pollen.error.poll.detected.duplicate.choice.name")); + } + } + + + optionsError = false; + + // validate security stuff + + if (isFreePoll()) { + + // nothing to validate + + } else { + Map<Integer, VotingList> votingLists = getOrderedVotingLists(); + + Set<String> groups = Sets.newHashSet(); + Set<String> voters = Sets.newHashSet(); + Set<String> emails = Sets.newHashSet(); + + for (Map.Entry<Integer, VotingList> entry : votingLists.entrySet()) { + optionsError |= validateVotingList(entry.getKey(), + entry.getValue(), + groups, + voters, + emails); + } + } + + informationsError = hasFieldErrors(); + + if (!informationsError && optionsError) { + + // trick to force to go back to form + addFieldError("", ""); + } + } + + protected boolean validateVotingList(int votingListNumber, + VotingList votingList, + Set<String> groups, + Set<String> voters, + Set<String> emails) { + + boolean result = false; + Map<String, String> errors = Maps.newHashMap(); + + String votingListErrorPrefix = "poll.votingList_" + votingListNumber; + + if (isGroupPoll()) { + + // group poll + + // check there is at least one group + // check no doublon on group names + // check there is at least one voter on each group + // check no doublon on voter names + // check no doublon on voter emails + + { // validate votingList name + String votingListName = votingList.getName(); + + if (StringUtils.isEmpty(votingListName)) { + + errors.put(votingListErrorPrefix + ".name", + _("pollen.error.poll.required.votingList.name")); + } else { + + // check no votingList name doublon + boolean add = groups.add(votingListName); + if (!add) { + + // name doublon + errors.put( + votingListErrorPrefix + ".name", + _("pollen.error.poll.votingList.name.doublon")); + } + + } + } + + { // validate votingList weight + + if (votingList.getWeight() == 0) { + + // no weight filled (can be a bad conversion) + errors.put( + votingListErrorPrefix + ".weight", + _("pollen.error.poll.votingList.weight.not.valid")); + } + } + } + + // check there is at least one voter + + String persontoListToken = DisplayPersonToList.getPersonToListTokenId( + votingListTokenId, votingListNumber); + + Map<Integer, PersonToList> personToLists = + getPollenSession().getDynamicData(persontoListToken); + + if (MapUtils.isEmpty(personToLists)) { + + // no personToList found for unique votingList 0 + errors.put(votingListErrorPrefix, + _("pollen.error.poll.required.one.personToList")); + } else { + + // check no doublon on voter names + // check no doublon on voter emails + + for (Map.Entry<Integer, PersonToList> entry : + personToLists.entrySet()) { + + result |= validatePersonList(entry.getKey(), entry.getValue(), + voters, emails); + } + } + + if (MapUtils.isNotEmpty(errors)) { + + // keep errors to display them in correct action + String errorToken = DisplayVotingList.getVotingListErrorTokenId( + votingListTokenId, votingListNumber); + if (log.isInfoEnabled()) { + log.info("Add " + errors.size() + " errors to " + errorToken); + } + getPollenSession().putDynamicData(errorToken, errors); + result = true; + } + return result; + } + + protected boolean validatePersonList(int personToListNumber, + PersonToList personToList, + Set<String> voters, + Set<String> emails) { + + boolean result = false; + Map<String, String> errors = Maps.newHashMap(); + String fieldNamePrefix = + "personToList_0_" + personToListNumber; + PollAccount pollAccount = personToList.getPollAccount(); + + { // validate votingId + + String votingId = pollAccount.getVotingId(); + // check voter is not doublon + boolean add = voters.add(votingId); + if (!add) { + + // voter doublon + errors.put( + fieldNamePrefix + ".votingId", + _("pollen.error.poll.personToList.votingId.doublon")); + } + } + { // validate email + String email = pollAccount.getEmail(); + + if (StringUtils.isEmpty(email)) { + errors.put( + fieldNamePrefix + ".email", + _("pollen.error.poll.personToList.email.required")); + } else { + + + boolean validEmail = StringUtil.isEmail(email); + if (!validEmail) { + + // not a valid email + errors.put( + fieldNamePrefix + ".email", + _("pollen.error.poll.personToList.email.not.valid")); + } else { + + // check email not doublon + boolean add = emails.add(email); + if (!add) { + + // email doublon + errors.put( + fieldNamePrefix + ".email", + _("pollen.error.poll.personToList.email.doublon")); + } + } + } + } + { // validate weight + if (personToList.getWeight() == 0) { + + // no weight filled (can be a bad conversion) + errors.put( + fieldNamePrefix + ".weight", + _("pollen.error.poll.personToList.weight.not.valid")); + } + } + + if (MapUtils.isNotEmpty(errors)) { + String errorToken = + DisplayPersonToList.getPersonToListErrorTokenId( + votingListTokenId, 0, personToListNumber); + if (log.isInfoEnabled()) { + log.info("Add " + errors.size() + " errors to " + errorToken); + } + getPollenSession().putDynamicData(errorToken, errors); + result = true; + } + return result; + } + + @Override + public void setParameters(Map<String, String[]> parameters) { + this.parameters = parameters; + } + + protected PollService getPollService() { + if (pollService == null) { + pollService = newService(PollService.class); + } + return pollService; + } + + protected Map<Integer, Choice> getOrderedChoices() { + Map<Integer, Choice> result = null; + switch (poll.getChoiceType()) { + case TEXT: + result = getPollenSession().getDynamicData(textChoiceTokenId); + break; + case DATE: + result = getPollenSession().getDynamicData(dateChoiceTokenId); + break; + case IMAGE: + result = getPollenSession().getDynamicData(imageChoiceTokenId); + break; + } + return result; + } + + protected Map<Integer, VotingList> getOrderedVotingLists() { + + Map<Integer, VotingList> result = getPollenSession().getDynamicData( + votingListTokenId); + return result; + } + + protected Map<Integer, Choice> buildTextChoices(int nbDefault) { + Map<Integer, Choice> result = Maps.newTreeMap(); + + int maxNumber = 0; + + for (String paramName : parameters.keySet()) { + + Matcher matcher = TEXT_CHOICE_NAME_PATTERN.matcher(paramName); + if (matcher.matches()) { + + // found a text choice name + + String paramValue = getNonEmptyParameterValue(paramName); + if (paramValue != null) { + + // can keep this none empty text choice name + + Integer choiceNumber = Integer.valueOf(matcher.group(1)); + if (choiceNumber > maxNumber) { + maxNumber = choiceNumber; + } + Choice choice = new ChoiceImpl(); + createChoice(choice, "textChoice_" + choiceNumber, + paramValue); + result.put(choiceNumber, choice); + } + } + } + result = reindexMap(result, maxNumber); + + int size = result.size(); + nbTextChoices = Math.max(nbDefault, size); + log.info("nbTextChoices (from request) = " + size); + logChoice(result); + return result; + } + + protected Map<Integer, Choice> buildDateChoices(int nbDefault) { + Map<Integer, Choice> result = Maps.newTreeMap(); + + int maxNumber = 0; + for (String paramName : parameters.keySet()) { + + Matcher matcher = DATE_CHOICE_NAME_PATTERN.matcher(paramName); + if (matcher.matches()) { + + // found a text choice name + + String paramValue = getNonEmptyParameterValue(paramName); + if (paramValue != null) { + + // can keep this none empty text choice name + + Integer choiceNumber = Integer.valueOf(matcher.group(1)); + if (choiceNumber > maxNumber) { + maxNumber = choiceNumber; + } + PollDateChoice choice = new PollDateChoice(); + createDateChoice(choice, + "dateChoice_" + choiceNumber, + paramValue); + result.put(choiceNumber, choice); + } + } + } + result = reindexMap(result, maxNumber); + + int size = result.size(); + nbDateChoices = Math.max(nbDefault, size); + log.info("nbDateChoices (from request) = " + size); + logChoice(result); + return result; + } + + protected Map<Integer, Choice> buildImageChoices(int nbDefault) { + Map<Integer, Choice> result = Maps.newTreeMap(); + + // push back in parameters stuff from uploaded files + int index = 0; + + for (String fileName : getImageChoiceFileName()) { + if (fileName != null) { + parameters.put("imageChoice_" + index + ".name", + new String[]{fileName}); + parameters.put( + "imageChoice_" + index + ".location", + new String[]{getImageChoice().get(index).getAbsolutePath()}); + } + index++; + } + + int maxNumber = 0; + for (String paramName : parameters.keySet()) { + + Matcher matcher = IMAGE_CHOICE_NAME_PATTERN.matcher(paramName); + if (matcher.matches()) { + + // found an image choice name + + String paramValue = getNonEmptyParameterValue(paramName); + if (paramValue != null) { + + // can keep this none empty text choice name + + Integer choiceNumber = Integer.valueOf(matcher.group(1)); + if (choiceNumber > maxNumber) { + maxNumber = choiceNumber; + } + PollImageChoice choice = new PollImageChoice(); + createImageChoice(choice, + "imageChoice_" + choiceNumber, + paramValue); + + result.put(choiceNumber, choice); + } + } + } + result = reindexMap(result, maxNumber); + int size = result.size(); + nbImageChoices = Math.max(nbDefault, size); + log.info("nbImageChoices (from request) = " + size); + logChoice(result); + return result; + } + + protected Map<Integer, VotingList> buildVotingLists(int nbDefault) { + Map<Integer, VotingList> result = Maps.newTreeMap(); + + int maxNumber = 0; + + // get all votingList_ parameters + Set<String> votingListParameterNames = Sets.filter( + parameters.keySet(), + new StringStartWithPredicate("votingList_")); + + for (String paramName : votingListParameterNames) { + + Matcher matcher = VOTING_LIST_NAME_PATTERN.matcher(paramName); + + if (matcher.matches()) { + + // found a voting list name + + int votingListNumber = buildVotingList(paramName, + matcher, + result + ); + maxNumber = Math.max(maxNumber, votingListNumber); + } + } + + result = reindexMap(result, maxNumber); + + int size = result.size(); + nbVotingLists = Math.max(nbDefault, size); + log.info("nbVotingList (from request) = " + size); + + // add personToList maps to session (but just now, since votingList + // could have been reindex) + for (Map.Entry<Integer, VotingList> entry : result.entrySet()) { + Integer votingListNumber = entry.getKey(); + VotingList votingList = entry.getValue(); + + if (!votingList.isPollAccountPersonToListEmpty()) { + List<PersonToList> personToList = + votingList.getPollAccountPersonToList(); + + Map<Integer, PersonToList> personToListMap = Maps.newTreeMap(); + int index = 0; + for (PersonToList toList : personToList) { + personToListMap.put(index++, toList); + } + + String token = DisplayPersonToList.getPersonToListTokenId( + votingListTokenId, votingListNumber); + if (log.isInfoEnabled()) { + log.info("Add " + token + " with " + + personToListMap.size() + " personToList"); + } + getPollenSession().putDynamicData(token, personToListMap); + } + } + + return result; + } + + private double getDoubleValue(String parameterName) { + String parameterValue = getNonEmptyParameterValue(parameterName); + double result = 0; + if (StringUtils.isNotEmpty(parameterValue)) { + + try { + result = Double.valueOf(parameterValue); + } catch (NumberFormatException e) { + //bad conversion, will be treated later + if (log.isDebugEnabled()) { + log.debug("Bad double conversion from param [" + + parameterName + "] : " + parameterValue); + } + } + } + return result; + } + + private int buildVotingList(String votingListParameterName, + Matcher votingListMatcher, + Map<Integer, VotingList> result) { + + String paramValue = getNonEmptyParameterValue(votingListParameterName); + int votingListNumber = Integer.valueOf(votingListMatcher.group(1)); + + VotingList votingList = new VotingListImpl(); + + votingList.setName(paramValue); + + String prefix = "votingList_" + votingListNumber; + + double weight = getDoubleValue(prefix + ".weight"); + votingList.setWeight(weight); + + String topiaId = getNonEmptyParameterValue(prefix + ".topiaId"); + votingList.setTopiaId(topiaId); + + result.put(votingListNumber, votingList); + + String personToListPrefix = "personToList_" + votingListNumber + "_"; + + // get all personToList parameters + Set<String> votingListParameterNames = Sets.filter( + parameters.keySet(), new StringStartWithPredicate(personToListPrefix)); + + Pattern personToListNamePattern = Pattern.compile( + personToListPrefix + "(\\d+)\\.votingId"); + + Map<Integer, PersonToList> personToLists = Maps.newTreeMap(); + + int maxPersonToListNumber = 0; + + // let's build personToList list + for (String personToListNameParameter : votingListParameterNames) { + + Matcher matcher = personToListNamePattern.matcher( + personToListNameParameter); + + if (matcher.matches()) { + + int personToListNumber = buildPersonToList( + personToListPrefix, + personToListNameParameter, + matcher, + votingListNumber, + personToLists); + + maxPersonToListNumber = Math.max(maxPersonToListNumber, personToListNumber); + } + } + + personToLists = reindexMap(personToLists, maxPersonToListNumber); + + for (PersonToList personToList : personToLists.values()) { + votingList.addPollAccountPersonToList(personToList); + } + + return votingListNumber; + } + + private int buildPersonToList(String personToListPrefix, + String paramName, + Matcher personToListMatcher, + int votingListNumber, + Map<Integer, PersonToList> result) { + + String paramValue = getNonEmptyParameterValue(paramName); + + int personToListNumber = 0; + + if (paramValue != null) { + + // found a PersonToList none empty name, keep it + + personToListNumber = Integer.valueOf(personToListMatcher.group(1)); + + PersonToList personToList = new PersonToListImpl(); + + PollAccount account = new PollAccountImpl(); + personToList.setPollAccount(account); + + account.setVotingId(paramValue); + + String prefix = personToListPrefix + personToListNumber; + + double weight = getDoubleValue(prefix + ".weight"); + personToList.setWeight(weight); + + String topiaId = getNonEmptyParameterValue(prefix + ".topiaId"); + personToList.setTopiaId(topiaId); + + String email = getNonEmptyParameterValue(prefix + ".email"); + account.setEmail(email); + + String accountId = getNonEmptyParameterValue(prefix + ".accountId"); + account.setAccountId(accountId); + + result.put(personToListNumber, personToList); + } + return personToListNumber; + } + + private Choice createImageChoice(PollImageChoice choice, + String prefix, + String name) { + createChoice(choice, prefix, name); + String locationName = prefix + ".location"; + String location = getNonEmptyParameterValue(locationName); + choice.setLocation(location); + if (log.isInfoEnabled()) { + log.info("image location [" + name + "] =" + location); + } + return choice; + } + + private Choice createDateChoice(PollDateChoice choice, + String prefix, + String name) { + createChoice(choice, prefix, name); + if (StringUtils.isNotEmpty(name)) { + Date date = null; + try { + date = parseDateTime(name); + } catch (ParseException e) { + if (log.isErrorEnabled()) { + log.error("Unparseable date " + name, e); + } + } + choice.setDate(date); + } + return choice; + } + + private Choice createChoice(Choice choice, String prefix, String name) { + String descriptionName = prefix + ".description"; + String topiaIdName = prefix + ".topiaId"; + String description = getNonEmptyParameterValue(descriptionName); + String topiaId = getNonEmptyParameterValue(topiaIdName); + choice.setName(name); + choice.setDescription(description); + choice.setTopiaId(topiaId); + return choice; + } + + private void logChoice(Map<Integer, Choice> result) { + for (Map.Entry<Integer, Choice> e : result.entrySet()) { + Integer choiceId = e.getKey(); + Choice choice = e.getValue(); + if (log.isInfoEnabled()) { + log.info("Choice [" + choiceId + "] = " + + choice.getName() + " -- " + + choice.getDescription()); + } + } + } + + + private <T> Map<Integer, T> reindexMap(Map<Integer, T> result, int maxNumber) { + Map<Integer, T> result2; + + if (maxNumber != result.size() - 1) { + + // means there is a hole inside the result (a empty choice was + // submitted) + + // le'ts remove this + List<Integer> numbers = Lists.newArrayList(result.keySet()); + + Collections.sort(numbers); + + result2 = Maps.newTreeMap(); + int i = 0; + for (Integer number : numbers) { + T choice = result.get(number); + result2.put(i++, choice); + } + } else { + result2 = result; + } + return result2; + } + + private <O> void addtoList(List<O> list, int index, O object) { + + while (list.size() < index) { + list.add(null); + } + list.add(index, object); + } + + + private String getNonEmptyParameterValue(String paramName) { + String[] paramValues = parameters.get(paramName); + String result = null; + if (paramValues != null && paramValues.length == 1) { + String paramValue = paramValues[0]; + if (StringUtils.isNotEmpty(paramValue)) { + result = paramValue; + } + } + return result; + } + + private <E extends Enum<E> & I18nAble> Map<String, String> decorateToName(E... values) { + Map<String, String> result = Maps.newLinkedHashMap(); + for (E value : values) { + result.put(value.name(), getText(value.getI18nKey())); + } + return result; + } + + private static class StringStartWithPredicate implements Predicate<String> { + private final String prefix; + + public StringStartWithPredicate(String prefix) { + this.prefix = prefix; + } + + @Override + public boolean apply(String input) { + return input.startsWith(prefix); + } + } +} Deleted: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/ClonePoll.java =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/ClonePoll.java 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/ClonePoll.java 2012-04-05 07:50:32 UTC (rev 3233) @@ -1,226 +0,0 @@ -/* - * #%L - * Pollen :: UI (strust2) - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2009 - 2012 CodeLutin, Tony Chemit - * %% - * 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. - * - * 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 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 <http://www.gnu.org/licenses/>. - * #L% - */ -package org.chorem.pollen.ui.actions.poll; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import org.chorem.pollen.bean.PollImageChoice; -import org.chorem.pollen.bean.PollUri; -import org.chorem.pollen.business.persistence.Choice; -import org.chorem.pollen.business.persistence.PersonToList; -import org.chorem.pollen.business.persistence.Poll; -import org.chorem.pollen.business.persistence.PollAccount; -import org.chorem.pollen.business.persistence.VotingList; -import org.chorem.pollen.common.ChoiceType; -import org.chorem.pollen.common.PollType; - -import java.util.List; - -/** - * Creates a new poll by cloning an existing one. - * - * @author tchemit <chemit@codelutin.com> - * @author fdesbois <desbois@codelutin.com> - * @since 1.2.6 - */ -public class ClonePoll extends CreatePoll { - - private static final long serialVersionUID = 1L; - - private static final String PREFIX_CHOICE = "%sChoice_%d"; - - private static final String PREFIX_VOTING_LIST = "votingList_%d"; - - private static final String PREFIX_PERSON_TO_LIST = "personToList_%d_%d"; - - protected PollUri pollUri; - - public final PollUri getUriId() { - return pollUri; - } - - public final void setUriId(PollUri pollUri) { - this.pollUri = pollUri; - } - - public String getPollUid() { - return pollUri.getPollId(); - } - - protected boolean keepTopiaId() { - return false; - } - - @Override - public Poll getPoll() { - if (poll == null) { - poll = getPollService().getPollByPollId(getPollUid()); - - if (!keepTopiaId()) { - poll.setTopiaId(null); - - // Use a new pollId - String pollUid = serviceContext.createPollenUrlId(); - poll.setPollId(pollUid); - } - } - return poll; - } - - @Override - public void prepare() throws Exception { - - // -- Choice -- - ChoiceType choiceType = getPoll().getChoiceType(); - prepareParams(getPoll().getChoice(), withChoicePrefix(choiceType)); - - // -- VotingList -- - if (getPoll().getPollType() != PollType.FREE) { - prepareParams(getPoll().getVotingList(), withVotingListPrefix()); - } - - super.prepare(); - } - - private Function<Choice, String> withChoicePrefix(final ChoiceType choiceType) { - final String choiceTypeName = choiceType.name().toLowerCase(); - return new IndexedFunction<Choice, String>() { - - @Override - protected String apply(Choice input, int index) { - - String prefix = String.format(PREFIX_CHOICE, choiceTypeName, index); - if (keepTopiaId()) { - putParameter(prefix, Choice.TOPIA_ID, input.getTopiaId()); - } - putParameter(prefix, Choice.PROPERTY_NAME, input.getName()); - putParameter(prefix, Choice.PROPERTY_DESCRIPTION, input.getDescription()); - - if (choiceType == ChoiceType.IMAGE) { - putParameter(prefix, PollImageChoice.PROPERTY_LOCATION, input.getName()); - } - - return prefix; - } - }; - } - - private Function<VotingList, String> withVotingListPrefix() { - return new IndexedFunction<VotingList, String>() { - - @Override - protected String apply(VotingList input, int index) { - - String prefix = String.format(PREFIX_VOTING_LIST, index); - if (keepTopiaId()) { - putParameter(prefix, VotingList.TOPIA_ID, input.getTopiaId()); - } - putParameter(prefix, VotingList.PROPERTY_NAME, input.getName()); - putParameter(prefix, VotingList.PROPERTY_WEIGHT, String.valueOf(input.getWeight())); - - prepareParams(input.getPollAccountPersonToList(), withPersonToListPrefix(index)); - - return prefix; - } - }; - } - - private Function<PersonToList, String> withPersonToListPrefix(final int votingListIndex) { - return new IndexedFunction<PersonToList, String>() { - - @Override - protected String apply(PersonToList input, int index) { - - PollAccount pollAccount = input.getPollAccount(); - - String prefix = String.format(PREFIX_PERSON_TO_LIST, votingListIndex, index); - if (keepTopiaId()) { - putParameter(prefix, PersonToList.TOPIA_ID, input.getTopiaId()); - } - putParameter(prefix, PersonToList.PROPERTY_WEIGHT, String.valueOf(input.getWeight())); - putParameter(prefix, PollAccount.PROPERTY_ACCOUNT_ID, pollAccount.getAccountId()); - putParameter(prefix, PollAccount.PROPERTY_VOTING_ID, pollAccount.getVotingId()); - putParameter(prefix, PollAccount.PROPERTY_EMAIL, pollAccount.getEmail()); - - return prefix; - } - }; - } - - /** - * Prepare the {@code source} for parameters using the {@code function} to - * push necessary data. - * - * @param source List of elements - * @param function Function used to push element data using {@link #putParameter(String, String, String)} - * @param <T> Type of data - * @see #putParameter(String, String, String) - */ - private <T> void prepareParams(List<T> source, Function<T, String> function) { - ImmutableList.copyOf(Lists.transform(source, function)); - } - - /** - * Put some data in the {@code parameters} with name built using - * {@code prefix} and {@code property}. The {@code value} will be put for - * this parameter. - * - * @param prefix Prefix to use for the parameter name - * @param property Name of the {@code property} to push in parameters - * @param value Value of this {@code property} - */ - private void putParameter(String prefix, String property, String value) { - parameters.put(prefix + "." + property, new String[]{value}); - } - - /** - * Guava {@link Function} that keeps index on each {@link Function#apply(Object)} call. - * You just have to implement {@link #apply(Object, int)} to have the current - * index of the {@code input} value. - * - * @param <F> Type of data where function will be applied on - * @param <T> Resulting type - */ - private abstract static class IndexedFunction<F, T> implements Function<F, T> { - - private int index; - - @Override - public T apply(F input) { - T result = apply(input, index); - index++; - return result; - } - - /** - * Called during {@link #apply(Object)} method with current {@code index}. - * - * @param input current value - * @param index current index - * @return the result of the function applied on the {@code input} object - */ - protected abstract T apply(F input, int index); - } -} Deleted: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/CreatePoll.java =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/CreatePoll.java 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/CreatePoll.java 2012-04-05 07:50:32 UTC (rev 3233) @@ -1,1163 +0,0 @@ -/* - * #%L - * Pollen :: UI (strust2) - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2009 - 2012 CodeLutin, Tony Chemit - * %% - * 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. - * - * 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 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 <http://www.gnu.org/licenses/>. - * #L% - */ -package org.chorem.pollen.ui.actions.poll; - -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.opensymphony.xwork2.Preparable; -import org.apache.commons.collections.MapUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.struts2.interceptor.ParameterAware; -import org.chorem.pollen.bean.ChoiceHelper; -import org.chorem.pollen.bean.PollDateChoice; -import org.chorem.pollen.bean.PollImageChoice; -import org.chorem.pollen.business.persistence.Choice; -import org.chorem.pollen.business.persistence.ChoiceImpl; -import org.chorem.pollen.business.persistence.PersonToList; -import org.chorem.pollen.business.persistence.PersonToListImpl; -import org.chorem.pollen.business.persistence.Poll; -import org.chorem.pollen.business.persistence.PollAccount; -import org.chorem.pollen.business.persistence.PollAccountImpl; -import org.chorem.pollen.business.persistence.PreventRule; -import org.chorem.pollen.business.persistence.UserAccount; -import org.chorem.pollen.business.persistence.VotingList; -import org.chorem.pollen.business.persistence.VotingListImpl; -import org.chorem.pollen.common.ChoiceType; -import org.chorem.pollen.common.I18nAble; -import org.chorem.pollen.common.PollType; -import org.chorem.pollen.common.VoteCountingType; -import org.chorem.pollen.services.impl.PollService; -import org.chorem.pollen.services.impl.PreventRuleService; -import org.chorem.pollen.ui.actions.FileUploadAware; -import org.chorem.pollen.ui.actions.PollenActionSupport; -import org.nuiton.util.StringUtil; - -import java.io.File; -import java.text.ParseException; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Creates a new poll. - * - * @author tchemit <chemit@codelutin.com> - * @since 1.2.6 - */ -public class CreatePoll extends PollenActionSupport implements Preparable, ParameterAware, FileUploadAware { - - private static final long serialVersionUID = 1L; - - /** Logger. */ - private static final Log log = LogFactory.getLog(CreatePoll.class); - - public static final Pattern TEXT_CHOICE_NAME_PATTERN = - Pattern.compile("textChoice_(\\d+)\\.name"); - - public static final Pattern DATE_CHOICE_NAME_PATTERN = - Pattern.compile("dateChoice_(\\d+)\\.name"); - - public static final Pattern IMAGE_CHOICE_NAME_PATTERN = - Pattern.compile("imageChoice_(\\d+)\\.name"); - - public static final Pattern VOTING_LIST_NAME_PATTERN = - Pattern.compile("votingList_(\\d+)\\.name"); - - protected Poll poll; - - protected Map<String, String> pollTypes; - - protected Map<String, String> voteCountingTypes; - - protected Map<String, String> choiceTypes; - - protected boolean notification; - - protected boolean reminder; - - protected boolean limitChoice; - - protected int reminderHourCountdown = 2; - - private String textChoiceTokenId; - - private String dateChoiceTokenId; - - private String imageChoiceTokenId; - - private String votingListTokenId; - - private int nbTextChoices; - - private int nbDateChoices; - - private int nbImageChoices; - - private int nbVotingLists; - - /** Uploaded images (for choice type poll). */ - private List<File> imageChoice; - - /** Uploaded images content type (for choice type poll). */ - private List<String> imageChoiceContentType; - - /** Uploaded images name (from use desktop) (for choice type poll). */ - private List<String> imageChoiceFileName; - - /** - * All the parameters send by request used to build back choices of the - * poll. - */ - protected Map<String, String[]> parameters; - - private boolean informationsError; - - private boolean optionsError; - - protected transient PollService pollService; - - @Override - public String getPageLogo() { - return "Creation"; - } - - public Poll getPoll() { - if (poll == null) { - // create poll - UserAccount userAccount = getPollenUserAccount(); - poll = getPollService().getNewPoll(userAccount); - } - return poll; - } - - public int getNbTextChoices() { - return nbTextChoices; - } - - public String getTextChoiceTokenId() { - return textChoiceTokenId; - } - - public int getNbDateChoices() { - return nbDateChoices; - } - - public String getDateChoiceTokenId() { - return dateChoiceTokenId; - } - - public int getNbImageChoices() { - return nbImageChoices; - } - - public String getImageChoiceTokenId() { - return imageChoiceTokenId; - } - - public int getNbVotingLists() { - return nbVotingLists; - } - - public String getVotingListTokenId() { - return votingListTokenId; - } - - public Map<String, String> getPollTypes() { - return pollTypes; - } - - public Map<String, String> getVoteCountingTypes() { - return voteCountingTypes; - } - - public Map<String, String> getChoiceTypes() { - return choiceTypes; - } - - public boolean isNotification() { - return notification; - } - - public void setNotification(boolean notification) { - this.notification = notification; - } - - public boolean isReminder() { - return reminder; - } - - public void setReminder(boolean reminder) { - this.reminder = reminder; - } - - public boolean isLimitChoice() { - return limitChoice; - } - - public void setLimitChoice(boolean limitChoice) { - this.limitChoice = limitChoice; - } - - public int getReminderHourCountdown() { - return reminderHourCountdown; - } - - public void setReminderHourCountdown(int reminderHourCountdown) { - this.reminderHourCountdown = reminderHourCountdown; - } - - @Override - public void setFiles(String paramName, List<File> files) { - this.imageChoice = Lists.newArrayList(files); - } - - @Override - public void setFileContentTypes(String paramName, List<String> contentTypes) { - this.imageChoiceContentType = Lists.newArrayList(contentTypes); - } - - @Override - public void setFileNames(String paramName, List<String> fileNames) { - this.imageChoiceFileName = Lists.newArrayList(fileNames); - } - - public List<File> getImageChoice() { - if (imageChoice == null) { - imageChoice = Lists.newArrayList(); - } - return imageChoice; - } - - public List<String> getImageChoiceContentType() { - if (imageChoiceContentType == null) { - imageChoiceContentType = Lists.newArrayList(); - } - return imageChoiceContentType; - } - - public List<String> getImageChoiceFileName() { - if (imageChoiceFileName == null) { - imageChoiceFileName = Lists.newArrayList(); - } - return imageChoiceFileName; - } - - public boolean isInformationsError() { - return informationsError; - } - - public boolean isOptionsError() { - return optionsError; - } - - public boolean isFreePoll() { - PollType pollType = poll.getPollType(); - return pollType == PollType.FREE; - } - - public boolean isGroupPoll() { - PollType pollType = poll.getPollType(); - return pollType == PollType.GROUP; - } - - public String getPollVoteUrl() { - return getPollService().getPollVoteUrl(poll); - } - - public String getPollEditUrl() { - return getPollService().getPollEditUrl(poll); - } - - public int getSelectedTab() { - int result; - if (isInformationsError()) { - result = 0; - } else { - if (isOptionsError()) { - result = 1; - } else { - result = 0; - } - } - return result; - } - - protected int getNbChoices() { - //TODO tchemit-2012-03-05 use a default value from configuration - return 5; - } - - protected int getDefaultNbVotingLists() { - return 1; - } - - @Override - public void prepare() throws Exception { - - // remove all stuff from session - getPollenSession().clearDynamicData(); - - pollTypes = decorateToName(PollType.values()); - choiceTypes = decorateToName(ChoiceType.values()); - voteCountingTypes = decorateToName(VoteCountingType.values()); - - nbTextChoices = nbDateChoices = nbImageChoices = getNbChoices(); - nbVotingLists = getDefaultNbVotingLists(); - - String tokenSuffix = getServiceContext().createPollenUrlId(); - - textChoiceTokenId = DisplayTextChoice.CHOICE_TOKEN + "_" + - tokenSuffix; - - dateChoiceTokenId = DisplayDateChoice.CHOICE_TOKEN + "_" + - tokenSuffix; - - imageChoiceTokenId = DisplayImageChoice.CHOICE_TOKEN + "_" + - tokenSuffix; - - ChoiceType pollChoiceType; - // Retrieve choiceType from parameters, the poll object will be updated after prepare - String choiceTypeParam = getNonEmptyParameterValue("poll.choiceType"); - if (choiceTypeParam == null) { - - // Default value will be initiliazed on poll instanciation - pollChoiceType = getPoll().getChoiceType(); - - } else { - pollChoiceType = ChoiceType.valueOf(choiceTypeParam); - } - - if (log.isInfoEnabled()) { - log.info("choice type " + pollChoiceType); - } - - Map<Integer, Choice> choices = null; - String tokenId = null; - - switch (pollChoiceType) { - case TEXT: - choices = buildTextChoices(nbTextChoices); - tokenId = textChoiceTokenId; - break; - case DATE: - choices = buildDateChoices(nbDateChoices); - tokenId = dateChoiceTokenId; - break; - case IMAGE: - choices = buildImageChoices(nbImageChoices); - tokenId = imageChoiceTokenId; - break; - } - getPollenSession().putDynamicData(tokenId, choices); - - // load votingLists - - votingListTokenId = DisplayVotingList.VOTING_LIST_TOKEN + "_" + - tokenSuffix; - Map<Integer, VotingList> votingLists = buildVotingLists(nbVotingLists); - getPollenSession().putDynamicData(votingListTokenId, votingLists); - } - - @Override - public void validate() { - - Preconditions.checkNotNull(poll); - - informationsError = false; - - // poll must have a title - if (StringUtils.isEmpty(poll.getTitle())) { - addFieldError("poll.title", _("pollen.error.poll.required.title")); - } - - - // validate choices - Map<Integer, Choice> orderedChoices = getOrderedChoices(); - - if (MapUtils.isEmpty(orderedChoices)) { - - // poll must have at least one choice - addFieldError("poll.choices", - _("pollen.error.poll.required.one.choice")); - } else { -// -// //TODO tchemit improve this (from different cases text-date-image) -// // check there is no choice with same name -// boolean duplicateNameDetected = false; -// Set<String> names = Sets.newHashSet(); -// for (Choice choice : orderedChoices.values()) { -// String choiceName = choice.getName(); -// if (!names.add(choiceName)) { -// duplicateNameDetected = true; -// break; -// } -// } -// if (duplicateNameDetected) { -// addFieldError("poll.choices", -// _("pollen.error.poll.detected.duplicate.choice.name")); -// } - - ChoiceType choiceType = poll.getChoiceType(); - int inputChoicesSize = orderedChoices.size(); - Set<Object> choiceValues = - Sets.newHashSet(ChoiceHelper.toValues(orderedChoices.values(), choiceType)); - - if (inputChoicesSize > choiceValues.size()) { - addFieldError("poll.choices", - _("pollen.error.poll.detected.duplicate.choice.name")); - } - } - - - optionsError = false; - - // validate security stuff - - if (isFreePoll()) { - - // nothing to validate - - } else { - Map<Integer, VotingList> votingLists = getOrderedVotingLists(); - - Set<String> groups = Sets.newHashSet(); - Set<String> voters = Sets.newHashSet(); - Set<String> emails = Sets.newHashSet(); - - for (Map.Entry<Integer, VotingList> entry : votingLists.entrySet()) { - optionsError |= validateVotingList(entry.getKey(), - entry.getValue(), - groups, - voters, - emails); - } - } - - informationsError = hasFieldErrors(); - - if (!informationsError && optionsError) { - - // trick to force to go back to form - addFieldError("", ""); - } - } - - @Override - public String execute() throws Exception { - - Map<Integer, Choice> orderedChoices = getOrderedChoices(); - - for (Integer index : orderedChoices.keySet()) { - Choice choice = orderedChoices.get(index); - poll.addChoice(choice); - } - - if (!isFreePoll()) { - - Map<Integer, VotingList> votingLists = getOrderedVotingLists(); - for (Integer index : votingLists.keySet()) { - VotingList votingList = votingLists.get(index); - poll.addVotingList(votingList); - } - } - - PollService service = getPollService(); - - PreventRuleService preventRuleService = - newService(PreventRuleService.class); - if (isNotification()) { - - // add a notification rule - - PreventRule rule = preventRuleService.createAddVotePreventRule(); - poll.addPreventRule(rule); - } - - if (isReminder()) { - - // add a reminder rule - - PreventRule rule = preventRuleService.createRemindPreventRule( - getReminderHourCountdown() - ); - - poll.addPreventRule(rule); - } - - poll = service.createPoll(poll); - - // remove all stuff from session - getPollenSession().clearDynamicData(); - - addActionMessage(_("pollen.information.poll.created")); - return SUCCESS; - } - - protected boolean validateVotingList(int votingListNumber, - VotingList votingList, - Set<String> groups, - Set<String> voters, - Set<String> emails) { - - boolean result = false; - Map<String, String> errors = Maps.newHashMap(); - - String votingListErrorPrefix = "poll.votingList_" + votingListNumber; - - if (isGroupPoll()) { - - // group poll - - // check there is at least one group - // check no doublon on group names - // check there is at least one voter on each group - // check no doublon on voter names - // check no doublon on voter emails - - { // validate votingList name - String votingListName = votingList.getName(); - - if (StringUtils.isEmpty(votingListName)) { - - errors.put(votingListErrorPrefix + ".name", - _("pollen.error.poll.required.votingList.name")); - } else { - - // check no votingList name doublon - boolean add = groups.add(votingListName); - if (!add) { - - // name doublon - errors.put( - votingListErrorPrefix + ".name", - _("pollen.error.poll.votingList.name.doublon")); - } - - } - } - - { // validate votingList weight - - if (votingList.getWeight() == 0) { - - // no weight filled (can be a bad conversion) - errors.put( - votingListErrorPrefix + ".weight", - _("pollen.error.poll.votingList.weight.not.valid")); - } - } - } - - // check there is at least one voter - - String persontoListToken = DisplayPersonToList.getPersonToListTokenId( - votingListTokenId, votingListNumber); - - Map<Integer, PersonToList> personToLists = - getPollenSession().getDynamicData(persontoListToken); - - if (MapUtils.isEmpty(personToLists)) { - - // no personToList found for unique votingList 0 - errors.put(votingListErrorPrefix, - _("pollen.error.poll.required.one.personToList")); - } else { - - // check no doublon on voter names - // check no doublon on voter emails - - for (Map.Entry<Integer, PersonToList> entry : - personToLists.entrySet()) { - - result |= validatePersonList(entry.getKey(), entry.getValue(), - voters, emails); - } - } - - if (MapUtils.isNotEmpty(errors)) { - - // keep errors to display them in correct action - String errorToken = DisplayVotingList.getVotingListErrorTokenId( - votingListTokenId, votingListNumber); - if (log.isInfoEnabled()) { - log.info("Add " + errors.size() + " errors to " + errorToken); - } - getPollenSession().putDynamicData(errorToken, errors); - result = true; - } - return result; - } - - protected boolean validatePersonList(int personToListNumber, - PersonToList personToList, - Set<String> voters, - Set<String> emails) { - - boolean result = false; - Map<String, String> errors = Maps.newHashMap(); - String fieldNamePrefix = - "personToList_0_" + personToListNumber; - PollAccount pollAccount = personToList.getPollAccount(); - - { // validate votingId - - String votingId = pollAccount.getVotingId(); - // check voter is not doublon - boolean add = voters.add(votingId); - if (!add) { - - // voter doublon - errors.put( - fieldNamePrefix + ".votingId", - _("pollen.error.poll.personToList.votingId.doublon")); - } - } - { // validate email - String email = pollAccount.getEmail(); - - if (StringUtils.isEmpty(email)) { - errors.put( - fieldNamePrefix + ".email", - _("pollen.error.poll.personToList.email.required")); - } else { - - - boolean validEmail = StringUtil.isEmail(email); - if (!validEmail) { - - // not a valid email - errors.put( - fieldNamePrefix + ".email", - _("pollen.error.poll.personToList.email.not.valid")); - } else { - - // check email not doublon - boolean add = emails.add(email); - if (!add) { - - // email doublon - errors.put( - fieldNamePrefix + ".email", - _("pollen.error.poll.personToList.email.doublon")); - } - } - } - } - { // validate weight - if (personToList.getWeight() == 0) { - - // no weight filled (can be a bad conversion) - errors.put( - fieldNamePrefix + ".weight", - _("pollen.error.poll.personToList.weight.not.valid")); - } - } - - if (MapUtils.isNotEmpty(errors)) { - String errorToken = - DisplayPersonToList.getPersonToListErrorTokenId( - votingListTokenId, 0, personToListNumber); - if (log.isInfoEnabled()) { - log.info("Add " + errors.size() + " errors to " + errorToken); - } - getPollenSession().putDynamicData(errorToken, errors); - result = true; - } - return result; - } - - @Override - public void setParameters(Map<String, String[]> parameters) { - this.parameters = parameters; - } - - protected PollService getPollService() { - if (pollService == null) { - pollService = newService(PollService.class); - } - return pollService; - } - - protected Map<Integer, Choice> getOrderedChoices() { - Map<Integer, Choice> result = null; - switch (poll.getChoiceType()) { - case TEXT: - result = getPollenSession().getDynamicData(textChoiceTokenId); - break; - case DATE: - result = getPollenSession().getDynamicData(dateChoiceTokenId); - break; - case IMAGE: - result = getPollenSession().getDynamicData(imageChoiceTokenId); - break; - } - return result; - } - - protected Map<Integer, VotingList> getOrderedVotingLists() { - - Map<Integer, VotingList> result = getPollenSession().getDynamicData( - votingListTokenId); - return result; - } - - protected Map<Integer, Choice> buildTextChoices(int nbDefault) { - Map<Integer, Choice> result = Maps.newTreeMap(); - - int maxNumber = 0; - - for (String paramName : parameters.keySet()) { - - Matcher matcher = TEXT_CHOICE_NAME_PATTERN.matcher(paramName); - if (matcher.matches()) { - - // found a text choice name - - String paramValue = getNonEmptyParameterValue(paramName); - if (paramValue != null) { - - // can keep this none empty text choice name - - Integer choiceNumber = Integer.valueOf(matcher.group(1)); - if (choiceNumber > maxNumber) { - maxNumber = choiceNumber; - } - Choice choice = new ChoiceImpl(); - createChoice(choice, "textChoice_" + choiceNumber, - paramValue); - result.put(choiceNumber, choice); - } - } - } - result = reindexMap(result, maxNumber); - - int size = result.size(); - nbTextChoices = Math.max(nbDefault, size); - log.info("nbTextChoices (from request) = " + size); - logChoice(result); - return result; - } - - protected Map<Integer, Choice> buildDateChoices(int nbDefault) { - Map<Integer, Choice> result = Maps.newTreeMap(); - - int maxNumber = 0; - for (String paramName : parameters.keySet()) { - - Matcher matcher = DATE_CHOICE_NAME_PATTERN.matcher(paramName); - if (matcher.matches()) { - - // found a text choice name - - String paramValue = getNonEmptyParameterValue(paramName); - if (paramValue != null) { - - // can keep this none empty text choice name - - Integer choiceNumber = Integer.valueOf(matcher.group(1)); - if (choiceNumber > maxNumber) { - maxNumber = choiceNumber; - } - PollDateChoice choice = new PollDateChoice(); - createDateChoice(choice, - "dateChoice_" + choiceNumber, - paramValue); - result.put(choiceNumber, choice); - } - } - } - result = reindexMap(result, maxNumber); - - int size = result.size(); - nbDateChoices = Math.max(nbDefault, size); - log.info("nbDateChoices (from request) = " + size); - logChoice(result); - return result; - } - - protected Map<Integer, Choice> buildImageChoices(int nbDefault) { - Map<Integer, Choice> result = Maps.newTreeMap(); - - // push back in parameters stuff from uploaded files - int index = 0; - - for (String fileName : getImageChoiceFileName()) { - if (fileName != null) { - parameters.put("imageChoice_" + index + ".name", - new String[]{fileName}); - parameters.put( - "imageChoice_" + index + ".location", - new String[]{getImageChoice().get(index).getAbsolutePath()}); - } - index++; - } - - int maxNumber = 0; - for (String paramName : parameters.keySet()) { - - Matcher matcher = IMAGE_CHOICE_NAME_PATTERN.matcher(paramName); - if (matcher.matches()) { - - // found an image choice name - - String paramValue = getNonEmptyParameterValue(paramName); - if (paramValue != null) { - - // can keep this none empty text choice name - - Integer choiceNumber = Integer.valueOf(matcher.group(1)); - if (choiceNumber > maxNumber) { - maxNumber = choiceNumber; - } - PollImageChoice choice = new PollImageChoice(); - createImageChoice(choice, - "imageChoice_" + choiceNumber, - paramValue); - - result.put(choiceNumber, choice); - } - } - } - result = reindexMap(result, maxNumber); - int size = result.size(); - nbImageChoices = Math.max(nbDefault, size); - log.info("nbImageChoices (from request) = " + size); - logChoice(result); - return result; - } - - protected Map<Integer, VotingList> buildVotingLists(int nbDefault) { - Map<Integer, VotingList> result = Maps.newTreeMap(); - - int maxNumber = 0; - - // get all votingList_ parameters - Set<String> votingListParameterNames = Sets.filter( - parameters.keySet(), - new StringStartWithPredicate("votingList_")); - - for (String paramName : votingListParameterNames) { - - Matcher matcher = VOTING_LIST_NAME_PATTERN.matcher(paramName); - - if (matcher.matches()) { - - // found a voting list name - - int votingListNumber = buildVotingList(paramName, - matcher, - result - ); - maxNumber = Math.max(maxNumber, votingListNumber); - } - } - - result = reindexMap(result, maxNumber); - - int size = result.size(); - nbVotingLists = Math.max(nbDefault, size); - log.info("nbVotingList (from request) = " + size); - - // add personToList maps to session (but just now, since votingList - // could have been reindex) - for (Map.Entry<Integer, VotingList> entry : result.entrySet()) { - Integer votingListNumber = entry.getKey(); - VotingList votingList = entry.getValue(); - - if (!votingList.isPollAccountPersonToListEmpty()) { - List<PersonToList> personToList = - votingList.getPollAccountPersonToList(); - - Map<Integer, PersonToList> personToListMap = Maps.newTreeMap(); - int index = 0; - for (PersonToList toList : personToList) { - personToListMap.put(index++, toList); - } - - String token = DisplayPersonToList.getPersonToListTokenId( - votingListTokenId, votingListNumber); - if (log.isInfoEnabled()) { - log.info("Add " + token + " with " + - personToListMap.size() + " personToList"); - } - getPollenSession().putDynamicData(token, personToListMap); - } - } - - return result; - } - - private double getDoubleValue(String parameterName) { - String parameterValue = getNonEmptyParameterValue(parameterName); - double result = 0; - if (StringUtils.isNotEmpty(parameterValue)) { - - try { - result = Double.valueOf(parameterValue); - } catch (NumberFormatException e) { - //bad conversion, will be treated later - if (log.isDebugEnabled()) { - log.debug("Bad double conversion from param [" + - parameterName + "] : " + parameterValue); - } - } - } - return result; - } - - private int buildVotingList(String votingListParameterName, - Matcher votingListMatcher, - Map<Integer, VotingList> result) { - - String paramValue = getNonEmptyParameterValue(votingListParameterName); - int votingListNumber = Integer.valueOf(votingListMatcher.group(1)); - - VotingList votingList = new VotingListImpl(); - - votingList.setName(paramValue); - - String prefix = "votingList_" + votingListNumber; - - double weight = getDoubleValue(prefix + ".weight"); - votingList.setWeight(weight); - - String topiaId = getNonEmptyParameterValue(prefix + ".topiaId"); - votingList.setTopiaId(topiaId); - - result.put(votingListNumber, votingList); - - String personToListPrefix = "personToList_" + votingListNumber + "_"; - - // get all personToList parameters - Set<String> votingListParameterNames = Sets.filter( - parameters.keySet(), new StringStartWithPredicate(personToListPrefix)); - - Pattern personToListNamePattern = Pattern.compile( - personToListPrefix + "(\\d+)\\.votingId"); - - Map<Integer, PersonToList> personToLists = Maps.newTreeMap(); - - int maxPersonToListNumber = 0; - - // let's build personToList list - for (String personToListNameParameter : votingListParameterNames) { - - Matcher matcher = personToListNamePattern.matcher( - personToListNameParameter); - - if (matcher.matches()) { - - int personToListNumber = buildPersonToList( - personToListPrefix, - personToListNameParameter, - matcher, - votingListNumber, - personToLists); - - maxPersonToListNumber = Math.max(maxPersonToListNumber, personToListNumber); - } - } - - personToLists = reindexMap(personToLists, maxPersonToListNumber); - - for (PersonToList personToList : personToLists.values()) { - votingList.addPollAccountPersonToList(personToList); - } - - return votingListNumber; - } - - private int buildPersonToList(String personToListPrefix, - String paramName, - Matcher personToListMatcher, - int votingListNumber, - Map<Integer, PersonToList> result) { - - String paramValue = getNonEmptyParameterValue(paramName); - - int personToListNumber = 0; - - if (paramValue != null) { - - // found a PersonToList none empty name, keep it - - personToListNumber = Integer.valueOf(personToListMatcher.group(1)); - - PersonToList personToList = new PersonToListImpl(); - - PollAccount account = new PollAccountImpl(); - personToList.setPollAccount(account); - - account.setVotingId(paramValue); - - String prefix = personToListPrefix + personToListNumber; - - double weight = getDoubleValue(prefix + ".weight"); - personToList.setWeight(weight); - - String topiaId = getNonEmptyParameterValue(prefix + ".topiaId"); - personToList.setTopiaId(topiaId); - - String email = getNonEmptyParameterValue(prefix + ".email"); - account.setEmail(email); - - String accountId = getNonEmptyParameterValue(prefix + ".accountId"); - account.setAccountId(accountId); - - result.put(personToListNumber, personToList); - } - return personToListNumber; - } - - private Choice createImageChoice(PollImageChoice choice, - String prefix, - String name) { - createChoice(choice, prefix, name); - String locationName = prefix + ".location"; - String location = getNonEmptyParameterValue(locationName); - choice.setLocation(location); - if (log.isInfoEnabled()) { - log.info("image location [" + name + "] =" + location); - } - return choice; - } - - private Choice createDateChoice(PollDateChoice choice, - String prefix, - String name) { - createChoice(choice, prefix, name); - if (StringUtils.isNotEmpty(name)) { - Date date = null; - try { - date = parseDateTime(name); - } catch (ParseException e) { - if (log.isErrorEnabled()) { - log.error("Unparseable date " + name, e); - } - } - choice.setDate(date); - } - return choice; - } - - private Choice createChoice(Choice choice, String prefix, String name) { - String descriptionName = prefix + ".description"; - String topiaIdName = prefix + ".topiaId"; - String description = getNonEmptyParameterValue(descriptionName); - String topiaId = getNonEmptyParameterValue(topiaIdName); - choice.setName(name); - choice.setDescription(description); - choice.setTopiaId(topiaId); - return choice; - } - - private void logChoice(Map<Integer, Choice> result) { - for (Map.Entry<Integer, Choice> e : result.entrySet()) { - Integer choiceId = e.getKey(); - Choice choice = e.getValue(); - if (log.isInfoEnabled()) { - log.info("Choice [" + choiceId + "] = " + - choice.getName() + " -- " + - choice.getDescription()); - } - } - } - - - private <T> Map<Integer, T> reindexMap(Map<Integer, T> result, int maxNumber) { - Map<Integer, T> result2; - - if (maxNumber != result.size() - 1) { - - // means there is a hole inside the result (a empty choice was - // submitted) - - // le'ts remove this - List<Integer> numbers = Lists.newArrayList(result.keySet()); - - Collections.sort(numbers); - - result2 = Maps.newTreeMap(); - int i = 0; - for (Integer number : numbers) { - T choice = result.get(number); - result2.put(i++, choice); - } - } else { - result2 = result; - } - return result2; - } - - private <O> void addtoList(List<O> list, int index, O object) { - - while (list.size() < index) { - list.add(null); - } - list.add(index, object); - } - - - private String getNonEmptyParameterValue(String paramName) { - String[] paramValues = parameters.get(paramName); - String result = null; - if (paramValues != null && paramValues.length == 1) { - String paramValue = paramValues[0]; - if (StringUtils.isNotEmpty(paramValue)) { - result = paramValue; - } - } - return result; - } - - private <E extends Enum<E> & I18nAble> Map<String, String> decorateToName(E... values) { - Map<String, String> result = Maps.newLinkedHashMap(); - for (E value : values) { - result.put(value.name(), getText(value.getI18nKey())); - } - return result; - } - - private static class StringStartWithPredicate implements Predicate<String> { - private final String prefix; - - public StringStartWithPredicate(String prefix) { - this.prefix = prefix; - } - - @Override - public boolean apply(String input) { - return input.startsWith(prefix); - } - } -} Deleted: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/EditPoll.java =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/EditPoll.java 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/EditPoll.java 2012-04-05 07:50:32 UTC (rev 3233) @@ -1,76 +0,0 @@ -/* - * #%L - * Pollen :: UI (strust2) - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2009 - 2012 CodeLutin, Tony Chemit - * %% - * 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. - * - * 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 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 <http://www.gnu.org/licenses/>. - * #L% - */ -package org.chorem.pollen.ui.actions.poll; - -import org.chorem.pollen.ui.actions.PollUriConverter; - -import java.util.Map; - -/** - * Edit a poll. - * - * @author tchemit <chemit@codelutin.com> - * @author fdesbois <desbois@codelutin.com> - * @since 1.2.6 - */ -public class EditPoll extends ClonePoll { - - private static final long serialVersionUID = 1L; - - protected void preparePollUri(Map<String, String[]> parameters) { - if (pollUri == null) { - String[] values = parameters.get("uriId"); - pollUri = PollUriConverter.convertFromString(values); - } - } - - @Override - protected boolean keepTopiaId() { - return true; - } - - public boolean isVoteStarted() { - return getPoll().sizeVote() > 0; - } - - @Override - public void prepare() throws Exception { - - preparePollUri(parameters); - - super.prepare(); - } - - @Override - public String execute() throws Exception { - -// getPollService().updatePoll(poll): - - // remove all stuff from session - getPollenSession().clearDynamicData(); - - addActionMessage(_("pollen.information.poll.updated")); - return SUCCESS; - } -} Copied: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/LoadPoll.java (from rev 3232, branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/ClonePoll.java) =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/LoadPoll.java (rev 0) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/LoadPoll.java 2012-04-05 07:50:32 UTC (rev 3233) @@ -0,0 +1,213 @@ +package org.chorem.pollen.ui.actions.poll; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.chorem.pollen.bean.PollImageChoice; +import org.chorem.pollen.bean.PollUri; +import org.chorem.pollen.business.persistence.Choice; +import org.chorem.pollen.business.persistence.PersonToList; +import org.chorem.pollen.business.persistence.Poll; +import org.chorem.pollen.business.persistence.PollAccount; +import org.chorem.pollen.business.persistence.UserAccount; +import org.chorem.pollen.business.persistence.VotingList; +import org.chorem.pollen.common.ChoiceType; +import org.chorem.pollen.common.PollType; + +import java.util.List; + +/** + * Created: 04/04/12 + * + * @author fdesbois <desbois@codelutin.com> + */ +public class LoadPoll extends AbstractPollForm { + + private static final String PREFIX_CHOICE = "%sChoice_%d"; + + private static final String PREFIX_VOTING_LIST = "votingList_%d"; + + private static final String PREFIX_PERSON_TO_LIST = "personToList_%d_%d"; + + private PollUri pollUri; + + private boolean clone; + + public PollUri getUriId() { + return pollUri; + } + + public void setUriId(PollUri pollUri) { + this.pollUri = pollUri; + } + + public boolean isClone() { + return clone; + } + + public void setClone(boolean clone) { + this.clone = clone; + } + + @Override + protected Poll initPoll() { + Poll result; + if (pollUri != null) { + result = getPollService().getPollByPollId(pollUri.getPollId()); + + if (clone) { + result.setTopiaId(null); + + // Use a new pollUid + String pollUid = serviceContext.createPollenUrlId(); + result.setPollId(pollUid); + } + + } else { + + UserAccount userAccount = getPollenUserAccount(); + result = getPollService().getNewPoll(userAccount); + } + return result; + } + + @Override + public String input() throws Exception { + + if (pollUri != null) { + + // -- Choice -- // + ChoiceType choiceType = getPoll().getChoiceType(); + prepareParams(getPoll().getChoice(), withChoicePrefix(choiceType)); + + // -- VotingList -- // + if (getPoll().getPollType() != PollType.FREE) { + prepareParams(getPoll().getVotingList(), withVotingListPrefix()); + } + } + + prepareFormPage(); + + return INPUT; + } + + private Function<Choice, String> withChoicePrefix(final ChoiceType choiceType) { + final String choiceTypeName = choiceType.name().toLowerCase(); + return new IndexedFunction<Choice, String>() { + + @Override + protected String apply(Choice input, int index) { + + String prefix = String.format(PREFIX_CHOICE, choiceTypeName, index); + if (!clone) { + putParameter(prefix, Choice.TOPIA_ID, input.getTopiaId()); + } + putParameter(prefix, Choice.PROPERTY_NAME, input.getName()); + putParameter(prefix, Choice.PROPERTY_DESCRIPTION, input.getDescription()); + + if (choiceType == ChoiceType.IMAGE) { + putParameter(prefix, PollImageChoice.PROPERTY_LOCATION, input.getName()); + } + + return prefix; + } + }; + } + + private Function<VotingList, String> withVotingListPrefix() { + return new IndexedFunction<VotingList, String>() { + + @Override + protected String apply(VotingList input, int index) { + + String prefix = String.format(PREFIX_VOTING_LIST, index); + if (!clone) { + putParameter(prefix, VotingList.TOPIA_ID, input.getTopiaId()); + } + putParameter(prefix, VotingList.PROPERTY_NAME, input.getName()); + putParameter(prefix, VotingList.PROPERTY_WEIGHT, String.valueOf(input.getWeight())); + + prepareParams(input.getPollAccountPersonToList(), withPersonToListPrefix(index)); + + return prefix; + } + }; + } + + private Function<PersonToList, String> withPersonToListPrefix(final int votingListIndex) { + return new IndexedFunction<PersonToList, String>() { + + @Override + protected String apply(PersonToList input, int index) { + + PollAccount pollAccount = input.getPollAccount(); + + String prefix = String.format(PREFIX_PERSON_TO_LIST, votingListIndex, index); + if (!clone) { + putParameter(prefix, PersonToList.TOPIA_ID, input.getTopiaId()); + } + putParameter(prefix, PersonToList.PROPERTY_WEIGHT, String.valueOf(input.getWeight())); + putParameter(prefix, PollAccount.PROPERTY_ACCOUNT_ID, pollAccount.getAccountId()); + putParameter(prefix, PollAccount.PROPERTY_VOTING_ID, pollAccount.getVotingId()); + putParameter(prefix, PollAccount.PROPERTY_EMAIL, pollAccount.getEmail()); + + return prefix; + } + }; + } + + /** + * Prepare the {@code source} for parameters using the {@code function} to + * push necessary data. + * + * @param source List of elements + * @param function Function used to push element data using {@link #putParameter(String, String, String)} + * @param <T> Type of data + * @see #putParameter(String, String, String) + */ + private <T> void prepareParams(List<T> source, Function<T, String> function) { + ImmutableList.copyOf(Lists.transform(source, function)); + } + + /** + * Put some data in the {@code parameters} with name built using + * {@code prefix} and {@code property}. The {@code value} will be put for + * this parameter. + * + * @param prefix Prefix to use for the parameter name + * @param property Name of the {@code property} to push in parameters + * @param value Value of this {@code property} + */ + private void putParameter(String prefix, String property, String value) { + parameters.put(prefix + "." + property, new String[]{value}); + } + + /** + * Guava {@link Function} that keeps index on each {@link Function#apply(Object)} call. + * You just have to implement {@link #apply(Object, int)} to have the current + * index of the {@code input} value. + * + * @param <F> Type of data where function will be applied on + * @param <T> Resulting type + */ + private abstract static class IndexedFunction<F, T> implements Function<F, T> { + + private int index; + + @Override + public T apply(F input) { + T result = apply(input, index); + index++; + return result; + } + + /** + * Called during {@link #apply(Object)} method with current {@code index}. + * + * @param input current value + * @param index current index + * @return the result of the function applied on the {@code input} object + */ + protected abstract T apply(F input, int index); + } +} Added: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/SavePoll.java =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/SavePoll.java (rev 0) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/java/org/chorem/pollen/ui/actions/poll/SavePoll.java 2012-04-05 07:50:32 UTC (rev 3233) @@ -0,0 +1,122 @@ +/* + * #%L + * Pollen :: UI (strust2) + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2009 - 2012 CodeLutin, Tony Chemit + * %% + * 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. + * + * 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 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 <http://www.gnu.org/licenses/>. + * #L% + */ +package org.chorem.pollen.ui.actions.poll; + +import com.opensymphony.xwork2.Preparable; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.chorem.pollen.business.persistence.Choice; +import org.chorem.pollen.business.persistence.Poll; +import org.chorem.pollen.business.persistence.PreventRule; +import org.chorem.pollen.business.persistence.UserAccount; +import org.chorem.pollen.business.persistence.VotingList; +import org.chorem.pollen.services.impl.PollService; +import org.chorem.pollen.services.impl.PreventRuleService; + +import java.util.Map; + +/** + * Creates a new poll. + * + * @author tchemit <chemit@codelutin.com> + * @since 1.2.6 + */ +public class SavePoll extends AbstractPollForm implements Preparable { + + private static final long serialVersionUID = 1L; + + /** Logger. */ + private static final Log log = LogFactory.getLog(SavePoll.class); + + @Override + protected Poll initPoll() { + UserAccount userAccount = getPollenUserAccount(); + Poll result = getPollService().getNewPoll(userAccount); + return result; + } + + @Override + public void prepare() throws Exception { + + prepareFormPage(); + } + + @Override + public String execute() throws Exception { + + Poll poll = getPoll(); + + Map<Integer, Choice> orderedChoices = getOrderedChoices(); + + for (Integer index : orderedChoices.keySet()) { + Choice choice = orderedChoices.get(index); + poll.addChoice(choice); + } + + if (!isFreePoll()) { + + Map<Integer, VotingList> votingLists = getOrderedVotingLists(); + for (Integer index : votingLists.keySet()) { + VotingList votingList = votingLists.get(index); + poll.addVotingList(votingList); + } + } + + PollService service = getPollService(); + + PreventRuleService preventRuleService = + newService(PreventRuleService.class); + if (isNotification()) { + + // add a notification rule + + PreventRule rule = preventRuleService.createAddVotePreventRule(); + poll.addPreventRule(rule); + } + + if (isReminder()) { + + // add a reminder rule + + PreventRule rule = preventRuleService.createRemindPreventRule( + getReminderHourCountdown() + ); + + poll.addPreventRule(rule); + } + + if (isEdit()) { +// service.createPoll(poll); + + } else { + service.createPoll(poll); + } + + // remove all stuff from session + getPollenSession().clearDynamicData(); + + addActionMessage(_("pollen.information.poll.created")); + return SUCCESS; + } +} Modified: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/config/struts-poll.xml =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/config/struts-poll.xml 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/config/struts-poll.xml 2012-04-05 07:50:32 UTC (rev 3233) @@ -43,9 +43,9 @@ <!-- create poll --> <action name="create" - class="org.chorem.pollen.ui.actions.poll.CreatePoll"> + class="org.chorem.pollen.ui.actions.poll.LoadPoll" + method="input"> <result name="input">/WEB-INF/jsp/poll/create.jsp</result> - <result>/WEB-INF/jsp/poll/resume.jsp</result> </action> <!-- display * --> @@ -86,24 +86,25 @@ <!-- edit poll --> <action name="modification/*" - class="org.chorem.pollen.ui.actions.poll.EditPoll"> + class="org.chorem.pollen.ui.actions.poll.LoadPoll" + method="input"> <param name="uriId">{1}</param> <result name="input">/WEB-INF/jsp/poll/create.jsp</result> - <result>/WEB-INF/jsp/poll/resume.jsp</result> </action> - <!-- confirm clone poll --> - <action name="confirmClonePoll/*" - class="org.chorem.pollen.ui.actions.poll.ConfirmPollAction"> - <param name="uriId">{1}</param> - <result>/WEB-INF/jsp/poll/confirmClonePoll.jsp</result> - </action> - <!-- clone poll --> <action name="clone/*" - class="org.chorem.pollen.ui.actions.poll.ClonePoll"> + class="org.chorem.pollen.ui.actions.poll.LoadPoll" + method="input"> <param name="uriId">{1}</param> + <param name="clone">true</param> <result name="input">/WEB-INF/jsp/poll/create.jsp</result> + </action> + + <!-- save poll --> + <action name="save" + class="org.chorem.pollen.ui.actions.poll.SavePoll"> + <result name="input">/WEB-INF/jsp/poll/create.jsp</result> <result>/WEB-INF/jsp/poll/resume.jsp</result> </action> Modified: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_en_GB.properties =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_en_GB.properties 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_en_GB.properties 2012-04-05 07:50:32 UTC (rev 3233) @@ -179,8 +179,6 @@ pollen.fieldset.userInformation.toCreate=User informations to create pollen.fieldset.userInformation.toDelete=User informations to delete pollen.fieldset.userInformation.toUpdate=User informations to update -pollen.information.poll.created=Poll created -pollen.information.poll.updated=Poll modified pollen.information.confirmClonePoll=Confirm clone of poll\: pollen.information.confirmClosePoll=Confirm close of poll\: pollen.information.confirmDeleteChoice=Confirm delete of choice %s @@ -192,6 +190,8 @@ pollen.information.favoriteList.deleted=Favorite list %s deleted. pollen.information.irreversible.operation=Be ware, this operation is irreversible. pollen.information.need.login=You must be logged to access this page. Please fill the form below. +pollen.information.poll.created=Poll created +pollen.information.poll.updated=Poll modified pollen.information.pollAccount.addedTofavoriteList=Member '%s was added to favorite list. pollen.information.pollAccount.removedFromFavoriteList=Member %s was removed from favorite list. pollen.information.pollAccount.updatedTofavoriteList=Member %s was updated in favorite list. Modified: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_fr_FR.properties =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_fr_FR.properties 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/i18n/pollen-ui-struts2_fr_FR.properties 2012-04-05 07:50:32 UTC (rev 3233) @@ -186,8 +186,6 @@ pollen.fieldset.userInformation.toCreate=Informations de l'utilisateur à créer pollen.fieldset.userInformation.toDelete=Informations de l'utilisateur à supprimer pollen.fieldset.userInformation.toUpdate=Informations de l'utilisateur à mettre à jour -pollen.information.poll.created=Sondage créé -pollen.information.poll.updated=Sondage mise à jour pollen.information.confirmClonePoll=Confirmer le clonage du sondage \: pollen.information.confirmClosePoll=Confirmer la fermeture du sondage \: pollen.information.confirmDeleteFavoriteList=Confirmer la suppression de la liste de votants \: @@ -200,6 +198,8 @@ pollen.information.favoriteList.deleted=La liste %s a été supprimée. pollen.information.irreversible.operation=Attention, Cette opération est irréversible. pollen.information.need.login=Vous devez être identifié pour pouvoir accéder à cette page. Veuillez remplir le formulaire ci-dessous. +pollen.information.poll.created=Sondage créé +pollen.information.poll.updated=Sondage mise à jour pollen.information.pollAccount.addedTofavoriteList=Le membre %s a été ajoutée à la liste des favoris. pollen.information.pollAccount.removedFromFavoriteList=Le membre %s a été supprimé de la liste des favoris. pollen.information.pollAccount.updatedTofavoriteList=Le membre %s a été mise à jour dans la liste des favoris. Modified: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/shiro.ini =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/shiro.ini 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/resources/shiro.ini 2012-04-05 07:50:32 UTC (rev 3233) @@ -42,4 +42,5 @@ /poll/results/**=poll,pollAccess # is pollCreator (can admin a poll) -/poll/modification/**=poll,pollCreator \ No newline at end of file +/poll/modification/**=poll,pollCreator +/poll/clone/**=poll,pollCreator \ No newline at end of file Modified: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/poll/create.jsp =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/poll/create.jsp 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/poll/create.jsp 2012-04-05 07:50:32 UTC (rev 3233) @@ -322,7 +322,13 @@ </sj:tabbedpanel> <br/> - <s:submit action="create" key="pollen.action.createPoll" align="center"/> + <s:submit action="save" key="pollen.action.savePoll" value="%{actionLabel}" align="center"/> + + <!--<div id="wwctrl_registerForm_pollen_action_<s:property value='%{actionLabel}'/>Poll" align="center"> + <input type="submit" id="registerForm_pollen_action_<s:property value='%{actionLabel}'/>Poll" + name="action:<s:property value='%{actionName}'/>" + value="<s:text name='pollen.action.%{actionLabel}Poll'/>"/> + </div>--> </s:form> <script type="text/javascript"> Modified: branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/pollListHelper.jsp =================================================================== --- branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/pollListHelper.jsp 2012-04-03 18:16:13 UTC (rev 3232) +++ branches/pollen-1.2.6-struts2/pollen-ui-struts2/src/main/webapp/WEB-INF/jsp/pollListHelper.jsp 2012-04-05 07:50:32 UTC (rev 3233) @@ -40,7 +40,6 @@ <s:url id="editUrl" action="modification/" namespace="/poll"/> <s:url id='editImg' value='/img/edit.png'/> -<s:set id="editMethod" value="input"/> <s:set id='editTitle'><s:text name="pollen.action.pollEdit"/></s:set> <s:url id="closeUrl" action="confirmClosePoll/" namespace="/poll"/> @@ -53,7 +52,6 @@ <s:url id="cloneUrl" action="clone/" namespace="/poll"/> <s:url id='cloneImg' value='/img/copy.png'/> -<s:set id="cloneMethod" value="input"/> <s:set id='cloneTitle'><s:text name="pollen.action.pollClone"/></s:set> <s:url id="deleteUrl" action="confirmDeletePoll/" namespace="/poll"/> @@ -82,16 +80,6 @@ return false; } -// function confirmClone(id) { -// $('.ui-dialog-title').html("<s:text name="pollen.title.clone.poll"/>") -// var dialog = $("#confirmDialog"); -// var url = "<s:url action='confirmClonePoll/' namespace='/poll'/>"; -// url += id + '?' + $.param({redirectUrl:redirectUrl}); -// dialog.load(url); -// dialog.dialog('open'); -// return false; -// } - function pollFunctions(cellvalue, options, rowObject) { var id = rowObject.pollId; @@ -110,7 +98,7 @@ result += formatLink("${resultUrl}" + id, "${resultImg}", "Result", "${resultTitle}") } if (cellvalue.indexOf('edit') > -1) { - result += formatLink("${editUrl}" + adminId + "!${editMethod}", "${editImg}", "Edit", "${editTitle}") + result += formatLink("${editUrl}" + adminId, "${editImg}", "Edit", "${editTitle}") } if (cellvalue.indexOf('close') > -1) { var script = 'return confirmClose("' + adminId + '");' @@ -120,9 +108,7 @@ result += formatLink("${exportUrl}" + id, "${exportImg}", "Export", "${exportTitle}") } if (cellvalue.indexOf('clone') > -1) { -// var script = 'return confirmClone("' + adminId + '");' -// result += formatLinkByScript(script, "${cloneImg}", "Clone", "${cloneTitle}") - result += formatLink("${cloneUrl}" + id + "!${cloneMethod}", "${cloneImg}", "Clone", "${cloneTitle}") + result += formatLink("${cloneUrl}" + adminId, "${cloneImg}", "Clone", "${cloneTitle}") } if (cellvalue.indexOf('delete') > -1) { var script = 'return confirmDelete("' + adminId + '");'
participants (1)
-
fdesbois@users.chorem.org