lila/app/controllers/Mod.scala

198 lines
6.5 KiB
Scala

package controllers
import lila.app._
import lila.security.Permission
import lila.user.UserRepo
import views._
import org.joda.time.DateTime
import play.api.mvc._
import play.api.mvc.Results._
import lila.evaluation.{ PlayerAssessment }
import chess.Color
object Mod extends LilaController {
private def modApi = Env.mod.api
private def modLogApi = Env.mod.logApi
private def assessApi = Env.mod.assessApi
def engine(username: String) = Secure(_.MarkEngine) { _ =>
me => modApi.toggleEngine(me.id, username) inject redirect(username)
}
def booster(username: String) = Secure(_.MarkBooster) { _ =>
me => modApi.toggleBooster(me.id, username) inject redirect(username)
}
def troll(username: String) = Secure(_.MarkTroll) { implicit ctx =>
me =>
modApi.troll(me.id, username, getBool("set")) inject {
get("then") match {
case Some("reports") => Redirect(routes.Report.list)
case _ => redirect(username)
}
}
}
def ban(username: String) = Secure(_.IpBan) { implicit ctx =>
me => modApi.ban(me.id, username) inject redirect(username)
}
def ipban(ip: String) = Secure(_.IpBan) { implicit ctx =>
me => modApi.ipban(me.id, ip)
}
def closeAccount(username: String) = Secure(_.CloseAccount) { implicit ctx =>
me => modApi.closeAccount(me.id, username) flatMap {
_ ?? Account.doClose
} inject redirect(username)
}
def reopenAccount(username: String) = Secure(_.ReopenAccount) { implicit ctx =>
me => modApi.reopenAccount(me.id, username) inject redirect(username)
}
def setTitle(username: String) = SecureBody(_.SetTitle) { implicit ctx =>
me =>
implicit def req = ctx.body
lila.user.DataForm.title.bindFromRequest.fold(
err => fuccess(redirect(username, mod = true)),
title => modApi.setTitle(me.id, username, title) inject redirect(username, mod = false)
)
}
def setEmail(username: String) = SecureBody(_.SetEmail) { implicit ctx =>
me =>
implicit def req = ctx.body
OptionFuResult(UserRepo named username) { user =>
Env.security.forms.modEmail(user).bindFromRequest.fold(
err => BadRequest(err.toString).fuccess,
email => modApi.setEmail(me.id, user.id, email) inject redirect(user.username, mod = true)
)
}
}
def notifySlack(username: String) = Auth { implicit ctx =>
me =>
OptionFuResult(UserRepo named username) { user =>
Env.slack.api.userMod(user = user, mod = me) inject redirect(user.username)
}
}
def log = Secure(_.SeeReport) { implicit ctx =>
me => modLogApi.recent map { html.mod.log(_) }
}
def communication(username: String) = Secure(_.MarkTroll) { implicit ctx =>
me =>
OptionFuOk(UserRepo named username) { user =>
for {
povs <- lila.game.GameRepo.recentPovsByUser(user, 100)
chats <- povs.map(p => Env.chat.api.playerChat findNonEmpty p.gameId).sequence
povWithChats = (povs zip chats) collect {
case (p, Some(c)) => p -> c
} take 9
threads <- {
lila.message.ThreadRepo.visibleByUser(user.id, 50) map {
_ filter (_ hasPostsWrittenBy user.id) take 9
}
}
publicLines <- Env.shutup.api getPublicLines user.id
spy <- Env.security userSpy user.id
} yield html.mod.communication(user, povWithChats, threads, publicLines, spy)
}
}
private val ipIntelCache =
lila.memo.AsyncCache[String, Int](ip => {
import play.api.libs.ws.WS
import play.api.Play.current
val email = "lichess.contact@gmail.com"
val url = s"http://check.getipintel.net/check.php?ip=$ip&contact=$email"
WS.url(url).get().map(_.body).mon(_.security.proxy.request.time).flatMap { str =>
parseFloatOption(str).fold[Fu[Int]](fufail(s"Invalid ratio ${str.take(140)}")) { ratio =>
fuccess((ratio * 100).toInt)
}
}.addEffects(
fail = _ => lila.mon.security.proxy.request.failure(),
succ = percent => {
lila.mon.security.proxy.percent(percent max 0)
lila.mon.security.proxy.request.success()
})
}, maxCapacity = 1024)
def ipIntel(ip: String) = Secure(_.IpBan) { ctx =>
me =>
ipIntelCache(ip).map { Ok(_) }.recover {
case e: Exception => InternalServerError(e.getMessage)
}
}
def redirect(username: String, mod: Boolean = true) = Redirect(routes.User.show(username).url + mod.??("?mod"))
def refreshUserAssess(username: String) = Secure(_.MarkEngine) { implicit ctx =>
me => assessApi.refreshAssessByUsername(username) inject redirect(username)
}
def gamify = Secure(_.SeeReport) { implicit ctx =>
me =>
Env.mod.gamify.leaderboards zip
Env.mod.gamify.history(orCompute = true) map {
case (leaderboards, history) => Ok(html.mod.gamify.index(leaderboards, history))
}
}
def gamifyPeriod(periodStr: String) = Secure(_.SeeReport) { implicit ctx =>
me =>
lila.mod.Gamify.Period(periodStr).fold(notFound) { period =>
Env.mod.gamify.leaderboards map { leaderboards =>
Ok(html.mod.gamify.period(leaderboards, period))
}
}
}
def search = Secure(_.UserSearch) { implicit ctx =>
me =>
val query = (~get("q")).trim
Env.mod.search(query) map { users =>
html.mod.search(query, users)
}
}
def chatUser(username: String) = Secure(_.ChatTimeout) { implicit ctx =>
me =>
implicit val lightUser = Env.user.lightUser _
JsonOptionOk {
Env.chat.api.userChat userModInfo username map2 lila.chat.JsonView.userModInfo
}
}
def powaaa(username: String) = Secure(_.ChangePermission) { implicit ctx =>
me =>
OptionOk(UserRepo named username) { user =>
html.mod.powaaa(user)
}
}
def savePowaaa(username: String) = SecureBody(_.ChangePermission) { implicit ctx =>
me =>
implicit def req = ctx.body
OptionFuResult(UserRepo named username) { user =>
import play.api.data._
import play.api.data.Forms._
Form(single(
"permissions" -> list(nonEmptyText.verifying { str =>
lila.security.Permission.allButSuperAdmin.exists(_.name == str)
})
)).bindFromRequest.fold(
err => BadRequest(html.mod.powaaa(user)).fuccess,
permissions =>
UserRepo.setRoles(user.id, permissions map (_.toUpperCase)) inject
Redirect(routes.User.show(user.username) + "?mod")
)
}
}
}