Merge branch 'master' into stripe-api-version

* master:
  add ModNote permission to Shusher package
  fix impersonation of the lichess user
  dark board 3d
  refactor event name form, allow single quotes
  fix swiss faq style
  fix compile error
  {master} ignore more streamer image upload exceptions
  {master} help timeago with layout reflow
  {master} tweak scalatags
  {master} improve captcha help url
  uianalyse
stripe-api-version
Thibault Duplessis 2020-10-18 10:04:14 +02:00
commit 8af5dd1152
11 changed files with 40 additions and 36 deletions

View File

@ -156,7 +156,7 @@ final class Mod(
env.mod.impersonate.stop(me) env.mod.impersonate.stop(me)
Redirect(routes.User.show(me.username)) 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 => OptionFuRedirect(env.user.repo named username) { user =>
env.mod.impersonate.start(me, user) env.mod.impersonate.start(me, user)
fuccess(routes.User.show(user.username)) fuccess(routes.User.show(user.username))

View File

@ -137,7 +137,7 @@ final class Streamer(
ctx.body.body.file("picture") match { ctx.body.body.file("picture") match {
case Some(pic) => case Some(pic) =>
api.uploadPicture(s.streamer, pic) recover { case e: Exception => 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()) } inject Redirect(routes.Streamer.edit())
case None => fuccess(Redirect(routes.Streamer.edit())) case None => fuccess(Redirect(routes.Streamer.edit()))
} }

View File

@ -5,7 +5,7 @@ import play.api.data.format.Formats._
import play.api.data.format.{ Formatter, JodaFormats } import play.api.data.format.{ Formatter, JodaFormats }
import play.api.data.Forms._ import play.api.data.Forms._
import play.api.data.JodaForms._ 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 play.api.data.{ Field, FormError, Mapping }
import scala.util.Try import scala.util.Try
@ -60,6 +60,16 @@ object Form {
trim(m) trim(m)
.verifying("This text contains invalid chars", s => !String.hasZeroWidthChars(s)) .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]) = def stringIn(choices: Options[String]) =
text.verifying(hasKey(choices, _)) text.verifying(hasKey(choices, _))

View File

@ -104,7 +104,8 @@ object Permission {
ReportBan, ReportBan,
ModMessage, ModMessage,
SeeReport, SeeReport,
ModLog ModLog,
ModNote
), ),
"Shusher" "Shusher"
) )

View File

@ -32,13 +32,7 @@ object SimulForm {
val colorDefault = "white" val colorDefault = "white"
private def nameType(host: User) = private def nameType(host: User) =
clean(text).verifying( eventName(2, 40).verifying(
Constraints minLength 2,
Constraints maxLength 40,
Constraints.pattern(
regex = """[\p{L}\p{N}-\s:,;]+""".r,
error = "error.unknown"
),
Constraint[String] { (t: String) => Constraint[String] { (t: String) =>
if (t.toLowerCase contains "lichess") if (t.toLowerCase contains "lichess")
validation.Invalid(validation.ValidationError("Must not contain \"lichess\"")) validation.Invalid(validation.ValidationError("Must not contain \"lichess\""))

View File

@ -5,7 +5,6 @@ import chess.variant.Variant
import org.joda.time.DateTime import org.joda.time.DateTime
import play.api.data._ import play.api.data._
import play.api.data.Forms._ import play.api.data.Forms._
import play.api.data.validation.Constraints
import play.api.Mode import play.api.Mode
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -18,16 +17,7 @@ final class SwissForm(implicit mode: Mode) {
def form(minRounds: Int = 3) = def form(minRounds: Int = 3) =
Form( Form(
mapping( mapping(
"name" -> optional( "name" -> optional(eventName(2, 3)),
clean(text).verifying(
Constraints minLength 2,
Constraints maxLength 30,
Constraints.pattern(
regex = """[\p{L}\p{N}-\s:,;\+]+""".r,
error = "Invalid characters"
)
)
),
"clock" -> mapping( "clock" -> mapping(
"limit" -> number.verifying(clockLimits.contains _), "limit" -> number.verifying(clockLimits.contains _),
"increment" -> number(min = 0, max = 600) "increment" -> number(min = 0, max = 600)

View File

@ -59,13 +59,7 @@ final class TournamentForm {
hasChat = tour.hasChat.some hasChat = tour.hasChat.some
) )
private def nameType(user: User) = clean(text).verifying( private def nameType(user: User) = eventName(2, 30).verifying(
Constraints minLength 2,
Constraints maxLength 30,
Constraints.pattern(
regex = """[\p{L}\p{N}-\s:,;]+""".r,
error = "error.unknown"
),
Constraint[String] { (t: String) => Constraint[String] { (t: String) =>
if (t.toLowerCase.contains("lichess") && !user.isVerified && !user.isAdmin) if (t.toLowerCase.contains("lichess") && !user.isVerified && !user.isAdmin)
validation.Invalid(validation.ValidationError("Must not contain \"lichess\"")) validation.Invalid(validation.ValidationError("Must not contain \"lichess\""))

View File

@ -272,6 +272,10 @@ declare namespace Tree {
cp?: number; cp?: number;
mate?: number; mate?: number;
best?: Uci; best?: Uci;
fen: Fen;
knodes: number;
depth: number;
pvs: PvData[];
} }
export interface PvData { export interface PvData {

View File

@ -20,7 +20,7 @@ const evalPutMinDepth = 20;
const evalPutMinNodes = 3e6; const evalPutMinNodes = 3e6;
const evalPutMaxMoves = 10; 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 // below 500k nodes, the eval might come from an imminent threefold repetition
// and should therefore be ignored // and should therefore be ignored
return ev.nodes > 500000 && ( return ev.nodes > 500000 && (
@ -29,7 +29,7 @@ function qualityCheck(ev): boolean {
} }
// from client eval to server eval // from client eval to server eval
function toPutData(variant: VariantKey, ev) { function toPutData(variant: VariantKey, ev: Tree.ClientEval) {
const data: any = { const data: any = {
fen: ev.fen, fen: ev.fen,
knodes: Math.round(ev.nodes / 1000), knodes: Math.round(ev.nodes / 1000),
@ -47,7 +47,7 @@ function toPutData(variant: VariantKey, ev) {
} }
// from server eval to client eval // from server eval to client eval
function toCeval(e) { function toCeval(e: Tree.ServerEval) {
const res: any = { const res: any = {
fen: e.fen, fen: e.fen,
nodes: e.knodes * 1000, nodes: e.knodes * 1000,

View File

@ -2,7 +2,8 @@
body.dark-board { body.dark-board {
--dark-factor: 0.4; --dark-factor: 0.4;
cg-board { cg-board,
.is3d cg-board::before {
background-color: rgba(0, 0, 0, var(--dark-factor)); background-color: rgba(0, 0, 0, var(--dark-factor));
background-blend-mode: darken; background-blend-mode: darken;
} }

View File

@ -18,10 +18,20 @@
color: $c-brag; color: $c-brag;
font-weight: bold; font-weight: bold;
} }
}
&.faq strong { #faq {
display: block; display: block;
margin-bottom: .4em;
.faq {
@extend %flex-center-nowrap;
margin-bottom: 4em;
strong {
display: block;
margin-bottom: .4em;
}
} }
} }
} }