diff --git a/app/controllers/User.scala b/app/controllers/User.scala index 170d89fe33..68115ee8ac 100644 --- a/app/controllers/User.scala +++ b/app/controllers/User.scala @@ -177,7 +177,7 @@ object User extends LilaController { def mod(username: String) = Secure(_.UserSpy) { implicit ctx => me => OptionFuOk(UserRepo named username) { user => (Env.security userSpy user.id) zip - (Env.mod.assessApi.getPlayerAggregateAssessment(user.id)) flatMap { + (Env.mod.assessApi.getPlayerAggregateAssessmentWithGames(user.id)) flatMap { case (spy, playerAggregateAssessment) => (Env.playban.api bans spy.otherUsers.map(_.id)) map { bans => html.user.mod(user, spy, playerAggregateAssessment, bans) diff --git a/app/templating/GameHelper.scala b/app/templating/GameHelper.scala index 1e0899ed7a..c9ce711c58 100644 --- a/app/templating/GameHelper.scala +++ b/app/templating/GameHelper.scala @@ -106,7 +106,8 @@ trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHel withDiff: Boolean = true, engine: Boolean = false, withStatus: Boolean = false, - mod: Boolean = false)(implicit ctx: UserContext) = Html { + mod: Boolean = false, + link: Boolean = true)(implicit ctx: UserContext) = Html { val statusIcon = if (withStatus) """""" else "" player.userId.flatMap(lightUser) match { case None => @@ -121,7 +122,8 @@ trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHel val mark = engine ?? s"""""" val dataIcon = withOnline ?? """data-icon="r"""" val space = if (withOnline) " " else "" - s"""$space$content$diff$mark$statusIcon""" + val tag = if (link) "a" else "span" + s"""<$tag $dataIcon $klass href="$href">$space$content$diff$mark$statusIcon""" } } diff --git a/app/views/user/mod.scala.html b/app/views/user/mod.scala.html index ce05c5b98e..56850274fe 100644 --- a/app/views/user/mod.scala.html +++ b/app/views/user/mod.scala.html @@ -1,4 +1,4 @@ -@(u: User, spy: lila.security.UserSpy, optionAggregateAssessment: Option[lila.evaluation.PlayerAggregateAssessment], bans: Map[String, Int])(implicit ctx: Context) +@(u: User, spy: lila.security.UserSpy, optionAggregateAssessment: Option[lila.evaluation.PlayerAggregateAssessment.WithGames], bans: Map[String, Int])(implicit ctx: Context) @import lila.evaluation.Display @@ -57,28 +57,28 @@

- }{ aggregateAssessment => + }{ pag =>
@@ -110,33 +110,33 @@ @@ -144,7 +144,8 @@
- @aggregateAssessment.action.description + @pag.pag.action.description - @aggregateAssessment.playerAssessments.size + @pag.pag.playerAssessments.size - @aggregateAssessment.cheatingSum + @pag.pag.cheatingSum - @aggregateAssessment.likelyCheatingSum + @pag.pag.likelyCheatingSum - @aggregateAssessment.relatedCheatersCount + @pag.pag.relatedCheatersCount - @aggregateAssessment.relatedUsersCount + @pag.pag.relatedUsersCount
Blurs - @aggregateAssessment.sfAvgBlurs + @pag.pag.sfAvgBlurs
high
- @aggregateAssessment.sfAvgNoBlurs + @pag.pag.sfAvgNoBlurs
low
Move Times - @aggregateAssessment.sfAvgLowVar + @pag.pag.sfAvgLowVar
low variance
- @aggregateAssessment.sfAvgHighVar + @pag.pag.sfAvgHighVar
high variance
Hold Alert - @aggregateAssessment.sfAvgHold + @pag.pag.sfAvgHold
alert
- @aggregateAssessment.sfAvgNoHold + @pag.pag.sfAvgNoHold
no alert
- + + - @aggregateAssessment.playerAssessments.sortBy(-_.assessment.id).take(15).map { result => + @pag.pag.playerAssessments.sortBy(-_.assessment.id).take(15).map { result => - + + diff --git a/modules/evaluation/src/main/PlayerAggregateAssessment.scala b/modules/evaluation/src/main/PlayerAggregateAssessment.scala index b9ad11e418..d143db5b8c 100644 --- a/modules/evaluation/src/main/PlayerAggregateAssessment.scala +++ b/modules/evaluation/src/main/PlayerAggregateAssessment.scala @@ -131,6 +131,13 @@ case class PlayerAggregateAssessment( } } +object PlayerAggregateAssessment { + + case class WithGames(pag: PlayerAggregateAssessment, games: List[lila.game.Game]) { + def pov(pa: PlayerAssessment) = games find (_.id == pa.gameId) map { lila.game.Pov(_, pa.color) } + } +} + case class PlayerFlags( suspiciousErrorRate: Boolean, alwaysHasAdvantage: Boolean, diff --git a/modules/mod/src/main/AssessApi.scala b/modules/mod/src/main/AssessApi.scala index e87242889d..707fea853c 100644 --- a/modules/mod/src/main/AssessApi.scala +++ b/modules/mod/src/main/AssessApi.scala @@ -66,6 +66,17 @@ final class AssessApi( } } + def withGames(pag: PlayerAggregateAssessment): Fu[PlayerAggregateAssessment.WithGames] = + GameRepo games pag.playerAssessments.map(_.gameId) map { + PlayerAggregateAssessment.WithGames(pag, _) + } + + def getPlayerAggregateAssessmentWithGames(userId: String, nb: Int = 100): Fu[Option[PlayerAggregateAssessment.WithGames]] = + getPlayerAggregateAssessment(userId, nb) flatMap { + case None => fuccess(none) + case Some(pag) => withGames(pag).map(_.some) + } + def refreshAssessByUsername(username: String): Funit = withUser(username) { user => (GameRepo.gamesForAssessment(user.id, 100) flatMap { gs => (gs map { g => diff --git a/public/stylesheets/user-show.css b/public/stylesheets/user-show.css index d1edcb6c8e..d1259eab5c 100644 --- a/public/stylesheets/user-show.css +++ b/public/stylesheets/user-show.css @@ -258,6 +258,9 @@ div.user_show .mod_zone .slist { font-size: 0.9em; margin-bottom: 1em; } +div.user_show .mod_zone .slist a { + text-decoration: none; +} div.user_show .mod_zone .same { font-style: italic; font-weight: bold; @@ -317,9 +320,6 @@ div.user_show .evaluation .legend { div.user_show .evaluation .legend span { padding: 10px; } -div.user_show .evaluation [data-icon] { - text-shadow: 1px 1px 1px #000; -} div.user_show .evaluation .sig_1 { color: #2077C0; /* dark blue */ @@ -406,9 +406,8 @@ div.user_show .extra_stats td { padding: 5px; } div.user_show .results .aggregate { - text-shadow: 1px -1px 1px #000; font-weight: bold; - font-size: 2.2em; + font-size: 1.4em; text-align: center; margin-left: -20px; width: 50px;
Assessed gameOpponentGame Centi-Pawn
(Avg ± SD) @@ -159,28 +160,49 @@
@routes.Round.watcher(result.gameId, result.color.name) - + + @pag.pov(result).fold{ + @result.gameId + } { p => + @playerLink(p.opponent, withRating = true, withDiff = true, withOnline = false, link = false) + } + + + @pag.pov(result).map { p => + + @if(p.game.isTournament) { + + } + @p.game.perfType.map { pt => + + } + @shortClockName(p.game.clock) + + } + + @result.sfAvg ± @result.sfSd - + @(result.mtAvg/10) ± @(result.mtSd/10) - + @(result.blurs)% - + @if(result.hold){Yes} else {No}
- @result.assessment.emoticon + @result.assessment.emoticon