This is an automated email from the git hooks/post-receive script. New commit to branch feature/210-rgpd in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 392460e0d3a4cee36b2ceca365e92f205339267d Author: jcouteau <couteau@codelutin.com> Date: Wed Sep 12 16:34:52 2018 +0200 refs #210 : Cron d'anonymisation ; Cassage des liens entre votes à l'anonymisation des votes d'un utilisateurs supprimant son compte. --- .../pollen/persistence/entity/VoteTopiaDao.java | 16 +++++++++++ .../rest/api/PollenRestApiApplicationListener.java | 15 ++++++++++ pollen-services/src/main/config/PollenServices.ini | 8 +++++- .../chorem/pollen/services/job/RGPDPurgeJob.java | 23 +++++++++++++-- .../pollen/services/service/PollenUserService.java | 12 ++++++-- .../pollen/services/service/VoteService.java | 33 ++++++++++++++++++++++ .../i18n/pollen-services_en_GB.properties | 1 + .../i18n/pollen-services_fr_FR.properties | 1 + 8 files changed, 103 insertions(+), 6 deletions(-) diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteTopiaDao.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteTopiaDao.java index 6af63b31..fe53c91f 100644 --- a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteTopiaDao.java +++ b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoteTopiaDao.java @@ -23,6 +23,7 @@ package org.chorem.pollen.persistence.entity; import org.nuiton.topia.persistence.HqlAndParametersBuilder; +import java.util.Calendar; import java.util.Date; import java.util.List; @@ -56,4 +57,19 @@ public class VoteTopiaDao extends AbstractVoteTopiaDao<Vote> { Vote.PROPERTY_TOPIA_CREATE_DATE, since).findAll(); } + public List<Vote> findAllOldVotes() { + + HqlAndParametersBuilder<Vote> builder = new HqlAndParametersBuilder<>(Vote.class); + + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.YEAR, -2); + Date twoYearsAgo = cal.getTime(); + + builder.addLowerThan(Vote.PROPERTY_TOPIA_CREATE_DATE, twoYearsAgo); + builder.addNotNull(Vote.PROPERTY_VOTER+"."+PollenPrincipal.PROPERTY_POLLEN_USER); + + List<Vote> oldVotes = findAll(builder.getHql(), builder.getHqlParameters()); + return oldVotes; + } + } diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplicationListener.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplicationListener.java index 469b0317..240198bc 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplicationListener.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiApplicationListener.java @@ -43,6 +43,7 @@ import org.chorem.pollen.services.config.PollenServicesConfig; import org.chorem.pollen.services.job.AbstractPollenJob; import org.chorem.pollen.services.job.CheckMailBoxJob; import org.chorem.pollen.services.job.DeleteObsoleteSessionTokensJob; +import org.chorem.pollen.services.job.RGPDPurgeJob; import org.chorem.pollen.services.job.SendEmailInErrorsJob; import org.chorem.pollen.services.job.SendPollEndReminderJob; import org.quartz.CronScheduleBuilder; @@ -127,6 +128,11 @@ public class PollenRestApiApplicationListener implements ServletContextListener .withIdentity("checkMailBoxJob", "pollenJobs") .build(); + JobDetail rgpdPurgeJob = JobBuilder.newJob(RGPDPurgeJob.class) + .usingJobData(data) + .withIdentity("rgpdPurgeJob", "pollenJobs") + .build(); + try { scheduler = new StdSchedulerFactory().getScheduler(); @@ -169,6 +175,15 @@ public class PollenRestApiApplicationListener implements ServletContextListener scheduler.scheduleJob(checkMailBoxJob, checkMailBoxTrigger); + // schedule rgpd purge + Trigger rgpdPurgeTrigger = TriggerBuilder + .newTrigger() + .withIdentity("rgpdPurgeTrigger", "pollenTriggers") + .withSchedule(CronScheduleBuilder.cronSchedule(applicationConfig.getRgpdPurgeCronSchedule())) + .build(); + + scheduler.scheduleJob(rgpdPurgeJob, rgpdPurgeTrigger); + scheduler.start(); if (log.isDebugEnabled()) { diff --git a/pollen-services/src/main/config/PollenServices.ini b/pollen-services/src/main/config/PollenServices.ini index a708830e..585db685 100644 --- a/pollen-services/src/main/config/PollenServices.ini +++ b/pollen-services/src/main/config/PollenServices.ini @@ -216,4 +216,10 @@ defaultValue = ALL_USERS description = pollen.configuration.deleteObsoleteSessionTokensCronSchedule key = pollen.deleteObsoleteSessionTokensCronSchedule type = string -defaultValue = "0 0/5 * * * ?" \ No newline at end of file +defaultValue = "0 0/5 * * * ?" + +[option rgpdPurgeCronSchedule] +description = pollen.configuration.rpgdPurgeCronSchedule +key = pollen.rgpdPurgeCronSchedule +type = string +defaultValue = "0 0 0 * * ?" \ No newline at end of file diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/job/RGPDPurgeJob.java b/pollen-services/src/main/java/org/chorem/pollen/services/job/RGPDPurgeJob.java index 189122b3..41e95628 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/job/RGPDPurgeJob.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/job/RGPDPurgeJob.java @@ -1,4 +1,23 @@ package org.chorem.pollen.services.job; -public class RGPDPurgeJob { -} +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.chorem.pollen.services.service.VoteService; +import org.quartz.DisallowConcurrentExecution; + +@DisallowConcurrentExecution +public class RGPDPurgeJob extends AbstractPollenJob { + + private static final Log log = LogFactory.getLog(CheckMailBoxJob.class); + + @Override + public void execute() { + + if (log.isDebugEnabled()) { + log.debug("Start job to anonymize old votes (RGPD)"); + } + + VoteService voteService = newService(VoteService.class); + voteService.purgeOldVotes(); + } +} \ No newline at end of file diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java index 942fc24c..6f740777 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java @@ -537,14 +537,18 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer } + /** + * Anonymize a user (setting name to "?"), and break links between votes and comments so that we cannot trace back + * the user + * @param user + */ protected void anonymizeUser(PollenUser user) { - PollenPrincipal anonymousUser = getSecurityService().generatePollenPrincipal(); - anonymousUser.setName("?"); - List<Vote> votesUser = getVoteDao().forEquals(Vote.PROPERTY_VOTER + "." + PollenPrincipal.PROPERTY_POLLEN_USER, user).findAll(); for (Vote vote : votesUser) { + PollenPrincipal anonymousUser = getSecurityService().generatePollenPrincipal(); + anonymousUser.setName("?"); vote.setVoter(anonymousUser); vote.setAnonymous(true); } @@ -552,6 +556,8 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer List<Comment> commentsUser = getCommentDao().forEquals(Comment.PROPERTY_AUTHOR + "." + PollenPrincipal.PROPERTY_POLLEN_USER, user).findAll(); for (Comment comment : commentsUser) { + PollenPrincipal anonymousUser = getSecurityService().generatePollenPrincipal(); + anonymousUser.setName("?"); comment.setAuthor(anonymousUser); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java index 852fe3ad..ed703bb5 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoteService.java @@ -26,12 +26,14 @@ import org.chorem.pollen.persistence.entity.Choice; import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.PollType; import org.chorem.pollen.persistence.entity.PollenPrincipal; +import org.chorem.pollen.persistence.entity.PollenPrincipalTopiaDao; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.Polls; import org.chorem.pollen.persistence.entity.Vote; import org.chorem.pollen.persistence.entity.VoteToChoice; import org.chorem.pollen.persistence.entity.VoteToChoiceTopiaDao; import org.chorem.pollen.persistence.entity.VoteToChoices; +import org.chorem.pollen.persistence.entity.VoteTopiaDao; import org.chorem.pollen.persistence.entity.VoterList; import org.chorem.pollen.persistence.entity.VoterListMember; import org.chorem.pollen.services.bean.ChoiceBean; @@ -46,6 +48,7 @@ import org.chorem.pollen.votecounting.VoteCounting; import org.chorem.pollen.votecounting.model.VoteCountingConfig; import org.nuiton.util.pagination.PaginationResult; +import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; @@ -537,4 +540,34 @@ public class VoteService extends PollenServiceSupport { return getVoteDao().forPollEquals(poll).count(); } + + public void purgeOldVotes() { + + PollenPrincipalTopiaDao principalDao = getPollenPrincipalDao(); + + VoteTopiaDao voteDao = getVoteDao(); + + List<Vote> votesToAnon = voteDao.findAllOldVotes(); + + List<PollenPrincipal> principalsToSave = new ArrayList<>(); + List<Vote> votesToSave = new ArrayList<>(); + + for(Vote vote:votesToAnon){ + PollenPrincipal principal = vote.getVoter(); + //Ceinture-bretelles, on vérifie bien que aucun user est lié, + // même si ça devrait jamais être le cas + if (principal.getPollenUser() != null) { + principal.setName("?"); + principalsToSave.add(principal); + vote.setAnonymous(true); + votesToSave.add(vote); + } + } + + //save votes + voteDao.updateAll(votesToSave); + + //save principals + principalDao.updateAll(principalsToSave); + } } 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 26ab4fbd..15abe9c9 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 @@ -26,6 +26,7 @@ pollen.configuration.report.maxScore=Maximum score for reporting before administ pollen.configuration.resendEmailsCronSchedule=Time between two cron jobs of email resending pollen.configuration.resource.maxSize=Maximum size of pollen resource pollen.configuration.resource.preview.max=Maximum dimension of image preview +pollen.configuration.rpgdPurgeCronSchedule= pollen.configuration.sendEndPollRemindersCronSchedule=Time between two cron jobs of poll end reminder sending pollen.configuration.smptHost=Smtp Host pollen.configuration.smtpFrom=Smtp From 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 e988b33b..11df2f24 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 @@ -26,6 +26,7 @@ pollen.configuration.report.maxScore=Score maximum pour un signalement avant que pollen.configuration.resendEmailsCronSchedule=Intervalle entre deux lancements de la tâche de renvoi des emails en erreur pollen.configuration.resource.maxSize=Taille maximal pour un fichier de resource de Pollen pollen.configuration.resource.preview.max=Dimension maximal de la prévisualisation d'un image +pollen.configuration.rpgdPurgeCronSchedule= pollen.configuration.sendEndPollRemindersCronSchedule=Intervalle entre deux lancements de la tâche d'envoi de mails de rappel de fin de sondage pollen.configuration.smptHost=Hôte smtp pollen.configuration.smtpFrom=Expéditeur -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.