FIDE titles
parent
821626cfa2
commit
16af702189
|
@ -1,9 +1,9 @@
|
|||
package controllers
|
||||
|
||||
import lila.app._
|
||||
import views._
|
||||
import lila.security.Permission
|
||||
import lila.user.UserRepo
|
||||
import views._
|
||||
|
||||
import play.api.mvc._
|
||||
import play.api.mvc.Results._
|
||||
|
@ -38,9 +38,21 @@ object Mod extends LilaController {
|
|||
me => modApi.reopenAccount(me.id, username) inject redirect(username)
|
||||
}
|
||||
|
||||
def setTitle(username: String) = AuthBody { implicit ctx =>
|
||||
me =>
|
||||
implicit def req = ctx.body
|
||||
if (isGranted(_.SetTitle))
|
||||
lila.user.DataForm.title.bindFromRequest.fold(
|
||||
err => fuccess(Redirect(routes.User.show(username))),
|
||||
title => modApi.setTitle(me.id, username, title) inject redirect(username, false)
|
||||
)
|
||||
else fuccess(authorizationFailed(ctx.req))
|
||||
}
|
||||
|
||||
def log = Auth { implicit ctx =>
|
||||
me => modLogApi.recent map { html.mod.log(_) }
|
||||
}
|
||||
|
||||
def redirect(username: String) = Redirect(routes.User.show(username).url + "?mod")
|
||||
def redirect(username: String, mod: Boolean = true) =
|
||||
Redirect(routes.User.show(username).url + mod.??("?mod"))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@(field: play.api.data.Field, options: Iterable[(Any,String)], default: Option[String] = None)
|
||||
|
||||
<select id="@field.id" name="@field.name">
|
||||
<select name="@field.name">
|
||||
@default.map { d =>
|
||||
<option value="">@d</option>
|
||||
}
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
</form>
|
||||
}
|
||||
}
|
||||
@if(isGranted(_.SetTitle)) {
|
||||
<form class="fide_title" method="post" action="@routes.Mod.setTitle(u.username)">
|
||||
@base.select(lila.user.DataForm.title.fill(u.title)("title"), lila.user.User.titles, "No FIDE title".some)
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="user_spy">
|
||||
|
|
|
@ -90,6 +90,10 @@ themepicker = true) {
|
|||
<span data-icon="j" class="is4"></span>
|
||||
@trans.thisPlayerUsesChessComputerAssistance()
|
||||
</div>
|
||||
} else {
|
||||
@u.title.flatMap(lila.user.User.titlesMap.get).map { title =>
|
||||
<p data-icon="E" class="title"> @title</p>
|
||||
}
|
||||
}
|
||||
@u.profile.map { p =>
|
||||
@p.nonEmptyRealName.map { name =>
|
||||
|
|
|
@ -156,6 +156,7 @@ POST /mod/:username/troll controllers.Mod.troll(username: String)
|
|||
POST /mod/:username/ban controllers.Mod.ban(username: String)
|
||||
POST /mod/:username/close controllers.Mod.closeAccount(username: String)
|
||||
POST /mod/:username/reopen controllers.Mod.reopenAccount(username: String)
|
||||
POST /mod/:username/title controllers.Mod.setTitle(username: String)
|
||||
POST /mod/:ip/ipban controllers.Mod.ipban(ip: String)
|
||||
GET /mod/log controllers.Mod.log
|
||||
|
||||
|
|
|
@ -15,10 +15,12 @@ final class DetectLanguage(url: String, key: String) {
|
|||
|
||||
private implicit val DetectionReads = Json.reads[Detection]
|
||||
|
||||
private val messageMaxLength = 2000
|
||||
|
||||
def apply(message: String): Fu[Option[Lang]] =
|
||||
WS.url(url).post(Map(
|
||||
"key" -> Seq(key),
|
||||
"q" -> Seq(message)
|
||||
"q" -> Seq(message take messageMaxLength)
|
||||
)) map { response =>
|
||||
(response.json \ "data" \ "detections").as[List[Detection]]
|
||||
.filter(_.isReliable)
|
||||
|
|
|
@ -49,6 +49,10 @@ final class ModApi(
|
|||
}
|
||||
}
|
||||
|
||||
def setTitle(mod: String, username: String, title: Option[String]): Funit = withUser(username) { user =>
|
||||
UserRepo.setTitle(user.id, title) >> logApi.setTitle(mod, user.id, title)
|
||||
}
|
||||
|
||||
def ipban(mod: String, ip: String): Funit =
|
||||
(firewall blockIp ip) >> logApi.ipban(mod, ip)
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ case class Modlog(
|
|||
case Modlog.reopenAccount => "reopen account"
|
||||
case Modlog.openTopic => "reopen topic"
|
||||
case Modlog.closeTopic => "close topic"
|
||||
case Modlog.setTitle => "set FIDE title"
|
||||
case Modlog.removeTitle => "remove FIDE title"
|
||||
case a => a
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +41,8 @@ object Modlog {
|
|||
val deletePost = "deletePost"
|
||||
val closeTopic = "closeTopic"
|
||||
val openTopic = "openTopic"
|
||||
val setTitle = "setTitle"
|
||||
val removeTitle = "removeTitle"
|
||||
|
||||
import lila.db.JsTube
|
||||
import JsTube.Helpers._
|
||||
|
|
|
@ -26,6 +26,11 @@ final class ModlogApi {
|
|||
Modlog(mod, user.some, Modlog.reopenAccount)
|
||||
}
|
||||
|
||||
def setTitle(mod: String, user: String, title: Option[String]) = add {
|
||||
val name = title flatMap lila.user.User.titlesMap.get
|
||||
Modlog(mod, user.some, name.isDefined.fold(Modlog.setTitle, Modlog.removeTitle), details = name)
|
||||
}
|
||||
|
||||
def ipban(mod: String, ip: String) = add {
|
||||
Modlog(mod, none, Modlog.ipban, ip.some)
|
||||
}
|
||||
|
|
|
@ -19,13 +19,15 @@ object Permission {
|
|||
case object IpBan extends Permission("ROLE_IP_BAN", List(UserSpy))
|
||||
case object CloseAccount extends Permission("ROLE_CLOSE_ACCOUNT", List(UserSpy))
|
||||
case object ReopenAccount extends Permission("ROLE_REOPEN_ACCOUNT", List(UserSpy))
|
||||
case object SetTitle extends Permission("ROLE_SET_TITLE", List(UserSpy))
|
||||
case object SeeReport extends Permission("ROLE_SEE_REPORT", Nil)
|
||||
|
||||
case object Hunter extends Permission("ROLE_HUNTER", List(
|
||||
ViewBlurs, MarkEngine, StaffForum, UserSpy, UserEvaluate, SeeReport))
|
||||
ViewBlurs, MarkEngine, StaffForum, UserSpy, UserEvaluate, SeeReport))
|
||||
|
||||
case object Admin extends Permission("ROLE_ADMIN", List(
|
||||
ViewBlurs, MarkTroll, MarkEngine, StaffForum, ModerateForum, UserSpy, UserEvaluate, SeeReport, IpBan, CloseAccount, ReopenAccount))
|
||||
ViewBlurs, MarkTroll, MarkEngine, StaffForum, ModerateForum, UserSpy,
|
||||
UserEvaluate, SeeReport, IpBan, CloseAccount, ReopenAccount, SetTitle))
|
||||
|
||||
case object SuperAdmin extends Permission("ROLE_SUPER_ADMIN", List(Admin))
|
||||
|
||||
|
|
|
@ -32,4 +32,6 @@ object DataForm {
|
|||
"the new passwords don't match",
|
||||
_.samePasswords
|
||||
))
|
||||
|
||||
val title = Form(single("title" -> optional(nonEmptyText)))
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ case class User(
|
|||
profile: Option[Profile] = None,
|
||||
engine: Boolean = false,
|
||||
toints: Int = 0,
|
||||
title: Option[String] = None,
|
||||
createdAt: DateTime,
|
||||
seenAt: Option[DateTime],
|
||||
lang: Option[String]) extends Ordered[User] {
|
||||
|
@ -67,6 +68,14 @@ object User {
|
|||
|
||||
def normalize(username: String) = username.toLowerCase
|
||||
|
||||
val titles = Seq(
|
||||
"CM" -> "Candidate Master (CM)",
|
||||
"FM" -> "FIDE Master (FM)",
|
||||
"IM" -> "International Master (IM)",
|
||||
"GM" -> "Grand Master (CM)")
|
||||
|
||||
val titlesMap = titles.toMap
|
||||
|
||||
object BSONFields {
|
||||
val id = "_id"
|
||||
val username = "username"
|
||||
|
@ -85,6 +94,7 @@ object User {
|
|||
val createdAt = "createdAt"
|
||||
val seenAt = "seenAt"
|
||||
val lang = "lang"
|
||||
val title = "title"
|
||||
def glicko(perf: String) = s"$perfs.$perf.gl"
|
||||
}
|
||||
|
||||
|
@ -116,7 +126,8 @@ object User {
|
|||
toints = r nIntD toints,
|
||||
createdAt = r date createdAt,
|
||||
seenAt = r dateO seenAt,
|
||||
lang = r strO lang)
|
||||
lang = r strO lang,
|
||||
title = r strO title)
|
||||
|
||||
def writes(w: BSON.Writer, o: User) = BSONDocument(
|
||||
id -> o.id,
|
||||
|
@ -135,7 +146,8 @@ object User {
|
|||
toints -> w.intO(o.toints),
|
||||
createdAt -> o.createdAt,
|
||||
seenAt -> o.seenAt,
|
||||
lang -> o.lang)
|
||||
lang -> o.lang,
|
||||
title -> o.title)
|
||||
}
|
||||
|
||||
private[user] lazy val tube = lila.db.BsTube(userBSONHandler)
|
||||
|
|
|
@ -93,6 +93,11 @@ trait UserRepo {
|
|||
def setProfile(id: ID, profile: Profile): Funit =
|
||||
$update($select(id), $setBson("profile" -> Profile.tube.handler.write(profile)))
|
||||
|
||||
def setTitle(id: ID, title: Option[String]): Funit = title match {
|
||||
case Some(t) => $update.field(id, "title", t)
|
||||
case None => $update($select(id), $unset("title"))
|
||||
}
|
||||
|
||||
def setEvaluated(id: ID, v: Boolean): Funit = $update.field(id, "evaluated", v)
|
||||
def isEvaluated(id: ID): Fu[Boolean] =
|
||||
$primitive.one($select(id), "evaluated")(_.asOpt[Boolean]) map (~_)
|
||||
|
|
|
@ -20,6 +20,9 @@ $(function() {
|
|||
var $zone = $("div.user_show .mod_zone");
|
||||
if ($zone.is(':visible')) $zone.hide();
|
||||
else $zone.html("Loading...").show().load($(this).attr("href"), function() {
|
||||
$(this).find('form.fide_title select').on('change', function() {
|
||||
$(this).parent('form').submit();
|
||||
});
|
||||
$('body').trigger('lichess.content_loaded');
|
||||
});
|
||||
return false;
|
||||
|
|
|
@ -21,7 +21,11 @@ div.user_show div.content_box_top > img.trophy {
|
|||
margin-top: -30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
div.user_show .title {
|
||||
margin-top: 1em;
|
||||
font-weight: bold;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
div.user_show .social {
|
||||
position: relative;
|
||||
border-top: 0;
|
||||
|
@ -138,7 +142,6 @@ div.user_show .mod_zone .same {
|
|||
font-weight: bold;
|
||||
}
|
||||
div.user_show .mod_zone form {
|
||||
margin: 0 25px 0 0;
|
||||
display: inline;
|
||||
}
|
||||
div.user_show .mod_zone .listings > div {
|
||||
|
|
Loading…
Reference in New Issue