Author: fdesbois Date: 2010-06-01 16:06:41 +0200 (Tue, 01 Jun 2010) New Revision: 3022 Url: http://chorem.org/repositories/revision/pollen/3022 Log: Vote is working. Creator can also delete votes. (only tested for free poll) Modified: trunk/doc/business-rules.rst trunk/pollen-business/src/main/java/org/chorem/pollen/PollenBusinessException.java trunk/pollen-business/src/main/java/org/chorem/pollen/PollenContextImpl.java trunk/pollen-business/src/main/java/org/chorem/pollen/service/ServiceVoteImpl.java trunk/pollen-business/src/main/resources/i18n/pollen-business-en_GB.properties trunk/pollen-business/src/main/resources/i18n/pollen-business-fr_FR.properties trunk/pollen-business/src/main/xmi/pollen.zargo trunk/pollen-business/src/test/java/org/chorem/pollen/service/ServiceVoteImplTest.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/components/Pager.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollForm.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollLinks.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/VoteForPoll.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/AppModule.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUri.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUriImpl.java trunk/pollen-ui/src/main/resources/i18n/pollen-ui-fr_FR.properties trunk/pollen-ui/src/main/webapp/css/common.css trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml Modified: trunk/doc/business-rules.rst =================================================================== --- trunk/doc/business-rules.rst 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/doc/business-rules.rst 2010-06-01 14:06:41 UTC (rev 3022) @@ -139,7 +139,7 @@ - Ajout d'un vote : pollUri = pollUid / participantUid (RESTRICTED/GROUP) ou null (FREE) - Modification d'un vote : pollUri = pollUid / participantUid ou ADMIN -- Suppression d'un vote : pollUri = pollUid / participantUid ou creatorUid ou ADMIN +- Suppression d'un vote : pollUri = pollUid / creatorUid ou ADMIN - Ajout d'un choix : même chose que pour l'ajout d'un vote - Suppression d'un choix : pollUri = pollUid / creatorUid ou ADMIN Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/PollenBusinessException.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/PollenBusinessException.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/PollenBusinessException.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -69,7 +69,15 @@ * Exception when doubloons ($2) are found when adding participants in a * list ($1). */ - PARTICIPANT_DOUBLOONS(n_("pollen.exception.participant_doubloons")); + PARTICIPANT_DOUBLOONS(n_("pollen.exception.participant_doubloons")), + /** + * Exception when doubloon are found on vote name ($1) + */ + VOTE_DOUBLOON(n_("pollen.exception.vote_doubloon")), + /** + * Exception when participant with uid ($1) can't vote + */ + VOTE_NOT_ALLOWED(n_("pollen.exception.vote_not_allowed")); private String message; Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/PollenContextImpl.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/PollenContextImpl.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/PollenContextImpl.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -360,16 +360,12 @@ return UUID.randomUUID().toString().replaceAll("-", ""); } -// public void setCurrentDate(Date currentDate) { -// PollenContextBusiness.currentDate = currentDate; -// } - @Override public Date getCurrentDate() { - if (currentDate == null) { - currentDate = new Date(); + if (currentDate != null) { + return currentDate; } - return currentDate; + return new Date(); } /** Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/service/ServiceVoteImpl.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/service/ServiceVoteImpl.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/service/ServiceVoteImpl.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -1,9 +1,11 @@ package org.chorem.pollen.service; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.pollen.EntityQueryProperty; import org.chorem.pollen.PollenBinderHelper; +import org.chorem.pollen.PollenBusinessException; import org.chorem.pollen.PollenContext; import org.chorem.pollen.PollenDAOHelper; import org.chorem.pollen.PollenException; @@ -15,6 +17,7 @@ import org.chorem.pollen.entity.PollAccountDAO; import org.chorem.pollen.entity.PollAccountImpl; import org.chorem.pollen.entity.PollDAO; +import org.chorem.pollen.entity.UserAccount; import org.chorem.pollen.entity.Vote; import org.chorem.pollen.entity.VoteDAO; import org.chorem.pollen.entity.VoteImpl; @@ -107,6 +110,9 @@ log.info("Poll is no longer running... Participant can't vote"); } result = false; + // Creator can't vote + } else if (poll.getCreator().equals(participant)) { + return false; } else if (poll.getPollType().isRestrictedOrGroup()) { if (log.isInfoEnabled()) { log.info("Poll is restricted... Participant need to be identified"); @@ -115,38 +121,16 @@ PollAccountDAO dao = PollenDAOHelper.getPollAccountDAO(transaction); EntityQueryProperty participantProperty = - PollenUtils.getEntityQueryProperty("A"); + PollenUtils.getEntityQueryProperty(PollAccount.class, "A"); EntityQueryProperty pollProperty = - PollenUtils.getEntityQueryProperty("P"); + PollenUtils.getEntityQueryProperty(Poll.class, "P"); EntityQueryProperty groupProperty = - PollenUtils.getEntityQueryProperty("G"); + PollenUtils.getEntityQueryProperty(PollAccount.class, "G"); - TopiaQuery query = dao.createQuery(participantProperty.name()). - addFrom(Poll.class, pollProperty.name()). - addEquals(pollProperty.name(), poll); + TopiaQuery query = createQueryFindParticipantByPoll( + participantProperty, groupProperty, pollProperty, poll); - // By default the parentCollection is pollAccount in poll - String parentCollectionProperty = - pollProperty.nameProperty(Poll.POLL_ACCOUNT); - - if (poll.getPollType().isGroup()) { - // Add the group into the query - query.addFrom(PollAccount.class, groupProperty.name()). - // It's not really necessary, but better to be sure - addEquals(groupProperty.nameProperty(PollAccount.LIST), - Boolean.TRUE). - // Add link between the group and the poll - addInElements(groupProperty.name(), parentCollectionProperty); - - // In case of group, the parentCollection is the child - // pollAccount from the group - parentCollectionProperty = - groupProperty.nameProperty(PollAccount.CHILD); - } - - // Add link between the participant to find and his parent - query.addInElements(participantProperty.name(), parentCollectionProperty). - addEquals(participantProperty.name(), participant). + query.addEquals(participantProperty.name(), participant). addWhere(pollProperty.nameProperty(Poll.CREATOR), TopiaQuery.Op.NEQ, participant @@ -158,14 +142,50 @@ result = dao.existByQuery(query); } - - // Note for freePoll, maybe check doubloons on participant name/email return result; } + protected TopiaQuery createQueryFindParticipantByPoll(EntityQueryProperty participantProperty, + EntityQueryProperty groupProperty, + EntityQueryProperty pollProperty, + Poll poll) { + TopiaQuery query = participantProperty.newQuery(). + addFrom(Poll.class, pollProperty.name()). + addEquals(pollProperty.name(), poll); + + // By default the parentCollection is pollAccount in poll + String parentCollectionProperty = + pollProperty.nameProperty(Poll.POLL_ACCOUNT); + + if (poll.getPollType().isGroup()) { + // Add the group into the query + query.addFrom(PollAccount.class, groupProperty.name()). + // It's not really necessary, but better to be sure + addEquals(groupProperty.nameProperty(PollAccount.LIST), + Boolean.TRUE). + // Add link between the group and the poll + addInElements(groupProperty.name(), parentCollectionProperty); + + // In case of group, the parentCollection is the child + // pollAccount from the group + parentCollectionProperty = + groupProperty.nameProperty(PollAccount.CHILD); + } + + // Add link between the participant to find and his parent + query.addInElements(participantProperty.name(), parentCollectionProperty); + + return query; + } + @Override - protected PollAccount executeGetNewPollAccount() throws Exception { + protected PollAccount executeGetNewPollAccount(UserAccount user) { PollAccount account = new PollAccountImpl(); + if (user != null) { + account.setName(user.getDisplayName()); + account.setEmail(user.getEmail()); + account.setUserAccount(user); + } return account; } @@ -193,6 +213,10 @@ List<PollAccount> results = dao.findAllByQuery(query); + if (log.isDebugEnabled()) { + log.debug("Query : " + query); + } + return results; } @@ -266,7 +290,7 @@ @Override protected String executeSaveVote(TopiaContext transaction, Poll poll, PollAccount participant) - throws TopiaException { + throws TopiaException, PollenBusinessException { // 1- executeCanVote(transaction, poll, participant); // 2- generate uid if needed @@ -286,6 +310,8 @@ PollAccountDAO dao = PollenDAOHelper.getPollAccountDAO(transaction); + checkParticipantDoubloons(dao, poll, participant); + PollAccount participantToSave = dao.findByTopiaId(participant.getTopiaId()); @@ -304,6 +330,11 @@ // Update vote date participantToSave.setVoteDate(context.getCurrentDate()); + if (log.isDebugEnabled()) { + log.debug("Vote " + participantToSave.getName() + + " updated : " + participantToSave.getVoteDate()); + } + // Save votes saveParticipantVotes(transaction, participant, participantToSave); @@ -315,12 +346,45 @@ transaction.commitTransaction(); } else { - // maybe throw exception + throw new PollenBusinessException( + PollenBusinessException.PollenExceptionType.VOTE_NOT_ALLOWED, + participant.getUid()); } return result; } + protected void checkParticipantDoubloons(PollAccountDAO dao, + Poll poll, + PollAccount participant) + throws PollenBusinessException, TopiaException { + + EntityQueryProperty participantProperty = + PollenUtils.getEntityQueryProperty(PollAccount.class, "A"); + EntityQueryProperty pollProperty = + PollenUtils.getEntityQueryProperty(Poll.class, "P"); + EntityQueryProperty groupProperty = + PollenUtils.getEntityQueryProperty(PollAccount.class, "G"); + + TopiaQuery query = createQueryFindParticipantByPoll( + participantProperty, groupProperty, pollProperty, poll); + + query.addEquals(participantProperty.nameProperty(PollAccount.NAME), + participant.getName()); + + if (StringUtils.isNotEmpty(participant.getTopiaId())) { + query.addWhere(participantProperty.namePropertyId(), + TopiaQuery.Op.NEQ, + participant.getTopiaId()); + } + + if (dao.existByQuery(query)) { + throw new PollenBusinessException( + PollenBusinessException.PollenExceptionType.VOTE_DOUBLOON, + participant.getName()); + } + } + /** * Create a new participant for a running {@code poll}. The participant uid * will be generated and the new instance of pollAccount will be added to Modified: trunk/pollen-business/src/main/resources/i18n/pollen-business-en_GB.properties =================================================================== --- trunk/pollen-business/src/main/resources/i18n/pollen-business-en_GB.properties 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-business/src/main/resources/i18n/pollen-business-en_GB.properties 2010-06-01 14:06:41 UTC (rev 3022) @@ -100,6 +100,8 @@ pollen.exception.user_login_exist= pollen.exception.user_not_exist= pollen.exception.user_wrong_password= +pollen.exception.vote_doubloon= +pollen.exception.vote_not_allowed= pollen.info.admin.created=Super admin was created with login %1$s pollen.info.admin.exists=Super admin already exists pollen.info.start=Start Pollen Modified: trunk/pollen-business/src/main/resources/i18n/pollen-business-fr_FR.properties =================================================================== --- trunk/pollen-business/src/main/resources/i18n/pollen-business-fr_FR.properties 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-business/src/main/resources/i18n/pollen-business-fr_FR.properties 2010-06-01 14:06:41 UTC (rev 3022) @@ -97,6 +97,8 @@ pollen.exception.user_login_exist=Un utilisateur est d\u00E9j\u00E0 enregistr\u00E9 avec cet identifiant. pollen.exception.user_not_exist=L'identifiant '%1$s' ne correspond \u00E0 aucun utilisateur connu. pollen.exception.user_wrong_password=Le mot de passe renseign\u00E9 est incorrect pour l'utilisateur '%1$s'. +pollen.exception.vote_doubloon= +pollen.exception.vote_not_allowed= pollen.info.admin.created=Le super admin a \u00E9t\u00E9 cr\u00E9\u00E9 avec l'identifiant %1$s. pollen.info.admin.exists=Le super admin existe d\u00E9j\u00E0 pollen.info.start=D\u00E9marrage de Pollen... Modified: trunk/pollen-business/src/main/xmi/pollen.zargo =================================================================== (Binary files differ) Modified: trunk/pollen-business/src/test/java/org/chorem/pollen/service/ServiceVoteImplTest.java =================================================================== --- trunk/pollen-business/src/test/java/org/chorem/pollen/service/ServiceVoteImplTest.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-business/src/test/java/org/chorem/pollen/service/ServiceVoteImplTest.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -147,6 +147,7 @@ log.info("test 2 : anonymous participant"); participant.setAnonymous(true); + participant.setName("participant2"); uid = serviceVote.saveVote(poll, participant); transaction = beginTransaction(); Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/components/Pager.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/components/Pager.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/components/Pager.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -135,20 +135,21 @@ rightarrow2, "p-pager-last"); } } + } - int doubleNbPerPage = range * 2; - int quadrupleNbPerPage = range * 4; - writer.element("div", "class", "p-pager-nbrows"); - writer.write(messages.format("showPerPage")); - writer.write(" "); - writeChangeNbRowsLink(writer, range); - writer.write(", "); - writeChangeNbRowsLink(writer, doubleNbPerPage); - writer.write(", "); - writeChangeNbRowsLink(writer, quadrupleNbPerPage); - writer.end(); - } + int doubleNbPerPage = range * 2; + int quadrupleNbPerPage = range * 4; + writer.element("div", "class", "p-pager-nbrows"); + writer.write(messages.format("showPerPage")); + writer.write(" "); + writeChangeNbRowsLink(writer, range); + writer.write(", "); + writeChangeNbRowsLink(writer, doubleNbPerPage); + writer.write(", "); + writeChangeNbRowsLink(writer, quadrupleNbPerPage); writer.end(); + + writer.end(); } void afterRender(MarkupWriter writer) { Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollForm.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollForm.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollForm.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -742,11 +742,12 @@ email.setSubject(messages.format( "pollen.email.createPoll.subject", getPoll().getTitle())); + email.setContent(messages.format( "pollen.email.createPoll.content", getPoll().getTitle(), servicePollUri.getVoteUrl(uri), - servicePollUri.getModerateVoteUrl(uri), + servicePollUri.getVoteUpdateUrl(uri), servicePollUri.getPollUpdateUrl(uri))); serviceEmail.sendEmail(email); Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollLinks.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollLinks.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollLinks.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -90,7 +90,7 @@ } public Link getModerateVoteLink() { - return servicePollUri.getModerateVoteLink(pollUri); + return servicePollUri.getVoteUpdateLink(pollUri); } public Link getPollLink() { Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/VoteForPoll.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/VoteForPoll.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/VoteForPoll.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -22,10 +22,12 @@ import java.util.Locale; +import org.apache.commons.lang.StringUtils; import org.apache.tapestry5.BindingConstants; import org.apache.tapestry5.Block; import org.apache.tapestry5.ComponentResources; import org.apache.tapestry5.EventContext; +import org.apache.tapestry5.Link; import org.apache.tapestry5.annotations.IncludeJavaScriptLibrary; import org.apache.tapestry5.annotations.IncludeStylesheet; import org.apache.tapestry5.annotations.InjectComponent; @@ -33,16 +35,20 @@ import org.apache.tapestry5.annotations.Parameter; import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.corelib.components.Form; import org.apache.tapestry5.ioc.Messages; import org.apache.tapestry5.ioc.annotations.Inject; import org.chorem.pollen.PollenBusinessException; import org.chorem.pollen.PollenProperty; import org.chorem.pollen.bean.Filter; +import org.chorem.pollen.bean.PollenEmail; +import org.chorem.pollen.bean.PollenEmailImpl; import org.chorem.pollen.entity.Choice; import org.chorem.pollen.entity.Poll; import org.chorem.pollen.entity.PollAccount; import org.chorem.pollen.entity.UserAccount; import org.chorem.pollen.entity.Vote; +import org.chorem.pollen.service.ServiceEmail; import org.chorem.pollen.service.ServicePoll; import org.chorem.pollen.service.ServiceUser; import org.chorem.pollen.service.ServiceVote; @@ -55,6 +61,8 @@ import org.chorem.pollen.ui.data.PollUri; import org.chorem.pollen.ui.services.PollenManager; import org.chorem.pollen.ui.services.ServiceImage; +import org.chorem.pollen.ui.services.ServicePollUri; +import org.nuiton.web.tapestry5.components.FeedBack; import org.slf4j.Logger; /** @@ -206,9 +214,21 @@ public PollAccount getPollAccount() { if (pollAccount == null) { if (uri.hasAccountUid()) { + if (logger.isDebugEnabled()) { + logger.debug("Loading existing pollAccount : " + uri.getAccountUid()); + } pollAccount = serviceVote.getPollAccount(uri.getAccountUid()); + if (logger.isDebugEnabled() && pollAccount != null) { + logger.debug("Pollaccount loaded : " + + pollAccount.getName() + " admin=" + + pollAccount.isAdmin()); + } } else { - pollAccount = serviceVote.getNewPollAccount(); + if (logger.isDebugEnabled()) { + logger.debug("Instantiate new pollAccount from connected" + + " user (defined=" + isUserConnected() + ")"); + } + pollAccount = serviceVote.getNewPollAccount(getUserConnected()); } } return pollAccount; @@ -513,6 +533,7 @@ filter.setStartIndex(pager.getStartIndex()); filter.setEndIndex(pager.getEndIndex()); filter.setReference(getPoll()); + filter.setOrderBy(PollAccount.VOTE_DATE + " desc"); return filter; } @@ -536,7 +557,26 @@ @Property private PollAccount participant; + + private List<Vote> editedVotes; + @Property + private Vote editedVote; + + @InjectComponent + private Form voteForm; + + private Boolean canVote; + + @InjectComponent + private FeedBack voteFeedback; + + @Inject + private ServicePollUri servicePollUri; + + @Inject + private ServiceEmail serviceEmail; + /** * Retrieve votes of the current poll from business module. * The votes are ordered by creation date, only the ones to display are @@ -552,22 +592,31 @@ return participants; } + public String getParticipantNameStyle() { + if (!participant.isAnonymous() && + participant.getName().equals(getPollAccount().getName())) { + return "selected"; + } + return evenOdd.getNext(); + } + public Vote getVote() { Vote vote = participant.getChoiceVote(choice.getChoice()); return vote; } - private List<Vote> editedVotes; - - @Property - private Vote editedVote; - public List<Vote> getEditedVotes() { if (editedVotes == null) { editedVotes = new ArrayList<Vote>(); for (ChoiceField choice : choices) { Vote vote = getPollAccount().getChoiceVote(choice.getChoice()); + if (logger.isDebugEnabled()) { + logger.debug("Load previous vote : " + + (vote != null ? + vote.getChoice().getName() + " with value " + + vote.getVoteValue() : "null")); + } if (vote == null) { vote = serviceVote.getNewVote(choice.getChoice()); } @@ -577,16 +626,135 @@ return editedVotes; } + public boolean canVote() throws PollenBusinessException { + if (canVote == null) { + canVote = serviceVote.canVote(getPoll(), getPollAccount()); + } + return canVote; + } + + public boolean canDeleteVote() { + return getPollAccount().isAdmin(); + } + + @Log + void onActionFromDeleteVote(int participantIndex) throws PollenBusinessException { + if (canDeleteVote()) { + PollAccount participant = getParticipants().get(participantIndex); + if (logger.isDebugEnabled()) { + logger.debug("Delete vote from participant index " + + participantIndex + " name = " + participant.getName()); + } + + serviceVote.deleteVote(getPoll(), participant); + } + } + + @Log void onValidateFormFromVoteForm() { // percentage : check total = 100 getPollAccount().setChoiceVote(getEditedVotes()); try { - serviceVote.saveVote(getPoll(), getPollAccount()); + // Link with user account + boolean linkWithUser = linkUserConnected(); + + // Execute the save + String uid = serviceVote.saveVote(getPoll(), getPollAccount()); + getPollAccount().setUid(uid); + + if (linkWithUser) { + voteFeedback.addInfo("Votre vote a été lié à votre compte utilisateur."); + } } catch (PollenBusinessException eee) { - // record error + String message = manager.getErrorMessage(logger, messages, eee); + voteForm.recordError(message); } } + protected boolean linkUserConnected() { + if (isUserConnected() && getPollAccount().getUserAccount() == null) { + if (logger.isInfoEnabled()) { + logger.info("Link participant with user connected : " + + getUserConnected().getDisplayName()); + } + getPollAccount().setUserAccount(getUserConnected()); + return true; + } + return false; + } + + protected Object manageFreeVote() throws PollenBusinessException { + // Prepare uri for redirection and being display to user + String uid = getPollAccount().getUid(); + + if (logger.isDebugEnabled()) { + logger.debug("New vote with uid : " + uid); + } + PollUri updateUri = + servicePollUri.getNewPollUri(uid, getPoll().getUid()); + String updateUrl = servicePollUri.getVoteUpdateUrl(updateUri); + + // with unconnected user + if (!isUserConnected()) { + + if (logger.isInfoEnabled()) { + logger.info("Vote created for free poll with unconnected user"); + } + + String email = getPollAccount().getEmail(); + boolean anonymous = getPollAccount().isAnonymous(); + + // send email + if (StringUtils.isNotEmpty(email) && !anonymous) { + + if (logger.isDebugEnabled()) { + logger.debug("Send an email to '" + email + "' with url : " + + updateUrl); + } + + PollenEmail pollenEmail = new PollenEmailImpl(); + pollenEmail.setTo(email); + pollenEmail.setSubject("Vote OK"); + pollenEmail.setContent("Url de modification de votre vote : " + + updateUrl); + try { + serviceEmail.sendEmail(pollenEmail); + } catch (PollenBusinessException eee) { + String message = manager.getErrorMessage(logger, messages, eee); + voteFeedback.addError(message); + } + + voteFeedback.addInfo("Envoi d'un email avec l'url de modification de votre vote."); + + // display url to update vote + } else { + voteFeedback.addInfo("Url de modification de votre vote : " + + updateUrl); + } + } + voteFeedback.addInfo("La page a été rechargée, vous pouvez modifier votre vote."); + return servicePollUri.getVoteUpdateLink(updateUri); + } + + @Log + Object onSuccessFromVoteForm() throws PollenBusinessException { + voteFeedback.addInfo("Enregistrement du vote OK"); + + boolean newFreeVote = StringUtils.isEmpty(uri.getAccountUid()); + + Object redirect = this; + // Case of new Free vote + if (newFreeVote && getPoll().getPollType().isFree()) { + redirect = manageFreeVote(); + } + page = 1; + return redirect; + } + + Object onFailureFromVoteForm() { + return voteForm; + } + // /** // * Retourne vrai si le champs pollAccount doit apparaître. // * @@ -604,17 +772,6 @@ // return !getPoll().isAnonymous() || isRestrictedPoll() || isGroupPoll(); // } - public boolean getCanVote() { - // FIXME-fdesbois-2010-05-25 : copy check treatment directly in service - if (poll.isFinished()) { - return false; - } - if (poll.getPollType().isRestrictedOrGroup() || poll.isAnonymous()) { - return serviceVote.canVote(poll, pollAccount); - } - return true; - } - public boolean canEditVote() throws PollenBusinessException { // If the current pollAccount exist from uri and equals to the current vote // String newAccountId = getPollAccount().getId(); Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/AppModule.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/AppModule.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/AppModule.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -206,7 +206,6 @@ return uri; } }; - Coercion<PollUri, String> coercion2 = new Coercion<PollUri, String>() { @Override @@ -215,12 +214,36 @@ } }; + Coercion<Boolean, Double> coercion3 = new Coercion<Boolean, Double>() { + + @Override + public Double coerce(Boolean input) { + return input ? 1. : 0.; + } + }; + Coercion<Double, Boolean> coercion4 = new Coercion<Double, Boolean>() { + + @Override + public Boolean coerce(Double input) { + return input > 1; + } + }; + + // coercions for String <-> PollUri configuration.add( new CoercionTuple<String, PollUri>( String.class, PollUri.class, coercion1)); configuration.add( new CoercionTuple<PollUri, String>( PollUri.class, String.class, coercion2)); + + // coercions for Double <-> Boolean : use for voteValue + configuration.add( + new CoercionTuple<Boolean, Double>( + Boolean.class, Double.class, coercion3)); + configuration.add( + new CoercionTuple<Double, Boolean>( + Double.class, Boolean.class, coercion4)); } /** Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUri.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUri.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUri.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -42,7 +42,7 @@ * @param uri PollUri that contains pollUid and creatorUid (moderator) * @return the Link to used for moderation on vote page */ - Link getModerateVoteLink(PollUri uri); + Link getVoteUpdateLink(PollUri uri); /** * Retrieve url for poll update page. @@ -66,7 +66,7 @@ * @param uri PollUri that contains pollUid and creatorUid (moderator) * @return the full url to used for moderation on vote page */ - String getModerateVoteUrl(PollUri uri); + String getVoteUpdateUrl(PollUri uri); /** * Retrieve a new instance of PollUri with {@code accountUid} and {@code Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUriImpl.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUriImpl.java 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/ServicePollUriImpl.java 2010-06-01 14:06:41 UTC (rev 3022) @@ -45,7 +45,7 @@ } @Override - public Link getModerateVoteLink(PollUri uri) { + public Link getVoteUpdateLink(PollUri uri) { Link link = linkSource.createPageRenderLinkWithContext( VoteForPoll.class, uri); return link; @@ -53,17 +53,17 @@ @Override public String getPollUpdateUrl(PollUri uri) { - return contextPath + getPollUpdateLink(uri); + return contextPath + getPollUpdateLink(uri).toAbsoluteURI(); } @Override public String getVoteUrl(PollUri uri) { - return contextPath + getVoteLink(uri); + return contextPath + getVoteLink(uri).toAbsoluteURI(); } @Override - public String getModerateVoteUrl(PollUri uri) { - return contextPath + getModerateVoteLink(uri); + public String getVoteUpdateUrl(PollUri uri) { + return contextPath + getVoteUpdateLink(uri).toAbsoluteURI(); } @Override Modified: trunk/pollen-ui/src/main/resources/i18n/pollen-ui-fr_FR.properties =================================================================== --- trunk/pollen-ui/src/main/resources/i18n/pollen-ui-fr_FR.properties 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/resources/i18n/pollen-ui-fr_FR.properties 2010-06-01 14:06:41 UTC (rev 3022) @@ -79,6 +79,8 @@ pollen.ui.poll.links.creatorEmail.success=Un email vous a \u00e9t\u00e9 envoy\u00e9 avec les liens ci-dessous. pollen.ui.poll.links.creatorEmail.notDefined=Aucun email n'a \u00e9t\u00e9 d\u00e9fini \u00e0 la cr\u00e9ation du sondage, vous devriez enregistrer cette page dans vos favoris pour ne pas perdre les liens. +############################ VOTE ############################################## +pollen.ui.vote.delete.confirmMessage=Etes-vous s\u00fbr de vouloir supprimer ce vote ? # OLD LOGIN_COMPONENT connectionLegend=Connexion Modified: trunk/pollen-ui/src/main/webapp/css/common.css =================================================================== --- trunk/pollen-ui/src/main/webapp/css/common.css 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/webapp/css/common.css 2010-06-01 14:06:41 UTC (rev 3022) @@ -38,6 +38,10 @@ text-align: center; } +.selected { + background-color: yellow; +} + input.ico { border: 0 none; font-size: 0; Modified: trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml =================================================================== --- trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml 2010-05-31 15:57:48 UTC (rev 3021) +++ trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml 2010-06-01 14:06:41 UTC (rev 3022) @@ -43,16 +43,16 @@ <!-- Sondage --> - <!--<t:zone t:id="pollZone" t:show="show" t:update="show">--> - <t:if t:test="pagerNeeded"> - <t:pager t:nbRowsPerPage="nbVotesPerPage" t:nbTotalRows="nbVotes" - t:currentPage="page" t:noPagerText="prop:noPagerText" t:range="pagerRange"/> - <!--<t:feedback t:id="voteFeedback"/>--> - <p:else> - <p>${format:vote-size=nbVotes}</p> - </p:else> - </t:if> - <t:form t:id="voteForm"> + <t:zone t:id="voteZone" t:update="show"> + <form t:type="form" t:id="voteForm" t:zone="voteZone"> + <t:nuiton.feedback t:id="voteFeedback" /> + <!--<t:if t:test="pagerNeeded">--> + <t:pager t:nbRowsPerPage="nbVotesPerPage" t:nbTotalRows="nbVotes" + t:currentPage="page" t:noPagerText="format:vote-size=nbVotes" t:range="pagerRange"/> + <!--<p:else>--> + <!--<p>${format:vote-size=nbVotes}</p>--> + <!--</p:else>--> + <!--</t:if>--> <table id="poll"> <thead> <tr> @@ -98,7 +98,7 @@ </th> </tr> </thead> - <t:if test="canVote"> + <t:if test="canVote()"> <tfoot> <tr> <!--<t:if test="accountFieldDisplayed">--> @@ -110,8 +110,8 @@ <!--</p:else>--> <!--</t:if>--> <t:loop t:source="editedVotes" t:value="editedVote" volatile="true"> - <t:unless test="editedChoice.hidden"> - <th> + <t:unless test="editedVote.choice.hidden"> + <th class="center"> <t:if test="poll.voteCountingType.normal"> <input t:type="checkbox" value="editedVote.voteValue" /> </t:if> @@ -132,9 +132,9 @@ </t:if> <tbody> <t:unless t:test="poll.anonymous"> - <t:loop t:source="participants" t:value="participant" t:rowIndex="participantIndex" volatile="true"> + <t:loop t:source="participants" t:value="participant" t:index="participantIndex" volatile="true"> <tr> - <td class="${evenodd.next}"> + <td class="${participantNameStyle}"> <!--<t:if test="accountFieldDisplayed">--> <t:if test="participant.anonymous"> ? @@ -149,11 +149,12 @@ <!--<img src="${asset:context:img/editSmall.png}" title="${message:edit}" alt="${message:edit}"/>--> <!--</t:actionlink>--> <!--</t:if>--> - <!--<t:if test="creatorUser">--> - <!--<t:actionlink t:id="deleteVote" context="vote.id" t:zone="pollZone">--> - <!--<img src="${asset:context:img/delete.png}" title="${message:delete}" alt="${message:delete}"/>--> - <!--</t:actionlink>--> - <!--</t:if>--> + <t:if test="canDeleteVote()"> + <a t:type="actionlink" t:id="deleteVote" t:context="participantIndex" t:mixins="nuiton/confirm" + t:message="${message:pollen.ui.vote.delete.confirmMessage}"> + <img src="${asset:context:img/delete.png}" title="${message:delete}" alt="${message:delete}"/> + </a> + </t:if> <!--</t:unless>--> </td> <t:loop t:source="choices" t:value="choice" volatile="true"> @@ -221,18 +222,22 @@ <div id="voteError"> <t:errors/> </div> - <!--<t:if test="poll.running">--> - <!--<div id="buttons">--> - <!--<t:if test="anonymousVoteDisplayed">--> - <!--<t:checkbox t:id="anonymousVote" t:value="anonymousVote" />--> - <!--<t:label for="anonymousVote" />--> - <!--<br/>--> - <!--</t:if>--> - <!--<input t:id="submitVote" t:type="Submit" t:value="${message:submitVote}" />--> - <!--</div>--> - <!--</t:if>--> - </t:form> - <!--</t:zone>--> + <t:if test="canVote()"> + <div id="buttons"> + <t:if t:test="poll.pollType.free"> + <label t:type="label" t:for="pollAccountEmail" /> + <input t:type="textfield" t:id="pollAccountEmail" value="pollAccount.email" /> + </t:if> + <t:if t:test="poll.anonymousVoteAllowed"> + <input t:type="checkbox" t:id="anonymousVote" value="pollAccount.anonymous" /> + <t:label t:for="anonymousVote" /> + <br/> + </t:if> + <input t:id="submitVote" t:type="Submit" t:value="${message:submitVote}" /> + </div> + </t:if> + </form> + </t:zone> <!--</t:if>-->