show appeals in user tables

closes lichess-org/tavern#106
pull/8706/head
Thibault Duplessis 2021-04-19 11:04:15 +02:00
parent 374fbddfa0
commit b7ad10f52e
6 changed files with 46 additions and 27 deletions

View File

@ -255,7 +255,7 @@ final class Mod(
.mon(_.mod.comm.segment("inquiries")) zip .mon(_.mod.comm.segment("inquiries")) zip
env.security.userLogins(user, 100).flatMap { env.security.userLogins(user, 100).flatMap {
userC.loginsTableData(user, _, 100) userC.loginsTableData(user, _, 100)
} map { case ((((((chats, convos), publicLines), notes), history), inquiry), logins) => } flatMap { case ((((((chats, convos), publicLines), notes), history), inquiry), logins) =>
if (priv) { if (priv) {
if (!inquiry.??(_.isRecentCommOf(Suspect(user)))) { if (!inquiry.??(_.isRecentCommOf(Suspect(user)))) {
env.irc.slack.commlog(mod = me, user = user, inquiry.map(_.oldestAtom.by.value)) env.irc.slack.commlog(mod = me, user = user, inquiry.map(_.oldestAtom.by.value))
@ -268,19 +268,22 @@ final class Mod(
) )
} }
} }
html.mod.communication( env.appeal.api.byUserIds(user.id :: logins.userLogins.otherUserIds) map { appeals =>
me, html.mod.communication(
user, me,
(povs zip chats) collect { user,
case (p, Some(c)) if c.nonEmpty => p -> c (povs zip chats) collect {
} take 15, case (p, Some(c)) if c.nonEmpty => p -> c
convos, } take 15,
publicLines, convos,
notes.filter(_.from != "irwin"), publicLines,
history, notes.filter(_.from != "irwin"),
logins, history,
priv logins,
) appeals,
priv
)
}
} }
} }
} }

View File

