r2943 - in trunk: . pollen-business/src/main/java/org/chorem/pollen/business pollen-business/src/main/java/org/chorem/pollen/business/business pollen-business/src/main/java/org/chorem/pollen/business/converters pollen-business/src/main/java/org/chorem/pollen/business/dto pollen-business/src/main/java/org/chorem/pollen/business/services pollen-business/src/main/java/org/chorem/pollen/business/utils pollen-business/src/main/resources pollen-business/src/test/java/org/chorem/pollen/business po
Author: fdesbois Date: 2010-03-15 15:48:49 +0100 (Mon, 15 Mar 2010) New Revision: 2943 Log: Merge branche 1.2.x with trunk 1.3 (running the application is not tested yet) Added: trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/ trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/ScalingVote.java trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/package-info.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/PollCreation.java.orig trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/SendMail.java trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_en.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_fr.properties trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml.orig trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/ trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/CSVAccountUtilTest.java trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/SendMailTest.java trunk/pollen-ui/src/test/resources/ trunk/pollen-ui/src/test/resources/import.csv Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/PollenProperty.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/business/PreventRuleManager.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataPollConverter.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataVoteConverter.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/PollDTO.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/VoteDTO.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePoll.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePollImpl.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVote.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVoteImpl.java trunk/pollen-business/src/main/java/org/chorem/pollen/business/utils/MailUtil.java trunk/pollen-business/src/main/resources/pollen.properties trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/admin/UsersAdmin.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollCreation.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollModification.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/pages/user/Register.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/BackgroundWorkerImpl.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/PollenManager.java trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/CSVAccountUtil.java trunk/pollen-ui/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/base/Polls_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/PollsAdmin_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/UsersAdmin_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CloseValidation_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ConfirmPoll_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CreationValidation_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ImageDisplay_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ModificationValidation_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_en.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_en.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/Results_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_en.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Account_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Register_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserLists_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsCreated_fr.properties trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsParticipated_fr.properties trunk/pollen-ui/src/main/webapp/css/vote.css trunk/pollen-ui/src/main/webapp/js/pollen.js trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml trunk/pollen-ui/src/main/webapp/poll/PollModification.tml trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml trunk/pom.xml Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/PollenProperty.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/PollenProperty.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/PollenProperty.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -31,6 +31,8 @@ EMAIL_PORT("email_port"), /** from for email sending configuration **/ EMAIL_FROM("email_from"), + /** directory to store emails before sending them **/ + EMAIL_DIR("pollen.emails.directory"), /** path for feed directory **/ FEED_DIR("feedDir"), /** path for uploaded images directory **/ Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/business/PreventRuleManager.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/business/PreventRuleManager.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/business/PreventRuleManager.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -33,6 +33,9 @@ */ public class PreventRuleManager { + /** log. */ + private static final Log log = LogFactory.getLog(PreventRuleManager.class); + /** Représente l'action qui ne fait rien. */ public static final String NULL_ACTION = "nullAction"; /** Représente l'action qui écrit sur la sortie standard. */ @@ -40,9 +43,6 @@ /** Représente l'action qui envoi un email de notification. */ public static final String EMAIL_ACTION = "emailAction"; - /** log. */ - private static final Log log = LogFactory.getLog(PreventRuleManager.class); - private PreventRuleDTO preventRule = null; /** @@ -150,6 +150,8 @@ /** * Action qui ne fait rien. + * + * TODO set this method to protected */ public static void nullAction(Object data) { // ne fait rien @@ -157,6 +159,8 @@ /** * Action qui écrit sur la sortie standard. + * + * TODO set this method to protected */ public static void printAction(Object data) { String message = ""; @@ -168,14 +172,24 @@ /** * Action qui envoi un email de notification. + * + * @param data mail data + * + * TODO set this method to protected */ public static void emailAction(Object data) { Map<String, String> fields = null; - if (data instanceof Map) { + if (data instanceof Map<?, ?>) { fields = (Map<String, String>) data; + MailUtil.sendMail(fields.get("host"), Integer.parseInt(fields + .get("port")), fields.get("from"), fields.get("to"), fields + .get("title"), fields.get("msg")); } - MailUtil.sendMail(fields.get("host"), Integer.parseInt(fields - .get("port")), fields.get("from"), fields.get("to"), fields - .get("title"), fields.get("msg")); + else { + if (log.isWarnEnabled()) { + log.warn("emailAction data parameter is not instance of Map"); + } + } + } } Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataPollConverter.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataPollConverter.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataPollConverter.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -91,9 +91,9 @@ pollDTO.setChoiceDTOs(choiceConverter.createChoiceDTOs(ePoll .getChoice())); } - if (ePoll.getVote().size() > 0) { - pollDTO.setVoteDTOs(voteConverter.createVoteDTOs(ePoll.getVote())); - } +// if (ePoll.getVote().size() > 0) { +// pollDTO.setVoteDTOs(voteConverter.createVoteDTOs(ePoll.getVote())); +// } for (Comment comment : ePoll.getComment()) { CommentDTO dto = PollenConverter.convert(comment, new CommentDTO()); Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataVoteConverter.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataVoteConverter.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/converters/DataVoteConverter.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -29,6 +29,7 @@ import org.chorem.pollen.business.persistence.PollAccountDAO; import org.chorem.pollen.business.persistence.PollDAO; import org.chorem.pollen.business.persistence.PollenModelDAOHelper; +import org.chorem.pollen.business.persistence.UserAccount; import org.chorem.pollen.business.persistence.Vote; import org.chorem.pollen.business.persistence.VoteDAO; import org.chorem.pollen.business.persistence.VoteToChoice; @@ -98,6 +99,11 @@ } if (eVote.getPollAccount() != null) { voteDTO.setPollAccountId(eVote.getPollAccount().getTopiaId()); + voteDTO.setName(eVote.getPollAccount().getVotingId()); + UserAccount user = eVote.getPollAccount().getUserAccount(); + if (user != null) { + voteDTO.setUserId(user.getTopiaId()); + } } if (eVote.getVotingList() != null) { voteDTO.setVotingListId(eVote.getVotingList().getTopiaId()); Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/PollDTO.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/PollDTO.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/PollDTO.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -88,6 +88,8 @@ private List<VoteDTO> voteDTOs = new ArrayList<VoteDTO>(); + private int nbVotes; + private List<PreventRuleDTO> preventRuleDTOs = new ArrayList<PreventRuleDTO>(); private List<ChoiceDTO> choiceDTOs = new ArrayList<ChoiceDTO>(); @@ -368,6 +370,14 @@ this.voteDTOs = voteDTOs; } + public int getNbVotes() { + return nbVotes; + } + + public void setNbVotes(int nbVotes) { + this.nbVotes = nbVotes; + } + public void addVote(VoteDTO vote) { if (voteDTOs == null) { voteDTOs = new ArrayList<VoteDTO>(); Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/VoteDTO.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/VoteDTO.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/dto/VoteDTO.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -46,6 +46,12 @@ /** topiaId of the account who has voted**/ private String pollAccountId = ""; + /** QUICK FIX to have pollAccount votingId **/ + private String name; + + /** QUICK FIX to have pollAccount userId **/ + private String userId; + /** * topiaId of the poll where the vote is done * FIXME-FD20100224 Is it really needed ?? @@ -115,6 +121,22 @@ this.pollAccountId = pollAccountId; } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + public String getPollId() { return pollId; } Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePoll.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePoll.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePoll.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -13,15 +13,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ - package org.chorem.pollen.business.services; import java.util.List; import java.util.Map; import org.chorem.pollen.business.dto.CommentDTO; +import org.chorem.pollen.business.dto.PollAccountDTO; import org.chorem.pollen.business.dto.PollDTO; -import org.chorem.pollen.business.dto.UserDTO; /** * Interface du service de gestion des sondages. @@ -144,4 +143,16 @@ * @param commentId id of the comment to delete */ public void deleteComment(PollDTO poll, String commentId); -} \ No newline at end of file + + /** + * Return the pollAccount corresponding to the {@code accountUId} for the + * restricted {@code poll}. + * TODO : need JUnit test, must be done for 1.3 + * + * @param accountUId to check the restriction constraint + * @param poll reference + * @return the pollAccount found from poll or null if there is no + * pollAccount in poll restriction for the accountUId in argument + */ + public PollAccountDTO getRestrictedAccount(String accountUId, PollDTO poll); +} Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePollImpl.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePollImpl.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServicePollImpl.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -13,7 +13,6 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ - package org.chorem.pollen.business.services; import java.util.ArrayList; @@ -34,7 +33,6 @@ import org.chorem.pollen.business.dto.PollAccountDTO; import org.chorem.pollen.business.dto.PollDTO; import org.chorem.pollen.business.dto.PreventRuleDTO; -import org.chorem.pollen.business.dto.VoteDTO; import org.chorem.pollen.business.dto.VotingListDTO; import org.chorem.pollen.business.persistence.Choice; import org.chorem.pollen.business.persistence.ChoiceDAO; @@ -55,7 +53,6 @@ import org.chorem.pollen.business.persistence.VotingListDAO; import org.chorem.pollen.business.utils.ContextUtil; import org.chorem.pollen.business.PollenContext; -import org.chorem.pollen.business.dto.UserDTO; import org.chorem.pollen.common.PollType; import org.chorem.pollen.common.VoteCountingType; import org.nuiton.topia.TopiaContext; @@ -76,11 +73,10 @@ private TopiaContext rootContext; private PollDAO pollDAO = null; private DataPollConverter converter = new DataPollConverter(); - /** log. */ private static final Log log = LogFactory.getLog(ServicePollImpl.class); - public ServicePollImpl() { + public ServicePollImpl() { rootContext = PollenContext.getRootContext(); PollenConverter.preparePollConverters(); @@ -96,7 +92,7 @@ public String createPoll(PollDTO pollDTO) { TopiaContext transaction = null; String result = null; - try { + try { transaction = rootContext.beginTransaction(); pollDAO = PollenModelDAOHelper.getPollDAO(transaction); @@ -105,7 +101,7 @@ String pollId = pollDTO.getPollId(); Poll entity = pollDAO.create(pollId); PollenConverter.convert(pollDTO, entity); - + // ** Manage the poll creator PollAccount creator = prepareCreator(transaction, pollDTO); entity.setCreator(creator); @@ -149,13 +145,12 @@ } catch (Exception eee) { PollenContext.doCatch(eee, _("pollen.error.servicePoll.createPoll", - pollDTO.getTitle(), pollDTO.getCreatorId()), transaction); + pollDTO.getTitle(), pollDTO.getCreatorId()), transaction); } finally { PollenContext.doFinally(transaction); } return result; } - /** * Prepare pollAccount as creator for {@code poll} save. If userId is @@ -174,7 +169,7 @@ // Search user from database UserAccount user = PollenModelDAOHelper.getUserAccountDAO(transaction). - findByTopiaId(poll.getUserId()); + findByTopiaId(poll.getUserId()); // Prepare properties for find or create Map<String, Object> accountProperties = new HashMap<String, Object>(); @@ -223,7 +218,7 @@ for (PollAccountDTO accountDTO : listDTO.getPollAccountDTOs()) { double weight = accountDTO.getWeight(); PollAccount account = - pollAccountDAO.findByTopiaId(accountDTO.getId()); + pollAccountDAO.findByTopiaId(accountDTO.getId()); // Create a new PollAccount if not already exists if (account == null) { @@ -255,14 +250,14 @@ PollenConverter.convert(pollDTO, pollEntity); ChoiceDAO choiceDAO = PollenModelDAOHelper.getChoiceDAO(transaction); - + // ** Update choices (no add, no remove) for (ChoiceDTO choiceDTO : pollDTO.getChoiceDTOs()) { Choice choice = choiceDAO.findByTopiaId(choiceDTO.getId()); PollenConverter.convert(choiceDTO, choice); choice.update(); } - + // Les règles de notifications restent mystérieuses // Y a t-il un besoin de suppression ? converter.persistPreventRules(pollDTO, pollEntity); @@ -279,7 +274,7 @@ } catch (Exception eee) { PollenContext.doCatch(eee, _("pollen.error.servicePoll.updatePoll", - pollDTO.getTitle(), pollDTO.getPollId()), transaction); + pollDTO.getTitle(), pollDTO.getPollId()), transaction); return false; } finally { PollenContext.doFinally(transaction); @@ -350,12 +345,30 @@ result.addChoice(dto); } + +// List<Long> tmp = transaction.find( +// "SELECT COUNT(*)" + +// " FROM " + Vote.class.getName() + +// " WHERE poll.pollId = :pollUId", +// "pollUId", pollId); +// int count = tmp.get(0).intValue(); + +// VoteDAO voteDAO = PollenModelDAOHelper.getVoteDAO(transaction); +// int count = voteDAO.createQuery().add(Poll.POLL_ID, pollId).executeCount(); + + // Need the number total of votes to push in the dto + int count = new TopiaQuery(Vote.class). + add(Vote.POLL + "." + Poll.POLL_ID, pollId). + executeCount(transaction); + + result.setNbVotes(count); + // Load votes - for (Vote vote : pollEntity.getVote()) { - VoteDTO dto = - PollenConverter.convert(vote, new VoteDTO()); - result.addVote(dto); - } +// for (Vote vote : pollEntity.getVote()) { +// VoteDTO dto = +// PollenConverter.convert(vote, new VoteDTO()); +// result.addVote(dto); +// } // Load comments for (Comment comment : pollEntity.getComment()) { @@ -374,16 +387,14 @@ // TODO Refactor this if (pollEntity.getVotingList().size() > 0) { DataVotingListConverter votingListConverter = new DataVotingListConverter(); - result.setVotingListDTOs(votingListConverter - .createVotingListDTOs(pollEntity.getVotingList())); + result.setVotingListDTOs(votingListConverter.createVotingListDTOs(pollEntity.getVotingList())); } } //transaction.commitTransaction(); if (log.isDebugEnabled()) { - log.debug("Entity found: " - + ((result == null) ? "null" : result.getId())); + log.debug("Entity found: " + ((result == null) ? "null" : result.getId())); } return result; @@ -414,8 +425,7 @@ transaction.commitTransaction(); if (log.isDebugEnabled()) { - log.debug("Entities found: " - + ((results == null) ? "null" : results.size())); + log.debug("Entities found: " + ((results == null) ? "null" : results.size())); } return results; @@ -449,8 +459,7 @@ transaction.commitTransaction(); if (log.isDebugEnabled()) { - log.debug("Entities found: " - + ((results == null) ? "null" : results.size())); + log.debug("Entities found: " + ((results == null) ? "null" : results.size())); } return results; @@ -481,14 +490,12 @@ } converter.setTransaction(transaction); - results = converter - .createPollDTOs(new ArrayList<Poll>(pollEntities)); + results = converter.createPollDTOs(new ArrayList<Poll>(pollEntities)); transaction.commitTransaction(); if (log.isDebugEnabled()) { - log.debug("Entities found: " - + ((results == null) ? "null" : results.size())); + log.debug("Entities found: " + ((results == null) ? "null" : results.size())); } return results; @@ -517,15 +524,11 @@ Set<Poll> pollEntities = new HashSet<Poll>(); for (Poll poll : polls) { for (VotingList votingList : poll.getVotingList()) { - for (PersonToList personToList : votingList - .getPollAccountPersonToList()) { + for (PersonToList personToList : votingList.getPollAccountPersonToList()) { if (!personToList.getHasVoted()) { - PollAccount pollAccount = personToList - .getPollAccount(); - if (pollAccount != null - && pollAccount.getEmail() != null - && pollAccount.getEmail().equals( - user.getEmail())) { + PollAccount pollAccount = personToList.getPollAccount(); + if (pollAccount != null && pollAccount.getEmail() != null && pollAccount.getEmail().equals( + user.getEmail())) { pollEntities.add(poll); } } @@ -534,14 +537,12 @@ } converter.setTransaction(transaction); - results = converter - .createPollDTOs(new ArrayList<Poll>(pollEntities)); + results = converter.createPollDTOs(new ArrayList<Poll>(pollEntities)); transaction.commitTransaction(); if (log.isDebugEnabled()) { - log.debug("Entities found: " - + ((results == null) ? "null" : results.size())); + log.debug("Entities found: " + ((results == null) ? "null" : results.size())); } return results; @@ -567,7 +568,7 @@ Date currentDate = PollenContext.getCurrentDate(); TopiaQuery query = dao.createQuery(). - addNullOr(beginDate, Op.LT, currentDate); + addNullOr(beginDate, Op.LT, currentDate); if (withEndDate) { query.add(endDate, Op.GT, currentDate); @@ -598,8 +599,7 @@ transaction.commitTransaction(); if (log.isDebugEnabled()) { - log.debug("Entities found: " - + ((results == null) ? "null" : results.size())); + log.debug("Entities found: " + ((results == null) ? "null" : results.size())); } return results; @@ -624,8 +624,7 @@ if (properties == null) { pollEntities = pollDAO.findAll(); if (log.isWarnEnabled()) { - log - .warn("Attention : tous les sondages ont été sélectionnés !"); + log.warn("Attention : tous les sondages ont été sélectionnés !"); } } else { pollEntities = pollDAO.findAllByProperties(properties); @@ -636,8 +635,7 @@ transaction.commitTransaction(); if (log.isDebugEnabled()) { - log.debug("Entities found: " - + ((results == null) ? "null" : results.size())); + log.debug("Entities found: " + ((results == null) ? "null" : results.size())); } return results; @@ -676,10 +674,9 @@ } catch (Exception eee) { PollenContext.doCatch(eee, - _("pollen.error.servicePoll.addComment", - comment.getAuthor(), poll.getTitle(), poll.getId()), - transaction - ); + _("pollen.error.servicePoll.addComment", + comment.getAuthor(), poll.getTitle(), poll.getId()), + transaction); } finally { PollenContext.doFinally(transaction); } @@ -711,9 +708,47 @@ } catch (Exception eee) { PollenContext.doCatch(eee, _("pollen.error.servicePoll.deleteComment", commentId, - poll.getTitle(), poll.getId()), transaction); + poll.getTitle(), poll.getId()), transaction); } finally { PollenContext.doFinally(transaction); } } -} \ No newline at end of file + + @Override + public PollAccountDTO getRestrictedAccount(String accountUId, PollDTO poll) { + TopiaContext transaction = null; + PollAccountDTO result = null; + try { + transaction = rootContext.beginTransaction(); + + if (log.isInfoEnabled()) { + log.info("getRestrictedAccount : accountUId = " + accountUId + + " _ pollUId = " + poll.getPollId()); + } + + // Use PersonToList association entity to find coherence between + // the poll and votingId + List<PersonToList> tmp = transaction.find( + "FROM " + PersonToList.class.getName() + + " WHERE pollAccount.accountId = :accountUId" + + " AND votingList.poll.pollId = :pollUId", + "accountUId", accountUId, + "pollUId", poll.getPollId()); + + //PersonToListDAO dao = PollenModel + + if (tmp.size() > 0) { + PollAccount account = tmp.get(0).getPollAccount(); + PollenConverter.convert(account, result); + } + + } catch (Exception eee) { + ContextUtil.doCatch(eee, transaction, + "Unable to retrieve restricted account with accountUId = " + + accountUId + " and poll with uid = " + poll.getPollId()); + } finally { + ContextUtil.doFinally(transaction); + } + return result; + } +} Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVote.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVote.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVote.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -20,6 +20,7 @@ import java.util.Map; import org.chorem.pollen.business.dto.PollAccountDTO; +import org.chorem.pollen.business.dto.PollDTO; import org.chorem.pollen.business.dto.VoteDTO; /** @@ -54,6 +55,29 @@ public boolean deleteVote(String voteId); /** + * Retrieve existings votes from the {@code poll}. Only needed votes inside + * the range ({@code startIndex} and {@code endIndex}) will be retrieve. + * The results will be ordered by creationDate (the last vote done will + * be at the end of the list). + * + * @param poll to retrieve votes + * @param startIndex begin range for resulting votes + * @param endIndex end range for resulting votes + * @return the votes corresponding to the poll between the range + */ + public List<VoteDTO> getVotesByPoll(PollDTO poll, + int startIndex, int endIndex); + + /** + * Test if the {@code votingId} has already voted for the {@code poll}. + * + * @param votingId to test existing vote + * @param poll where the votingId can have already voted + * @return true if the votingId has already voted or false otherwise + */ + public boolean hasAlreadyVoted(String votingId, PollDTO poll); + + /** * Retourne les votes d'un sondage * * @param properties La HashMap pour sélectionner les votes d'un sondage. Il Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVoteImpl.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVoteImpl.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/services/ServiceVoteImpl.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -16,6 +16,7 @@ package org.chorem.pollen.business.services; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -26,6 +27,7 @@ import org.chorem.pollen.business.converters.DataPollAccountConverter; import org.chorem.pollen.business.converters.DataVoteConverter; import org.chorem.pollen.business.dto.PollAccountDTO; +import org.chorem.pollen.business.dto.PollDTO; import org.chorem.pollen.business.dto.VoteDTO; import org.chorem.pollen.business.persistence.PollAccount; import org.chorem.pollen.business.persistence.PollAccountDAO; @@ -184,6 +186,88 @@ } @Override + public List<VoteDTO> getVotesByPoll(PollDTO poll, + int startIndex, int endIndex) { + TopiaContext transaction = null; + List<VoteDTO> results = new ArrayList<VoteDTO>(); + try { + // No need to load votes for an anonymous poll + if (poll.isAnonymous()) { + return results; + } + + // FIXME-FD20100309 : change model to suppress link from poll to vote + // It's not necessary to have votes when retrieving the poll, this + // method do this job only when it's needed + + if (log.isDebugEnabled()) { + log.debug("Load votes for poll with uid = " + poll.getPollId()); + log.debug("LIMIT : startIndex = " + startIndex + " _ " + + "endIndex = " + endIndex); + } + + transaction = rootContext.beginTransaction(); + + // FIXME : refactor this to use TopiaQuery from ToPIA 2.3 + // Order the results by creation date (the last vote done will be + // at the end of the list) + List<Vote> votes = transaction.find( + "FROM " + Vote.class.getName() + + " WHERE poll.pollId = :pollUId" + + " ORDER BY topiaCreateDate", + startIndex, endIndex, + "pollUId", poll.getPollId()); + + if (log.isDebugEnabled()) { + log.debug("Nb votes found : " + votes.size()); + } + converter.setTransaction(transaction); + results = converter.createVoteDTOs(votes); + + } catch (Exception eee) { + ContextUtil.doCatch(eee, transaction, + "Unable to load votes from poll with uid = " + + poll.getPollId()); + } finally { + ContextUtil.doFinally(transaction); + } + return results; + } + + @Override + public boolean hasAlreadyVoted(String votingId, PollDTO poll) { + TopiaContext transaction = null; + boolean result = false; + try { + + transaction = rootContext.beginTransaction(); + + // Test using a count(*) on votes + List<Long> tmp = transaction.find( + "SELECT COUNT(*)" + + " FROM " + Vote.class.getName() + + " WHERE poll.pollId = :pollUId" + + " AND pollAccount.votingId = :votingId", + "pollUId", poll.getPollId(), + "votingId", votingId); + + int count = tmp.get(0).intValue(); + + // If the count is greater than 0, there is an existing votingId + // who has already voted for the poll + result = count > 0; + + } catch (Exception eee) { + ContextUtil.doCatch(eee, transaction, + "Unable test vote existing for account with votingId = " + + votingId + " and poll with uid = " + poll.getPollId()); + } finally { + ContextUtil.doFinally(transaction); + } + return result; + } + + @Override public List<VoteDTO> selectVotes(Map<String, Object> properties) { TopiaContext transaction = null; List<VoteDTO> results = null; Modified: trunk/pollen-business/src/main/java/org/chorem/pollen/business/utils/MailUtil.java =================================================================== --- trunk/pollen-business/src/main/java/org/chorem/pollen/business/utils/MailUtil.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/java/org/chorem/pollen/business/utils/MailUtil.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -22,7 +22,7 @@ import org.apache.commons.mail.SimpleEmail; /** - * Classe permettant d'envoyer des mails. Basée sur SimpleMail. + * Classe permettant d'envoyer des mails. Basée sur {@link SimpleEmail} (commons-email). * * @author rannou * @version $Id$ @@ -59,14 +59,15 @@ } if (log.isInfoEnabled()) { - log.info("Email envoyé."); + log.info("Mail sent to : " + to); + + if (log.isDebugEnabled()) { + log.debug("Détail de l'email : " + "\ndate: " + email.getSentDate() + + "\nhostname: " + email.getHostName() + "\nport: " + + email.getSmtpPort() + "\nfrom: " + + email.getFromAddress().toString() + "\nto: " + to + + "\nsubject: " + email.getSubject()); + } } - if (log.isDebugEnabled()) { - log.debug("Détail de l'email : " + "\ndate: " + email.getSentDate() - + "\nhostname: " + email.getHostName() + "\nport: " - + email.getSmtpPort() + "\nfrom: " - + email.getFromAddress().toString() + "\nto: " + to - + "\nsubject: " + email.getSubject()); - } } } Modified: trunk/pollen-business/src/main/resources/pollen.properties =================================================================== --- trunk/pollen-business/src/main/resources/pollen.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-business/src/main/resources/pollen.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -45,8 +45,11 @@ ## R\u00C3\u00A9pertoire des flux de syndication (Atom) feedDir=.pollen/feeds +## Repertoire de stockage des mails a envoyer +pollen.emails.directory=.pollen/emails + ## Nombre de votes a afficher par page -pollen.ui.nbVotesPerPage=100 +pollen.ui.nbVotesPerPage=50 ## Adresse du site (utilis\u00C3\u00A9e pour les emails de rappel) siteUrl= Added: trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/ScalingVote.java =================================================================== --- trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/ScalingVote.java (rev 0) +++ trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/ScalingVote.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,223 @@ +/* *##% Pollen + * Copyright (C) 2010 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ + +package org.chorem.pollen.business.scaling; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +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.PersonToList; +import org.chorem.pollen.business.persistence.Poll; +import org.chorem.pollen.business.persistence.PollAccount; +import org.chorem.pollen.business.persistence.PollAccountDAO; +import org.chorem.pollen.business.persistence.PollDAO; +import org.chorem.pollen.business.persistence.PollenModelDAOHelper; +import org.chorem.pollen.business.persistence.Vote; +import org.chorem.pollen.business.persistence.VoteDAO; +import org.chorem.pollen.business.persistence.VoteToChoice; +import org.chorem.pollen.business.persistence.VoteToChoiceDAO; +import org.chorem.pollen.business.persistence.VotingList; +import org.chorem.pollen.business.utils.ContextUtil; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaContextFactory; +import org.nuiton.topia.TopiaException; + +/** + * TODO add comment here. + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ + * By : $Author$ + */ +public class ScalingVote { + + /** log. */ + private static final Log log = LogFactory.getLog(ScalingVote.class); + + /** Adresse de la base de données (surchage l'adresse dans src/test/resources) */ + public static final String DB_URL = "jdbc:h2:" + System.getProperty("user.home") + + File.separator + ".pollen" + File.separator + "pollendb"; + + /** La config en cours. */ + protected static Properties config; + + /** + * Main. + * + * @param args + */ + public static void main(String args[]) { + System.out.println("Using database at : " + DB_URL); + + ContextUtil contextUtil = ContextUtil.getInstance(); + config = contextUtil.getConf(); + config.setProperty("hibernate.connection.url", DB_URL); + config.remove("hibernate.hbm2ddl.auto"); + + try { + new ScalingVote().doInsertFixedNumber(); + } + catch(Exception e) { + if (log.isErrorEnabled()) { + log.error("Can't insert mass mail", e); + } + } + } + + /** + * Insert a lot of vote into poll. + * + * This version find a poll with his name and add a vote + * for each votant in voting list. + * + * @throws TopiaException + */ + public void doInsertWithVotingList() throws TopiaException { + TopiaContext rootContext = TopiaContextFactory.getContext(config); + TopiaContext context = rootContext.beginTransaction(); + + PollDAO pollDAO = PollenModelDAOHelper.getPollDAO(context); + VoteDAO voteDAO = PollenModelDAOHelper.getVoteDAO(context); + VoteToChoiceDAO voteToChoiceDAO = PollenModelDAOHelper.getVoteToChoiceDAO(context); + + // find a poll with his name + Poll poll = pollDAO.findByTitle("Test condorcet 3000 v2"); + VotingList votingLists = poll.getVotingList().get(0); + + for (PersonToList personList : votingLists.getPollAccountPersonToList()) { + + PollAccount pollAccount = personList.getPollAccount(); + + // ne traite pas les email qui contienent 20 + // pour qu'il reste des choix de login ensuite + if (pollAccount.getEmail().contains("20@")) { + continue; + } + else { + if (log.isInfoEnabled()) { + log.info("Create vote for " + pollAccount.getEmail()); + } + } + + Vote myNewVote = voteDAO.create(); + myNewVote.setVotingList(votingLists); + myNewVote.setPollAccount(pollAccount); + myNewVote.setPoll(poll); + myNewVote.setWeight(new Double(1)); + myNewVote.setAnonymous(Boolean.FALSE); + + List<Choice> choices = new ArrayList<Choice>(); + choices.add(poll.getChoice().get(0)); + + List<VoteToChoice> voteToChoices = new ArrayList<VoteToChoice>(); + VoteToChoice voteToChoice = voteToChoiceDAO.create(); + voteToChoice.setChoice(poll.getChoice().get(0)); + voteToChoice.setVoteValue(1); + voteToChoice.setVote(myNewVote); + voteToChoices.add(voteToChoice); + + VoteToChoice voteToChoice2 = voteToChoiceDAO.create(); + voteToChoice2.setChoice(poll.getChoice().get(1)); + voteToChoice2.setVoteValue(2); + voteToChoice2.setVote(myNewVote); + voteToChoices.add(voteToChoice2); + + myNewVote.setChoiceVoteToChoice(voteToChoices); + myNewVote.update(); + poll.getVote().add(myNewVote); + } + + poll.update(); + context.commitTransaction(); + context.closeContext(); + + rootContext.closeContext(); + } + + /** + * Insert a lot of vote into poll. + * + * This version find a poll with his name and add a vote + * for each votant in voting list. + * + * @throws TopiaException + */ + public void doInsertFixedNumber() throws TopiaException { + TopiaContext rootContext = TopiaContextFactory.getContext(config); + TopiaContext context = rootContext.beginTransaction(); + + PollDAO pollDAO = PollenModelDAOHelper.getPollDAO(context); + VoteDAO voteDAO = PollenModelDAOHelper.getVoteDAO(context); + PollAccountDAO pollAccountDAO = PollenModelDAOHelper.getPollAccountDAO(context); + VoteToChoiceDAO voteToChoiceDAO = PollenModelDAOHelper.getVoteToChoiceDAO(context); + + // find a poll with his name + Poll poll = pollDAO.findByTitle("test pagination 3000"); + + for (int i = 1 ; i <= 4200 ; ++i) { + + PollAccount pollAccount = pollAccountDAO.create(); + pollAccount.setVotingId("Test " + i); + + if (log.isInfoEnabled()) { + log.info("Create vote for " + pollAccount.getVotingId()); + } + + Vote myNewVote = voteDAO.create(); + myNewVote.setPollAccount(pollAccount); + myNewVote.setPoll(poll); + myNewVote.setWeight(new Double(1)); + myNewVote.setAnonymous(Boolean.FALSE); + + List<Choice> choices = new ArrayList<Choice>(); + choices.add(poll.getChoice().get(0)); + + List<VoteToChoice> voteToChoices = new ArrayList<VoteToChoice>(); + + if (i % 2 == 0) { + VoteToChoice voteToChoice = voteToChoiceDAO.create(); + voteToChoice.setChoice(poll.getChoice().get(0)); + voteToChoice.setVoteValue(1); + voteToChoice.setVote(myNewVote); + voteToChoices.add(voteToChoice); + } + else { + VoteToChoice voteToChoice2 = voteToChoiceDAO.create(); + voteToChoice2.setChoice(poll.getChoice().get(1)); + voteToChoice2.setVoteValue(2); + voteToChoice2.setVote(myNewVote); + voteToChoices.add(voteToChoice2); + } + + myNewVote.setChoiceVoteToChoice(voteToChoices); + myNewVote.update(); + poll.getVote().add(myNewVote); + + } + poll.update(); + context.commitTransaction(); + context.closeContext(); + + rootContext.closeContext(); + } +} Property changes on: trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/ScalingVote.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Added: trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/package-info.java =================================================================== --- trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/package-info.java (rev 0) +++ trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/package-info.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,20 @@ +/* *##% Pollen + * Copyright (C) 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ + +/** + * Ensemble de classes pour injecter des données et faire de la montée en charge. + */ +package org.chorem.pollen.business.scaling; Property changes on: trunk/pollen-business/src/test/java/org/chorem/pollen/business/scaling/package-info.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Added: 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 (rev 0) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/components/Pager.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,197 @@ +package org.chorem.pollen.ui.components; + + +import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.ComponentResources; +import org.apache.tapestry5.EventConstants; +import org.apache.tapestry5.Link; +import org.apache.tapestry5.MarkupWriter; +import org.apache.tapestry5.annotations.Log; +import org.apache.tapestry5.annotations.Parameter; +import org.apache.tapestry5.ioc.Messages; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.slf4j.Logger; + + +/** + * Pager + * + * Created: 8 mars 2010 + * + * @author fdesbois + * @version $Revision$ + * + * Mise a jour: $Date$ + * par : $Author$ + */ +public class Pager { + + /** + * Number of total rows. + */ + @Parameter(required = true) + private int nbTotalRows; + + /** + * Main element of the pager, the page which contains the pager have + * to manage this property (using @Persist for exemple) to ensure that + * the pager will done its work correctly. You can use + * {@link #getFirstPage() } to initialize the first page. + */ + @Parameter(required = true) + private int currentPage; + + /** + * Number of rows to show per page. + */ + @Parameter(required = true) + private int nbRowsPerPage; + + @Parameter(defaultPrefix = BindingConstants.LITERAL) + private String noPagerText; + + @Inject + private ComponentResources resources; + + @Inject + private Messages messages; + + @Inject + private Logger log; + + void beginRender(MarkupWriter writer) { + if (log.isDebugEnabled()) { + log.debug("pager from : " + getFirstValue() + " to " + getLastValue()); + log.debug("current page : " + currentPage); + log.debug("max nb rows : " + nbTotalRows); + log.debug("has previous : " + hasPrevious()); + log.debug("has next : " + hasNext()); + log.debug("indexes from : " + getStartIndex() + " to " + getEndIndex()); + log.debug("last page : " + getLastPage()); + } + writer.element("div", "class", "p-pager"); + // If firstPage and lastPage are the same, no need to use the pager + if (getFirstPage() == getLastPage()) { + writer.write(noPagerText); + } else { + if (hasPrevious()) { + int previousPage = currentPage - 1; + if (previousPage != getFirstPage()) { + writeLink(writer, getFirstPage(), "<<", "p-pager-first"); + writer.write(" "); + } + writeLink(writer, previousPage, "<", "p-pager-previous"); + writer.write(" "); + } + // Text display for current page + writer.element("span", "title", + messages.format("rows-title", + getFirstValue(), getLastValue(), nbTotalRows)); + writer.element("strong"); + writer.write(messages.format("page", currentPage)); + writer.end(); + writer.end(); + + if (hasNext()) { + int nextPage = currentPage + 1; + writer.write(" "); + writeLink(writer, nextPage, ">", "p-pager-next"); + if (nextPage != getLastPage()) { + writer.write(" "); + writeLink(writer, getLastPage(), ">>", "p-pager-last"); + } + } + } + writer.end(); + } + + void afterRender(MarkupWriter writer) { + + } + + /** + * Use an action event to change the current page. The link refresh the + * entire page, no zone is managed yet. + * + * @param writer used to write a element + * @param index new page to change (argument of onAction method) + * @param text to write inside the a tag + * @param style of the css (class) for the a tag + */ + protected void writeLink(MarkupWriter writer, int index, + String text, String style) { + Link link = resources.createEventLink(EventConstants.ACTION, + new Object[] {index}); + String title = messages.format("go-to", index); + writer.element("a", "href", link, "class", style, "title", title); + writer.write(text); + writer.end(); + } + + /** + * Get the start index of the range shown. + * + * @return the start index for elements to show + */ + public int getStartIndex() { + return ( (currentPage - 1) * nbRowsPerPage); + } + + /** + * Get the end index of the range shown. + * + * @return the end index for elements to show + */ + public int getEndIndex() { + int end = (currentPage * nbRowsPerPage) - 1; + if (end >= nbTotalRows) { + end = nbTotalRows - 1; + } + return end; + } + + protected int getFirstValue() { + return getStartIndex() + 1; + } + + protected int getLastValue() { + return getEndIndex() + 1; + } + + /** + * Test if there is previous elements before this actual range. + * + * @return true if there is previous elements, false otherwise + */ + public boolean hasPrevious() { + return getStartIndex() > 0; + } + + /** + * Test if there is next elements after this actual range. + * + * @return true if there is next elements, false otherwise + */ + public boolean hasNext() { + return getEndIndex() < (nbTotalRows - 1); + } + + public int getFirstPage() { + return 1; + } + + public int getLastPage() { + return (int)Math.ceil((double)nbTotalRows / (double)nbRowsPerPage); + } + + /** + * Action event for changing page. The currentPage is changed to + * {@code newPage}. + * + * @param newPage to set + */ + void onAction(int newPage) { + currentPage = newPage; + } + +} Property changes on: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/components/Pager.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/admin/UsersAdmin.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/admin/UsersAdmin.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/admin/UsersAdmin.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -212,6 +212,8 @@ .getFirstName(), newUser.getLastName(), newUser.getLogin(), password, siteURL)); + // FIXME call directly MailUtil.sendMail() + // skip fill map, get from map... PreventRuleManager.emailAction(data); } Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollCreation.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollCreation.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollCreation.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -13,10 +13,10 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ - package org.chorem.pollen.ui.pages.poll; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -74,6 +74,7 @@ import org.chorem.pollen.ui.data.uio.ImageChoiceUIO; import org.chorem.pollen.ui.utils.FeedUtil; import org.chorem.pollen.ui.utils.ImageUtil; +import org.chorem.pollen.ui.utils.SendMail; import org.chorem.pollen.ui.utils.UnitConverter; import org.slf4j.Logger; @@ -89,11 +90,9 @@ @Inject private Logger log; - /** Étape courante du formulaire */ @Persist private PollStep step; - /** * Objet de session représentant l'utilisateur identifié. */ @@ -101,205 +100,172 @@ private UserDTO user; @Property private boolean userExists; - /** * Objet de session représentant l'url du site. */ @SessionState @Property private String siteURL; - /** Date de début du sondage (utilisée pour la validation). */ private Date beginDateValidation; - /** Date de début d'ajout des choix (utilisée pour la validation). */ private Date beginChoiceDateValidation; - /** Mixin de selection de liste de favoris */ @SuppressWarnings("unused") private Select listSelect; - @InjectComponent private Zone pollCreationZone; - /** * Sondage créé par le formulaire */ @Property @Persist private PollDTO poll; - /** * Sondage copié pour créer un nouveau sondage */ @Persist private PollDTO oldPoll; - /** * Sondage copié existe. */ private boolean oldPollExists = false; - /** * variable utilisée pour déterminer si le bouton cliqué mène à l'étape * suivante */ private boolean noStepSubmitSelected = false; - /** * variable utilisée pour déterminer si le bouton d'ajout de choix a été * cliqué */ @Persist private boolean addChoiceSelected; - /** * variable utilisée pour déterminer le groupe à supprimer */ private int deleteGroupId = -1; - /** * variable utilisée pour déterminer s'il y a eu une exception lors de * l'upload des images */ @Persist private boolean uploadExceptionCatched; - /** variable utilisée pour l'affichage de la choiceNbCheckBox */ @Property @Persist private boolean choiceNbCheckBox; - /** variable utilisée pour l'affichage de la notificationCheckBox */ @Property @Persist private boolean notificationCheckBox; - /** variable utilisée pour l'affichage de la reminderCheckBox */ @Property @Persist private boolean reminderCheckBox; - /** Règle de notification de vote */ @Property @Persist private PreventRuleDTO notificationPreventRule; - /** Règle de notification pour le rappel des votants */ @Property @Persist private PreventRuleDTO reminderPreventRule; - /** * Groupes de votants à créer */ @Property @Persist private List<VotingListDTO> votingLists; - /** * Objet utilisé dans la boucle de parcours des listes de votants */ @Property private VotingListDTO votingList; - /** * Objet utilisé dans la boucle de parcours de la liste de votants courante */ @SuppressWarnings("unused") @Property private PollAccountDTO votingListPerson; - /** * Nombre de votants affichés initialement */ @Property private int nbVotingListPersons = 5; - /** * Liste modifiée actuellement */ @Persist private int currentList; - /** * Listes de favoris de l'utilisateur. */ @Property @Persist private GenericSelectModel<PersonListDTO> personLists; - /** * Liste de favoris sélectionnée. */ @Property private PersonListDTO personList; - /** * Nombre de choix affichés initialement */ @Property private int nbChoices = 5; - /** * Objet utilisé dans la boucle de parcours de la liste des choix */ @SuppressWarnings("unused") @Property private ChoiceDTO choice; - /** * Objet utilisé dans la boucle de parcours de la liste des choix */ @SuppressWarnings("unused") @Property private DateChoiceUIO dateTypeChoice; - /** * Objet utilisé dans la boucle de parcours de la liste des choix */ @SuppressWarnings("unused") @Property private ImageChoiceUIO imgTypeChoice; - /** * Liste des choix à créer */ @Property @Persist private List<ChoiceDTO> choices; - /** * Liste des choix à créer */ @Property @Persist private List<DateChoiceUIO> dateTypeChoices; - /** * Liste des choix à créer */ @Property @Persist private List<ImageChoiceUIO> imgTypeChoices; - /** * Contexte pour l'upload des images (parametres definis dans .tml) */ @InjectComponent private ImageContextLink imgContext; - /** * Contexte pour la gestion du flux RSS */ @InjectComponent private ContextLink feedContext; - /** * Formulaire de création de sondage */ @Component(id = "pollCreationForm") private Form pollCreationForm; + @Component(id = "choicesCreationForm") private Form choicesCreationForm; @@ -328,6 +294,7 @@ @Inject @Symbol(UploadSymbols.FILESIZE_MAX) private int fileSizeMax; + @Inject @Symbol(UploadSymbols.REQUESTSIZE_MAX) private int requestSizeMax; @@ -341,11 +308,16 @@ /** Injection des services */ @Inject private ServicePoll servicePoll; + @Inject private ServicePollAccount servicePollAccount; + @Inject private ServiceList serviceList; + @Inject + private SendMail sendMailService; + /** * Méthode appelée lorsqu'on souhaite accéder à l'étape suivante de la * création de sondage. @@ -356,31 +328,31 @@ log.debug("Step : " + step); } switch (step) { - case POLL: - adaptStepPoll(); - step = PollStep.OPTIONS; - break; - case OPTIONS: - adaptStepOptions(); - if (isFreePoll()) { - step = PollStep.CHOICES; - } else { - step = PollStep.LISTS; - } - break; - case LISTS: - if (deleteGroupId >= 0) { - votingLists.remove(deleteGroupId); - } - if (!noStepSubmitSelected) { - step = PollStep.CHOICES; - } - break; - case CHOICES: - break; - default: - step = PollStep.POLL; - break; + case POLL: + adaptStepPoll(); + step = PollStep.OPTIONS; + break; + case OPTIONS: + adaptStepOptions(); + if (isFreePoll()) { + step = PollStep.CHOICES; + } else { + step = PollStep.LISTS; + } + break; + case LISTS: + if (deleteGroupId >= 0) { + votingLists.remove(deleteGroupId); + } + if (!noStepSubmitSelected) { + step = PollStep.CHOICES; + } + break; + case CHOICES: + break; + default: + step = PollStep.POLL; + break; } // Cas particulier, autre formulaire pour les choix if (step.equals(PollStep.CHOICES)) { @@ -402,7 +374,7 @@ /** * Méthode appelée lorsqu'on souhaite valider la création du sondage. */ - Object onSuccessFromChoicesCreationForm() { + Object onSuccessFromChoicesCreationForm() { if (!addChoiceSelected) { // Préparation et création du sondage @@ -424,22 +396,22 @@ */ Object onPrevious() { switch (step) { - case OPTIONS: - step = PollStep.POLL; - break; - case LISTS: - step = PollStep.OPTIONS; - break; - case CHOICES: - if (isFreePoll()) { + case OPTIONS: + step = PollStep.POLL; + break; + case LISTS: step = PollStep.OPTIONS; - } else { - step = PollStep.LISTS; - } - break; - default: - step = PollStep.POLL; - break; + break; + case CHOICES: + if (isFreePoll()) { + step = PollStep.OPTIONS; + } else { + step = PollStep.LISTS; + } + break; + default: + step = PollStep.POLL; + break; } return pollCreationForm; // Pas de gestion du formulaire des choix car derniere etape } @@ -485,10 +457,10 @@ } beginChoiceDateValidation = value; if (value != null && value.after(beginDateValidation)) { - throw new ValidationException(messages - .get("beginChoiceDate-validate")); + throw new ValidationException(messages.get("beginChoiceDate-validate")); } } + /** * Méthode appelée lors de la validation du formulaire. Validation du champs * endChoiceDate. @@ -539,17 +511,14 @@ for (VotingListDTO list1 : votingLists) { int nbLocalNotNull = 0; for (PollAccountDTO account1 : list1.getPollAccountDTOs()) { - if (account1.getVotingId() != null - && account1.getVotingId() != "") { + if (account1.getVotingId() != null && account1.getVotingId() != "") { nbNotNull++; nbLocalNotNull++; // comparaison avec les autres votants for (VotingListDTO list2 : votingLists) { - for (PollAccountDTO account2 : list2 - .getPollAccountDTOs()) { - if (account2.getVotingId() != null - && account1.getVotingId() != "") { + for (PollAccountDTO account2 : list2.getPollAccountDTOs()) { + if (account2.getVotingId() != null && account1.getVotingId() != "") { if (account1.getVotingId().equals( account2.getVotingId())) { nbEqual++; @@ -560,14 +529,12 @@ } } if (nbLocalNotNull == 0) { - throw new ValidationException(messages - .get("noList-validate")); + throw new ValidationException(messages.get("noList-validate")); } } if (logger.isDebugEnabled()) { - logger.debug("Votants (equal/notNull) : " + nbEqual + "/" - + nbNotNull); + logger.debug("Votants (equal/notNull) : " + nbEqual + "/" + nbNotNull); } if (nbEqual > nbNotNull) { throw new ValidationException(messages.get("list-validate")); @@ -673,17 +640,13 @@ // Sondage libre : suppression de toutes les listes if (isFreePoll()) { votingLists.clear(); - } - - // Sondage restreint : suppression des listes supplémentaires + } // Sondage restreint : suppression des listes supplémentaires else if (isRestrictedPoll() && votingLists.size() > 1) { for (int i = 1; i < votingLists.size(); i++) { votingLists.remove(i); } currentList = 0; - } - - // Sondage non libre : création d'une liste initiale + } // Sondage non libre : création d'une liste initiale else if (votingLists.isEmpty()) { votingList = new VotingListDTO(); for (int i = 0; i < nbVotingListPersons; i++) { @@ -721,8 +684,7 @@ // après suppression des entrées vides if (!isFreePoll()) { for (VotingListDTO list : votingLists) { - Iterator<PollAccountDTO> it = list.getPollAccountDTOs() - .iterator(); + Iterator<PollAccountDTO> it = list.getPollAccountDTOs().iterator(); while (it.hasNext()) { if (it.next().getVotingId() == null) { it.remove(); @@ -732,7 +694,7 @@ poll.setVotingListDTOs(votingLists); } - + // Ajout des choix au sondage if (isTextChoices()) { for (ChoiceDTO choice : choices) { @@ -752,14 +714,11 @@ } else if (isImgChoices()) { for (ImageChoiceUIO imgChoice : imgTypeChoices) { if (imgChoice.getImg() != null) { - logger.debug("Image: " + imgChoice.getImg().getFileName() - + ", type: " + imgChoice.getImg().getContentType()); - if (imgChoice.getImg().getContentType().contains("image") - || imgChoice.getImg().getContentType().contains( - "IMAGE")) { + logger.debug("Image: " + imgChoice.getImg().getFileName() + ", type: " + imgChoice.getImg().getContentType()); + if (imgChoice.getImg().getContentType().contains("image") || imgChoice.getImg().getContentType().contains( + "IMAGE")) { imgChoice.setValidate(true); - imgChoice.setName(imgChoice.getImg().getFileName() - .replace(' ', '_')); + imgChoice.setName(imgChoice.getImg().getFileName().replace(' ', '_')); poll.getChoiceDTOs().add(imgChoice); } else { return false; @@ -767,7 +726,7 @@ } } } - + // Retouche des attributs dépendants l'un de l'autre if (poll.getBeginDate() == null) { poll.setBeginDate(new Date()); @@ -778,8 +737,7 @@ if (poll.isContinuousResults()) { poll.setPublicResults(true); } - if (poll.getMaxChoiceNb() < 1 - || poll.getMaxChoiceNb() > poll.getChoiceDTOs().size()) { + if (poll.getMaxChoiceNb() < 1 || poll.getMaxChoiceNb() > poll.getChoiceDTOs().size()) { poll.setMaxChoiceNb(poll.getChoiceDTOs().size()); } @@ -789,7 +747,7 @@ /** * Création du sondage. */ - private void createPoll() { + private void createPoll() { // Création du sondage servicePoll.createPoll(poll); @@ -798,45 +756,59 @@ // problem comes from createPoll //if (poll.getId() != null) { - // Création des images - if (poll.getChoiceType() == ChoiceType.IMAGE) { - File dir = imgContext.getImageDir(); - ImageUtil.saveImages(imgTypeChoices, dir); + // Création des images + if (poll.getChoiceType() == ChoiceType.IMAGE) { + File dir = imgContext.getImageDir(); + ImageUtil.saveImages(imgTypeChoices, dir); + } + + // FD-20100226 : not necessary, the service will update + // automatically the poll when it was created + // Mise à jour du sondage : + //poll = servicePoll.findPollById(poll.getId()); + + // Mise à jour du flux Atom et envoi d'un mail de confirmation + addFeedEntry(); + + // on les passe en parametres car au + // moment de l'execution du thread, il y a des NPE + // à l'utilisation des valeurs + final String localSiteURL = siteURL; + final ServicePollAccount localServicePollAccount = servicePollAccount; + final PollDTO localPoll = poll; + final Messages localMessages = messages; + + // Mise à jour du flux Atom et envoi d'un mail de confirmation + // FIXME replace this ugly thread code !!! + new Thread() { + @Override + public void run() { + sendMailNotification(localSiteURL, localServicePollAccount, + localPoll, localMessages); } + }.start(); - // FD-20100226 : not necessary, the service will update - // automatically the poll when it was created - // Mise à jour du sondage : - //poll = servicePoll.findPollById(poll.getId()); - - // Mise à jour du flux Atom et envoi d'un mail de confirmation - addFeedEntry(); - sendMailNotification(); - //} } /** Ajout d'une entrée dans le flux de syndication */ - private void addFeedEntry() { - PollAccountDTO creator = servicePollAccount.findPollAccountById(poll - .getCreatorId()); - String voteURL = siteURL + "poll/VoteFor/" + poll.getPollId(); + private void addFeedEntry() { + PollAccountDTO creator = servicePollAccount.findPollAccountById(poll.getCreatorId()); + String voteURL = siteURL + "poll/votefor/" + poll.getPollId(); File feedFile = feedContext.getFile(poll.getPollId()); FeedUtil.createFeed(feedFile, "atom_1.0", messages.format( "pollFeed_title", poll.getTitle()), siteURL, messages.format( "pollFeed_desc", poll.getDescription())); FeedUtil.feedFeed(feedFile, messages.format("pollFeed_createTitle", - creator.getVotingId()), voteURL, messages - .get("pollFeed_createContent")); + creator.getVotingId()), voteURL, messages.get("pollFeed_createContent")); } /** Envoi du mail de notification */ - private void sendMailNotification() { - PollAccountDTO creator = servicePollAccount.findPollAccountById(poll - .getCreatorId()); + private void sendMailNotification(String siteURL, ServicePollAccount servicePollAccount, + PollDTO poll, Messages messages) { + PollAccountDTO creator = servicePollAccount.findPollAccountById(poll.getCreatorId()); String voteURL = siteURL + "poll/VoteFor/" + poll.getPollId(); - String modifURL = siteURL + "poll/Modification/" + poll.getPollId() - + ":" + creator.getAccountId(); + String modifURL = siteURL + "poll/Modification/" + poll.getPollId() + ":" + creator.getAccountId(); Map<String, String> data = new HashMap<String, String>(); data.put("host", PollenProperty.EMAIL_HOST.getValue()); data.put("port", PollenProperty.EMAIL_PORT.getValue()); @@ -845,32 +817,51 @@ // Mail au créateur if (poll.getCreatorEmail() != null) { data.put("to", poll.getCreatorEmail()); - data.put("title", messages.format("creatorEmail_subject", poll - .getTitle())); + data.put("title", messages.format("creatorEmail_subject", poll.getTitle())); data.put("msg", messages.format("creatorEmail_msg", poll.getTitle(), voteURL, modifURL)); + // FIXME call directly MailUtil.sendMail() + // skip fill map, get from map... PreventRuleManager.emailAction(data); } // Mails aux votants for (VotingListDTO list : poll.getVotingListDTOs()) { + + List<Map<String, String>> mailList = new ArrayList<Map<String, String>>(); for (PollAccountDTO account : list.getPollAccountDTOs()) { if (account.getEmail() != null) { - String accountVoteURL = voteURL + ":" - + account.getAccountId(); + String accountVoteURL = voteURL + ":" + account.getAccountId(); - data.put("to", account.getEmail()); + /*data.put("to", account.getEmail()); data.put("title", messages.format("votingEmail_subject", - poll.getTitle())); - data - .put("msg", messages.format("votingEmail_msg", poll - .getTitle(), account.getVotingId(), - accountVoteURL)); + poll.getTitle())); + data.put("msg", messages.format("votingEmail_msg", poll + .getTitle(), account.getVotingId(), + accountVoteURL)); - PreventRuleManager.emailAction(data); + // FIXME call directly MailUtil.sendMail() + // skip fill map, get from map... + PreventRuleManager.emailAction(data);*/ + + Map<String, String> mailData = new HashMap<String, String>(); + mailData.put("receiver", account.getEmail()); + mailData.put("subject", messages.format("votingEmail_subject", poll.getTitle())); + mailData.put("body", messages.format("votingEmail_msg", poll.getTitle(), account.getVotingId(), accountVoteURL)); + mailList.add(mailData); } } + + // send mail preparation + try { + sendMailService.prepareMails(poll.getId(), mailList); + sendMailService.wakeUp(); + } catch (IOException ex) { + if (log.isErrorEnabled()) { + log.error("Can't prepare send mail on disk, mail won't be send !!!", ex); + } + } } } @@ -913,16 +904,16 @@ // mise en forme du message switch (step) { - case POLL: - return messages.format("pollLegend", index); - case OPTIONS: - return messages.format("optionsLegend", index); - case LISTS: - return messages.format("listsLegend", index); - case CHOICES: - return messages.format("choicesLegend", index); - default: - return ""; + case POLL: + return messages.format("pollLegend", index); + case OPTIONS: + return messages.format("optionsLegend", index); + case LISTS: + return messages.format("listsLegend", index); + case CHOICES: + return messages.format("choicesLegend", index); + default: + return ""; } } @@ -972,7 +963,7 @@ public boolean isNumberVoteCounting() { return poll.getVoteCounting() == VoteCountingType.NUMBER; } - + public boolean isFreePoll() { return poll.getPollType() == PollType.FREE; } @@ -1009,6 +1000,7 @@ * zone. */ public JSONObject onChangeFromListSelect(String value) { + JSONObject result = new JSONObject(); if (StringUtils.isNotEmpty(value)) { personList = serviceList.findPersonListById(value); @@ -1020,11 +1012,44 @@ votingLists.get(currentList).setPollAccountDTOs( personList.getPollAccounts()); + + int size = personList.getPollAccounts().size(); + + if (log.isDebugEnabled()) { + log.debug("List size : " + size); + } + + // If the list size is too large, an alert message will be shown + if (size > LIST_MAX_SHOW_PERSONS) { + result.put("listAlert", messages.format("list-maxSize-alert", + personList.getName(), size)); + } } - return createParamsForCallback(); + return createParamsForCallback(result); } + /** TODO : move this value to pollen.properties, waiting for 1.3 version **/ + public static final int LIST_MAX_SHOW_PERSONS = 20; /** + * Test if the list size made an alert (too large to be shown). + * + * @return true if the current list size is > to LIST_MAX_SHOW_PERSONS + */ + public boolean isListSizeAlert() { + return votingList.getPollAccountDTOs().size() > LIST_MAX_SHOW_PERSONS; + } + + /** + * Get the message to show when the too large list size is loaded. + * + * @return the localized message to show when big list is loaded. + */ + public String getListMaxSizeLoadedMessage() { + return messages.format("list-maxSize-loaded", votingList.getName(), + votingList.getPollAccountDTOs().size()); + } + + /** * Méthode appelée à la sélection d'un type de choix. Le mixin ck/OnEvent ne * permet pas de retourner le contenu d'une zone. Il faut donc passer par * une fonction JavaScript pour activer un event link. Un lien est créé. Il @@ -1036,7 +1061,7 @@ */ public JSONObject onChangeFromChoiceType(String value) { poll.setChoiceType(ChoiceType.valueOf(value)); - return createParamsForCallback(); + return createParamsForCallback(new JSONObject()); } /** @@ -1045,8 +1070,8 @@ * * @return un JSONObject contenant un zoneId et une url. */ - private JSONObject createParamsForCallback() { - JSONObject json = new JSONObject(); + private JSONObject createParamsForCallback(JSONObject json) { + //JSONObject json = new JSONObject(); Link link = resources.createEventLink("updatePollCreationZone"); json.put("link", link.toAbsoluteURI()); json.put("zoneId", "pollCreationZone"); @@ -1154,11 +1179,10 @@ * Initialisation de l'affichage */ void setupRender() { - address = new AddressBarItem[] { new AddressBarItem("Pollen", "Index"), - new AddressBarItem(title, null) }; + address = new AddressBarItem[]{new AddressBarItem("Pollen", "Index"), + new AddressBarItem(title, null)}; - if (!addChoiceSelected && !uploadExceptionCatched - && !choicesCreationForm.getHasErrors()) { + if (!addChoiceSelected && !uploadExceptionCatched && !choicesCreationForm.getHasErrors()) { step = PollStep.POLL; if (!oldPollExists) { oldPoll = null; @@ -1223,8 +1247,7 @@ poll.setCreatorEmail(oldPoll.getCreatorEmail()); // Initialisation des règles de notification - notificationPreventRule = PollHelper - .getNotificationPreventRule(oldPoll); + notificationPreventRule = PollHelper.getNotificationPreventRule(oldPoll); notificationCheckBox = !"".equals(notificationPreventRule.getScope()); reminderPreventRule = PollHelper.getReminderPreventRule(oldPoll); reminderCheckBox = !"".equals(reminderPreventRule.getScope()); @@ -1243,8 +1266,7 @@ */ private void initPersonLists() { if (userExists) { - List<PersonListDTO> _personLists = serviceList - .findPersonListByUser(user.getId()); + List<PersonListDTO> _personLists = serviceList.findPersonListByUser(user.getId()); personLists = new GenericSelectModel<PersonListDTO>(_personLists, PersonListDTO.class, "name", "id", _propertyAccess); } Added: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollCreation.java.orig =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollCreation.java.orig (rev 0) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollCreation.java.orig 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,1252 @@ +/* *##% Pollen + * Copyright (C) 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ + +package org.chorem.pollen.ui.pages.poll; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.lang.StringUtils; +import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.ComponentResources; +import org.apache.tapestry5.Link; +import org.apache.tapestry5.ValidationException; +import org.apache.tapestry5.annotations.Component; +import org.apache.tapestry5.annotations.IncludeStylesheet; +import org.apache.tapestry5.annotations.InjectComponent; +import org.apache.tapestry5.annotations.InjectPage; +import org.apache.tapestry5.annotations.Log; +import org.apache.tapestry5.annotations.Parameter; +import org.apache.tapestry5.annotations.Persist; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.annotations.SessionState; +import org.apache.tapestry5.corelib.components.Form; +import org.apache.tapestry5.corelib.components.Select; +import org.apache.tapestry5.corelib.components.Zone; +import org.apache.tapestry5.ioc.Messages; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.ioc.services.PropertyAccess; +import org.apache.tapestry5.json.JSONObject; +import org.apache.tapestry5.upload.services.UploadSymbols; +import org.chorem.pollen.business.PollenProperty; +import org.chorem.pollen.business.business.PreventRuleManager; +import org.chorem.pollen.business.dto.ChoiceDTO; +import org.chorem.pollen.business.dto.PersonListDTO; +import org.chorem.pollen.business.dto.PollAccountDTO; +import org.chorem.pollen.business.dto.PollDTO; +import org.chorem.pollen.business.dto.PreventRuleDTO; +import org.chorem.pollen.business.dto.UserDTO; +import org.chorem.pollen.business.dto.VotingListDTO; +import org.chorem.pollen.business.services.ServiceList; +import org.chorem.pollen.business.services.ServicePoll; +import org.chorem.pollen.business.services.ServicePollAccount; +import org.chorem.pollen.common.ChoiceType; +import org.chorem.pollen.common.PollType; +import org.chorem.pollen.common.VoteCountingType; +import org.chorem.pollen.ui.base.ContextLink; +import org.chorem.pollen.ui.components.FeedBack; +import org.chorem.pollen.ui.components.ImageContextLink; +import org.chorem.pollen.ui.data.GenericSelectModel; +import org.chorem.pollen.ui.data.AddressBarItem; +import org.chorem.pollen.ui.data.PollHelper; +import org.chorem.pollen.ui.data.PollStep; +import org.chorem.pollen.ui.data.uio.DateChoiceUIO; +import org.chorem.pollen.ui.data.uio.ImageChoiceUIO; +import org.chorem.pollen.ui.utils.FeedUtil; +import org.chorem.pollen.ui.utils.ImageUtil; +import org.chorem.pollen.ui.utils.UnitConverter; +import org.slf4j.Logger; + +/** + * Classe de la page de création d'un sondage. + * + * @author kmorin + * @author rannou + * @version $Id: PollCreation.java 2893 2010-03-02 20:14:34Z fdesbois $ + */ +@IncludeStylesheet("context:css/pollCreation.css") +public class PollCreation { + + @Inject + private Logger log; + + /** Étape courante du formulaire */ + @Persist + private PollStep step; + + /** + * Objet de session représentant l'utilisateur identifié. + */ + @SessionState + private UserDTO user; + @Property + private boolean userExists; + + /** + * Objet de session représentant l'url du site. + */ + @SessionState + @Property + private String siteURL; + + /** Date de début du sondage (utilisée pour la validation). */ + private Date beginDateValidation; + + /** Date de début d'ajout des choix (utilisée pour la validation). */ + private Date beginChoiceDateValidation; + + /** Mixin de selection de liste de favoris */ + @SuppressWarnings("unused") + private Select listSelect; + + @InjectComponent + private Zone pollCreationZone; + + /** + * Sondage créé par le formulaire + */ + @Property + @Persist + private PollDTO poll; + + /** + * Sondage copié pour créer un nouveau sondage + */ + @Persist + private PollDTO oldPoll; + + /** + * Sondage copié existe. + */ + private boolean oldPollExists = false; + + /** + * variable utilisée pour déterminer si le bouton cliqué mène à l'étape + * suivante + */ + private boolean noStepSubmitSelected = false; + + /** + * variable utilisée pour déterminer si le bouton d'ajout de choix a été + * cliqué + */ + @Persist + private boolean addChoiceSelected; + + /** + * variable utilisée pour déterminer le groupe à supprimer + */ + private int deleteGroupId = -1; + + /** + * variable utilisée pour déterminer s'il y a eu une exception lors de + * l'upload des images + */ + @Persist + private boolean uploadExceptionCatched; + + /** variable utilisée pour l'affichage de la choiceNbCheckBox */ + @Property + @Persist + private boolean choiceNbCheckBox; + + /** variable utilisée pour l'affichage de la notificationCheckBox */ + @Property + @Persist + private boolean notificationCheckBox; + + /** variable utilisée pour l'affichage de la reminderCheckBox */ + @Property + @Persist + private boolean reminderCheckBox; + + /** Règle de notification de vote */ + @Property + @Persist + private PreventRuleDTO notificationPreventRule; + + /** Règle de notification pour le rappel des votants */ + @Property + @Persist + private PreventRuleDTO reminderPreventRule; + + /** + * Groupes de votants à créer + */ + @Property + @Persist + private List<VotingListDTO> votingLists; + + /** + * Objet utilisé dans la boucle de parcours des listes de votants + */ + @Property + private VotingListDTO votingList; + + /** + * Objet utilisé dans la boucle de parcours de la liste de votants courante + */ + @SuppressWarnings("unused") + @Property + private PollAccountDTO votingListPerson; + + /** + * Nombre de votants affichés initialement + */ + @Property + private int nbVotingListPersons = 5; + + /** + * Liste modifiée actuellement + */ + @Persist + private int currentList; + + /** + * Listes de favoris de l'utilisateur. + */ + @Property + @Persist + private GenericSelectModel<PersonListDTO> personLists; + + /** + * Liste de favoris sélectionnée. + */ + @Property + private PersonListDTO personList; + + /** + * Nombre de choix affichés initialement + */ + @Property + private int nbChoices = 5; + + /** + * Objet utilisé dans la boucle de parcours de la liste des choix + */ + @SuppressWarnings("unused") + @Property + private ChoiceDTO choice; + + /** + * Objet utilisé dans la boucle de parcours de la liste des choix + */ + @SuppressWarnings("unused") + @Property + private DateChoiceUIO dateTypeChoice; + + /** + * Objet utilisé dans la boucle de parcours de la liste des choix + */ + @SuppressWarnings("unused") + @Property + private ImageChoiceUIO imgTypeChoice; + + /** + * Liste des choix à créer + */ + @Property + @Persist + private List<ChoiceDTO> choices; + + /** + * Liste des choix à créer + */ + @Property + @Persist + private List<DateChoiceUIO> dateTypeChoices; + + /** + * Liste des choix à créer + */ + @Property + @Persist + private List<ImageChoiceUIO> imgTypeChoices; + + /** + * Contexte pour l'upload des images (parametres definis dans .tml) + */ + @InjectComponent + private ImageContextLink imgContext; + + /** + * Contexte pour la gestion du flux RSS + */ + @InjectComponent + private ContextLink feedContext; + + /** + * Formulaire de création de sondage + */ + @Component(id = "pollCreationForm") + private Form pollCreationForm; + @Component(id = "choicesCreationForm") + private Form choicesCreationForm; + + @InjectPage + private CreationValidation creationValidation; + + @Parameter(defaultPrefix = BindingConstants.MESSAGE, value = "title") + @Property + private String title; + + @SuppressWarnings("unused") + @Property + private AddressBarItem[] address; + + @Inject + private PropertyAccess _propertyAccess; + + @Inject + private ComponentResources resources; + + /** Affichage des messages pour l'utilisateur */ + @Component(id = "feedback") + private FeedBack feedback; + + /** Tailles maximales des fichiers uploadés */ + @Inject + @Symbol(UploadSymbols.FILESIZE_MAX) + private int fileSizeMax; + @Inject + @Symbol(UploadSymbols.REQUESTSIZE_MAX) + private int requestSizeMax; + + @Inject + private Messages messages; + + @Inject + private Logger logger; + + /** Injection des services */ + @Inject + private ServicePoll servicePoll; + @Inject + private ServicePollAccount servicePollAccount; + @Inject + private ServiceList serviceList; + + /** + * Méthode appelée lorsqu'on souhaite accéder à l'étape suivante de la + * création de sondage. + */ + @Log + Object onSuccessFromPollCreationForm() { + if (log.isDebugEnabled()) { + log.debug("Step : " + step); + } + switch (step) { + case POLL: + adaptStepPoll(); + step = PollStep.OPTIONS; + break; + case OPTIONS: + adaptStepOptions(); + if (isFreePoll()) { + step = PollStep.CHOICES; + } else { + step = PollStep.LISTS; + } + break; + case LISTS: + if (deleteGroupId >= 0) { + votingLists.remove(deleteGroupId); + } + if (!noStepSubmitSelected) { + step = PollStep.CHOICES; + } + break; + case CHOICES: + break; + default: + step = PollStep.POLL; + break; + } + // Cas particulier, autre formulaire pour les choix + if (step.equals(PollStep.CHOICES)) { + return choicesCreationForm; + } + return pollCreationForm; + } + + /** + * Méthode appelée que le formulaire soit valide ou non. Il est nécessaire + * de la redéfinir pour qu'en cas d'erreur de validation, la zone soit tout + * de même mise à jour pour afficher l'erreur. + */ + @Log + Object onSubmitFromPollCreationForm() { + return pollCreationForm; + } + + /** + * Méthode appelée lorsqu'on souhaite valider la création du sondage. + */ + Object onSuccessFromChoicesCreationForm() { + if (!addChoiceSelected) { + + // Préparation et création du sondage + if (!preparePoll()) { + return this; + } + createPoll(); + + creationValidation.setPoll(poll); + return creationValidation; + } + + return this; + } + + /** + * Méthode appelée lorsqu'on souhaite accéder à l'étape précédente de la + * création de sondage. + */ + Object onPrevious() { + switch (step) { + case OPTIONS: + step = PollStep.POLL; + break; + case LISTS: + step = PollStep.OPTIONS; + break; + case CHOICES: + if (isFreePoll()) { + step = PollStep.OPTIONS; + } else { + step = PollStep.LISTS; + } + break; + default: + step = PollStep.POLL; + break; + } + return pollCreationForm; // Pas de gestion du formulaire des choix car derniere etape + } + + /** + * Méthode appelée lors de la validation du formulaire. Validation du champs + * beginDate. + * + * @throws ValidationException + */ + void onValidateFromBeginDate(Date value) throws ValidationException { + beginDateValidation = value; + if (value != null && value.before(new Date())) { + throw new ValidationException(messages.get("beginDate-validate")); + } + } + + /** + * Méthode appelée lors de la validation du formulaire. Validation du champs + * endDate. + * + * @throws ValidationException + */ + void onValidateFromEndDate(Date value) throws ValidationException { + if (beginDateValidation == null) { + beginDateValidation = new Date(); + } + + if (value != null && value.before(beginDateValidation)) { + throw new ValidationException(messages.get("endDate-validate")); + } + } + + /** + * Méthode appelée lors de la validation du formulaire. Validation du champs + * beginChoiceDate. + * + * @throws ValidationException + */ + void onValidateFromBeginChoiceDate(Date value) throws ValidationException { + if (beginDateValidation == null) { + beginDateValidation = new Date(); + } + beginChoiceDateValidation = value; + if (value != null && value.after(beginDateValidation)) { + throw new ValidationException(messages + .get("beginChoiceDate-validate")); + } + } + /** + * Méthode appelée lors de la validation du formulaire. Validation du champs + * endChoiceDate. + * + * @throws ValidationException + */ + void onValidateFromEndChoiceDate(Date value) throws ValidationException { + if (beginChoiceDateValidation == null) { + beginChoiceDateValidation = new Date(); + } + + if (value != null && value.before(beginChoiceDateValidation)) { + throw new ValidationException(messages.get("endChoiceDate-validate")); + } + } + + /** + * Méthode appelée lors de la validation du formulaire. Validation des + * listes de votants. + * + * @throws ValidationException + */ + void onValidateFormFromPollCreationForm() throws ValidationException { + if (noStepSubmitSelected) { + return; + } + + // Validation des votants + if (step == PollStep.LISTS) { + int nbListEqual = 0; + int nbEqual = 0; + int nbNotNull = 0; + + // Repérage des doublons (listes) + for (VotingListDTO list1 : votingLists) { + for (VotingListDTO list2 : votingLists) { + if (list1.getName().equals(list2.getName())) { + nbListEqual++; + } + } + } + + if (nbListEqual > votingLists.size()) { + throw new ValidationException(messages.get("lists-validate")); + } + + // Repérage des doublons (votants) + for (VotingListDTO list1 : votingLists) { + int nbLocalNotNull = 0; + for (PollAccountDTO account1 : list1.getPollAccountDTOs()) { + if (account1.getVotingId() != null + && account1.getVotingId() != "") { + nbNotNull++; + nbLocalNotNull++; + + // comparaison avec les autres votants + for (VotingListDTO list2 : votingLists) { + for (PollAccountDTO account2 : list2 + .getPollAccountDTOs()) { + if (account2.getVotingId() != null + && account1.getVotingId() != "") { + if (account1.getVotingId().equals( + account2.getVotingId())) { + nbEqual++; + } + } + } + } + } + } + if (nbLocalNotNull == 0) { + throw new ValidationException(messages + .get("noList-validate")); + } + } + + if (logger.isDebugEnabled()) { + logger.debug("Votants (equal/notNull) : " + nbEqual + "/" + + nbNotNull); + } + if (nbEqual > nbNotNull) { + throw new ValidationException(messages.get("list-validate")); + } + } + } + + /** + * Méthode appelée lors de la validation du formulaire. Validation de la + * liste de choix. + * + * @throws ValidationException + */ + void onValidateFormFromChoicesCreationForm() throws ValidationException { + int nbEqual = 0; + int nbNotNull = 0; + + // Validation des choix + if (step == PollStep.CHOICES) { + + // Repérage des doublons (type Texte) + if (isTextChoices()) { + for (ChoiceDTO choice1 : choices) { + if (choice1.getName() != null) { + nbNotNull++; + for (ChoiceDTO choice2 : choices) { + if (choice2.getName() != null) { + if (choice1.getName().equals(choice2.getName())) { + nbEqual++; + } + } + } + } + } + // Repérage des doublons (type Date) + } else if (isDateChoices()) { + for (DateChoiceUIO choice1 : dateTypeChoices) { + if (choice1.getDate() != null) { + nbNotNull++; + for (DateChoiceUIO choice2 : dateTypeChoices) { + if (choice2.getDate() != null) { + if (choice1.getDate().equals(choice2.getDate())) { + nbEqual++; + } + } + } + } + } + // Repérage des doublons (type Image) + } else if (isImgChoices()) { + for (ImageChoiceUIO choice1 : imgTypeChoices) { + if (choice1.getImg() != null) { + nbNotNull++; + for (ImageChoiceUIO choice2 : imgTypeChoices) { + if (choice2.getImg() != null) { + if (choice1.getImg().getFileName().equals( + choice2.getImg().getFileName())) { + nbEqual++; + } + } + } + } + } + } + + if (nbNotNull == 0) { + throw new ValidationException(messages.get("noChoice-validate")); + } + if (nbEqual > nbNotNull) { + throw new ValidationException(messages.get("choice-validate")); + } + } + } + + /** Echec lors du téléchargement */ + Object onUploadException(FileUploadException e) { + logger.error(e.getMessage()); + String fSize = UnitConverter.getFormattedFileSize(fileSizeMax); + String rSize = UnitConverter.getFormattedFileSize(requestSizeMax); + feedback.addError(messages.format("uploadError", fSize, rSize)); + uploadExceptionCatched = true; + return this; + } + + /** + * Réinitialisation des options en fonction des autres options. + */ + private void adaptStepOptions() { + if (poll.isAnonymous()) { + poll.setAnonymousVoteAllowed(true); + } + if (poll.isContinuousResults()) { + poll.setPublicResults(true); + } + } + + /** + * Réinitialisation des listes de votants en fonction du type de sondage. + */ + @Log + private void adaptStepPoll() { + + // Sondage libre : suppression de toutes les listes + if (isFreePoll()) { + votingLists.clear(); + } + + // Sondage restreint : suppression des listes supplémentaires + else if (isRestrictedPoll() && votingLists.size() > 1) { + for (int i = 1; i < votingLists.size(); i++) { + votingLists.remove(i); + } + currentList = 0; + } + + // Sondage non libre : création d'une liste initiale + else if (votingLists.isEmpty()) { + votingList = new VotingListDTO(); + for (int i = 0; i < nbVotingListPersons; i++) { + votingList.getPollAccountDTOs().add(new PollAccountDTO()); + } + votingLists.add(votingList); + currentList = getVotingListIndex(); + } + + if (poll.getBeginDate() != null) { + poll.setEndChoiceDate(poll.getBeginDate()); + } + } + + /** + * Préparation du sondage. + */ + @Log + private boolean preparePoll() { + + // Ajout de l'identifiant du créateur + if (userExists) { + poll.setUserId(user.getId()); + } + + // Ajout des règles de notification au sondage + if (notificationCheckBox) { + poll.getPreventRuleDTOs().add(notificationPreventRule); + } + if (reminderCheckBox) { + poll.getPreventRuleDTOs().add(reminderPreventRule); + } + + // Ajout des groupes de votants au sondage + // après suppression des entrées vides + if (!isFreePoll()) { + for (VotingListDTO list : votingLists) { + Iterator<PollAccountDTO> it = list.getPollAccountDTOs() + .iterator(); + while (it.hasNext()) { + if (it.next().getVotingId() == null) { + it.remove(); + } + } + } + poll.setVotingListDTOs(votingLists); + } + + + // Ajout des choix au sondage + if (isTextChoices()) { + for (ChoiceDTO choice : choices) { + if (choice.getName() != null) { + choice.setValidate(true); + poll.getChoiceDTOs().add(choice); + } + } + } else if (isDateChoices()) { + for (DateChoiceUIO choice : dateTypeChoices) { + if (choice.getDate() != null) { + choice.setValidate(true); + choice.setName(String.valueOf(choice.getDate().getTime())); + poll.getChoiceDTOs().add(choice); + } + } + } else if (isImgChoices()) { + for (ImageChoiceUIO imgChoice : imgTypeChoices) { + if (imgChoice.getImg() != null) { + logger.debug("Image: " + imgChoice.getImg().getFileName() + + ", type: " + imgChoice.getImg().getContentType()); + if (imgChoice.getImg().getContentType().contains("image") + || imgChoice.getImg().getContentType().contains( + "IMAGE")) { + imgChoice.setValidate(true); + imgChoice.setName(imgChoice.getImg().getFileName() + .replace(' ', '_')); + poll.getChoiceDTOs().add(imgChoice); + } else { + return false; + } + } + } + } + + // Retouche des attributs dépendants l'un de l'autre + if (poll.getBeginDate() == null) { + poll.setBeginDate(new Date()); + } + if (poll.isAnonymous()) { + poll.setAnonymousVoteAllowed(true); + } + if (poll.isContinuousResults()) { + poll.setPublicResults(true); + } + if (poll.getMaxChoiceNb() < 1 + || poll.getMaxChoiceNb() > poll.getChoiceDTOs().size()) { + poll.setMaxChoiceNb(poll.getChoiceDTOs().size()); + } + + return true; + } + + /** + * Création du sondage. + */ + private void createPoll() { + + // Création du sondage + servicePoll.createPoll(poll); + + // FD-20100226 : Can't be null, an exception will be thrown if a + // problem comes from createPoll + //if (poll.getId() != null) { + + // Création des images + if (poll.getChoiceType() == ChoiceType.IMAGE) { + File dir = imgContext.getImageDir(); + ImageUtil.saveImages(imgTypeChoices, dir); + } + + // FD-20100226 : not necessary, the service will update + // automatically the poll when it was created + // Mise à jour du sondage : + //poll = servicePoll.findPollById(poll.getId()); + + // Mise à jour du flux Atom et envoi d'un mail de confirmation + addFeedEntry(); + sendMailNotification(); + //} + } + + /** Ajout d'une entrée dans le flux de syndication */ + private void addFeedEntry() { + PollAccountDTO creator = servicePollAccount.findPollAccountById(poll + .getCreatorId()); + String voteURL = siteURL + "poll/VoteFor/" + poll.getPollId(); + File feedFile = feedContext.getFile(poll.getPollId()); + + FeedUtil.createFeed(feedFile, "atom_1.0", messages.format( + "pollFeed_title", poll.getTitle()), siteURL, messages.format( + "pollFeed_desc", poll.getDescription())); + FeedUtil.feedFeed(feedFile, messages.format("pollFeed_createTitle", + creator.getVotingId()), voteURL, messages + .get("pollFeed_createContent")); + } + + /** Envoi du mail de notification */ + private void sendMailNotification() { + PollAccountDTO creator = servicePollAccount.findPollAccountById(poll + .getCreatorId()); + String voteURL = siteURL + "poll/VoteFor/" + poll.getPollId(); + String modifURL = siteURL + "poll/Modification/" + poll.getPollId() + + ":" + creator.getAccountId(); + Map<String, String> data = new HashMap<String, String>(); + data.put("host", PollenProperty.EMAIL_HOST.getValue()); + data.put("port", PollenProperty.EMAIL_PORT.getValue()); + data.put("from", PollenProperty.EMAIL_FROM.getValue()); + + // Mail au créateur + if (poll.getCreatorEmail() != null) { + data.put("to", poll.getCreatorEmail()); + data.put("title", messages.format("creatorEmail_subject", poll + .getTitle())); + data.put("msg", messages.format("creatorEmail_msg", + poll.getTitle(), voteURL, modifURL)); + + PreventRuleManager.emailAction(data); + } + + // Mails aux votants + for (VotingListDTO list : poll.getVotingListDTOs()) { + for (PollAccountDTO account : list.getPollAccountDTOs()) { + if (account.getEmail() != null) { + String accountVoteURL = voteURL + ":" + + account.getAccountId(); + + data.put("to", account.getEmail()); + data.put("title", messages.format("votingEmail_subject", + poll.getTitle())); + data + .put("msg", messages.format("votingEmail_msg", poll + .getTitle(), account.getVotingId(), + accountVoteURL)); + + PreventRuleManager.emailAction(data); + } + } + } + } + + public String getChoiceDateDisplay() { + return poll.isChoiceAddAllowed() ? "display: block;" : "display: none;"; + } + + public String getChoiceNbDisplay() { + return choiceNbCheckBox ? "display: block;" : "display: none;"; + } + + public String getNotificationDisplay() { + return notificationCheckBox ? "display: block;" : "display: none;"; + } + + public String getReminderDisplay() { + return reminderCheckBox ? "display: block;" : "display: none;"; + } + + /** Retourne l'index de la liste courante */ + public int getVotingListIndex() { + return votingLists.indexOf(votingList); + } + + /** Retourne le numéro de la liste courante (index+1) */ + public int getVotingListNumber() { + return votingLists.indexOf(votingList) + 1; + } + + /** Retourne la chaîne correspondant à l'étape courante */ + public String getStepLegend() { + Integer index = step.getIndex(); + + // corrections selon le type de sondage + if (isFreePoll()) { + if (step == PollStep.CHOICES) { + index--; + } + } + + // mise en forme du message + switch (step) { + case POLL: + return messages.format("pollLegend", index); + case OPTIONS: + return messages.format("optionsLegend", index); + case LISTS: + return messages.format("listsLegend", index); + case CHOICES: + return messages.format("choicesLegend", index); + default: + return ""; + } + } + + /** Retourne la classe CSS correspondant au groupe courant */ + public String getCurrentListClass() { + if (votingLists.size() > 1 && getVotingListIndex() == currentList) { + return "currentGroupDiv"; + } + return "groupDiv"; + } + + /** + * Retourne s'il existe plusieurs groupes. + */ + public boolean isSeveralGroups() { + return votingLists.size() > 1; + } + + public boolean isInPoll() { + return step == PollStep.POLL; + } + + public boolean isInLists() { + return step == PollStep.LISTS; + } + + public boolean isInChoices() { + return step == PollStep.CHOICES; + } + + public boolean isInOptions() { + return step == PollStep.OPTIONS; + } + + public boolean isNormalVoteCounting() { + return poll.getVoteCounting() == VoteCountingType.NORMAL; + } + + public boolean isPercentageVoteCounting() { + return poll.getVoteCounting() == VoteCountingType.PERCENTAGE; + } + + public boolean isCondorcetVoteCounting() { + return poll.getVoteCounting() == VoteCountingType.CONDORCET; + } + + public boolean isNumberVoteCounting() { + return poll.getVoteCounting() == VoteCountingType.NUMBER; + } + + public boolean isFreePoll() { + return poll.getPollType() == PollType.FREE; + } + + public boolean isRestrictedPoll() { + return poll.getPollType() == PollType.RESTRICTED; + } + + public boolean isGroupPoll() { + return poll.getPollType() == PollType.GROUP; + } + + public boolean isTextChoices() { + return poll.getChoiceType() == ChoiceType.TEXT; + } + + public boolean isDateChoices() { + return poll.getChoiceType() == ChoiceType.DATE; + } + + public boolean isImgChoices() { + return poll.getChoiceType() == ChoiceType.IMAGE; + } + + /** + * Méthode appelée à la sélection d'une liste de votants. Le mixin + * ck/OnEvent ne permet pas de retourner le contenu d'une zone. Il faut donc + * passer par une fonction JavaScript pour activer un event link. Un lien + * est créé. Il sera retourné à la fonction JavaScript onCompleteCallback + * pour mettre à jour la zone. + * + * @param value + * @return un JSONObject contenant l'url de l'évènement mettant à jour la + * zone. + */ + public JSONObject onChangeFromListSelect(String value) { + if (StringUtils.isNotEmpty(value)) { + personList = serviceList.findPersonListById(value); + + // Copie des personnes de la liste de favoris dans la liste de votants + for (PollAccountDTO account : personList.getPollAccounts()) { + account.setId(""); + account.setPersonListId(""); + } + + votingLists.get(currentList).setPollAccountDTOs( + personList.getPollAccounts()); + } + return createParamsForCallback(); + } + + /** + * Méthode appelée à la sélection d'un type de choix. Le mixin ck/OnEvent ne + * permet pas de retourner le contenu d'une zone. Il faut donc passer par + * une fonction JavaScript pour activer un event link. Un lien est créé. Il + * sera retourné à la fonction JavaScript onCompleteCallback pour mettre à + * jour la zone. + * + * @return un JSONObject contenant l'url de l'évènement mettant à jour la + * zone. + */ + public JSONObject onChangeFromChoiceType(String value) { + poll.setChoiceType(ChoiceType.valueOf(value)); + return createParamsForCallback(); + } + + /** + * Création d'un JSONObject contenant un identifiant de zone et une url pour + * un évènement. + * + * @return un JSONObject contenant un zoneId et une url. + */ + private JSONObject createParamsForCallback() { + JSONObject json = new JSONObject(); + Link link = resources.createEventLink("updatePollCreationZone"); + json.put("link", link.toAbsoluteURI()); + json.put("zoneId", "pollCreationZone"); + return json; + } + + /** + * Méthode appelée par le callback JavaScript pour mettre à jour la zone. + * + * @return le contenu mis à jour de la zone. + */ + public Object onUpdatePollCreationZone() { + return pollCreationZone.getBody(); + } + + /** + * Méthode appelée pour l'ajout d'une ligne supplémentaire dans le + * formulaire des listes de votants. + */ + void onSelectedFromAddPerson(int i) { + votingLists.get(i).getPollAccountDTOs().add(new PollAccountDTO()); + noStepSubmitSelected = true; + } + + /** + * Méthode appelée pour l'ajout d'un groupe dans le formulaire des listes de + * votants. + */ + void onSelectedFromAddGroup() { + votingList = new VotingListDTO(); + for (int i = 0; i < nbVotingListPersons; i++) { + votingList.getPollAccountDTOs().add(new PollAccountDTO()); + } + votingLists.add(votingList); + currentList = getVotingListIndex(); + noStepSubmitSelected = true; + } + + /** + * Méthode appelée lors de la suppression d'un groupe dans le formulaire des + * listes de votants. + */ + void onSelectedFromDeleteGroup(int i) { + //votingLists.remove(i); + if (currentList == i) { + currentList = votingLists.size() - 1; + } else if (currentList > i) { + currentList--; + } + deleteGroupId = i; + noStepSubmitSelected = true; + } + + /** + * Méthode appelée à la selection d'un groupe dans le formulaire des listes + * de votants. + */ + void onSelectedFromEditGroup(int i) { + currentList = i; + noStepSubmitSelected = true; + } + + /** + * Méthode appelée pour l'ajout d'une ligne supplémentaire dans le + * formulaire des choix. + */ + void onSelectedFromAddChoice() { + if (poll.getChoiceType() == ChoiceType.DATE) { + dateTypeChoices.add(new DateChoiceUIO()); + } else if (poll.getChoiceType() == ChoiceType.IMAGE) { + imgTypeChoices.add(new ImageChoiceUIO()); + } else { + choices.add(new ChoiceDTO()); + } + addChoiceSelected = true; + } + + /** Retourne vrai si des listes de favoris existent */ + public boolean isPersonListsExists() { + return personLists != null && !personLists.getList().isEmpty(); + } + + /** + * Activation de la page + */ + void onActivate(String id) { + + // Si un sondage est fourni (copie de sondage) + if (id != null && !"".equals(id)) { + + // Réinitialisation des variables de session + // Si l'ancien sondage n'existe pas ou est différent de celui fourni + if (oldPoll == null || !id.equals(oldPoll.getPollId())) { + oldPoll = servicePoll.findPollByPollId(id); + if (oldPoll != null) { + initWithExistingPoll(oldPoll); + oldPoll = null; + oldPollExists = true; + } + } + } + } + + /** + * Initialisation de l'affichage + */ + void setupRender() { + address = new AddressBarItem[] { new AddressBarItem("Pollen", "Index"), + new AddressBarItem(title, null) }; + + if (!addChoiceSelected && !uploadExceptionCatched + && !choicesCreationForm.getHasErrors()) { + step = PollStep.POLL; + if (!oldPollExists) { + oldPoll = null; + initPoll(); + } + initPersonLists(); + } + + addChoiceSelected = false; + uploadExceptionCatched = false; + } + + /** + * Initialisation du sondage. + */ + private void initPoll() { + + // Initialisation du sondage + poll = new PollDTO(); + if (userExists) { + poll.setCreatorName(user.getLogin()); + poll.setCreatorEmail(user.getEmail()); + } + + // Initialisation des règles de notification + notificationPreventRule = new PreventRuleDTO("vote", 0, true, + PreventRuleManager.EMAIL_ACTION); + reminderPreventRule = new PreventRuleDTO("rappel", 0, false, + PreventRuleManager.EMAIL_ACTION); + + notificationCheckBox = false; + reminderCheckBox = false; + choiceNbCheckBox = false; + + // Initialisation des choix + choices = new ArrayList<ChoiceDTO>(); + dateTypeChoices = new ArrayList<DateChoiceUIO>(); + imgTypeChoices = new ArrayList<ImageChoiceUIO>(); + for (int i = 0; i < nbChoices; i++) { + choices.add(new ChoiceDTO()); + dateTypeChoices.add(new DateChoiceUIO()); + imgTypeChoices.add(new ImageChoiceUIO()); + } + + // Initialisation des listes de votants + votingLists = new ArrayList<VotingListDTO>(); + } + + /** + * Initialisation du sondage à partir d'un sondage existant. + */ + private void initWithExistingPoll(PollDTO oldPoll) { + + // Initialisation du sondage + poll = PollHelper.getPoll(oldPoll); + + // Initialisation du créateur du sondage +// PollAccountDTO creator = servicePollAccount.findPollAccountById(oldPoll +// .getCreatorId()); + //poll.setCreatorId(oldPoll.getCreatorId()); + poll.setCreatorName(oldPoll.getCreatorName()); + poll.setCreatorEmail(oldPoll.getCreatorEmail()); + + // Initialisation des règles de notification + notificationPreventRule = PollHelper + .getNotificationPreventRule(oldPoll); + notificationCheckBox = !"".equals(notificationPreventRule.getScope()); + reminderPreventRule = PollHelper.getReminderPreventRule(oldPoll); + reminderCheckBox = !"".equals(reminderPreventRule.getScope()); + + // Initialisation des choix + choices = PollHelper.getTextChoices(oldPoll); + dateTypeChoices = PollHelper.getDateChoices(oldPoll); + imgTypeChoices = PollHelper.getImageChoices(oldPoll); + + // Initialisation des listes de votants + votingLists = PollHelper.getVotingLists(oldPoll); + } + + /** + * Initialisation de la liste de favoris. + */ + private void initPersonLists() { + if (userExists) { + List<PersonListDTO> _personLists = serviceList + .findPersonListByUser(user.getId()); + personLists = new GenericSelectModel<PersonListDTO>(_personLists, + PersonListDTO.class, "name", "id", _propertyAccess); + } + } +} Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollModification.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollModification.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/PollModification.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -485,6 +485,11 @@ } } + public boolean isListSizeAlert() { + return votingList.getPollAccountDTOs().size() > + PollCreation.LIST_MAX_SHOW_PERSONS; + } + public boolean isInPoll() { return step == PollStep.POLL; } @@ -544,6 +549,8 @@ data.put("msg", messages.format("votingEmail_msg", poll .getTitle(), account.getVotingId(), accountVoteURL)); + // FIXME call directly MailUtil.sendMail() + // skip fill map, get from map... PreventRuleManager.emailAction(data); } } 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-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/poll/VoteForPoll.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -28,6 +28,7 @@ import java.util.UUID; import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.EventContext; import org.apache.tapestry5.ValidationException; import org.apache.tapestry5.annotations.Component; import org.apache.tapestry5.annotations.IncludeJavaScriptLibrary; @@ -59,7 +60,6 @@ import org.chorem.pollen.business.dto.ResultListDTO; import org.chorem.pollen.business.dto.UserDTO; import org.chorem.pollen.business.dto.VoteDTO; -import org.chorem.pollen.business.dto.VotingListDTO; import org.chorem.pollen.business.services.ServiceChoice; import org.chorem.pollen.business.services.ServicePoll; import org.chorem.pollen.business.services.ServicePollAccount; @@ -72,6 +72,7 @@ import org.chorem.pollen.ui.base.ContextLink; import org.chorem.pollen.ui.components.FeedBack; import org.chorem.pollen.ui.components.ImageContextLink; +import org.chorem.pollen.ui.components.Pager; import org.chorem.pollen.ui.data.EvenOdd; import org.chorem.pollen.ui.data.AddressBarItem; import org.chorem.pollen.ui.data.PollAction; @@ -212,7 +213,7 @@ private boolean anonymousVote = false; /** Liste des choix */ - private List<ChoiceDTO> voteChoices = new ArrayList<ChoiceDTO>(); +// private List<ChoiceDTO> voteChoices = new ArrayList<ChoiceDTO>(); /** Identifiant du compte correspondant à l'adresse forgée */ private String pollAccountId; @@ -288,6 +289,17 @@ return imgContext; } + @InjectComponent + private FeedBack voteFeedback; + + public String getVoteSizeMessage() { + if (log.isDebugEnabled()) { + log.debug("poll voteDTOs list size : " + getVotes().size()); + log.debug("poll nbVotes : " + poll.getNbVotes()); + } + return messages.format("vote-size", poll.getNbVotes()); + } + /** Méthode appelée après la soumission du vote. */ @Log Object onSuccessFromVoteForm() { @@ -360,7 +372,7 @@ // mise à jour du vote ou création d'un nouveau vote if (alreadyVoted) { - for (VoteDTO v : poll.getVoteDTOs()) { + for (VoteDTO v : getVotes()) { PollAccountDTO voteAccount = servicePollAccount .findPollAccountById(v.getPollAccountId()); @@ -381,13 +393,18 @@ addFeedEntry(PollAction.ADDVOTE, pollAccount.getVotingId(), getResultsAsString()); sendMailNotification(); + voteFeedback.addInfo(messages.get("vote-success")); + page = pager.getLastPage(); + // Reset votes to reload them depends on page change. + votes = null; + return this; } - voteChoices.clear(); +// voteChoices.clear(); return pollZone.getBody(); } private void deleteVote(String voteId) { - for (VoteDTO vote : poll.getVoteDTOs()) { + for (VoteDTO vote : getVotes()) { if (vote.getId().equals(voteId)) { List<ChoiceDTO> choiceDTOs = vote.getChoiceDTOs(); @@ -436,26 +453,53 @@ // Contrôle de la présence du votant dans les listes de votants // du sondage (si le sondage n'est pas libre) - if (!isFreePoll()) { - restrictedListsForbidden = true; - for (VotingListDTO list : poll.getVotingListDTOs()) { - for (PollAccountDTO account : list.getPollAccountDTOs()) { - if (pollAccount.getVotingId().equals(account.getVotingId())) { - restrictedListsForbidden = false; - pollAccount = servicePollAccount - .findPollAccountById(account.getId()); - pollAccount.setVotingListId(list.getId()); - pollAccount.setWeight(account.getWeight()); - logger.debug("Compte \"" + account.getVotingId() - + "\" présent dans la liste \"" - + list.getName() + "\" (poids=" - + account.getWeight() + ")"); - } +// if (!isFreePoll()) { +// restrictedListsForbidden = true; +// for (VotingListDTO list : poll.getVotingListDTOs()) { +// for (PollAccountDTO account : list.getPollAccountDTOs()) { +// if (pollAccount.getVotingId().equals(account.getVotingId())) { +// restrictedListsForbidden = false; +// pollAccount = servicePollAccount +// .findPollAccountById(account.getId()); +// pollAccount.setVotingListId(list.getId()); +// pollAccount.setWeight(account.getWeight()); +// logger.debug("Compte \"" + account.getVotingId() +// + "\" présent dans la liste \"" +// + list.getName() + "\" (poids=" +// + account.getWeight() + ")"); +// } +// } +// } +// } + + // The calcul of alreadyVoted will be needed for no double votingId + // Carefull, not correct for an anonymous vote + alreadyVoted = serviceVote.hasAlreadyVoted(votingId, poll); + + // Check for restricted poll + if (!alreadyVoted && !isFreePoll()) { + if (getAccountUId() != null) { + // The accountUId must be valid for the poll + PollAccountDTO restrictedAccount = + servicePoll.getRestrictedAccount(getAccountUId(), poll); + + if (restrictedAccount != null) { + // PollAccount is replaced by the good account from db + pollAccount = restrictedAccount; + // Refresh alreadyVoted value depends on pollAccount + alreadyVoted = pollAccount.isHasVoted(); + // Existing account is null is forbidden for a restricted poll + } else { + restrictedListsForbidden = true; } + // Not allowed to vote without an accountUId + } else { + restrictedListsForbidden = true; } + if (restrictedListsForbidden) { - voteForm.recordError(nameField, messages.format( - "restrictedListsForbidden", pollAccount.getVotingId())); + voteForm.recordError(nameField, + messages.get("restrictedListsForbidden")); } } @@ -473,10 +517,8 @@ pollAccount.setUserId(user.getId()); } else { pollAccount.setUserId(""); - } - - // Contrôle si le votant n'a pas déjà voté - alreadyVoted = hasAlreadyVoted(pollAccount.getVotingId()); + } + modifAllowed = isModifAllowed(pollAccount.getVotingId()); if (alreadyVoted && !modifAllowed) { voteForm.recordError(nameField, messages.format("alreadyVoted", @@ -491,27 +533,6 @@ } /** - * Retourne vrai si le votant a déjà voté. - * - * @param votingId le votant a rechercher - * @return vrai si le votant a déjà voté - */ - private boolean hasAlreadyVoted(String votingId) { - - // comparaison du votant (pollAccount) avec les votants des votes existants - for (VoteDTO vote : poll.getVoteDTOs()) { - PollAccountDTO account = servicePollAccount - .findPollAccountById(vote.getPollAccountId()); - - if (account.getVotingId().equals(votingId)) { - return true; - } - } - - return false; - } - - /** * Retourne vrai si la modification du vote est autorisée. C'est à dire si * l'utilisateur connecté est l'auteur du vote ou si le votant défini par * l'url est l'auteur du vote. @@ -525,28 +546,37 @@ // parcours des votes pour trouver celui correspondant au votingId // et contrôle du droit de modification - while (i < poll.getVoteDTOs().size() && !modifAllowed) { + if (log.isDebugEnabled()) { + log.debug("Nb votes : " + getVotes().size()); + log.debug("Nb votes in poll : " + poll.getNbVotes()); + } + + // FIXME !!!!!! SEEMS TO BE INDEFINITE + while (i < getVotes().size() && !modifAllowed) { + // account : compte associé au vote courant - String id = poll.getVoteDTOs().get(i).getPollAccountId(); - PollAccountDTO account = servicePollAccount.findPollAccountById(id); + //String id = getVotes().get(i).getPollAccountId(); + //PollAccountDTO account = servicePollAccount.findPollAccountById(id); + VoteDTO curr = getVotes().get(i); // si le votant du vote correspond au votingId - if (account.getVotingId().equals(votingId)) { + if (curr.getName().equals(votingId)) { if (logger.isDebugEnabled()) { - logger.debug("vote account: " + account.getId()); + logger.debug("vote name: " + curr.getName()); + logger.debug("vote account: " + curr.getPollAccountId()); logger.debug("voting account: " + pollAccountId); } // si le votant du vote correspond au votant actuel (pollAccountId) if (pollAccountId != null - && pollAccountId.equals(account.getId())) { + && pollAccountId.equals(curr.getPollAccountId())) { modifAllowed = true; } // si l'utilisateur du vote correspond à l'utilisateur actuel (user) if (userExists && user.getId().length() > 0) { - modifAllowed = user.getId().equals(account.getUserId()); + modifAllowed = user.getId().equals(curr.getUserId()); } } @@ -602,15 +632,13 @@ // Mail au créateur data.put("to", poll.getCreatorEmail()); - data - .put("title", messages.format("voteEmail_subject", poll - .getTitle())); + data.put("title", messages.format("voteEmail_subject", poll.getTitle())); data.put("msg", messages.format("voteEmail_msg", poll.getTitle(), poll .getVoteDTOs().size(), voteURL, modifURL)); for (PreventRuleDTO rule : poll.getPreventRuleDTOs()) { PreventRuleManager manager = new PreventRuleManager(rule); - manager.execute("vote", poll.getVoteDTOs().size(), data); + manager.execute("vote", getVotes().size(), data); } } @@ -777,11 +805,12 @@ } /** Retourne l'identifiant du votant du vote courant */ + // FIXME !!!!!! DON'T DO A QUERY FOR THAT public String getCurrentVotingId() { - String id = vote.getPollAccountId(); - String votingId = servicePollAccount.findPollAccountById(id) - .getVotingId(); - return votingId; +// String id = vote.getPollAccountId(); +// String votingId = servicePollAccount.findPollAccountById(id) +// .getVotingId(); + return vote.getName(); } /** Validation du champs de saisie du choix (texte). */ @@ -1065,21 +1094,23 @@ * * @param id l'identifiant du sondage et du votant */ - void onActivate(String id) { - param = id; + void onActivate(EventContext ec) { + param = ec.get(String.class, 0); + if (ec.getCount() > 1) { + page = ec.get(Integer.class, 1); + } // Initialisation du sondage - if (id != null && !"".equals(id)) { - String pollId = id.split(":", 2)[0]; + if (param != null && !"".equals(param)) { + String pollId = param.split(":", 2)[0]; poll = servicePoll.findPollByPollId(pollId); if (poll != null) { // Identification du votant - if (id.split(":", 2).length == 2) { - String accountId = id.split(":", 2)[1]; + if (getAccountUId() != null) { pollAccount = servicePollAccount - .findPollAccountByAccountId(accountId); + .findPollAccountByAccountId(getAccountUId()); pollAccountId = pollAccount.getId(); } @@ -1126,13 +1157,22 @@ } } + private String accountUId; + + public String getAccountUId() { + if (accountUId == null && param.split(":", 2).length == 2) { + accountUId = param.split(":", 2)[1]; + } + return accountUId; + } + /** * Méthode appelée au moment de la désactivation de la page * * @return l'identifiant du sondage et du votant */ - String onPassivate() { - return param; + Object[] onPassivate() { + return new Object[]{param, page}; } /** @@ -1146,4 +1186,56 @@ countPoll(); } + + /************** PAGER AND VOTES MANAGMENT *********************************/ + + @InjectComponent + private Pager pager; + + private List<VoteDTO> votes; + + private Integer page; + + public int getPage() { + if (page == null) { + page = pager.getFirstPage(); + } + return page; + } + + @Log + public void setPage(int page) { + this.page = page; + } + + /** + * Get the number of votes to display per page from configuration. + * + * @return the number of votes to display per page + */ + public int getNbVotesPerPage() { + return Integer.parseInt(PollenProperty.NB_VOTES_PER_PAGE.getValue()); + } + + public String getNoPagerText() { + return messages.format("vote-noPagerText", poll.getNbVotes()); + } + + /** + * Retrieve votes of the current poll from business module. + * The votes are ordered by creation date, only the ones to display are + * loaded depends on current page using pager component. + * + * @return the list of votes to display + */ + public List<VoteDTO> getVotes() { + if (votes == null) { + if (log.isInfoEnabled()) { + log.info("BUSINESS REQUEST [getVotesByPoll]"); + } + votes = serviceVote.getVotesByPoll(poll, + pager.getStartIndex(), pager.getEndIndex()); + } + return votes; + } } Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/user/Register.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/user/Register.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/pages/user/Register.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -163,6 +163,8 @@ .getFirstName(), newUser.getLastName(), newUser.getLogin(), password1, siteURL)); + // FIXME call directly MailUtil.sendMail() + // skip fill map, get from map... PreventRuleManager.emailAction(data); } 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-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/AppModule.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -36,6 +36,7 @@ import org.chorem.pollen.business.services.ServiceResults; import org.chorem.pollen.business.services.ServiceUser; import org.chorem.pollen.business.services.ServiceVote; +import org.chorem.pollen.ui.utils.SendMail; import org.slf4j.Logger; /** @@ -158,7 +159,32 @@ return new BackgroundWorkerImpl(messages, servicePoll); } + /* + * Contribution au démarrage de services tapestry. + * + * Ajout de SendMail + * + * @param configuration configuration tapestry + * @param conf configuration pollen + * + public static void contributeRegistryStartup(OrderedConfiguration<Runnable> configuration, Configuration conf) { + configuration.add("SendMail", new SendMail(conf)); + }*/ + /** + * Init send mail service. + * + * @param conf + * @return + */ +// @EagerLoad +// public SendMail buildSendMail(Configuration conf) { +// SendMail res = new SendMail(conf); +// res.start(); +// return res; +// } + + /** * Make configuration from a Properties file available as symbols. */ public PropertiesFileSymbolProvider buildConfigPropertiesFileSymbolProvider( Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/BackgroundWorkerImpl.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/BackgroundWorkerImpl.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/BackgroundWorkerImpl.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -23,6 +23,7 @@ import java.util.Timer; import java.util.TimerTask; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tapestry5.ioc.Messages; Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/PollenManager.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/PollenManager.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/services/PollenManager.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -20,8 +20,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.tapestry5.ioc.services.RegistryShutdownListener; import org.chorem.pollen.business.PollenContext; -import org.nuiton.util.ApplicationConfig; -import org.nuiton.util.ArgumentsParserException; +import org.chorem.pollen.ui.utils.SendMail; /** * Service de gestion de l'arrêt du serveur. Ce service exécute une action à la @@ -34,12 +33,16 @@ private static final Log log = LogFactory.getLog(PollenManager.class); + protected SendMail sendMail; + @Override public void run() { if (log.isInfoEnabled()) { log.info("Start Pollen"); } PollenContext.start(); + sendMail = new SendMail(); + sendMail.start(); } @Override @@ -48,6 +51,7 @@ log.info("Stop Pollen"); } PollenContext.stop(); + sendMail.stopExec(); } } Modified: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/CSVAccountUtil.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/CSVAccountUtil.java 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/CSVAccountUtil.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -41,10 +41,12 @@ private static final Log log = LogFactory.getLog(CSVAccountUtil.class); /** - * Import d'une liste de votants à partir d'un flux (fichier CSV). + * CSV import from a reader. The CSV file contains three columns + * corresponding to 'votingId', 'email' and 'weight'.No header column is + * needed, the separator is ','. Ex : "toto","toto@titi.fr","3" * - * @param reader le flux - * @return la liste de votants + * @param reader which contains the input stream + * @return the new PollAccountDTO list from results imported */ public static List<PollAccountDTO> importList(Reader reader) { List<PollAccountDTO> accounts = null; @@ -53,7 +55,7 @@ ColumnPositionMappingStrategy<PollAccountDTO> strat = new ColumnPositionMappingStrategy<PollAccountDTO>(); String[] columns = new String[] { "votingId", "email", "weight" }; -// strat.setType(PollAccountDTO.class); // <---- cette ligne doit etre manquante a verifier par un Test unitaire + strat.setType(PollAccountDTO.class); strat.setColumnMapping(columns); // Parsing du fichier CSV @@ -79,6 +81,8 @@ * Import d'une liste de votants à partir d'un fichier CSV. * * @param file le fichier CSV + * @return a PollAccountDTO list + * @see #importList(java.io.Reader) */ public static List<PollAccountDTO> importList(UploadedFile file) { if (log.isInfoEnabled()) { Added: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/SendMail.java =================================================================== --- trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/SendMail.java (rev 0) +++ trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/SendMail.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,248 @@ +/* *##% Pollen + * Copyright (C) 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ + +package org.chorem.pollen.ui.utils; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.chorem.pollen.business.utils.MailUtil; +import org.nuiton.util.FileUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import au.com.bytecode.opencsv.CSVReader; +import au.com.bytecode.opencsv.CSVWriter; +import org.apache.commons.io.IOUtils; +import org.chorem.pollen.business.PollenProperty; + +/** + * Mass mail management class. + * + * This class store email to send in a csv file, and send it (one per second) in + * a second time. + * This class can restart to send mail at application restart. + * + * For a mass mail sending to start, following files must be present: + * <ul> + * <li>xxx.emails : CSV file ("email", "subject", "body")</li> + * <li>xxx.index : next index to manage ( inited at 0)</li> + * </ul> + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ + * By : $Author$ + */ +public class SendMail extends Thread { + + /** logger. */ + private static final Logger log = LoggerFactory.getLogger(SendMail.class); + + public static final String EXTENSION_MAIL = ".mail"; + public static final String EXTENSION_INDEX = ".index"; + + /** Mail storage directory. */ + protected File mailStorageDirectory; + + protected volatile boolean stop; + + public SendMail() { + + // get email directory in configuration + // create it if not exists + String filename = PollenProperty.EMAIL_DIR.getValue(); + mailStorageDirectory = new File(filename); + if (!mailStorageDirectory.exists()) { + if (mailStorageDirectory.mkdirs()) { + if (log.isDebugEnabled()) { + log.debug("Email storage directory created in : " + mailStorageDirectory.getAbsolutePath()); + } + } + } + } + + public synchronized void stopExec() { + stop = true; + } + + /* + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + + // try to find existing files + while (!stop) { + try { + sendAllMails(); + + // bloque thread until next notify + sleep(); + } + catch (Exception ex) { + if (log.isErrorEnabled()) { + log.error("Error during SendMail main loop", ex); + } + } + } + } + + protected synchronized void sleep() throws InterruptedException { + wait(); + } + + public synchronized void wakeUp() { + notifyAll(); + } + + /** + * Look for all xx.index file, and restart mail sending on + * non ending mass mail sending. + * + * After execution, delete mail and index file. + * @throws IOException + */ + protected void sendAllMails() throws IOException { + + // don't do for, allways take the first found + // a new one can be created when managing one other + List<File> indexFiles = null; + do { + + // filter is java valid : .*\\.index + indexFiles = FileUtil.find(mailStorageDirectory, ".*\\" + EXTENSION_INDEX, false); + + if (!indexFiles.isEmpty()) { + File indexFile = indexFiles.get(0); + // convert index content to int + String indexContent = FileUtils.readFileToString(indexFile, "UTF-8"); + int index = Integer.parseInt(indexContent); + + // get mail content file + File mailFile = new File(indexFile.getAbsolutePath().replaceAll(EXTENSION_INDEX + "$", EXTENSION_MAIL)); + + if (log.isDebugEnabled()) { + log.debug("Managing mail file : " + mailFile + " (from index " + indexContent + ")"); + } + + Reader indexFileReader = new BufferedReader(new FileReader(mailFile)); + CSVReader cvsReader = new CSVReader(indexFileReader); + + int currentIndex = 0; + String[] currentLine = cvsReader.readNext(); + while (currentLine != null) { + String receiver = currentLine[0]; + String subject = currentLine[1]; + String body = currentLine[2]; + + // index contains next index to treat so == is ok + if (currentIndex >= index) { + String host = PollenProperty.EMAIL_HOST.getValue(); + int port = Integer.parseInt( + PollenProperty.EMAIL_PORT.getValue()); + String from = PollenProperty.EMAIL_FROM.getValue(); + MailUtil.sendMail(host, port, from, + receiver, subject, body); + + // index contains next index to treat + FileUtils.writeStringToFile(indexFile, String.valueOf(currentIndex + 1)); + + // wait 2 secondes between each mail to not + // load smtp server + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + if (log.isErrorEnabled()) { + log.error("Can't wait between mail", ex); + } + } + } + else { + if (log.isDebugEnabled()) { + log.debug("Mail to " + receiver + " already sent in a previous execution, skip."); + } + } + + currentIndex++; + currentLine = cvsReader.readNext(); + } + + // delete woth index and mail file + mailFile.delete(); + indexFile.delete(); + } + else { + if (log.isInfoEnabled()) { + log.info("No more index mail index file found, go to sleep a while :)"); + } + } + } while (!indexFiles.isEmpty()); + } + + /** + * Prepare mail list. + * + * TODO : improve configuration reading + * + * @param id + * @param mailData + * @throws IOException + */ + public void prepareMails(String id, List<Map<String, String>> mailData) throws IOException { + + Writer fileWriter = null; + CSVWriter cvsWriter = null; + try { + + // write CSV datas + File emailFile = new File(mailStorageDirectory, id + EXTENSION_MAIL); + fileWriter = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(emailFile))); + cvsWriter = new CSVWriter(fileWriter); + + for (Map<String, String> singleMailData : mailData) { + String[] nextLine = new String[] { + singleMailData.get("receiver"), + singleMailData.get("subject"), + singleMailData.get("body") + }; + cvsWriter.writeNext(nextLine); + } + + // write index (default to 0) + File indexFile = new File(mailStorageDirectory, id + EXTENSION_INDEX); + FileUtil.writeString(indexFile, "0"); + } + finally { + if (cvsWriter != null) { + cvsWriter.close(); + } + IOUtils.closeQuietly(fileWriter); + } + + } +} Property changes on: trunk/pollen-ui/src/main/java/org/chorem/pollen/ui/utils/SendMail.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Modified: trunk/pollen-ui/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,10 +1,10 @@ required=Le champs %s est requis. -minimum-string-length=Le champs %2$s doit contenir plus de %1$d caractères. -maximum-string-length=Le champs %2$s est limité à %1$d caractères. -min-integer=Le champs %2$s doit avoir une valeur supérieure à %1$d. -max-integer=Le champs %2$s doit avoir une valeur inférieure à %1$d. -regexp=Le champs %2$s ne correspond pas à l'expression '%1$s'. +minimum-string-length=Le champs %2$s doit contenir plus de %1$d caract\u00E8res. +maximum-string-length=Le champs %2$s est limit\u00E9 \u00E0 %1$d caract\u00E8res. +min-integer=Le champs %2$s doit avoir une valeur sup\u00E9rieure \u00E0 %1$d. +max-integer=Le champs %2$s doit avoir une valeur inf\u00E9rieure \u00E0 %1$d. +regexp=Le champs %2$s ne correspond pas \u00E0 l'expression '%1$s'. invalid-email='%s' n'est pas une adresse email valide. -integer-format-exception=Vous devez fournir une valeur entière pour %s. -number-format-exception=Vous devez fournir une valeur numérique pour %s. +integer-format-exception=Vous devez fournir une valeur enti\u00E8re pour %s. +number-format-exception=Vous devez fournir une valeur num\u00E9rique pour %s. Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/base/Polls_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/base/Polls_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/base/Polls_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,27 +1,27 @@ #functions vote=Voter vote-help=Voir le sondage. -count=Dépouiller -count-help=Voir les résultats. +count=D\u00E9pouiller +count-help=Voir les r\u00E9sultats. edit=Modifier edit-help=Modifier le sondage. close=Clore close-help=Clore le sondage. copy=Copier -copy-help=Copier le sondage pour en créer un nouveau. +copy-help=Copier le sondage pour en cr\u00E9er un nouveau. export=Exporter export-help=Exporter le sondage dans un fichier XML. import=Importer -import-help=Importer un sondage à partir d'un fichier XML. +import-help=Importer un sondage \u00E0\u00A0 partir d'un fichier XML. delete=Supprimer delete-help=Supprimer le sondage. -pollDeleted=Le sondage %s a été supprimé. +pollDeleted=Le sondage %s a \u00E9t\u00E9 supprim\u00E9. pollNotDeleted=Erreur lors de la suppression du sondage %s. #grid title-label=Titre description-label=Description beginChoiceDate-label=Ajout de choix -beginDate-label=Début +beginDate-label=D\u00E9but endDate-label=Fin functions-label=Fonctions \ No newline at end of file Added: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_en.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_en.properties (rev 0) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_en.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,3 @@ +page=Page %d +go-to=Go to page %d +rows-title=Rows %d - %d over %d \ No newline at end of file Added: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_fr.properties (rev 0) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/components/Pager_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,3 @@ +page=Page %d +go-to=Aller \u00E0 la page %d +rows-title=Lignes %d - %d sur %d Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/PollsAdmin_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/PollsAdmin_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/PollsAdmin_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,4 +1,4 @@ title=Gestion des sondages -noUser=Vous devez être identifié pour pouvoir administrer les sondages.\n Veuillez remplir le formulaire ci-dessous. -userNotAllowed=Vous n'êtes pas autorisé à accéder à cette page. +noUser=Vous devez \u00EAtre identifi\u00E9 pour pouvoir administrer les sondages.\n Veuillez remplir le formulaire ci-dessous. +userNotAllowed=Vous n'\u00EAtes pas autoris\u00E9 \u00E0 acc\u00E9der \u00E0 cette page. noPolls=Aucun sondage existant. \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/UsersAdmin_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/UsersAdmin_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/admin/UsersAdmin_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,18 +1,18 @@ title=Gestion des utilisateurs -noUser=Vous devez être identifié pour pouvoir administrer les utilisateurs.\n Veuillez remplir le formulaire ci-dessous. -userNotAllowed=Vous n'êtes pas autorisé à accéder à cette page. +noUser=Vous devez \u00EAtre identifi\u00E9 pour pouvoir administrer les utilisateurs.\n Veuillez remplir le formulaire ci-dessous. +userNotAllowed=Vous n'\u00EAtes pas autoris\u00E9 \u00E0 acc\u00E9der \u00E0 cette page. noPolls=Aucun utilisateur existant. -userCreated=L'utilisateur %s a été créé. -userNotCreated=Erreur lors de la création de l'utilisateur %s. -userUpdated=L'utilisateur %s a été mis à jour. -userNotUpdated=Erreur lors de la mise à jour de l'utilisateur %s. -userDeleted=L'utilisateur %s a été supprimé. +userCreated=L'utilisateur %s a \u00E9t\u00E9 cr\u00E9\u00E9. +userNotCreated=Erreur lors de la cr\u00E9ation de l'utilisateur %s. +userUpdated=L'utilisateur %s a \u00E9t\u00E9 mis \u00E0 jour. +userNotUpdated=Erreur lors de la mise \u00E0 jour de l'utilisateur %s. +userDeleted=L'utilisateur %s a \u00E9t\u00E9 supprim\u00E9. userNotDeleted=Erreur lors de la suppression de l'utilisateur %s. -dataSaved=Les données ont été enregistrées. +dataSaved=Les donn\u00E9es ont \u00E9t\u00E9 enregistr\u00E9es. #grid login-label=Identifiant -firstName-label=Prénom +firstName-label=Pr\u00E9nom lastName-label=Nom email-label=Email administrator-label=Admin Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CloseValidation_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CloseValidation_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CloseValidation_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,7 +1,7 @@ title=Cloture d'un sondage by=par closed=Sondage clos -count=Dépouillement -countPage=Le lien ci-dessous mène à la page de dépouillement. Enregistrez-le pour pouvoir accéder au dépouillement plus tard : -register=Si vous êtes un utilisateur identifié, vous pouvez retrouver ces liens dans la page +count=D\u00E9pouillement +countPage=Le lien ci-dessous m\u00E8ne \u00E0 la page de d\u00E9pouillement. Enregistrez-le pour pouvoir acc\u00E9der au d\u00E9pouillement plus tard : +register=Si vous \u00EAtes un utilisateur identifi\u00E9, vous pouvez retrouver ces liens dans la page myPolls=Mes sondages Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ConfirmPoll_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ConfirmPoll_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ConfirmPoll_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,3 +1,3 @@ title=Confirmation -confirmClose=Êtes-vous sûr de vouloir clore ce sondage ? Cette opération est irréversible. -confirmDelete=Êtes-vous sûr de vouloir supprimer ce sondage ? Cette opération est irréversible. \ No newline at end of file +confirmClose=\u00CAtes-vous s\u00FBr de vouloir clore ce sondage ? Cette op\u00E9ration est irr\u00E9versible. +confirmDelete=\u00CAtes-vous s\u00FBr de vouloir supprimer ce sondage ? Cette op\u00E9ration est irr\u00E9versible. \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CreationValidation_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CreationValidation_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/CreationValidation_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,8 +1,8 @@ -title=Création d'un sondage +title=Cr\u00E9ation d'un sondage by=par -created=Sondage créé +created=Sondage cr\u00E9\u00E9 vote=Vote -votePage=Le lien ci-dessous mène à la page de vote. Enregistrez-le et envoyez-le à ceux que vous voulez voir voter : -editPage=Le lien ci-dessous mène à la page de modification du sondage. Enregistrez-le pour pouvoir modifier votre sondage au besoin ou le clore : -register=Si vous êtes un utilisateur identifié, vous pouvez retrouver ces liens dans la page +votePage=Le lien ci-dessous m\u00E8ne \u00E0 la page de vote. Enregistrez-le et envoyez-le \u00E0 ceux que vous voulez voir voter : +editPage=Le lien ci-dessous m\u00E8ne \u00E0 la page de modification du sondage. Enregistrez-le pour pouvoir modifier votre sondage au besoin ou le clore : +register=Si vous \u00EAtes un utilisateur identifi\u00E9, vous pouvez retrouver ces liens dans la page myPolls=Mes sondages Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ImageDisplay_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ImageDisplay_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ImageDisplay_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,4 +1,4 @@ title=Vote title2=Image returnVote-help=Retour au vote -returnCount-help=Retour aux résultats \ No newline at end of file +returnCount-help=Retour aux r\u00E9sultats \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ModificationValidation_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ModificationValidation_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/ModificationValidation_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,8 +1,8 @@ title=Modification d'un sondage by=par -modified=Sondage modifié +modified=Sondage modifi\u00E9 vote=Vote -votePage=Le lien ci-dessous mène à la page de vote. Enregistrez-le et envoyez-le à ceux que vous voulez voir voter : -editPage=Le lien ci-dessous mène à la page de modification du sondage. Enregistrez-le pour pouvoir modifier votre sondage au besoin ou le clore : -register=Si vous êtes un utilisateur identifié, vous pouvez retrouver ces liens dans la page +votePage=Le lien ci-dessous m\u00E8ne \u00E0 la page de vote. Enregistrez-le et envoyez-le \u00E0 ceux que vous voulez voir voter : +editPage=Le lien ci-dessous m\u00E8ne \u00E0 la page de modification du sondage. Enregistrez-le pour pouvoir modifier votre sondage au besoin ou le clore : +register=Si vous \u00EAtes un utilisateur identifi\u00E9, vous pouvez retrouver ces liens dans la page myPolls=Mes sondages Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_en.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_en.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_en.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -83,6 +83,8 @@ noList-validate=A list must contain at least one person. list-validate=Persons names must be unique. lists-validate=Lists names must be unique. +list-maxSize-alert=The list %s contains too many persons (%d) to be shown. You can manage your list on page 'Voting Lists' in 'Polls' menu. +list-maxSize-loaded=List %s with %d persons is correctly loaded, you can go to the next step. #choices choicesLegend=Step %d : poll choices Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollCreation_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -83,6 +83,8 @@ noList-validate=Une liste doit contenir au moins un votant. list-validate=Les noms des votants doivent \u00EAtre uniques. lists-validate=Les noms des listes doivent \u00EAtre uniques. +list-maxSize-alert=La liste %s contient trop de votants (%d) pour \u00EAtre affich\u00E9e. Vous pouvez g\u00E9rer votre liste sur la page 'Liste de votants' dans le menu 'Sondages'. +list-maxSize-loaded=Liste %s de %d votants correctement charg\u00E9, vous pouvez passer \u00E0 l'\u00E9tape suivante. #choices choicesLegend=\u00C9tape %d : les choix de votre sondage Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_en.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_en.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_en.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -63,6 +63,7 @@ groupWeight-label=Weight list-validate=Persons names must be unique. lists-validate=Lists names must be unique. +list-maxSize-cant-update=The voting list is too large to be updated. #choices choicesLegend=Step %d: poll choices Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/PollModification_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -63,6 +63,7 @@ groupWeight-label=Poids list-validate=Les noms des votants doivent \u00EAtre uniques. lists-validate=Les noms des listes doivent \u00EAtre uniques. +list-maxSize-cant-update=La liste de votants est trop grande pour \u00EAtre modifi\u00E9e. #choices choicesLegend=\u00C9tape %d : les choix de votre sondage Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/Results_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/Results_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/Results_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,27 +1,27 @@ -title=Résultats +title=R\u00E9sultats return-help=Retour au sondage -normalVote-help=Le diagramme représente le cumul des votes par choix. -percentageVote-help=Le diagramme représente le cumul des votes par choix. -condorcetVote-help=Le diagramme représente le nombre de victoires des choix par rapport aux autres choix de chaque vote. -numberVote-help=Le diagramme présente la répartition des votes par votants. +normalVote-help=Le diagramme repr\u00E9sente le cumul des votes par choix. +percentageVote-help=Le diagramme repr\u00E9sente le cumul des votes par choix. +condorcetVote-help=Le diagramme repr\u00E9sente le nombre de victoires des choix par rapport aux autres choix de chaque vote. +numberVote-help=Le diagramme pr\u00E9sente la r\u00E9partition des votes par votants. victory=Gagnant : victories=Gagnants : -about=À propos du sondage -creator-label=Créateur : -beginDate-label=Date de début : +about=A propos du sondage +creator-label=Cr\u00E9ateur : +beginDate-label=Date de d\u00E9but : endDate-label=Date de fin : -voteCounting-label=Dépouillement : +voteCounting-label=D\u00E9pouillement : chartType-pie=Camembert chartType-pie3d=Camembert 3D chartType-ring=Anneau -displayType-group=Résultats par groupes -displayType-normal=Résultats -results=Résultats : +displayType-group=R\u00E9sultats par groupes +displayType-normal=R\u00E9sultats +results=R\u00E9sultats : group=groupes normal=normal -pollNotClosed=Ce sondage n'est pas clos. Les résultats peuvent encore changer. -pollNotFound=Le sondage que vous voulez dépouiller n'existe pas. -userNotAllowed=Vous n'êtes pas autorisé à dépouiller ce sondage. +pollNotClosed=Ce sondage n'est pas clos. Les r\u00E9sultats peuvent encore changer. +pollNotFound=Le sondage que vous voulez d\u00E9pouiller n'existe pas. +userNotAllowed=Vous n'\u00EAtes pas autoris\u00E9 \u00E0 d\u00E9pouiller ce sondage. numberVote-total=Somme des nombres numberVote-average=Moyenne des nombres numberVote-blank-votes=Nombre de votes blancs Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_en.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_en.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_en.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -5,19 +5,22 @@ endDate-label=End Date: pollType-label=Poll type: normalVote-help=Normal vote: vote for your favorite choice. -percentageVote-help=Percentage vote: allocate choices to get a 100% total. +percentageVote-help=Percentage vote: allocate choices to get a 100%% total. condorcetVote-help=Condorcet vote: rank choices by preference order from 1 to N (1=favorite). Only the rank is taken into account, not the values. Two choices can have the same value. numberVote-help=Voting by number: The answer is free, leave blank or enter a integer. results=Results results-help=Display results #vote +vote-size=%d votes has been saved. anonymous=anonymous description=Description voterName=Voter pollAccountName-required-message=You must provide your name. anonymousVote-label=Anonymous vote submitVote=Vote +vote-success=Your vote has been correctly saved. +vote-noPagerText=%d existing votes. #choices addChoice=Adding a choice @@ -48,7 +51,7 @@ #messages pollNotFound=No such poll exists. Please make sure that you are using the correct link and copy it completely into your browser's address field. anonymousForbidden=Anonymous vote is forbidden for this poll. Enter a name. -restrictedListsForbidden=The poll is restricted and the name %s is not allowed. +restrictedListsForbidden=The poll is restricted and you are not allowed to vote. Check if you have correctly used the link sent to you by email. alreadyVoted=Someone has already used the name %s to vote. tooManyChoices=The maximal number of choices is %d. not100percent=The sum of the values must be equals to 100. Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/poll/VoteForPoll_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,23 +1,26 @@ title=Vote -about=à propos du sondage -creator-label=Créateur : -beginDate-label=Date de début : +about=A propos du sondage +creator-label=Cr\u00E9ateur : +beginDate-label=Date de d\u00E9but : endDate-label=Date de fin : pollType-label=Type de sondage : -normalVote-help=Vote normal : voter pour le ou les choix préférés. -percentageVote-help=Vote par pourcentage : répartir les choix de manière à obtenir 100% au total. -condorcetVote-help=Vote Condorcet : classer les choix par ordre de préférence de 1 à N (1=préféré). Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la même valeur. -numberVote-help=Vote par nombre : La réponse est libre, laissez vide ou entrez un nombre entier -results=Résultats -results-help=Voir les résultats +normalVote-help=Vote normal : voter pour le ou les choix pr\u00E9f\u00E9r\u00E9s. +percentageVote-help=Vote par pourcentage : r\u00E9partir les choix de mani\u00E8re \u00E0 obtenir 100%% au total. +condorcetVote-help=Vote Condorcet : classer les choix par ordre de pr\u00E9f\u00E9rence de 1 \u00E0 N (1=pr\u00E9f\u00E9r\u00E9). Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la m\u00EAme valeur. +numberVote-help=Vote par nombre : La r\u00C3\u00A9ponse est libre, laissez vide ou entrez un nombre entier +results=R\u00E9sultats +results-help=Voir les r\u00E9sultats #vote +vote-size=%d votes ont \u00E9t\u00E9 enregistr\u00E9s anonymous=anonyme description=Description voterName=Votant pollAccountName-required-message=Vous devez saisir votre nom. anonymousVote-label=Vote anonyme submitVote=Voter +vote-success=Votre vote a bien \u00E9t\u00E9 enregistr\u00E9 +vote-noPagerText=%d votes existants. #choices addChoice=Ajout d'un choix @@ -26,19 +29,19 @@ textDesc-label=Description imgFile-label=Image * imgFile-regexp=\\.(jpe?g|gif|png|JPE?G|GIF|PNG)$ -imgFile-regexp-message=L'image doit-être au format JPG, GIF ou PNG. +imgFile-regexp-message=L'image doit-\u00EAtre au format JPG, GIF ou PNG. imgFile-required-message=Vous devez saisir un choix. imgDesc-label=Description dateDTF-label=Date et heure * dateDTF-regexp=\\d{2}\/\\d{2}\/\\d{4}( \\d{2}\\:\\d{2})? -dateDTF-regexp-message=La date de début doit-être au format 31/12/2000 23:59. +dateDTF-regexp-message=La date de d\u00E9but doit-\u00EAtre au format 31/12/2000 23:59. dateDTF-required-message=Vous devez saisir un choix. dateDesc-label=Description DTF-pattern=dd/MM/yyyy HH:mm submitChoice=Ajouter #comments -comments=Commentaires à propos du sondage +comments=Commentaires \u00E0 propos du sondage commenterName-label=Nom commenterName-required-message=Vous devez saisir votre nom. commentArea-label=Commentaire @@ -46,14 +49,14 @@ submitComment=Ajouter un commentaire #messages -pollNotFound=Il n'y a pas de sondage à cette adresse. Veuillez verifier que vous utilisez le lien correcte et copiez-le complètement dans le champ d'adresse de votre navigateur. +pollNotFound=Il n'y a pas de sondage \u00E0 cette adresse. Veuillez verifier que vous utilisez le lien correcte et copiez-le compl\u00E8tement dans le champ d'adresse de votre navigateur. anonymousForbidden=Le vote anonyme est interdit pour ce sondage. Saisissez un nom. -restrictedListsForbidden=Le sondage est restreint et le nom %s n'est pas autorisé. -alreadyVoted=Une personne a déjà voté sous le nom %s. +restrictedListsForbidden=Le sondage est restreint et vous n'\u00EAtes pas autoris\u00E9 \u00E0 voter. V\u00E9rifiez que vous avez bien utiliser le lien qui vous a \u00E9t\u00E9 envoy\u00E9. +alreadyVoted=Une personne a d\u00E9j\u00E0 vot\u00E9 sous le nom %s. tooManyChoices=Le nombre de choix maximal est de %d. -not100percent=La somme des valeurs doit être égale à 100. -choiceExists=Le choix %s existe déjà. -pollNotStarted=Ce sondage n'a pas encore commencé. -pollFinished=Ce sondage est terminé. Vous ne pouvez plus voter. +not100percent=La somme des valeurs doit \u00EAtre \u00E9gale \u00E0 100. +choiceExists=Le choix %s existe d\u00E9j\u00E0\u00A0. +pollNotStarted=Ce sondage n'a pas encore commenc\u00E9. +pollFinished=Ce sondage est termin\u00E9. Vous ne pouvez plus voter. pollClosed=Ce sondage est clos. Vous ne pouvez plus voter. pollChoiceRunning=L'ajout de choix est possible. \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Account_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Account_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Account_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -2,8 +2,8 @@ login-label=Identifiant password-label=Mot de passe * newPassword1-label=Nouveau mot de passe -newPassword2-label=Répétez votre nouveau mot de passe -firstName-label=Prénom +newPassword2-label=R\u00E9p\u00E9tez votre nouveau mot de passe +firstName-label=Pr\u00E9nom lastName-label=Nom email-label=Em@il * submit-label=Valider @@ -14,10 +14,10 @@ email-regexp-message=Email invalide. login-required-message=Vous devez fournir un identifiant. password1-required-message=Vous devez fournir un mot de passe. -password1-minlength-message=Votre mot de passe doit comporter au moins 6 caractères. -password2-required-message=Vous devez répéter votre mot de passe pour confirmation. -password2-minlength-message=Votre mot de passe doit comporter au moins 6 caractères. +password1-minlength-message=Votre mot de passe doit comporter au moins 6 caract\u00E8res. +password2-required-message=Vous devez r\u00E9p\u00E9ter votre mot de passe pour confirmation. +password2-minlength-message=Votre mot de passe doit comporter au moins 6 caract\u00E8res. passwords-dont-match=Les deux mots de passe ne correspondent pas. -noUser=Vous devez être identifié pour pouvoir accéder à votre compte.\n Veuillez remplir le formulaire ci-dessous. +noUser=Vous devez \u00EAtre identifi\u00E9 pour pouvoir acc\u00E9der \u00E0 votre compte.\n Veuillez remplir le formulaire ci-dessous. badPassword=Votre mot de passe est invalide. -emailAlreadyExists=Un utilisateur est déjà enregistré avec cet email. \ No newline at end of file +emailAlreadyExists=Un utilisateur est d\u00E9j\u00E0 enregistr\u00E9 avec cet email. \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Register_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Register_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/Register_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,8 +1,8 @@ title=S'enregistrer login-label=Identifiant * password1-label=Mot de passe * -password2-label=Répétez votre mot de passe * -firstName-label=Prénom +password2-label=R\u00E9p\u00E9tez votre mot de passe * +firstName-label=Pr\u00E9nom lastName-label=Nom email-label=Em@il * submit-label=S'enregistrer @@ -12,9 +12,9 @@ email-regexp-message=Email invalide. login-required-message=Vous devez fournir un identifiant. password1-required-message=Vous devez fournir un mot de passe. -password1-minlength-message=Votre mot de passe doit comporter au moins 6 caractères. -password2-required-message=Vous devez répéter votre mot de passe pour confirmation. -password2-minlength-message=Votre mot de passe doit comporter au moins 6 caractères. +password1-minlength-message=Votre mot de passe doit comporter au moins 6 caract\u00E8res. +password2-required-message=Vous devez r\u00E9p\u00E9ter votre mot de passe pour confirmation. +password2-minlength-message=Votre mot de passe doit comporter au moins 6 caract\u00E8res. passwords-dont-match=Les deux mots de passe ne correspondent pas. -loginAlreadyExists=Un utilisateur est déjà enregistré avec cet identifiant. -emailAlreadyExists=Un utilisateur est déjà enregistré avec cet email. \ No newline at end of file +loginAlreadyExists=Un utilisateur est d\u00E9j\u00E0 enregistr\u00E9 avec cet identifiant. +emailAlreadyExists=Un utilisateur est d\u00E9j\u00E0 enregistr\u00E9 avec cet email. \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserLists_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserLists_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserLists_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,14 +1,14 @@ title=Vos listes de votants -accountExists=L'identifiant de vote %s existe déjà dans cette liste. -listExists=La liste %s existe déjà. +accountExists=L'identifiant de vote %s existe d\u00E9j\u00E0 dans cette liste. +listExists=La liste %s existe d\u00E9j\u00E0. invalidCsv=Le fichier %s n'est pas un fichier CSV. -noAccountCsv=Le fichier %s ne contient aucune entrée valide. -noAccountLdap=L'URL %s ne permet pas d'obtenir d'entrées valides. -noUser=Vous devez être identifié pour pouvoir accéder à vos listes de votants.\n Veuillez remplir le formulaire ci-dessous. -noList=Aucune liste sélectionnée. +noAccountCsv=Le fichier %s ne contient aucune entr\u00E9e valide. +noAccountLdap=L'URL %s ne permet pas d'obtenir d'entr\u00E9es valides. +noUser=Vous devez \u00EAtre identifi\u00E9 pour pouvoir acc\u00E9der \u00E0 vos listes de votants.\n Veuillez remplir le formulaire ci-dessous. +noList=Aucune liste s\u00E9lectionn\u00E9e. emptyList=Liste vide. Ajoutez des votants en saisissant leur nom et email. listSelect-label=Liste -listDeleted=La liste %s a été supprimée. +listDeleted=La liste %s a \u00E9t\u00E9 supprim\u00E9e. listNotDeleted=Erreur lors de la suppression de la liste %s. #list @@ -22,10 +22,10 @@ deleteList=Supprimer la liste #new list -createListLegend=Créer une nouvelle liste +createListLegend=Cr\u00E9er une nouvelle liste listName-label=Nom * listName-required-message=Vous devez fournir un nom. accountsFile-label=Import CSV -accountsFile-help=Vous pouvez importer une liste à partir d'un fichier CSV contenant un votant par ligne (nom, email) +accountsFile-help=Vous pouvez importer une liste \u00E0 partir d'un fichier CSV contenant un votant par ligne (nom, email) accountsUrl-label=Import LDAP -accountsUrl-help=Vous pouvez importer une liste en utilisant une URL de recherche LDAP (ldap[s]://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>) Les entrées doivent contenir les attributs cn et mail \ No newline at end of file +accountsUrl-help=Vous pouvez importer une liste en utilisant une URL de recherche LDAP (ldap[s]://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>) Les entr\u00E9es doivent contenir les attributs cn et mail \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsCreated_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsCreated_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsCreated_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,8 +1,8 @@ -title=Sondages créés -subtitle=Liste des sondages que vous avez proposés -noUser=Vous devez être identifié pour pouvoir accéder à vos sondages.\n Veuillez remplir le formulaire ci-dessous. -noPolls=Vous n'avez créé aucun sondage. +title=Sondages cr\u00E9\u00E9s +subtitle=Liste des sondages que vous avez propos\u00E9s +noUser=Vous devez \u00EAtre identifi\u00E9 pour pouvoir acc\u00E9der \u00E0 vos sondages.\n Veuillez remplir le formulaire ci-dessous. +noPolls=Vous n'avez cr\u00E9\u00E9 aucun sondage. #import -importPoll-help=Vous pouvez importer un sondage à partir d'un fichier XML +importPoll-help=Vous pouvez importer un sondage \u00E0 partir d'un fichier XML invalidFile=Le fichier %s n'est pas un fichier XML. \ No newline at end of file Modified: trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsParticipated_fr.properties =================================================================== --- trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsParticipated_fr.properties 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/resources/org/chorem/pollen/ui/pages/user/UserPollsParticipated_fr.properties 2010-03-15 14:48:49 UTC (rev 2943) @@ -1,5 +1,5 @@ -title=Sondages participés -invitedPolls=Liste des sondages pour lesquels vous êtes invité à voter -participatedPolls=Liste des sondages pour lesquels vous avez voté -noUser=Vous devez être identifié pour pouvoir accéder à vos sondages.\n Veuillez remplir le formulaire ci-dessous. +title=Sondages particip\u00E9s +invitedPolls=Liste des sondages pour lesquels vous \u00EAtes invit\u00E9 \u00E0 voter +participatedPolls=Liste des sondages pour lesquels vous avez vot\u00E9 +noUser=Vous devez \u00EAtre identifi\u00E9 pour pouvoir acc\u00E9der \u00E0 vos sondages.\n Veuillez remplir le formulaire ci-dessous. noPolls=Aucun sondage. \ No newline at end of file Modified: trunk/pollen-ui/src/main/webapp/css/vote.css =================================================================== --- trunk/pollen-ui/src/main/webapp/css/vote.css 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/webapp/css/vote.css 2010-03-15 14:48:49 UTC (rev 2943) @@ -22,18 +22,22 @@ } #pollZone { - padding: 10px; - text-align: center; - -moz-border-radius: 15px; + /*padding: 10px;*/ + text-align: center; + -moz-border-radius: 15px; } +#pollZone form { + margin-top: 10px; +} + #poll { - border-collapse: collapse; - border-left: 1px solid #aab; - border-top: 1px solid #aab; - background-color: #fff; - font-size: 14px; - margin: auto; + border-collapse: collapse; + border-left: 1px solid #aab; + border-top: 1px solid #aab; + background-color: #fff; + font-size: 14px; + margin: auto; } #poll THEAD, Modified: trunk/pollen-ui/src/main/webapp/js/pollen.js =================================================================== --- trunk/pollen-ui/src/main/webapp/js/pollen.js 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/webapp/js/pollen.js 2010-03-15 14:48:49 UTC (rev 2943) @@ -30,6 +30,11 @@ */ function onCompleteZoneUpdate(response) { var zoneManager = Tapestry.findZoneManagerForZone(response.zoneId); + + if (response.listAlert) { + alert(response.listAlert); + } + zoneManager.updateFromURL(response.link); } Modified: trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml =================================================================== --- trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml 2010-03-15 14:48:49 UTC (rev 2943) @@ -196,17 +196,22 @@ <t:label for="groupWeight" /> <t:textfield t:id="groupWeight" t:value="votingList.weight" t:size="1" validate="required,min=1" /> </div> - <div t:type="loop" t:source="votingList.pollAccountDTOs" t:value="votingListPerson" t:volatile="true"> - <t:label for="personName" /> - <t:textfield t:id="personName" t:value="votingListPerson.votingId" /> - - - <t:label for="personEmail" /> - <t:textfield t:id="personEmail" t:value="votingListPerson.email" validate="regexp" /> - - - <t:label for="personWeight" /> - <t:textfield t:id="personWeight" t:value="votingListPerson.weight" t:size="1" validate="required,min=1" /> - </div> - <t:submit t:id="addPerson" t:value="${message:addPerson}" t:context="${votingListIndex}" t:defer="false"/> + <t:unless t:test="listSizeAlert"> + <div t:type="loop" t:source="votingList.pollAccountDTOs" t:value="votingListPerson" t:volatile="true"> + <t:label for="personName" /> + <t:textfield t:id="personName" t:value="votingListPerson.votingId" /> + - + <t:label for="personEmail" /> + <t:textfield t:id="personEmail" t:value="votingListPerson.email" validate="regexp" /> + - + <t:label for="personWeight" /> + <t:textfield t:id="personWeight" t:value="votingListPerson.weight" t:size="1" validate="required,min=1" /> + </div> + <t:submit t:id="addPerson" t:value="${message:addPerson}" t:context="${votingListIndex}" t:defer="false"/> + <p:else> + ${listMaxSizeLoadedMessage} + </p:else> + </t:unless> </div> </fieldset> <div class="buttons"> Added: trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml.orig =================================================================== --- trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml.orig (rev 0) +++ trunk/pollen-ui/src/main/webapp/poll/PollCreation.tml.orig 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,301 @@ + +<t:border t:address="address" t:pageLogo="literal:Creation" + xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter"> + + <t:feedback t:id="feedback"/> + <h1 class="titleCreation">${message:title-new}</h1> + <t:zone t:id="pollCreationZone" show="show" update="show"> + <t:form t:id="pollCreationForm" t:zone="pollCreationZone"> + + <!-- Étape POLL --> + <t:formfragment visible="inPoll"> + <div id="pollCreationFormDiv"> + <t:errors/> + <fieldset> + <legend>${stepLegend}</legend> + <div> + <t:label for="votingId" /> + <t:textfield t:id="votingId" t:value="poll.creatorName" t:validate="required,minlength=2"/> + </div> + <div> + <t:label for="email" /> + <t:textfield t:id="email" t:value="poll.creatorEmail" t:validate="regexp" /> + </div> + <br /> + <div> + <t:label for="title" /> + <t:textfield t:id="title" t:value="poll.title" t:validate="required" /> + </div> + <div> + <t:label for="description" /> + <t:textarea cols="23" t:id="description" t:value="poll.description"/> + </div> + <div> + <t:label for="beginDate" /> + <input t:type="ck/dateTimeField" t:id="beginDate" value="poll.beginDate" t:validate="regexp" + t:datePattern="${message:DTF-pattern}" t:timePicker="true" t:timePickerAdjacent="true"/> + </div> + <div> + <t:label for="endDate" /> + <input t:type="ck/dateTimeField" t:id="endDate" value="poll.endDate" t:validate="regexp" + t:datePattern="${message:DTF-pattern}" t:timePicker="true" t:timePickerAdjacent="true"/> + </div> + <div> + <t:label for="pollType" /> + <t:select t:id="pollType" t:value="poll.pollType" t:validate="required"></t:select> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:pollType-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + </div> + <div> + <t:label for="voteCounting" /> + <t:select t:id="voteCounting" t:value="poll.voteCounting" t:validate="required"></t:select> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:voteCounting-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + </div> + </fieldset> + <div class="buttons"> + <t:submit t:value="${message:next-button}" t:zone="pollCreationZone" /> + </div> + </div> + </t:formfragment> + + <!-- Étape OPTIONS --> + <t:formfragment visible="inOptions"> + <div id="optionsCreationFormDiv"> + <t:errors/> + <FieldSet> + <legend>${stepLegend}</legend> + <div> + <t:checkbox t:id="anonymous" t:value="poll.anonymous" onChange="cbDisable(this, this.form.anonymousVoteAllowed)" /> + <t:label for="anonymous" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:anonymous-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + </div> + <div> + <t:checkbox t:id="anonymousVoteAllowed" t:value="poll.anonymousVoteAllowed" /> + <t:label for="anonymousVoteAllowed" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:anonymousVoteAllowed-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + </div> + <div> + <t:checkbox t:id="continuousResults" t:value="poll.continuousResults" onChange="cbDisable(this, this.form.publicResults)" /> + <t:label for="continuousResults" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:continuousResults-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + </div> + <div> + <t:checkbox t:id="publicResults" t:value="poll.publicResults" /> + <t:label for="publicResults" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:publicResults-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + </div> + <div> + <t:checkbox t:id="addChoiceAllowed" t:value="poll.choiceAddAllowed" onChange="$('choiceDateDiv').toggle()" /> + <t:label for="addChoiceAllowed" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:addChoiceAllowed-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + <br/> + <span id="choiceDateDiv" style="${choiceDateDisplay}"> + <t:label for="beginChoiceDate" /> + <input t:type="ck/dateTimeField" t:id="beginChoiceDate" value="poll.beginChoiceDate" t:validate="regexp" + t:datePattern="${message:DTF-pattern}" t:timePicker="true" t:timePickerAdjacent="true"/> + <br /> + <t:label for="endChoiceDate" /> + <input t:type="ck/dateTimeField" t:id="endChoiceDate" value="poll.endChoiceDate" t:validate="regexp" + t:datePattern="${message:DTF-pattern}" t:timePicker="true" t:timePickerAdjacent="true"/> + </span> + </div> + <t:if test="normalVoteCounting"> + <div> + <t:checkbox t:id="choiceNb" value="choiceNbCheckBox" onChange="$('choiceNbDiv').toggle()"/> + <t:label for="choiceNb" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:choiceNb-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + <br/> + <span id="choiceNbDiv" style="${choiceNbDisplay}"> + <t:label for="maxChoiceNb" /> + <t:TextField t:id="maxChoiceNb" t:value="poll.maxChoiceNb" t:size="1" t:validate="min=0"/> + </span> + </div> + </t:if> + <t:if test="poll.creatorEmail"> + <div> + <t:checkbox t:id="sendNotification" t:value="notificationCheckBox" onChange="$('notificationDiv').toggle()"/> + <t:label for="sendNotification" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:sendNotification-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + <br/> + <span id="notificationDiv" style="${notificationDisplay}"> + <t:label for="notification" /> + <t:TextField t:id="notification" t:value="notificationPreventRule.sensibility" t:size="3" t:validate="min=0"/> + ${message:notification-label2} + </span> + </div> + </t:if> + <t:unless test="freePoll"> + <div> + <t:checkbox t:id="sendReminder" t:value="reminderCheckBox" onChange="$('reminderDiv').toggle()"/> + <t:label for="sendReminder" /> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:sendReminder-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + <br/> + <span id="reminderDiv" style="${reminderDisplay}"> + <t:TextField t:id="reminder" t:value="reminderPreventRule.sensibility" t:size="1" t:validate="min=0"/> + <t:label for="reminder" /> + </span> + </div> + </t:unless> + </FieldSet> + <div class="buttons"> + <t:eventLink t:event="previous" t:zone="pollCreationZone" style="text-decoration: none;"> + <input type="button" value="${message:prev-button}" /> + </t:eventLink> + <t:submit t:value="${message:next-button}" t:zone="pollCreationZone" /> + </div> + </div> + </t:formfragment> + + <!-- Étape LISTS --> + <t:formfragment visible="inLists"> + <div id="listsCreationFormDiv"> + <t:if test="personListsExists"> + <div> + <t:label for="listSelect" />: + <t:select t:id="listSelect" t:model="personLists" t:encoder="personLists" t:value="personList" + t:mixins="ck/onEvent" t:event="change" t:onCompleteCallback="literal:onCompleteZoneUpdate"></t:select> + <span t:type="ck/Tooltip" title="${message:help}" value="${message:listSelect-help}" effect="appear"> + <img src="${asset:context:img/help.png}" alt="${message:help}"/> + </span> + </div> + </t:if> + <t:errors/> + <fieldset> + <legend>${stepLegend}</legend> + <div t:type="loop" t:source="votingLists" t:value="votingList" t:volatile="true" class="${currentListClass}"> + <div t:type="if" test="groupPoll" class="groupTitleDiv"> + <t:if test="severalGroups"> + <span class="cmd"> + <t:submit t:id="editGroup" t:value="${message:edit}" t:context="${votingListIndex}" t:defer="false" t:class="editGroupSubmit"/> + <t:submit t:id="deleteGroup" t:value="${message:delete}" t:context="${votingListIndex}" t:defer="false" t:class="deleteGroupSubmit"/> + </span> + </t:if> + ${message:group-label} ${votingListNumber} >> + <t:label for="groupName" /> + <t:textfield t:id="groupName" t:value="votingList.name" validate="required" /> + - + <t:label for="groupWeight" /> + <t:textfield t:id="groupWeight" t:value="votingList.weight" t:size="1" validate="required,min=1" /> + </div> + <div t:type="loop" t:source="votingList.pollAccountDTOs" t:value="votingListPerson" t:volatile="true"> + <t:label for="personName" /> + <t:textfield t:id="personName" t:value="votingListPerson.votingId" /> + - + <t:label for="personEmail" /> + <t:textfield t:id="personEmail" t:value="votingListPerson.email" validate="regexp" /> + - + <t:label for="personWeight" /> + <t:textfield t:id="personWeight" t:value="votingListPerson.weight" t:size="1" validate="required,min=1" /> + </div> + <t:submit t:id="addPerson" t:value="${message:addPerson}" t:context="${votingListIndex}" t:defer="false"/> + </div> + </fieldset> + <div class="buttons"> + <t:eventLink t:event="previous" t:zone="pollCreationZone" style="text-decoration: none;"> + <input type="button" value="${message:prev-button}" /> + </t:eventLink> + <t:if test="groupPoll"> + <t:submit t:id="addGroup" t:value="${message:addGroup}" /> + </t:if> + <t:submit t:value="${message:next-button}" t:zone="pollCreationZone" /> + </div> + </div> + </t:formfragment> + + </t:form> + + + <!-- Étape CHOICES - Formulaire différent car t:upload ne fonctionne pas en ajax --> + <t:if test="inChoices"> + <t:FeedContextLink t:id="feedContext" /> + <t:form t:id="choicesCreationForm"> + <div id="choicesCreationFormDiv"> + <t:unless test="numberVoteCounting"> + <div> + <t:label for="choiceType" />: + <t:select t:id="choiceType" t:value="poll.choiceType" t:validate="required" + t:mixins="ck/OnEvent" event="change" onCompleteCallback="onCompleteZoneUpdate"> + </t:select> + </div> + </t:unless> + <t:errors/> + <fieldset> + <legend>${stepLegend}</legend> + <t:formfragment t:id="textChoiceFragment" visible="isTextChoices()"> + <div t:type="loop" t:source="choices" t:value="choice" t:volatile="true"> + <div class="fleft choiceName"> + <t:label for="textName" /> + <t:textfield class="nameField" t:id="textName" t:value="choice.name" /> + - + <t:label for="textDesc" /> + </div> + <div class="fleft"> + <t:textarea cols="30" t:id="textDesc" t:value="choice.description" /> + </div> + <div class="clr" /> + </div> + </t:formfragment> + <t:formfragment t:id="dateChoiceFragment" visible="isDateChoices()"> + <div t:type="loop" t:source="dateTypeChoices" t:value="dateTypeChoice" t:volatile="true"> + <div class="fleft choiceName"> + <t:label for="dateDTF" /> + <input t:type="ck/dateTimeField" t:id="dateDTF" value="dateTypeChoice.date" t:validate="regexp" + t:datePattern="${message:DTF-pattern}" t:timePicker="true" t:timePickerAdjacent="true"/> + - + <t:label for="dateDesc" /> + </div> + <div class="fleft"> + <t:textarea cols="35" t:id="dateDesc" t:value="dateTypeChoice.description" /> + </div> + <div class="clr" /> + </div> + </t:formfragment> + <t:formfragment t:id="imgChoiceFragment" visible="isImgChoices()"> + <t:ImageContextLink t:id="imgContext" t:dir="poll.pollId" /> + <div t:type="loop" t:source="imgTypeChoices" t:value="imgTypeChoice" t:volatile="true"> + <div class="fleft choiceName"> + <t:label for="imgFile" /> + <input class="nameField" t:type="upload" t:id="imgFile" t:value="imgTypeChoice.img" t:validate="regexp" /> + - + <t:label for="imgDesc" /> + </div> + <div class="fleft"> + <t:textarea cols="30" t:id="imgDesc" t:value="imgTypeChoice.description" /> + </div> + <div class="clr" /> + </div> + </t:formfragment> + </fieldset> + <div class="buttons"> + <t:eventLink t:event="previous" t:zone="pollCreationZone" style="text-decoration: none;"> + <input type="button" value="${message:prev-button}" /> + </t:eventLink> + <t:submit t:id="addChoice" t:value="${message:addChoice}" /> + <t:submit t:value="${message:submit}" /> + </div> + </div> + </t:form> + </t:if> + + + </t:zone> +</t:border> \ No newline at end of file Modified: trunk/pollen-ui/src/main/webapp/poll/PollModification.tml =================================================================== --- trunk/pollen-ui/src/main/webapp/poll/PollModification.tml 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/webapp/poll/PollModification.tml 2010-03-15 14:48:49 UTC (rev 2943) @@ -128,16 +128,21 @@ <t:textfield t:id="groupName" t:value="votingList.name" validate="required" /> - ${message:groupWeight-label} ${weightAsInt} </div> - <div t:type="loop" t:source="votingList.pollAccountDTOs" t:value="votingListPerson" t:volatile="true"> - <t:label for="personName" /> - <t:textfield t:id="personName" t:value="votingListPerson.votingId" validate="required" t:disabled="votingListPerson.hasVoted"/> - - - <t:label for="personEmail" /> - <t:textfield t:id="personEmail" t:value="votingListPerson.email" validate="regexp" t:disabled="votingListPerson.hasVoted"/> - - - <t:label for="personWeight" /> - <t:textfield t:id="personWeight" t:value="votingListPerson.weight" t:size="1" validate="required,min=1" t:disabled="votingListPerson.hasVoted"/> - </div> + <t:unless t:test="listSizeAlert"> + <div t:type="loop" t:source="votingList.pollAccountDTOs" t:value="votingListPerson" t:volatile="true"> + <t:label for="personName" /> + <t:textfield t:id="personName" t:value="votingListPerson.votingId" validate="required" t:disabled="votingListPerson.hasVoted"/> + - + <t:label for="personEmail" /> + <t:textfield t:id="personEmail" t:value="votingListPerson.email" validate="regexp" t:disabled="votingListPerson.hasVoted"/> + - + <t:label for="personWeight" /> + <t:textfield t:id="personWeight" t:value="votingListPerson.weight" t:size="1" validate="required,min=1" t:disabled="votingListPerson.hasVoted"/> + </div> + <p:else> + ${message:list-maxSize-cant-update} + </p:else> + </t:unless> </div> </fieldset> <div class="buttons"> Modified: trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml =================================================================== --- trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pollen-ui/src/main/webapp/poll/VoteForPoll.tml 2010-03-15 14:48:49 UTC (rev 2943) @@ -46,6 +46,14 @@ <!-- Sondage --> <t:zone t:id="pollZone" t:show="show" t:update="show"> + <t:if t:test="poll.anonymous"> + <p>${voteSizeMessage}</p> + <t:feedback t:id="voteFeedback"/> + <p:else> + <t:pager t:nbRowsPerPage="nbVotesPerPage" t:nbTotalRows="poll.nbVotes" + t:currentPage="page" t:noPagerText="prop:noPagerText"/> + </p:else> + </t:if> <t:form t:id="voteForm" t:zone="pollZone"> <table id="poll"> <thead> @@ -104,17 +112,11 @@ <t:unless test="isDescNull()"> <th class="desc"> <span t:type="ck/Tooltip" title="${message:description}" value="${choiceOfPoll.description}" effect="blind"> - <!-- <t:eventlink event="displayImage" context="${choiceOfPoll.id}"> - <t:image src="${choiceOfPoll.name}" alt="${choiceOfPoll.name}" t:context="imgContext"/> - </t:eventlink> --> <t:image t:src="choiceOfPoll.name" alt="choiceOfPoll.description" t:dir="poll.pollId"/> </span> </th> <p:else> <th> - <!--<t:eventlink event="displayImage" context="${choiceOfPoll.id}"> - <t:image src="${choiceOfPoll.name}" alt="${choiceOfPoll.name}" t:context="imgContext"/> - </t:eventlink> --> <t:image t:src="choiceOfPoll.name" alt="choiceOfPoll.name" t:dir="poll.pollId"/> </th> </p:else> @@ -157,74 +159,76 @@ </tfoot> </t:if> <tbody> - <t:loop t:source="poll.voteDTOs" t:value="vote" volatile="true"> - <tr> - <td class="${evenodd.next}"> - <t:if test="${AccountFieldDisplayed}"> - <t:unless test="${currentVoteAnonymous}"> - ${currentVotingId} - <p:else> - ? - </p:else> + <t:unless t:test="poll.anonymous"> + <t:loop t:source="votes" t:value="vote" volatile="true"> + <tr> + <td class="${evenodd.next}"> + <t:if test="${AccountFieldDisplayed}"> + <t:unless test="${currentVoteAnonymous}"> + ${currentVotingId} + <p:else> + ? + </p:else> + </t:unless> + </t:if> + <t:unless test="${poll.anonymous}"> + <t:if test="isModifAllowed(currentVotingId)"> + <t:actionlink t:id="editVote" context="${currentVotingId}" t:zone="pollZone"> + <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:unless> - </t:if> - <t:unless test="${poll.anonymous}"> - <t:if test="isModifAllowed(currentVotingId)"> - <t:actionlink t:id="editVote" context="${currentVotingId}" t:zone="pollZone"> - <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:unless> - </td> - <t:loop t:source="poll.choiceDTOs" t:value="choiceOfPoll" volatile="true"> - <t:if test="!isChoiceHidden()"> - ${setCurrentVoteChoice()} - <t:if test="${poll.anonymous}"> - <td class="anonymous">?</td> - <p:else> - <t:if test="isNormalVoteCounting()"> - <t:if test="isChoiceInVote(currentVoteChoice)"> - <td class="voted">OK</td> - <p:else> - <td class="notVoted"></td> - </p:else> - </t:if> - </t:if> - <t:if test="isPercentageVoteCounting()"> - <t:if test="isChoiceInVote(currentVoteChoice)"> - <td class="voted">${currentVoteChoice.value} %</td> - <p:else> - <td class="notVoted"></td> - </p:else> - </t:if> - </t:if> - <t:if test="isCondorcetVoteCounting()"> - <t:if test="isChoiceInVote(currentVoteChoice)"> - <td class="voted">${currentVoteChoice.value}</td> - <p:else> - <td class="notVoted"></td> - </p:else> - </t:if> - </t:if> - <t:if test="isNumberVoteCounting()"> - <t:if test="isChoiceInVote(currentVoteChoice)"> - <td class="voted">${currentVoteChoice.value}</td> - <p:else> - <td class="notVoted"></td> - </p:else> - </t:if> - </t:if> - </p:else> - </t:if> - </t:if> - </t:loop> - </tr> - </t:loop> + </td> + <t:loop t:source="poll.choiceDTOs" t:value="choiceOfPoll" volatile="true"> + <t:unless t:test="choiceHidden"> + ${setCurrentVoteChoice()} + <t:if t:test="poll.anonymous"> + <td class="anonymous">?</td> + <p:else> + <t:if test="isNormalVoteCounting()"> + <t:if test="isChoiceInVote(currentVoteChoice)"> + <td class="voted">OK</td> + <p:else> + <td class="notVoted"></td> + </p:else> + </t:if> + </t:if> + <t:if test="isPercentageVoteCounting()"> + <t:if test="isChoiceInVote(currentVoteChoice)"> + <td class="voted">${currentVoteChoice.value} %</td> + <p:else> + <td class="notVoted"></td> + </p:else> + </t:if> + </t:if> + <t:if test="isCondorcetVoteCounting()"> + <t:if test="isChoiceInVote(currentVoteChoice)"> + <td class="voted">${currentVoteChoice.value}</td> + <p:else> + <td class="notVoted"></td> + </p:else> + </t:if> + </t:if> + <t:if test="isNumberVoteCounting()"> + <t:if test="isChoiceInVote(currentVoteChoice)"> + <td class="voted">${currentVoteChoice.value}</td> + <p:else> + <td class="notVoted"></td> + </p:else> + </t:if> + </t:if> + </p:else> + </t:if> + </t:unless> + </t:loop> + </tr> + </t:loop> + </t:unless> <t:if test="poll.continuousResults"> <tr> <td> Added: trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/CSVAccountUtilTest.java =================================================================== --- trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/CSVAccountUtilTest.java (rev 0) +++ trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/CSVAccountUtilTest.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,69 @@ + +package org.chorem.pollen.ui.utils; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import org.chorem.pollen.business.dto.PollAccountDTO; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * + * @author fdesbois + */ +public class CSVAccountUtilTest { + + public CSVAccountUtilTest() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of importList method, of class CSVAccountUtil. + */ + @Test + public void testImportList_Reader() { + System.out.println("importList"); + + InputStream input = getClass().getResourceAsStream("/import.csv"); + InputStreamReader reader = new InputStreamReader(input); + + List<PollAccountDTO> accounts = CSVAccountUtil.importList(reader); + + Assert.assertEquals(3, accounts.size()); + + PollAccountDTO account = accounts.get(0); + + Assert.assertEquals("toto", account.getVotingId()); + Assert.assertEquals("toto@titi.fr", account.getEmail()); + Assert.assertEquals(3., account.getWeight(), 0.1); + } + + /** + * Test of importList method, of class CSVAccountUtil. + */ + @Test + public void testImportList_UploadedFile() { + System.out.println("importList"); + } + +} \ No newline at end of file Property changes on: trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/CSVAccountUtilTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Added: trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/SendMailTest.java =================================================================== --- trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/SendMailTest.java (rev 0) +++ trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/SendMailTest.java 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,102 @@ +/* *##% Pollen + * Copyright (C) 2010 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. ##%*/ + +package org.chorem.pollen.ui.utils; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.chorem.pollen.business.PollenContext; +import org.chorem.pollen.business.PollenProperty; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.nuiton.util.ApplicationConfig; + +/** + * Class for send mail storage class. + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ + * By : $Author$ + */ +@Ignore +public class SendMailTest { + + protected static SendMail sendMail; + + @BeforeClass + public static void init() throws InterruptedException { + + ApplicationConfig config = new ApplicationConfig(); + config.setOption(PollenProperty.EMAIL_DIR.getKey(), "target" + File.separator + "massmail"); + config.setOption(PollenProperty.EMAIL_HOST.getKey(), "smtp"); + config.setOption(PollenProperty.EMAIL_PORT.getKey(), "25"); + config.setOption(PollenProperty.EMAIL_FROM.getKey(), "pollenreminder@codelutin.com"); + + PollenContext.loadConfiguration(config); + + sendMail = new SendMail(); + sendMail.start(); + Thread.sleep(3000); + } + + /** + * Test to add mail and send mail. + * + * WARNING : This test really send mail, don't set it automatic. + * + * @throws IOException + * @throws InterruptedException + */ + @Test + public void testAddMail() throws IOException, InterruptedException { + List<Map<String, String>> mailList = new ArrayList<Map<String,String>>(); + + Map<String, String> mailMap = new HashMap<String, String>(); + mailMap.put("receiver", "chatellier+test@codelutin.com"); + mailMap.put("subject", "Test 18:00"); + mailMap.put("body", "Test body"); + + Map<String, String> mailMap2 = new HashMap<String, String>(); + mailMap2.put("receiver", "chorlet+test@codelutin.com"); + mailMap2.put("subject", "CR, CR CR !!! 18:00"); + mailMap2.put("body", "Des cr, encore des \"CRs\" !!!"); + + mailList.add(mailMap); + mailList.add(mailMap2); + + sendMail.prepareMails("test", mailList); + + String emailDir = PollenProperty.EMAIL_DIR.getValue(); + + Assert.assertTrue(new File(emailDir, "test.mail").exists()); + Assert.assertTrue(new File(emailDir, "test.index").exists()); + sendMail.wakeUp(); + + // TODO , en 5 secondes, il aura le temps d'envoyer 2 mails ? + Thread.sleep(5000); + Assert.assertFalse(new File(emailDir, "test.mail").exists()); + Assert.assertFalse(new File(emailDir, "test.index").exists()); + } +} Property changes on: trunk/pollen-ui/src/test/java/org/chorem/pollen/ui/utils/SendMailTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Added: trunk/pollen-ui/src/test/resources/import.csv =================================================================== --- trunk/pollen-ui/src/test/resources/import.csv (rev 0) +++ trunk/pollen-ui/src/test/resources/import.csv 2010-03-15 14:48:49 UTC (rev 2943) @@ -0,0 +1,3 @@ +toto,"toto@titi.fr","3" +John Locke,john@locke.fr,1 +"Jack Pot","jackpot@bloum.fr","1" \ No newline at end of file Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2010-03-15 11:03:11 UTC (rev 2942) +++ trunk/pom.xml 2010-03-15 14:48:49 UTC (rev 2943) @@ -129,7 +129,7 @@ <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> - <version>1.2.128</version> + <version>1.2.131</version> </dependency> <dependency> <groupId>postgresql</groupId> @@ -299,8 +299,8 @@ <!-- customized versions --> <!--javadoc.version>2.4</javadoc.version--> - <topia.version>2.3.0-beta-9-SNAPSHOT</topia.version> - <eugene.version>2.0.0-beta-4</eugene.version> + <topia.version>2.3</topia.version> + <eugene.version>2.0</eugene.version> <i18n.version>1.0.1</i18n.version> <tapestry.version>5.1.0.5</tapestry.version> <nuiton-utils.version>1.1.5-SNAPSHOT</nuiton-utils.version>
participants (1)
-
fdesbois@users.chorem.org