remove report score threshold and unprocessed counts
use highest report score insteadreport-no-threshold
parent
0d796c60f4
commit
e29907ad3c
|
@ -32,10 +32,10 @@ final class Appeal(env: Env, reportC: => Report) extends LilaController(env) {
|
|||
|
||||
def queue =
|
||||
Secure(_.Appeals) { implicit ctx => me =>
|
||||
env.appeal.api.queue zip env.report.api.inquiries.allBySuspect zip reportC.getCounts flatMap {
|
||||
case ((appeals, inquiries), counts ~ streamers ~ nbAppeals) =>
|
||||
env.appeal.api.queue zip env.report.api.inquiries.allBySuspect zip reportC.getScores flatMap {
|
||||
case ((appeals, inquiries), scores ~ streamers ~ nbAppeals) =>
|
||||
(env.user.lightUserApi preloadMany appeals.map(_.id)) inject
|
||||
Ok(html.appeal.queue(appeals, inquiries, counts, streamers, nbAppeals))
|
||||
Ok(html.appeal.queue(appeals, inquiries, scores, streamers, nbAppeals))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ final class Dev(env: Env) extends LilaController(env) {
|
|||
env.security.spamKeywordsSetting,
|
||||
env.irwin.irwinThresholdsSetting,
|
||||
env.explorer.indexFlowSetting,
|
||||
env.report.scoreThresholdSetting,
|
||||
env.report.scoreThresholdsSetting,
|
||||
env.report.slackScoreThresholdSetting,
|
||||
env.streamer.homepageMaxSetting,
|
||||
env.streamer.alwaysFeaturedSetting,
|
||||
|
|
|
@ -30,14 +30,14 @@ final class Report(
|
|||
renderList(room)
|
||||
}
|
||||
|
||||
protected[controllers] def getCounts =
|
||||
api.countOpenByRooms zip env.streamer.api.approval.countRequests zip env.appeal.api.countUnread
|
||||
protected[controllers] def getScores =
|
||||
api.maxScores zip env.streamer.api.approval.countRequests zip env.appeal.api.countUnread
|
||||
|
||||
private def renderList(room: String)(implicit ctx: Context) =
|
||||
api.openAndRecentWithFilter(12, Room(room)) zip
|
||||
getCounts flatMap { case (reports, counts ~ streamers ~ appeals) =>
|
||||
getScores flatMap { case (reports, scores ~ streamers ~ appeals) =>
|
||||
(env.user.lightUserApi preloadMany reports.flatMap(_.report.userIds)) inject
|
||||
Ok(html.report.list(reports, room, counts, streamers, appeals))
|
||||
Ok(html.report.list(reports, room, scores, streamers, appeals))
|
||||
}
|
||||
|
||||
def inquiry(id: String) =
|
||||
|
|
|
@ -46,7 +46,8 @@ object Environment
|
|||
|
||||
def isChatPanicEnabled = env.chat.panic.enabled
|
||||
|
||||
def blockingReportMaxScore: Int = env.report.api.maxScore.awaitOrElse(30.millis, "nbReports", 0)
|
||||
def blockingReportMaxScore: Int =
|
||||
env.report.api.maxScores.dmap(_.highest).awaitOrElse(50.millis, "nbReports", 0)
|
||||
|
||||
val spinner: Frag = raw(
|
||||
"""<div class="spinner"><svg viewBox="0 0 40 40"><circle cx=20 cy=20 r=18 fill="none"></circle></svg></div>"""
|
||||
|
|
|
@ -80,11 +80,11 @@ object appeal {
|
|||
def queue(
|
||||
appeals: List[Appeal],
|
||||
inquiries: Map[User.ID, Inquiry],
|
||||
counts: lila.report.Room.Counts,
|
||||
scores: lila.report.Room.Scores,
|
||||
streamers: Int,
|
||||
nbAppeals: Int
|
||||
)(implicit ctx: Context) =
|
||||
views.html.report.list.layout("appeal", counts, streamers, nbAppeals)(
|
||||
views.html.report.list.layout("appeal", scores, streamers, nbAppeals)(
|
||||
table(cls := "slist slist-pad see appeal-queue")(
|
||||
thead(
|
||||
tr(
|
||||
|
|
|
@ -12,11 +12,11 @@ object list {
|
|||
def apply(
|
||||
reports: List[lila.report.Report.WithSuspect],
|
||||
filter: String,
|
||||
counts: lila.report.Room.Counts,
|
||||
scores: lila.report.Room.Scores,
|
||||
streamers: Int,
|
||||
appeals: Int
|
||||
)(implicit ctx: Context) =
|
||||
layout(filter, counts, streamers, appeals)(
|
||||
layout(filter, scores, streamers, appeals)(
|
||||
table(cls := "slist slist-pad see")(
|
||||
thead(
|
||||
tr(
|
||||
|
@ -88,7 +88,9 @@ object list {
|
|||
)
|
||||
)
|
||||
|
||||
def layout(filter: String, counts: lila.report.Room.Counts, streamers: Int, appeals: Int)(
|
||||
private val scoreTag = tag("score")
|
||||
|
||||
def layout(filter: String, scores: lila.report.Room.Scores, streamers: Int, appeals: Int)(
|
||||
body: Frag
|
||||
)(implicit ctx: Context) =
|
||||
views.html.base.layout(
|
||||
|
@ -103,22 +105,21 @@ object list {
|
|||
span(cls := "tabs")(
|
||||
a(
|
||||
href := routes.Report.listWithFilter("all"),
|
||||
cls := List("new" -> (counts.sum > 0), "active" -> (filter == "all"))
|
||||
cls := List("active" -> (filter == "all"))
|
||||
)(
|
||||
countTag(counts.sum > 0 option counts.sum),
|
||||
"All"
|
||||
"All",
|
||||
scoreTag(scores.highest)
|
||||
),
|
||||
lila.report.Room.all.map { room =>
|
||||
a(
|
||||
href := routes.Report.listWithFilter(room.key),
|
||||
cls := List(
|
||||
"new" -> counts.value.contains(room),
|
||||
"active" -> (filter == room.key),
|
||||
s"room-${room.key}" -> true
|
||||
)
|
||||
)(
|
||||
countTag(counts.get(room)),
|
||||
room.name
|
||||
room.name,
|
||||
scoreTag(scores get room)
|
||||
)
|
||||
},
|
||||
(appeals > 0 && isGranted(_.Appeals)) option a(
|
||||
|
|
|
@ -6,6 +6,11 @@ import chess.Centis
|
|||
trait Iso[A, B] {
|
||||
val from: A => B
|
||||
val to: B => A
|
||||
|
||||
def map[BB](mapFrom: B => BB, mapTo: BB => B) = new Iso[A, BB] {
|
||||
val from = a => mapFrom(Iso.this.from(a))
|
||||
val to = bb => Iso.this.to(mapTo(bb))
|
||||
}
|
||||
}
|
||||
|
||||
object Iso {
|
||||
|
@ -29,12 +34,17 @@ object Iso {
|
|||
|
||||
def strings(sep: String): StringIso[Strings] =
|
||||
Iso[String, Strings](
|
||||
str => Strings(str.split(sep).iterator.map(_.trim).to(List)),
|
||||
str => Strings(str.split(sep).iterator.map(_.trim).toList),
|
||||
strs => strs.value mkString sep
|
||||
)
|
||||
def userIds(sep: String): StringIso[UserIds] =
|
||||
Iso[String, UserIds](
|
||||
str => UserIds(str.split(sep).iterator.map(_.trim.toLowerCase).to(List)),
|
||||
str => UserIds(str.split(sep).iterator.map(_.trim.toLowerCase).toList),
|
||||
strs => strs.value mkString sep
|
||||
)
|
||||
def ints(sep: String): StringIso[Ints] =
|
||||
Iso[String, Ints](
|
||||
str => Ints(str.split(sep).iterator.map(_.trim).flatMap(_.toIntOption).toList),
|
||||
strs => strs.value mkString sep
|
||||
)
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@ object Domain {
|
|||
|
||||
case class Strings(value: List[String]) extends AnyVal
|
||||
case class UserIds(value: List[String]) extends AnyVal
|
||||
case class Ints(value: List[Int]) extends AnyVal
|
||||
|
||||
case class Every(value: FiniteDuration) extends AnyVal
|
||||
case class AtMost(value: FiniteDuration) extends AnyVal
|
||||
|
|
|
@ -239,7 +239,7 @@ object mon {
|
|||
}
|
||||
object mod {
|
||||
object report {
|
||||
val unprocessed = gauge("mod.report.unprocessed").withoutTags()
|
||||
val highest = gauge("mod.report.highest").withoutTags()
|
||||
val close = counter("mod.report.close").withoutTags()
|
||||
def create(reason: String) = counter("mod.report.create").withTag("reason", reason)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ package clas {
|
|||
|
||||
package report {
|
||||
case class Cheater(userId: String, text: String)
|
||||
case class Shutup(userId: String, text: String, major: Boolean)
|
||||
case class Shutup(userId: String, text: String)
|
||||
case class Booster(winnerId: String, loserId: String)
|
||||
case class AutoFlag(suspectId: String, resource: String, text: String)
|
||||
case class CheatReportCreated(userId: String)
|
||||
|
|
|
@ -3,26 +3,23 @@ package lila.irwin
|
|||
import lila.memo.SettingStore.{ Formable, StringReader }
|
||||
import play.api.data.Form
|
||||
import play.api.data.Forms.{ single, text }
|
||||
import lila.common.Ints
|
||||
|
||||
case class IrwinThresholds(report: Int, mark: Int)
|
||||
|
||||
private object IrwinThresholds {
|
||||
val defaultThresholds = IrwinThresholds(88, 95)
|
||||
|
||||
val thresholdsIso = lila.common.Iso[String, IrwinThresholds](
|
||||
str =>
|
||||
private val defaultThresholds = IrwinThresholds(88, 95)
|
||||
|
||||
val thresholdsIso = lila.common.Iso
|
||||
.ints(",")
|
||||
.map[IrwinThresholds](
|
||||
{
|
||||
str.split(',').map(_.trim) match {
|
||||
case Array(rs, ms) =>
|
||||
for {
|
||||
report <- rs.toIntOption
|
||||
mark <- ms.toIntOption
|
||||
} yield IrwinThresholds(report, mark)
|
||||
case _ => none
|
||||
}
|
||||
} | defaultThresholds,
|
||||
t => s"${t.report}, ${t.mark}"
|
||||
)
|
||||
case Ints(List(r, m)) => IrwinThresholds(r, m)
|
||||
case _ => defaultThresholds
|
||||
},
|
||||
t => Ints(List(t.report, t.mark))
|
||||
)
|
||||
|
||||
implicit val thresholdsBsonHandler = lila.db.dsl.isoHandler(thresholdsIso)
|
||||
implicit val thresholdsStringReader = StringReader.fromIso(thresholdsIso)
|
||||
|
|
|
@ -79,6 +79,11 @@ object SettingStore {
|
|||
implicit val userIdsBsonHandler = lila.db.dsl.isoHandler(userIdsIso)
|
||||
implicit val userIdsReader = StringReader.fromIso(userIdsIso)
|
||||
}
|
||||
object Ints {
|
||||
val intsIso = lila.common.Iso.ints(",")
|
||||
implicit val intsBsonHandler = lila.db.dsl.isoHandler(intsIso)
|
||||
implicit val intsReader = StringReader.fromIso(intsIso)
|
||||
}
|
||||
object Regex {
|
||||
val regexIso = lila.common.Iso.string[Regex](_.r, _.toString)
|
||||
implicit val regexBsonHandler = lila.db.dsl.isoHandler(regexIso)
|
||||
|
|
|
@ -15,8 +15,6 @@ private class ReportConfig(
|
|||
@ConfigName("actor.name") val actorName: String
|
||||
)
|
||||
|
||||
private case class Thresholds(score: () => Int, slack: () => Int)
|
||||
|
||||
@Module
|
||||
final class Env(
|
||||
appConfig: Configuration,
|
||||
|
@ -43,20 +41,12 @@ final class Env(
|
|||
|
||||
private lazy val reportColl = db(config.reportColl)
|
||||
|
||||
lazy val scoreThresholdSetting = settingStore[Int](
|
||||
"reportScoreThreshold",
|
||||
default = config.scoreThreshold,
|
||||
text = "Report score threshold. Reports with lower scores are concealed to moderators".some
|
||||
)
|
||||
lazy val scoreThresholdsSetting = ReportThresholds makeScoreSetting settingStore
|
||||
|
||||
lazy val slackScoreThresholdSetting = settingStore[Int](
|
||||
"slackScoreThreshold",
|
||||
default = 80,
|
||||
text = "Slack score threshold. Comm reports with higher scores are notified in slack".some
|
||||
)
|
||||
lazy val slackScoreThresholdSetting = ReportThresholds makeSlackSetting settingStore
|
||||
|
||||
private val thresholds = Thresholds(
|
||||
score = scoreThresholdSetting.get _,
|
||||
score = scoreThresholdsSetting.get _,
|
||||
slack = slackScoreThresholdSetting.get _
|
||||
)
|
||||
|
||||
|
@ -74,8 +64,8 @@ final class Env(
|
|||
def receive = {
|
||||
case lila.hub.actorApi.report.Cheater(userId, text) =>
|
||||
api.autoCheatReport(userId, text).unit
|
||||
case lila.hub.actorApi.report.Shutup(userId, text, major) =>
|
||||
api.autoInsultReport(userId, text, major).unit
|
||||
case lila.hub.actorApi.report.Shutup(userId, text) =>
|
||||
api.autoInsultReport(userId, text).unit
|
||||
case lila.hub.actorApi.report.Booster(winnerId, loserId) =>
|
||||
api.autoBoostReport(winnerId, loserId).unit
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ object Report {
|
|||
def urgency: Int =
|
||||
report.score.value.toInt +
|
||||
(isOnline ?? 1000) +
|
||||
(report.closed ?? Int.MinValue)
|
||||
(report.closed ?? -999999)
|
||||
}
|
||||
|
||||
case class ByAndAbout(by: List[Report], about: List[Report]) {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package lila.report
|
||||
|
||||
import com.softwaremill.macwire._
|
||||
import org.joda.time.DateTime
|
||||
import reactivemongo.api.ReadPreference
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import com.softwaremill.macwire._
|
||||
import lila.common.Bus
|
||||
import lila.db.dsl._
|
||||
import lila.memo.CacheApi._
|
||||
import lila.user.{ User, UserRepo }
|
||||
import org.joda.time.DateTime
|
||||
import reactivemongo.api.ReadPreference
|
||||
|
||||
final class ReportApi(
|
||||
val coll: Coll,
|
||||
|
@ -276,7 +276,7 @@ final class ReportApi(
|
|||
)
|
||||
.void
|
||||
|
||||
def autoInsultReport(userId: String, text: String, major: Boolean): Funit =
|
||||
def autoInsultReport(userId: String, text: String): Funit =
|
||||
getSuspect(userId) zip getLichessReporter flatMap {
|
||||
case (Some(suspect), reporter) =>
|
||||
create(
|
||||
|
@ -286,7 +286,7 @@ final class ReportApi(
|
|||
reason = Reason.Comm,
|
||||
text = text
|
||||
),
|
||||
score => if (major) Report.Score(score.value atLeast thresholds.score()) else score
|
||||
score => score
|
||||
)
|
||||
case _ => funit
|
||||
}
|
||||
|
@ -299,39 +299,46 @@ final class ReportApi(
|
|||
)
|
||||
.void
|
||||
|
||||
private val closedSelect: Bdoc = $doc("open" -> false)
|
||||
private def scoreThresholdSelect = $doc("score" $gte thresholds.score())
|
||||
private val sortLastAtomAt = $doc("atoms.0.at" -> -1)
|
||||
private val closedSelect: Bdoc = $doc("open" -> false)
|
||||
private val sortLastAtomAt = $doc("atoms.0.at" -> -1)
|
||||
|
||||
private def roomSelect(room: Option[Room]): Bdoc =
|
||||
room.fold($doc("room" $ne Room.Xfiles.key)) { r =>
|
||||
room.fold($doc("room" $in Room.allButXfiles)) { r =>
|
||||
$doc("room" -> r)
|
||||
}
|
||||
|
||||
private def selectOpenInRoom(room: Option[Room]) =
|
||||
$doc("open" -> true) ++ roomSelect(room) ++ scoreThresholdSelect
|
||||
$doc("open" -> true) ++ roomSelect(room)
|
||||
|
||||
private def selectOpenAvailableInRoom(room: Option[Room]) =
|
||||
selectOpenInRoom(room) ++ $doc("inquiry" $exists false)
|
||||
|
||||
private val maxScoreCache = cacheApi.unit[Int] {
|
||||
private val maxScoreCache = cacheApi.unit[Room.Scores] {
|
||||
_.refreshAfterWrite(5 minutes)
|
||||
.buildAsyncFuture { _ =>
|
||||
coll // hits the best_open partial index
|
||||
.primitiveOne[Int](
|
||||
$doc(
|
||||
"open" -> true,
|
||||
"room" $in List(Room.Cheat, Room.Print, Room.Comm, Room.Other).flatMap(RoomBSONHandler.writeOpt)
|
||||
),
|
||||
$sort desc "score",
|
||||
"score"
|
||||
)
|
||||
.dmap(~_)
|
||||
.addEffect(lila.mon.mod.report.unprocessed.update(_).unit)
|
||||
Room.all
|
||||
.map { room =>
|
||||
coll // hits the best_open partial index
|
||||
.primitiveOne[Float](
|
||||
selectOpenAvailableInRoom(room.some),
|
||||
$sort desc "score",
|
||||
"score"
|
||||
)
|
||||
.dmap(room -> _)
|
||||
}
|
||||
.sequenceFu
|
||||
.dmap { scores =>
|
||||
Room.Scores(scores.map { case (room, s) =>
|
||||
room -> s.??(_.toInt)
|
||||
}.toMap)
|
||||
}
|
||||
.addEffect { scores =>
|
||||
lila.mon.mod.report.highest.update(scores.highest).unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def maxScore = maxScoreCache.getUnit
|
||||
def maxScores = maxScoreCache.getUnit
|
||||
|
||||
def recent(
|
||||
suspect: Suspect,
|
||||
|
@ -407,7 +414,7 @@ final class ReportApi(
|
|||
findBest(1, selectOpenAvailableInRoom(room.some)).map(_.headOption)
|
||||
|
||||
private def addSuspectsAndNotes(reports: List[Report]): Fu[List[Report.WithSuspect]] =
|
||||
userRepo byIdsSecondary (reports.map(_.user).distinct) map { users =>
|
||||
userRepo byIdsSecondary reports.map(_.user).distinct map { users =>
|
||||
reports
|
||||
.flatMap { r =>
|
||||
users.find(_.id == r.user) map { u =>
|
||||
|
@ -462,22 +469,6 @@ final class ReportApi(
|
|||
.void
|
||||
}
|
||||
|
||||
def countOpenByRooms: Fu[Room.Counts] =
|
||||
coll
|
||||
.aggregateList(maxDocs = 100) { framework =>
|
||||
import framework._
|
||||
Match(selectOpenAvailableInRoom(none)) -> List(
|
||||
GroupField("room")("nb" -> SumAll)
|
||||
)
|
||||
}
|
||||
.map { docs =>
|
||||
Room.Counts(docs.flatMap { doc =>
|
||||
doc.string("_id") flatMap Room.apply flatMap { room =>
|
||||
doc.int("nb") map { room -> _ }
|
||||
}
|
||||
}.toMap)
|
||||
}
|
||||
|
||||
private def findRecent(nb: Int, selector: Bdoc): Fu[List[Report]] =
|
||||
(nb > 0) ?? coll.find(selector).sort(sortLastAtomAt).cursor[Report]().list(nb)
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package lila.report
|
||||
|
||||
import play.api.data.Form
|
||||
import play.api.data.Forms.{ single, text }
|
||||
|
||||
import lila.common.Ints
|
||||
import lila.memo.SettingStore.{ Formable, StringReader }
|
||||
|
||||
case class ScoreThresholds(mid: Int, high: Int)
|
||||
|
||||
private case class Thresholds(score: () => ScoreThresholds, slack: () => Int)
|
||||
|
||||
private object ReportThresholds {
|
||||
|
||||
private val defaultScoreThresholds = ScoreThresholds(40, 50)
|
||||
|
||||
val thresholdsIso = lila.common.Iso
|
||||
.ints(",")
|
||||
.map[ScoreThresholds](
|
||||
{
|
||||
case Ints(List(m, h)) => ScoreThresholds(m, h)
|
||||
case _ => defaultScoreThresholds
|
||||
},
|
||||
t => Ints(List(t.mid, t.high))
|
||||
)
|
||||
|
||||
implicit val scoreThresholdsBsonHandler = lila.db.dsl.isoHandler(thresholdsIso)
|
||||
implicit val scoreThresholdsStringReader = StringReader.fromIso(thresholdsIso)
|
||||
implicit val scoreThresholdsFormable =
|
||||
new Formable[ScoreThresholds](t => Form(single("v" -> text)) fill thresholdsIso.to(t))
|
||||
|
||||
def makeScoreSetting(store: lila.memo.SettingStore.Builder) =
|
||||
store[ScoreThresholds](
|
||||
"reportScoreThresholds",
|
||||
default = defaultScoreThresholds,
|
||||
text = "Report score mid and high thresholds, separated with a comma.".some
|
||||
)
|
||||
|
||||
def makeSlackSetting(store: lila.memo.SettingStore.Builder) =
|
||||
store[Int](
|
||||
"slackScoreThreshold",
|
||||
default = 80,
|
||||
text = "Slack score threshold. Comm reports with higher scores are notified in slack".some
|
||||
)
|
||||
}
|
|
@ -22,6 +22,8 @@ object Room {
|
|||
(v.key, v)
|
||||
} toMap
|
||||
|
||||
val allButXfiles: List[Room] = all.filter(Xfiles !=)
|
||||
|
||||
implicit val roomIso = lila.common.Iso[String, Room](k => byKey.getOrElse(k, Other), _.key)
|
||||
|
||||
def apply(key: String): Option[Room] = byKey get key
|
||||
|
@ -43,8 +45,8 @@ object Room {
|
|||
case Xfiles => Set.empty
|
||||
}
|
||||
|
||||
case class Counts(value: Map[Room, Int]) {
|
||||
def get = value.get _
|
||||
lazy val sum = value.view.filterKeys(Xfiles !=).values.sum
|
||||
case class Scores(value: Map[Room, Int]) {
|
||||
def get = value.get _
|
||||
def highest = ~value.values.maxOption
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,7 @@ final class ShutupApi(
|
|||
text: String,
|
||||
textType: TextType,
|
||||
source: Option[PublicSource] = None,
|
||||
toUserId: Option[User.ID] = None,
|
||||
major: Boolean = false
|
||||
toUserId: Option[User.ID] = None
|
||||
): Funit =
|
||||
userRepo isTroll userId flatMap {
|
||||
case true => funit
|
||||
|
@ -79,29 +78,28 @@ final class ShutupApi(
|
|||
)
|
||||
.flatMap {
|
||||
case None => fufail(s"can't find user record for $userId")
|
||||
case Some(userRecord) => legiferate(userRecord, major)
|
||||
case Some(userRecord) => legiferate(userRecord)
|
||||
}
|
||||
.recover(lila.db.ignoreDuplicateKey)
|
||||
}
|
||||
}
|
||||
|
||||
private def legiferate(userRecord: UserRecord, major: Boolean): Funit = {
|
||||
major || userRecord.reports.exists(_.unacceptable)
|
||||
} ?? {
|
||||
reporter ! lila.hub.actorApi.report.Shutup(userRecord.userId, reportText(userRecord), major)
|
||||
coll.update
|
||||
.one(
|
||||
$id(userRecord.userId),
|
||||
$unset(
|
||||
TextType.PublicForumMessage.key,
|
||||
TextType.TeamForumMessage.key,
|
||||
TextType.PrivateMessage.key,
|
||||
TextType.PrivateChat.key,
|
||||
TextType.PublicChat.key
|
||||
private def legiferate(userRecord: UserRecord): Funit =
|
||||
userRecord.reports.exists(_.unacceptable) ?? {
|
||||
reporter ! lila.hub.actorApi.report.Shutup(userRecord.userId, reportText(userRecord))
|
||||
coll.update
|
||||
.one(
|
||||
$id(userRecord.userId),
|
||||
$unset(
|
||||
TextType.PublicForumMessage.key,
|
||||
TextType.TeamForumMessage.key,
|
||||
TextType.PrivateMessage.key,
|
||||
TextType.PrivateChat.key,
|
||||
TextType.PublicChat.key
|
||||
)
|
||||
)
|
||||
)
|
||||
.void
|
||||
}
|
||||
.void
|
||||
}
|
||||
|
||||
private def reportText(userRecord: UserRecord) =
|
||||
userRecord.reports
|
||||
|
|
|
@ -58,6 +58,7 @@ $c-report-high-over: white;
|
|||
font-size: 1.2em;
|
||||
padding: .3em .5em;
|
||||
border-radius: .3em;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.score.green {
|
||||
|
|
Loading…
Reference in New Issue