Skip to content

Commit

Permalink
Merge branch 'master' into reset-practice-confirm
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar authored Oct 30, 2024
2 parents f5a116e + f2e0879 commit 3de65c9
Show file tree
Hide file tree
Showing 32 changed files with 202 additions and 86 deletions.
13 changes: 9 additions & 4 deletions app/controllers/User.scala
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,10 @@ final class User(
ctx: Context,
me: Me
): Fu[Result] =
env.user.api.withPerfsAndEmails(username).orFail(s"No such user $username").flatMap {
case WithPerfsAndEmails(user, emails) =>
env.report.api.inquiries
.ofModId(me.id)
.zip(env.user.api.withPerfsAndEmails(username).orFail(s"No such user $username"))
.flatMap { case (inquiry, WithPerfsAndEmails(user, emails)) =>
import views.mod.{ user as ui }
import lila.ui.ScalatagsExtensions.{ emptyFrag, given }
given lila.mod.IpRender.RenderIp = env.mod.ipRender.apply
Expand All @@ -356,7 +358,10 @@ final class User(

val timeline = env.api.modTimeline
.load(user, withPlayBans = true)
.map(views.mod.timeline.renderGeneral)
.map: tl =>
if inquiry.exists(_.isPlay)
then views.mod.timeline.renderPlay(tl)
else views.mod.timeline.renderGeneral(tl)
.map(lila.mod.ui.mzSection("timeline")(_))

val plan =
Expand Down Expand Up @@ -444,7 +449,7 @@ final class User(
.log("User.renderModZone")
.as(ContentTypes.EVENT_STREAM)
.pipe(noProxyBuffer)
}
}

protected[controllers] def renderModZoneActions(username: UserStr)(using ctx: Context) =
env.user.api.withPerfsAndEmails(username).orFail(s"No such user $username").flatMap {
Expand Down
14 changes: 11 additions & 3 deletions modules/api/src/main/ModTimeline.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,21 @@ object ModTimeline:
case Play
object Angle:
def filter(e: Event)(using angle: Angle): Boolean = e match
case _: PlayBans => angle != Angle.Comm
case l: Modlog if l.action == Modlog.chatTimeout && angle != Angle.Comm => false
case _: PlayBans => angle != Angle.Comm
case l: Modlog if l.action == Modlog.chatTimeout => angle == Angle.Comm
case l: Modlog if l.action == Modlog.deletePost => angle != Angle.Play
case l: Modlog if l.action == Modlog.disableTeam => angle != Angle.Play
case l: Modlog if l.action == Modlog.teamKick => angle != Angle.Play
case l: Modlog if l.action == Modlog.blankedPassword => angle == Angle.None
case l: Modlog if l.action == Modlog.weakPassword => angle == Angle.None
case l: Modlog if l.action == Modlog.troll => angle != Angle.Play
case l: Modlog if l.action == Modlog.modMessage =>
angle match
case Comm => !l.details.has(lila.playban.PlaybanFeedback.sittingAutoPreset.name)
case _ => true
case _ => true
case r: ReportNewAtom if r.report.is(_.Comm) => angle != Angle.Play
case _: PublicLine => angle != Angle.Play
case _ => true

final class ModTimelineApi(
modLogApi: ModlogApi,
Expand Down
3 changes: 1 addition & 2 deletions modules/fide/src/main/FidePlayer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ case class FidePlayer(
blitz: Option[Elo],
blitzK: Option[KFactor],
year: Option[Int],
inactive: Boolean,
fetchedAt: Instant
inactive: Boolean
) extends lila.core.fide.Player:

def ratingOf(tc: FideTC): Option[Elo] = tc match
Expand Down
19 changes: 4 additions & 15 deletions modules/fide/src/main/FidePlayerSync.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,11 @@ final private class FidePlayerSync(repo: FideRepo, ws: StandaloneWSClient)(using
.mapAsync(1)(saveIfChanged)
.runWith(lila.common.LilaStream.sinkSum)
.monSuccess(_.fideSync.time)
_ = lila.mon.fideSync.updated.update(nbUpdated)
nbAll <- repo.player.countAll
_ = lila.mon.fideSync.players.update(nbAll)
nbDeleted <- setDeletedFlags(startAt)
yield
lila.mon.fideSync.deleted.update(nbDeleted)
logger.info(s"RelayFidePlayerApi.update upserted: $nbUpdated, deleted: $nbDeleted")
lila.mon.fideSync.updated.update(nbUpdated)
lila.mon.fideSync.players.update(nbAll)
logger.info(s"RelayFidePlayerApi.update upserted: $nbUpdated, total: $nbAll")
yield ()

/*
Expand Down Expand Up @@ -161,8 +159,7 @@ final private class FidePlayerSync(repo: FideRepo, ws: StandaloneWSClient)(using
blitz = rating(139),
blitzK = kFactor(149),
year = year,
inactive = flags.exists(_.contains("i")),
fetchedAt = nowInstant
inactive = flags.exists(_.contains("i"))
)

private def saveIfChanged(players: Seq[FidePlayer]): Future[Int] =
Expand All @@ -183,11 +180,3 @@ final private class FidePlayerSync(repo: FideRepo, ws: StandaloneWSClient)(using
)
_ <- elements.nonEmpty.so(update.many(elements).void)
yield elements.size

private def setDeletedFlags(date: Instant): Fu[Int] = for
nbDeleted <- repo.playerColl.update
.one($doc("deleted".$ne(true), "fetchedAt".$lt(date)), $set("deleted" -> true), multi = true)
.map(_.n)
_ <- repo.playerColl.update
.one($doc("deleted" -> true, "fetchedAt".$gte(date)), $unset("deleted"), multi = true)
yield nbDeleted
2 changes: 1 addition & 1 deletion modules/fide/src/main/FideRepo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final private class FideRepo(

object player:
given handler: BSONDocumentHandler[FidePlayer] = Macros.handler
val selectActive: Bdoc = $doc("deleted".$ne(true), "inactive".$ne(true))
val selectActive: Bdoc = $doc("inactive".$ne(true))
def selectFed(fed: hub.Federation.Id): Bdoc = $doc("fed" -> fed)
def sortStandard: Bdoc = $sort.desc("standard")
def fetch(id: FideId): Fu[Option[FidePlayer]] = playerColl.byId[FidePlayer](id)
Expand Down
1 change: 1 addition & 0 deletions modules/puzzle/src/main/PuzzleBatch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ final class PuzzleBatch(colls: PuzzleColls, anonApi: PuzzleAnon, pathApi: Puzzle
me.foldUse(anonApi.getBatchFor(angle, difficulty, nb)): me ?=>
val tier =
if perf.nb > 5000 then PuzzleTier.good
else if angle.opening.isDefined then PuzzleTier.good
else if PuzzleDifficulty.isExtreme(difficulty) then PuzzleTier.good
else PuzzleTier.top
pathApi
Expand Down
4 changes: 1 addition & 3 deletions modules/puzzle/src/main/PuzzleFinisher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,7 @@ final private[puzzle] class PuzzleFinisher(
if player.clueless then glicko._1
else glicko._1.average(glicko._2, weightOf(angle, win))

private val VOLATILITY = lila.rating.Glicko.default.volatility
private val TAU = 0.75d
private val calculator = glicko2.RatingCalculator(VOLATILITY, TAU)
private val calculator = glicko2.RatingCalculator()

def incPuzzlePlays(puzzleId: PuzzleId): Funit =
colls.puzzle.map(_.incFieldUnchecked($id(puzzleId), Puzzle.BSONFields.plays))
Expand Down
5 changes: 2 additions & 3 deletions modules/rating/src/main/Glicko.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object Glicko:
val defaultVolatility = 0.09d

// Chosen so a typical player's RD goes from 60 -> 110 in 1 year
val ratingPeriodsPerDay = 0.21436d
val ratingPeriodsPerDay = glicko2.RatingPeriodsPerDay(0.21436d)

val default = new Glicko(1500d, maxDeviation, defaultVolatility)

Expand All @@ -76,8 +76,7 @@ object Glicko:
// rating that can be lost or gained with a single game
val maxRatingDelta = 700

val tau = 0.75d
val system = glicko2.RatingCalculator(tau, ratingPeriodsPerDay)
val system = glicko2.RatingCalculator(glicko2.Tau.default, ratingPeriodsPerDay)

def liveDeviation(p: Perf, reverse: Boolean): Double = {
system.previewDeviation(p.toRating, nowInstant, reverse)
Expand Down
23 changes: 16 additions & 7 deletions modules/rating/src/main/glicko2/RatingCalculator.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package lila.rating
package glicko2

opaque type Tau = Double
object Tau extends OpaqueDouble[Tau]:
val default: Tau = 0.75d

opaque type RatingPeriodsPerDay = Double
object RatingPeriodsPerDay extends OpaqueDouble[RatingPeriodsPerDay]:
val default: RatingPeriodsPerDay = 0d

// rewrite from java https://github.com/goochjs/glicko2
object RatingCalculator:

Expand All @@ -20,18 +28,18 @@ object RatingCalculator:
(ratingDeviation / MULTIPLIER)

final class RatingCalculator(
tau: Double = 0.75d,
ratingPeriodsPerDay: Double = 0
tau: Tau = Tau.default,
ratingPeriodsPerDay: RatingPeriodsPerDay = RatingPeriodsPerDay.default
):

import RatingCalculator.*

val DEFAULT_DEVIATION: Double = 350
val CONVERGENCE_TOLERANCE: Double = 0.000001
val ITERATION_MAX: Int = 1000
val DAYS_PER_MILLI: Double = 1.0 / (1000 * 60 * 60 * 24)
private val DEFAULT_DEVIATION: Double = 350
private val CONVERGENCE_TOLERANCE: Double = 0.000001
private val ITERATION_MAX: Int = 1000
private val DAYS_PER_MILLI: Double = 1.0 / (1000 * 60 * 60 * 24)

val ratingPeriodsPerMilli: Double = ratingPeriodsPerDay * DAYS_PER_MILLI
private val ratingPeriodsPerMilli: Double = ratingPeriodsPerDay.value * DAYS_PER_MILLI

/** <p>Run through all players within a resultset and calculate their new ratings.</p> <p>Players within the
* resultset who did not compete during the rating period will have see their deviation increase (in line
Expand Down Expand Up @@ -89,6 +97,7 @@ final class RatingCalculator(
val a = Math.log(Math.pow(sigma, 2))
val delta = deltaOf(player, results)
val v = vOf(player, results)
val tau = this.tau.value

// step 5.2 - set the initial values of the iterative algorithm to come in step 5.4
var A: Double = a
Expand Down
1 change: 1 addition & 0 deletions modules/report/src/main/Report.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ case class Report(

def isRecentComm = open && room == Room.Comm
def isRecentCommOf(sus: Suspect) = isRecentComm && user == sus.user.id
def isPlay = room == Room.Boost || room == Room.Cheat

def isAppeal = room == Room.Other && atoms.head.text == Report.appealText
def isAppealInquiryByMe(using me: MyId) = isAppeal && atoms.head.by.is(me)
Expand Down
8 changes: 2 additions & 6 deletions modules/tutor/src/main/TutorGlicko.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ object TutorGlicko:
private type Rating = Int
private type Score = Float

private val VOLATILITY = Glicko.default.volatility
private val TAU = 0.75d

def scoresRating(perf: Perf, scores: List[(Rating, Score)]): Rating =
val calculator = glicko2.RatingCalculator(VOLATILITY, TAU)
val calculator = glicko2.RatingCalculator()
val player = perf.toRating
val results = glicko2.FloatingRatingPeriodResults(
scores.map { case (rating, score) =>
scores.map: (rating, score) =>
glicko2.FloatingResult(player, glicko2.Rating(rating, 60, 0.06, 10), score)
}
)

try calculator.updateRatings(results, true)
Expand Down
12 changes: 6 additions & 6 deletions translation/dest/broadcast/de-DE.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@
<string name="openLichess">In Lichess öffnen</string>
<string name="teams">Teams</string>
<string name="boards">Bretter</string>
<string name="overview">Übersicht</string>
<string name="subscribeTitle">Abonnieren, um bei Rundenbeginn benachrichtigt zu werden. Du kannst in deinen Benutzereinstellungen bei Übertragungen zwischen einer Benachrichtigung per Glocke oder Push-Benachrichtigungen wählen.</string>
<string name="overview">Überblick</string>
<string name="subscribeTitle">Abonnieren, um bei Rundenbeginn benachrichtigt zu werden. Du kannst in deinen Benutzereinstellungen für Übertragungen zwischen einer Benachrichtigung per Glocke oder per Push-Benachrichtigung wählen.</string>
<string name="uploadImage">Turnierbild hochladen</string>
<string name="noBoardsYet">Noch keine Bretter vorhanden. Diese werden angezeigt, sobald die Partien hochgeladen werden.</string>
<string name="boardsCanBeLoaded" comment="%s is 'Broadcaster App'">Die Bretter können per Quelle oder via %s geladen werden</string>
<string name="boardsCanBeLoaded" comment="%s is 'Broadcaster App', and links to https://lichess.org/broadcast/app">Die Bretter können per Quelle oder via %s geladen werden</string>
<string name="startsAfter">Beginnt nach %s</string>
<string name="startVerySoon">Diese Übertragung wird in Kürze beginnen.</string>
<string name="notYetStarted">Die Übertragung hat noch nicht begonnen.</string>
<string name="officialWebsite">Offizielle Webseite</string>
<string name="standings">Rangliste</string>
<string name="iframeHelp" comment="%s is 'webmasters page'">Weitere Optionen auf der %s</string>
<string name="webmastersPage">Webmaster-Seite</string>
<string name="iframeHelp" comment="%s is 'webmasters page', which is available for translation separately.&#10;&#10;Appears on broadcast pages for the person who set up the tournament broadcast.">Weitere Optionen auf der %s</string>
<string name="webmastersPage" comment="Part of the longer string iframeHelp.&#10;&#10;Appears on broadcast pages for the person who set up the tournament broadcast. Links to https://lichess.org/developers#broadcast">Webmaster-Seite</string>
<string name="pgnSourceHelp" comment="%s is 'streaming API'">Eine öffentliche Echtzeit-PGN-Quelle für diese Runde. Wir bieten auch eine %s für eine schnellere und effizientere Synchronisation.</string>
<string name="embedThisBroadcast">Bette diese Übertragung in deine Webseite ein</string>
<string name="embedThisRound" comment="%s is &quot;this round&quot;">Bette %s in deine Webseite ein</string>
<string name="embedThisRound" comment="%s is the name of the round in the broadcasted tournament (e.g. &quot;Round 6&quot;). The round name is defined by the creator of the broadcast and may be in a different language.">Bette %s in deine Webseite ein</string>
<string name="ratingDiff">Wertungsdifferenz</string>
<string name="gamesThisTournament">Partien in diesem Turnier</string>
<string name="score">Punktestand</string>
Expand Down
21 changes: 21 additions & 0 deletions translation/dest/broadcast/ko-KR.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,25 @@
<string name="ageThisYear">올해 나이</string>
<string name="unrated">비레이팅</string>
<string name="recentTournaments">최근 토너먼트</string>
<string name="openLichess">Lichess에서 열기</string>
<string name="teams">팀</string>
<string name="boards">보드</string>
<string name="overview">개요</string>
<string name="subscribeTitle">라운드가 시작될 때 알림을 받으려면 구독하세요. 계정 설정에서 방송을 위한 벨이나 알림 푸시를 토글할 수 있습니다.</string>
<string name="uploadImage">토너먼트 사진 업로드</string>
<string name="noBoardsYet">아직 보드가 없습니다. 게임들이 업로드되면 나타납니다.</string>
<string name="boardsCanBeLoaded" comment="%s is 'Broadcaster App', and links to https://lichess.org/broadcast/app">보드들은 소스나 %s(으)로 로드될 수 있습니다</string>
<string name="startsAfter">%s 후 시작</string>
<string name="startVerySoon">방송이 곧 시작됩니다.</string>
<string name="notYetStarted">아직 방송이 시작을 하지 않았습니다.</string>
<string name="officialWebsite">공식 웹사이트</string>
<string name="standings">순위</string>
<string name="iframeHelp" comment="%s is 'webmasters page', which is available for translation separately.&#10;&#10;Appears on broadcast pages for the person who set up the tournament broadcast.">%s에서 더 많은 정보를 확인하실 수 있습니다</string>
<string name="webmastersPage" comment="Part of the longer string iframeHelp.&#10;&#10;Appears on broadcast pages for the person who set up the tournament broadcast. Links to https://lichess.org/developers#broadcast">웹마스터 페이지</string>
<string name="pgnSourceHelp" comment="%s is 'streaming API'">이 라운드의 공개된, 실시간 PGN 소스 입니다. 보다 더 빠르고 효율적인 동기화를 위해 %s도 제공됩니다.</string>
<string name="embedThisBroadcast">이 방송을 웹사이트에 삼입하세요</string>
<string name="embedThisRound" comment="%s is the name of the round in the broadcasted tournament (e.g. &quot;Round 6&quot;). The round name is defined by the creator of the broadcast and may be in a different language.">%s을(를) 웹사이트에 삼입하세요</string>
<string name="ratingDiff">레이팅 차이</string>
<string name="gamesThisTournament">이 토너먼트의 게임들</string>
<string name="score">점수</string>
</resources>
21 changes: 21 additions & 0 deletions translation/dest/broadcast/nb-NO.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,25 @@
<string name="ageThisYear">Alder i år</string>
<string name="unrated">Uratet</string>
<string name="recentTournaments">Nylige turneringer</string>
<string name="openLichess">Åpne i Lichess</string>
<string name="teams">Lag</string>
<string name="boards">Brett</string>
<string name="overview">Oversikt</string>
<string name="subscribeTitle">Abonner for å bli varslet når hver runde starter. Du kan velge varselform i kontoinnstillingene dine.</string>
<string name="uploadImage">Last opp bilde for turneringen</string>
<string name="noBoardsYet">Ingen brett. De vises når partiene er lastet opp.</string>
<string name="boardsCanBeLoaded" comment="%s is 'Broadcaster App', and links to https://lichess.org/broadcast/app">Brett kan lastes med en kilde eller via %s</string>
<string name="startsAfter">Starter etter %s</string>
<string name="startVerySoon">Overføringen starter straks.</string>
<string name="notYetStarted">Overføringen har ikke startet.</string>
<string name="officialWebsite">Offisiell nettside</string>
<string name="standings">Resultatliste</string>
<string name="iframeHelp" comment="%s is 'webmasters page'">Flere alternativer på %s</string>
<string name="webmastersPage">administratorens side</string>
<string name="pgnSourceHelp" comment="%s is 'streaming API'">En offentlig PGN-kilde i sanntid for denne runden. Vi tilbyr også en %s for raskere og mer effektiv synkronisering.</string>
<string name="embedThisBroadcast">Bygg inn denne overføringen på nettstedet ditt</string>
<string name="embedThisRound" comment="%s is the name of the round in the broadcasted tournament (e.g. &quot;Round 6&quot;). The round name is defined by the creator of the broadcast and may be in a different language.">Bygg inn %s på nettstedet ditt</string>
<string name="ratingDiff">Ratingdifferanse</string>
<string name="gamesThisTournament">Partier i denne turneringen</string>
<string name="score">Poengsum</string>
</resources>
4 changes: 4 additions & 0 deletions translation/dest/broadcast/ro-RO.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@
<string name="ageThisYear">Vârsta în acest an</string>
<string name="unrated">Fără rating</string>
<string name="recentTournaments">Turnee recente</string>
<string name="openLichess">Deschide în Lichess</string>
<string name="teams">Echipe</string>
<string name="standings">Clasament</string>
<string name="score">Scor</string>
</resources>
Loading

0 comments on commit 3de65c9

Please sign in to comment.