@ -395,11 +395,12 @@ final class User(
html.user.mod.actions(user, emails, erased, env.mod.presets.pmPresets.get()) html.user.mod.actions(user, emails, erased, env.mod.presets.pmPresets.get())
} }
val userLoginsFu = env.security.userLogins(user, nbOthers) val userLoginsFu = env.security.userLogins(user, nbOthers)
val others = userLoginsFu flatMap { userLogins => val others = for {
loginsTableData(user, userLogins, nbOthers) map { userLogins <- userLoginsFu
html.user.mod.otherUsers(holder, user, _) appeals <- env.appeal.api.byUserIds(user.id :: userLogins.otherUserIds)
} data <- loginsTableData(user, userLogins, nbOthers)
} } yield html.user.mod.otherUsers(holder, user, data, appeals)
val identification = userLoginsFu map { logins => val identification = userLoginsFu map { logins =>
Granter.is(_.ViewPrintNoIP)(holder) ?? Granter.is(_.ViewPrintNoIP)(holder) ??
html.user.mod.identification(holder, user, logins) html.user.mod.identification(holder, user, logins)

View File

@ -22,6 +22,7 @@ object communication {
notes: List[lila.user.Note], notes: List[lila.user.Note],
history: List[lila.mod.Modlog], history: List[lila.mod.Modlog],
logins: lila.security.UserLogins.TableData, logins: lila.security.UserLogins.TableData,
appeals: List[lila.appeal.Appeal],
priv: Boolean priv: Boolean
)(implicit ctx: Context, renderIp: RenderIp) = )(implicit ctx: Context, renderIp: RenderIp) =
views.html.base.layout( views.html.base.layout(
@ -58,7 +59,9 @@ object communication {
), ),
isGranted(_.UserModView) option frag( isGranted(_.UserModView) option frag(
div(cls := "mod-zone none"), div(cls := "mod-zone none"),
views.html.user.mod.otherUsers(mod, u, logins)(ctx, renderIp)(cls := "communication__logins") views.html.user.mod.otherUsers(mod, u, logins, appeals)(ctx, renderIp)(
cls := "communication__logins"
)
), ),
history.nonEmpty option frag( history.nonEmpty option frag(
h2("Moderation history"), h2("Moderation history"),

View File

@ -44,11 +44,6 @@ object message {
"Sorry, boosters and sandbaggers are not allowed here." "Sorry, boosters and sandbaggers are not allowed here."
} }
def blacklisted(implicit ctx: Context) =
apply("IP address blacklisted") {
blacklistedMessage
}
def blacklistedMessage(implicit ctx: Context) = def blacklistedMessage(implicit ctx: Context) =
s"Sorry, your IP address ${HTTPRequest ipAddress ctx.req} has been used to violate the ToS, and is now blacklisted." s"Sorry, your IP address ${HTTPRequest ipAddress ctx.req} has been used to violate the ToS, and is now blacklisted."

View File

@ -7,12 +7,13 @@ import lila.api.Context
import lila.app.templating.Environment._ import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._ import lila.app.ui.ScalatagsTemplate._
import lila.evaluation.Display import lila.evaluation.Display
import lila.mod.IpRender.RenderIp
import lila.mod.ModPresets import lila.mod.ModPresets
import lila.playban.RageSit import lila.playban.RageSit
import lila.security.Granter import lila.security.Granter
import lila.security.{ Permission, UserLogins } import lila.security.{ Permission, UserLogins }
import lila.user.{ Holder, User } import lila.user.{ Holder, User }
import lila.mod.IpRender.RenderIp import lila.appeal.Appeal
object mod { object mod {
private def mzSection(key: String) = div(id := s"mz_$key", cls := "mz-section") private def mzSection(key: String) = div(id := s"mz_$key", cls := "mz-section")
@ -525,7 +526,7 @@ object mod {
if (nb > 0) td(cls := "i", dataSort := nb)(content) if (nb > 0) td(cls := "i", dataSort := nb)(content)
else td else td
def otherUsers(mod: Holder, u: User, data: UserLogins.TableData)(implicit def otherUsers(mod: Holder, u: User, data: UserLogins.TableData, appeals: List[Appeal])(implicit
ctx: Context, ctx: Context,
renderIp: RenderIp renderIp: RenderIp
): Tag = { ): Tag = {
@ -552,6 +553,7 @@ object mod {
sortNumberTh(closed)(cls := "i", title := "Closed"), sortNumberTh(closed)(cls := "i", title := "Closed"),
sortNumberTh(reportban)(cls := "i", title := "Reportban"), sortNumberTh(reportban)(cls := "i", title := "Reportban"),
sortNumberTh(notesText)(cls := "i", title := "Notes"), sortNumberTh(notesText)(cls := "i", title := "Notes"),
sortNumberTh(iconTag("6"))(cls := "i", title := "Appeals"),
sortNumberTh("Created"), sortNumberTh("Created"),
sortNumberTh("Active"), sortNumberTh("Active"),
isGranted(_.CloseAccount) option th isGranted(_.CloseAccount) option th
@ -561,6 +563,7 @@ object mod {
othersWithEmail.others.map { case other @ UserLogins.OtherUser(o, _, _) => othersWithEmail.others.map { case other @ UserLogins.OtherUser(o, _, _) =>
val userNotes = val userNotes =
notes.filter(n => n.to == o.id && (ctx.me.exists(n.isFrom) || isGranted(_.Admin))) notes.filter(n => n.to == o.id && (ctx.me.exists(n.isFrom) || isGranted(_.Admin)))
val userAppeal = appeals.find(_.isAbout(o.id))
tr( tr(
dataTags := s"${other.ips.map(renderIp).mkString(" ")} ${other.fps.mkString(" ")}", dataTags := s"${other.ips.map(renderIp).mkString(" ")} ${other.fps.mkString(" ")}",
cls := (o == u) option "same" cls := (o == u) option "same"
@ -598,6 +601,18 @@ object mod {
) )
) )
} getOrElse td(dataSort := 0), } getOrElse td(dataSort := 0),
userAppeal match {
case None => td(dataSort := 0)
case Some(appeal) =>
td(dataSort := 1)(
a(
href := isGranted(_.Appeals).option(routes.Appeal.show(o.username).url),
cls := "text",
dataIcon := "6",
title := pluralize("appeal message", appeal.msgs.size)
)(appeal.msgs.size)
)
},
td(dataSort := o.createdAt.getMillis)(momentFromNowServer(o.createdAt)), td(dataSort := o.createdAt.getMillis)(momentFromNowServer(o.createdAt)),
td(dataSort := o.seenAt.map(_.getMillis.toString))(o.seenAt.map(momentFromNowServer)), td(dataSort := o.seenAt.map(_.getMillis.toString))(o.seenAt.map(momentFromNowServer)),
isGranted(_.CloseAccount) option td( isGranted(_.CloseAccount) option td(

View File

@ -17,6 +17,8 @@ final class AppealApi(
def get(user: User) = coll.byId[Appeal](user.id) def get(user: User) = coll.byId[Appeal](user.id)
def byUserIds(userIds: List[User.ID]) = coll.byIds[Appeal](userIds)
def exists(user: User) = coll.exists($id(user.id)) def exists(user: User) = coll.exists($id(user.id))
def post(text: String, me: User) = def post(text: String, me: User) =