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 8bba608d74628b1bc8687c25da19b931a7441739 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Fri Jun 15 11:41:59 2018 +0200 refs #209 : Ajout de la liste d'emargement pour les sondage restreints --- .../chorem/pollen/rest/api/v1/VoterListApi.java | 26 ++++ pollen-services/pom.xml | 5 + .../org/chorem/pollen/services/bean/PollBean.java | 10 ++ .../pollen/services/bean/VoterListMemberBean.java | 10 ++ .../pollen/services/service/CommentService.java | 16 -- .../pollen/services/service/PollService.java | 3 + .../services/service/PollenServiceSupport.java | 18 +++ .../pollen/services/service/VoteService.java | 17 -- .../pollen/services/service/VoterListService.java | 77 +++++++++- .../service/security/PollenPermissions.java | 4 + .../services/service/security/SecurityService.java | 7 + .../i18n/pollen-services_en_GB.properties | 1 + .../i18n/pollen-services_fr_FR.properties | 1 + pollen-ui-riot-js/src/main/web/i18n/en.json | 4 + pollen-ui-riot-js/src/main/web/i18n/fr.json | 4 + pollen-ui-riot-js/src/main/web/js/Poll.js | 9 ++ pollen-ui-riot-js/src/main/web/js/PollService.js | 18 +++ pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 14 ++ .../src/main/web/tag/poll/Participants.tag.html | 171 +++++++++++++++++++++ .../src/main/web/tag/poll/Poll.tag.html | 31 ++-- pom.xml | 6 +- 21 files changed, 401 insertions(+), 51 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java index 2b132b12..50dd0a2a 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java @@ -26,13 +26,17 @@ import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.VoterList; import org.chorem.pollen.persistence.entity.VoterListMember; import org.chorem.pollen.rest.api.beans.VoterListSaveBean; +import org.chorem.pollen.services.bean.PaginationParameterBean; +import org.chorem.pollen.services.bean.PaginationResultBean; import org.chorem.pollen.services.bean.PollenEntityId; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.bean.VoterListBean; import org.chorem.pollen.services.bean.VoterListMemberBean; +import org.chorem.pollen.services.bean.export.ExportBean; import org.chorem.pollen.services.service.InvalidFormException; import org.chorem.pollen.services.service.VoterListService; +import javax.ws.rs.BeanParam; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -43,6 +47,7 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.util.List; import java.util.Set; @@ -150,6 +155,27 @@ public class VoterListApi { } + @Path("/polls/{pollId}/participants") + @GET + public PaginationResultBean<VoterListMemberBean> getMembers(@Context VoterListService voterListService, + @PathParam("pollId") PollenEntityId<Poll> pollId, + @BeanParam PaginationParameterBean paginationParameter) { + + return voterListService.getAllVoterListMembers(pollId.getEntityId(), paginationParameter); + + } + + @Path("/polls/{pollId}/participants/exports") + @GET + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response exportFavoriteLists(@Context VoterListService voterListService, + @PathParam("pollId") PollenEntityId<Poll> pollId) { + + ExportBean exportBean = voterListService.exportAllVoterListMembers(pollId.getEntityId()); + + return ApiUtils.exportBeanToResponse(exportBean); + } + @Path("/polls/{pollId}/voterLists/{voterListId}/members") @POST public VoterListMemberBean addMember(@Context VoterListService voterListService, diff --git a/pollen-services/pom.xml b/pollen-services/pom.xml index 30c9ff2d..374d9bd0 100644 --- a/pollen-services/pom.xml +++ b/pollen-services/pom.xml @@ -181,6 +181,11 @@ <artifactId>nuiton-config</artifactId> </dependency> + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-csv</artifactId> + </dependency> + <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> 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 5cd77515..6b8960d1 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 @@ -106,6 +106,8 @@ public class PollBean extends PollenBean<Poll> { protected boolean voteIsVisible; + protected boolean participantsIsVisible; + protected boolean canVote; protected long commentCount; @@ -318,6 +320,14 @@ public class PollBean extends PollenBean<Poll> { this.voteIsVisible = voteIsVisible; } + public boolean isParticipantsIsVisible() { + return participantsIsVisible; + } + + public void setParticipantsIsVisible(boolean participantsIsVisible) { + this.participantsIsVisible = participantsIsVisible; + } + public boolean isCanVote() { return canVote; } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java index 2a0d21f2..4d881f75 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java @@ -34,6 +34,8 @@ public class VoterListMemberBean extends PollenBean<VoterListMember> { protected String name; + protected String avatar; + protected String email; protected double weight; @@ -58,6 +60,14 @@ public class VoterListMemberBean extends PollenBean<VoterListMember> { this.name = name; } + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + public String getEmail() { return email; } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java index 11cad0ab..1a38cdb6 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/CommentService.java @@ -292,20 +292,4 @@ public class CommentService extends PollenServiceSupport { } - protected PaginationParameter getPaginationParameter(PaginationParameterBean paginationParameter) { - - if (paginationParameter == null) { - - paginationParameter = PaginationParameterBean.of( - 0, - PAGE_SIZE_DEFAULT, - Comment.PROPERTY_TOPIA_CREATE_DATE, - true); - - } - - return paginationParameter.toPaginationParameter(); - - } - } 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 6f20b476..aea55ec6 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 @@ -170,6 +170,9 @@ public class PollService extends PollenServiceSupport { bean.setResultIsVisible(resultIsVisible); + boolean canReadParticipants = isPermitted(PollenPermissions.readParticipants(entity)); + bean.setParticipantsIsVisible(canReadParticipants); + boolean canVote = isPermitted(PollenPermissions.addVote(entity)); bean.setCanVote(canVote); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java index 7862bf41..6eac8118 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenServiceSupport.java @@ -53,6 +53,7 @@ import org.chorem.pollen.persistence.entity.VoterListTopiaDao; import org.chorem.pollen.services.PollenService; import org.chorem.pollen.services.PollenServiceContext; import org.chorem.pollen.services.PollenUIContext; +import org.chorem.pollen.services.bean.PaginationParameterBean; import org.chorem.pollen.services.bean.PaginationResultBean; import org.chorem.pollen.services.bean.PollenBean; import org.chorem.pollen.services.bean.PollenBeans; @@ -67,6 +68,7 @@ import org.nuiton.topia.persistence.TopiaDao; import org.nuiton.topia.persistence.TopiaEntity; import org.nuiton.topia.persistence.TopiaIdFactory; import org.nuiton.util.StringUtil; +import org.nuiton.util.pagination.PaginationParameter; import org.nuiton.util.pagination.PaginationResult; import java.util.Collection; @@ -529,4 +531,20 @@ public abstract class PollenServiceSupport implements PollenService { token); } + protected PaginationParameter getPaginationParameter(PaginationParameterBean paginationParameter) { + + if (paginationParameter == null) { + + paginationParameter = PaginationParameterBean.of( + 0, + PAGE_SIZE_DEFAULT, + TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, + true); + + } + + return paginationParameter.toPaginationParameter(); + + } + } 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 5cac2fb8..852fe3ad 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 @@ -44,7 +44,6 @@ import org.chorem.pollen.services.bean.VoteToChoiceBean; import org.chorem.pollen.services.service.security.PollenPermissions; import org.chorem.pollen.votecounting.VoteCounting; import org.chorem.pollen.votecounting.model.VoteCountingConfig; -import org.nuiton.util.pagination.PaginationParameter; import org.nuiton.util.pagination.PaginationResult; import java.util.Collection; @@ -538,20 +537,4 @@ public class VoteService extends PollenServiceSupport { return getVoteDao().forPollEquals(poll).count(); } - - protected PaginationParameter getPaginationParameter(PaginationParameterBean paginationParameter) { - - if (paginationParameter == null) { - - paginationParameter = PaginationParameterBean.of( - 0, - PAGE_SIZE_DEFAULT, - Vote.PROPERTY_TOPIA_CREATE_DATE, - true); - - } - - return paginationParameter.toPaginationParameter(); - - } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java index cb870f25..17b1bdfa 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java @@ -21,6 +21,7 @@ package org.chorem.pollen.services.service; * #L% */ +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -32,12 +33,21 @@ import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.Vote; 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.PaginationParameterBean; +import org.chorem.pollen.services.bean.PaginationResultBean; import org.chorem.pollen.services.bean.PollenEntityId; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.bean.VoterListBean; import org.chorem.pollen.services.bean.VoterListMemberBean; +import org.chorem.pollen.services.bean.export.ExportBean; import org.chorem.pollen.services.service.security.PollenPermissions; +import org.nuiton.csv.Exporter; +import org.nuiton.csv.ExporterBuilder; +import org.nuiton.util.pagination.PaginationParameter; +import org.nuiton.util.pagination.PaginationResult; +import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -61,9 +71,13 @@ public class VoterListService extends PollenServiceSupport { VoterListMemberBean bean = new VoterListMemberBean(); bean.setEntityId(entity.getTopiaId()); - if (entity.getMember() != null) { - bean.setName(entity.getMember().getName()); - bean.setEmail(entity.getMember().getEmail()); + PollenPrincipal pollenPrincipal = entity.getMember(); + if (pollenPrincipal != null) { + bean.setName(pollenPrincipal.getName()); + bean.setEmail(pollenPrincipal.getEmail()); + if (pollenPrincipal.getPollenUser() != null && pollenPrincipal.getPollenUser().getAvatar() != null) { + bean.setAvatar(getPollenResourceService().getReduceIdByTopiaId(pollenPrincipal.getPollenUser().getAvatar().getTopiaId())); + } } bean.setWeight(entity.getWeight()); bean.getVoterListId().setEntityId(entity.getVoterList().getTopiaId()); @@ -71,7 +85,7 @@ public class VoterListService extends PollenServiceSupport { boolean voting = getVoteDao().forVoterListMemberContains(entity).exists(); bean.setVoting(voting); - bean.setInvalidEmail(entity.getMember().isInvalid()); + bean.setInvalidEmail(pollenPrincipal.isInvalid()); return bean; } @@ -216,6 +230,61 @@ public class VoterListService extends PollenServiceSupport { } + public PaginationResultBean<VoterListMemberBean> getAllVoterListMembers(String pollId, PaginationParameterBean paginationParameter) { + checkIsConnectedRequired(); + + checkNotNull(pollId); + Poll poll = getPollService().getPoll0(pollId); + checkPermission(PollenPermissions.readParticipants(poll)); + + PaginationParameter paginationParameter1 = + PaginationParameter.of(paginationParameter.getPageNumber(), + paginationParameter.getPageSize(), + "topiaEntity_." + VoterListMember.PROPERTY_MEMBER + "." + PollenPrincipal.PROPERTY_NAME, // FIXME pourquoi l'alias doit être ajouté ? + false); + PaginationResult<VoterListMember> result = getVoterListMemberDao() + .forProperties(VoterListMember.PROPERTY_VOTER_LIST + "." + VoterList.PROPERTY_POLL, poll) + .findPage(paginationParameter1); + + return toPaginationListBean(result, this::toVoterListMemberBean); + } + + public ExportBean exportAllVoterListMembers(String pollId) { + checkIsConnectedRequired(); + + checkNotNull(pollId); + Poll poll = getPollService().getPoll0(pollId); + checkPermission(PollenPermissions.readParticipants(poll)); + + List<VoterListMember> members = getVoterListMemberDao() + .forProperties(VoterListMember.PROPERTY_VOTER_LIST + "." + VoterList.PROPERTY_POLL, poll) + .setOrderByArguments(VoterListMember.PROPERTY_MEMBER + "." + PollenPrincipal.PROPERTY_NAME) + .findAll(); + + ImmutableList<VoterListMemberBean> memberBeans = toBeanList(members, this::toVoterListMemberBean); + + Exporter<VoterListMemberBean> beanExporter = new ExporterBuilder<VoterListMemberBean>() + .addColumn(PollenPrincipal.PROPERTY_NAME, VoterListMemberBean::getName) + .addColumn(PollenPrincipal.PROPERTY_EMAIL, VoterListMemberBean::getEmail) + .addColumn("voting", VoterListMemberBean::isVoting, b -> Boolean.toString(b)) + .build(); + + + ExportBean exportBean = new ExportBean(); + + try { + exportBean.setContent(beanExporter.toString(memberBeans)); + } catch (IOException e) { + throw new PollenTechnicalException("erron on export participants", e); + } + exportBean.setName(l(getLocale(), "pollen.export.voterListMember", poll.getTitle(), getNow())); + exportBean.setContentType("text/csv"); + + return exportBean; + } + + + public VoterListMemberBean getVoterListMember(String pollId, String voterListId, String memberId) { checkIsConnectedRequired(); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenPermissions.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenPermissions.java index 1fd62788..15f11a58 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenPermissions.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenPermissions.java @@ -47,6 +47,10 @@ public class PollenPermissions { return securityService -> securityService.canReadVotes(poll); } + public static PollenPermission readParticipants(Poll poll) { + return securityService -> securityService.canReadParticipants(poll); + } + public static PollenPermission read(Vote vote) { return securityService -> securityService.canRead(vote); } 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 58dc2de3..38f0e953 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 @@ -456,6 +456,13 @@ public class SecurityService extends PollenServiceSupport { || VoteVisibility.CREATOR.equals(poll.getVoteVisibility()) && isCreator(poll)); } + public boolean canReadParticipants(Poll poll) { + return Polls.isPollRestricted(poll) && canRead(poll) + && (VoteVisibility.ANONYMOUS.equals(poll.getVoteVisibility()) + || Polls.isFinished(poll, getNow()) + || !poll.isContinuousResults()); + } + public boolean canRead(Vote vote) { return matchPrincipal(vote.getVoter()) || canReadVotes(vote.getPoll()); diff --git a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties index dc059689..26ab4fbd 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties @@ -114,6 +114,7 @@ pollen.error.voterList.name.alreadyUsed=voterList name already used pollen.error.voterList.name.mandatory=voterList name cannot be empty pollen.error.voterList.weight.greaterThan0=voterList weight must be greater than 0 pollen.export.favoriteLists=favorite lists %s %tF.json +pollen.export.voterListMember=Voting List %1$s %2$TF %2$TH-%2$TM.csv pollen.service.feed.anonymous=Someone pollen.service.feed.choiceAdded.title=A choice has been added to the poll pollen.service.feed.commentAdded.title=A new comment has been published diff --git a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties index 95a8f648..e988b33b 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties @@ -114,6 +114,7 @@ pollen.error.voterList.name.alreadyUsed=Le nom de la liste de votant existe déj pollen.error.voterList.name.mandatory=Nom de la liste de votant est obligatoire pollen.error.voterList.weight.greaterThan0=Poid de la liste de votant doit être supérieur à 0 pollen.export.favoriteLists=Listes de votants %s %tF.json +pollen.export.voterListMember=Liste d'émargement %1$s %2$TF %2$TH-%2$TM.csv pollen.service.feed.anonymous=Quelqu'un pollen.service.feed.choiceAdded.title=Un choix a été ajouté au sondage pollen.service.feed.commentAdded.title=Un nouveau commentaire a été publié 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 f940cf6a..7b220644 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/en.json +++ b/pollen-ui-riot-js/src/main/web/i18n/en.json @@ -54,6 +54,7 @@ "poll_summaryTab": "Summary", "poll_settings": "Settings", "poll_tab_results": "Results", + "poll_tab_participant" : "Voting List", "poll_CLOSED": "Closed", "poll_ADDING_CHOICES": "Adding choices", "poll_VOTING": "Voting", @@ -183,6 +184,9 @@ "poll_votes_tooManyPoint": "There is {0} point distributed too much", "poll_votes_voteByClickAndDrop": "Vote by click and drop", "poll_votes_voteByInput": "Vote by entry", + "poll_participants_noParticipant": "Voting list is not available", + "poll_participants_download": "Download", + "poll_participants_download_title": "Download voting list", "polls_createdPolls": "My polls", "polls_assignPollToMe": "Link a poll to my account", "polls_assignPollToMe_title": "Link the poll", 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 86449fd5..0c3a0a3f 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/fr.json +++ b/pollen-ui-riot-js/src/main/web/i18n/fr.json @@ -54,6 +54,7 @@ "poll_summaryTab": "Résumé", "poll_settings": "Configuration", "poll_tab_results": "Résultats", + "poll_tab_participant" : "Liste d'émargement", "poll_CLOSED": "Fermé", "poll_ADDING_CHOICES": "Ajout de choix", "poll_VOTING": "Ouvert", @@ -183,6 +184,9 @@ "poll_votes_tooManyPoint": "Il y a {0} point distribué en trop", "poll_votes_voteByClickAndDrop": "Vote par cliquer/glisser", "poll_votes_voteByInput": "Vote par saisie", + "poll_participants_noParticipant": "Le liste d'émagement n'est pas diponible", + "poll_participants_download": "Télécharger", + "poll_participants_download_title": "Télécharger la liste d'émargement", "polls_createdPolls": "Mes sondages", "polls_assignPollToMe": "Attacher le sondage", "polls_assignPollToMe_title": "Attacher un sondage à mon compte", diff --git a/pollen-ui-riot-js/src/main/web/js/Poll.js b/pollen-ui-riot-js/src/main/web/js/Poll.js index a926373a..ca1e6bfb 100644 --- a/pollen-ui-riot-js/src/main/web/js/Poll.js +++ b/pollen-ui-riot-js/src/main/web/js/Poll.js @@ -149,6 +149,15 @@ class Poll { return Promise.reject("Init poll after load votes"); } + loadLazyParticipants(pagination) { + if (this._initPromise) { + return this._initPromise.then(() => { + return pollService.getParticipants(this.id, pagination, this.getPermission()); + }); + } + return Promise.reject("Init poll after load participants"); + } + loadForVotes() { if (this._initPromise) { return this._initPromise.then(() => { diff --git a/pollen-ui-riot-js/src/main/web/js/PollService.js b/pollen-ui-riot-js/src/main/web/js/PollService.js index 472edb1f..16cf67f1 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollService.js +++ b/pollen-ui-riot-js/src/main/web/js/PollService.js @@ -128,6 +128,24 @@ class PollService extends FetchService { let url = this._getUrlPrefix(pollId) + "/invalidEmails"; return this.get(url, {permission: permission}); } + + getParticipants(pollId, pagination, permission) { + let params = Object.assign({}, pagination); + if (permission) { + params.permission = permission; + } + let url = this._getUrlPrefix(pollId) + "/participants"; + return this.get(url, params); + } + + getVotes(pollId, pagination, permission) { + let params = Object.assign({}, pagination); + if (permission) { + params.permission = permission; + } + let url = this._getUrlPrefix(pollId); + return this.get(url, params); + } } export default singleton(PollService); diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html index 9cfd4e59..a83a98cd 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html @@ -131,6 +131,20 @@ import "./popup/ShowReportsModal.tag.html"; </Authorization> </route> + <route path="poll/*/participants"> + <Authorization connected-if-required="true"> + <Poll poll-id={routeArguments[0]} + tab-name="participants" /> + </Authorization> + </route> + <route path="poll/*/participants/*"> + <Authorization connected-if-required="true"> + <Poll poll-id={routeArguments[0]} + tab-name="participants" + permission={routeArguments[1]}/> + </Authorization> + </route> + <route path="poll/new/*"> <Authorization connected-if-required="true" promise={parent.parent.session.getCanCreatePollPromise()}> <PageChanged page="newPoll"/> diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Participants.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Participants.tag.html new file mode 100644 index 00000000..25b550e5 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Participants.tag.html @@ -0,0 +1,171 @@ +<!-- + #%L + Pollen :: UI RiotJs + %% + 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% + --> +<Participants> + <div class="container" show="{loaded}"> + <div if="{!poll.participantsIsVisible}" + class="c-alert c-alert--warning"> + {_t.noParticipant} + </div> + <div if="{poll.participantsIsVisible}" class="participants-body" > + <div class="actions-right"> + <a class="c-button c-button--info" + href="{parent.session.configuration.endPoint}/v1/polls/{poll.id}/participants/exports" + target="_blank" + title={_t.download_title}> + <i class="fa fa-download"></i> + {_t.download} + </a> + </div> + <LazyLoad pagination={pagination} onload={lazyLoad} load-size="20" ref="lazyLoad" class="elements"> + <yield to="element"> + <div class="participant"> + <div class="voting"> + <span class="fa-stack fa-lg"> + <i class="fa fa-square-o fa-stack-1x"></i> + <i show={element.voting} class="fa fa-check fa-stack-1x success"></i> + </span> + </div> + <div class="avatar"> + <Avatar avatar={element.avatar} name={element.name} rounded="true"/> + </div> + <div class="name-email"> + <div class="name"> + {element.name} + </div> + <div class="email"> + {element.email} + </div> + </div> + </div> + </yield> + <yield to="loading"> + <div class="participant"> + <div class="voting"></div> + <div class="avatar"> + <i class="fa fa-user-circle c-icon"></i> + </div> + <div class="name-email"> + <div class="name"> + <i class="fa fa-spinner fa-pulse"></i> + </div> + <div class="email"> + <i class="fa fa-spinner fa-pulse"></i> + </div> + </div> + </div> + </yield> + </LazyLoad> + </div> + </div> + + <script type="es6"> + import session from "../../js/Session"; + import poll from "../../js/Poll.js"; + + this.loaded = false; + this.installBundle(session, "poll_participants"); + + this.poll = poll; + + this.pagination = { + order: "member.name", + desc: true + }; + + this.lazyLoad = pagination => { + return this.poll.loadLazyParticipants(pagination).then((result) => { + this.loaded = true; + this.update(); + return result; + }); + }; + + this.onPollChange = poll2 => { + this.poll = poll2; + this.update(); + }; + + this.listen("poll", this.onPollChange); + + this.listen("user", (user, oldUser) => { + if (user !== oldUser && this.refs.lazyLoad) { + this.refs.lazyLoad.reload().then(() => { + this.update(); + }); + } + }); + + </script> + <style> + + .container { + display: flex; + justify-content: center; + } + + .participants-body { + /* width: 100% */ + } + + .participant { + display: flex; + align-items: center; + } + + .participant .voting { + width: 3em; + + } + + .participant .voting .fa-check { + left: 0.1em; + top: -0.1em; + font-size: 1.3em; + } + + .name-email { + display: flex; + justify-content: space-between; + flex-grow: 1; + } + + .participant .name, + .participant .email { + padding: 0 0.7em; + } + + .participant .avatar { + display: flex; + width: 2em; + height: 2em; + } + + .loading .participant .avatar { + font-size: 2em; + } + + .participant .avatar avatar { + width: 2em; + height: 2em; + } + + </style> +</Participants> diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html index 7e046150..2f2e733f 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html @@ -18,16 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #L% --> -import "./Votes.tag.html"; -import "./Comments.tag.html"; -import "./Results.tag.html"; -import "./Choices.tag.html"; -import "./Settings.tag.html"; -import "./CheckEmails.tag.html"; -import "../popup/QrCodeButton.tag.html"; -import "../components/MultiLineLabel.tag.html"; -import "../components/InnerHtml.tag.html"; -import "./Report.tag.html"; <Poll> <div class="main-container" ref="mainContainer"> @@ -60,6 +50,12 @@ import "./Report.tag.html"; <i class="fa fa-trophy fa-15x"></i> {_t.tab_results} </a> </div> + <div if="{poll.participantsIsVisible}" + class="tab {selected : selectedTab === 'participants'}"> + <a href="#poll/{poll.id}/participants{poll.getPermission()?'/' + poll.getPermission() : ''}"> + <i class="fa fa-list fa-15x"></i> {_t.tab_participant} + </a> + </div> </div> <div if="{poll.permission}" @@ -145,8 +141,8 @@ import "./Report.tag.html"; </div> <Votes if={selectedTab === "votes"}/> - <Results if={selectedTab === "results"}/> + <Participants if={selectedTab === "participants"}/> </div> @@ -154,6 +150,19 @@ import "./Report.tag.html"; </div> <script type="es6"> + import "./Votes.tag.html"; + import "./Comments.tag.html"; + import "./Results.tag.html"; + import "./Choices.tag.html"; + import "./Settings.tag.html"; + import "./CheckEmails.tag.html"; + import "../popup/QrCodeButton.tag.html"; + import "../components/MultiLineLabel.tag.html"; + import "../components/InnerHtml.tag.html"; + import "./Report.tag.html"; + import "./Participants.tag.html"; + + import session from "../../js/Session"; import Message from "../../js/Message"; import route from "riot-route/lib/tag"; diff --git a/pom.xml b/pom.xml index f2cec315..6ee64536 100644 --- a/pom.xml +++ b/pom.xml @@ -185,7 +185,7 @@ <nuitonWebVersion>1.20</nuitonWebVersion> <nuitonUtilsVersion>3.0</nuitonUtilsVersion> <nuitonConfigVersion>3.4</nuitonConfigVersion> - <nuitonCsvVersion>3.0-alpha-3</nuitonCsvVersion> + <nuitonCsvVersion>3.0-rc-6</nuitonCsvVersion> <nuitonValidatorVersion>3.2</nuitonValidatorVersion> <h2Version>1.4.197</h2Version> <postgresqlVersion>42.2.2.jre7</postgresqlVersion> @@ -430,11 +430,11 @@ <version>1.0-rc-2</version> </dependency> - <!--dependency> + <dependency> <groupId>org.nuiton</groupId> <artifactId>nuiton-csv</artifactId> <version>${nuitonCsvVersion}</version> - </dependency--> + </dependency> <!--dependency> <groupId>org.nuiton</groupId> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.