implement user-side report routing, controller and templating
parent
9fac73aad7
commit
d274266076
|
@ -104,4 +104,5 @@ object Env {
|
|||
def importer = lila.importer.Env.current
|
||||
def tournament = lila.tournament.Env.current
|
||||
def relation = lila.relation.Env.current
|
||||
def report = lila.report.Env.current
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package controllers
|
||||
|
||||
import play.api.mvc._
|
||||
import play.api.templates.Html
|
||||
import views._
|
||||
|
||||
import lila.app._
|
||||
import lila.security.Granter
|
||||
import lila.user.{ User ⇒ UserModel, UserRepo, Context }
|
||||
|
||||
object Report extends LilaController {
|
||||
|
||||
private def forms = Env.report.forms
|
||||
private def api = Env.report.api
|
||||
|
||||
def form = Auth { implicit ctx ⇒
|
||||
implicit me ⇒
|
||||
get("username") ?? UserRepo.named flatMap { user ⇒
|
||||
forms.createWithCaptcha map {
|
||||
case (form, captcha) ⇒ Ok(html.report.form(form, user, captcha))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def create = AuthBody { implicit ctx ⇒
|
||||
implicit me ⇒
|
||||
implicit val req = ctx.body
|
||||
forms.create.bindFromRequest.fold(
|
||||
err ⇒ get("username") ?? UserRepo.named flatMap { user ⇒
|
||||
forms.anyCaptcha map { captcha ⇒
|
||||
BadRequest(html.report.form(err.pp, user, captcha))
|
||||
}
|
||||
},
|
||||
data ⇒ api.create(data, me) map { thread ⇒
|
||||
Redirect(routes.Report.thanks)
|
||||
})
|
||||
}
|
||||
|
||||
def thanks = Auth { implicit ctx ⇒
|
||||
implicit me ⇒
|
||||
fuccess {
|
||||
html.report.thanks()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
@(form: Form[_], reqUser: Option[User] = None, captcha: lila.common.Captcha)(implicit ctx: Context)
|
||||
|
||||
@import lila.report.Reason
|
||||
|
||||
@site.layout(title = "Report a user", moreCss = cssTag("report.css")) {
|
||||
<div class="content_box" id="report">
|
||||
<h1>Report a user</h1>
|
||||
<form class="create" action="@routes.Report.create()@reqUser.map(u => "?username=" + u.username)" method="post">
|
||||
<div class="field_to">
|
||||
<label for="@form("username").id">User</label>
|
||||
@reqUser.map { user =>
|
||||
@userLink(user, cssClass = "inline".some)
|
||||
<input
|
||||
type="hidden"
|
||||
name="@form("username").name"
|
||||
value="@user.id">
|
||||
}.getOrElse {
|
||||
<input
|
||||
type="text"
|
||||
data-provider="@routes.User.autocomplete"
|
||||
class="autocomplete"
|
||||
required="required"
|
||||
name="@form("username").name"
|
||||
id="@form("username").id"
|
||||
value="@form("username").value">
|
||||
@errMsg(form("username"))
|
||||
}
|
||||
</div>
|
||||
<div class="field_reason">
|
||||
<label for="@form("reason").id">Reason</label>
|
||||
@base.select(form("reason"), Reason.all.map(r => r.name -> r.name.capitalize), "What's the matter?".some)
|
||||
@errMsg(form("reason"))
|
||||
</div>
|
||||
<div class="field_body">
|
||||
<label for="@form("text").id">Description</label>
|
||||
<textarea
|
||||
name="@form("text").name"
|
||||
required="required"
|
||||
id="@form("text").id">@form("text").value</textarea>
|
||||
<p class="help">
|
||||
Paste the link to the game(s) and explain what is wrong about this user behavior.
|
||||
</p>
|
||||
@errMsg(form("text"))
|
||||
</div>
|
||||
@base.captcha(form("move"), form("gameId"), captcha)
|
||||
@errMsg(form)
|
||||
<div class="actions">
|
||||
<input class="send button" type="submit" value="@trans.send()" />
|
||||
<a class="cancel" href="@routes.Lobby.home()">@trans.cancel()</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
@()(implicit ctx: Context)
|
||||
|
||||
@site.layout(title = "Thanks for the report", moreCss = cssTag("report.css")) {
|
||||
|
||||
<div class="content_box small_box">
|
||||
<h1 class="lichess_title">Thanks for the report</h1>
|
||||
<p>The moderators will review it very soon, and take appropriate action</p>
|
||||
<p>
|
||||
<a href="@routes.Lobby.home">Back to lichess homepage</a>
|
||||
</p>
|
||||
</div>
|
||||
}
|
|
@ -131,6 +131,10 @@ evenMoreCss = evenMoreCss) {
|
|||
<p>@trans.lastLogin() @timeago(seen)</p>
|
||||
}
|
||||
<a href="@routes.User.opponents(u.username)">@trans.favoriteOpponents()</a>
|
||||
@if(ctx.isAuth && !(ctx is u)) {
|
||||
<br />
|
||||
<a href="@routes.Report.form?username=@u.username">Report @u.username to moderators</a>
|
||||
}
|
||||
<div class="teams">
|
||||
@teamIds(u.id).sortBy(t => !myTeam(t)).map { teamId =>
|
||||
@teamLink(teamId, ("s16 team revert-underline" + myTeam(teamId).fold(" mine", "")).some)
|
||||
|
|
|
@ -187,6 +187,11 @@ GET /monitor controllers.Monitor.index
|
|||
GET /monitor/socket controllers.Monitor.websocket
|
||||
GET /monitor/status controllers.Monitor.status
|
||||
|
||||
# Report
|
||||
GET /report controllers.Report.form
|
||||
POST /report controllers.Report.create
|
||||
GET /report/thanks controllers.Report.thanks
|
||||
|
||||
# Misc
|
||||
POST /cli controllers.Cli.command
|
||||
GET /captcha/$id<[\w]{8}> controllers.Main.captchaCheck(id: String)
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package lila.report
|
||||
|
||||
private[report] sealed trait Reason {
|
||||
sealed trait Reason {
|
||||
|
||||
def name = toString.toLowerCase
|
||||
}
|
||||
|
||||
private[report] object Reason {
|
||||
object Reason {
|
||||
|
||||
object Cheat extends Reason
|
||||
object Violence extends Reason
|
||||
object Troll extends Reason
|
||||
object Other extends Reason
|
||||
case object Cheat extends Reason
|
||||
case object Violence extends Reason
|
||||
case object Troll extends Reason
|
||||
case object Other extends Reason
|
||||
|
||||
val all = List(Cheat, Violence, Troll, Other)
|
||||
val names = all map (_.name)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
#report form.create {
|
||||
font-size: 1.1em;
|
||||
padding-top: 2em;
|
||||
}
|
||||
#report form.create div.actions,
|
||||
#report div.answer div.actions {
|
||||
padding: 0.5em 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
#report form.create .actions a,
|
||||
#report div.answer div.actions a {
|
||||
margin-left: 1em;
|
||||
}
|
||||
#report form.create >div >label {
|
||||
float: left;
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
margin-top: 3px;
|
||||
}
|
||||
#report .field_to input,
|
||||
#report .field_reason input {
|
||||
width: 450px;
|
||||
border: 1px solid #D4D4D4;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
#report .field_to,
|
||||
#report .field_reason {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
#report textarea {
|
||||
width: 547px;
|
||||
height: 150px;
|
||||
padding: 10px;
|
||||
border: 1px solid #D4D4D4;
|
||||
}
|
||||
#report .error {
|
||||
color: red;
|
||||
margin-left: 110px;
|
||||
}
|
||||
#report .help {
|
||||
margin-left: 110px;
|
||||
}
|
||||
#report .checkmateCaptcha {
|
||||
margin-top: 2em;
|
||||
}
|
4
todo
4
todo
|
@ -51,3 +51,7 @@ customize piece images
|
|||
opera bug http://postimg.org/image/zcv8hse8n/full/
|
||||
customize sound notifications http://imgur.com/70WVyb5
|
||||
opera issue http://en.lichess.org/forum/lichess-feedback/new-game-wont-show-on-games-list-opera#1
|
||||
|
||||
deploy
|
||||
------
|
||||
db.report.ensureIndex({createdAt: -1, processedBy: 1})
|
||||
|
|
Loading…
Reference in New Issue