diff --git a/app/controllers/User.scala b/app/controllers/User.scala
index 913c74c7a9..30d2d076ca 100644
--- a/app/controllers/User.scala
+++ b/app/controllers/User.scala
@@ -12,6 +12,7 @@ import lila.rating.PerfType
import lila.security.Permission
import lila.user.tube.userTube
import lila.user.{ User => UserModel, UserRepo }
+import lila.evaluation.PlayerAggregateAssessment
import views._
object User extends LilaController {
@@ -147,7 +148,7 @@ object User extends LilaController {
def mod(username: String) = Secure(_.UserSpy) { implicit ctx =>
me => OptionFuOk(UserRepo named username) { user =>
(Env.evaluation.evaluator find user) zip (Env.security userSpy user.id) zip (Env.mod.assessApi.getResultsByUserId(user.id, 25)) map {
- case ((eval, spy), gameResults) => html.user.mod(user, spy, eval, gameResults)
+ case ((eval, spy), gameResults) => html.user.mod(user, spy, eval, PlayerAggregateAssessment(gameResults))
}
}
}
diff --git a/app/views/user/mod.scala.html b/app/views/user/mod.scala.html
index 9829341fc0..7102816fbb 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, eval: Option[lila.evaluation.Evaluation], gameResults: List[lila.evaluation.GameGroupResult])(implicit ctx: Context)
+@(u: User, spy: lila.security.UserSpy, eval: Option[lila.evaluation.Evaluation], aggregateAssessment: lila.evaluation.PlayerAggregateAssessment)(implicit ctx: Context)
@import lila.evaluation.Display
@@ -77,8 +77,39 @@
}
}
- @if(gameResults.nonEmpty) {
+ @if(aggregateAssessment.gameGroupResults.nonEmpty) {
+
+
+
+
+ Cheating
+ |
+
+ Cheating
+ |
+
+ Report
+ |
+
+
+
+
+
+ @aggregateAssessment.cheatingSum / 2
+ |
+
+ @aggregateAssessment.cheatingSum +
+ @aggregateAssessment.likelyCheatingSum / 5
+ |
+
+ @aggregateAssessment.cheatingSum +
+ @aggregateAssessment.likelyCheatingSum +
+ @aggregateAssessment.unclearSum / 5
+ |
+
+
+
@Range(1, 6).map { i =>
@Display.assessmentString(i)
@@ -107,7 +138,7 @@
- @gameResults.map { result =>
+ @aggregateAssessment.gameGroupResults.map { result =>
@routes.Round.watcher(result.gameId, result.color.name) |
@result.sfAvg ± @result.sfSd |
diff --git a/modules/evaluation/src/main/Group.scala b/modules/evaluation/src/main/Group.scala
index 7193db9734..8dcaf701ae 100644
--- a/modules/evaluation/src/main/Group.scala
+++ b/modules/evaluation/src/main/Group.scala
@@ -38,6 +38,25 @@ case class PeerGame(
}) + " game at " + matchPercentage + "% confidence"
}
+case class PlayerAggregateAssessment(
+ gameGroupResults: List[GameGroupResult]
+ ) {
+ import Statistics.listSum
+ def sumAssessment(x: Int): Int =
+ listSum(gameGroupResults.map { result =>
+ if (result.aggregate.assessment == x && (result.aggregate.positiveMatch || result.aggregate.confidence > 80)) 1
+ else 0
+ })
+
+ val cheatingSum: Int = sumAssessment(5)
+ val likelyCheatingSum: Int = sumAssessment(4)
+ val unclearSum: Int = sumAssessment(3)
+
+ val markPri: Boolean = cheatingSum >= 2
+ val markSec: Boolean = cheatingSum + likelyCheatingSum >= 5
+ val report: Boolean = cheatingSum + likelyCheatingSum + unclearSum >= 5
+}
+
case class AggregateAssessment(
assessment: Int,
confidence: Int,
@@ -62,6 +81,7 @@ case class GameGroupResult(
white: Boolean, // The side of the game being talked about
bestMatch: PeerGame,
secondaryMatches: List[PeerGame],
+ date: DateTime,
// Meta infos
sfAvg: Int,
sfSd: Int,
@@ -70,7 +90,7 @@ case class GameGroupResult(
blur: Int,
hold: Boolean
) {
- import Statistics.listSum
+ import Statistics.{listSum, listAverage}
val color = Color(white)
val aggregate: AggregateAssessment = {
def maxConfidence(xs: List[PeerGame]): Int = xs match {
@@ -87,7 +107,10 @@ case class GameGroupResult(
case a if (a.positiveMatch) => 2 * a.matchPercentage
case a => a.matchPercentage
})).toInt,
- maxConfidence(peers),
+ listAverage(peers.map{ _ match {
+ case i if (i.positiveMatch) => List.fill(2)(i.matchPercentage)
+ case i => List(i.matchPercentage)
+ }}.flatten).toInt,
peers.exists(_.positiveMatch)
)
}
diff --git a/modules/mod/src/main/AssessApi.scala b/modules/mod/src/main/AssessApi.scala
index 7a04f6976e..2b0d350d1f 100644
--- a/modules/mod/src/main/AssessApi.scala
+++ b/modules/mod/src/main/AssessApi.scala
@@ -6,6 +6,7 @@ import lila.db.BSON.BSONJodaDateTimeHandler
import lila.evaluation.{ PlayerAssessment, GameGroupResult, GameResults, GameGroup, Analysed, PeerGame, MatchAndSig }
import lila.game.Game
import lila.game.{ Game, GameRepo }
+import org.joda.time.DateTime
import reactivemongo.bson._
import scala.concurrent._
@@ -86,6 +87,7 @@ final class AssessApi(collRef: Coll, collRes: Coll, logApi: ModlogApi) {
white = source.color.white,
bestMatch = a,
secondaryMatches = b,
+ date = DateTime.now,
sfAvg = source.sfAvg,
sfSd = source.sfSd,
mtAvg = source.mtAvg,
diff --git a/public/stylesheets/analyse.css b/public/stylesheets/analyse.css
index 638b484dda..2432c9352a 100644
--- a/public/stylesheets/analyse.css
+++ b/public/stylesheets/analyse.css
@@ -294,7 +294,7 @@ table.modAssessment td.match a {
color: #759900;
}
table.modAssessment td.partial a {
- /*color: #d59120;*/
+ color: #d59120;
}
table.modAssessment td.noMatch {
color: #ac524f;
diff --git a/public/stylesheets/user-show.css b/public/stylesheets/user-show.css
index 12d94b3ff2..f856c0a377 100644
--- a/public/stylesheets/user-show.css
+++ b/public/stylesheets/user-show.css
@@ -278,4 +278,30 @@ div.user_show .results table.slist th {
}
div.user_show .results table.slist td {
text-align: center;
+}
+div.user_show .reportCard {
+ margin: 0 auto 10px auto;
+}
+div.user_show .reportCard th {
+ text-align: center;
+ font-weight: bold;
+ font-size: 2em;
+ padding: 0 20px 5px 20px;
+}
+div.user_show .reportCard td {
+ text-align: center;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+div.user_show .reportCard .mark {
+ color: #dc322f; /* red */
+}
+div.user_show .reportCard .noMark {
+ /*color: #dc322f;*/ /* red */
+}
+div.user_show .reportCard .report {
+ color: #B8AA1A; /* red */
+}
+div.user_show .reportCard .noReport {
+ /*color: #dc322f;*/ /* red */
}
\ No newline at end of file