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 d059538c853bc6310979e0d4695408a6a885ff60 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Tue May 16 11:48:30 2017 +0200 gestion des participant d'un sondage --- .../org/chorem/pollen/rest/api/v1/PollApi.java | 8 +- .../chorem/pollen/rest/api/v1/VoterListApi.java | 37 ++-- pollen-rest-api/src/main/resources/mapping | 4 +- .../chorem/pollen/services/bean/PollenBean.java | 10 +- .../pollen/services/bean/PollenEntityId.java | 10 ++ .../chorem/pollen/services/bean/VoterListBean.java | 5 +- .../pollen/services/service/VoterListService.java | 39 +++-- pollen-ui-riot-js/src/main/web/i18n.json | 24 ++- pollen-ui-riot-js/src/main/web/js/PollForm.js | 22 ++- pollen-ui-riot-js/src/main/web/js/PollService.js | 4 +- .../src/main/web/js/VoterListService.js | 150 ++++++++++++++++ .../src/main/web/tag/poll/Voters.tag.html | 78 ++++++--- .../src/main/web/tag/voterList/VoterList.tag.html | 190 +++++++++++++++++++++ .../web/tag/voterList/VoterListMember.tag.html | 92 ++++++++++ 14 files changed, 607 insertions(+), 66 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java index 732839b..988304f 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java @@ -86,12 +86,14 @@ public class PollApi extends WebMotionController { public PollenEntityRef<Poll> createPoll(PollService pollService, PollBean poll, ChoiceBean[] choices, - List<VoterListBean> voterLists, - List<VoterListMemberBean> voterListMembers) throws InvalidFormException { + VoterListBean[] voterLists, + VoterListMemberBean[] voterListMembers) throws InvalidFormException { List<ChoiceBean> choiceList = Lists.newArrayList(choices); + List<VoterListBean> voterListList = Lists.newArrayList(voterLists); + List<VoterListMemberBean> voterListMemberList = Lists.newArrayList(voterListMembers); - return pollService.createPoll(poll, choiceList, voterLists, voterListMembers); + return pollService.createPoll(poll, choiceList, voterListList, voterListMemberList); } 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 cb2ef7c..a8e7181 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 @@ -35,7 +35,6 @@ import org.debux.webmotion.server.WebMotionController; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; /** * TODO @@ -57,9 +56,15 @@ public class VoterListApi extends WebMotionController { // // } - public List<VoterListBean> getVoterLists(VoterListService voterListService, PollenEntityId<Poll> pollId, PollenEntityId<VoterList> parentId) { + public VoterListBean getMainVoterList(VoterListService voterListService, PollenEntityId<Poll> pollId) { - return voterListService.getVoterLists(pollId.getEntityId(), parentId.getEntityId()); + return voterListService.getMainVoterList(pollId.getEntityId()); + + } + + public List<VoterListBean> getVoterLists(VoterListService voterListService, PollenEntityId<Poll> pollId, PollenEntityId<VoterList> voterListId) { + + return voterListService.getVoterLists(pollId.getEntityId(), voterListId.getEntityId()); } @@ -120,15 +125,25 @@ public class VoterListApi extends WebMotionController { } public void saveVoters(VoterListService voterListService, PollenEntityId<Poll> pollId, - List<VoterListBean> listsToSave, - List<VoterListMemberBean> membersToSave, - List<PollenEntityId<VoterList>> listIdsToDelete, - List<PollenEntityId<VoterListMember>> memberIdsToDelete) throws InvalidFormException { + VoterListBean[] listsToSave, + VoterListMemberBean[] membersToSave, + VoterListBean[] listsToDelete, + VoterListMemberBean[] membersToDelete) throws InvalidFormException { + List<String> listIds = Lists.newLinkedList(); + for (VoterListBean list : listsToDelete) { + listIds.add(list.getEntityId()); + } + + List<String> memberIds = Lists.newLinkedList(); + for (VoterListMemberBean member : membersToDelete) { + memberIds.add(member.getEntityId()); + } + voterListService.saveVoters(pollId.getEntityId(), - listsToSave, - membersToSave, - listIdsToDelete.stream().map(PollenEntityId::getEntityId).collect(Collectors.toList()), - memberIdsToDelete.stream().map(PollenEntityId::getEntityId).collect(Collectors.toList())); + Lists.newArrayList(listsToSave), + Lists.newArrayList(membersToSave), + listIds, + memberIds); } } diff --git a/pollen-rest-api/src/main/resources/mapping b/pollen-rest-api/src/main/resources/mapping index c1a63e2..6fee0d6 100644 --- a/pollen-rest-api/src/main/resources/mapping +++ b/pollen-rest-api/src/main/resources/mapping @@ -166,13 +166,15 @@ 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}/voterLists VoterListApi.getVoterLists +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}/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 diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenBean.java index 2f94f20..24779cf 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenBean.java @@ -49,13 +49,21 @@ public abstract class PollenBean<E extends TopiaEntity> { } public boolean isPersisted() { - return id != null && id.isNotEmpty(); + return id != null && id.isNotEmpty() && !id.isTemporaryId(); } public String getEntityId() { return id.getEntityId(); } + public PollenEntityId<E> getId() { + return id; + } + + public boolean isTemporaryId() { + return id.isTemporaryId(); + } + public void setEntityId(String id) { this.id.setEntityId(id); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenEntityId.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenEntityId.java index 6a7dfaa..7cad78e 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenEntityId.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollenEntityId.java @@ -37,6 +37,8 @@ import java.lang.reflect.Type; */ public class PollenEntityId<E extends TopiaEntity> { + public static final String TEMPORARY_ID_PREFIX = "TEMP"; + protected final Class<E> entityType; protected String entityId; @@ -67,6 +69,10 @@ public class PollenEntityId<E extends TopiaEntity> { this.entityType = entityType; } + public boolean isEmpty() { + return !isNotEmpty(); + } + public boolean isNotEmpty() { return StringUtils.isNotEmpty(reducedId) || StringUtils.isNotEmpty(entityId); } @@ -87,6 +93,10 @@ public class PollenEntityId<E extends TopiaEntity> { this.entityId = entityId; } + public boolean isTemporaryId() { + return reducedId != null && reducedId.startsWith(TEMPORARY_ID_PREFIX); + } + public void encode(TopiaIdFactory topiaIdFactory) { if (entityId != null) { diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java index 906c931..dc55075 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java @@ -48,8 +48,9 @@ public class VoterListBean extends PollenBean<VoterList> { setEntityId(entity.getTopiaId()); setName(entity.getName()); setWeight(entity.getWeight()); - setParentId(entity.getParent().getTopiaId()); - + if (entity.getParent() != null) { + setParentId(entity.getParent().getTopiaId()); + } } @Override 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 d09647b..2ced80e 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 @@ -31,6 +31,7 @@ import org.chorem.pollen.persistence.entity.PollenPrincipal; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.VoterList; import org.chorem.pollen.persistence.entity.VoterListMember; +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; @@ -53,8 +54,6 @@ import static org.nuiton.i18n.I18n.l; */ public class VoterListService extends PollenServiceSupport { - public static final String TEMP_ID_PREFIX = "TEMP-"; - // protected VoterListMemberBean emailToMember(String email) { // VoterListMemberBean member = new VoterListMemberBean(); // member.setEmail(email); @@ -573,16 +572,16 @@ public class VoterListService extends PollenServiceSupport { checkNotNull(listsToSave); checkNotNull(membersToSave); // verification des listes de voteurs - Map<String, Set<String>> listNameByParentId = Maps.newHashMap(); + Map<PollenEntityId<VoterList>, Set<String>> listNameByParentId = Maps.newHashMap(); for (VoterListBean voterList : listsToSave) { - Set<String> sisterNames = listNameByParentId.computeIfAbsent(voterList.getParentId().getEntityId(), parentId -> { - if (poll == null || parentId == null || parentId.startsWith(TEMP_ID_PREFIX)) { + Set<String> sisterNames = listNameByParentId.computeIfAbsent(voterList.getParentId(), parentId -> { + if (poll == null || parentId.isNotEmpty() || parentId.isTemporaryId()) { return Sets.newHashSet(); } else { - List<VoterList> existingVoterLists = getVoterLists0(poll, parentId); - return existingVoterLists.stream() + List<VoterList> existingVoterLists = getVoterLists0(poll, parentId.getEntityId()); + return existingVoterLists.stream() .map(VoterList::getName) .collect(Collectors.toSet()); } @@ -592,7 +591,7 @@ public class VoterListService extends PollenServiceSupport { if (voterList.getEntityId() != null) { - if (voterList.getEntityId().startsWith(TEMP_ID_PREFIX)) { + if (voterList.isTemporaryId()) { members = membersToSave.stream() .filter(member -> member.getVoterListId().getEntityId().equals(voterList.getEntityId())) @@ -625,7 +624,7 @@ public class VoterListService extends PollenServiceSupport { for (VoterListMemberBean voterListMember : membersToSave) { - if (voterListMember.getVoterListId().getEntityId() != null && !voterListMember.getVoterListId().getEntityId().startsWith(TEMP_ID_PREFIX)) { + if (voterListMember.getVoterListId().getEntityId() != null && !voterListMember.getVoterListId().isTemporaryId()) { Pair<Set<String>, Set<String>> brotherNamesEmails = listNamesEmailsByListId.computeIfAbsent(voterListMember.getVoterListId().getEntityId(), voterListId -> { List<VoterListMember> existingVoterListMembers = getVoterListMembers0(voterListId); @@ -665,21 +664,21 @@ public class VoterListService extends PollenServiceSupport { protected List<VoterListMember> createVoters(Poll poll, List<VoterListBean> listsToSave, List<VoterListMemberBean> membersToSave) { Map<String, VoterListBean> voterListBeanByTempId = listsToSave.stream() - .filter(list -> list.getEntityId() == null || list.getEntityId().startsWith(TEMP_ID_PREFIX)) + .filter(list -> list.getId().isEmpty() || list.isTemporaryId()) .collect(Collectors.toMap( - VoterListBean::getEntityId, + v -> v.getId().getReducedId(), Function.identity())); List<VoterListMember> newVoters = Lists.newLinkedList(); for (VoterListBean voterList : listsToSave) { - if (voterList.getEntityId() == null || voterList.getEntityId().startsWith(TEMP_ID_PREFIX)) { + if (voterList.getEntityId() == null || voterList.isTemporaryId()) { - String parentId = voterList.getParentId().getEntityId(); - if (parentId != null && parentId.startsWith(TEMP_ID_PREFIX)) { - parentId = voterListBeanByTempId.get(parentId).getEntityId(); - voterList.setParentId(parentId); + PollenEntityId<VoterList> parentId = voterList.getParentId(); + if (parentId.isNotEmpty() && parentId.isTemporaryId()) { + String parentIdString = voterListBeanByTempId.get(parentId.getReducedId()).getEntityId(); + voterList.setParentId(parentIdString); } voterList.setEntityId(null); @@ -694,10 +693,10 @@ public class VoterListService extends PollenServiceSupport { for (VoterListMemberBean voterListMember : membersToSave) { if (!voterListMember.isPersisted()) { - String voterListId = voterListMember.getVoterListId().getEntityId(); - if (voterListId == null || voterListId.startsWith(TEMP_ID_PREFIX)) { - voterListId = voterListBeanByTempId.get(voterListId).getEntityId(); - voterListMember.setVoterListId(voterListId); + PollenEntityId<VoterList> voterListId = voterListMember.getVoterListId(); + if (voterListId.isEmpty() || voterListId.isTemporaryId()) { + String voterListIdString = voterListBeanByTempId.get(voterListId.getReducedId()).getEntityId(); + voterListMember.setVoterListId(voterListIdString); } voterListMember.setEntityId(null); diff --git a/pollen-ui-riot-js/src/main/web/i18n.json b/pollen-ui-riot-js/src/main/web/i18n.json index 7685492..c1499fb 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -285,6 +285,7 @@ "poll_voters_freePoll": "Tout le monde peut voter (Sondage public)", "poll_voters_restrictedPoll": "Seul les invités peuvent voter (Sondage privé)", "poll_voters_restrictedPoll_withMe": "Je participe au sondage", + "poll_voters_restrictedPoll_participants": "Participants au sondage", "poll_voters_restrictedPoll_withGroup": "Organiser les invités dans des groupes", "poll_voters_invite": "Inviter des participants", "poll_voters_already_invite_label": "Participants déjà invités", @@ -396,7 +397,16 @@ "favoriteList_childList_delete": "Retirer la sous-liste", "favoriteList_childList_deleteMessage": "Retirer la sou-liste ?", "error_manager_403": "Erreur : Accès refusé", - "error_manager_500": "Erreur : Service indisponible" + "error_manager_500": "Erreur : Service indisponile", + "voterList_name": "Nom", + "voterList_weight": "Poids", + "voterList_addMember": "Ajouter un participant", + "voterList_addVoterList": "Ajouter une sous-liste", + "voterList_delete": "Supprimer la liste", + "voterList_member_name": "Nom", + "voterList_member_email": "Courriel", + "voterList_member_weight": "Poids", + "voterList_member_delete": "Supprimer le participant" }, "en": { "main_pollen_title": "Pollen - ", @@ -674,6 +684,7 @@ "poll_voters_freePoll": "Everybody can vote (Public poll)", "poll_voters_restrictedPoll": "Only invited people can vote (Private poll)", "poll_voters_restrictedPoll_withMe": "I also want to participate", + "poll_voters_restrictedPoll_participants": "Poll participants", "poll_voters_restrictedPoll_withGroup": "Organize participants in groups", "poll_voters_invite": "Invite people to vote", "poll_voters_already_invite_label": "Participants already invited", @@ -783,6 +794,15 @@ "favoriteList_childList_delete": "Remove sub-list", "favoriteList_childList_deleteMessage": "Remove sub-list ?", "error_manager_403": "Error: Forbidden access", - "error_manager_500": "Error: Service unavailable" + "error_manager_500": "Error: Service unavailable", + "voterList_name": "Name", + "voterList_weight": "Weight", + "voterList_addMember": "Add member", + "voterList_addVoterList": "Add sub-list", + "voterList_delete": "delete list", + "voterList_member_name": "Name", + "voterList_member_email": "Email", + "voterList_member_weight": "Weight", + "voterList_member_delete": "delete member" } } 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 d71d181..72d2201 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollForm.js +++ b/pollen-ui-riot-js/src/main/web/js/PollForm.js @@ -25,6 +25,7 @@ let voteCountingTypeService = require("./VoteCountingTypeService"); let choiceService = require("./ChoiceService"); let resourceService = require("./ResourceService"); let pollService = require("./PollService"); +let voterListService = require("./VoterListService"); let bus = require("./PollenBus"); class PollForm { @@ -62,6 +63,7 @@ class PollForm { return Promise.all([ pollService.getPoll(pollId, permission), choiceService.getChoices(pollId, permission), + voterListService.init(pollId, permission), this._loadVoteCountingTypes() ]).then(results => { Object.assign(this.model, results[0]); @@ -94,7 +96,12 @@ class PollForm { } } + voterListService.init(this).then(voterList => { + this.mainVoterList = voterList; + }); + this.step = 0; + return Promise.resolve(this); }); } @@ -118,6 +125,10 @@ class PollForm { this.model.participant = []; this.choices = [new Choice("TEXT")]; + voterListService.init(this).then(voterList => { + this.mainVoterList = voterList; + }); + this.isInit = true; this.step = 0; }); @@ -141,7 +152,7 @@ class PollForm { } }); return Promise.all(fileUploadPromises).then(() => { - return pollService.create(this.model, this.choices).then((result) => { + return pollService.create(this.model, this.choices, voterListService.getVoterLists(), voterListService.getVoterListMembers()).then((result) => { console.info("Poll created"); console.info(result); this.model.id = result.id; @@ -184,10 +195,15 @@ class PollForm { save() { - return Promise.all([ + let promises = [ pollService.save(this.model), this._saveChoices() - ]); + ]; + + if (this.model.pollType !== "FREE") { + promises.push(voterListService.save()); + } + return Promise.all(promises); } previousStep() { 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 90e836d..12bd3f9 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollService.js +++ b/pollen-ui-riot-js/src/main/web/js/PollService.js @@ -27,8 +27,8 @@ class PollService extends FetchService { return this.getWithParams("/v1/polls/new", {choiceType: choiceType}); } - create(poll, choices) { - return this.form("/v1/polls/create", {poll: poll, choices: choices}); + create(poll, choices, voterLists, voterListMembers) { + return this.form("/v1/polls/create", {poll: poll, choices: choices, voterLists: voterLists, voterListMembers: voterListMembers}); } save(poll) { diff --git a/pollen-ui-riot-js/src/main/web/js/VoterListService.js b/pollen-ui-riot-js/src/main/web/js/VoterListService.js new file mode 100644 index 0000000..6ee5738 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/js/VoterListService.js @@ -0,0 +1,150 @@ +let singleton = require("./Singleton"); +let FetchService = require("./FetchService"); + +class VoterListService extends FetchService { + + constructor() { + super(); + this.tempPrefix = "TEMP"; + this.tempId = 1; + this.voterListsById = {}; + this.voterListMembersById = {}; + this.voterListsToDelete = []; + this.voterListMembersToDelete = []; + } + + _newVoterList(parent) { + return { + id: this.tempPrefix + this.tempId++, + parentId: parent && parent.id, + subLists: [], + members: [], + weight: 1, + loadded: true + }; + } + + _newMember(voterList) { + return { + id: this.tempPrefix + this.tempId++, + voterListId: voterList.id, + weight: 1 + }; + } + + init(pollForm) { + this.tempId = 1; + this.voterListsById = {}; + this.voterListMembersById = {}; + this.voterListsToDelete = []; + this.voterListMembersToDelete = []; + this.pollForm = pollForm; + let mainVoterListPromise = Promise.resolve(); + if (this.pollForm.model && this.pollForm.model.id) { + mainVoterListPromise = this.getWithParams("/v1/polls/" + pollForm.model.id + "/mainVoterList", {permission: pollForm.model.permission}); + } + mainVoterListPromise = mainVoterListPromise.then(list => { + let mainList = list || this._newVoterList(); + this.voterListsById[mainList.id] = mainList; + return mainList; + }); + return mainVoterListPromise; + } + + loadList(voterList) { + let voterListPromise; + if (!voterList.loadded) { + voterListPromise = Promise.resolve([[], []]); + if (this.pollForm.model && this.pollForm.model.id && !voterList.subLists && !voterList.id.startsWith(this.tempPrefix)) { + voterListPromise = Promise.all([ + this.getWithParams("/v1/polls/" + this.pollForm.model.id + "/voterLists/" + voterList.id + "/lists", {permission: this.pollForm.model.permission}), + this.getWithParams("/v1/polls/" + this.pollForm.model.id + "/voterLists/" + voterList.id + "/members", {permission: this.pollForm.model.permission})]); + } + voterListPromise.then(result => { + voterList.subLists = result[0]; + voterList.members = result[1]; + voterList.subLists.forEach(list => {this.voterListsById[list.id] = list;}); + voterList.members.forEach(member => {this.voterListMembersById[member.id] = member;}); + voterList.loadded = true; + return voterList; + }); + } else { + voterListPromise = Promise.resolve(voterList); + } + return voterListPromise; + } + + addVoterList(parent) { + let voterList = this._newVoterList(parent); + parent.subLists.push(voterList); + this.voterListsById[voterList.id] = voterList; + } + + deleteVoterList(voterList) { + let parent = this.voterListsById[voterList.parentId]; + let index = parent.subLists.indexOf(voterList); + parent.subLists.splice(index, 1); + + if (!voterList.id.startsWith(this.tempPrefix)) { + this.voterListsToDelete.push(voterList); + } + } + + addMember(parent) { + let member = this._newMember(parent); + parent.members.push(member); + this.voterListMembersById[member.id] = member; + } + + deleteMember(member) { + let voterList = this.voterListsById[member.voterListId]; + let index = voterList.members.indexOf(member); + voterList.members.splice(index, 1); + + if (!member.id.startsWith(this.tempPrefix)) { + this.voterListMembersToDelete.push(member); + } + } + + getVoterLists() { + return Object.values(this.voterListsById).map(voterlist => { + return { + id: voterlist.id, + parentId: voterlist.parentId, + name: voterlist.name, + weight: voterlist.weight + }; + }); + } + + getVoterListMembers() { + return Object.values(this.voterListMembersById).map(voterlistmember => { + return { + id: voterlistmember.id, + voterListId: voterlistmember.voterListId, + name: voterlistmember.name, + email: voterlistmember.email, + weight: voterlistmember.weight}; + }); + } + + getVoterListIdsToDelete() { + return this.voterListsToDelete.map(voterList => voterList.id); + } + + getVoterListMemberIdsToDelete() { + return this.voterListMembersToDelete.map(member => member.id); + } + + save() { + return this.form("/v1/polls/" + this.pollForm.model.id + "/voterLists/save?permission=" + this.pollForm.model.permission, + { + listsToSave: this.getVoterLists(), + membersToSave: this.getVoterListMembers(), + listsToDelete: this.voterListsToDelete, + membersToDelete: this.voterListMembersToDelete + }); + } +} + +module.exports = singleton(VoterListService); diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Voters.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Voters.tag.html index e926411..56666c4 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Voters.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Voters.tag.html @@ -18,6 +18,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ + require("../voterList/VoterList.tag.html"); + <Voters> <div class="o-form-element"> <label class="c-label"> @@ -47,28 +49,38 @@ </label> </div> - <div class="o-form-element" if={form.model.alreadyParticipants && form.model.alreadyParticipants.length}> - <label class="c-label"> - {__.already_invite_label} - </label> - <div class="participants"> - <ul class="c-list"> - <li each={participant in form.model.alreadyParticipants} class="c-list__item"> - {participant} - </li> - </ul> + <div show={!votePrivate}> + <div class="o-form-element" if={form.model.alreadyParticipants && form.model.alreadyParticipants.length}> + <label class="c-label"> + {__.already_invite_label} + </label> + <div class="participants"> + <ul class="c-list"> + <li each={participant in form.model.alreadyParticipants} class="c-list__item"> + {participant} + </li> + </ul> + </div> </div> - </div> - <div class="o-form-element"> - <label class="c-label"> - {__.new_invite_label} + <div class="o-form-element"> + <label class="c-label"> + {__.new_invite_label} + </label> + <textarea class="c-field" + rows="5" + ref="participants" + name="participants" + value="{participants}"/> + </div> + </div> + <div class="form-section" show={votePrivate}> + <label class="section-title"> + {__.restrictedPoll_participants} </label> - <textarea class="c-field" - rows="5" - ref="participants" - name="participants" - value="{participants}"/> + <div class="section-content"> + <VoterList voter-list={this.form.mainVoterList} ref="mainVoterList"/> + </div> </div> <script type="es6"> @@ -83,10 +95,10 @@ this.submit = () => { this.form.model.pollType = this.refs.pollType.value; - this.form.model.withMe = this.refs.withMe.checked; if (this.refs.participants.value) { this.form.model.participants = (this.form.model.participants || []).concat(this.refs.participants.value.split(/\s+/)); } + this.refs.mainVoterList.submit(); }; </script> @@ -96,7 +108,30 @@ padding: .5em; } + .form-section { + display: flex; + flex-wrap: wrap; + } + + .form-section .section-title { + width : 100%; + } + .form-section .section-content { + width : 100%; + } + @media (min-width: 640px) { + + .form-section .section-title { + width : 25%; + text-align: right; + padding: 1.5em 5px 0 0; + } + .form-section .section-content { + width : 75%; + } + + .o-form-element .c-label:first-child { width: 25%; display: inline-block; @@ -106,7 +141,8 @@ padding-right: 5px; } - .o-form-element .c-field { + .o-form-element .c-field, + .o-form-element .participants { width: 75%; display: inline-block; } diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterList.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterList.tag.html new file mode 100644 index 0000000..2f986cd --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterList.tag.html @@ -0,0 +1,190 @@ +require("./VoterListMember.tag.html"); + +<VoterList> + <div class="voter-list-header"> + <div class="voter-list-icone" onclick={toggleExpand}> + <i class="fa fa-caret-{expand ? 'down' : 'right'}" aria-hidden="true"></i> + <i class="fa fa-users" aria-hidden="true"></i> + </div> + <div class="voter-list-form"> + <div class="voter-list-fields" + if={opts.voterList.parentId}> + <div class="c-input-group"> + <div class="o-field"> + <input class="c-field" + type="text" + name="name" + ref="name" + value={opts.voterList.name} + placeholder={__.name}> + </div> + <div class="o-field field-weight"> + <input class="c-field" + type="number" + name="weight" + ref="weight" + value={opts.voterList.weight} + placeholder={__.weight}> + </div> + </div> + </div> + <div class="voter-list-actions"> + <button class="c-button c-button--success" + type="button" + onclick={addMember} + title={__.addMember}> + <i class="fa fa-plus" aria-hidden="true"></i> + <i class="fa fa-user" aria-hidden="true"></i> + </button> + <button class="c-button c-button--success" + type="button" + onclick={addVoterList} + title={__.addVoterList}> + <i class="fa fa-plus" aria-hidden="true"></i> + <i class="fa fa-users" aria-hidden="true"></i> + </button> + + <button class="c-button c-button--error" + type="button" + show={opts.voterList.parentId} + onclick={delete} + title={__.delete}> + <i class="fa fa-times" aria-hidden="true"></i> + </button> + </div> + </div> + + </div> + <div class="voter-list-content" + show={expand}> + + <VoterList each={voterlist in opts.voterList.subLists} voter-list={voterlist} ref="voterLists"/> + <voterListmember each={member in opts.voterList.members} member={member} ref="voterListMembers"/> + + </div> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "voterList"); + let voterListService = require("../../js/VoterListService"); + + this.expand = false; + + this.toggleExpand = () => { + if (this.expand) { + this.expand = false; + } else { + this.expandWithAdd(false, false); + } + }; + + this.expandWithAdd = (addMember, addVoterList) => { + voterListService.loadList(this.opts.voterList).then(() => { + if (addMember) { + voterListService.addMember(this.opts.voterList); + } + if (addVoterList) { + voterListService.addVoterList(this.opts.voterList); + } + this.expand = true; + this.update(); + }); + }; + + this.addMember = () => { + this.expandWithAdd(true, false); + }; + + this.addVoterList = () => { + this.expandWithAdd(false, true); + }; + + this.delete = () => { + if (this.opts.voterList.parentId) { + voterListService.deleteVoterList(this.opts.voterList); + this.parent.update(); + } + }; + + this.submit = () => { + if (this.opts.voterList.parentId) { + this.opts.voterList.name = this.refs.name.value; + this.opts.voterList.weight = this.refs.weight.value; + } else { + this.opts.voterList.name = "main voters list"; + this.opts.voterList.weight = 1; + } + if (Array.isArray(this.refs.voterLists)) { + this.refs.voterLists.forEach(voterList => { + voterList.submit(); + }); + } else if (this.refs.voterLists) { + this.refs.voterLists.submit(); + } + + if (Array.isArray(this.refs.voterListMembers)) { + this.refs.voterListMembers.forEach(voterListMember => { + voterListMember.submit(); + }); + } else if (this.refs.voterListMembers) { + this.refs.voterListMembers.submit(); + } + }; + + </script> + + <style> + + voterlist { + display: block; + margin: 5px auto; + border-radius: 4px; + border: 1px solid #13a2ff; + box-shadow: 0 0 1px hsla(0,0%,7%,.6); + padding: 0 0.5em 0.5em 0.5em; + color: #13a2ff; + } + + .voter-list-header { + display: flex; + } + + .voter-list-icone { + display: flex; + margin: 0.8em 0 auto 0; + font-size: 1.2em; + } + + .voter-list-icone .fa { + margin-right: 5px; + } + + .voter-list-form { + flex-grow: 1; + display: flex; + justify-content: flex-end;; + flex-wrap: wrap; + } + + .voter-list-fields { + margin-top: 0.5em; + flex-grow: 1; + } + + .o-field.field-weight { + min-width: 90px; + flex-grow: 0; + } + + .voter-list-actions { + margin-top: 0.5em; + display: flex; + justify-content: flex-end; + } + + .voter-list-actions .c-button { + margin-left: 5px; + } + + </style> +</voterList> 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 new file mode 100644 index 0000000..ba772c4 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html @@ -0,0 +1,92 @@ +<VoterlistMember> + <div class="voter-list-member-icone"> + <i class="fa fa-user" aria-hidden="true"></i> + </div> + <div class="voter-list-member-fields"> + <div class="c-input-group"> + <div class="o-field"> + <input class="c-field" + type="text" + name="name" + ref="name" + value={opts.member.name} + placeholder={__.name}> + </div> + <div class="o-field"> + <input class="c-field" + type="email" + name="email" + ref="email" + value={opts.member.email} + placeholder={__.email}> + </div> + <div class="o-field field-weight"> + <input class="c-field" + type="number" + name="weight" + ref="weight" + value={opts.member.weight} + placeholder={__.weight}> + </div> + </div> + </div> + <div class="voter-list-member-actions"> + <button class="c-button c-button--error" + type="button" + onclick={delete} + title={__.delete}> + <i class="fa fa-times" aria-hidden="true"></i> + </button> + </div> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "voterList_member"); + let voterListService = require("../../js/VoterListService"); + + + this.delete = () => { + voterListService.deleteMember(this.opts.member); + this.parent.update(); + }; + + this.submit = () => { + this.opts.member.name = this.refs.name.value; + this.opts.member.email = this.refs.email.value; + this.opts.member.weight = this.refs.weight.value; + }; + + </script> + + <style> + + voterlistmember { + display: flex; + margin: 5px auto; + border-radius: 4px; + border: 1px solid #13a2ff; + box-shadow: 0 0 1px hsla(0,0%,7%,.6); + padding: 0.5em; + color: #13a2ff; + } + + .voter-list-member-icone { + margin: auto 5px auto 0; + font-size: 1.2em; + } + + .voter-list-member-fields { + flex-grow: 1; + } + + .o-field.field-weight { + min-width: 90px; + flex-grow: 0; + } + + .voter-list-member-actions { + margin-left: 5px; + } + + </style> +</VoterlistMember> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.