diff --git a/app/controllers/Mod.scala b/app/controllers/Mod.scala index 7a4d70dc92..8065b1ec90 100644 --- a/app/controllers/Mod.scala +++ b/app/controllers/Mod.scala @@ -156,7 +156,7 @@ final class Mod( env.mod.impersonate.stop(me) Redirect(routes.User.show(me.username)) } - else if (isGranted(_.Impersonate) || (isGranted(_.Admin) && username == "lichess")) + else if (isGranted(_.Impersonate) || (isGranted(_.Admin) && username.toLowerCase == "lichess")) OptionFuRedirect(env.user.repo named username) { user => env.mod.impersonate.start(me, user) fuccess(routes.User.show(user.username)) diff --git a/app/controllers/Streamer.scala b/app/controllers/Streamer.scala index 00ad050b79..9a4b226546 100644 --- a/app/controllers/Streamer.scala +++ b/app/controllers/Streamer.scala @@ -137,7 +137,7 @@ final class Streamer( ctx.body.body.file("picture") match { case Some(pic) => api.uploadPicture(s.streamer, pic) recover { case e: Exception => - BadRequest(html.streamer.picture(s, e.message.some)) + BadRequest(html.streamer.picture(s, e.getMessage.some)) } inject Redirect(routes.Streamer.edit()) case None => fuccess(Redirect(routes.Streamer.edit())) } diff --git a/modules/common/src/main/Form.scala b/modules/common/src/main/Form.scala index f779c038d1..0a3d2d4161 100644 --- a/modules/common/src/main/Form.scala +++ b/modules/common/src/main/Form.scala @@ -5,7 +5,7 @@ import play.api.data.format.Formats._ import play.api.data.format.{ Formatter, JodaFormats } import play.api.data.Forms._ import play.api.data.JodaForms._ -import play.api.data.validation.Constraint +import play.api.data.validation.{ Constraint, Constraints } import play.api.data.{ Field, FormError, Mapping } import scala.util.Try @@ -60,6 +60,16 @@ object Form { trim(m) .verifying("This text contains invalid chars", s => !String.hasZeroWidthChars(s)) + def eventName(minLength: Int, maxLength: Int) = + clean(text).verifying( + Constraints minLength minLength, + Constraints maxLength maxLength, + Constraints.pattern( + regex = """[\p{L}\p{N}-\s:,;'\+]+""".r, + error = "Invalid characters" + ) + ) + def stringIn(choices: Options[String]) = text.verifying(hasKey(choices, _)) diff --git a/modules/security/src/main/Permission.scala b/modules/security/src/main/Permission.scala index 08c8f138f1..fa05695cc1 100644 --- a/modules/security/src/main/Permission.scala +++ b/modules/security/src/main/Permission.scala @@ -104,7 +104,8 @@ object Permission { ReportBan, ModMessage, SeeReport, - ModLog + ModLog, + ModNote ), "Shusher" ) diff --git a/modules/simul/src/main/SimulForm.scala b/modules/simul/src/main/SimulForm.scala index bd29838053..a1c4f305be 100644 --- a/modules/simul/src/main/SimulForm.scala +++ b/modules/simul/src/main/SimulForm.scala @@ -32,13 +32,7 @@ object SimulForm { val colorDefault = "white" private def nameType(host: User) = - clean(text).verifying( - Constraints minLength 2, - Constraints maxLength 40, - Constraints.pattern( - regex = """[\p{L}\p{N}-\s:,;]+""".r, - error = "error.unknown" - ), + eventName(2, 40).verifying( Constraint[String] { (t: String) => if (t.toLowerCase contains "lichess") validation.Invalid(validation.ValidationError("Must not contain \"lichess\"")) diff --git a/modules/swiss/src/main/SwissForm.scala b/modules/swiss/src/main/SwissForm.scala index 90c8a181c9..d117e05070 100644 --- a/modules/swiss/src/main/SwissForm.scala +++ b/modules/swiss/src/main/SwissForm.scala @@ -5,7 +5,6 @@ import chess.variant.Variant import org.joda.time.DateTime import play.api.data._ import play.api.data.Forms._ -import play.api.data.validation.Constraints import play.api.Mode import scala.concurrent.duration._ @@ -18,16 +17,7 @@ final class SwissForm(implicit mode: Mode) { def form(minRounds: Int = 3) = Form( mapping( - "name" -> optional( - clean(text).verifying( - Constraints minLength 2, - Constraints maxLength 30, - Constraints.pattern( - regex = """[\p{L}\p{N}-\s:,;\+]+""".r, - error = "Invalid characters" - ) - ) - ), + "name" -> optional(eventName(2, 3)), "clock" -> mapping( "limit" -> number.verifying(clockLimits.contains _), "increment" -> number(min = 0, max = 600) diff --git a/modules/tournament/src/main/TournamentForm.scala b/modules/tournament/src/main/TournamentForm.scala index e2bae3ecff..70f273f16d 100644 --- a/modules/tournament/src/main/TournamentForm.scala +++ b/modules/tournament/src/main/TournamentForm.scala @@ -59,13 +59,7 @@ final class TournamentForm { hasChat = tour.hasChat.some ) - private def nameType(user: User) = clean(text).verifying( - Constraints minLength 2, - Constraints maxLength 30, - Constraints.pattern( - regex = """[\p{L}\p{N}-\s:,;]+""".r, - error = "error.unknown" - ), + private def nameType(user: User) = eventName(2, 30).verifying( Constraint[String] { (t: String) => if (t.toLowerCase.contains("lichess") && !user.isVerified && !user.isAdmin) validation.Invalid(validation.ValidationError("Must not contain \"lichess\"")) diff --git a/ui/@types/lichess/index.d.ts b/ui/@types/lichess/index.d.ts index 1e1f400349..faad5c0635 100644 --- a/ui/@types/lichess/index.d.ts +++ b/ui/@types/lichess/index.d.ts @@ -272,6 +272,10 @@ declare namespace Tree { cp?: number; mate?: number; best?: Uci; + fen: Fen; + knodes: number; + depth: number; + pvs: PvData[]; } export interface PvData { diff --git a/ui/analyse/src/evalCache.ts b/ui/analyse/src/evalCache.ts index b475b00c15..27509c6de1 100644 --- a/ui/analyse/src/evalCache.ts +++ b/ui/analyse/src/evalCache.ts @@ -20,7 +20,7 @@ const evalPutMinDepth = 20; const evalPutMinNodes = 3e6; const evalPutMaxMoves = 10; -function qualityCheck(ev): boolean { +function qualityCheck(ev: Tree.ClientEval): boolean { // below 500k nodes, the eval might come from an imminent threefold repetition // and should therefore be ignored return ev.nodes > 500000 && ( @@ -29,7 +29,7 @@ function qualityCheck(ev): boolean { } // from client eval to server eval -function toPutData(variant: VariantKey, ev) { +function toPutData(variant: VariantKey, ev: Tree.ClientEval) { const data: any = { fen: ev.fen, knodes: Math.round(ev.nodes / 1000), @@ -47,7 +47,7 @@ function toPutData(variant: VariantKey, ev) { } // from server eval to client eval -function toCeval(e) { +function toCeval(e: Tree.ServerEval) { const res: any = { fen: e.fen, nodes: e.knodes * 1000, diff --git a/ui/common/css/vendor/chessground/_dark-board.scss b/ui/common/css/vendor/chessground/_dark-board.scss index 25a22b6784..3e50067e56 100644 --- a/ui/common/css/vendor/chessground/_dark-board.scss +++ b/ui/common/css/vendor/chessground/_dark-board.scss @@ -2,7 +2,8 @@ body.dark-board { --dark-factor: 0.4; - cg-board { + cg-board, + .is3d cg-board::before { background-color: rgba(0, 0, 0, var(--dark-factor)); background-blend-mode: darken; } diff --git a/ui/swiss/css/_home.scss b/ui/swiss/css/_home.scss index 356af50266..29a11d493e 100644 --- a/ui/swiss/css/_home.scss +++ b/ui/swiss/css/_home.scss @@ -18,10 +18,20 @@ color: $c-brag; font-weight: bold; } + } - &.faq strong { - display: block; - margin-bottom: .4em; + #faq { + display: block; + + .faq { + @extend %flex-center-nowrap; + + margin-bottom: 4em; + + strong { + display: block; + margin-bottom: .4em; + } } } }