branch develop updated (c594bd23 -> 70121878)
This is an automated email from the git hooks/post-receive script. New change to branch develop in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git from c594bd23 Merge tag '3.1.5' into develop new 70121878 refs #192 : Restreindre un sondage sur les emails des votants The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit 701218781f95a038d9c5dbf1adb0cec8220665a9 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Mon Jun 11 17:25:25 2018 +0200 refs #192 : Restreindre un sondage sur les emails des votants Summary of changes: .../chorem/pollen/persistence/entity/Polls.java | 4 + .../V3_2_0_3__add_parcicipants_Filters_in_poll.sql | 2 + .../V3_2_0_3__add_parcicipants_Filters_in_poll.sql | 2 + pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 30924 -> 31056 bytes .../org/chorem/pollen/services/bean/PollBean.java | 11 ++ .../pollen/services/service/PollService.java | 18 +++ .../services/service/security/SecurityService.java | 26 +++- pollen-ui-riot-js/src/main/web/i18n/en.json | 18 ++- pollen-ui-riot-js/src/main/web/i18n/fr.json | 18 ++- pollen-ui-riot-js/src/main/web/js/PollForm.js | 13 +- .../src/main/web/tag/poll/Settings.tag.html | 152 ++++++++++++++++----- .../src/main/web/tag/poll/Summary.tag.html | 18 ++- .../pollen-votecounting-condorcet_en_GB.properties | 2 +- .../pollen-votecounting-condorcet_fr_FR.properties | 2 +- 15 files changed, 233 insertions(+), 55 deletions(-) create mode 100644 pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_3__add_parcicipants_Filters_in_poll.sql create mode 100644 pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_3__add_parcicipants_Filters_in_poll.sql -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 701218781f95a038d9c5dbf1adb0cec8220665a9 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Mon Jun 11 17:25:25 2018 +0200 refs #192 : Restreindre un sondage sur les emails des votants --- .../chorem/pollen/persistence/entity/Polls.java | 4 + .../V3_2_0_3__add_parcicipants_Filters_in_poll.sql | 2 + .../V3_2_0_3__add_parcicipants_Filters_in_poll.sql | 2 + pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 30924 -> 31056 bytes .../org/chorem/pollen/services/bean/PollBean.java | 11 ++ .../pollen/services/service/PollService.java | 18 +++ .../services/service/security/SecurityService.java | 26 +++- pollen-ui-riot-js/src/main/web/i18n/en.json | 18 ++- pollen-ui-riot-js/src/main/web/i18n/fr.json | 18 ++- pollen-ui-riot-js/src/main/web/js/PollForm.js | 13 +- .../src/main/web/tag/poll/Settings.tag.html | 152 ++++++++++++++++----- .../src/main/web/tag/poll/Summary.tag.html | 18 ++- .../pollen-votecounting-condorcet_en_GB.properties | 2 +- .../pollen-votecounting-condorcet_fr_FR.properties | 2 +- 15 files changed, 233 insertions(+), 55 deletions(-) diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Polls.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Polls.java index 76b9c00a..460057a8 100644 --- a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Polls.java +++ b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/Polls.java @@ -40,6 +40,10 @@ public class Polls { return Objects.equals(PollType.RESTRICTED, poll.getPollType()); } + public static boolean isPollRegistered(Poll poll) { + return Objects.equals(PollType.REGISTERED, poll.getPollType()); + } + public static boolean isStarted(Poll poll, Date currentDate) { Date beginDate = poll.getBeginDate(); return beginDate == null || beginDate.before(currentDate); diff --git a/pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_3__add_parcicipants_Filters_in_poll.sql b/pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_3__add_parcicipants_Filters_in_poll.sql new file mode 100644 index 00000000..d4d5830b --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_3__add_parcicipants_Filters_in_poll.sql @@ -0,0 +1,2 @@ +-- add participant filter in Poll +alter table poll add emailAddressSuffixes LONGVARCHAR; diff --git a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_3__add_parcicipants_Filters_in_poll.sql b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_3__add_parcicipants_Filters_in_poll.sql new file mode 100644 index 00000000..83a4e9f8 --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_3__add_parcicipants_Filters_in_poll.sql @@ -0,0 +1,2 @@ +-- add participant filter in Poll +alter table poll add emailAddressSuffixes text; diff --git a/pollen-persistence/src/main/xmi/pollen.properties b/pollen-persistence/src/main/xmi/pollen.properties index 8001c99f..ff910a8e 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.2.0.2 +model.tagvalue.version=3.2.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 52b95159..419ff5bf 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-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 e117cac2..5cd77515 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 @@ -31,6 +31,7 @@ import org.chorem.pollen.persistence.entity.VoteVisibility; import org.chorem.pollen.votecounting.model.VoteCountingConfig; import java.util.Date; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -147,6 +148,8 @@ public class PollBean extends PollenBean<Poll> { protected VoteCountingConfig voteCountingConfig; + protected List<String> emailAddressSuffixes; + public String getPermission() { return permission; } @@ -493,4 +496,12 @@ public class PollBean extends PollenBean<Poll> { public void setInvalidEmails(Set<String> invalidEmails) { this.invalidEmails = invalidEmails; } + + public List<String> getEmailAddressSuffixes() { + return emailAddressSuffixes; + } + + public void setEmailAddressSuffixes(List<String> emailAddressSuffixes) { + this.emailAddressSuffixes = emailAddressSuffixes; + } } 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 97dc8ea2..6f20b476 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 @@ -22,8 +22,10 @@ package org.chorem.pollen.services.service; */ import com.google.common.base.Joiner; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.chorem.pollen.persistence.entity.Choice; import org.chorem.pollen.persistence.entity.ChoiceType; @@ -57,6 +59,7 @@ import java.util.Date; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import static org.nuiton.i18n.I18n.l; @@ -68,6 +71,8 @@ import static org.nuiton.i18n.I18n.l; */ public class PollService extends PollenServiceSupport { + public static String EMAIL_SUFFIX_SEPARATOR = ";"; + public PollBean toPollBean(Poll entity) { PollBean bean = new PollBean(); @@ -116,6 +121,10 @@ public class PollService extends PollenServiceSupport { bean.setNewChoiceNotification(entity.isNewChoiceNotification()); bean.setNotificationLocale(entity.getNotificationLocale()); bean.setVoteCountingConfig(getVoteCountingService().getVoteCountingConfig(entity)); + String emailAddressSuffixes = entity.getEmailAddressSuffixes(); + if (StringUtils.isNotBlank(emailAddressSuffixes)) { + bean.setEmailAddressSuffixes(Lists.newArrayList(emailAddressSuffixes.split(PollService.EMAIL_SUFFIX_SEPARATOR))); + } Date now = getNow(); if (Polls.isFinished(entity, now)) { @@ -572,6 +581,15 @@ public class PollService extends PollenServiceSupport { toSave.setBeginDate(poll.getBeginDate()); toSave.setEndDate(poll.getEndDate()); + String suffixes = null; + if (CollectionUtils.isNotEmpty(poll.getEmailAddressSuffixes())) { + suffixes = poll.getEmailAddressSuffixes().stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.joining(PollService.EMAIL_SUFFIX_SEPARATOR)); + + } + toSave.setEmailAddressSuffixes(suffixes); + if (toSave.getBeginDate() == null) { toSave.setBeginDate(getNow()); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java index 9748e54d..0a9903a9 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java @@ -39,6 +39,7 @@ import org.chorem.pollen.persistence.entity.PollenPrincipalTopiaDao; import org.chorem.pollen.persistence.entity.PollenToken; import org.chorem.pollen.persistence.entity.PollenTokenTopiaDao; import org.chorem.pollen.persistence.entity.PollenUser; +import org.chorem.pollen.persistence.entity.PollenUserEmailAddress; import org.chorem.pollen.persistence.entity.Polls; import org.chorem.pollen.persistence.entity.ResultVisibility; import org.chorem.pollen.persistence.entity.SessionToken; @@ -50,6 +51,7 @@ import org.chorem.pollen.services.PollenServiceContext; import org.chorem.pollen.services.PollenTechnicalException; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.bean.UsersRight; +import org.chorem.pollen.services.service.PollService; import org.chorem.pollen.services.service.PollenServiceSupport; import org.nuiton.topia.persistence.TopiaNoResultException; @@ -58,6 +60,7 @@ import java.util.Calendar; import java.util.Date; import java.util.Objects; import java.util.Set; +import java.util.stream.Stream; /** * TODO @@ -347,7 +350,8 @@ public class SecurityService extends PollenServiceSupport { return isAdmin() || Polls.isPollFree(poll) || matchPrincipal(poll.getCreator()) - || isInvited(poll); + || Polls.isPollRestricted(poll) && isInvited(poll) + || Polls.isPollRegistered(poll) && isRegisteredAndAccept(poll); } protected boolean isInvited(Poll poll) { @@ -363,6 +367,21 @@ public class SecurityService extends PollenServiceSupport { .exists(); } + protected boolean isRegisteredAndAccept(Poll poll) { + String suffixes = poll.getEmailAddressSuffixes(); + return getSecurityContext().isConnected() && (StringUtils.isBlank(suffixes) || + Stream.of(suffixes.split(PollService.EMAIL_SUFFIX_SEPARATOR)) + .anyMatch(this::isConnectedUserAcceptEmailSuffix) + ); + } + + protected boolean isConnectedUserAcceptEmailSuffix(String suffix) { + return getConnectedUser().getEmailAddresses().stream() + .filter(email -> email.getActivationToken() == null) // email Validate + .map(PollenUserEmailAddress::getEmailAddress) + .anyMatch(email -> email.endsWith(suffix)); + } + protected boolean hasVoted(Poll poll) { return (getSecurityContext().getMainPrincipal() != null && getVoteDao() @@ -423,7 +442,10 @@ public class SecurityService extends PollenServiceSupport { public boolean canAddVote(Poll poll) { return Polls.isRunning(poll, getNow()) - && (Polls.isPollFree(poll) || Polls.isPollRestricted(poll) && isInvited(poll) && !hasVoted(poll)); + && (Polls.isPollFree(poll) + || Polls.isPollRestricted(poll) && isInvited(poll) && !hasVoted(poll) + || Polls.isPollRegistered(poll) && isRegisteredAndAccept(poll) && !hasVoted(poll) + ); } public boolean canEdit(Poll poll) { 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 4880471c..f940cf6a 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/en.json +++ b/pollen-ui-riot-js/src/main/web/i18n/en.json @@ -37,6 +37,8 @@ "summary_membersNoInvited_one": "1 Invitation email has not been sent yet", "summary_sendInvitation": "Send invitation", "summary_sendInvitations": "Send {0} invitations", + "summary_registered_filter": "Only registered users whose email address verifies any of the following suffixes can vote", + "summary_registered_all": "Only registered users can vote", "summary_sendInvitations_success": "The {0} invitations are sent", "summary_sendInvitation_success": "The invitation is sent", "summary_closePoll": "Close poll", @@ -287,9 +289,19 @@ "poll_description_nameNotBlank": "Name nust be not blank", "poll_description_email": "Your email", "poll_description_emailPlaceHolder": "Enter your email", - "poll_settings_restricted": "Restricted poll ?", - "poll_settings_restricted_yes": "Only those invited to the next stage can vote. An email will be sent to them with a personal link.", - "poll_settings_restricted_no": "All people with the poll link can vote", + "poll_settings_pollType": "Poll opening", + "poll_settings_pollType_FREE": "Open to all", + "poll_settings_pollType_FREE_help": "Anyone with the poll link can vote.", + "poll_settings_pollType_RESTRICTED": "Restricted", + "poll_settings_pollType_RESTRICTED_help": "Only those invited to the next step can vote. An email will be sent to them with a personal link.", + "poll_settings_pollType_REGISTERED": "Registered uusers", + "poll_settings_pollType_REGISTERED_help": "Only registered users can vote.", + "poll_settings_pollType_REGISTERED_limitEmail": "Limit to certain email addresses", + "poll_settings_pollType_REGISTERED_suffix": "addresse suffix", + "poll_settings_pollType_REGISTERED_suffixPlaceHolder": "@pollen.cl", + "poll_settings_pollType_REGISTERED_suffix_remove": "Remove this suffix", + "poll_settings_pollType_REGISTERED_suffix_add": "Add", + "poll_settings_pollType_REGISTERED_suffix_add_title": "Add a email addresse suffix", "poll_settings_basic_usage": "For a basic poll, you can skip this step.", "poll_settings_use_basic_usage": "Use the default options", "poll_settings_basic_usage_detail": "Default Pollen offers you : ", 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 3353992d..86449fd5 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/fr.json +++ b/pollen-ui-riot-js/src/main/web/i18n/fr.json @@ -35,6 +35,8 @@ "summary_membersNoInvited_all": "Les mails d'invitations n'ont pas encore été envoyés", "summary_membersNoInvited_many": "{0} mails d'invitation n'ont pas encore été envoyés", "summary_membersNoInvited_one": "1 mails d'invitation n'a pas encore été envoyé", + "summary_registered_filter": "Seul les utilisateurs enregistrés et dont l'adresse électronique vérifie l'un des suffixes suivants peuvent voter", + "summary_registered_all": "Seul les utilisateurs enregistrés peuvent voter", "summary_sendInvitation": "Envoyer l'invitation", "summary_sendInvitations": "Envoyer les {0} invitations", "summary_sendInvitations_success": "Les {0} invitations sont envoyées", @@ -287,9 +289,19 @@ "poll_description_nameNotBlank": "Vote nom ne doit pas être blanc", "poll_description_email": "Votre adresse électronique", "poll_description_emailPlaceHolder": "Renseignez votre adresse électronique", - "poll_settings_restricted": "Sondage restreint ?", - "poll_settings_restricted_yes": "Seules les personnes invitées à l'etape suivante peuvent voter. Un courriel leur sera envoyé avec un lien personnel.", - "poll_settings_restricted_no": "Toutes les personnes ayant le lien du sondage peuvent voter.", + "poll_settings_pollType": "Ouverture du sondage", + "poll_settings_pollType_FREE": "Ouvert à tous", + "poll_settings_pollType_FREE_help": "Toutes les personnes ayant le lien du sondage peuvent voter.", + "poll_settings_pollType_RESTRICTED": "Restreint à une liste", + "poll_settings_pollType_RESTRICTED_help": "Seules les personnes invitées à l'etape suivante peuvent voter. Un courriel leur sera envoyé avec un lien personnel.", + "poll_settings_pollType_REGISTERED": "Utilisateurs enregistrés", + "poll_settings_pollType_REGISTERED_help": "Seules les utilisateurs enregistrés peuvent voter.", + "poll_settings_pollType_REGISTERED_limitEmail": "Limiter à certaines adresse électroniques", + "poll_settings_pollType_REGISTERED_suffix": "suffix de l'adresse", + "poll_settings_pollType_REGISTERED_suffixPlaceHolder": "@pollen.cl", + "poll_settings_pollType_REGISTERED_suffix_remove": "Supprimer le suffix", + "poll_settings_pollType_REGISTERED_suffix_add": "Ajouter", + "poll_settings_pollType_REGISTERED_suffix_add_title": "Ajouter un suffix d'adresse électronique", "poll_settings_basic_usage": "Options par défaut", "poll_settings_use_basic_usage": "Utiliser les options par défaut", "poll_settings_basic_usage_detail": "Par défaut Pollen vous propose : ", 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 52c38fb4..273546d5 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollForm.js +++ b/pollen-ui-riot-js/src/main/web/js/PollForm.js @@ -38,6 +38,7 @@ class PollForm { "options", "voters" ]; + this.types = ["FREE", "RESTRICTED", "REGISTERED"]; this.pollService = pollService; this.pageTracker = pageTracker; @@ -279,14 +280,12 @@ class PollForm { this.model.commentVisibility = "EVERYBODY"; } - togglePollType() { - if (this.model.pollType === "RESTRICTED") { - this.model.pollType = "FREE"; - } else { - this.model.pollType = "RESTRICTED"; + setPollType(type) { + if (this.types.indexOf(type) >= 0 && this.model.pollType !== type) { + this.model.pollType = type; + this._updateSteps(); + bus.trigger("pollStepsChange", this.steps); } - this._updateSteps(); - bus.trigger("pollStepsChange", this.steps); } _updateSteps() { 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 9f7c56c1..eace7e03 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 @@ -28,23 +28,73 @@ import "../voteCountingType/CumulativeConfig.tag.html"; import "../voteCountingType/MajorityJudgmentConfig.tag.html"; <Settings> - <div class="form-section" show={form.creation}> + <div class="form-section"> + <h4><i class="fa fa-users"></i> {_t.pollType}</h4> <div class="o-form-element"> - <Checkbox label="{_t.restricted}" - name="pollType" - ref="pollType" - i18nprefix="{i18nprefix}" - disabled={opts.form.hasVotes} - checkboxchecked={opts.form.model.pollType === "RESTRICTED"} - ontogglecheckbox={togglePollType}> - {checked ? _t.restricted_yes : _t.restricted_no} - </Checkbox> + <span class="c-input-group"> + <button each={type in form.types} + class="c-button c-button--brand {c-button--ghost-brand: form.model.pollType !== type, c-button--brand: form.model.pollType === type}" + onclick={pollTypeChange(type)} + title={_l("pollType_" + type)} + ref={"pollType_" + type} + disabled={form.hasVotes || form.model.closed} + type="button"> + {_l("pollType_" + type)} + </button> + </span> + <div class="help-selected"> + <i class="fa fa-info-circle" aria-hidden="true"></i> + {_l("pollType_" + form.model.pollType + "_help")} + </div> + </div> + <div class="settings-options {with-default: form.creation}" show={form.model.pollType === "REGISTERED"}> + <div class="o-form-element"> + <Checkbox label="{_t.pollType_REGISTERED_limitEmail}" + disabled={form.model.closed} + checkboxchecked={limitEmail} + ontogglecheckbox={toggleLimitEmail}/> + </div> + <div show={limitEmail}> + <div class="o-form-element" each={suffix, index in form.model.emailAddressSuffixes}> + <div class="c-input-group"> + <div class="o-field"> + <input ref="suffix" + type="text" + class="c-field" + required + title={_t.pollType_REGISTERED_suffix} + name="suffix" + value="{suffix}" + disabled={form.model.closed} + placeholder="{_t.pollType_REGISTERED_suffixPlaceHolder}"/> + </div> + <button class="c-button c-button--error" + onclick={removeSuffix(index)} + disabled={form.model.closed || form.model.emailAddressSuffixes.length === 1} + title={_t.pollType_REGISTERED_suffix_remove}> + <i class="fa fa-times"></i> + </button> + </div> + </div> + <div class="actions-right"> + <button class="c-button c-button--success" + onclick={addSuffix} + title={_t.pollType_REGISTERED_suffix_add_title} + disabled={form.model.closed} + type="button"> + <i class="fa fa-plus"></i> + {_t.pollType_REGISTERED_suffix_add} + </button> + </div> + </div> </div> + </div> + <div class="form-section" show={form.creation}> <h4><i class="fa fa-cogs"></i> {_t.basic_usage}</h4> <div class="o-form-element"> <Checkbox label="{_t.use_basic_usage}" - disabled={opts.form.model.closed} + disabled={form.model.closed} checkboxchecked={!showOptions} ontogglecheckbox={toggleShowOptions}/> </div> @@ -72,7 +122,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; </h4> <div class="o-form-element select-or-radio"> <fieldset class="o-fieldset choice-radio" - disabled={form.hasVotes || opts.form.model.closed}> + disabled={form.hasVotes || form.model.closed}> <legend class="o-fieldset__legend">{_t.voteCountingType}</legend> <label each={type in form.voteCountingTypes} class="c-field c-field--choice" @@ -91,7 +141,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; tabindex="1" ref="voteCountingType" value={form.model.voteCountingType} - disabled={form.hasVotes || opts.form.model.closed} + disabled={form.hasVotes || form.model.closed} onchange={voteCountingTypeChanged}> <option each={type in form.voteCountingTypes} value={type.id} @@ -113,7 +163,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; name="choiceAddAllowed" id="choiceAddAllowed" ref="addChoices" - disabled={form.hasVotes || opts.form.model.closed} + disabled={form.hasVotes || form.model.closed} checkboxchecked={form.model.choiceAddAllowed} ontogglecheckbox={toggleChoiceAddAllowed}/> </div> @@ -127,7 +177,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; name="beginChoiceDate" id="beginChoiceDate" datetime={form.model.beginChoiceDate} - disabled={form.hasVotes || opts.form.model.closed}/> + disabled={form.hasVotes || form.model.closed}/> </div> <div class="o-form-element"> <label class="c-label" for="endChoiceDate"> @@ -138,24 +188,24 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; name="endChoiceDate" id="endChoiceDate" datetime={form.model.endChoiceDate} - disabled={form.hasVotes || opts.form.model.closed}/> + disabled={form.hasVotes || form.model.closed}/> </div> </div> - <MaxChoicesNumberConfig if={opts.form.model.voteCountingType == 1 || opts.form.model.voteCountingType == 4} + <MaxChoicesNumberConfig if={form.model.voteCountingType == 1 || 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} + <BordaConfig if={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} + <CumulativeConfig if={form.model.voteCountingType == 2} ref="config" config={form.model.voteCountingConfig} disabled={form.hasVotes || form.model.closed}/> - <MajorityJudgmentConfig if={opts.form.model.voteCountingType == 8} + <MajorityJudgmentConfig if={form.model.voteCountingType == 8} ref="config" config={form.model.voteCountingConfig} disabled={form.hasVotes || form.model.closed}/> @@ -170,7 +220,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; name="votePeriod" id="votePeriod" ref="votePeriod" - disabled={opts.form.model.closed} + disabled={form.model.closed} checkboxchecked={form.model.votePeriod} ontogglecheckbox={toggleVotePeriod}/> </div> @@ -183,7 +233,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; tabindex="1" name="beginDate" id="beginDate" - disabled={form.hasVotes || opts.form.model.closed} + disabled={form.hasVotes || form.model.closed} datetime={form.model.beginDate}/> </div> <div class="o-form-element"> @@ -196,7 +246,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; id="endDate" datetime={form.model.endDate} min={refs.beginDate.value} - disabled={opts.form.model.closed} + disabled={form.model.closed} onchange="{onEndDateChanged}"/> </div> </div> @@ -207,7 +257,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; <select class="c-field c-field--label" tabindex="1" ref="voteVisibility" - disabled={form.hasVotes || opts.form.model.closed} + disabled={form.hasVotes || form.model.closed} value={form.model.voteVisibility}> <option value="ANONYMOUS">{_t.voteVisibility_anonymous}</option> <option value="CREATOR">{_t.voteVisibility_creator}</option> @@ -220,7 +270,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; name="anonymousVote" id="anonymousVote" ref="anonymousVote" - disabled={form.hasVotes || opts.form.model.closed} + disabled={form.hasVotes || form.model.closed} checkboxchecked={form.model.anonymousVoteAllowed} ontogglecheckbox={toggleAnonymousVote}/> </div> @@ -234,7 +284,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; <select class="c-field c-field--label" tabindex="1" ref="resultVisibility" - disabled={form.hasVotes || opts.form.model.closed} + disabled={form.hasVotes || form.model.closed} value={form.model.resultVisibility}> <option value="CREATOR">{_t.resultVisibility_creator}</option> <option value="VOTER">{_t.resultVisibility_voter}</option> @@ -246,7 +296,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; name="continuousResults" id="continuousResults" ref="continuousResults" - disabled={opts.form.model.closed} + disabled={form.model.closed} checkboxchecked={form.model.continuousResults} ontogglecheckbox={toggleContinuousResults}/> </div> @@ -263,7 +313,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; <select class="c-field c-field--label" tabindex="1" ref="commentVisibility" - disabled={form.hasVotes || opts.form.model.closed} + disabled={form.hasVotes || form.model.closed} value={form.model.commentVisibility}> <option value="CREATOR">{_t.commentVisibility_creator}</option> <option value="VOTER">{_t.commentVisibility_voter}</option> @@ -282,24 +332,24 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; <Checkbox label="{_t.voteNotification}" labelclass="c-field c-field--choice" ref="voteNotification" - disabled={!form.model.creatorEmail || opts.form.model.closed} + disabled={!form.model.creatorEmail || form.model.closed} checkboxchecked={form.model.voteNotification}/> <Checkbox label="{_t.commentNotification}" labelclass="c-field c-field--choice" ref="commentNotification" - disabled={!form.model.creatorEmail || opts.form.model.closed} + disabled={!form.model.creatorEmail || form.model.closed} checkboxchecked={form.model.commentNotification}/> <Checkbox label="{_t.newChoiceNotification}" labelclass="c-field c-field--choice" ref="newChoiceNotification" - disabled={!form.model.creatorEmail || opts.form.model.closed} + disabled={!form.model.creatorEmail || form.model.closed} checkboxchecked={form.model.newChoiceNotification}/> </fieldset> <div class="o-form-element"> <Checkbox label="{_t.notifyMeBeforePollEnds}" labelclass="c-field c-field--choice" i18nprefix="{i18nprefix}" - disabled={disableNotifyMeBeforePollEnds || opts.form.model.closed} + disabled={disableNotifyMeBeforePollEnds || form.model.closed} checkboxchecked={notifyMeBeforePollEnds} ontogglecheckbox={toggleNotifyMeBeforePollEnds}> <i class="fa fa-question-circle cursor-help warning" @@ -316,7 +366,7 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; ref="notifyMeHoursBeforePollEnds" value={form.model.notifyMeHoursBeforePollEnds} min="{notifyMeBeforePollEnds ? 1 : 0}" - disabled={opts.form.model.closed}> + disabled={form.model.closed}> </div> </div> </div> @@ -341,12 +391,13 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; 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; + this.limitEmail = this.form.model.emailAddressSuffixes && this.form.model.emailAddressSuffixes.length; this.on("mount", () => { this.refs["voteCountingType" + this.form.model.voteCountingType].checked = true; this.refs.voteCountingType.value = this.form.model.voteCountingType; this.updateVoteCountingTypeHelp(); - this.refs.pollType.focus(); + this.refs["pollType_" + this.form.model.pollType].focus(); }); this.toggleVoteCountingTypeHelp = () => { @@ -434,11 +485,29 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; this.update(); }; - this.togglePollType = () => { - this.opts.form.togglePollType(); + this.pollTypeChange = newType => () => { + this.form.setPollType(newType); this.update(); }; + this.toggleLimitEmail = () => { + this.limitEmail = !this.limitEmail; + if (this.limitEmail && !this.form.model.emailAddressSuffixes) { + this.form.model.emailAddressSuffixes = [""]; + } + this.update(); + }; + + this.removeSuffix = index => () => { + if (this.form.model.emailAddressSuffixes.length > 1) { + this.form.model.emailAddressSuffixes.splice(index, 1); + } + }; + + this.addSuffix = () => { + this.form.model.emailAddressSuffixes.push(""); + }; + this.submit = () => { if (!this.showOptions && this.form.creation) { @@ -470,6 +539,13 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; this.form.model.notifyMeHoursBeforePollEnds = 0; } } + if (this.form.model.pollType === "REGISTERED" && this.limitEmail) { + this.form.model.emailAddressSuffixes = + (Array.isArray(this.refs.suffix) ? this.refs.suffix : [this.refs.suffix]) + .map(suffixInput => suffixInput.value); + } else { + this.form.model.emailAddressSuffixes = null; + } }; this.listen("locale", () => { @@ -526,6 +602,10 @@ import "../voteCountingType/MajorityJudgmentConfig.tag.html"; padding: 0.5em 0; } + .o-form-element .c-input-group { + margin: 0.5em 0; + } + .settings-options .form-section { margin: 1.5em 0; } diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Summary.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Summary.tag.html index 01ae48a3..a933ad72 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Summary.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Summary.tag.html @@ -117,8 +117,20 @@ </div> </div> + <div if={opts.form.model.pollType === "REGISTERED"} class="summary-part"> + <h3>{_t.members}</h3> + <div> + {opts.form.model.emailAddressSuffixes && opts.form.model.emailAddressSuffixes.length ? _t.registered_filter : _t.registered_all} + <ul class="suffixes"> + <li each={suffix in opts.form.model.emailAddressSuffixes}> + *{suffix} + </li> + </ul> + </div> + </div> + <div class="summary-part"> - <a if={opts.form.model.pollType === "FREE"} + <a if={opts.form.model.pollType !== "RESTRICTED"} href="{voteUrl}" class="c-button c-button--info"> <i class="link fa fa-envelope-o"/> @@ -258,5 +270,9 @@ font-size: 1em; } + ul.suffixes { + margin-left: 2em; + } + </style> </Summary> diff --git a/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_en_GB.properties b/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_en_GB.properties index 6fd2e4da..06afd681 100644 --- a/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_en_GB.properties +++ b/pollen-votecounting-condorcet/src/main/resources/i18n/pollen-votecounting-condorcet_en_GB.properties @@ -1,5 +1,5 @@ pollen.voteCountingType.condorcet=Condorcet -pollen.voteCountingType.condorcet.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 winner is the choice which wins the most duels against the other choices.<br/>More about this method: <a href='http://en.wikipedia.org/wiki/Condorcet_method' target='#doc'>http://en.wikipedia.org/wiki/Condorcet_method</a> +pollen.voteCountingType.condorcet.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 winner is the choice which wins the most duels against the other choices.<br/>More about this method\: <a href\='http\://en.wikipedia.org/wiki/Condorcet_method' target\='\#doc'>http\://en.wikipedia.org/wiki/Condorcet_method</a> pollen.voteCountingType.condorcet.shortHelp=Rank choices by preference order from 1 to N (1\=favorite). pollen.voteCountingType.condorcet.voteValue.error.positive=The value %1$s must be positive. pollen.voteCountingType.condorcet.voteValue.error.required=The value is required. 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 b790dbb8..b748948c 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,5 +1,5 @@ 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 duels 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.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 duels 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é). pollen.voteCountingType.condorcet.voteValue.error.positive=La valeur du vote %1$s doit être positive. pollen.voteCountingType.condorcet.voteValue.error.required=La valeur du vote est obligatoire. -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
participants (1)
-
chorem.org scm