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 9330980a03ee10fec9c1ef1bb959fb2453b76255 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Wed May 24 16:44:07 2017 +0200 afficher quels participants ont votés et leur renvoyer des invitations (#51, #36 et #33) --- .../chorem/pollen/rest/api/v1/VoterListApi.java | 9 +++ pollen-rest-api/src/main/resources/mapping | 24 ++++--- .../org/chorem/pollen/services/bean/PollBean.java | 10 +++ .../pollen/services/bean/VoterListMemberBean.java | 10 +++ .../pollen/services/service/PollService.java | 6 +- .../pollen/services/service/VoterListService.java | 84 +++++++++++++++++++++- pollen-ui-riot-js/src/main/web/i18n.json | 14 ++++ .../src/main/web/js/VoterListService.js | 20 +++++- .../src/main/web/tag/poll/Poll.tag.html | 14 ++-- .../web/tag/voterList/VoterListActions.tag.html | 21 ++++++ .../web/tag/voterList/VoterListMember.tag.html | 17 ++++- 11 files changed, 201 insertions(+), 28 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 a8e7181..59a49d6 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 @@ -146,4 +146,13 @@ public class VoterListApi extends WebMotionController { memberIds); } + public int resendInvitationVoterList(VoterListService voterListService, PollenEntityId<Poll> pollId, PollenEntityId<VoterList> voterListId) { + return voterListService.resendInvitationVoterList(pollId.getEntityId(), voterListId.getEntityId()); + } + + public boolean resendInvitationMember(VoterListService voterListService, PollenEntityId<Poll> pollId, PollenEntityId<VoterList> voterListId, PollenEntityId<VoterListMember> memberId) { + return voterListService.resendInvitationMember(pollId.getEntityId(), voterListId.getEntityId(), memberId.getEntityId()); + } + + } diff --git a/pollen-rest-api/src/main/resources/mapping b/pollen-rest-api/src/main/resources/mapping index 14b9d81..32e4f20 100644 --- a/pollen-rest-api/src/main/resources/mapping +++ b/pollen-rest-api/src/main/resources/mapping @@ -167,20 +167,22 @@ GET /v1/voteCountingTypes/{id} VoteCountingTypeApi.getVoteCounti # PUT /v1/polls/{pollId}/favoriteLists/{favoriteListId} VoterListApi.importFavoriteListNewGroup # PUT /v1/polls/{pollId}/voterLists/{voterListId}/favoriteLists/{favoriteListId} VoterListApi.importFavoriteList -GET /v1/polls/{pollId}/mainVoterList VoterListApi.getMainVoterList -GET /v1/polls/{pollId}/voterLists/{voterListId} VoterListApi.getVoterList -POST /v1/polls/{pollId}/voterLists VoterListApi.createVoterList -POST /v1/polls/{pollId}/voterLists/save VoterListApi.saveVoters -PUT,POST /v1/polls/{pollId}/voterLists/{voterListId} VoterListApi.editVoterList -DELETE /v1/polls/{pollId}/voterLists/{voterListId} VoterListApi.deleteVoterList +GET /v1/polls/{pollId}/mainVoterList VoterListApi.getMainVoterList +GET /v1/polls/{pollId}/voterLists/{voterListId} VoterListApi.getVoterList +GET /v1/polls/{pollId}/voterLists/{voterListId}/resend VoterListApi.resendInvitationVoterList +POST /v1/polls/{pollId}/voterLists VoterListApi.createVoterList +POST /v1/polls/{pollId}/voterLists/save VoterListApi.saveVoters +PUT,POST /v1/polls/{pollId}/voterLists/{voterListId} VoterListApi.editVoterList +DELETE /v1/polls/{pollId}/voterLists/{voterListId} VoterListApi.deleteVoterList GET /v1/polls/{pollId}/voterLists/{voterListId}/lists VoterListApi.getVoterLists -GET /v1/polls/{pollId}/voterLists/{voterListId}/members VoterListApi.getMembers -GET /v1/polls/{pollId}/voterLists/{voterListId}/members/{memberId} VoterListApi.getMember -POST /v1/polls/{pollId}/voterLists/{voterListId}/members VoterListApi.addMember -PUT,POST /v1/polls/{pollId}/voterLists/{voterListId}/members/{memberId} VoterListApi.editMember -DELETE /v1/polls/{pollId}/voterLists/{voterListId}/members/{memberId} VoterListApi.deleteMember +GET /v1/polls/{pollId}/voterLists/{voterListId}/members VoterListApi.getMembers +GET /v1/polls/{pollId}/voterLists/{voterListId}/members/{memberId} VoterListApi.getMember +GET /v1/polls/{pollId}/voterLists/{voterListId}/members/{memberId}/resend VoterListApi.resendInvitationMember +POST /v1/polls/{pollId}/voterLists/{voterListId}/members VoterListApi.addMember +PUT,POST /v1/polls/{pollId}/voterLists/{voterListId}/members/{memberId} VoterListApi.editMember +DELETE /v1/polls/{pollId}/voterLists/{voterListId}/members/{memberId} VoterListApi.deleteMember # VoteApi 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 07f63c5..7c79574 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 @@ -122,6 +122,8 @@ public class PollBean extends PollenBean<Poll> { protected long voteCount; + protected long participantCount; + protected long choiceCount; protected PollStatus status; @@ -518,4 +520,12 @@ public class PollBean extends PollenBean<Poll> { public void setNotificationLocale(String notificationLocale) { this.notificationLocale = notificationLocale; } + + public long getParticipantCount() { + return participantCount; + } + + public void setParticipantCount(long participantCount) { + this.participantCount = participantCount; + } } 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 649de10..9ac026c 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 @@ -43,6 +43,8 @@ public class VoterListMemberBean extends PollenBean<VoterListMember> { protected PollenEntityId<VoterList> voterListId; + protected boolean voting; + public VoterListMemberBean() { super(VoterListMember.class); } @@ -112,4 +114,12 @@ public class VoterListMemberBean extends PollenBean<VoterListMember> { public void setVoterListId(String voterListId) { getVoterListId().setEntityId(voterListId); } + + public boolean isVoting() { + return voting; + } + + public void setVoting(boolean voting) { + this.voting = voting; + } } 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 2bd0066..d4039b2 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 @@ -94,8 +94,10 @@ public class PollService extends PollenServiceSupport { long commentCount = getCommentService().getCommentCount(input.getEntityId()); input.setCommentCount(commentCount); - long voteVount = getVoteService().getVoteCount(input.getEntityId()); - input.setVoteCount(voteVount); + long voteCount = getVoteService().getVoteCount(input.getEntityId()); + input.setVoteCount(voteCount); + long participantCount = getVoterListService().getVoterListMemberCount(input.getEntityId()); + input.setParticipantCount(participantCount); long choiceCount = getChoiceService().getChoiceCount(input.getEntityId()); input.setChoiceCount(choiceCount); 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 1936514..cd50111 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 @@ -29,6 +29,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.PollenPrincipal; 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.bean.PollenEntityId; @@ -37,6 +38,7 @@ import org.chorem.pollen.services.bean.VoterListBean; import org.chorem.pollen.services.bean.VoterListMemberBean; import org.chorem.pollen.services.service.security.PermissionVerb; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -134,6 +136,21 @@ public class VoterListService extends PollenServiceSupport { // // } + protected Function<VoterListMemberBean, VoterListMemberBean> getAddVotingField(String pollId) { + List<Vote> votes = getVoteDao().forProperties(Vote.PROPERTY_POLL + "." + Poll.PROPERTY_TOPIA_ID, pollId).findAll(); + + final Set<String> memberIdVoting = votes.stream() + .map(Vote::getVoterListMember) + .flatMap(Collection::stream) + .map(VoterListMember::getTopiaId) + .collect(Collectors.toSet()); + + return member -> { + member.setVoting(memberIdVoting.contains(member.getEntityId())); + return member; + }; + } + public List<VoterListBean> getVoterLists(String pollId, String parentId) { checkNotNull(pollId); @@ -233,7 +250,7 @@ public class VoterListService extends PollenServiceSupport { VoterList voterList = getVoterList0(pollId, voterListId); List<VoterListMember> members = getVoterListMembers0(voterList); - return toBeanSet(VoterListMemberBean.class, members); + return toBeanSet(VoterListMemberBean.class, members, getAddVotingField(pollId)); } @@ -247,7 +264,7 @@ public class VoterListService extends PollenServiceSupport { VoterList voterList = getVoterList0(pollId, voterListId); VoterListMember member = getVoterListMember0(voterList, memberId); - return toBean(VoterListMemberBean.class, member); + return toBean(VoterListMemberBean.class, member, getAddVotingField(pollId)); } @@ -278,7 +295,7 @@ public class VoterListService extends PollenServiceSupport { Collections.emptyList()); VoterListMember result = getVoterListMemberDao().forTopiaIdEquals(member.getEntityId()).findUnique(); - return toBean(VoterListMemberBean.class, result); + return toBean(VoterListMemberBean.class, result, getAddVotingField(pollId)); } @@ -734,4 +751,65 @@ public class VoterListService extends PollenServiceSupport { return newVoters; } + + public int resendInvitationVoterList(String pollId, String voterListId) { + + checkNotNull(pollId); + checkPermission(PermissionVerb.editPoll, pollId); + + Poll poll = getPollService().getPoll0(pollId); + + VoterList voterList = getVoterList0(poll, voterListId); + + List<VoterListMember> members = getVoterListDao().getAllMembers(voterList); + + return resendInvitation(poll, members); + } + + public boolean resendInvitationMember(String pollId, String voterListId, String memberId) { + checkNotNull(pollId); + checkPermission(PermissionVerb.editPoll, pollId); + + Poll poll = getPollService().getPoll0(pollId); + + VoterList voterList = getVoterList0(poll, voterListId); + + VoterListMember member = getVoterListMember0(voterList, memberId); + + return resendInvitation(poll, Collections.singletonList(member)) == 1; + } + + protected int resendInvitation(Poll poll, List<VoterListMember> members) { + List<Vote> votes = getVoteDao().forPollEquals(poll).findAll(); + + final Set<VoterListMember> memberVoting = votes.stream() + .map(Vote::getVoterListMember) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + List<VoterListMember> memberToSend = members.stream() + .filter(member -> !memberVoting.contains(member)) + .collect(Collectors.toList()); + + getNotificationService().onAddVoterList(poll, memberToSend); + + return memberToSend.size(); + } + + public long getVoterListMemberCount(String pollId) { + checkNotNull(pollId); + checkPermission(PermissionVerb.readPoll, pollId); + + VoterList voterList = getVoterListDao() + .forProperties(VoterList.PROPERTY_POLL + "." + Poll.PROPERTY_TOPIA_ID, pollId) + .addNull(VoterList.PROPERTY_PARENT) + .findUniqueOrNull(); + + List<VoterListMember> allMembers = getVoterListDao().getAllMembers(voterList); + + return allMembers.stream() + .map(VoterListMember::getMember) + .distinct() + .count(); + } } diff --git a/pollen-ui-riot-js/src/main/web/i18n.json b/pollen-ui-riot-js/src/main/web/i18n.json index 31a6a82..781e712 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -43,6 +43,7 @@ "poll_noVote": "aucun vote", "poll_vote": "vote", "poll_votes": "votes", + "poll_participants": "participants", "poll_closedFrom": "Fermé depuis le", "poll_urlForAdmin" : "Administrer ce sondage avec cette adresse", "poll_urlForVote" : "Inviter de nouveaux participants en leur envoyant cette adresse", @@ -410,11 +411,17 @@ "voterList_delete": "Supprimer la liste", "voterList_deleteMessage": "Supprimer la liste ?", "voterList_mainList": "Liste principale du sondage : ", + "voterList_resendInvitation": "Renvoyer une invitation aux participants de cette liste n'ayant pas votés", + "voterList_resendInvitation_success": "invitations sont envoyées", + "voterList_resendInvitation_one": "1 invitation est envoyée", + "voterList_resendInvitation_none": "Tout les participants de cette liste ont votés", "voterList_member_name": "Nom", "voterList_member_email": "Courriel", "voterList_member_weight": "Poids", "voterList_member_delete": "Supprimer le participant", "voterList_member_deleteMessage": "Supprimer le participant ?", + "voterList_member_resendInvitation": "Renvoyer une invitation", + "voterList_member_resendInvitation_success": "L'invitation est envoyée", "modal_cancel": "Annuler", "modal_ok": "Ok", "confirm_cancel": "Annuler", @@ -465,6 +472,7 @@ "poll_noVote": "no vote", "poll_vote": "vote", "poll_votes": "votes", + "poll_participants": "participants", "poll_closedFrom": "Closing from", "poll_urlForAdmin" : "Administrate poll with this address", "poll_urlForVote" : "Invited new participants with this address", @@ -818,6 +826,10 @@ "voterList_importFavoriteList": "Import favorite list", "voterList_importFavoriteList_none": "None favorite list saved", "voterList_mainList": "Poll main list : ", + "voterList_resendInvitation": "Resend an invitation to member of this list who not voting", + "voterList_resendInvitation_success": "invitations send", + "voterList_resendInvitation_one": "1 invitation send", + "voterList_resendInvitation_none": "All member of this liste has voting", "voterList_delete": "Delete list", "voterList_deleteMessage": "Delete list ?", "voterList_member_name": "Name", @@ -825,6 +837,8 @@ "voterList_member_weight": "Weight", "voterList_member_delete": "Delete member", "voterList_member_deleteMessage": "Delete member ?", + "voterList_member_resendInvitation": "Resent a invitation", + "voterList_member_resendInvitation_success": "invitation send", "modal_cancel": "Cancel", "modal_ok": "Ok", "confirm_cancel": "Cancel", diff --git a/pollen-ui-riot-js/src/main/web/js/VoterListService.js b/pollen-ui-riot-js/src/main/web/js/VoterListService.js index 8367d41..3e1ecfa 100644 --- a/pollen-ui-riot-js/src/main/web/js/VoterListService.js +++ b/pollen-ui-riot-js/src/main/web/js/VoterListService.js @@ -37,7 +37,8 @@ class VoterListService extends FetchService { voterListId: voterList.id, name: name, email: email, - weight: weight || 1 + weight: weight || 1, + temp: true }; } @@ -203,6 +204,23 @@ class VoterListService extends FetchService { })); return Promise.all(importPromises); } + + resendInvitationList(voterList) { + if (!voterList.temp) { + return this.getWithParams("/v1/polls/" + this.pollForm.model.id + "/voterLists/" + voterList.id + "/resend", {permission: this.pollForm.model.permission}); + } + return Promise.reject(); + } + + resendInvitationMember(member) { + if (!member.temp) { + return this.getWithParams("/v1/polls/" + this.pollForm.model.id + + "/voterLists/" + member.voterListId + + "/members/" + member.id + "/resend", + {permission: this.pollForm.model.permission}); + } + return Promise.reject(); + } } module.exports = singleton(VoterListService); 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 2199d01..137d91f 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 @@ -154,19 +154,13 @@ require("../popup/QrCodeButton.tag.html"); </div> <div class="poll-voting" - if={poll.status === "VOTING"}> + if={poll.status === "VOTING" || poll.status === "CLOSED"}> <span if={poll.voteCount === 0}>{__.noVote}</span> <span if={poll.voteCount === 1}>1 {__.vote}</span> <span if={poll.voteCount > 1}>{poll.voteCount} {__.votes}</span> - <span if={poll.endDate}> {__.votingTo} {formatDate(poll.endDate)}</span> - </div> - - <div class="poll-voting" - if={poll.status === "CLOSED"}> - <span if={poll.voteCount === 0}>{__.noVote}</span> - <span if={poll.voteCount === 1}>1 {__.vote}</span> - <span if={poll.voteCount > 1}>{poll.voteCount} {__.votes}</span> - <span if={poll.endDate}> {__.closedFrom} {formatDate(poll.endDate)}</span> + <span if={poll.pollType === "RESTRICTED"}>({poll.participantCount} {__.participants})</span> + <span if={poll.status === "VOTING" && poll.endDate}> {__.votingTo} {formatDate(poll.endDate)}</span> + <span if={poll.status === "CLOSED" && poll.endDate}> {__.closedFrom} {formatDate(poll.endDate)}</span> </div> </div> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListActions.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListActions.tag.html index 923d3f2..299c525 100644 --- a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListActions.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListActions.tag.html @@ -39,6 +39,15 @@ <i class="fa fa-users" aria-hidden="true"></i> </button> + <button class="c-button c-button--info" + type="button" + show={!opts.form.model.isClosed} + disabled={opts.form.model.isClosed} + onclick={resendInvitation} + title={__.resendInvitation}> + <i class="fa fa-paper-plane" aria-hidden="true"></i> + </button> + <button class="c-button c-button--error" type="button" show={opts.voterList.parentId && !opts.form.model.isClosed} @@ -138,6 +147,18 @@ }); } }; + + this.resendInvitation = () => { + voterListService.resendInvitationList(this.opts.voterList).then((result) => { + if (result <= 0) { + this.info(this.__.resendInvitation_none); + } else if (result === 1) { + this.info(this.__.resendInvitation_one); + } else { + this.info(result + " " + this.__.resendInvitation_success); + } + }); + }; </script> <style> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html index a072a30..9a77d39 100644 --- a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html @@ -1,6 +1,6 @@ <VoterlistMember> <div class="c-input-group"> - <div class="o-field o-field--icon-left "> + <div class="o-field o-field--icon-left o-field--icon-right"> <i class="fa fa-user c-icon" aria-hidden="true"></i> <input class="c-field" type="text" @@ -10,6 +10,7 @@ value={opts.member.name} required placeholder={__.name}> + <i class="fa fa-{opts.member.voting ? 'check-square-o' : 'square-o'} c-icon" aria-hidden="true"></i> </div> <div class="o-field"> <input class="c-field" @@ -32,6 +33,14 @@ required placeholder={__.weight}> </div> + <button class="c-button c-button--info" + type="button" + show={!opts.form.model.isClosed} + disabled={opts.member.voting || opts.form.model.isClosed} + onclick={resendInvitation} + title={__.resendInvitation}> + <i class="fa fa-paper-plane" aria-hidden="true"></i> + </button> <button class="c-button c-button--error" type="button" show={!opts.form.model.isClosed} @@ -57,6 +66,12 @@ }); }; + this.resendInvitation = () => { + voterListService.resendInvitationMember(this.opts.member).then((result) => { + this.info(result ? this.__.resendInvitation_success : this.__.resendInvitation_none); + }); + }; + this.submit = () => { this.opts.member.name = this.refs.name.value; this.opts.member.email = this.refs.email.value; -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.