109 lines
3.2 KiB
Scala
109 lines
3.2 KiB
Scala
package lila.api
|
|
|
|
import akka.stream.Materializer
|
|
import akka.stream.scaladsl._
|
|
import org.joda.time.DateTime
|
|
import org.joda.time.format.DateTimeFormat
|
|
import reactivemongo.akkastream.cursorProducer
|
|
import reactivemongo.api.ReadPreference
|
|
import scala.concurrent.duration._
|
|
import scala.concurrent.ExecutionContext
|
|
|
|
import lila.chat.Chat
|
|
import lila.db.dsl._
|
|
import lila.game.Game
|
|
import lila.user.User
|
|
|
|
final class PersonalDataExport(
|
|
securityEnv: lila.security.Env,
|
|
msgEnv: lila.msg.Env,
|
|
forumEnv: lila.forum.Env,
|
|
gameEnv: lila.game.Env,
|
|
chatEnv: lila.chat.Env,
|
|
relationEnv: lila.relation.Env,
|
|
mongoCacheApi: lila.memo.MongoCache.Api
|
|
)(implicit ec: ExecutionContext, mat: Materializer) {
|
|
|
|
def apply(user: User) = cache get user.id
|
|
|
|
private val cache = mongoCacheApi[User.ID, String](64, "personal-data-export", 1 day, identity) { loader =>
|
|
_.expireAfterAccess(1 minute)
|
|
.buildAsyncFuture {
|
|
loader(fetch)
|
|
}
|
|
}
|
|
|
|
private def fetch(userId: User.ID) =
|
|
for {
|
|
sessions <- securityEnv.store.allSessions(userId)
|
|
posts <- forumEnv.postApi.allByUser(userId)
|
|
msgs <- msgEnv.api.allMessagesOf(userId)
|
|
following <- relationEnv.api.fetchFollowing(userId)
|
|
chats <-
|
|
gameEnv.gameRepo.coll
|
|
.find($doc(Game.BSONFields.playerUids -> userId), $id(true).some)
|
|
.cursor[Bdoc](ReadPreference.secondaryPreferred)
|
|
.documentSource(90_000)
|
|
.mapConcat { doc =>
|
|
doc string "_id" toList
|
|
}
|
|
.mapAsyncUnordered(8) { id =>
|
|
chatEnv.api.userChat.findLinesBy(Chat.Id(id), userId)
|
|
}
|
|
.mapConcat(identity)
|
|
.runWith(Sink.seq)
|
|
} yield List(
|
|
render.connections(sessions),
|
|
render.followedUsers(following),
|
|
render.forumPosts(posts),
|
|
render.privateMessages(msgs),
|
|
render.gameChats(chats)
|
|
).flatten mkString "\n\n"
|
|
|
|
private object render {
|
|
|
|
def connections(sessions: List[lila.security.UserSession]) =
|
|
List(
|
|
textTitle(s"${sessions.size} Connections"),
|
|
sessions.map { s =>
|
|
s"${s.ip} ${s.date.map(textDate)}\n${s.ua}"
|
|
} mkString "\n\n"
|
|
)
|
|
|
|
def forumPosts(posts: List[lila.forum.Post]) =
|
|
List(
|
|
textTitle(s"${posts.size} Forum posts"),
|
|
posts.map { p =>
|
|
s"${textDate(p.createdAt)}\n${p.text}"
|
|
} mkString bigSep
|
|
)
|
|
|
|
def privateMessages(msgs: Seq[(User.ID, String, DateTime)]) =
|
|
List(
|
|
textTitle(s"${msgs.size} Direct messages"),
|
|
msgs.map { case (to, text, date) =>
|
|
s"$to ${textDate(date)}\n$text"
|
|
} mkString bigSep
|
|
)
|
|
|
|
def gameChats(lines: Seq[String]) =
|
|
List(
|
|
textTitle(s"${lines.size} Game chat messages"),
|
|
lines mkString bigSep
|
|
)
|
|
|
|
def followedUsers(userIds: Iterable[User.ID]) =
|
|
List(
|
|
textTitle(s"${userIds.size} Followed players"),
|
|
userIds mkString "\n"
|
|
)
|
|
|
|
private val bigSep = "\n\n------------------------------------------\n\n"
|
|
|
|
private def textTitle(t: String) = s"\n\n${"=" * t.length}\n$t\n${"=" * t.length}\n\n\n"
|
|
|
|
private val englishDateTimeFormatter = DateTimeFormat forStyle "MS"
|
|
private def textDate(date: DateTime) = englishDateTimeFormatter print date
|
|
}
|
|
}
|