configurable appeal and PM mod presets

pull/7079/head
Thibault Duplessis 2020-08-04 11:57:06 +02:00
parent c1c47944ec
commit ac422a9b72
8 changed files with 87 additions and 142 deletions

View File

@ -42,7 +42,7 @@ final class Appeal(env: Env, reportC: => Report) extends LilaController(env) {
Secure(_.Appeals) { implicit ctx => me =>
asMod(username) { (appeal, suspect) =>
env.report.api.inquiries.ofSuspectId(suspect.user.id) map { inquiry =>
Ok(html.appeal.show(appeal, suspect, inquiry, env.appeal.forms.text))
Ok(html.appeal.show(appeal, suspect, inquiry, env.appeal.forms.text, getPresets))
}
}
}
@ -56,7 +56,7 @@ final class Appeal(env: Env, reportC: => Report) extends LilaController(env) {
.fold(
err =>
env.report.api.inquiries.ofSuspectId(suspect.user.id) map { inquiry =>
BadRequest(html.appeal.show(appeal, suspect, inquiry, err))
BadRequest(html.appeal.show(appeal, suspect, inquiry, err, getPresets))
},
text =>
for {
@ -93,6 +93,8 @@ final class Appeal(env: Env, reportC: => Report) extends LilaController(env) {
}
}
private def getPresets = env.mod.presets.appealPresets.get()
private def asMod(
username: String
)(f: (lila.appeal.Appeal, Suspect) => Fu[Result])(implicit ctx: Context): Fu[Result] =

View File

@ -93,12 +93,12 @@ final class Mod(
def warn(username: String, subject: String) =
OAuthModBody(_.ModMessage) { me =>
lila.msg.MsgPreset.byName(subject) ?? { preset =>
env.mod.presets.pmPresets.get().named(subject) ?? { preset =>
withSuspect(username) { prev =>
for {
inquiry <- env.report.api.inquiries ofModId me.id
suspect <- modApi.setTroll(AsMod(me), prev, prev.user.marks.troll)
_ <- env.msg.api.postPreset(suspect.user, preset)
_ <- env.msg.api.systemPost(suspect.user.id, preset.text)
_ <- env.mod.logApi.modMessage(me.id, suspect.user.id, preset.name)
} yield (inquiry, suspect).some
}

View File

@ -1,16 +1,18 @@
package views.html
import controllers.routes
import play.api.data.Form
import play.api.i18n.Lang
import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.appeal.Appeal
import lila.common.String.html.richText
import lila.mod.{ ModPreset, ModPresets }
import lila.report.Report.Inquiry
import lila.report.Suspect
import lila.user.User
import play.api.data.Form
import play.api.i18n.Lang
object appeal {
@ -18,7 +20,7 @@ object appeal {
layout("Appeal") {
main(cls := "page-small box box-pad page appeal")(
appeal match {
case Some(a) => renderAppeal(a, textForm, asMod = false)
case Some(a) => renderAppeal(a, textForm, asMod = false, presets = none)
case None => newAppeal(textForm)
}
)
@ -29,16 +31,28 @@ object appeal {
h1("Appeal a moderation decision"),
renderHelp,
div(cls := "body")(
renderForm(textForm, action = routes.Appeal.post().url, isNew = true)
renderForm(textForm, action = routes.Appeal.post().url, isNew = true, presets = none)
)
)
def show(appeal: Appeal, suspect: Suspect, inquiry: Option[Inquiry], textForm: Form[_])(implicit
def show(
appeal: Appeal,
suspect: Suspect,
inquiry: Option[Inquiry],
textForm: Form[_],
presets: ModPresets
)(implicit
ctx: Context
) =
layout(s"Appeal by ${suspect.user.username}") {
main(cls := "page-small box box-pad page appeal")(
renderAppeal(appeal, textForm, asMod = true, inquiry = inquiry.map(_.mod).exists(ctx.userId.has)),
renderAppeal(
appeal,
textForm,
asMod = true,
inquiry = inquiry.map(_.mod).exists(ctx.userId.has),
presets.some
),
div(cls := "appeal__actions")(
inquiry match {
case None =>
@ -88,7 +102,7 @@ object appeal {
tr(
th("By"),
th("Last message"),
th
th(isGranted(_.Presets) option a(href := routes.Mod.presets("appeal"))("Presets"))
)
),
tbody(
@ -119,15 +133,24 @@ object appeal {
private def layout(title: String)(body: Frag)(implicit ctx: Context) =
views.html.base.layout(
title = title,
moreCss = frag(
cssTag("form3"),
cssTag("appeal")
),
title = title
moreJs = embedJsUnsafe(
"""$('select.appeal-presets').on('change', e => $('#form3-text').val(e.target.value))"""
)
)(body)
private def renderAppeal(appeal: Appeal, textForm: Form[_], asMod: Boolean, inquiry: Boolean = false)(
implicit ctx: Context
private def renderAppeal(
appeal: Appeal,
textForm: Form[_],
asMod: Boolean,
inquiry: Boolean = false,
presets: Option[ModPresets]
)(implicit
ctx: Context
) =
frag(
h1(
@ -152,7 +175,8 @@ object appeal {
action =
if (asMod) routes.Appeal.reply(appeal.id).url
else routes.Appeal.post().url,
isNew = false
isNew = false,
presets = presets ifTrue asMod
)
)
)
@ -198,12 +222,28 @@ object appeal {
")"
)
private def renderForm(form: Form[_], action: String, isNew: Boolean)(implicit ctx: Context) =
private def renderForm(form: Form[_], action: String, isNew: Boolean, presets: Option[ModPresets])(implicit
ctx: Context
) =
postForm(st.action := action)(
form3.globalError(form),
form3.group(form("text"), if (isNew) "Create an appeal" else "Add something to the appeal")(
form3.textarea(_)(rows := 6)
),
form3.submit(trans.send())
presets.map { ps =>
form3.actions(
select(cls := "appeal-presets")(
option(st.value := "")("Presets"),
ps.value.map {
case ModPreset(name, text) =>
option(
st.value := text,
st.title := text
)(name)
}
),
form3.submit(trans.send())
)
} getOrElse form3.submit(trans.send())
)
}

View File

@ -144,7 +144,7 @@ object inquiry {
isGranted(_.ModMessage) option div(cls := "dropper warn buttons")(
iconTag("e"),
div(
lila.msg.MsgPreset.all.map { preset =>
env.mod.presets.pmPresets.get().value.map { preset =>
postForm(action := routes.Mod.warn(in.user.username, preset.name))(
submitButton(cls := "fbt")(preset.name),
autoNextInput

View File

@ -7,10 +7,11 @@ import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.memo.SettingStore
import play.api.data.Form
import lila.mod.ModPresets
object presets {
def apply(group: String, setting: SettingStore[lila.mod.ModPresets], form: Form[_])(implicit ctx: Context) =
def apply(group: String, setting: SettingStore[ModPresets], form: Form[_])(implicit ctx: Context) =
views.html.base.layout(
title = s"$group presets",
moreCss = frag(cssTag("mod.misc"), cssTag("form3"))
@ -18,10 +19,15 @@ object presets {
main(cls := "page-menu")(
views.html.mod.menu("presets"),
div(cls := "page-menu__content box box-pad mod-presets")(
h1(s"$group presets"),
div(ModPresets.groups.filter(group !=).map { group =>
a(href := routes.Mod.presets(group))(group)
}),
h1(
s"${setting.get().value.size} $group presets",
small(
" / ",
ModPresets.groups.filter(group !=).map { group =>
a(href := routes.Mod.presets(group))(s"$group presets")
}
)
),
standardFlash(),
postForm(action := routes.Mod.presetsUpdate(group))(
form3.group(

View File

@ -13,8 +13,6 @@ final class ModPresetsApi(
import ModPresets.setting._
val groups = List("PM", "appeal")
def get(group: String) =
group match {
case "PM" => pmPresets.some
@ -35,27 +33,31 @@ final class ModPresetsApi(
)
}
case class ModPresets(value: List[ModPreset])
case class ModPresets(value: List[ModPreset]) {
def named(name: String) = value.find(_.name == name)
}
case class ModPreset(name: String, text: String)
private object ModPresets {
object ModPresets {
object setting {
val groups = List("PM", "appeal")
private[mod] object setting {
private def write(presets: ModPresets): String =
presets.value.map {
case ModPreset(name, text) => s"$name\n$text"
} mkString "\n----------\n"
case ModPreset(name, text) => s"$name\n\n$text"
} mkString "\n\n----------\n\n"
private def read(s: String): ModPresets =
ModPresets {
"\n-{3,}\n"
.split(s)
"\n-{3,}\\s*\n".r
.split(s.linesIterator.map(_.trim).dropWhile(_.isEmpty) mkString "\n")
.toList
.map(_.linesIterator.map(_.trim).filter(_.nonEmpty).toList)
.map(_.linesIterator.toList)
.filter(_.nonEmpty)
.flatMap {
case name :: text => ModPreset(name, text mkString "\n").some
case name :: text => ModPreset(name, text.dropWhile(_.isEmpty) mkString "\n").some
case _ => none
}
}

View File

@ -4,106 +4,6 @@ case class MsgPreset(name: String, text: String)
object MsgPreset {
/* First line is the preset name;
* Other lines are the message.
* The message can contain several lines.
*/
// format: off
val all = List("""
Warning: Offensive language
On Lichess, you *must* be nice when communicating with other players. At all times.
Lichess is intended to be a fun and friendly environment for everyone. Please note that repeated violation of chat policy will result in loss of chat privileges.
""", /* ---------------------------------------------------------------*/ """
Warning: Sandbagging
In your game history, you have several games where you clearly have intentionally lost the game. Attempts to artificially manipulate your own or someone else's rating are unacceptable. If this behavior continues to happen, your account will be terminated.
""", /* ---------------------------------------------------------------*/ """
Warning: Boosting
In your game history, you have several games where the opponent clearly has intentionally lost against you. Attempts to artificially manipulate your own or someone else's rating are unacceptable. If this behavior continues to happen, your account will be terminated.
""", /* ---------------------------------------------------------------*/ """
Warning: Excessive draw offers
Offering an excessive amount of draws in order to distract or annoy an opponent is not acceptable on Lichess. If this behavior continues to happen, your account will be terminated.
""", /* ---------------------------------------------------------------*/ """
En passant
This is called "en passant" and is one of the rules of chess. Check https://lichess.org/learn#/15 to learn more about it.
""", /* ---------------------------------------------------------------*/ """
Use /report
In order to report players for bad behavior, please visit https://lichess.org/report
""", /* ---------------------------------------------------------------*/ """
Warning: Accusations
Accusing other players of using computer assistance or otherwise cheating is not acceptable on Lichess. If you are confident that a player is cheating, use the report button on their profile page to report them to the moderators.
""", /* ---------------------------------------------------------------*/ """
Warning: spam is not permitted
Spamming is not permitted on Lichess.
Do not post anything more than once, in public chats, private chats, forums, or any other communication channel.
Please note that repeated violation of this policy will result in loss of communication privileges.
""", /* ---------------------------------------------------------------*/ """
Regarding rating refunds
To receive rating refunds certain conditions must be met, in order to mitigate rating inflation. These conditions were not met in this case.
Please also remember that, over the long run, ratings tend to gravitate towards the player's real skill level.
""", /* ---------------------------------------------------------------*/ """
Warning: Username or profile that implies you are a titled player
The username policy (https://github.com/ornicar/lila/wiki/Username-policy) for Lichess states that you can't have a username that implies that you have a FIDE title or the Lichess Master title, or impersonating a specific titled player. Actual titled players can verify using the form here (https://lichess.org/verify-title) with evidence that documents their identity, e.g. a scanned ID card, driving license, passport or similar. We will then verify your identity and title, and your title will be shown in front of your username and on your Lichess user profile. Since your username or profile implies that you have a title, we reserve the right to close your account within two weeks, if you have not verified your title within that time.
""", /* ---------------------------------------------------------------*/ """
Account marked for computer assistance
Our cheating detection algorithms have marked your account for using computer assistance. If you want to contest the mark, please send an email to Lichess Contact contact@lichess.org. If you are a titled player, we will need a proof of your identity. It can be a picture of a document, like an ID card or a driving license. You can verify your title using the form at lichess.org/help/master .
""", /* ---------------------------------------------------------------*/ """
Warning: leaving games / stalling on time
In your game history, you have several games where you have left the game or just let the time run out instead of playing or resigning.
This can be very annoying for your opponents. If this behavior continues to happen, we may be forced to terminate your account.
""", /* ---------------------------------------------------------------*/ """
Title Verification
Unfortunately we had to reject your title verification. You are free to make another application with the appropriate documentation.
""") flatMap toPreset
// format: on
private def toPreset(txt: String) =
txt.linesIterator.toList.map(_.trim).filter(_.nonEmpty) match {
case name :: body => MsgPreset(name, body mkString "\n").some
case _ =>
logger.warn(s"Invalid message preset $txt")
none
}
lazy val sandbagAuto = MsgPreset(
name = "Warning: possible sandbagging",
text =
@ -128,12 +28,4 @@ To follow new players, you must first unfollow some on https://lichess.org/@/$us
Thank you for your understanding."""
)
lazy val asJson = play.api.libs.json.Json.toJson {
all.map { p =>
List(p.name, p.text)
}
}
def byName(s: String) = all.find(_.name == s)
}

View File

@ -65,6 +65,9 @@
}
.mod-presets {
h1 small {
font-size: 70%;
}
textarea {
width: 100%;
}