160 lines
5.1 KiB
Scala
160 lines
5.1 KiB
Scala
package controllers
|
|
|
|
import play.api.data.Form
|
|
import play.api.libs.json._
|
|
import play.api.mvc.Result
|
|
import scala.concurrent.duration._
|
|
import scalatags.Text.Frag
|
|
|
|
import lila.api.Context
|
|
import lila.app._
|
|
import lila.common.{ IpAddress, HTTPRequest }
|
|
import lila.security.Granter
|
|
import lila.user.{ User => UserModel, UserRepo }
|
|
import views._
|
|
|
|
object Message extends LilaController {
|
|
|
|
private def api = Env.message.api
|
|
private def security = Env.message.security
|
|
private def forms = Env.message.forms
|
|
private def relationApi = Env.relation.api
|
|
|
|
def inbox(page: Int) = Auth { implicit ctx => me =>
|
|
NotForKids {
|
|
for {
|
|
pag <- api.inbox(me, page)
|
|
_ <- Env.user.lightUserApi preloadMany pag.currentPageResults.flatMap(_.userIds)
|
|
res <- negotiate(
|
|
html = fuccess(html.message.inbox(me, pag)),
|
|
api = _ => fuccess(Env.message.jsonView.inbox(me, pag))
|
|
)
|
|
} yield res
|
|
}
|
|
}
|
|
|
|
def unreadCount = Auth { implicit ctx => me =>
|
|
NotForKids {
|
|
negotiate(
|
|
html = notFound,
|
|
api = _ => JsonOk(api unreadCount me)
|
|
)
|
|
}
|
|
}
|
|
|
|
def thread(id: String) = Auth { implicit ctx => implicit me =>
|
|
NotForKids {
|
|
negotiate(
|
|
html = OptionFuOk(api.thread(id, me)) { thread =>
|
|
relationApi.fetchBlocks(thread otherUserId me, me.id) map { blocked =>
|
|
val form = thread.isReplyable option forms.post
|
|
html.message.thread(thread, form, blocked)
|
|
}
|
|
} map NoCache,
|
|
api = _ => JsonOptionFuOk(api.thread(id, me)) { thread => Env.message.jsonView.thread(thread) }
|
|
)
|
|
}
|
|
}
|
|
|
|
def answer(id: String) = AuthBody { implicit ctx => implicit me =>
|
|
OptionFuResult(api.thread(id, me) map (_.filterNot(_.isTooBig))) { thread =>
|
|
implicit val req = ctx.body
|
|
negotiate(
|
|
html = forms.post.bindFromRequest.fold(
|
|
err => relationApi.fetchBlocks(thread otherUserId me, me.id) map { blocked =>
|
|
BadRequest(html.message.thread(thread, err.some, blocked))
|
|
},
|
|
text => api.makePost(thread, text, me) inject Redirect(routes.Message.thread(thread.id) + "#bottom")
|
|
),
|
|
api = _ => forms.post.bindFromRequest.fold(
|
|
err => fuccess(BadRequest(Json.obj("err" -> "Malformed request"))),
|
|
text => api.makePost(thread, text, me) inject Ok(Json.obj("ok" -> true, "id" -> thread.id))
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
def form = Auth { implicit ctx => implicit me =>
|
|
NotForKids {
|
|
renderForm(me, get("title"), identity) map { Ok(_) }
|
|
}
|
|
}
|
|
|
|
private val ThreadLimitPerUser = new lila.memo.RateLimit[lila.user.User.ID](
|
|
credits = 20,
|
|
duration = 24 hour,
|
|
name = "PM thread per user",
|
|
key = "pm_thread.user"
|
|
)
|
|
|
|
private val ThreadLimitPerIP = new lila.memo.RateLimit[IpAddress](
|
|
credits = 30,
|
|
duration = 24 hour,
|
|
name = "PM thread per IP",
|
|
key = "pm_thread.ip"
|
|
)
|
|
|
|
private implicit val rateLimited = ornicar.scalalib.Zero.instance[Fu[Result]] {
|
|
fuccess(Redirect(routes.Message.inbox(1)))
|
|
}
|
|
|
|
def create = AuthBody { implicit ctx => implicit me =>
|
|
NotForKids {
|
|
Env.chat.panic.allowed(me) ?? {
|
|
implicit val req = ctx.body
|
|
negotiate(
|
|
html = forms.thread(me).bindFromRequest.fold(
|
|
err => renderForm(me, none, _ => err) map { BadRequest(_) },
|
|
data => {
|
|
val cost =
|
|
if (isGranted(_.ModMessage)) 0
|
|
else if (!me.createdSinceDays(3)) 2
|
|
else 1
|
|
ThreadLimitPerUser(me.id, cost = cost) {
|
|
ThreadLimitPerIP(HTTPRequest lastRemoteAddress ctx.req, cost = cost) {
|
|
api.makeThread(data, me) map { thread =>
|
|
if (thread.asMod) Env.mod.logApi.modMessage(thread.creatorId, thread.invitedId, thread.name)
|
|
Redirect(routes.Message.thread(thread.id))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
),
|
|
api = _ => forms.thread(me).bindFromRequest.fold(
|
|
jsonFormError,
|
|
data => api.makeThread(data, me) map { thread =>
|
|
Ok(Json.obj("ok" -> true, "id" -> thread.id))
|
|
}
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
private def renderForm(me: UserModel, title: Option[String], f: Form[_] => Form[_])(implicit ctx: Context): Fu[Frag] =
|
|
get("user") ?? UserRepo.named flatMap { user =>
|
|
user.fold(fuTrue)(u => security.canMessage(me.id, u.id)) map { canMessage =>
|
|
html.message.form(
|
|
f(forms thread me),
|
|
reqUser = user,
|
|
reqTitle = title,
|
|
reqMod = getBool("mod"),
|
|
canMessage = canMessage || Granter(_.MessageAnyone)(me),
|
|
oldEnough = Env.chat.panic.allowed(me)
|
|
)
|
|
}
|
|
}
|
|
|
|
def batch = AuthBody { implicit ctx => implicit me =>
|
|
val ids = get("ids").??(_.split(",").toList).distinct take 200
|
|
Env.message.batch(me, ~get("action"), ids) inject Redirect(routes.Message.inbox(1))
|
|
}
|
|
|
|
def delete(id: String) = AuthBody { implicit ctx => implicit me =>
|
|
negotiate(
|
|
html = api.deleteThread(id, me) inject Redirect(routes.Message.inbox(1)),
|
|
api = _ => api.deleteThread(id, me) inject Ok(Json.obj("ok" -> true))
|
|
)
|
|
}
|
|
}
|