msg integration WIP

inbox2
Thibault Duplessis 2020-01-26 23:07:27 -06:00
parent b1b230a1cb
commit 5a40eb8483
15 changed files with 70 additions and 89 deletions

View File

@ -93,13 +93,13 @@ final class Mod(
def warn(username: String, subject: String) =
OAuthModBody(_.ModMessage) { me =>
lila.message.ModPreset.bySubject(subject) ?? { preset =>
lila.msg.MsgPreset.byName(subject) ?? { preset =>
withSuspect(username) { prev =>
for {
inquiry <- env.report.api.inquiries ofModId me.id
suspect <- modApi.setTroll(AsMod(me), prev, prev.user.marks.troll)
thread <- env.message.api.sendPreset(me, suspect.user, preset)
_ <- env.mod.logApi.modMessage(thread.creatorId, thread.invitedId, thread.name)
_ <- env.msg.api.postPreset(suspect.user, preset)
_ <- env.mod.logApi.modMessage(me.id, suspect.user.id, preset.name)
} yield (inquiry, suspect).some
}
}

View File

@ -46,10 +46,10 @@ final class Relation(
def follow(userId: String) = Auth { implicit ctx => me =>
api.reachedMaxFollowing(me.id) flatMap {
case true =>
env.message.api
.sendPresetFromLichess(
env.msg.api
.postPreset(
me,
lila.message.ModPreset.maxFollow(me.username, env.relation.maxFollow.value)
lila.msg.MsgPreset.maxFollow(me.username, env.relation.maxFollow.value)
)
.void
case _ =>

View File

@ -66,7 +66,7 @@ object form {
isGranted(_.ModMessage) option frag(
form3.checkbox(form("mod"), frag("Send as mod")),
form3.group(form("preset"), frag("Preset")) { form3.select(_, Nil) },
embedJsUnsafe(s"""lichess_mod_presets=${safeJsonValue(lila.message.ModPreset.asJson)}""")
embedJsUnsafe(s"""lichess_mod_presets=${safeJsonValue(lila.msg.MsgPreset.asJson)}""")
),
form3.group(form("subject"), trans.subject()) { f =>
input(

View File

@ -136,17 +136,12 @@ object inquiry {
div(cls := "dropper warn buttons")(
iconTag("e"),
div(
lila.message.ModPreset.all.map { preset =>
postForm(action := routes.Mod.warn(in.user.username, preset.subject))(
submitButton(cls := "fbt")(preset.subject),
lila.msg.MsgPreset.all.map { preset =>
postForm(action := routes.Mod.warn(in.user.username, preset.name))(
submitButton(cls := "fbt")(preset.name),
autoNextInput
)
},
form(method := "get", action := routes.Message.form)(
input(tpe := "hidden", name := "mod", value := "1"),
input(tpe := "hidden", name := "user", value := "@in.user.id"),
submitButton(cls := "fbt")("Custom message")
)
}
)
),
isGranted(_.MarkEngine) option {

View File

@ -319,7 +319,7 @@ lazy val practice = module("practice",
)
lazy val playban = module("playban",
Seq(common, db, game, message, chat),
Seq(common, db, game, msg, chat),
reactivemongo.bundle
)

View File

@ -46,20 +46,6 @@ final class MessageApi(
_ <- threadOption.filter(_ isUnReadBy me).??(threadRepo.setReadFor(me))
} yield threadOption
def sendPreset(mod: User, user: User, preset: ModPreset): Fu[Thread] =
makeThread(
DataForm.ThreadData(
user = user.light,
subject = preset.subject,
text = preset.text,
asMod = true
),
mod
)
def sendPresetFromLichess(user: User, preset: ModPreset) =
userRepo.lichess orFail "Missing lichess user" flatMap { sendPreset(_, user, preset) }
def makeThread(data: DataForm.ThreadData, me: User): Fu[Thread] = {
val fromMod = Granter(_.MessageAnyone)(me)
userRepo named data.user.id flatMap {

View File

@ -29,12 +29,12 @@ object Msg {
read: Boolean
)
def make(
text: String,
user: User.ID
): Msg = Msg(
text = text,
user = user,
date = DateTime.now
)
def make(text: String, user: User.ID): Option[Msg] = {
val cleanText = text.trim
cleanText.nonEmpty option Msg(
text = cleanText take 10_000,
user = user,
date = DateTime.now
)
}
}

View File

@ -1,7 +1,5 @@
package lila.msg
import play.api.data._
import play.api.data.Forms._
import reactivemongo.api._
import scala.concurrent.duration._
@ -48,10 +46,7 @@ final class MsgApi(
.void
}
val postForm = Form(single("text" -> nonEmptyText(maxLength = 10_000)))
private[msg] def post(orig: User.ID, dest: User.ID, text: String): Funit = {
val msg = Msg.make(text, orig)
private[msg] def post(orig: User.ID, dest: User.ID, text: String): Funit = Msg.make(text, orig) ?? { msg =>
val threadId = MsgThread.id(orig, dest)
!colls.thread.exists($id(threadId)) flatMap { isNew =>
security.can.post(dest, msg, isNew) flatMap {
@ -96,9 +91,19 @@ final class MsgApi(
"lastMsg.read",
true
)
.void >>- notifier.onRead(threadId)
.map { res =>
if (res.nModified > 0) notifier.onRead(threadId)
}
}
def postPreset(dest: User, preset: MsgPreset): Funit =
postAsLichess(dest, preset.text)
def postAsLichess(dest: User, text: String): Funit =
post(User.lichessId, dest.id, text)
def unreadCount(me: User): Fu[Int] = unreadCountCache.get(me.id)
private val unreadCountCache = cacheApi[User.ID, Int](256, "message.unreadCount") {
_.expireAfterWrite(10 seconds)
.buildAsyncFuture[User.ID, Int] { userId =>
@ -106,8 +111,6 @@ final class MsgApi(
}
}
def unreadCount(me: User): Fu[Int] = unreadCountCache.get(me.id)
private val msgProjection = $doc("_id" -> false, "tid" -> false)
private def threadMsgsFor(threadId: MsgThread.Id, me: User): Fu[List[Msg]] =

View File

@ -1,13 +1,12 @@
package lila.message
package lila.msg
case class ModPreset(subject: String, text: String)
case class MsgPreset(name: String, text: String)
/* From https://github.com/ornicar/lila/wiki/Canned-responses-for-moderators */
object ModPreset {
object MsgPreset {
/* First line is the message subject;
* Other lines are the message body.
* The message body can contain several lines.
/* First line is the preset name;
* Other lines are the message.
* The message can contain several lines.
*/
// format: off
val all = List("""
@ -97,14 +96,14 @@ Unfortunately we had to reject your title verification. You are free to make ano
private def toPreset(txt: String) =
txt.linesIterator.toList.map(_.trim).filter(_.nonEmpty) match {
case subject :: body => ModPreset(subject, body mkString "\n").some
case name :: body => MsgPreset(name, body mkString "\n").some
case _ =>
logger.warn(s"Invalid mod message preset $txt")
logger.warn(s"Invalid message preset $txt")
none
}
lazy val sandbagAuto = ModPreset(
subject = "Warning: possible sandbagging",
lazy val sandbagAuto = MsgPreset(
name = "Warning: possible sandbagging",
text =
"""You have lost a couple games after a few moves. Please note that you MUST try to win every rated game.
Losing rated games on purpose is called "sandbagging", and is not allowed on Lichess.
@ -112,15 +111,15 @@ Losing rated games on purpose is called "sandbagging", and is not allowed on Lic
Thank you for your understanding."""
)
lazy val sittingAuto = ModPreset(
subject = "Warning: leaving games / stalling on time",
lazy val sittingAuto = MsgPreset(
name = "Warning: leaving games / stalling on time",
text =
"""In your game history, you have several games where you have left the game or just let the time run out instead of playing or resigning.
This can be very annoying for your opponents. If this behavior continues to happen, we may be forced to terminate your account."""
)
def maxFollow(username: String, max: Int) = ModPreset(
subject = "Follow limit reached!",
def maxFollow(username: String, max: Int) = MsgPreset(
name = "Follow limit reached!",
text = s"""Sorry, you can't follow more than $max players on Lichess.
To follow new players, you must first unfollow some on https://lichess.org/@/$username/following.
@ -129,9 +128,9 @@ Thank you for your understanding."""
lazy val asJson = play.api.libs.json.Json.toJson {
all.map { p =>
List(p.subject, p.text)
List(p.name, p.text)
}
}
def bySubject(s: String) = all.find(_.subject == s)
def byName(s: String) = all.find(_.name == s)
}

View File

@ -78,10 +78,11 @@ final private class MsgSecurity(
object may {
def post(orig: User.ID, dest: User.ID): Fu[Boolean] =
def post(orig: User.ID, dest: User.ID): Fu[Boolean] = (dest != User.lichessId) ?? {
!relationApi.fetchBlocks(dest, orig) >>& {
create(orig, dest) >>| reply(orig, dest)
}
}
private def create(orig: User.ID, dest: User.ID): Fu[Boolean] =
prefApi.getPref(dest, _.message) flatMap {

View File

@ -8,7 +8,7 @@ import lila.common.config.CollName
@Module
final class Env(
appConfig: Configuration,
messenger: lila.message.MessageApi,
messenger: lila.msg.MsgApi,
chatApi: lila.chat.ChatApi,
userRepo: lila.user.UserRepo,
lightUser: lila.common.LightUser.Getter,

View File

@ -7,7 +7,7 @@ import chess.{ Centis, Color, Status }
import lila.common.{ Bus, Iso, Uptime }
import lila.db.dsl._
import lila.game.{ Game, Player, Pov, Source }
import lila.message.{ MessageApi, ModPreset }
import lila.msg.{ MsgApi, MsgPreset }
import lila.user.{ User, UserRepo }
import org.joda.time.DateTime
@ -18,7 +18,7 @@ final class PlaybanApi(
feedback: PlaybanFeedback,
userRepo: UserRepo,
cacheApi: lila.memo.CacheApi,
messenger: MessageApi
messenger: MsgApi
)(implicit ec: scala.concurrent.ExecutionContext) {
import lila.db.BSON.BSONJodaDateTimeHandler
@ -239,16 +239,14 @@ final class PlaybanApi(
rageSitCache.put(record.userId, fuccess(record.rageSit))
(delta < 0) ?? {
if (record.rageSit.isTerrible) funit
else if (record.rageSit.isVeryBad) for {
mod <- userRepo.lichess
user <- userRepo byId record.userId
} yield (mod zip user).headOption foreach {
case (m, u) =>
lila.log("ragesit").info(s"https://lichess.org/@/${u.username} ${record.rageSit.counterView}")
Bus.publish(lila.hub.actorApi.mod.AutoWarning(u.id, ModPreset.sittingAuto.subject), "autoWarning")
messenger.sendPreset(m, u, ModPreset.sittingAuto).void
}
else funit
else if (record.rageSit.isVeryBad)
userRepo byId record.userId map {
_ ?? { u =>
lila.log("ragesit").info(s"https://lichess.org/@/${u.username} ${record.rageSit.counterView}")
Bus.publish(lila.hub.actorApi.mod.AutoWarning(u.id, MsgPreset.sittingAuto.name), "autoWarning")
messenger.postPreset(u, MsgPreset.sittingAuto).void
}
} else funit
}
case _ => funit
}

View File

@ -5,12 +5,12 @@ import scala.concurrent.duration._
import chess.Color
import lila.game.Game
import lila.message.{ MessageApi, ModPreset }
import lila.msg.{ MsgApi, MsgPreset }
import lila.user.{ User, UserRepo }
final private class SandbagWatch(
userRepo: UserRepo,
messenger: MessageApi
messenger: MsgApi
)(implicit ec: scala.concurrent.ExecutionContext) {
import SandbagWatch._
@ -29,15 +29,13 @@ final private class SandbagWatch(
}
private def sendMessage(userId: User.ID): Funit =
for {
mod <- userRepo.lichess
user <- userRepo byId userId
} yield (mod zip user).headOption.?? {
case (m, u) =>
userRepo byId userId map {
_ ?? { u =>
lila.log("sandbag").info(s"https://lichess.org/@/${u.username}")
lila.common.Bus
.publish(lila.hub.actorApi.mod.AutoWarning(u.id, ModPreset.sandbagAuto.subject), "autoWarning")
messenger.sendPreset(m, u, ModPreset.sandbagAuto).void
.publish(lila.hub.actorApi.mod.AutoWarning(u.id, MsgPreset.sandbagAuto.name), "autoWarning")
messenger.postPreset(u, MsgPreset.sandbagAuto).void
}
}
private def updateRecord(userId: User.ID, record: Record) =

View File

@ -176,7 +176,7 @@ final class RelationApi(
(config.maxBlock < nb) ?? repo.drop(u, false, nb - config.maxBlock.value)
}
def block(u1: ID, u2: ID): Funit = (u1 != u2) ?? {
def block(u1: ID, u2: ID): Funit = (u1 != u2 && u2 != User.lichessId) ?? {
fetchBlocks(u1, u2) flatMap {
case true => funit
case _ =>

View File

@ -5,6 +5,7 @@ import { bind } from './util';
import MsgCtrl from '../ctrl';
export default function renderActions(ctrl: MsgCtrl, convo: Convo): VNode[] {
if (convo.user.id == 'lichess') return [];
const nodes = [];
const cls = 'msg-app__convo__action.button.button-empty';
nodes.push(