This is an automated email from the git hooks/post-receive script. New commit to branch feature/148-configuration-methodes-de-votes in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 065aa1618483d53b8267cfd69fb7324b0cbc11b7 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Wed Oct 4 15:03:39 2017 +0200 Ajouter la configuration des méthodes vote (ref #148). Adaptation pour Normal, Cumulatif (ancien pourcentage), Nombre et Borda --- .../h2/V3_1_0_3__add_vote_counting_config.sql | 23 +++++ .../V3_1_0_3__add_vote_counting_config.sql | 23 +++++ pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 29157 -> 29234 bytes pollen-rest-api/pom.xml | 1 - .../pollen/rest/api/converter/JacksonConfig.java | 2 + .../converter/VoteCountingConfigDeserializer.java | 111 +++++++++++++++++++++ .../org/chorem/pollen/services/bean/PollBean.java | 20 ++-- .../pollen/services/service/PollService.java | 10 +- .../services/service/VoteCountingService.java | 66 ++++++++++-- .../pollen/services/service/VoteService.java | 28 ++++-- pollen-ui-riot-js/src/main/web/i18n/en.json | 17 ++-- pollen-ui-riot-js/src/main/web/i18n/fr.json | 17 ++-- pollen-ui-riot-js/src/main/web/js/PollForm.js | 2 +- .../src/main/web/tag/poll/Settings.tag.html | 58 ++++------- .../src/main/web/tag/poll/Votes.tag.html | 8 +- .../web/tag/voteCountingType/BordaConfig.tag.html | 107 ++++++++++++++++++++ .../voteCountingType/BordaDetailResult.tag.html | 12 +-- .../tag/voteCountingType/CumulativeConfig.tag.html | 34 +++++++ .../MaxChoicesNumberConfig.tag.html | 60 +++++++++++ pollen-votecounting-aggregator/pom.xml | 4 +- pollen-votecounting-api/pom.xml | 4 + .../pollen/votecounting/AbstractVoteCounting.java | 14 ++- .../votecounting/AbstractVoteCountingStrategy.java | 10 +- .../chorem/pollen/votecounting/VoteCounting.java | 14 ++- .../pollen/votecounting/VoteCountingFactory.java | 3 +- .../pollen/votecounting/VoteCountingStrategy.java | 5 +- .../model/EmptyVoteCountingConfig.java | 7 ++ .../votecounting/model/MaxChoicesNumberConfig.java | 17 ++++ .../votecounting/model/VoteCountingConfig.java | 7 ++ .../chorem/pollen/votecounting/BordaConfig.java | 21 ++++ .../pollen/votecounting/BordaVoteCounting.java | 7 +- .../votecounting/BordaVoteCountingStrategy.java | 38 ++++++- .../pollen-votecounting-borda_fr_FR.properties | 2 +- .../BordaVoteCountingStrategyTest.java | 8 +- .../pollen/votecounting/CondorcetVoteCounting.java | 8 +- .../CondorcetVoteCountingStrategy.java | 3 +- .../pollen-votecounting-condorcet_fr_FR.properties | 2 +- .../CondorcetVoteCountingStrategyTest.java | 8 +- .../pollen/votecounting/CoombsVoteCounting.java | 8 +- .../votecounting/CoombsVoteCountingStrategy.java | 3 +- .../pollen-votecounting-coombs_en_GB.properties | 2 +- .../pollen-votecounting-coombs_fr_FR.properties | 2 +- .../CoombsVoteCountingStrategyTest.java | 8 +- .../LICENSE.txt | 0 .../README.md | 0 .../pom.xml | 6 +- .../pollen/votecounting/CumulativeConfig.java | 19 ++++ .../votecounting/CumulativeVoteCounting.java | 21 ++-- .../CumulativeVoteCountingStrategy.java | 2 +- .../org.chorem.pollen.votecounting.VoteCounting | 1 + ...pollen-votecounting-cumulative_en_GB.properties | 4 + ...pollen-votecounting-cumulative_fr_FR.properties | 4 + .../CumulativeVoteCountingStrategyTest.java | 14 +-- .../votecounting/VoteCountingFactoryTest.java | 2 +- .../src/test/resources/log4j.properties | 0 .../votecounting/InstantRunoffVoteCounting.java | 16 +-- .../InstantRunoffVoteCountingStrategy.java | 3 +- .../InstantRunoffVoteCountingStrategyTest.java | 8 +- .../pollen/votecounting/NormalVoteCounting.java | 16 +-- .../votecounting/NormalVoteCountingStrategy.java | 3 +- .../NormalVoteCountingStrategyTest.java | 8 +- .../pollen/votecounting/NumberVoteCounting.java | 16 +-- .../votecounting/NumberVoteCountingStrategy.java | 9 +- .../NumberVoteCountingStrategyTest.java | 9 +- .../org.chorem.pollen.votecounting.VoteCounting | 1 - ...pollen-votecounting-percentage_en_GB.properties | 4 - ...pollen-votecounting-percentage_fr_FR.properties | 4 - 68 files changed, 781 insertions(+), 195 deletions(-) diff --git a/pollen-persistence/src/main/resources/db/migration/h2/V3_1_0_3__add_vote_counting_config.sql b/pollen-persistence/src/main/resources/db/migration/h2/V3_1_0_3__add_vote_counting_config.sql new file mode 100644 index 00000000..85448132 --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/h2/V3_1_0_3__add_vote_counting_config.sql @@ -0,0 +1,23 @@ +-- add vote counting type configuration +alter table poll add votecountingconfig longvarchar; + +-- 1 Normal ; +UPDATE poll set votecountingconfig = concat('{maxChoiceNumber: ', maxChoiceNumber, '}') where votecountingtype = 1; + +-- 2 Pourcentage +UPDATE poll set votecountingconfig = '{weight: 100}' where votecountingtype = 2; + +-- 3 Condorcet +UPDATE poll set votecountingconfig = '' where votecountingtype = 3; + +-- 4 Number +UPDATE poll set votecountingconfig = concat('{maxChoiceNumber: ', maxChoiceNumber, '}') where votecountingtype = 4; + +-- 5 Boda +UPDATE poll set votecountingconfig = '{maxChoiceNumber: 0, pointsByRank: null}' where votecountingtype = 5; + +-- 6 Instant runoff +UPDATE poll set votecountingconfig = '' where votecountingtype = 6; + +-- 6 Coombs +UPDATE poll set votecountingconfig = '' where votecountingtype = 7; \ No newline at end of file diff --git a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_1_0_3__add_vote_counting_config.sql b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_1_0_3__add_vote_counting_config.sql new file mode 100644 index 00000000..c3a80bd5 --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_1_0_3__add_vote_counting_config.sql @@ -0,0 +1,23 @@ +-- add vote counting type configuration +alter table poll add votecountingconfig text; + +-- 1 Normal ; +UPDATE poll set votecountingconfig = concat('{maxChoiceNumber: ', maxChoiceNumber, '}') where votecountingtype = 1; + +-- 2 Pourcentage +UPDATE poll set votecountingconfig = '{weight: 100}' where votecountingtype = 2; + +-- 3 Condorcet +UPDATE poll set votecountingconfig = '' where votecountingtype = 3; + +-- 4 Number +UPDATE poll set votecountingconfig = concat('{maxChoiceNumber: ', maxChoiceNumber, '}') where votecountingtype = 4; + +-- 5 Boda +UPDATE poll set votecountingconfig = '{maxChoiceNumber: 0, pointsByRank: null}' where votecountingtype = 5; + +-- 6 Instant runoff +UPDATE poll set votecountingconfig = '' where votecountingtype = 6; + +-- 6 Coombs +UPDATE poll set votecountingconfig = '' where votecountingtype = 7; \ No newline at end of file diff --git a/pollen-persistence/src/main/xmi/pollen.properties b/pollen-persistence/src/main/xmi/pollen.properties index 4d9d4fbb..28095962 100644 --- a/pollen-persistence/src/main/xmi/pollen.properties +++ b/pollen-persistence/src/main/xmi/pollen.properties @@ -18,7 +18,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # #L% ###m -model.tagvalue.version=3.1.0.2 +model.tagvalue.version=3.1.0.3 #model.tagValue.notGenerateToString=true #model.tagValue.constantPrefix=PROPERTY_ #model.tagValue.useEnumerationName=true diff --git a/pollen-persistence/src/main/xmi/pollen.zargo b/pollen-persistence/src/main/xmi/pollen.zargo index e77a7ac6..e4adfd28 100644 Binary files a/pollen-persistence/src/main/xmi/pollen.zargo and b/pollen-persistence/src/main/xmi/pollen.zargo differ diff --git a/pollen-rest-api/pom.xml b/pollen-rest-api/pom.xml index 864c7dbd..3fcca8db 100644 --- a/pollen-rest-api/pom.xml +++ b/pollen-rest-api/pom.xml @@ -68,7 +68,6 @@ <artifactId>pollen-votecounting-aggregator</artifactId> <version>${project.version}</version> <type>pom</type> - <scope>runtime</scope> </dependency> <dependency> <groupId>${project.groupId}</groupId> diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/converter/JacksonConfig.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/converter/JacksonConfig.java index 93984b95..ba152e8c 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/converter/JacksonConfig.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/converter/JacksonConfig.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import org.chorem.pollen.services.bean.PollenEntityId; import org.chorem.pollen.services.bean.PollenEntityRef; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; @@ -44,6 +45,7 @@ public class JacksonConfig implements ContextResolver<ObjectMapper> { module.addSerializer(PollenEntityRef.class, new PollenEntityRefSerializer()); module.addDeserializer(PollenEntityId.class, new PollenEntityIdDeserializer()); module.addDeserializer(PollenEntityRef.class, new PollenEntityRefDeserializer()); + module.addDeserializer(VoteCountingConfig.class, new VoteCountingConfigDeserializer()); objectMapper.registerModule(module); } diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/converter/VoteCountingConfigDeserializer.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/converter/VoteCountingConfigDeserializer.java new file mode 100644 index 00000000..504c5b32 --- /dev/null +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/converter/VoteCountingConfigDeserializer.java @@ -0,0 +1,111 @@ +package org.chorem.pollen.rest.api.converter; + +/*- + * #%L + * Pollen :: Rest Api + * %% + * Copyright (C) 2009 - 2017 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import org.chorem.pollen.votecounting.BordaConfig; +import org.chorem.pollen.votecounting.CumulativeConfig; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; + +import java.io.IOException; +import java.util.List; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class VoteCountingConfigDeserializer extends JsonDeserializer<VoteCountingConfig> { + + @Override + public VoteCountingConfig deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + + VoteCountingConfigTemp configTemp = ctxt.readValue(p, VoteCountingConfigTemp.class); + + VoteCountingConfig config; + + if (configTemp.getMaxChoiceNumber() != null) { + + if (configTemp.getPointsByRank() != null) { + + BordaConfig bordaConfig = new BordaConfig(); + bordaConfig.setMaxChoiceNumber(configTemp.getMaxChoiceNumber()); + bordaConfig.setPointsByRank(configTemp.getPointsByRank()); + config = bordaConfig; + + } else { + + MaxChoicesNumberConfig maxChoicesNumberConfig = new MaxChoicesNumberConfig(); + maxChoicesNumberConfig.setMaxChoiceNumber(configTemp.getMaxChoiceNumber()); + config = maxChoicesNumberConfig; + } + } else if (configTemp.getPoints() != null) { + + CumulativeConfig cumulativeConfig = new CumulativeConfig(); + cumulativeConfig.setPoints(configTemp.getPoints()); + config = cumulativeConfig; + + } else { + + config = new EmptyVoteCountingConfig(); + + } + + return config; + + } + + static class VoteCountingConfigTemp { + + protected Integer maxChoiceNumber; + + protected List<Integer> pointsByRank; + + protected Integer points; + + public Integer getMaxChoiceNumber() { + return maxChoiceNumber; + } + + public void setMaxChoiceNumber(Integer maxChoiceNumber) { + this.maxChoiceNumber = maxChoiceNumber; + } + + public List<Integer> getPointsByRank() { + return pointsByRank; + } + + public void setPointsByRank(List<Integer> pointsByRank) { + this.pointsByRank = pointsByRank; + } + + public Integer getPoints() { + return points; + } + + public void setPoints(Integer points) { + this.points = points; + } + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java index dd89ed27..b1d2bbaf 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java @@ -28,6 +28,7 @@ import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.PollType; import org.chorem.pollen.persistence.entity.ResultVisibility; import org.chorem.pollen.persistence.entity.VoteVisibility; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import java.util.Date; import java.util.Objects; @@ -80,8 +81,6 @@ public class PollBean extends PollenBean<Poll> { protected Date endDate; - protected int maxChoiceNumber; - protected boolean choiceAddAllowed; protected boolean anonymousVoteAllowed; @@ -142,6 +141,7 @@ public class PollBean extends PollenBean<Poll> { protected String creatorAvatar; + protected VoteCountingConfig voteCountingConfig; public String getPermission() { return permission; @@ -215,14 +215,6 @@ public class PollBean extends PollenBean<Poll> { this.endDate = endDate; } - public int getMaxChoiceNumber() { - return maxChoiceNumber; - } - - public void setMaxChoiceNumber(int maxChoiceNumber) { - this.maxChoiceNumber = maxChoiceNumber; - } - public boolean isChoiceAddAllowed() { return choiceAddAllowed; } @@ -473,4 +465,12 @@ public class PollBean extends PollenBean<Poll> { public void setCreatorAvatar(String creatorAvatar) { this.creatorAvatar = creatorAvatar; } + + public VoteCountingConfig getVoteCountingConfig() { + return voteCountingConfig; + } + + public void setVoteCountingConfig(VoteCountingConfig voteCountingConfig) { + this.voteCountingConfig = voteCountingConfig; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java index 314f96b9..ee82987b 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java @@ -98,7 +98,6 @@ public class PollService extends PollenServiceSupport { bean.setEndChoiceDate(entity.getEndChoiceDate()); bean.setBeginDate(entity.getBeginDate()); bean.setEndDate(entity.getEndDate()); - bean.setMaxChoiceNumber(entity.getMaxChoiceNumber()); bean.setChoiceAddAllowed(entity.isChoiceAddAllowed()); bean.setAnonymousVoteAllowed(entity.isAnonymousVoteAllowed()); bean.setContinuousResults(entity.isContinuousResults()); @@ -115,6 +114,7 @@ public class PollService extends PollenServiceSupport { bean.setCommentNotification(entity.isCommentNotification()); bean.setNewChoiceNotification(entity.isNewChoiceNotification()); bean.setNotificationLocale(entity.getNotificationLocale()); + bean.setVoteCountingConfig(getVoteCountingService().getVoteCountingConfig(entity)); Date now = getNow(); if (Polls.isFinished(entity, now)) { @@ -256,7 +256,9 @@ public class PollService extends PollenServiceSupport { // -- default values -- // PollenServicesConfig pollenServiceConfig = getPollenServiceConfig(); - pollBean.setVoteCountingType(pollenServiceConfig.getDefaultVoteCountingType()); + int voteCountingType = pollenServiceConfig.getDefaultVoteCountingType(); + pollBean.setVoteCountingType(voteCountingType); + pollBean.setVoteCountingConfig(getVoteCountingService().newConfig(voteCountingType)); pollBean.setPollType(pollenServiceConfig.getDefaultPollType()); pollBean.setVoteVisibility(pollenServiceConfig.getDefaultVoteVisibility()); pollBean.setCommentVisibility(pollenServiceConfig.getDefaultCommentVisibility()); @@ -531,7 +533,6 @@ public class PollService extends PollenServiceSupport { toSave.setContinuousResults(poll.isContinuousResults()); toSave.setDescription(poll.getDescription()); toSave.setPollType(poll.getPollType()); - toSave.setMaxChoiceNumber(poll.getMaxChoiceNumber()); toSave.setTitle(poll.getTitle()); toSave.setChoiceType(poll.getChoiceType()); toSave.setWithMe(poll.isWithMe()); @@ -563,6 +564,9 @@ public class PollService extends PollenServiceSupport { toSave.setEndChoiceDate(poll.getEndChoiceDate()); } + String configToJson = getVoteCountingService().configToJson(poll.getVoteCountingConfig()); + toSave.setVoteCountingConfig(configToJson); + // -- choice -- // if (CollectionUtils.isNotEmpty(choices)) { diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java index 145cb25d..4ee03c36 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteCountingService.java @@ -23,12 +23,15 @@ package org.chorem.pollen.services.service; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.Polls; import org.chorem.pollen.persistence.entity.Vote; import org.chorem.pollen.persistence.entity.VoteToChoice; import org.chorem.pollen.persistence.entity.VoterList; import org.chorem.pollen.persistence.entity.VoterListMember; +import org.chorem.pollen.services.PollenTechnicalException; import org.chorem.pollen.services.bean.ChoiceBean; import org.chorem.pollen.services.bean.ListVoteCountingResultBean; import org.chorem.pollen.services.bean.VoteBean; @@ -41,6 +44,7 @@ import org.chorem.pollen.votecounting.VoteCountingStrategy; import org.chorem.pollen.votecounting.model.ListOfVoter; import org.chorem.pollen.votecounting.model.ListVoteCountingResult; import org.chorem.pollen.votecounting.model.SimpleVoter; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; import org.chorem.pollen.votecounting.model.Voter; @@ -82,6 +86,52 @@ public class VoteCountingService extends PollenServiceSupport { } + public <S extends VoteCountingStrategy<C>, C extends VoteCountingConfig> C newConfig(int voteCountingType) { + + VoteCountingFactory voteCountingFactory = serviceContext.getVoteCountingFactory(); + + VoteCounting<S, C> voteCounting = voteCountingFactory.getVoteCounting(voteCountingType); + + Class<C> configType = voteCounting.getConfigType(); + + try { + return configType.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new PollenTechnicalException(e); + } + } + + protected <C extends VoteCountingConfig> C configFromJson(String json, Class<C> configType) { + Gson gson = new GsonBuilder().create(); + if (json == null || "null".equals(json)) { + try { + return configType.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new PollenTechnicalException(e); + } + } + return gson.fromJson(json, configType); + } + + protected <C extends VoteCountingConfig> String configToJson(C config) { + Gson gson = new GsonBuilder().create(); + return gson.toJson(config); + } + + public <S extends VoteCountingStrategy<C>, C extends VoteCountingConfig> C getVoteCountingConfig(Poll poll) { + VoteCounting<S, C> voteCounting = getVoteCounting(poll); + return configFromJson(poll.getVoteCountingConfig(), voteCounting.getConfigType()); + } + + public <S extends VoteCountingStrategy<C>, C extends VoteCountingConfig> VoteCountingStrategy<C> getVoteCountingStrategy(Poll poll) { + VoteCounting<S, C> voteCounting = getVoteCounting(poll); + VoteCountingStrategy<C> strategy = voteCounting.newStrategy(); + C config = configFromJson(poll.getVoteCountingConfig(), voteCounting.getConfigType()); + strategy.setConfig(config); + + return strategy; + } + public VoteCountingResultBean getSimpleResult(String pollId) { Preconditions.checkNotNull(pollId); @@ -89,8 +139,7 @@ public class VoteCountingService extends PollenServiceSupport { Poll poll = getPollService().getPoll0(pollId); List<Vote> votes = getVotes(poll); - VoteCounting voteCounting = getVoteCounting(poll); - VoteCountingStrategy strategy = voteCounting.newStrategy(); + VoteCountingStrategy strategy = getVoteCountingStrategy(poll); ListOfVoter groupOfVoter = toSimpleVotersGroup(votes); @@ -123,8 +172,7 @@ public class VoteCountingService extends PollenServiceSupport { VoterList mainVoterList = getVoterListService().getMainVoterList0(poll); List<Vote> votes = getVotes(poll); - VoteCounting voteCounting = getVoteCounting(poll); - VoteCountingStrategy strategy = voteCounting.newStrategy(); + VoteCountingStrategy strategy = getVoteCountingStrategy(poll); // Create a groupVoter including of the root voters ListOfVoter listOfVoter = toListOfVoters(poll, mainVoterList, votes); @@ -245,12 +293,12 @@ public class VoteCountingService extends PollenServiceSupport { } - protected VoteCounting getVoteCounting(Poll poll) { + protected <S extends VoteCountingStrategy<C>, C extends VoteCountingConfig> VoteCounting<S, C> getVoteCounting(Poll poll) { int id = poll.getVoteCountingType(); VoteCountingFactory voteCountingFactory = serviceContext.getVoteCountingFactory(); - VoteCounting result = voteCountingFactory.getVoteCounting(id); + VoteCounting<S, C> result = voteCountingFactory.getVoteCounting(id); Preconditions.checkNotNull( result, "Could not find vote counting for id " + id); @@ -259,7 +307,7 @@ public class VoteCountingService extends PollenServiceSupport { } - protected ErrorMap voteIsValid(VoteBean vote, VoteCounting voteCounting, List<ChoiceBean> choices) { + protected <C extends VoteCountingConfig> ErrorMap voteIsValid(VoteBean vote, VoteCounting<?, C> voteCounting, List<ChoiceBean> choices, C config) { ErrorMap errors = new ErrorMap(); Map<String, String> choiceNamesById = choices.stream().collect(Collectors.toMap(ChoiceBean::getEntityId, ChoiceBean::getChoiceValue)); @@ -287,8 +335,8 @@ public class VoteCountingService extends PollenServiceSupport { check(errors, "totalVoteValue", - voteCounting.isTotalVoteValueValid(total), - voteCounting.getTotalVoteValueNotValidMessage(getLocale())); + voteCounting.isTotalVoteValueValid(total, config), + voteCounting.getTotalVoteValueNotValidMessage(getLocale(), config)); return errors; } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java index 61fae5cc..223a2e42 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java @@ -43,6 +43,8 @@ import org.chorem.pollen.services.bean.VoteBean; import org.chorem.pollen.services.bean.VoteToChoiceBean; import org.chorem.pollen.services.service.security.PermissionVerb; import org.chorem.pollen.votecounting.VoteCounting; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import org.nuiton.util.pagination.PaginationParameter; import org.nuiton.util.pagination.PaginationResult; @@ -302,7 +304,7 @@ public class VoteService extends PollenServiceSupport { return errors; } - protected ErrorMap checkVote(Poll poll, VoteBean vote, List<ChoiceBean> choices) { + protected <C extends VoteCountingConfig> ErrorMap checkVote(Poll poll, VoteBean vote, List<ChoiceBean> choices) { ErrorMap errors = new ErrorMap(); @@ -336,20 +338,26 @@ public class VoteService extends PollenServiceSupport { } - VoteCounting voteCounting = getVoteCountingService().getVoteCounting(poll); + VoteCounting<?, C> voteCounting = getVoteCountingService().getVoteCounting(poll); + C config = getVoteCountingService().getVoteCountingConfig(poll); - ErrorMap valueErrors = getVoteCountingService().voteIsValid(vote, voteCounting, choices); + + ErrorMap valueErrors = getVoteCountingService().voteIsValid(vote, voteCounting, choices, config); valueErrors.copyTo(errors, "vote."); - if (poll.getMaxChoiceNumber() > 0) { - int nbChoice = 0; - for (VoteToChoiceBean voteToChoice : vote.getChoice()) { - if (voteCounting.isChoiceInVote(voteToChoice.getVoteValue())) { - nbChoice++; + if (MaxChoicesNumberConfig.class.isInstance(config)) { + MaxChoicesNumberConfig maxChoicesNumberConfig = MaxChoicesNumberConfig.class.cast(config); + + if (maxChoicesNumberConfig.getMaxChoiceNumber() > 0) { + int nbChoice = 0; + for (VoteToChoiceBean voteToChoice : vote.getChoice()) { + if (voteCounting.isChoiceInVote(voteToChoice.getVoteValue())) { + nbChoice++; + } } - } - check(errors, "vote.limitedVote", nbChoice <= poll.getMaxChoiceNumber(), l(getLocale(), "pollen.error.vote.limitedVote.overflow")); + check(errors, "vote.limitedVote", nbChoice <= maxChoicesNumberConfig.getMaxChoiceNumber(), l(getLocale(), "pollen.error.vote.limitedVote.overflow")); + } } //TODO Finish validation diff --git a/pollen-ui-riot-js/src/main/web/i18n/en.json b/pollen-ui-riot-js/src/main/web/i18n/en.json index 864b4f6e..91e85b3e 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/en.json +++ b/pollen-ui-riot-js/src/main/web/i18n/en.json @@ -83,8 +83,8 @@ "poll_results_results": "Results", "poll_results_unit_1_one": "vote", "poll_results_unit_1_many": "votes", - "poll_results_unit_2_one": "%", - "poll_results_unit_2_many": "%", + "poll_results_unit_2_one": "point", + "poll_results_unit_2_many": "points", "poll_results_unit_3_one": "battle", "poll_results_unit_3_many": "battles", "poll_results_unit_4_one": "", @@ -141,8 +141,8 @@ "poll_votes_noVote": "No vote", "poll_votes_results_unit_1_one": "vote", "poll_votes_results_unit_1_many": "votes", - "poll_votes_results_unit_2_one": "%", - "poll_votes_results_unit_2_many": "%", + "poll_votes_results_unit_2_one": "point", + "poll_votes_results_unit_2_many": "points", "poll_votes_results_unit_3_one": "battle", "poll_votes_results_unit_3_many": "battles", "poll_votes_results_unit_4_one": "", @@ -313,7 +313,13 @@ "poll_settings_votersConfiguration": "Voters configuration", "poll_settings_voters": "Fill voters separated by space", "poll_settings_addChoices": "add choices by users", - "poll_settings_limitChoices": "Limit number of choices to use on a vote", + "poll_settings_voteCountingConfig_limitChoices": "Limit number of choices to use on a vote", + "poll_settings_voteCountingConfig_maxChoiceNumber": "Maximum number of choices", + "poll_settings_voteCountingConfig_bordaDefault": "default points distibution", + "poll_settings_voteCountingConfig_pointsByRank": "number of points allocated by rank", + "poll_settings_voteCountingConfig_rank": "Rank", + "poll_settings_voteCountingConfig_points": "points", + "poll_settings_voteCountingConfig_cumulativePoints": "number of points to allocate", "poll_settings_votesConfiguration": "Votes configuration", "poll_settings_voteCountingType": "Vote counting type used to compute poll's results.", "poll_settings_voteCountingType_normal": "Normal", @@ -328,7 +334,6 @@ "poll_settings_endDate": "to", "poll_settings_beginChoiceDate": "Add choices from", "poll_settings_endChoiceDate": "to", - "poll_settings_maxChoiceNumber": "Maximum number of choices", "poll_settings_freePoll": "Everybody can vote (Public poll)", "poll_settings_restrictedPoll": "Only invited people can vote (Private poll)", "poll_settings_restrictedPoll_withMe": "I also want to participate", diff --git a/pollen-ui-riot-js/src/main/web/i18n/fr.json b/pollen-ui-riot-js/src/main/web/i18n/fr.json index 630120cc..43a10aec 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/fr.json +++ b/pollen-ui-riot-js/src/main/web/i18n/fr.json @@ -83,8 +83,8 @@ "poll_results_results": "Résultats", "poll_results_unit_1_one": "vote", "poll_results_unit_1_many": "votes", - "poll_results_unit_2_one": "%", - "poll_results_unit_2_many": "%", + "poll_results_unit_2_one": "point", + "poll_results_unit_2_many": "points", "poll_results_unit_3_one": "combat", "poll_results_unit_3_many": "combats", "poll_results_unit_4_one": "", @@ -141,8 +141,8 @@ "poll_votes_noVote": "Aucun vote", "poll_votes_results_unit_1_one": "vote", "poll_votes_results_unit_1_many": "votes", - "poll_votes_results_unit_2_one": "%", - "poll_votes_results_unit_2_many": "%", + "poll_votes_results_unit_2_one": "point", + "poll_votes_results_unit_2_many": "points", "poll_votes_results_unit_3_one": "combat", "poll_votes_results_unit_3_many": "combats", "poll_votes_results_unit_4_one": "", @@ -313,7 +313,13 @@ "poll_settings_votersConfiguration": "Configuration des participants", "poll_settings_voters": "Renseignez la liste des participants", "poll_settings_addChoices": "Ajout de choix par les participants", - "poll_settings_limitChoices": "Limiter le nombre de choix par vote", + "poll_settings_voteCountingConfig_limitChoices": "Limiter le nombre de choix par vote", + "poll_settings_voteCountingConfig_maxChoiceNumber": "Nombre maximum de choix", + "poll_settings_voteCountingConfig_bordaDefault": "Répartition des points par défaut", + "poll_settings_voteCountingConfig_pointsByRank": "Nombre de points distribués par rang", + "poll_settings_voteCountingConfig_rank": "Rang", + "poll_settings_voteCountingConfig_points": "points", + "poll_settings_voteCountingConfig_cumulativePoints": "Nombre de points à distribuer", "poll_settings_votesConfiguration": "Configuration des votes", "poll_settings_voteCountingType": "Type de scrutin pour effectuer le dépouillement du sondage", "poll_settings_voteCountingType_normal": "Normal", @@ -328,7 +334,6 @@ "poll_settings_endDate": "au", "poll_settings_beginChoiceDate": "Ajout de choix du", "poll_settings_endChoiceDate": "au", - "poll_settings_maxChoiceNumber": "Nombre maximum de choix", "poll_settings_freePoll": "Tout le monde peut voter (Sondage public)", "poll_settings_restrictedPoll": "Seul les invités peuvent voter (Sondage privé)", "poll_settings_restrictedPoll_withMe": "Je participe au sondage", diff --git a/pollen-ui-riot-js/src/main/web/js/PollForm.js b/pollen-ui-riot-js/src/main/web/js/PollForm.js index ef2a2fda..97c90b8d 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollForm.js +++ b/pollen-ui-riot-js/src/main/web/js/PollForm.js @@ -260,7 +260,7 @@ class PollForm { this.model.addChoices = false; this.model.beginChoiceDate = undefined; this.model.endChoiceDate = undefined; - this.model.maxChoiceNumber = undefined; + this.model.voteCountingConfig = {}; this.model.voteCountingType = 1; diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html index e26ca8e7..40bfec72 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html @@ -10,18 +10,21 @@ it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. #L% */ require("../components/date-time-picker.tag.html"); require("../components/Checkbox.tag.html"); +require("../voteCountingType/MaxChoicesNumberConfig.tag.html"); +require("../voteCountingType/BordaConfig.tag.html"); +require("../voteCountingType/CumulativeConfig.tag.html"); <Settings> <div class="form-section" show={form.creation}> @@ -137,29 +140,20 @@ require("../components/Checkbox.tag.html"); disabled={form.hasVotes || opts.form.model.closed}/> </div> </div> - <div show="{canLimitNumberOfChoices}" class="o-form-element"> - <Checkbox label="{__.limitChoices}" - name="limitChoices" - id="limitChoices" - ref="limitChoices" - disabled={form.hasVotes || opts.form.model.closed} - checkboxchecked={form.model.limitChoices} - ontogglecheckbox={toggleLimitChoices}/> - </div> - <div show="{form.model.limitChoices}" class="o-form-element"> - <label class="c-label" for="maxChoiceNumber"> - {__.maxChoiceNumber} - </label> - <input name="maxChoiceNumber" - tabindex="1" - id="maxChoiceNumber" - ref="maxChoiceNumber" - class="c-field c-field--label" - disabled={form.hasVotes || opts.form.model.closed} - value={form.model.maxChoiceNumber} - min="{form.model.limitChoices ? 1 : 0}" max="{form.choices.length}" - type="number"> - </div> + <MaxChoicesNumberConfig if={opts.form.model.voteCountingType == 1 || opts.form.model.voteCountingType == 4} + ref="config" + config={form.model.voteCountingConfig} + count-choices={form.choices.length} + disabled={form.hasVotes || form.model.closed}/> + <BordaConfig if={opts.form.model.voteCountingType == 5} + ref="config" + config={form.model.voteCountingConfig} + count-choices={form.choices.length} + disabled={form.hasVotes || form.model.closed}/> + <CumulativeConfig if={opts.form.model.voteCountingType == 2} + ref="config" + config={form.model.voteCountingConfig} + disabled={form.hasVotes || form.model.closed}/> </div> </div> @@ -337,7 +331,6 @@ require("../components/Checkbox.tag.html"); this.showOptions = this.form.showOptions; this.showHelp = false; this.voteCountingTypes = new Map(this.form.voteCountingTypes.map((t) => [t.id.toString(), t])); - this.canLimitNumberOfChoices = this.voteCountingTypes.get(this.form.model.voteCountingType.toString()).canLimitNumberOfChoices; this.form.model.votePeriod = this.form.model.beginDate || this.form.model.endDate; this.notifyMeBeforePollEnds = this.form.model.creatorEmail && this.form.model.notifyMeHoursBeforePollEnds > 0; this.disableNotifyMeBeforePollEnds = !this.form.model.creatorEmail || !this.form.model.votePeriod || !this.form.model.endDate; @@ -388,14 +381,6 @@ require("../components/Checkbox.tag.html"); this.update(); }; - this.toggleLimitChoices = () => { - this.form.model.limitChoices = !this.form.model.limitChoices; - if (this.form.model.limitChoices && !this.form.model.maxChoiceNumber) { - this.form.model.maxChoiceNumber = 1; - } - this.update(); - }; - this.toggleVotePeriod = () => { this.form.model.votePeriod = !this.form.model.votePeriod; this.updateDisableNotifyMeBeforePollEnds(); @@ -431,8 +416,6 @@ require("../components/Checkbox.tag.html"); } else { this.form.model.voteCountingType = e.target.value; } - this.canLimitNumberOfChoices = this.voteCountingTypes.get(this.form.model.voteCountingType).canLimitNumberOfChoices; - this.form.model.limitChoices &= this.canLimitNumberOfChoices; this.updateVoteCountingTypeHelp(); }; @@ -458,13 +441,13 @@ require("../components/Checkbox.tag.html"); this.form.model.addChoices = this.refs.addChoices.checked; this.form.model.beginChoiceDate = this.refs.addChoices.checked ? this.refs.beginChoiceDate.getValue() : undefined; this.form.model.endChoiceDate = this.refs.addChoices.checked ? this.refs.endChoiceDate.getValue() : undefined; - this.form.model.maxChoiceNumber = this.refs.limitChoices.checked ? this.refs.maxChoiceNumber.value : undefined; this.form.model.beginDate = this.refs.votePeriod.checked ? this.refs.beginDate.getValue() : undefined; this.form.model.voteVisibility = this.refs.voteVisibility.value; this.form.model.anonymousVoteAllowed = this.refs.anonymousVote.checked; this.form.model.resultVisibility = this.refs.resultVisibility.value; this.form.model.commentVisibility = this.refs.commentVisibility.value; + this.form.model.voteCountingConfig = this.refs.config ? this.refs.config.getConfig() : {}; } this.form.model.endDate = this.refs.votePeriod.checked ? this.refs.endDate.getValue() : undefined; @@ -485,7 +468,6 @@ require("../components/Checkbox.tag.html"); this.listen("locale", () => { this.form.reloadVoteCountingTypes().then(() => { this.voteCountingTypes = new Map(this.form.voteCountingTypes.map((t) => [t.id.toString(), t])); - this.canLimitNumberOfChoices = this.voteCountingTypes.get(this.form.model.voteCountingType.toString()).canLimitNumberOfChoices; this.updateVoteCountingTypeHelp(); }); }); diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Votes.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Votes.tag.html index 5d25d051..9e88a4a4 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Votes.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Votes.tag.html @@ -71,7 +71,7 @@ require("../components/Avatar.tag.html"); <input if={!pollTypeCheckbox} class="text c-field {c-field--error: !voteInEdition && error && (error['vote.voteValue#' + choice.id] || error['vote.totalVoteValue'])}" type="number" - required + required={!poll.voteCountingConfig.maxChoiceNumber} min="{poll.voteCountingTypeValue && poll.voteCountingTypeValue.minimumValue}" max="{poll.voteCountingTypeValue && poll.voteCountingTypeValue.maximumValue}" onchange="{onVoteChanged}" @@ -119,7 +119,7 @@ require("../components/Avatar.tag.html"); </button> </div> <div class="c-hint--static c-hint--error" if="{tooManyChoicesSelected}"> - {__.tooManyChoicesSelected} {poll.maxChoiceNumber} + {__.tooManyChoicesSelected} {poll.voteCountingConfig.maxChoiceNumber} </div> <div class="c-hint--static c-hint--error" if="{error}"> <div each={fields in error}> @@ -335,7 +335,7 @@ require("../components/Avatar.tag.html"); }; this.onVoteChanged = () => { - if (this.loaded && this.poll.maxChoiceNumber) { + if (this.loaded && this.poll.voteCountingConfig.maxChoiceNumber) { var selectedChoiceNb = 0; this.poll.choices.forEach(c => { var choiceValue = this.getChoiceVoteValue(c.id + "_voteValue"); @@ -343,7 +343,7 @@ require("../components/Avatar.tag.html"); selectedChoiceNb++; } }); - this.tooManyChoicesSelected = selectedChoiceNb > this.poll.maxChoiceNumber; + this.tooManyChoicesSelected = selectedChoiceNb > this.poll.voteCountingConfig.maxChoiceNumber; } else { this.tooManyChoicesSelected = false; } diff --git a/pollen-ui-riot-js/src/main/web/tag/voteCountingType/BordaConfig.tag.html b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/BordaConfig.tag.html new file mode 100644 index 00000000..e15a2653 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/BordaConfig.tag.html @@ -0,0 +1,107 @@ +require("./MaxChoicesNumberConfig.tag.html"); + +<BordaConfig> + + <MaxChoicesNumberConfig ref="maxChoiceNumber" + config={opts.config} + count-choices={opts.countChoices} + disabled={opts.disabled} + onchange={updatePointsByRank}/> + + <div class="o-form-element"> + <Checkbox label="{__.bordaDefault}" + name="bordaDefault" + id="bordaDefault" + ref="bordaDefault" + disabled={opts.disabled} + checkboxchecked={opts.config.pointsByRankDefault} + ontogglecheckbox={toggleBordaDefault}/> + </div> + <div class="o-form-element"> + <label class="c-label" for="maxChoiceNumber"> + {__.pointsByRank} + </label> + <div class="c-input-group c-input-group--stacked c-field--label"> + <div class="o-field ranks" + each={value, index in opts.config.pointsByRank || []}> + <i class="rank">{parent.__.rank} {index + 1} :</i> + <input name="points-{index}" + tabindex="1" + id="points-{index}" + ref="points" + class="c-field" + disabled={parent.opts.disabled || parent.opts.config.pointsByRankDefault} + value={value} + min="{index + 1 === parent.opts.config.pointsByRank.length ? 1 : parent.opts.config.pointsByRank[index + 1]}" + max="{index === 0 ? undefined : parent.opts.config.pointsByRank[index - 1]}" + onChange={parent.pointsChange(index)} + type="number"> + <i class="points">{parent.__.points}</i> + </div> + </div> + </div> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "poll_settings_voteCountingConfig"); + + if (this.opts.config.pointsByRankDefault === undefined) { + this.opts.config.pointsByRankDefault = this.opts.config.pointsByRank === undefined || this.opts.config.pointsByRank === null; + } + + + this.toggleBordaDefault = () => { + this.opts.config.pointsByRankDefault = !this.opts.config.pointsByRankDefault; + if (this.opts.config.pointsByRankDefault) { + this.updatePointsByRank(); + } + this.update(); + }; + + this.updatePointsByRank = () => { + let length = this.opts.config.maxChoiceNumber || this.opts.countChoices; + this.opts.config.pointsByRank = Array.from(Array(length).keys(), x => length - x); + }; + + this.pointsChange = index => () => { + this.opts.config.pointsByRank[index] = this.refs.points[index].valueAsNumber; + }; + + this.getConfig = () => { + let config = this.refs.maxChoiceNumber.getConfig(); + config.pointsByRank = this.opts.config.pointsByRankDefault ? null : this.refs.points.map(input => input.valueAsNumber); + return config; + }; + + if (!this.opts.config.pointsByRank) { + this.updatePointsByRank(); + } + + + </script> + + <style> + + .ranks .rank { + left: .5em; + position: absolute; + top: 50%; + transform: translateY(-50%); + color: var(--default); + } + + .ranks .points { + right: .5em; + position: absolute; + top: 50%; + transform: translateY(-50%); + color: var(--default); + } + + .ranks .c-field { + padding-left: 5em; + padding-right: 4em; + } + </stryle> + +</BordaConfig> diff --git a/pollen-ui-riot-js/src/main/web/tag/voteCountingType/BordaDetailResult.tag.html b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/BordaDetailResult.tag.html index 7fa67c9a..a5b25608 100644 --- a/pollen-ui-riot-js/src/main/web/tag/voteCountingType/BordaDetailResult.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/BordaDetailResult.tag.html @@ -8,12 +8,12 @@ it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. #L% @@ -25,15 +25,15 @@ require("../poll/ChoiceView.tag.html"); <table class="ranks"> <tr> <td class="cell">{__.ranks}</td> - <td class="cell rank" each={rank in Array.from(Array(poll.choices.length).keys())}> + <td class="cell rank" each={rank in Array.from(Array(poll.voteCountingConfig.maxChoiceNumber || poll.choices.length).keys())}> {rank + 1} </td> <td class="cell"></td> </tr> <tr> <td class="cell separator-top">{__.points}</td> - <td class="cell separator-top" each={rank in Array.from(Array(poll.choices.length).keys())}> - {poll.choices.length - rank} + <td class="cell separator-top" each={rank in Array.from(Array(poll.voteCountingConfig.maxChoiceNumber || poll.choices.length).keys())}> + {poll.voteCountingConfig.pointsByRank ? poll.voteCountingConfig.pointsByRank[rank] : (poll.voteCountingConfig.maxChoiceNumber || poll.choices.length) - rank} </td> <td class="cell score">{__.total}</td> </tr> @@ -41,7 +41,7 @@ require("../poll/ChoiceView.tag.html"); <td class="cell separator-top"> <ChoiceView choice={choice} center="true"/> </td> - <td class="cell separator-top" each={rank in Array.from(Array(poll.choices.length).keys())}> + <td class="cell separator-top" each={rank in Array.from(Array(poll.voteCountingConfig.maxChoiceNumber || poll.choices.length).keys())}> {getRankScore(choice, rank)} </td> <td class="cell separator-top score"> diff --git a/pollen-ui-riot-js/src/main/web/tag/voteCountingType/CumulativeConfig.tag.html b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/CumulativeConfig.tag.html new file mode 100644 index 00000000..e2b4f9c2 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/CumulativeConfig.tag.html @@ -0,0 +1,34 @@ +<CumulativeConfig> + + <div class="o-form-element"> + <label class="c-label" for="points"> + {__.cumulativePoints} + </label> + <input name="points" + tabindex="1" + id="points" + ref="points" + class="c-field c-field--label" + disabled={opts.disabled} + value={opts.config.points} + min="2" + type="number"> + </div> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "poll_settings_voteCountingConfig"); + + if (!this.opts.config.points) { + this.opts.config.points = 100; + } + + this.getConfig = () => { + return { + points: this.refs.points.valueAsNumber + }; + }; + + </script> + +</CumulativeConfig> diff --git a/pollen-ui-riot-js/src/main/web/tag/voteCountingType/MaxChoicesNumberConfig.tag.html b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/MaxChoicesNumberConfig.tag.html new file mode 100644 index 00000000..5eed5c93 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voteCountingType/MaxChoicesNumberConfig.tag.html @@ -0,0 +1,60 @@ +<MaxChoicesNumberConfig> + + <div class="o-form-element"> + <Checkbox label="{__.limitChoices}" + name="limitChoices" + id="limitChoices" + ref="limitChoices" + disabled={opts.disabled} + checkboxchecked={opts.config.maxChoiceNumber > 0} + ontogglecheckbox={toggleLimitChoices}/> + </div> + <div show={opts.config.maxChoiceNumber > 0} class="o-form-element"> + <label class="c-label" for="maxChoiceNumber"> + {__.maxChoiceNumber} + </label> + <input name="maxChoiceNumber" + tabindex="1" + id="maxChoiceNumber" + ref="maxChoiceNumber" + class="c-field c-field--label" + disabled={opts.disabled} + value={Math.max(1, opts.config.maxChoiceNumber)} + min="1" max="{opts.countChoices}" + type="number" + onchange={maxChoiceNumberChange}> + </div> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "poll_settings_voteCountingConfig"); + + this.toggleLimitChoices = () => { + if (this.opts.config.maxChoiceNumber === 0) { + this.opts.config.maxChoiceNumber = this.opts.countChoices; + } else { + this.opts.config.maxChoiceNumber = 0; + } + if (this.opts.onchange) { + this.opts.onchange(); + } + this.update(); + }; + + this.maxChoiceNumberChange = () => { + this.opts.config.maxChoiceNumber = this.refs.maxChoiceNumber.valueAsNumber; + if (this.opts.onchange) { + this.opts.onchange(); + } + }; + + this.getConfig = () => { + return { + maxChoiceNumber: this.refs.limitChoices.checked ? this.refs.maxChoiceNumber.valueAsNumber : 0 + }; + }; + + </script> + + +</MaxChoicesNumberConfig> diff --git a/pollen-votecounting-aggregator/pom.xml b/pollen-votecounting-aggregator/pom.xml index 21f7884e..d5e69273 100644 --- a/pollen-votecounting-aggregator/pom.xml +++ b/pollen-votecounting-aggregator/pom.xml @@ -41,7 +41,7 @@ <modules> <module>../pollen-votecounting-normal</module> - <module>../pollen-votecounting-percentage</module> + <module>../pollen-votecounting-cumulative</module> <module>../pollen-votecounting-condorcet</module> <module>../pollen-votecounting-number</module> <module>../pollen-votecounting-borda</module> @@ -57,7 +57,7 @@ </dependency> <dependency> <groupId>${project.groupId}</groupId> - <artifactId>pollen-votecounting-percentage</artifactId> + <artifactId>pollen-votecounting-cumulative</artifactId> <version>${project.version}</version> </dependency> <dependency> diff --git a/pollen-votecounting-api/pom.xml b/pollen-votecounting-api/pom.xml index c6b796ae..61491300 100644 --- a/pollen-votecounting-api/pom.xml +++ b/pollen-votecounting-api/pom.xml @@ -63,6 +63,10 @@ <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> </dependencies> diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCounting.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCounting.java index d05c3377..7e28a8fd 100644 --- a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCounting.java +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCounting.java @@ -21,6 +21,8 @@ package org.chorem.pollen.votecounting; * #L% */ +import org.chorem.pollen.votecounting.model.VoteCountingConfig; + import java.util.Locale; import static org.nuiton.i18n.I18n.l; @@ -31,7 +33,7 @@ import static org.nuiton.i18n.I18n.l; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public abstract class AbstractVoteCounting<S extends VoteCountingStrategy> implements VoteCounting<S> { +public abstract class AbstractVoteCounting<S extends VoteCountingStrategy<C>, C extends VoteCountingConfig> implements VoteCounting<S, C> { /** Unique id of the vote counting type. */ protected final int id; @@ -39,6 +41,9 @@ public abstract class AbstractVoteCounting<S extends VoteCountingStrategy> imple /** Type of strategy used to vote count. */ protected final Class<S> strategyType; + /** Type of config used to vote count. */ + protected final Class<C> configType; + /** I18n key for name of this vote counting type. */ protected final String i18nName; @@ -50,11 +55,13 @@ public abstract class AbstractVoteCounting<S extends VoteCountingStrategy> imple protected AbstractVoteCounting(int id, Class<S> strategyType, + Class<C> configType, String i18nName, String i18nShortHelp, String i18nHelp) { this.id = id; this.strategyType = strategyType; + this.configType = configType; this.i18nName = i18nName; this.i18nShortHelp = i18nShortHelp; this.i18nHelp = i18nHelp; @@ -90,4 +97,9 @@ public abstract class AbstractVoteCounting<S extends VoteCountingStrategy> imple public final int getId() { return id; } + + @Override + public Class<C> getConfigType() { + return configType; + } } diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCountingStrategy.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCountingStrategy.java index 50f6cf03..ffd402bf 100644 --- a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCountingStrategy.java +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/AbstractVoteCountingStrategy.java @@ -29,6 +29,7 @@ import org.chorem.pollen.votecounting.model.ChoiceIdAble; import org.chorem.pollen.votecounting.model.ChoiceScore; import org.chorem.pollen.votecounting.model.ListOfVoter; import org.chorem.pollen.votecounting.model.ListVoteCountingResult; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import org.chorem.pollen.votecounting.model.VoteCountingDetailResult; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; @@ -49,7 +50,7 @@ import java.util.stream.Collectors; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public abstract class AbstractVoteCountingStrategy implements VoteCountingStrategy { +public abstract class AbstractVoteCountingStrategy<C extends VoteCountingConfig> implements VoteCountingStrategy<C> { public static final BigDecimal ZERO_D = BigDecimal.valueOf(0.); @@ -65,6 +66,13 @@ public abstract class AbstractVoteCountingStrategy implements VoteCountingStrate return v1.intValue() - v2.intValue(); }; + protected C config; + + @Override + public void setConfig(C config) { + this.config = config; + } + @Override public final ListVoteCountingResult votecount(ListOfVoter listOfVoter) { diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCounting.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCounting.java index b3ec2f24..eb127b3b 100644 --- a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCounting.java +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCounting.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; */ import org.chorem.pollen.votecounting.model.ChoiceToVoteRenderType; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import java.util.Locale; @@ -31,7 +32,7 @@ import java.util.Locale; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public interface VoteCounting<S extends VoteCountingStrategy> { +public interface VoteCounting<S extends VoteCountingStrategy<C>, C extends VoteCountingConfig> { /** * Obtains a fresh instance of a vote coutning strategy. @@ -42,6 +43,13 @@ public interface VoteCounting<S extends VoteCountingStrategy> { S newStrategy(); /** + * get vote couting config type + * + * @return a vote counting config type . + */ + Class<C> getConfigType(); + + /** * Obtains the unique id of this strategy. * * @return the unique id of this strategy. @@ -116,7 +124,7 @@ public interface VoteCounting<S extends VoteCountingStrategy> { * @return {@code true} if the total values of a vote is valid, * {@code false} otherwhise. */ - boolean isTotalVoteValueValid(Double totalValues); + boolean isTotalVoteValueValid(Double totalValues, C config); /** * If the total values of a vote is not valid, gets the localized error @@ -125,7 +133,7 @@ public interface VoteCounting<S extends VoteCountingStrategy> { * @param locale the locale used to render the error message * @return the localized validation message */ - String getTotalVoteValueNotValidMessage(Locale locale); + String getTotalVoteValueNotValidMessage(Locale locale, C config); /** * Tests if a given vote value is null or not. diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingFactory.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingFactory.java index 361d7f57..d5a50dc3 100644 --- a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingFactory.java +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingFactory.java @@ -24,6 +24,7 @@ package org.chorem.pollen.votecounting; import com.google.common.collect.Maps; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import java.util.Iterator; import java.util.Locale; @@ -77,7 +78,7 @@ public class VoteCountingFactory implements Iterable<VoteCounting> { } - public VoteCounting getVoteCounting(int strategyId) throws VoteCountingNotFound { + public <S extends VoteCountingStrategy<C>, C extends VoteCountingConfig> VoteCounting<S, C> getVoteCounting(int strategyId) throws VoteCountingNotFound { VoteCounting type = voteCountings.get(strategyId); if (type == null) { diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingStrategy.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingStrategy.java index 93f9de1f..598beb66 100644 --- a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingStrategy.java +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/VoteCountingStrategy.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; import org.chorem.pollen.votecounting.model.ListOfVoter; import org.chorem.pollen.votecounting.model.ListVoteCountingResult; +import org.chorem.pollen.votecounting.model.VoteCountingConfig; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; import org.chorem.pollen.votecounting.model.Voter; @@ -34,7 +35,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public interface VoteCountingStrategy { +public interface VoteCountingStrategy<C extends VoteCountingConfig> { /** * Vote count for the given {@code group} of voters and return the @@ -60,4 +61,6 @@ public interface VoteCountingStrategy { * @return the vot for choices */ Set<VoteForChoice> toVoteForChoices(VoteCountingResult voteCountingResult); + + void setConfig(C config); } diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/EmptyVoteCountingConfig.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/EmptyVoteCountingConfig.java new file mode 100644 index 00000000..140850d6 --- /dev/null +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/EmptyVoteCountingConfig.java @@ -0,0 +1,7 @@ +package org.chorem.pollen.votecounting.model; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class EmptyVoteCountingConfig implements VoteCountingConfig { +} diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/MaxChoicesNumberConfig.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/MaxChoicesNumberConfig.java new file mode 100644 index 00000000..5d48c0b6 --- /dev/null +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/MaxChoicesNumberConfig.java @@ -0,0 +1,17 @@ +package org.chorem.pollen.votecounting.model; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class MaxChoicesNumberConfig implements VoteCountingConfig { + + protected int maxChoiceNumber; + + public int getMaxChoiceNumber() { + return maxChoiceNumber; + } + + public void setMaxChoiceNumber(int maxChoiceNumber) { + this.maxChoiceNumber = maxChoiceNumber; + } +} diff --git a/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/VoteCountingConfig.java b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/VoteCountingConfig.java new file mode 100644 index 00000000..21e317e8 --- /dev/null +++ b/pollen-votecounting-api/src/main/java/org/chorem/pollen/votecounting/model/VoteCountingConfig.java @@ -0,0 +1,7 @@ +package org.chorem.pollen.votecounting.model; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public interface VoteCountingConfig { +} diff --git a/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaConfig.java b/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaConfig.java new file mode 100644 index 00000000..3def5e15 --- /dev/null +++ b/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaConfig.java @@ -0,0 +1,21 @@ +package org.chorem.pollen.votecounting; + +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; + +import java.util.List; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class BordaConfig extends MaxChoicesNumberConfig { + + protected List<Integer> pointsByRank; + + public List<Integer> getPointsByRank() { + return pointsByRank; + } + + public void setPointsByRank(List<Integer> pointsByRank) { + this.pointsByRank = pointsByRank; + } +} diff --git a/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCounting.java b/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCounting.java index c9168a49..637bcc7f 100644 --- a/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCounting.java +++ b/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCounting.java @@ -34,13 +34,14 @@ import static org.nuiton.i18n.I18n.n; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public class BordaVoteCounting extends AbstractVoteCounting<BordaVoteCountingStrategy> { +public class BordaVoteCounting extends AbstractVoteCounting<BordaVoteCountingStrategy, BordaConfig> { public static final int ID = 5; public BordaVoteCounting() { super(ID, BordaVoteCountingStrategy.class, + BordaConfig.class, n("pollen.voteCountingType.borda"), n("pollen.voteCountingType.borda.shortHelp"), n("pollen.voteCountingType.borda.help") @@ -48,7 +49,7 @@ public class BordaVoteCounting extends AbstractVoteCounting<BordaVoteCountingStr } @Override - public String getTotalVoteValueNotValidMessage(Locale locale) { + public String getTotalVoteValueNotValidMessage(Locale locale, BordaConfig config) { // no validation on total value, so no message return null; } @@ -102,7 +103,7 @@ public class BordaVoteCounting extends AbstractVoteCounting<BordaVoteCountingStr } @Override - public boolean isTotalVoteValueValid(Double totalValues) { + public boolean isTotalVoteValueValid(Double totalValues, BordaConfig config) { // no validation on total value return true; } diff --git a/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategy.java b/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategy.java index b2fb5605..befd8304 100644 --- a/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategy.java +++ b/pollen-votecounting-borda/src/main/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategy.java @@ -21,6 +21,7 @@ package org.chorem.pollen.votecounting; import com.google.common.collect.Sets; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.pollen.votecounting.model.ChoiceScore; @@ -39,7 +40,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class BordaVoteCountingStrategy extends AbstractVoteCountingStrategy { +public class BordaVoteCountingStrategy extends AbstractVoteCountingStrategy<BordaConfig> { /** Logger. */ private static final Log log = @@ -59,6 +60,12 @@ public class BordaVoteCountingStrategy extends AbstractVoteCountingStrategy { log.debug("Nb choices: " + nbChoices); } + // nb Ranks + int nbRanks = nbChoices; + if (config.getMaxChoiceNumber() > 0) { + nbRanks = config.getMaxChoiceNumber(); + } + // calcul pour chaque votant de sa liste des choix dans son ordre préféré Map<Voter, List<Set<String>>> voterSortedChoices = @@ -70,10 +77,32 @@ public class BordaVoteCountingStrategy extends AbstractVoteCountingStrategy { for (Map.Entry<Voter, List<Set<String>>> entry : voterSortedChoices.entrySet()) { Voter voter = entry.getKey(); double weight = voter.getWeight(); - double choiceWeight = nbChoices * weight; + List<Integer> pointsByRank = config.getPointsByRank(); + int rank = 0; + for (Set<String> sortedChoiceId : entry.getValue()) { + double choiceWeight; + + if (CollectionUtils.isNotEmpty(pointsByRank)) { + + if (pointsByRank.size() > rank) { + + choiceWeight = pointsByRank.get(rank) * weight; + + } else { + + choiceWeight = 0; + + } + + } else { + + choiceWeight = (nbRanks - rank) * weight; + + } + for (String choiceId : sortedChoiceId) { scores.get(choiceId).addScoreValue(choiceWeight); @@ -81,7 +110,10 @@ public class BordaVoteCountingStrategy extends AbstractVoteCountingStrategy { } rank++; - choiceWeight -= weight; + + if (rank > nbRanks) { + break; + } } } diff --git a/pollen-votecounting-borda/src/main/resources/i18n/pollen-votecounting-borda_fr_FR.properties b/pollen-votecounting-borda/src/main/resources/i18n/pollen-votecounting-borda_fr_FR.properties index 789614f5..dd0d5b77 100644 --- a/pollen-votecounting-borda/src/main/resources/i18n/pollen-votecounting-borda_fr_FR.properties +++ b/pollen-votecounting-borda/src/main/resources/i18n/pollen-votecounting-borda_fr_FR.properties @@ -1,4 +1,4 @@ pollen.error.vote.invalidBordaVoteValue=La valeur du vote '%2$s' pour le choix %1$s n'est pas correcte, seul des valeurs entières sont autorisées. pollen.voteCountingType.borda=Borda -pollen.voteCountingType.borda.help=Classer les choix par ordre de préférence de 1 à N (1\=préféré).<br/> Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la même valeur.<br/>Pour chaque vote, on attribue des points aux choix en fonction de leur rang (comme pour le concours de l'Eurovision) ; le gagnant est le choix avec le plus de points.<br/>Pour en savoir plus \: <a href\='http\://fr.wikipedia.org/wiki/M%C3%A9thode_Borda' target\='\#doc'>http\://fr.wikip [...] +pollen.voteCountingType.borda.help=Classer les choix par ordre de préférence de 1 à N (1\=préféré).<br/> Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la même valeur.<br/>Pour chaque vote, on attribue des points aux choix en fonction de leur rang (comme pour le concours de l'Eurovision) ; le gagnant est le choix avec le plus de points.<br/>Pour en savoir plus \: <a href\='http\://fr.wikipedia.org/wiki/M%C3%A9thode_Borda' target\='\#doc'>http\://fr.wikip [...] pollen.voteCountingType.borda.shortHelp=Classer les choix par ordre de préférence de 1 à N (1\=préféré). diff --git a/pollen-votecounting-borda/src/test/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategyTest.java b/pollen-votecounting-borda/src/test/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategyTest.java index bb9404f3..53b07c12 100644 --- a/pollen-votecounting-borda/src/test/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategyTest.java +++ b/pollen-votecounting-borda/src/test/java/org/chorem/pollen/votecounting/BordaVoteCountingStrategyTest.java @@ -54,19 +54,21 @@ public class BordaVoteCountingStrategyTest { public static final String CHOICE_D = "d"; - protected static VoteCounting voteCounting; + protected static BordaVoteCounting voteCounting; - protected VoteCountingStrategy strategy; + protected BordaVoteCountingStrategy strategy; @BeforeClass public static void beforeClass() throws Exception { VoteCountingFactory factory = new VoteCountingFactory(); - voteCounting = factory.getVoteCounting(BordaVoteCounting.ID); + voteCounting = BordaVoteCounting.class.cast(factory.getVoteCounting(BordaVoteCounting.ID)); } @Before public void setUp() throws Exception { strategy = voteCounting.newStrategy(); + BordaConfig config = new BordaConfig(); + strategy.setConfig(config); } @Test diff --git a/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCounting.java b/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCounting.java index 4949d521..f43e8ea6 100644 --- a/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCounting.java +++ b/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCounting.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; */ import org.chorem.pollen.votecounting.model.ChoiceToVoteRenderType; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import java.util.Locale; @@ -34,13 +35,14 @@ import static org.nuiton.i18n.I18n.n; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public class CondorcetVoteCounting extends AbstractVoteCounting<CondorcetVoteCountingStrategy> { +public class CondorcetVoteCounting extends AbstractVoteCounting<CondorcetVoteCountingStrategy, EmptyVoteCountingConfig> { public static final int ID = 3; public CondorcetVoteCounting() { super(ID, CondorcetVoteCountingStrategy.class, + EmptyVoteCountingConfig.class, n("pollen.voteCountingType.condorcet"), n("pollen.voteCountingType.condorcet.shortHelp"), n("pollen.voteCountingType.condorcet.help") @@ -48,7 +50,7 @@ public class CondorcetVoteCounting extends AbstractVoteCounting<CondorcetVoteCou } @Override - public String getTotalVoteValueNotValidMessage(Locale locale) { + public String getTotalVoteValueNotValidMessage(Locale locale, EmptyVoteCountingConfig config) { // no validation on total value, so no message return null; } @@ -102,7 +104,7 @@ public class CondorcetVoteCounting extends AbstractVoteCounting<CondorcetVoteCou } @Override - public boolean isTotalVoteValueValid(Double totalValues) { + public boolean isTotalVoteValueValid(Double totalValues, EmptyVoteCountingConfig config) { // no validation on total value return true; } diff --git a/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategy.java b/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategy.java index a2d122d7..7db1fb77 100644 --- a/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategy.java +++ b/pollen-votecounting-condorcet/src/main/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategy.java @@ -24,6 +24,7 @@ import com.google.common.collect.Sets; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; import org.chorem.pollen.votecounting.model.Voter; @@ -38,7 +39,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class CondorcetVoteCountingStrategy extends AbstractVoteCountingStrategy { +public class CondorcetVoteCountingStrategy extends AbstractVoteCountingStrategy<EmptyVoteCountingConfig> { /** Logger. */ private static final Log log = diff --git a/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_fr_FR.properties b/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_fr_FR.properties index f79011b4..0452c805 100644 --- a/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_fr_FR.properties +++ b/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_fr_FR.properties @@ -1,4 +1,4 @@ pollen.error.vote.invalidCondorcetVoteValue=La valeur du vote '%2$s' pour le choix %1$s n'est pas correcte, seul des valeurs entières sont autorisées. pollen.voteCountingType.condorcet=Condorcet -pollen.voteCountingType.condorcet.help=Classer les choix par ordre de préférence de 1 à N (1\=préféré).<br/>Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la même valeur.<br/>Dans cette méthode, le gagnant est celui qui remporte le plus de combats par rapport aux autres choix.<br/>Pour en savoir plus \: <a href\='http\://fr.wikipedia.org/wiki/M%C3%A9thode_Condorcet' target\='\#doc'>http\://fr.wikipedia.org/wiki/M%C3%A9thode_Condorcet</a> +pollen.voteCountingType.condorcet.help=Classer les choix par ordre de préférence de 1 à N (1\=préféré).<br/>Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la même valeur.<br/>Dans cette méthode, le gagnant est celui qui remporte le plus de combats par rapport aux autres choix.<br/>Pour en savoir plus \: <a href\='http\://fr.wikipedia.org/wiki/M%C3%A9thode_Condorcet' target\='\#doc'>http\://fr.wikipedia.org/wiki/Méthode_Condorcet</a> pollen.voteCountingType.condorcet.shortHelp=Classer les choix par ordre de préférence de 1 à N (1\=préféré). diff --git a/pollen-votecounting-condorcet/src/test/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategyTest.java b/pollen-votecounting-condorcet/src/test/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategyTest.java index 59eb5c0a..04f811b8 100644 --- a/pollen-votecounting-condorcet/src/test/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategyTest.java +++ b/pollen-votecounting-condorcet/src/test/java/org/chorem/pollen/votecounting/CondorcetVoteCountingStrategyTest.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; import com.google.common.collect.Sets; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import org.chorem.pollen.votecounting.model.ListOfVoter; import org.chorem.pollen.votecounting.model.ListVoteCountingResult; import org.chorem.pollen.votecounting.model.SimpleVoter; @@ -52,19 +53,20 @@ public class CondorcetVoteCountingStrategyTest { public static final String CHOICE_C = "c"; - protected static VoteCounting voteCounting; + protected static CondorcetVoteCounting voteCounting; - protected VoteCountingStrategy strategy; + protected CondorcetVoteCountingStrategy strategy; @BeforeClass public static void beforeClass() throws Exception { VoteCountingFactory factory = new VoteCountingFactory(); - voteCounting = factory.getVoteCounting(CondorcetVoteCounting.ID); + voteCounting = CondorcetVoteCounting.class.cast(factory.getVoteCounting(CondorcetVoteCounting.ID)); } @Before public void setUp() throws Exception { strategy = voteCounting.newStrategy(); + strategy.setConfig(new EmptyVoteCountingConfig()); } @Test diff --git a/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCounting.java b/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCounting.java index 955c5467..1d30fbd0 100644 --- a/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCounting.java +++ b/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCounting.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; */ import org.chorem.pollen.votecounting.model.ChoiceToVoteRenderType; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import java.util.Locale; @@ -34,13 +35,14 @@ import static org.nuiton.i18n.I18n.n; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public class CoombsVoteCounting extends AbstractVoteCounting<CoombsVoteCountingStrategy> { +public class CoombsVoteCounting extends AbstractVoteCounting<CoombsVoteCountingStrategy, EmptyVoteCountingConfig> { public static final int ID = 7; public CoombsVoteCounting() { super(ID, CoombsVoteCountingStrategy.class, + EmptyVoteCountingConfig.class, n("pollen.voteCountingType.coombs"), n("pollen.voteCountingType.coombs.shortHelp"), n("pollen.voteCountingType.coombs.help") @@ -48,7 +50,7 @@ public class CoombsVoteCounting extends AbstractVoteCounting<CoombsVoteCountingS } @Override - public String getTotalVoteValueNotValidMessage(Locale locale) { + public String getTotalVoteValueNotValidMessage(Locale locale, EmptyVoteCountingConfig config) { // no validation on total value, so no message return null; } @@ -103,7 +105,7 @@ public class CoombsVoteCounting extends AbstractVoteCounting<CoombsVoteCountingS } @Override - public boolean isTotalVoteValueValid(Double totalValues) { + public boolean isTotalVoteValueValid(Double totalValues, EmptyVoteCountingConfig config) { // no validation on total value return true; } diff --git a/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategy.java b/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategy.java index 0ab194ee..2048d8e7 100644 --- a/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategy.java +++ b/pollen-votecounting-coombs/src/main/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategy.java @@ -25,6 +25,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.commons.collections4.CollectionUtils; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; import org.chorem.pollen.votecounting.model.Voter; @@ -43,7 +44,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class CoombsVoteCountingStrategy extends AbstractVoteCountingStrategy { +public class CoombsVoteCountingStrategy extends AbstractVoteCountingStrategy<EmptyVoteCountingConfig> { @Override public VoteCountingResult votecount(Set<Voter> voters) { diff --git a/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_en_GB.properties b/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_en_GB.properties index b70fc7ef..d6902ca1 100644 --- a/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_en_GB.properties +++ b/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_en_GB.properties @@ -1,4 +1,4 @@ pollen.error.vote.invalidCoombsVoteValue=The value '%2$s' of vote for choice %1$s is not valid, only integer values are authorized. pollen.voteCountingType.coombs=Coombs -pollen.voteCountingType.coombs.help=Rank choices by preference order from 1 to N (1\=favorite).<br/>Only the rank is taken into account, not the values. Two choices can have the same value.<br/>In this method, the choice which is last the most times is eliminated round by round until only one remains.<br/>More about this method\: <a href\='http\://en.wikipedia.org/wiki/Coombs%27_method' target\='\#doc'>http\://en.wikipedia.org/wiki/Coombs%27_method</a> +pollen.voteCountingType.coombs.help=Rank choices by preference order from 1 to N (1\=favorite).<br/>Only the rank is taken into account, not the values. Two choices can have the same value.<br/>In this method, the choice which is last the most times is eliminated round by round until only one remains.<br/>More about this method\: <a href\='http\://en.wikipedia.org/wiki/Coombs%27_method' target\='\#doc'>http\://en.wikipedia.org/wiki/Coombs_method</a> pollen.voteCountingType.coombs.shortHelp=Rank choices by preference order from 1 to N (1\=favorite). diff --git a/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_fr_FR.properties b/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_fr_FR.properties index 6674d907..a62223d3 100644 --- a/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_fr_FR.properties +++ b/pollen-votecounting-coombs/src/main/resources/i18n/pollen-votecounting-coombs_fr_FR.properties @@ -1,4 +1,4 @@ pollen.error.vote.invalidCoombsVoteValue=La valeur du vote '%2$s' pour le choix %1$s n'est pas correcte, seul des valeurs entières sont autorisées. pollen.voteCountingType.coombs=Coombs -pollen.voteCountingType.coombs.help=Classer les choix par ordre de préférence de 1 à N (1\=préféré).<br/>Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la même valeur.<br/>Dans cette méthode, le choix qui arrive le plus souvent en dernier de liste est éliminé à chaque tour, jusqu'à ce qu'il n'en reste qu'un.<br/>Pour en savoir plus \: <a href\='http\://fr.wikipedia.org/wiki/M%C3%A9thode_de_Coombs' target\='\#doc'>http\://fr.wikipedia.org/wiki/M%C3%A9thod [...] +pollen.voteCountingType.coombs.help=Classer les choix par ordre de préférence de 1 à N (1\=préféré).<br/>Seul l'ordre des choix compte, peu importe les valeurs. Deux choix peuvent avoir la même valeur.<br/>Dans cette méthode, le choix qui arrive le plus souvent en dernier de liste est éliminé à chaque tour, jusqu'à ce qu'il n'en reste qu'un.<br/>Pour en savoir plus \: <a href\='http\://fr.wikipedia.org/wiki/M%C3%A9thode_de_Coombs' target\='\#doc'>http\://fr.wikipedia.org/wiki/Méthode_de_ [...] pollen.voteCountingType.coombs.shortHelp=Classer les choix par ordre de préférence de 1 à N (1\=préféré). diff --git a/pollen-votecounting-coombs/src/test/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategyTest.java b/pollen-votecounting-coombs/src/test/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategyTest.java index 014a241c..9e388fb6 100644 --- a/pollen-votecounting-coombs/src/test/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategyTest.java +++ b/pollen-votecounting-coombs/src/test/java/org/chorem/pollen/votecounting/CoombsVoteCountingStrategyTest.java @@ -21,6 +21,7 @@ package org.chorem.pollen.votecounting; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import org.chorem.pollen.votecounting.model.SimpleVoterBuilder; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.Voter; @@ -52,19 +53,20 @@ public class CoombsVoteCountingStrategyTest { public static final String CHOICE_D = "Ville D"; - protected static VoteCounting voteCounting; + protected static CoombsVoteCounting voteCounting; - protected VoteCountingStrategy strategy; + protected CoombsVoteCountingStrategy strategy; @BeforeClass public static void beforeClass() throws Exception { VoteCountingFactory factory = new VoteCountingFactory(); - voteCounting = factory.getVoteCounting(CoombsVoteCounting.ID); + voteCounting = CoombsVoteCounting.class.cast(factory.getVoteCounting(CoombsVoteCounting.ID)); } @Before public void setUp() throws Exception { strategy = voteCounting.newStrategy(); + strategy.setConfig(new EmptyVoteCountingConfig()); } @Test diff --git a/pollen-votecounting-percentage/LICENSE.txt b/pollen-votecounting-cumulative/LICENSE.txt similarity index 100% rename from pollen-votecounting-percentage/LICENSE.txt rename to pollen-votecounting-cumulative/LICENSE.txt diff --git a/pollen-votecounting-percentage/README.md b/pollen-votecounting-cumulative/README.md similarity index 100% rename from pollen-votecounting-percentage/README.md rename to pollen-votecounting-cumulative/README.md diff --git a/pollen-votecounting-percentage/pom.xml b/pollen-votecounting-cumulative/pom.xml similarity index 93% rename from pollen-votecounting-percentage/pom.xml rename to pollen-votecounting-cumulative/pom.xml index 1d75c4b9..8efd327a 100644 --- a/pollen-votecounting-percentage/pom.xml +++ b/pollen-votecounting-cumulative/pom.xml @@ -31,10 +31,10 @@ </parent> <groupId>org.chorem.pollen</groupId> - <artifactId>pollen-votecounting-percentage</artifactId> + <artifactId>pollen-votecounting-cumulative</artifactId> - <name>Pollen :: VoteCounting :: Percentage</name> - <description>Implements the percentage vote counting</description> + <name>Pollen :: VoteCounting :: Cumulative</name> + <description>Implements the cumulative vote counting</description> <dependencies> diff --git a/pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeConfig.java b/pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeConfig.java new file mode 100644 index 00000000..4ff961e4 --- /dev/null +++ b/pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeConfig.java @@ -0,0 +1,19 @@ +package org.chorem.pollen.votecounting; + +import org.chorem.pollen.votecounting.model.VoteCountingConfig; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class CumulativeConfig implements VoteCountingConfig { + + protected int points; + + public int getPoints() { + return points; + } + + public void setPoints(int points) { + this.points = points; + } +} diff --git a/pollen-votecounting-percentage/src/main/java/org/chorem/pollen/votecounting/PercentageVoteCounting.java b/pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeVoteCounting.java similarity index 77% rename from pollen-votecounting-percentage/src/main/java/org/chorem/pollen/votecounting/PercentageVoteCounting.java rename to pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeVoteCounting.java index efd1e3ea..4ed03213 100644 --- a/pollen-votecounting-percentage/src/main/java/org/chorem/pollen/votecounting/PercentageVoteCounting.java +++ b/pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeVoteCounting.java @@ -34,16 +34,17 @@ import static org.nuiton.i18n.I18n.n; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public class PercentageVoteCounting extends AbstractVoteCounting<PercentageVoteCountingStrategy> { +public class CumulativeVoteCounting extends AbstractVoteCounting<CumulativeVoteCountingStrategy, CumulativeConfig> { public static final int ID = 2; - public PercentageVoteCounting() { + public CumulativeVoteCounting() { super(ID, - PercentageVoteCountingStrategy.class, - n("pollen.voteCountingType.percentage"), - n("pollen.voteCountingType.percentage.shortHelp"), - n("pollen.voteCountingType.percentage.help") + CumulativeVoteCountingStrategy.class, + CumulativeConfig.class, + n("pollen.voteCountingType.cumulative"), + n("pollen.voteCountingType.cumulative.shortHelp"), + n("pollen.voteCountingType.cumulative.help") ); } @@ -89,8 +90,8 @@ public class PercentageVoteCounting extends AbstractVoteCounting<PercentageVoteC } @Override - public boolean isTotalVoteValueValid(Double totalValues) { - return totalValues == null || totalValues == 100; + public boolean isTotalVoteValueValid(Double totalValues, CumulativeConfig cumulativeConfig) { + return totalValues == null || totalValues == cumulativeConfig.getPoints(); } @Override @@ -102,8 +103,8 @@ public class PercentageVoteCounting extends AbstractVoteCounting<PercentageVoteC } @Override - public String getTotalVoteValueNotValidMessage(Locale locale) { - return l(locale, "pollen.error.vote.percentage"); + public String getTotalVoteValueNotValidMessage(Locale locale, CumulativeConfig cumulativeConfig) { + return l(locale, "pollen.error.vote.cumulative", cumulativeConfig.getPoints()); } } diff --git a/pollen-votecounting-percentage/src/main/java/org/chorem/pollen/votecounting/PercentageVoteCountingStrategy.java b/pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeVoteCountingStrategy.java similarity index 97% rename from pollen-votecounting-percentage/src/main/java/org/chorem/pollen/votecounting/PercentageVoteCountingStrategy.java rename to pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeVoteCountingStrategy.java index d503fd01..583629a6 100644 --- a/pollen-votecounting-percentage/src/main/java/org/chorem/pollen/votecounting/PercentageVoteCountingStrategy.java +++ b/pollen-votecounting-cumulative/src/main/java/org/chorem/pollen/votecounting/CumulativeVoteCountingStrategy.java @@ -36,7 +36,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class PercentageVoteCountingStrategy extends AbstractVoteCountingStrategy { +public class CumulativeVoteCountingStrategy extends AbstractVoteCountingStrategy<CumulativeConfig> { @Override public VoteCountingResult votecount(Set<Voter> voters) { diff --git a/pollen-votecounting-cumulative/src/main/resources/META-INF/services/org.chorem.pollen.votecounting.VoteCounting b/pollen-votecounting-cumulative/src/main/resources/META-INF/services/org.chorem.pollen.votecounting.VoteCounting new file mode 100644 index 00000000..afd5c887 --- /dev/null +++ b/pollen-votecounting-cumulative/src/main/resources/META-INF/services/org.chorem.pollen.votecounting.VoteCounting @@ -0,0 +1 @@ +org.chorem.pollen.votecounting.CumulativeVoteCounting diff --git a/pollen-votecounting-cumulative/src/main/resources/i18n/pollen-votecounting-cumulative_en_GB.properties b/pollen-votecounting-cumulative/src/main/resources/i18n/pollen-votecounting-cumulative_en_GB.properties new file mode 100644 index 00000000..00701bf7 --- /dev/null +++ b/pollen-votecounting-cumulative/src/main/resources/i18n/pollen-votecounting-cumulative_en_GB.properties @@ -0,0 +1,4 @@ +pollen.error.vote.cumulative=choices sum must be equals to %1$s +pollen.voteCountingType.cumulative=Cumulative +pollen.voteCountingType.cumulative.help=Each voter has a given number of points. He distributes this number of points freely between all choices. The choice of the most points wins.<br/>More about this method\: <a href\='http\://en.wikipedia.org/wiki/Cumulative_voting' target\='\#doc'>http\://en.wikipedia.org/wiki/Cumulative_voting</a> +pollen.voteCountingType.cumulative.shortHelp=Allocate your points between all choices. diff --git a/pollen-votecounting-cumulative/src/main/resources/i18n/pollen-votecounting-cumulative_fr_FR.properties b/pollen-votecounting-cumulative/src/main/resources/i18n/pollen-votecounting-cumulative_fr_FR.properties new file mode 100644 index 00000000..8c27e46f --- /dev/null +++ b/pollen-votecounting-cumulative/src/main/resources/i18n/pollen-votecounting-cumulative_fr_FR.properties @@ -0,0 +1,4 @@ +pollen.error.vote.cumulative=La somme de tout les choix doit être égale à %1$s +pollen.voteCountingType.cumulative=Cumulatif +pollen.voteCountingType.cumulative.help=Chaque votant possède un nombre de points donnés. Il distribue ce nombre de points librement entre tous les choix. Le choix récoltant le plus de points gagne. <br/>Pour en savoir plus \: <a href\='http\://fr.wikipedia.org/wiki/Vote_cumulatif' target\='\#doc'>http\://fr.wikipedia.org/wiki/Vote_cumulatif</a> +pollen.voteCountingType.cumulative.shortHelp=Répartir vos points entre tous les choix. diff --git a/pollen-votecounting-percentage/src/test/java/org/chorem/pollen/votecounting/PercentageVoteCountingStrategyTest.java b/pollen-votecounting-cumulative/src/test/java/org/chorem/pollen/votecounting/CumulativeVoteCountingStrategyTest.java similarity index 97% rename from pollen-votecounting-percentage/src/test/java/org/chorem/pollen/votecounting/PercentageVoteCountingStrategyTest.java rename to pollen-votecounting-cumulative/src/test/java/org/chorem/pollen/votecounting/CumulativeVoteCountingStrategyTest.java index bcb8856a..b6bb2fe9 100644 --- a/pollen-votecounting-percentage/src/test/java/org/chorem/pollen/votecounting/PercentageVoteCountingStrategyTest.java +++ b/pollen-votecounting-cumulative/src/test/java/org/chorem/pollen/votecounting/CumulativeVoteCountingStrategyTest.java @@ -39,12 +39,12 @@ import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests the {@link PercentageVoteCountingStrategy}. + * Tests the {@link CumulativeVoteCountingStrategy}. * * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class PercentageVoteCountingStrategyTest { +public class CumulativeVoteCountingStrategyTest { public static final String CHOICE_A = "a"; @@ -52,20 +52,22 @@ public class PercentageVoteCountingStrategyTest { public static final String CHOICE_C = "c"; - protected static VoteCounting voteCounting; + protected static CumulativeVoteCounting voteCounting; - protected VoteCountingStrategy strategy; + protected CumulativeVoteCountingStrategy strategy; @BeforeClass public static void beforeClass() throws Exception { VoteCountingFactory factory = new VoteCountingFactory(); - voteCounting = factory.getVoteCounting(PercentageVoteCounting.ID); + voteCounting = CumulativeVoteCounting.class.cast(factory.getVoteCounting(CumulativeVoteCounting.ID)); } @Before public void setUp() throws Exception { - strategy = voteCounting.newStrategy(); + CumulativeConfig config = new CumulativeConfig(); + config.setPoints(100); + strategy.setConfig(config); } @Test diff --git a/pollen-votecounting-percentage/src/test/java/org/chorem/pollen/votecounting/VoteCountingFactoryTest.java b/pollen-votecounting-cumulative/src/test/java/org/chorem/pollen/votecounting/VoteCountingFactoryTest.java similarity index 95% rename from pollen-votecounting-percentage/src/test/java/org/chorem/pollen/votecounting/VoteCountingFactoryTest.java rename to pollen-votecounting-cumulative/src/test/java/org/chorem/pollen/votecounting/VoteCountingFactoryTest.java index 423f6984..f247f2cc 100644 --- a/pollen-votecounting-percentage/src/test/java/org/chorem/pollen/votecounting/VoteCountingFactoryTest.java +++ b/pollen-votecounting-cumulative/src/test/java/org/chorem/pollen/votecounting/VoteCountingFactoryTest.java @@ -36,7 +36,7 @@ public class VoteCountingFactoryTest { VoteCountingFactory factory = new VoteCountingFactory(); VoteCounting voteCounting = - factory.getVoteCounting(PercentageVoteCounting.ID); + factory.getVoteCounting(CumulativeVoteCounting.ID); Assert.assertNotNull(voteCounting); } } diff --git a/pollen-votecounting-percentage/src/test/resources/log4j.properties b/pollen-votecounting-cumulative/src/test/resources/log4j.properties similarity index 100% rename from pollen-votecounting-percentage/src/test/resources/log4j.properties rename to pollen-votecounting-cumulative/src/test/resources/log4j.properties diff --git a/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCounting.java b/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCounting.java index 1fafc24c..111368cd 100644 --- a/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCounting.java +++ b/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCounting.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; */ import org.chorem.pollen.votecounting.model.ChoiceToVoteRenderType; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import java.util.Locale; @@ -34,21 +35,22 @@ import static org.nuiton.i18n.I18n.n; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public class InstantRunoffVoteCounting extends AbstractVoteCounting<InstantRunoffVoteCountingStrategy> { +public class InstantRunoffVoteCounting extends AbstractVoteCounting<InstantRunoffVoteCountingStrategy, EmptyVoteCountingConfig> { public static final int ID = 6; public InstantRunoffVoteCounting() { super(ID, - InstantRunoffVoteCountingStrategy.class, - n("pollen.voteCountingType.instantRunoff"), - n("pollen.voteCountingType.instantRunoff.shortHelp"), - n("pollen.voteCountingType.instantRunoff.help") + InstantRunoffVoteCountingStrategy.class, + EmptyVoteCountingConfig.class, + n("pollen.voteCountingType.instantRunoff"), + n("pollen.voteCountingType.instantRunoff.shortHelp"), + n("pollen.voteCountingType.instantRunoff.help") ); } @Override - public String getTotalVoteValueNotValidMessage(Locale locale) { + public String getTotalVoteValueNotValidMessage(Locale locale, EmptyVoteCountingConfig config) { // no validation on total value, so no message return null; } @@ -103,7 +105,7 @@ public class InstantRunoffVoteCounting extends AbstractVoteCounting<InstantRunof } @Override - public boolean isTotalVoteValueValid(Double totalValues) { + public boolean isTotalVoteValueValid(Double totalValues, EmptyVoteCountingConfig config) { // no validation on total value return true; } diff --git a/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategy.java b/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategy.java index 5bb19870..4d0900bb 100644 --- a/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategy.java +++ b/pollen-votecounting-instant-runoff/src/main/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategy.java @@ -24,6 +24,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.commons.collections4.CollectionUtils; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; import org.chorem.pollen.votecounting.model.Voter; @@ -42,7 +43,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class InstantRunoffVoteCountingStrategy extends AbstractVoteCountingStrategy { +public class InstantRunoffVoteCountingStrategy extends AbstractVoteCountingStrategy<EmptyVoteCountingConfig> { @Override public VoteCountingResult votecount(Set<Voter> voters) { diff --git a/pollen-votecounting-instant-runoff/src/test/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategyTest.java b/pollen-votecounting-instant-runoff/src/test/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategyTest.java index 8f3580d2..96b78afc 100644 --- a/pollen-votecounting-instant-runoff/src/test/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategyTest.java +++ b/pollen-votecounting-instant-runoff/src/test/java/org/chorem/pollen/votecounting/InstantRunoffVoteCountingStrategyTest.java @@ -21,6 +21,7 @@ package org.chorem.pollen.votecounting; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.EmptyVoteCountingConfig; import org.chorem.pollen.votecounting.model.SimpleVoterBuilder; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.Voter; @@ -51,19 +52,20 @@ public class InstantRunoffVoteCountingStrategyTest { public static final String CHOICE_D = "Ville D"; - protected static VoteCounting voteCounting; + protected static InstantRunoffVoteCounting voteCounting; - protected VoteCountingStrategy strategy; + protected InstantRunoffVoteCountingStrategy strategy; @BeforeClass public static void beforeClass() throws Exception { VoteCountingFactory factory = new VoteCountingFactory(); - voteCounting = factory.getVoteCounting(InstantRunoffVoteCounting.ID); + voteCounting = InstantRunoffVoteCounting.class.cast(factory.getVoteCounting(InstantRunoffVoteCounting.ID)); } @Before public void setUp() throws Exception { strategy = voteCounting.newStrategy(); + strategy.setConfig(new EmptyVoteCountingConfig()); } @Test diff --git a/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCounting.java b/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCounting.java index c69bc61e..e271e7b5 100644 --- a/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCounting.java +++ b/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCounting.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; */ import org.chorem.pollen.votecounting.model.ChoiceToVoteRenderType; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; import java.util.Locale; @@ -33,16 +34,17 @@ import static org.nuiton.i18n.I18n.n; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public class NormalVoteCounting extends AbstractVoteCounting<NormalVoteCountingStrategy> { +public class NormalVoteCounting extends AbstractVoteCounting<NormalVoteCountingStrategy, MaxChoicesNumberConfig> { public static final int ID = 1; public NormalVoteCounting() { super(ID, - NormalVoteCountingStrategy.class, - n("pollen.voteCountingType.normal"), - n("pollen.voteCountingType.normal.shortHelp"), - n("pollen.voteCountingType.normal.help") + NormalVoteCountingStrategy.class, + MaxChoicesNumberConfig.class, + n("pollen.voteCountingType.normal"), + n("pollen.voteCountingType.normal.shortHelp"), + n("pollen.voteCountingType.normal.help") ); } @@ -88,7 +90,7 @@ public class NormalVoteCounting extends AbstractVoteCounting<NormalVoteCountingS } @Override - public boolean isTotalVoteValueValid(Double totalValues) { + public boolean isTotalVoteValueValid(Double totalValues, MaxChoicesNumberConfig config) { // no validation on total value return true; } @@ -102,7 +104,7 @@ public class NormalVoteCounting extends AbstractVoteCounting<NormalVoteCountingS } @Override - public String getTotalVoteValueNotValidMessage(Locale locale) { + public String getTotalVoteValueNotValidMessage(Locale locale, MaxChoicesNumberConfig config) { // no validation on total values, so no message return null; } diff --git a/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategy.java b/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategy.java index 456e19c3..c65455ac 100644 --- a/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategy.java +++ b/pollen-votecounting-normal/src/main/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategy.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; import com.google.common.collect.Sets; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; import org.chorem.pollen.votecounting.model.Voter; @@ -38,7 +39,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class NormalVoteCountingStrategy extends AbstractVoteCountingStrategy { +public class NormalVoteCountingStrategy extends AbstractVoteCountingStrategy<MaxChoicesNumberConfig> { @Override public VoteCountingResult votecount(Set<Voter> voters) { diff --git a/pollen-votecounting-normal/src/test/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategyTest.java b/pollen-votecounting-normal/src/test/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategyTest.java index 918b1667..2650b970 100644 --- a/pollen-votecounting-normal/src/test/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategyTest.java +++ b/pollen-votecounting-normal/src/test/java/org/chorem/pollen/votecounting/NormalVoteCountingStrategyTest.java @@ -24,6 +24,7 @@ import com.google.common.collect.Sets; import org.chorem.pollen.votecounting.model.ChoiceScore; import org.chorem.pollen.votecounting.model.ListOfVoter; import org.chorem.pollen.votecounting.model.ListVoteCountingResult; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; import org.chorem.pollen.votecounting.model.SimpleVoter; import org.chorem.pollen.votecounting.model.SimpleVoterBuilder; import org.chorem.pollen.votecounting.model.VoteCountingResult; @@ -52,19 +53,20 @@ public class NormalVoteCountingStrategyTest { public static final String CHOICE_C = "c"; - protected static VoteCounting voteCounting; + protected static NormalVoteCounting voteCounting; - protected VoteCountingStrategy strategy; + protected NormalVoteCountingStrategy strategy; @BeforeClass public static void beforeClass() throws Exception { VoteCountingFactory factory = new VoteCountingFactory(); - voteCounting = factory.getVoteCounting(NormalVoteCounting.ID); + voteCounting = NormalVoteCounting.class.cast(factory.getVoteCounting(NormalVoteCounting.ID)); } @Before public void setUp() throws Exception { strategy = voteCounting.newStrategy(); + strategy.setConfig(new MaxChoicesNumberConfig()); } @Test diff --git a/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCounting.java b/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCounting.java index 1c9f5c8d..1aad2a1d 100644 --- a/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCounting.java +++ b/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCounting.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; */ import org.chorem.pollen.votecounting.model.ChoiceToVoteRenderType; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; import java.util.Locale; @@ -33,16 +34,17 @@ import static org.nuiton.i18n.I18n.n; * @author Tony Chemit - dev@tchemit.fr * @since 1.6 */ -public class NumberVoteCounting extends AbstractVoteCounting<NumberVoteCountingStrategy> { +public class NumberVoteCounting extends AbstractVoteCounting<NumberVoteCountingStrategy, MaxChoicesNumberConfig> { public static final int ID = 4; public NumberVoteCounting() { super(ID, - NumberVoteCountingStrategy.class, - n("pollen.voteCountingType.number"), - n("pollen.voteCountingType.number.shortHelp"), - n("pollen.voteCountingType.number.help") + NumberVoteCountingStrategy.class, + MaxChoicesNumberConfig.class, + n("pollen.voteCountingType.number"), + n("pollen.voteCountingType.number.shortHelp"), + n("pollen.voteCountingType.number.help") ); } @@ -88,13 +90,13 @@ public class NumberVoteCounting extends AbstractVoteCounting<NumberVoteCountingS } @Override - public boolean isTotalVoteValueValid(Double totalValues) { + public boolean isTotalVoteValueValid(Double totalValues, MaxChoicesNumberConfig config) { // no validation on total value return true; } @Override - public String getTotalVoteValueNotValidMessage(Locale locale) { + public String getTotalVoteValueNotValidMessage(Locale locale, MaxChoicesNumberConfig config) { // no validation on total values, so no message return null; } diff --git a/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategy.java b/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategy.java index 8b5deaf5..8108b0a9 100644 --- a/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategy.java +++ b/pollen-votecounting-number/src/main/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategy.java @@ -22,6 +22,7 @@ package org.chorem.pollen.votecounting; import com.google.common.collect.Sets; import org.chorem.pollen.votecounting.model.ChoiceScore; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; import org.chorem.pollen.votecounting.model.VoteCountingResult; import org.chorem.pollen.votecounting.model.VoteForChoice; import org.chorem.pollen.votecounting.model.Voter; @@ -35,7 +36,7 @@ import java.util.Set; * @author Tony Chemit - dev@tchemit.fr * @since 1.4.5 */ -public class NumberVoteCountingStrategy extends AbstractVoteCountingStrategy { +public class NumberVoteCountingStrategy extends AbstractVoteCountingStrategy<MaxChoicesNumberConfig> { @Override public VoteCountingResult votecount(Set<Voter> voters) { @@ -59,7 +60,11 @@ public class NumberVoteCountingStrategy extends AbstractVoteCountingStrategy { for (ChoiceScore choiceScore : voteCountingResult.getScores()) { - double score = choiceScore.getScoreValue().doubleValue(); + double score = 0; + if (choiceScore.getScoreValue() != null) { + score = choiceScore.getScoreValue().doubleValue(); + } + VoteForChoice voteForChoice = VoteForChoice.newVote( choiceScore.getChoiceId(), score); diff --git a/pollen-votecounting-number/src/test/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategyTest.java b/pollen-votecounting-number/src/test/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategyTest.java index 7706453a..4dc057a7 100644 --- a/pollen-votecounting-number/src/test/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategyTest.java +++ b/pollen-votecounting-number/src/test/java/org/chorem/pollen/votecounting/NumberVoteCountingStrategyTest.java @@ -24,6 +24,7 @@ import com.google.common.collect.Sets; import org.chorem.pollen.votecounting.model.ChoiceScore; import org.chorem.pollen.votecounting.model.ListOfVoter; import org.chorem.pollen.votecounting.model.ListVoteCountingResult; +import org.chorem.pollen.votecounting.model.MaxChoicesNumberConfig; import org.chorem.pollen.votecounting.model.SimpleVoter; import org.chorem.pollen.votecounting.model.SimpleVoterBuilder; import org.chorem.pollen.votecounting.model.VoteCountingResult; @@ -52,19 +53,21 @@ public class NumberVoteCountingStrategyTest { public static final String CHOICE_C = "c"; - protected static VoteCounting voteCounting; + protected static NumberVoteCounting voteCounting; + + protected NumberVoteCountingStrategy strategy; - protected VoteCountingStrategy strategy; @BeforeClass public static void beforeClass() throws Exception { VoteCountingFactory factory = new VoteCountingFactory(); - voteCounting = factory.getVoteCounting(NumberVoteCounting.ID); + voteCounting = NumberVoteCounting.class.cast(factory.getVoteCounting(NumberVoteCounting.ID)); } @Before public void setUp() throws Exception { strategy = voteCounting.newStrategy(); + strategy.setConfig(new MaxChoicesNumberConfig()); } @Test diff --git a/pollen-votecounting-percentage/src/main/resources/META-INF/services/org.chorem.pollen.votecounting.VoteCounting b/pollen-votecounting-percentage/src/main/resources/META-INF/services/org.chorem.pollen.votecounting.VoteCounting deleted file mode 100644 index 2b668e8a..00000000 --- a/pollen-votecounting-percentage/src/main/resources/META-INF/services/org.chorem.pollen.votecounting.VoteCounting +++ /dev/null @@ -1 +0,0 @@ -org.chorem.pollen.votecounting.PercentageVoteCounting diff --git a/pollen-votecounting-percentage/src/main/resources/i18n/pollen-votecounting-percentage_en_GB.properties b/pollen-votecounting-percentage/src/main/resources/i18n/pollen-votecounting-percentage_en_GB.properties deleted file mode 100644 index 0f239566..00000000 --- a/pollen-votecounting-percentage/src/main/resources/i18n/pollen-votecounting-percentage_en_GB.properties +++ /dev/null @@ -1,4 +0,0 @@ -pollen.error.vote.percentage=choices sum must be equals to 100% -pollen.voteCountingType.percentage=Percentage -pollen.voteCountingType.percentage.help=Allocate choices to get a 100% total. -pollen.voteCountingType.percentage.shortHelp=Allocate choices to get a 100% total. diff --git a/pollen-votecounting-percentage/src/main/resources/i18n/pollen-votecounting-percentage_fr_FR.properties b/pollen-votecounting-percentage/src/main/resources/i18n/pollen-votecounting-percentage_fr_FR.properties deleted file mode 100644 index a8bdf881..00000000 --- a/pollen-votecounting-percentage/src/main/resources/i18n/pollen-votecounting-percentage_fr_FR.properties +++ /dev/null @@ -1,4 +0,0 @@ -pollen.error.vote.percentage=La somme de tout les choix doit être égale à 100% -pollen.voteCountingType.percentage=Pourcentage -pollen.voteCountingType.percentage.help=Répartir les choix de manière à obtenir 100% au total. -pollen.voteCountingType.percentage.shortHelp=Répartir les choix de manière à obtenir 100% au total. -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.