From 0b439bd578c489815f78876f261aafee8e6a6d62 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Thu, 3 May 2018 23:43:33 +0200 Subject: [PATCH] GDPR erasure: user profile and Q&A --- conf/base.conf | 2 +- modules/common/src/main/DetectLanguage.scala | 3 ++- modules/qa/src/main/Env.scala | 12 ++++++++++++ modules/qa/src/main/QaApi.scala | 9 +++++++++ modules/user/src/main/Env.scala | 1 + modules/user/src/main/UserRepo.scala | 2 ++ 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/conf/base.conf b/conf/base.conf index afda7799ac..b3370ebbf9 100644 --- a/conf/base.conf +++ b/conf/base.conf @@ -316,7 +316,7 @@ i18n { } detectlanguage.api { url = "http://ws.detectlanguage.com/0.2/detect" - key = "???" + key = "" } mailgun { api { diff --git a/modules/common/src/main/DetectLanguage.scala b/modules/common/src/main/DetectLanguage.scala index eb727f9179..796801f59c 100644 --- a/modules/common/src/main/DetectLanguage.scala +++ b/modules/common/src/main/DetectLanguage.scala @@ -19,7 +19,8 @@ final class DetectLanguage(url: String, key: String) { private val messageMaxLength = 2000 def apply(message: String): Fu[Option[Lang]] = - WS.url(url).post(Map( + if (key.isEmpty) fuccess(Lang("en").some) + else WS.url(url).post(Map( "key" -> Seq(key), "q" -> Seq(message take messageMaxLength) )) map { response => diff --git a/modules/qa/src/main/Env.scala b/modules/qa/src/main/Env.scala index 3a0a648112..c3ae3fc3b3 100644 --- a/modules/qa/src/main/Env.scala +++ b/modules/qa/src/main/Env.scala @@ -2,6 +2,7 @@ package lila.qa import com.typesafe.config.Config import lila.common.DetectLanguage +import akka.actor._ final class Env( config: Config, @@ -10,6 +11,7 @@ final class Env( mongoCache: lila.memo.MongoCache.Builder, asyncCache: lila.memo.AsyncCache.Builder, notifyApi: lila.notify.NotifyApi, + system: akka.actor.ActorSystem, db: lila.db.Env ) { @@ -34,6 +36,15 @@ final class Env( lazy val search = new Search(questionColl) lazy val forms = new DataForm(hub.actor.captcher, detectLanguage) + + system.lilaBus.subscribe(system.actorOf(Props(new Actor { + def receive = { + case lila.user.User.GDPRErase(user) => for { + _ <- api.question erase user + _ <- api.answer erase user + } yield () + } + })), 'gdprErase) } object Env { @@ -45,6 +56,7 @@ object Env { mongoCache = lila.memo.Env.current.mongoCache, asyncCache = lila.memo.Env.current.asyncCache, notifyApi = lila.notify.Env.current.api, + system = lila.common.PlayApp.system, db = lila.db.Env.current ) } diff --git a/modules/qa/src/main/QaApi.scala b/modules/qa/src/main/QaApi.scala index 274220bef7..f552f75371 100644 --- a/modules/qa/src/main/QaApi.scala +++ b/modules/qa/src/main/QaApi.scala @@ -148,6 +148,13 @@ final class QaApi( case None => $unset("locked") case Some(u) => $set("locked" -> Locked(by = u.id, at = DateTime.now)) }).void + + def erase(user: User) = questionColl.distinct[QuestionId, List]("_id", $doc("userId" -> user.id).some).flatMap { ids => + (ids.nonEmpty) ?? { + questionColl.remove($inIds(ids)) >> + answerColl.remove($doc("questionId" $in ids)).void + } + } } object answer { @@ -263,6 +270,8 @@ final class QaApi( def countByQuestionId(id: QuestionId) = answerColl.count(Some($doc("questionId" -> id))) + + def erase(user: User) = answerColl.remove($doc("userId" -> user.id)) } object comment { diff --git a/modules/user/src/main/Env.scala b/modules/user/src/main/Env.scala index cd453ccc2d..9ec7bccca8 100644 --- a/modules/user/src/main/Env.scala +++ b/modules/user/src/main/Env.scala @@ -56,6 +56,7 @@ final class Env( case User.Active(user) => if (!user.seenRecently) UserRepo setSeenAt user.id onlineUserIdMemo put user.id + case User.GDPRErase(user) => UserRepo erase user } })), 'adjustCheater, 'adjustBooster, 'userActive, 'kickFromRankings) diff --git a/modules/user/src/main/UserRepo.scala b/modules/user/src/main/UserRepo.scala index 0815c888f6..b6b4169644 100644 --- a/modules/user/src/main/UserRepo.scala +++ b/modules/user/src/main/UserRepo.scala @@ -411,6 +411,8 @@ object UserRepo { def setEmailConfirmed(id: User.ID): Funit = coll.update($id(id), $unset(F.mustConfirmEmail)).void + def erase(user: User): Funit = coll.update($id(user.id), $unset(F.profile)).void + private def newUser( username: String, passwordHash: HashedPassword,