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 d339bb58c602cbc6d823c3dca7005875a5c68441 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Thu Jun 8 16:36:58 2017 +0200 Import et Export des listes de votants (refs #62) --- .../entity/ChildFavoriteListTopiaDao.java | 32 --- .../chorem/pollen/rest/api/v1/FavoriteListApi.java | 19 ++ pollen-rest-api/src/main/resources/mapping | 2 + pollen-services/pom.xml | 5 + .../bean/export/ChildFavoriteListExport.java | 71 +++++ .../pollen/services/bean/export/ExportBean.java | 36 +++ .../services/bean/export/FavoriteListExport.java | 98 +++++++ .../bean/export/FavoriteListMemberExport.java | 94 +++++++ .../services/bean/export/FavoriteListsExport.java | 36 +++ .../services/service/FavoriteListService.java | 296 ++++++++++++++++++--- .../i18n/pollen-services_en_GB.properties | 21 +- .../i18n/pollen-services_fr_FR.properties | 21 +- pollen-ui-riot-js/src/main/web/i18n.json | 10 + .../src/main/web/js/FavoriteListService.js | 4 + .../web/tag/favoriteList/FavoriteLists.tag.html | 81 +++++- 15 files changed, 739 insertions(+), 87 deletions(-) diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/ChildFavoriteListTopiaDao.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/ChildFavoriteListTopiaDao.java deleted file mode 100644 index 3e7d9fa1..00000000 --- a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/ChildFavoriteListTopiaDao.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.chorem.pollen.persistence.entity; - - -import java.util.List; - -public class ChildFavoriteListTopiaDao extends AbstractChildFavoriteListTopiaDao<ChildFavoriteList> { - - public boolean isAncestorOrSelf(String ancestorFavoriteListId, String favoriteListId) { - - boolean result = ancestorFavoriteListId.equals(favoriteListId); - - if (! result) { - - List<ChildFavoriteList> childrenFavoriteList = forProperties(ChildFavoriteList.PROPERTY_CHILD + "." + FavoriteList.PROPERTY_TOPIA_ID, favoriteListId).findAll(); - - for (ChildFavoriteList childFavoriteList : childrenFavoriteList) { - - result = result || isAncestorOrSelf(ancestorFavoriteListId, childFavoriteList.getParent().getTopiaId()); - - if (result) { - break; - } - - } - } - - return result; - - } - - -} //ChildFavoriteListTopiaDao diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/FavoriteListApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/FavoriteListApi.java index f1b602b6..c23e9335 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/FavoriteListApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/FavoriteListApi.java @@ -21,6 +21,8 @@ package org.chorem.pollen.rest.api.v1; * #L% */ +import com.google.common.base.Charsets; +import org.apache.commons.io.IOUtils; import org.chorem.pollen.persistence.entity.ChildFavoriteList; import org.chorem.pollen.persistence.entity.FavoriteList; import org.chorem.pollen.persistence.entity.FavoriteListMember; @@ -32,11 +34,15 @@ 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.export.ExportBean; import org.chorem.pollen.services.service.FavoriteListImportException; import org.chorem.pollen.services.service.FavoriteListService; import org.chorem.pollen.services.service.InvalidFormException; import org.debux.webmotion.server.WebMotionController; import org.debux.webmotion.server.call.UploadFile; +import org.debux.webmotion.server.render.Render; + +import java.io.InputStream; /** * TODO @@ -58,6 +64,19 @@ public class FavoriteListApi extends WebMotionController { } + public int importFavoriteLists(FavoriteListService favoriteListService, UploadFile importFile) throws InvalidFormException { + return favoriteListService.importFavoriteLists(importFile.getFile()); + } + + public Render exportFavoriteLists(FavoriteListService favoriteListService) { + + ExportBean exportBean = favoriteListService.exportFavoriteLists(); + + InputStream inputStream = IOUtils.toInputStream(exportBean.getContent(), Charsets.UTF_8); + + return renderDownload(inputStream, exportBean.getName(), exportBean.getContentType()); + } + public PollenEntityRef<FavoriteList> createFavoriteList(FavoriteListService favoriteListService, FavoriteListBean favoriteList) throws InvalidFormException { return favoriteListService.createFavoriteList(favoriteList); diff --git a/pollen-rest-api/src/main/resources/mapping b/pollen-rest-api/src/main/resources/mapping index 96658bae..2d1c78cc 100644 --- a/pollen-rest-api/src/main/resources/mapping +++ b/pollen-rest-api/src/main/resources/mapping @@ -82,6 +82,8 @@ DELETE /v1/polls/{pollId}/comments/{commentId} CommentApi.deleteComment # FavoriteListApi GET /v1/favoriteLists FavoriteListApi.getFavoriteLists +GET /v1/favoriteLists/exports FavoriteListApi.exportFavoriteLists +POST /v1/favoriteLists/imports FavoriteListApi.importFavoriteLists GET /v1/favoriteLists/{favoriteListId} FavoriteListApi.getFavoriteList POST /v1/favoriteLists/{favoriteListId}/importCsv FavoriteListApi.importFavoriteListMembersFromCsv POST /v1/favoriteLists/{favoriteListId}/importLdap FavoriteListApi.importFavoriteListMembersFromLdap diff --git a/pollen-services/pom.xml b/pollen-services/pom.xml index 49951934..5c78a99f 100644 --- a/pollen-services/pom.xml +++ b/pollen-services/pom.xml @@ -128,6 +128,11 @@ </dependency> <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + + <dependency> <groupId>com.rometools</groupId> <artifactId>rome</artifactId> </dependency> diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/ChildFavoriteListExport.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/ChildFavoriteListExport.java new file mode 100644 index 00000000..61a277fb --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/ChildFavoriteListExport.java @@ -0,0 +1,71 @@ +package org.chorem.pollen.services.bean.export; + +import org.chorem.pollen.persistence.entity.ChildFavoriteList; +import org.chorem.pollen.persistence.entity.ChildFavoriteListImpl; +import org.chorem.pollen.persistence.entity.FavoriteList; +import org.chorem.pollen.services.bean.ChildFavoriteListBean; +import org.chorem.pollen.services.bean.FavoriteListBean; + +import java.util.List; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class ChildFavoriteListExport { + + protected String child; + + protected double weight; + + public static ChildFavoriteListExport fromEntity(ChildFavoriteList entity) { + ChildFavoriteListExport export = new ChildFavoriteListExport(); + + export.setChild(entity.getChild().getName()); + export.setWeight(entity.getWeight()); + + return export; + } + + public String getChild() { + return child; + } + + public void setChild(String child) { + this.child = child; + } + + public double getWeight() { + return weight; + } + + public void setWeight(double weight) { + this.weight = weight; + } + + public ChildFavoriteList toEntity(FavoriteList parent, List<FavoriteList> existingFavoriteLists) { + ChildFavoriteList entity = new ChildFavoriteListImpl(); + entity.setWeight(getWeight()); + entity.setParent(parent); + entity.setChild(existingFavoriteLists.stream() + .filter(favoriteList -> getChild().equals(favoriteList.getName())) + .findFirst() + .orElse(null)); + + return entity; + + } + + public ChildFavoriteListBean toBean(List<FavoriteList> existingFavoriteLists) { + ChildFavoriteListBean bean = new ChildFavoriteListBean(); + bean.setWeight(getWeight()); + FavoriteList childEntity = existingFavoriteLists.stream() + .filter(favoriteList -> getChild().equals(favoriteList.getName())) + .findFirst() + .orElse(null); + FavoriteListBean childBean = new FavoriteListBean(); + childBean.fromEntity(childEntity); + bean.setChild(childBean); + + return bean; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/ExportBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/ExportBean.java new file mode 100644 index 00000000..1ee539c5 --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/ExportBean.java @@ -0,0 +1,36 @@ +package org.chorem.pollen.services.bean.export; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class ExportBean { + + protected String content; + + protected String contentType; + private String name; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListExport.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListExport.java new file mode 100644 index 00000000..a173c3fd --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListExport.java @@ -0,0 +1,98 @@ +package org.chorem.pollen.services.bean.export; + +/* + * #%L + * Pollen :: Service + * %% + * Copyright (C) 2009 - 2017 Code Lutin, Tony Chemit + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import com.google.common.collect.Lists; +import org.chorem.pollen.persistence.entity.FavoriteList; +import org.chorem.pollen.persistence.entity.FavoriteListImpl; +import org.chorem.pollen.services.bean.FavoriteListBean; + +import java.util.List; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class FavoriteListExport { + + protected String name; + + protected List<ChildFavoriteListExport> children; + + protected List<FavoriteListMemberExport> members; + + public static FavoriteListExport fromEntity(FavoriteList entity) { + FavoriteListExport export = new FavoriteListExport(); + + export.setName(entity.getName()); + + return export; + } + + public FavoriteList toEntity() { + + FavoriteList entity = new FavoriteListImpl(); + entity.setName(getName()); + + return entity; + + } + + public FavoriteListBean toBean() { + + FavoriteListBean bean = new FavoriteListBean(); + bean.setName(getName()); + + return bean; + + } + + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } + + public List<ChildFavoriteListExport> getChildren() { + if (children == null) { + children = Lists.newLinkedList(); + } + return children; + } + + public void setChildren(List<ChildFavoriteListExport> children) { + this.children = children; + } + + public List<FavoriteListMemberExport> getMembers() { + if (members == null) { + members = Lists.newLinkedList(); + } + return members; + } + + public void setMembers(List<FavoriteListMemberExport> members) { + this.members = members; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListMemberExport.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListMemberExport.java new file mode 100644 index 00000000..242cdeae --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListMemberExport.java @@ -0,0 +1,94 @@ +package org.chorem.pollen.services.bean.export; + +/* + * #%L + * Pollen :: Service + * %% + * Copyright (C) 2009 - 2017 Code Lutin, Tony Chemit + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import org.chorem.pollen.persistence.entity.FavoriteListMember; +import org.chorem.pollen.persistence.entity.FavoriteListMemberImpl; +import org.chorem.pollen.services.bean.FavoriteListMemberBean; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class FavoriteListMemberExport { + + protected String name; + + protected String email; + + protected double weight; + + public static FavoriteListMemberExport fromEntity(FavoriteListMember entity) { + FavoriteListMemberExport export = new FavoriteListMemberExport(); + export.setName(entity.getName()); + export.setEmail(entity.getEmail()); + export.setWeight(entity.getWeight()); + + return export; + } + + public FavoriteListMember toEntity() { + + FavoriteListMember entity = new FavoriteListMemberImpl(); + entity.setEmail(getEmail()); + entity.setName(getName()); + entity.setWeight(getWeight()); + + return entity; + + } + + public FavoriteListMemberBean toBean() { + FavoriteListMemberBean bean = new FavoriteListMemberBean(); + bean.setEmail(getEmail()); + bean.setName(getName()); + bean.setWeight(getWeight()); + + return bean; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public double getWeight() { + return weight; + } + + public void setWeight(double weight) { + this.weight = weight; + } + + +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListsExport.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListsExport.java new file mode 100644 index 00000000..3716001a --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/export/FavoriteListsExport.java @@ -0,0 +1,36 @@ +package org.chorem.pollen.services.bean.export; + +import com.google.common.collect.Lists; + +import java.util.List; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class FavoriteListsExport { + + public static String VERSION = "1.0.0"; + + protected String version; + + protected List<FavoriteListExport> favoriteLists; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List<FavoriteListExport> getFavoriteLists() { + if (favoriteLists == null) { + favoriteLists = Lists.newLinkedList(); + } + return favoriteLists; + } + + public void setFavoriteLists(List<FavoriteListExport> favoriteLists) { + this.favoriteLists = favoriteLists; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java index 8812af91..90ff4f7d 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java @@ -21,7 +21,12 @@ package org.chorem.pollen.services.service; * #L% */ +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.chorem.pollen.persistence.entity.ChildFavoriteList; @@ -32,19 +37,29 @@ import org.chorem.pollen.persistence.entity.FavoriteListTopiaDao; 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.PollenTechnicalException; import org.chorem.pollen.services.bean.ChildFavoriteListBean; import org.chorem.pollen.services.bean.FavoriteListBean; import org.chorem.pollen.services.bean.FavoriteListMemberBean; import org.chorem.pollen.services.bean.PaginationParameterBean; import org.chorem.pollen.services.bean.PaginationResultBean; import org.chorem.pollen.services.bean.PollenEntityRef; +import org.chorem.pollen.services.bean.export.ChildFavoriteListExport; +import org.chorem.pollen.services.bean.export.ExportBean; +import org.chorem.pollen.services.bean.export.FavoriteListExport; +import org.chorem.pollen.services.bean.export.FavoriteListMemberExport; +import org.chorem.pollen.services.bean.export.FavoriteListsExport; import org.nuiton.util.pagination.PaginationParameter; import org.nuiton.util.pagination.PaginationResult; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static org.nuiton.i18n.I18n.l; @@ -390,6 +405,17 @@ public class FavoriteListService extends PollenServiceSupport { } + protected List<ChildFavoriteList> getAllChildrenLists0(PollenUser user) { + + + List<ChildFavoriteList> result = getChildFavoriteListDao() + .forProperties(ChildFavoriteList.PROPERTY_PARENT + "." + FavoriteList.PROPERTY_POLLEN_USER, user) + .findAll(); + + return result; + + } + protected ErrorMap checkFavoriteList(List<FavoriteList> existingFavoriteLists, FavoriteListBean favoriteList) { ErrorMap errors = new ErrorMap(); @@ -402,29 +428,12 @@ public class FavoriteListService extends PollenServiceSupport { if (nameNotBlank) { - Set<String> favoriteListNames = Sets.newHashSet(); - - if (CollectionUtils.isNotEmpty(existingFavoriteLists)) { - - // get all used names - - for (FavoriteList favoriteList1 : existingFavoriteLists) { - - if (favoriteListExists && - favoriteList1.getTopiaId().equals(favoriteList.getEntityId())) { - - continue; - - } - - favoriteListNames.add(favoriteList1.getName()); - - } - - } + Optional<FavoriteList> sameName = existingFavoriteLists.stream() + .filter(favoriteList1 -> !favoriteList1.getTopiaId().equals(favoriteList.getEntityId())) + .filter(favoriteList1 -> favoriteList1.getName().equals(favoriteListName)) + .findFirst(); - boolean nameAdded = favoriteListNames.add(favoriteListName); - check(errors, "name", nameAdded, l(getLocale(), "pollen.error.favoriteList.name.already.used")); + check(errors, "name", !sameName.isPresent(), l(getLocale(), "pollen.error.favoriteList.name.already.used", favoriteListName)); } return errors; @@ -462,7 +471,7 @@ public class FavoriteListService extends PollenServiceSupport { if (nameNotBlank) { boolean added = memberNames.add(favoriteListMember.getName()); - check(errors, "name", added, l(getLocale(), "pollen.error.favoriteListMember.name.already.used")); + check(errors, "name", added, l(getLocale(), "pollen.error.favoriteListMember.name.already.used", favoriteListMember.getName())); } @@ -472,18 +481,18 @@ public class FavoriteListService extends PollenServiceSupport { if (emailNotBlank) { - boolean emailValid = checkValidEmail(errors, "email", memberEmail, l(getLocale(), "pollen.error.favoriteListMember.email.invalid")); + boolean emailValid = checkValidEmail(errors, "email", memberEmail, l(getLocale(), "pollen.error.favoriteListMember.email.invalid", memberEmail)); if (emailValid) { boolean emailAdded = memberEmails.add(memberEmail); - check(errors, "email", emailAdded, l(getLocale(), "pollen.error.favoriteListMember.email.already.used")); + check(errors, "email", emailAdded, l(getLocale(), "pollen.error.favoriteListMember.email.already.used", memberEmail)); } } - check(errors, "weight", favoriteListMember.getWeight() > 0, l(getLocale(), "pollen.error.favoriteListMember.weight.negativeOrNull")); + check(errors, "weight", favoriteListMember.getWeight() > 0, l(getLocale(), "pollen.error.favoriteListMember.weight.negativeOrNull", favoriteListMember.getWeight())); return errors; @@ -499,32 +508,61 @@ public class FavoriteListService extends PollenServiceSupport { // get all used Optional<String> childListAlreadyExist = existingChildList.stream() + .filter(child -> parentList.equals(child.getParent())) .map(ChildFavoriteList::getChild) + .filter(list -> list.getName().equals(childFavoriteList.getChild().getName())) .map(FavoriteList::getTopiaId) - .filter(id -> id.equals(childFavoriteList.getChild().getEntityId())) .findFirst(); check(errors, ChildFavoriteList.PROPERTY_CHILD, !childListAlreadyExist.isPresent(), - l(getLocale(), "pollen.error.childFavoriteList.already.used")); + l(getLocale(), "pollen.error.childFavoriteList.already.used", childFavoriteList.getChild().getName())); } - boolean sameList = parentList.getTopiaId().equals(childFavoriteList.getChild().getEntityId()); + //on se base sur le nom plutot que sur L'id car pour les import les id n'existe pas encore + + boolean sameList = parentList.getName().equals(childFavoriteList.getChild().getName()); check(errors, ChildFavoriteList.PROPERTY_CHILD, !sameList, l(getLocale(), "pollen.error.childFavoriteList.sameParentChild", parentList.getName())); check(errors, ChildFavoriteList.PROPERTY_CHILD, - sameList || !getChildFavoriteListDao().isAncestorOrSelf(childFavoriteList.getChild().getEntityId(), parentList.getTopiaId()), + sameList || !isAncestorOrSelf(childFavoriteList.getChild().getName(), parentList.getName(), existingChildList), l(getLocale(), "pollen.error.childFavoriteList.childIsAncestor", parentList.getName(), childFavoriteList.getChild().getName())); - check(errors, "weight", childFavoriteList.getWeight() > 0, l(getLocale(), "pollen.error.childFavoriteList.weight.negativeOrNull")); + check(errors, "weight", childFavoriteList.getWeight() > 0, l(getLocale(), "pollen.error.childFavoriteList.weight.negativeOrNull", childFavoriteList.getWeight())); return errors; } + + protected boolean isAncestorOrSelf(String ancestorFavoriteListName, String favoriteListName, List<ChildFavoriteList> existingChildList) { + + boolean result = ancestorFavoriteListName.equals(favoriteListName); + + if (! result) { + + List<ChildFavoriteList> childrenFavoriteList = existingChildList.stream() + .filter(child -> favoriteListName.equals(child.getChild().getName())) + .collect(Collectors.toList()); + + for (ChildFavoriteList childFavoriteList : childrenFavoriteList) { + + result = result || isAncestorOrSelf(ancestorFavoriteListName, childFavoriteList.getParent().getName(), existingChildList); + + if (result) { + break; + } + + } + } + + return result; + + } + protected PaginationParameter getFavoriteListPaginationParameter(PaginationParameterBean paginationParameter) { if (paginationParameter == null) { @@ -597,7 +635,7 @@ public class FavoriteListService extends PollenServiceSupport { FavoriteList favoriteList = getFavoriteList0(user, favoriteListId); - List<ChildFavoriteList> existingChildFavoriteList = getChildrenLists0(favoriteList); + List<ChildFavoriteList> existingChildFavoriteList = getAllChildrenLists0(user); ErrorMap errorMap = checkChildList(favoriteList, existingChildFavoriteList, childList); errorMap.failIfNotEmpty(); @@ -726,7 +764,7 @@ public class FavoriteListService extends PollenServiceSupport { String name = voterList.getName(); boolean nameAlreadyUsed = existingFavoriteLists.stream().filter(fl -> fl.getName().equals(name)).findFirst().isPresent(); - check(errors, FavoriteList.PROPERTY_NAME, !nameAlreadyUsed, l(getLocale(), "pollen.error.favoriteList.name.already.used") + " (" + name + ")"); + check(errors, FavoriteList.PROPERTY_NAME, !nameAlreadyUsed, l(getLocale(), "pollen.error.favoriteList.name.already.used", name)); List<VoterList> childrenVoterLists = getVoterListDao().forParentEquals(voterList).addEquals(VoterList.PROPERTY_POLL, voterList.getPoll()).findAll(); for (VoterList childVoterList : childrenVoterLists) { @@ -735,4 +773,196 @@ public class FavoriteListService extends PollenServiceSupport { return errors; } + + public int importFavoriteLists(File favoriteListsExportFile) throws InvalidFormException { + checkIsConnected(); + PollenUser user = getConnectedUser(); + + Gson gson = new Gson(); + FileReader reader; + try { + reader = new FileReader(favoriteListsExportFile); + + } catch (FileNotFoundException e) { + + // should never happens ? + throw new PollenTechnicalException(e); + + } + + List<FavoriteList> favoriteLists = Lists.newArrayList(); + try { + FavoriteListsExport favoriteListsExport = gson.fromJson(reader, FavoriteListsExport.class); + + List<FavoriteList> existingFavoriteLists = getFavoriteLists0(user); + + ErrorMap errorMap = checkImportFavoriteLists(favoriteListsExport, existingFavoriteLists); + errorMap.failIfNotEmpty(); + + favoriteLists = saveImportFavoriteLists(favoriteListsExport, user); + + commit(); + } catch (JsonSyntaxException e) { + ErrorMap errors = new ErrorMap(); + + errors.addError("file", l(getLocale(), "pollen.error.import.favoriteList.parser", e.getMessage())); + errors.failIfNotEmpty(); + } + + + + return favoriteLists.size(); + + } + + private List<FavoriteList> saveImportFavoriteLists(FavoriteListsExport favoriteListsExport, PollenUser user) { + + Map<FavoriteListExport, FavoriteList> favoriteListByExport = Maps.newHashMap(); + + for (FavoriteListExport favoriteListExport : favoriteListsExport.getFavoriteLists()) { + + FavoriteList favoriteList = favoriteListExport.toEntity(); + favoriteList.setPollenUser(user); + favoriteList.setOwner(getSecurityContext().getMainPrincipal()); + + getFavoriteListDao().create(favoriteList); + + favoriteListByExport.put(favoriteListExport, favoriteList); + + for (FavoriteListMemberExport favoriteListMemberExport : favoriteListExport.getMembers()) { + + FavoriteListMember member = favoriteListMemberExport.toEntity(); + member.setFavoriteList(favoriteList); + + getFavoriteListMemberDao().create(member); + + } + } + + List<FavoriteList> favoriteLists = getFavoriteLists0(user); + + for (FavoriteListExport favoriteListExport : favoriteListsExport.getFavoriteLists()) { + + FavoriteList favoriteList = favoriteListByExport.get(favoriteListExport); + + for (ChildFavoriteListExport childFavoriteListExport : favoriteListExport.getChildren()) { + + ChildFavoriteList childFavoriteList = childFavoriteListExport.toEntity(favoriteList, favoriteLists); + + getChildFavoriteListDao().create(childFavoriteList); + + } + + } + + return Lists.newArrayList(favoriteListByExport.values()); + } + + private ErrorMap checkImportFavoriteLists( + FavoriteListsExport favoriteListsExport, + List<FavoriteList> existingFavoriteLists) { + + ErrorMap errors = new ErrorMap(); + + check(errors, "version", FavoriteListsExport.VERSION.equals(favoriteListsExport.getVersion()), l(getLocale(), "pollen.error.import.favoriteList.version", favoriteListsExport.getVersion())); + + Map<FavoriteListExport, FavoriteList> favoriteListByExport = Maps.newHashMap(); + + int favoriteListIndex = 0; + for (FavoriteListExport favoriteListExport : favoriteListsExport.getFavoriteLists()) { + + ErrorMap errorsList = checkFavoriteList(existingFavoriteLists, favoriteListExport.toBean()); + + FavoriteList favoriteList = favoriteListExport.toEntity(); + + existingFavoriteLists.add(favoriteList); + + favoriteListByExport.put(favoriteListExport, favoriteList); + + List<FavoriteListMember> members = Lists.newLinkedList(); + + int memberIndex = 0; + for (FavoriteListMemberExport favoriteListMemberExport : favoriteListExport.getMembers()) { + + ErrorMap errorsMember = checkFavoriteListMember(members, favoriteListMemberExport.toBean()); + + + errorsMember.copyTo(errorsList, ".members[" + memberIndex + "]"); + + members.add(favoriteListMemberExport.toEntity()); + + memberIndex++; + } + + errorsList.copyTo(errors, "favoriteLists[" + favoriteListIndex + "]"); + + favoriteListIndex++; + } + + favoriteListIndex = 0; + for (FavoriteListExport favoriteListExport : favoriteListsExport.getFavoriteLists()) { + + FavoriteList favoriteList = favoriteListByExport.get(favoriteListExport); + + List<ChildFavoriteList> children = Lists.newLinkedList(); + + int childIndex = 0; + for (ChildFavoriteListExport childFavoriteListExport : favoriteListExport.getChildren()) { + + ErrorMap errorsChild = checkChildList(favoriteList, children, childFavoriteListExport.toBean(existingFavoriteLists)); + + errorsChild.copyTo(errors, "favoriteLists[" + favoriteListIndex + "].children[" + childIndex + "]"); + + children.add(childFavoriteListExport.toEntity(favoriteList, existingFavoriteLists)); + + childIndex++; + } + + } + + return errors; + } + + public ExportBean exportFavoriteLists() { + checkIsConnected(); + PollenUser user = getConnectedUser(); + + FavoriteListsExport result = new FavoriteListsExport(); + + List<FavoriteList> favoriteLists = getFavoriteLists0(user); + + result.setVersion(FavoriteListsExport.VERSION); + + for (FavoriteList favoriteList : favoriteLists) { + + FavoriteListExport favoriteListExport = FavoriteListExport.fromEntity(favoriteList); + + List<ChildFavoriteList> children = getChildrenLists0(favoriteList); + + List<ChildFavoriteListExport> childrenExport = children.stream() + .map(ChildFavoriteListExport::fromEntity) + .collect(Collectors.toList()); + + favoriteListExport.setChildren(childrenExport); + + List<FavoriteListMember> members = getFavoriteListMembers0(favoriteList); + + List<FavoriteListMemberExport> membersExport = members.stream() + .map(FavoriteListMemberExport::fromEntity) + .collect(Collectors.toList()); + + favoriteListExport.setMembers(membersExport); + + result.getFavoriteLists().add(favoriteListExport); + } + + ExportBean exportBean = new ExportBean(); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + exportBean.setContent(gson.toJson(result)); + exportBean.setName(l(getLocale(), "pollen.export.favoriteLists", user.getName(), getNow())); + exportBean.setContentType("application/json"); + + + return exportBean; + } } 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 c6c4e244..57efe787 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 @@ -35,10 +35,10 @@ pollen.configuration.uiUrlPollVote=Url to vote on a poll pollen.configuration.version=Application version pollen.configurqtion.uiUrlPollVoteEdit=Url to edit a vote on a poll pollen.configurqtion.uiUrlUserValidate=Url de validate user account -pollen.error.childFavoriteList.already.used=Child list is already used -pollen.error.childFavoriteList.childIsAncestor=Child list is ancestor of %s -pollen.error.childFavoriteList.sameParentChild=Child must be not equal to parent -pollen.error.childFavoriteList.weight.negativeOrNull=Weight must be positive +pollen.error.childFavoriteList.already.used=Child list "%s" is already used +pollen.error.childFavoriteList.childIsAncestor=Child list "%2$s" is ancestor of main list %1$s +pollen.error.childFavoriteList.sameParentChild=Child "%s" must be not equal to parent +pollen.error.childFavoriteList.weight.negativeOrNull=Weight (%s) must be positive pollen.error.choice.choiceDateEmpty=choice date can not be empty pollen.error.choice.choiceDateExist=choice date already used in this list pollen.error.choice.choiceDateInvalid=Date format %s is not valid @@ -54,14 +54,16 @@ pollen.error.favoriteList.import.csv.weight.notNumber=Line %s \: weight is not a pollen.error.favoriteList.import.ldap.already.used.email= pollen.error.favoriteList.import.ldap.already.used.name= pollen.error.favoriteList.import.ldap.invalid.email= -pollen.error.favoriteList.name.already.used=name already used by another favorite list +pollen.error.favoriteList.name.already.used=name "%s" already used by another favorite list pollen.error.favoriteList.name.empty=name can not be empty -pollen.error.favoriteListMember.email.already.used=member email already used in this list +pollen.error.favoriteListMember.email.already.used=member email "%s" already used in this list pollen.error.favoriteListMember.email.empty=member email can not be empty -pollen.error.favoriteListMember.email.invalid=member email is not valid -pollen.error.favoriteListMember.name.already.used=member name already used +pollen.error.favoriteListMember.email.invalid=member email "%s" is not valid +pollen.error.favoriteListMember.name.already.used=member name "%s" already used pollen.error.favoriteListMember.name.empty=member name can not be empty -pollen.error.favoriteListMember.weight.negativeOrNull=Weight must be positive +pollen.error.favoriteListMember.weight.negativeOrNull=Weight (%s) must be positive +pollen.error.import.favoriteList.parser=Bad structure file \: %s +pollen.error.import.favoriteList.version=import file version (%s) is not correct pollen.error.poll.beginChoiceDate.afterEndDate=the begin date of adding choice is after the end of poll pollen.error.poll.choice.mandatory=At least a choice is mandatory pollen.error.poll.choiceType.mandatory= @@ -104,6 +106,7 @@ pollen.error.voterList.member.weight.greaterThan0=member weight must be greater pollen.error.voterList.name.alreadyUsed=voterList name already used pollen.error.voterList.name.mandatory=voterList name can not be empty pollen.error.voterList.weight.greaterThan0=voterList weight must be greater than 0 +pollen.export.favoriteLists=favorite lists %s %tF.json 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 e3241be7..2c90d02b 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 @@ -35,10 +35,10 @@ pollen.configuration.uiUrlPollVote=Url de vote sur un sondage pollen.configuration.version=Version de l'application pollen.configurqtion.uiUrlPollVoteEdit=Url d'édition de vote sur un sondage pollen.configurqtion.uiUrlUserValidate=Url de validation d'un compte utilisateur -pollen.error.childFavoriteList.already.used=La sous-liste est déja utlisée -pollen.error.childFavoriteList.childIsAncestor=La sous-liste "%2s" ne doit pas dépendre de la liste principal "%1s" -pollen.error.childFavoriteList.sameParentChild=La liste principal ne peut avoir comme sous-lists elle-même -pollen.error.childFavoriteList.weight.negativeOrNull=le poids de la sous-liste doit être positif +pollen.error.childFavoriteList.already.used=La sous-liste « %s » est déja utlisée +pollen.error.childFavoriteList.childIsAncestor=La sous-liste « %2$s » ne doit pas dépendre de la liste principal « %1$s » +pollen.error.childFavoriteList.sameParentChild=La liste principal « %s » ne peut avoir comme sous-lists elle-même +pollen.error.childFavoriteList.weight.negativeOrNull=le poids de la sous-liste (%s) doit être positif pollen.error.choice.choiceDateEmpty=La date ne peut pas être vide pollen.error.choice.choiceDateExist=La date exist déjà utilisé sur ce sondage pollen.error.choice.choiceDateInvalid=Le format de la date %s n'est pas valide @@ -54,14 +54,16 @@ pollen.error.favoriteList.import.csv.weight.notNumber=Ligne %s \: Le poids n'est pollen.error.favoriteList.import.ldap.already.used.email= pollen.error.favoriteList.import.ldap.already.used.name= pollen.error.favoriteList.import.ldap.invalid.email= -pollen.error.favoriteList.name.already.used=Le nom est déjà utilisé par une autre liste +pollen.error.favoriteList.name.already.used=Le nom « %s » est déjà utilisé par une autre liste pollen.error.favoriteList.name.empty=Le nom de la liste est obligatoire -pollen.error.favoriteListMember.email.already.used=Le courriel du membre est déjà utilisé dans cette liste +pollen.error.favoriteListMember.email.already.used=Le courriel du membre « %s » est déjà utilisé dans cette liste pollen.error.favoriteListMember.email.empty=Le courriel est obligatoire -pollen.error.favoriteListMember.email.invalid=Le courriel du membre est invalide -pollen.error.favoriteListMember.name.already.used=Le nom du membre est déjà utilisé dans cette liste +pollen.error.favoriteListMember.email.invalid=Le courriel du membre « %s »est invalide +pollen.error.favoriteListMember.name.already.used=Le nom du membre « %s » est déjà utilisé dans cette liste pollen.error.favoriteListMember.name.empty=Le nom du membre est obligatoire -pollen.error.favoriteListMember.weight.negativeOrNull=le poids du membre doit être positif +pollen.error.favoriteListMember.weight.negativeOrNull=le poids du membre (%s) doit être positif +pollen.error.import.favoriteList.parser=Fichier mal structuré \: %s +pollen.error.import.favoriteList.version=Le version du fichier d'import (%s) n'est pas correcte pollen.error.poll.beginChoiceDate.afterEndDate=La date de début d'ajout de choix est après la date de fin du sondage pollen.error.poll.choice.mandatory=Au moins un choix est nécessaire pollen.error.poll.choiceType.mandatory= @@ -103,6 +105,7 @@ pollen.error.voterList.member.weight.greaterThan0=Le membre doit avoir un poid s 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.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.json b/pollen-ui-riot-js/src/main/web/i18n.json index b373de20..4866404c 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -354,6 +354,7 @@ "choice_fileSizeMax_message": "Le fichier « {0} » de taille de {1} ne doit pas dépasser {2}.", "favoriteList_title": "Mes listes de votants", "favoriteList_addFavoriteList": "Ajouter une nouvelle liste de votants", + "favoriteList_export": "Exporter les listes de votants", "favoriteList_name": "Nom", "favoriteList_name_placdeholder": "Renseignez le nom de la nouvelle liste", "favoriteList_add": "Ajouter", @@ -406,6 +407,10 @@ "favoriteList_childList_add": "Ajouter", "favoriteList_childList_delete": "Retirer la sous-liste", "favoriteList_childList_deleteMessage": "Retirer la sou-liste ?", + "favoriteList_importFavoriteLists": "Importer des listes de votants", + "favoriteList_import_file": "Fichier à importer", + "favoriteList_import_file_detail": "Le fichier doit être au format JSON", + "favoriteList_import": "Importer", "error_manager_403": "Erreur : Accès refusé", "error_manager_500": "Erreur : Service indisponile", "voterList_name": "Nom", @@ -779,6 +784,7 @@ "choice_fileSizeMax_message": "File \"{0}\" for size {1} can't be over {2}.", "favoriteList_title": "My favorite lists", "favoriteList_addFavoriteList": "Add new favorite list", + "favoriteList_export": "Export favorite lists", "favoriteList_name": "Name", "favoriteList_name_placdeholder": "Enter new list name", "favoriteList_add": "Add", @@ -830,6 +836,10 @@ "favoriteList_childList_add": "Ajouter", "favoriteList_childList_delete": "Remove sub-list", "favoriteList_childList_deleteMessage": "Remove sub-list ?", + "favoriteList_importFavoriteLists": "Import favorite lists", + "favoriteList_import_file": "Import file", + "favoriteList_import_file_detail": "File must be in JSON format", + "favoriteList_import": "Import", "error_manager_403": "Error: Forbidden access", "error_manager_500": "Error: Service unavailable", "voterList_name": "Name", diff --git a/pollen-ui-riot-js/src/main/web/js/FavoriteListService.js b/pollen-ui-riot-js/src/main/web/js/FavoriteListService.js index 752a2d42..4ef43777 100644 --- a/pollen-ui-riot-js/src/main/web/js/FavoriteListService.js +++ b/pollen-ui-riot-js/src/main/web/js/FavoriteListService.js @@ -31,6 +31,10 @@ class FavoriteListService extends FetchService { return this.get("/v1/favoriteLists/" + favoriteListId); } + importFavoriteLists(importFile) { + return this.form("/v1/favoriteLists/imports", {importFile: importFile}, true); + } + importCsv(favoriteListId, csvFile) { return this.form("/v1/favoriteLists/" + favoriteListId + "/importCsv", {csvFile: csvFile}, true); } diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html index d33616f1..e3ecbdcf 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html @@ -34,19 +34,49 @@ require("./FavoriteListCard.tag.html"); </div> <div class="actions-right"> - <a class="c-button c-button--success" + <a class="c-button c-button--info" + if={pagination.count > 0} + href="{session.configuration.endPoint}/v1/favoriteLists/exports" + target="_blank"> + <i class="fa fa-download"></i> + {__.export} + </a> + <a class="c-button c-button--success" href="#/favoriteLists/new"> {__.addFavoriteList} <i class="fa fa-plus"></i> </a> + </div> + <hr/> + <form class="form-add" onsubmit={import}> + <h3 class="c-heading">{__.importFavoriteLists}</h3> + <div class="o-form-element"> + <label class="c-label" for="importFile">{__.import_file}</label> + <input type="file" + id="importFile" + ref="importFile" + required + class="c-field {c-field--error : importErrors.error}"> + <div class="exemple"> + {__.import_file_detail} + </div> + </div> + <div class="actions-right"> + <button class="c-button c-button--success" + type="submit"> + <i class="fa fa-upload" aria-hidden="true"></i> + {__.import} + </button> + </div> + </form> </div> </div> <script type="es6"> this.loaded = false; - let session = require("../../js/Session"); + this.session = require("../../js/Session"); let favoriteListsService = require("../../js/FavoriteListService"); - this.installBundle(session, "favoriteList"); + this.installBundle(this.session, "favoriteList"); this.pagination = { order: "topiaCreateDate", @@ -55,6 +85,7 @@ require("./FavoriteListCard.tag.html"); pageNumber: 0 }; this.favoriteLists = []; + this.importErrors = {}; this.refresh = () => { return favoriteListsService.favoriteLists(this.pagination).then((result) => { @@ -95,10 +126,25 @@ require("./FavoriteListCard.tag.html"); this.refresh(); }; + this.import = (e) => { + e.preventDefault(); + e.stopPropagation(); + let importFile = this.refs.importFile.files[0]; + favoriteListsService.importFavoriteLists(importFile).then(() => { + this.importErrors = {}; + this.refs.importFile.value = ""; + this.refresh(); + }, errors => { + this.importErrors = errors; + this.bus.trigger("error", errors); + this.update(); + }); + }; + </script> <style> - .c-heading { + h1.c-heading { text-align: center; } @@ -115,5 +161,32 @@ require("./FavoriteListCard.tag.html"); width: 200px; } + .o-form-element.sort .c-input-group .c-field { + width: 100%; + } + + .exemple { + font-size: 0.9em; + padding-left: 25%; + padding-top: 0.5em; + width: 100%; + } + + @media (min-width: 640px) { + .o-form-element .c-label:first-child { + width: 25%; + display: inline-block; + text-align: right; + float: left; + padding-top: 0.5em; + padding-right: 5px; + } + + .o-form-element .c-field { + width: 75%; + display: inline-block; + } + } + </style> </FavoriteLists> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.