lila/modules/activity/src/main/ActivityReadApi.scala

186 lines
5.8 KiB
Scala
Raw Normal View History

2017-07-18 16:29:35 -06:00
package lila.activity
2017-07-23 09:11:02 -06:00
import org.joda.time.{ DateTime, Interval }
2020-08-23 01:13:34 -06:00
import lila.common.Heapsort
2021-09-15 01:41:10 -06:00
import lila.db.AsyncCollFailingSilently
2017-07-18 16:29:35 -06:00
import lila.db.dsl._
2019-12-03 18:56:07 -07:00
import lila.game.LightPov
2017-07-19 18:13:20 -06:00
import lila.practice.PracticeStructure
import lila.swiss.Swiss
2021-09-01 01:26:15 -06:00
import lila.tournament.LeaderboardApi
import lila.ublog.UblogPost
import lila.user.User
2017-07-18 16:29:35 -06:00
2017-07-19 16:44:03 -06:00
final class ActivityReadApi(
2021-09-15 01:41:10 -06:00
coll: AsyncCollFailingSilently,
2019-12-03 18:56:07 -07:00
gameRepo: lila.game.GameRepo,
2017-07-19 18:13:20 -06:00
practiceApi: lila.practice.PracticeApi,
2021-08-31 05:10:05 -06:00
forumPostApi: lila.forum.PostApi,
ublogApi: lila.ublog.UblogApi,
2017-07-21 04:49:54 -06:00
simulApi: lila.simul.SimulApi,
2017-07-22 01:27:50 -06:00
studyApi: lila.study.StudyApi,
tourLeaderApi: lila.tournament.LeaderboardApi,
swissApi: lila.swiss.SwissApi
)(implicit ec: scala.concurrent.ExecutionContext) {
2017-07-18 16:29:35 -06:00
import BSONHandlers._
import model._
2017-07-18 16:29:35 -06:00
2019-12-13 07:30:20 -07:00
implicit private val ordering = scala.math.Ordering.Double.TotalOrdering
2019-12-08 10:35:26 -07:00
def recent(u: User): Fu[Vector[ActivityView]] =
2019-12-13 07:30:20 -07:00
for {
2020-05-05 22:11:15 -06:00
activities <-
2021-09-15 00:37:33 -06:00
coll(
_.find(regexId(u.id))
.sort($sort desc "_id")
.cursor[Activity]()
.vector(Activity.recentNb)
2021-09-15 00:37:33 -06:00
).dmap(_.filterNot(_.isEmpty))
2020-05-05 22:11:15 -06:00
.mon(_.user segment "activity.raws")
2019-12-13 07:30:20 -07:00
practiceStructure <- activities.exists(_.practice.isDefined) ?? {
2019-12-15 11:41:47 -07:00
practiceApi.structure.get dmap some
2019-12-13 07:30:20 -07:00
}
2019-12-21 16:26:42 -07:00
views <- activities.map { a =>
one(practiceStructure, a).mon(_.user segment "activity.view")
}.sequenceFu
2019-12-13 07:30:20 -07:00
} yield addSignup(u.createdAt, views)
2017-07-19 16:44:03 -06:00
2019-12-21 16:26:42 -07:00
private def one(practiceStructure: Option[PracticeStructure], a: Activity): Fu[ActivityView] =
2019-12-13 07:30:20 -07:00
for {
2021-08-31 05:10:05 -06:00
forumPosts <- a.forumPosts ?? { p =>
forumPostApi
2019-12-21 16:26:42 -07:00
.liteViewsByIds(p.value.map(_.value))
.mon(_.user segment "activity.posts") dmap some
}
2021-08-31 05:10:05 -06:00
ublogPosts <- a.ublogPosts ?? { p =>
2021-09-01 01:26:15 -06:00
ublogApi
.liveLightsByIds(p.value.map(_.value).map(UblogPost.Id))
.mon(_.user segment "activity.ublogs")
.dmap(_.some.filter(_.nonEmpty))
2021-08-31 05:10:05 -06:00
}
2019-12-13 07:30:20 -07:00
practice = (for {
2020-09-21 01:28:28 -06:00
p <- a.practice
struct <- practiceStructure
} yield p.value flatMap { case (studyId, nb) =>
struct study studyId map (_ -> nb)
} toMap)
2021-09-01 01:26:15 -06:00
forumPostView = forumPosts.map { p =>
2019-12-13 07:30:20 -07:00
p.groupBy(_.topic)
.view
.mapValues { posts =>
posts.view.map(_.post).sortBy(_.createdAt).toList
}
.toMap
} filter (_.nonEmpty)
corresMoves <- a.corres ?? { corres =>
getLightPovs(a.id.userId, corres.movesIn) dmap {
_.map(corres.moves -> _)
}
}
2019-12-13 07:30:20 -07:00
corresEnds <- a.corres ?? { corres =>
getLightPovs(a.id.userId, corres.end) dmap {
_.map { povs =>
Score.make(povs) -> povs
}
}
2017-07-22 01:27:50 -06:00
}
2020-05-05 22:11:15 -06:00
simuls <-
a.simuls
.?? { simuls =>
simulApi byIds simuls.value.map(_.value) dmap some
}
.dmap(_.filter(_.nonEmpty))
2020-05-05 22:11:15 -06:00
studies <-
a.studies
.?? { studies =>
studyApi publicIdNames studies.value dmap some
}
.dmap(_.filter(_.nonEmpty))
2019-12-13 07:30:20 -07:00
tours <- a.games.exists(_.hasNonCorres) ?? {
val dateRange = a.date -> a.date.plusDays(1)
2019-12-21 16:26:42 -07:00
tourLeaderApi
.timeRange(a.id.userId, dateRange)
.dmap { entries =>
entries.nonEmpty option ActivityView.Tours(
nb = entries.size,
2020-08-23 01:13:34 -06:00
best = Heapsort.topN(
entries,
activities.maxSubEntries,
Ordering.by[LeaderboardApi.Entry, Double](-_.rankRatio.value)
)
2019-12-21 16:26:42 -07:00
)
}
.mon(_.user segment "activity.tours")
2019-12-13 07:30:20 -07:00
}
swisses <-
a.swisses
.?? { swisses =>
toSwissesView(swisses.value).dmap(_.some.filter(_.nonEmpty))
}
2019-12-13 07:30:20 -07:00
} yield ActivityView(
interval = a.interval,
games = a.games,
puzzles = a.puzzles,
2021-01-26 10:15:47 -07:00
storm = a.storm,
2021-03-19 07:37:28 -06:00
racer = a.racer,
2021-03-28 11:51:40 -06:00
streak = a.streak,
2019-12-13 07:30:20 -07:00
practice = practice,
2021-09-01 01:26:15 -06:00
forumPosts = forumPostView,
ublogPosts = ublogPosts,
2019-12-13 07:30:20 -07:00
simuls = simuls,
patron = a.patron,
corresMoves = corresMoves,
corresEnds = corresEnds,
follows = a.follows,
studies = studies,
teams = a.teams,
tours = tours,
swisses = swisses,
2019-12-13 07:30:20 -07:00
stream = a.stream
)
2017-07-23 09:11:02 -06:00
def recentSwissRanks(userId: User.ID): Fu[List[(Swiss.IdName, Int)]] =
2021-09-15 00:37:33 -06:00
coll(
_.find(regexId(userId) ++ $doc(BSONHandlers.ActivityFields.swisses $exists true))
.sort($sort desc "_id")
.cursor[Activity]()
2021-09-15 00:37:33 -06:00
.list(10)
).flatMap { activities =>
toSwissesView(activities.flatMap(_.swisses.??(_.value)))
}
private def toSwissesView(swisses: List[activities.SwissRank]): Fu[List[(Swiss.IdName, Int)]] =
swissApi
.idNames(swisses.map(_.id))
.map {
_.flatMap { idName =>
swisses.find(_.id == idName.id) map { s =>
(idName, s.rank)
}
}
}
2017-07-23 09:11:02 -06:00
private def addSignup(at: DateTime, recent: Vector[ActivityView]) = {
val (found, views) = recent.foldLeft(false -> Vector.empty[ActivityView]) {
case ((false, as), a) if a.interval contains at => (true, as :+ a.copy(signup = true))
2019-12-13 07:30:20 -07:00
case ((found, as), a) => (found, as :+ a)
2017-07-23 09:11:02 -06:00
}
if (!found && views.sizeIs < Activity.recentNb && DateTime.now.minusDays(8).isBefore(at))
2017-07-23 09:11:02 -06:00
views :+ ActivityView(
interval = new Interval(at.withTimeAtStartOfDay, at.withTimeAtStartOfDay plusDays 1),
signup = true
)
else views
}
2017-07-19 14:37:50 -06:00
2019-12-13 07:30:20 -07:00
private def getLightPovs(userId: User.ID, gameIds: List[GameId]): Fu[Option[List[LightPov]]] =
gameIds.nonEmpty ?? {
gameRepo.light.gamesFromSecondary(gameIds.map(_.value)).dmap {
_.flatMap { LightPov.ofUserId(_, userId) }.some.filter(_.nonEmpty)
}
}
2017-07-18 16:29:35 -06:00
}