Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
891edb8
rename UserPerfs
ornicar Jun 29, 2023
be5c3ff
extract user.perfs to user_perf collection WIP
ornicar Jun 29, 2023
a93aee1
Merge branch 'master' into user-perfs
ornicar Jun 30, 2023
4351961
Merge branch 'master' into user-perfs
ornicar Jun 30, 2023
10c48b0
Merge branch 'user-perfs' of github.com:lichess-org/lila into user-perfs
ornicar Jun 30, 2023
fc49606
UserPerfs WIP
ornicar Jun 30, 2023
335aa91
Merge branch 'master' into user-perfs
ornicar Jun 30, 2023
3b81c8d
UserPerfs WIP
ornicar Jun 30, 2023
527635e
Merge branch 'user-perfs' of github.com:lichess-org/lila into user-perfs
ornicar Jun 30, 2023
8a74402
Merge remote-tracking branch 'origin/master' into user-perfs
ornicar Jul 1, 2023
da70011
UserPerfs WIP
ornicar Jul 1, 2023
3b71b91
Merge branch 'master' into user-perfs
ornicar Jul 1, 2023
6731e8e
Merge branch 'master' into user-perfs
ornicar Jul 2, 2023
36f74e9
UserPerfs WIP
ornicar Jul 2, 2023
2060630
UserPerfs WIP, remove PerfPicker
ornicar Jul 2, 2023
306d11f
UserPerfs WIP
ornicar Jul 2, 2023
7958f0a
UserPerfs WIP
ornicar Jul 2, 2023
e85d0f7
Merge branch 'master' into user-perfs
ornicar Jul 2, 2023
8a2a1ed
UserPerfs WIP, Option.soFu
ornicar Jul 2, 2023
98e6243
use Option.soFu some more
ornicar Jul 3, 2023
2d563ad
UserPerfs WIP
ornicar Jul 3, 2023
e55d5d3
Merge remote-tracking branch 'origin/master' into user-perfs
ornicar Jul 3, 2023
b50237f
fix setup controller
ornicar Jul 3, 2023
12da21d
UserPerfs WIP
ornicar Jul 4, 2023
11f225f
UserPerfs WIP
ornicar Jul 4, 2023
ee82eeb
Merge remote-tracking branch 'origin/master' into user-perfs
ornicar Jul 4, 2023
8c29289
fix bogus embedded links
ornicar Jul 4, 2023
94a3cd8
Merge remote-tracking branch 'origin/master' into user-perfs
ornicar Jul 5, 2023
634bd28
UserPerfs WIP
ornicar Jul 5, 2023
4dd53bc
UserPerfs: it compiles!
ornicar Jul 5, 2023
aa8f0fb
tweak coach list CSS
ornicar Jul 5, 2023
1704acf
scala tweaks
ornicar Jul 5, 2023
d3b3f37
avoid loading streamer perfs on the list page
ornicar Jul 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/controllers/Account.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ final class Account(
povs <- env.round.proxyRepo urgentGames me
nbChallenges <- env.challenge.api.countInFor get me
playban <- env.playban.api currentBan me
perfs <- ctx.pref.showRatings.soFu(env.user.perfsRepo.perfsOf(me))
yield Ok:
env.user.jsonView
.full(me, withRating = ctx.pref.showRatings, withProfile = false) ++ Json
.full(me, perfs, withProfile = false) ++ Json
.obj(
"prefs" -> lila.pref.JsonView.write(ctx.pref, lichobileCompat = HTTPRequest.isLichobile(req)),
"nowPlaying" -> JsArray(povs take 50 map env.api.lobbyApi.nowPlaying),
Expand All @@ -86,8 +87,7 @@ final class Account(
"Please don't poll this endpoint. Stream https://lichess.org/api#tag/Board/operation/apiStreamEvent instead."
rateLimit(me, limited):
env.api.userApi.extended(
me,
me.some,
me.value,
withFollows = apiC.userWithFollows,
withTrophies = false
) dmap { JsonOk(_) }
Expand Down
5 changes: 2 additions & 3 deletions app/controllers/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ final class Api(
userRateLimit(ctx.ip, rateLimited):
userApi.extended(
name,
ctx.me,
withFollows = userWithFollows,
withTrophies = getBool("trophies")
) map toApiResult map toHttp
Expand All @@ -61,8 +60,8 @@ final class Api(
val cost = usernames.size / 4
UsersRateLimitPerIP(req.ipAddress, rateLimited, cost = cost):
lila.mon.api.users.increment(cost.toLong)
env.user.repo byIds usernames map {
_.map { env.user.jsonView.full(_, none, withRating = true, withProfile = true) }
env.user.api.listWithPerfs(usernames) map {
_.map { u => env.user.jsonView.full(u.user, u.perfs.some, withProfile = true) }
} map toApiResult map toHttp

def usersStatus = ApiRequest:
Expand Down
20 changes: 8 additions & 12 deletions app/controllers/Auth.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,14 @@ final class Auth(
private def api = env.security.api
private def forms = env.security.forms

private def mobileUserOk(u: UserModel, sessionId: String)(using Context): Fu[Result] =
env.round.proxyRepo urgentGames u map { povs =>
Ok:
env.user.jsonView.full(
u,
withRating = ctx.pref.showRatings,
withProfile = true
) ++ Json.obj(
"nowPlaying" -> JsArray(povs take 20 map env.api.lobbyApi.nowPlaying),
"sessionId" -> sessionId
)
}
private def mobileUserOk(u: UserModel, sessionId: String)(using Context): Fu[Result] = for
povs <- env.round.proxyRepo urgentGames u
perfs <- ctx.pref.showRatings.soFu(env.user.perfsRepo perfsOf u)
yield Ok:
env.user.jsonView.full(u, perfs, withProfile = true) ++ Json.obj(
"nowPlaying" -> JsArray(povs take 20 map env.api.lobbyApi.nowPlaying),
"sessionId" -> sessionId
)

private def getReferrerOption(using ctx: Context): Option[String] =
get("referrer").flatMap(env.api.referrerRedirect.valid) orElse
Expand Down
54 changes: 28 additions & 26 deletions app/controllers/Challenge.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ final class Challenge(
case None => Ok.page(html.challenge.mine(c, json, none, color))
else
Ok.pageAsync:
(c.challengerUserId so env.user.repo.byId) map {
c.challengerUserId.so(env.user.api.withPerf(_, c.perfType)).map {
html.challenge.theirs(c, json, _, color)
}
,
Expand All @@ -88,7 +88,7 @@ final class Challenge(
val cc = color flatMap chess.Color.fromName
isForMe(c) so api
.accept(c, ctx.req.sid, cc)
.flatMap {
.flatMap:
case Validated.Valid(Some(pov)) =>
negotiateApi(
html = Redirect(routes.Round.watcher(pov.gameId, cc.fold("white")(_.name))),
Expand All @@ -102,7 +102,6 @@ final class Challenge(
case _ => "The challenge has already been accepted"
)
)
}

def apiAccept(id: ChallengeId) =
Scoped(_.Challenge.Write, _.Bot.Play, _.Board.Play) { _ ?=> me ?=>
Expand Down Expand Up @@ -267,7 +266,7 @@ final class Challenge(
case None => Redirect(routes.Challenge.show(c.id))
case Some(dest) if ctx.is(dest) => Redirect(routes.Challenge.show(c.id))
case Some(dest) =>
env.challenge.granter.isDenied(ctx.me, dest, c.perfType.some) flatMap {
env.challenge.granter.isDenied(dest, c.perfType) flatMap {
case Some(denied) =>
showChallenge(c, lila.challenge.ChallengeDenied.translated(denied).some)
case None => api.setDestUser(c, dest) inject Redirect(routes.Challenge.show(c.id))
Expand All @@ -291,44 +290,47 @@ final class Challenge(
val cost = if me.isApiHog then 0 else if destUser.isBot then 1 else 5
BotChallengeIpRateLimit(req.ipAddress, rateLimited, cost = if me.isBot then 1 else 0):
ChallengeUserRateLimit(me, rateLimited, cost = cost):
val challenge = makeOauthChallenge(config, me, destUser)
env.challenge.granter
.isDenied(me.some, destUser, config.perfType)
.flatMap:
for
challenge <- makeOauthChallenge(config, me, destUser)
grant <- env.challenge.granter.isDenied(destUser, config.perfType)
res <- grant match
case Some(denied) =>
JsonBadRequest:
jsonError(lila.challenge.ChallengeDenied.translated(denied))
fuccess:
JsonBadRequest:
jsonError(lila.challenge.ChallengeDenied.translated(denied))
case _ =>
env.challenge.api create challenge map {
if _ then
val json = env.challenge.jsonView
.show(challenge, SocketVersion(0), lila.challenge.Direction.Out.some)
if config.keepAliveStream
then
apiC.sourceToNdJsonOption(
if config.keepAliveStream then
apiC.sourceToNdJsonOption:
apiC.addKeepAlive(env.challenge.keepAliveStream(challenge, json))
)
else JsonOk(json)
else JsonBadRequest(jsonError("Challenge not created"))
}
yield res
}
)
}

private def makeOauthChallenge(config: ApiConfig, orig: UserModel, dest: UserModel) =
import lila.challenge.Challenge.*
val timeControl = TimeControl.make(config.clock, config.days)
lila.challenge.Challenge.make(
variant = config.variant,
initialFen = config.position,
timeControl = timeControl,
mode = config.mode,
color = config.color.name,
challenger = ChallengeModel.toRegistered(config.variant, timeControl)(orig),
destUser = dest.some,
rematchOf = none,
rules = config.rules
)
env.user.perfsRepo
.withPerfs(orig -> dest, _.sec)
.map: (orig, dest) =>
lila.challenge.Challenge.make(
variant = config.variant,
initialFen = config.position,
timeControl = timeControl,
mode = config.mode,
color = config.color.name,
challenger = ChallengeModel.toRegistered(config.variant, timeControl)(orig),
destUser = dest.some,
rematchOf = none,
rules = config.rules
)

def openCreate = AnonOrScopedBody(parse.anyContent)(_.Challenge.Write): ctx ?=>
env.setup.forms.api.open
Expand All @@ -353,7 +355,7 @@ final class Challenge(
NoBot:
Found(env.game.gameRepo game gameId): g =>
Pov.opponentOf(g, me).flatMap(_.userId) so env.user.repo.byId orNotFound { opponent =>
env.challenge.granter.isDenied(me.some, opponent, g.perfType) flatMap {
env.challenge.granter.isDenied(opponent, g.perfType) flatMap {
case Some(d) => BadRequest(jsonError(lila.challenge.ChallengeDenied translated d))
case _ =>
api.offerRematchForGame(g, me) map {
Expand Down
47 changes: 25 additions & 22 deletions app/controllers/Clas.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,21 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
def show(id: ClasId) = Auth { ctx ?=> me ?=>
WithClassAny(id)(
forTeacher = WithClass(id): clas =>
env.msg.twoFactorReminder(me) >>
Ok.pageAsync:
env.clas.api.student.activeWithUsers(clas) map { students =>
preloadStudentUsers(students)
views.html.clas.teacherDashboard.overview(clas, students)
}
,
for
_ <- env.msg.twoFactorReminder(me)
students <- env.clas.api.student.activeWithUsers(clas)
_ = preloadStudentUsers(students)
students <- env.clas.api.student.withPerfs(students)
page <- renderPage(views.html.clas.teacherDashboard.overview(clas, students))
yield Ok(page),
forStudent = (clas, students) =>
Ok.pageAsync:
env.clas.api.clas.teachers(clas) map { teachers =>
preloadStudentUsers(students)
for
teachers <- env.clas.api.clas.teachers(clas)
_ = preloadStudentUsers(students)
students <- env.clas.api.student.withPerfs(students)
page <- renderPage:
views.html.clas.studentDashboard(clas, env.clas.markup(clas), teachers, students)
}
,
yield Ok(page),
orDefault = _ =>
isGranted(_.UserModView) so
FoundPage(env.clas.api.clas.byId(id)): clas =>
Expand Down Expand Up @@ -184,12 +185,12 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):

def students(id: ClasId) = Secure(_.Teacher) { ctx ?=> me ?=>
WithClass(id): clas =>
env.clas.api.student.allWithUsers(clas) flatMap { students =>
Ok.pageAsync:
env.clas.api.invite.listPending(clas) map {
views.html.clas.teacherDashboard.students(clas, students, _)
}
}
for
students <- env.clas.api.student.allWithUsers(clas)
students <- env.clas.api.student.withPerfs(students)
invites <- env.clas.api.invite.listPending(clas)
page <- renderPage(views.html.clas.teacherDashboard.students(clas, students, invites))
yield Ok(page)
}

def progress(id: ClasId, key: lila.rating.Perf.Key, days: Int) = Secure(_.Teacher) { ctx ?=> me ?=>
Expand All @@ -199,10 +200,11 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
WithClass(id): clas =>
env.clas.api.student.activeWithUsers(clas) flatMap { students =>
Reasonable(clas, students, "progress"):
Ok.pageAsync:
env.clas.progressApi(perfType, days, students) map {
views.html.clas.teacherDashboard.progress(clas, students, _)
}
for
progress <- env.clas.progressApi(perfType, days, students)
students <- env.clas.api.student.withPerf(students, perfType)
page <- renderPage(views.html.clas.teacherDashboard.progress(clas, students, progress))
yield Ok(page)
}
}

Expand Down Expand Up @@ -376,6 +378,7 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
WithClassAndStudents(id): (clas, students) =>
WithStudent(clas, username): s =>
for
s <- env.clas.api.student.withPerfs(s)
withManagingClas <- env.clas.api.student.withManagingClas(s, clas)
activity <- env.activity.read.recentAndPreload(s.user)
page <- renderPage(views.html.clas.student.show(clas, students, withManagingClas, activity))
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/Learn.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ final class Learn(env: Env) extends LilaController(env):
private def serveIndex(using ctx: Context) = NoBot:
pageHit
ctx.me
.so: me =>
env.learn.api.get(me) map { Json.toJson(_) } map some
.soFu: me =>
env.learn.api.get(me) map Json.toJson
.flatMap: progress =>
Ok.page(html.learn.index(progress))

Expand Down
10 changes: 10 additions & 0 deletions app/controllers/LilaController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,16 @@ abstract private[controllers] class LilaController(val env: Env)
pageHit
f(using ctx.withLang(lang))

import lila.rating.{ Perf, PerfType }
def WithMyPerf[A](pt: PerfType)(f: Perf ?=> Fu[A])(using me: Option[Me]): Fu[A] = me
.soFu(env.user.perfsRepo.perfOf(_, pt))
.flatMap: perf =>
f(using perf | Perf.default)
def WithMyPerfs[A](f: Option[lila.user.User.WithPerfs] ?=> Fu[A])(using me: Option[Me]): Fu[A] = me
.soFu(me => env.user.api.withPerfs(me.value))
.flatMap:
f(using _)

/* We roll our own action, as we don't want to compose play Actions. */
private def action[A](parser: BodyParser[A])(handler: Request[A] ?=> Fu[Result]): EssentialAction = new:
import play.api.libs.streams.Accumulator
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/Lobby.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ final class Lobby(env: Env) extends LilaController(env):

def seeks = Open:
negotiateJson:
ctx.me.foldUse(env.lobby.seekApi.forAnon)(env.lobby.seekApi.forMe) map { seeks =>
ctx.me.foldUse(env.lobby.seekApi.forAnon)(me ?=> env.lobby.seekApi.forMe(using me)) map { seeks =>
Ok(JsArray(seeks.map(_.render))).withHeaders(CACHE_CONTROL -> s"max-age=10")
}

Expand Down
15 changes: 8 additions & 7 deletions app/controllers/Mod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -444,15 +444,16 @@ final class Mod(
val email = query.headOption.flatMap(EmailAddress.from)
val username = query lift 1
def tryWith(setEmail: EmailAddress, q: String): Fu[Option[Result]] =
env.mod.search(q).map(_.filter(_.user.enabled.yes)) flatMap {
env.mod.search(q).map(_.filter(_.user.enabled.yes)).flatMap {
case List(UserModel.WithEmails(user, _)) =>
(!user.everLoggedIn).so {
lila.mon.user.register.modConfirmEmail.increment()
modApi.setEmail(user.id, setEmail)
} >>
env.user.repo.email(user.id).flatMap { email =>
Ok.page(html.mod.emailConfirm("", user.some, email)).dmap(some)
for
_ <- (!user.everLoggedIn).so {
lila.mon.user.register.modConfirmEmail.increment()
modApi.setEmail(user.id, setEmail)
}
email <- env.user.repo.email(user.id)
page <- renderPage(html.mod.emailConfirm("", user.some, email))
yield Ok(page).some
case _ => fuccess(none)
}
email.so { em =>
Expand Down
20 changes: 10 additions & 10 deletions app/controllers/PlayApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final class PlayApi(env: Env, apiC: => Api)(using akka.stream.Materializer) exte
else
env.tournament.api.withdrawAll(me) >>
env.team.cached.teamIdsList(me).flatMap { env.swiss.api.withdrawAll(me, _) } >>
env.user.repo.setBot(me) >>
env.user.api.setBot(me) >>
env.pref.api.setBot(me) >>
env.streamer.api.delete(me) >>-
env.user.lightUserApi.invalidate(me) pipe
Expand Down Expand Up @@ -147,16 +147,16 @@ final class PlayApi(env: Env, apiC: => Api)(using akka.stream.Materializer) exte
}

def botOnline = Open:
Ok.pageAsync:
env.user.repo
.botsByIds(env.bot.onlineApiUsers.get)
.map(views.html.user.bots(_))
for
users <- env.user.repo.botsByIds(env.bot.onlineApiUsers.get)
users <- env.user.perfsRepo.withPerfs(users)
page <- renderPage(views.html.user.bots(users))
yield Ok(page)

def botOnlineApi = Anon:
apiC
.jsonDownload:
env.user.repo
.botsByIdsCursor(env.bot.onlineApiUsers.get)
.documentSource(getInt("nb") | Int.MaxValue)
.throttle(50, 1 second)
.map { env.user.jsonView.full(_, withRating = true, withProfile = true) }
env.user.api
.botsByIdsStream(env.bot.onlineApiUsers.get, getInt("nb"))
.map: u =>
env.user.jsonView.full(u.user, u.perfs.some, withProfile = true)
Loading