diff --git a/app/controllers/Appeal.scala b/app/controllers/Appeal.scala index b196c69699..b6462072d8 100644 --- a/app/controllers/Appeal.scala +++ b/app/controllers/Appeal.scala @@ -6,26 +6,32 @@ import views._ import lila.api.Context import lila.app._ import lila.report.Suspect +import play.api.data.Form final class Appeal(env: Env, reportC: => Report) extends LilaController(env) { + import lila.appeal.Appeal.form + def home = Auth { implicit ctx => me => - env.appeal.api.mine(me) map { appeal => - Ok(html.appeal.discussion(appeal, env.appeal.forms.text)) - } + renderAppealOrTree(me) map { Ok(_) } } + private def renderAppealOrTree( + me: lila.user.User, + err: Option[Form[String]] = None + )(implicit ctx: Context) = env.appeal.api.mine(me) map { + case None => html.appeal.tree(me) + case Some(a) => html.appeal.discussion(a, err | form) + } + def post = AuthBody { implicit ctx => me => implicit val req = ctx.body - env.appeal.forms.text + form .bindFromRequest() .fold( - err => - env.appeal.api.mine(me) map { appeal => - BadRequest(html.appeal.discussion(appeal, err)) - }, + err => renderAppealOrTree(me, err.some) map { BadRequest(_) }, text => env.appeal.api.post(text, me) inject Redirect(routes.Appeal.home).flashSuccess ) } @@ -43,7 +49,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.discussion.show(appeal, suspect, inquiry, env.appeal.forms.text, getPresets)) + Ok(html.appeal.discussion.show(appeal, suspect, inquiry, form, getPresets)) } } } @@ -52,7 +58,7 @@ final class Appeal(env: Env, reportC: => Report) extends LilaController(env) { SecureBody(_.Appeals) { implicit ctx => me => asMod(username) { (appeal, suspect) => implicit val req = ctx.body - env.appeal.forms.text + form .bindFromRequest() .fold( err => diff --git a/app/views/appeal/bits.scala b/app/views/appeal/bits.scala new file mode 100644 index 0000000000..d17dc5da65 --- /dev/null +++ b/app/views/appeal/bits.scala @@ -0,0 +1,19 @@ +package views.html +package appeal + +import lila.api.Context +import lila.app.templating.Environment._ +import lila.app.ui.ScalatagsTemplate._ + +object bits { + + def layout(title: String)(body: Frag)(implicit ctx: Context) = + views.html.base.layout( + title = title, + moreCss = frag( + cssTag("form3"), + cssTag("appeal") + ), + moreJs = jsModule("appeal") + )(body) +} diff --git a/app/views/appeal/discussion.scala b/app/views/appeal/discussion.scala index d4aa143acd..24a2d8d441 100644 --- a/app/views/appeal/discussion.scala +++ b/app/views/appeal/discussion.scala @@ -16,35 +16,21 @@ import lila.user.User object discussion { - def apply(appeal: Option[Appeal], textForm: Form[_])(implicit ctx: Context) = - layout("Appeal") { + def apply(appeal: Appeal, textForm: Form[String])(implicit ctx: Context) = + bits.layout("Appeal") { main(cls := "page-small box box-pad page appeal")( - appeal match { - case Some(a) => renderAppeal(a, textForm, asMod = false, presets = none) - case None => newAppeal(textForm) - } + renderAppeal(appeal, textForm, asMod = false, presets = none) ) } - private def newAppeal(textForm: Form[_])(implicit ctx: Context) = - frag( - h1("Appeal a moderation decision"), - renderHelp, - div(cls := "body")( - renderForm(textForm, action = routes.Appeal.post.url, isNew = true, presets = none) - ) - ) - def show( appeal: Appeal, suspect: Suspect, inquiry: Option[Inquiry], - textForm: Form[_], + textForm: Form[String], presets: ModPresets - )(implicit - ctx: Context - ) = - layout(s"Appeal by ${suspect.user.username}") { + )(implicit ctx: Context) = + bits.layout(s"Appeal by ${suspect.user.username}") { main(cls := "page-small box box-pad page appeal")( renderAppeal( appeal, @@ -81,19 +67,9 @@ object discussion { ) } - private def layout(title: String)(body: Frag)(implicit ctx: Context) = - views.html.base.layout( - title = title, - moreCss = frag( - cssTag("form3"), - cssTag("appeal") - ), - moreJs = jsModule("appeal") - )(body) - private def renderAppeal( appeal: Appeal, - textForm: Form[_], + textForm: Form[String], asMod: Boolean, inquiry: Boolean = false, presets: Option[ModPresets] @@ -125,19 +101,6 @@ object discussion { ) ) - private def renderHelp = - div(cls := "appeal__help")( - p( - "If your account has been restricted for violation of ", - a(href := routes.Page.tos)("the Lichess rules"), - " you may file an appeal here." - ), - p( - "You can read more about the appeal process ", - a(href := routes.Page.loneBookmark("appeal"))("here.") - ) - ) - private def renderUser(appeal: Appeal, userId: User.ID, asMod: Boolean)(implicit ctx: Context) = if (appeal isAbout userId) userIdLink(userId.some) else @@ -150,7 +113,7 @@ object discussion { ) ) - private def renderForm(form: Form[_], action: String, isNew: Boolean, presets: Option[ModPresets])(implicit + def renderForm(form: Form[String], action: String, isNew: Boolean, presets: Option[ModPresets])(implicit ctx: Context ) = postForm(st.action := action)( diff --git a/app/views/appeal/tree.scala b/app/views/appeal/tree.scala new file mode 100644 index 0000000000..3ba8bc1be3 --- /dev/null +++ b/app/views/appeal/tree.scala @@ -0,0 +1,100 @@ +package views.html +package appeal + +import controllers.routes +import play.api.data.Form + +import lila.api.Context +import lila.app.templating.Environment._ +import lila.app.ui.ScalatagsTemplate._ +import lila.report.Report.Inquiry +import lila.user.User + +object tree { + + import trans.contact.doNotMessageModerators + import views.html.base.navTree._ + + private def cleanMenu(implicit ctx: Context): Branch = + Branch( + "root", + "Your account is not marked or restricted. You're all good!", + List( + Leaf( + "clean-other-account", + "I want to appeal for another account", + frag( + p( + "Sorry we don't take appeals from other accounts. The appeal should come from nowhere else, but the concerned account." + ) + ) + ), + Leaf( + "clean-warning", + "I want to discuss a warning I received", + frag( + p( + "Please note that warnings are only warnings, and that your account has not been restricted currently.", + br, + "If you still want to file an appeal, use the following form:" + ), + newAppeal + ) + ), + Leaf( + "clean-other-issue", + "I have another issue to discuss", + p( + "This channel of communication is for appealing moderation related issues.", + br, + "Please use ", + a(href := routes.Main.contact)("the contact page"), + " or ", + a(href := "https://discordapp.com/invite/pvHanhg")("our discord server"), + " to contact us about other issues.", + br, + "You can also ", + a(href := routes.Page.loneBookmark("appeal"))("find here more information about appeals.") + ) + ) + ) + ) + + def apply(me: User)(implicit ctx: Context) = + bits.layout("Appeal a moderation decision") { + main(cls := "page page-small box box-pad appeal")( + h1("Appeal"), + div(cls := "nav-tree")( + renderNode( + { + if (me.marks.clean) cleanMenu + else ??? + }, + none + ) + ), + p(cls := "appeal__moderators text", dataIcon := "")(doNotMessageModerators()) + ) + } + + private def newAppeal(implicit ctx: Context) = + discussion.renderForm( + lila.appeal.Appeal.form, + action = routes.Appeal.post.url, + isNew = true, + presets = none + ) + + private def renderHelp = + div(cls := "appeal__help")( + p( + "If your account has been restricted for violation of ", + a(href := routes.Page.tos)("the Lichess rules"), + " you may file an appeal here." + ), + p( + "You can read more about the appeal process ", + a(href := routes.Page.loneBookmark("appeal"))("here.") + ) + ) +} diff --git a/app/views/base/navTree.scala b/app/views/base/navTree.scala new file mode 100644 index 0000000000..81517fe6ef --- /dev/null +++ b/app/views/base/navTree.scala @@ -0,0 +1,46 @@ +package views.html +package base + +import lila.api.Context +import lila.app.templating.Environment._ +import lila.app.ui.ScalatagsTemplate._ + +object navTree { + + sealed trait Node { + val id: String + val name: Frag + } + case class Branch(id: String, name: Frag, children: List[Node]) extends Node + case class Leaf(id: String, name: Frag, content: Frag) extends Node + + def renderNode(node: Node, parent: Option[Node])(implicit ctx: Context): Frag = + node match { + case Leaf(_, _, content) => + List( + div(makeId(node.id), cls := "node leaf")( + h2(parent map goBack, node.name), + div(cls := "content")(content) + ) + ) + case b @ Branch(id, _, children) => + frag( + div(makeId(node.id), cls := s"node branch $id")( + h2(parent map goBack, node.name), + div(cls := "links")( + children map { child => + a(makeLink(child.id))(child.name) + } + ) + ), + children map { renderNode(_, b.some) } + ) + } + + private def makeId(id: String) = st.id := s"help-$id" + + private def makeLink(id: String) = href := s"#help-$id" + + private def goBack(parent: Node): Frag = + a(makeLink(parent.id), cls := "back", dataIcon := "I", title := "Go back") +} diff --git a/app/views/site/contact.scala b/app/views/site/contact.scala index cb1fea3aba..f9421e218e 100644 --- a/app/views/site/contact.scala +++ b/app/views/site/contact.scala @@ -1,5 +1,5 @@ -package views -package html.site +package views.html +package site import controllers.routes import scala.util.chaining._ @@ -11,13 +11,7 @@ import lila.app.ui.ScalatagsTemplate._ object contact { import trans.contact._ - - sealed private trait Node { - val id: String - val name: Frag - } - private case class Branch(id: String, name: Frag, children: List[Node]) extends Node - private case class Leaf(id: String, name: Frag, content: Frag) extends Node + import views.html.base.navTree._ private def reopenLeaf(prefix: String)(implicit ctx: Context) = Leaf( @@ -347,35 +341,6 @@ object contact { ) ) - private def renderNode(node: Node, parent: Option[Node])(implicit ctx: Context): Frag = - node match { - case Leaf(_, _, content) => - List( - div(makeId(node.id), cls := "node leaf")( - h2(parent map goBack, node.name), - div(cls := "content")(content) - ) - ) - case b @ Branch(id, _, children) => - frag( - div(makeId(node.id), cls := s"node branch $id")( - h2(parent map goBack, node.name), - div(cls := "links")( - children map { child => - a(makeLink(child.id))(child.name) - } - ) - ), - children map { renderNode(_, b.some) } - ) - } - - private def makeId(id: String) = st.id := s"help-$id" - private def makeLink(id: String) = href := s"#help-$id" - - private def goBack(parent: Node): Frag = - a(makeLink(parent.id), cls := "back", dataIcon := "I", title := "Go back") - def apply()(implicit ctx: Context) = page.layout( title = trans.contact.contact.txt(), diff --git a/modules/appeal/src/main/Appeal.scala b/modules/appeal/src/main/Appeal.scala index c1716dbdbc..4d4805c8f2 100644 --- a/modules/appeal/src/main/Appeal.scala +++ b/modules/appeal/src/main/Appeal.scala @@ -59,6 +59,13 @@ object Appeal { def apply(key: String) = all.find(_.key == key) } + val form = { + import play.api.data._ + import play.api.data.Forms._ + Form[String]( + single("text" -> nonEmptyText) + ) + } } case class AppealMsg( diff --git a/modules/appeal/src/main/AppealForm.scala b/modules/appeal/src/main/AppealForm.scala deleted file mode 100644 index 256e0a14a6..0000000000 --- a/modules/appeal/src/main/AppealForm.scala +++ /dev/null @@ -1,11 +0,0 @@ -package lila.appeal - -import play.api.data._ -import play.api.data.Forms._ - -final class AppealForm { - - val text = Form( - single("text" -> nonEmptyText) - ) -} diff --git a/modules/appeal/src/main/Env.scala b/modules/appeal/src/main/Env.scala index a3350ed6ad..0d1be19aa3 100644 --- a/modules/appeal/src/main/Env.scala +++ b/modules/appeal/src/main/Env.scala @@ -12,7 +12,5 @@ final class Env( private val coll = db(CollName("appeal")) - lazy val forms = wire[AppealForm] - lazy val api: AppealApi = wire[AppealApi] } diff --git a/translation/source/contact.xml b/translation/source/contact.xml index fc72ea5f94..59db2f8fdd 100644 --- a/translation/source/contact.xml +++ b/translation/source/contact.xml @@ -31,7 +31,7 @@ You can also reach that page by clicking the %s report button on a profile page. Do not report players in the forum. Do not send us report emails. - Do not send direct messages to moderators. + Please do not send direct messages to moderators. Only reporting players through the report form is effective. I want to report a bug In the Lichess Feedback section of the forum diff --git a/ui/site/css/_appeal.scss b/ui/site/css/_appeal.scss index 4fb9b4390a..320b426a20 100644 --- a/ui/site/css/_appeal.scss +++ b/ui/site/css/_appeal.scss @@ -52,4 +52,11 @@ .appeal-presets { margin-right: 1em; } + + &__moderators { + @extend %box-radius; + margin-top: 3em; + padding: 2em 3em; + background: $c-bg-zebra; + } } diff --git a/ui/site/src/appeal.ts b/ui/site/src/appeal.ts index e2f717658c..f66ec9bac8 100644 --- a/ui/site/src/appeal.ts +++ b/ui/site/src/appeal.ts @@ -1,6 +1,8 @@ import { formToXhr } from 'common/xhr'; lichess.load.then(() => { + if ($('.nav-tree').length) location.hash = location.hash || '#help-root'; + $('select.appeal-presets').on('change', (e: Event) => $('#form3-text').val((e.target as HTMLTextAreaElement).value)); $('form.appeal__actions__slack').on('submit', (e: Event) => {