lila/app/views/mod/communication.scala

195 lines
6.8 KiB
Scala
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package views.html.mod
import controllers.routes
import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.common.String.html.richText
import lila.common.base.StringUtils.escapeHtmlRaw
import lila.hub.actorApi.shutup.PublicSource
import lila.mod.IpRender.RenderIp
import lila.user.{ Holder, User }
import lila.shutup.Analyser
object communication {
def apply(
mod: Holder,
u: User,
players: List[(lila.game.Pov, lila.chat.MixedChat)],
convos: List[lila.msg.ModMsgConvo],
publicLines: List[lila.shutup.PublicLine],
notes: List[lila.user.Note],
history: List[lila.mod.Modlog],
logins: lila.security.UserLogins.TableData,
appeals: List[lila.appeal.Appeal],
priv: Boolean
)(implicit ctx: Context, renderIp: RenderIp) =
views.html.base.layout(
title = u.username + " communications",
moreCss = frag(
cssTag("mod.communication"),
isGranted(_.UserModView) option cssTag("mod.user")
),
moreJs = frag(
isGranted(_.UserModView) option jsModule("mod.user")
)
) {
main(id := "communication", cls := "box box-pad")(
h1(
div(cls := "title")(userLink(u), " communications"),
div(cls := "actions")(
a(
cls := "button button-empty mod-zone-toggle",
href := routes.User.mod(u.username),
titleOrText("Mod zone (Hotkey: m)"),
dataIcon := ""
),
isGranted(_.ViewPrivateComms) option {
if (priv)
a(cls := "priv button active", href := routes.Mod.communicationPublic(u.username))("PMs")
else
a(
cls := "priv button",
href := routes.Mod.communicationPrivate(u.username),
title := "View private messages. This will be logged in #commlog"
)("PMs")
}
)
),
isGranted(_.UserModView) option frag(
div(cls := "mod-zone mod-zone-full none"),
views.html.user.mod.otherUsers(mod, u, logins, appeals)(ctx, renderIp)(
cls := "mod-zone communication__logins"
)
),
history.nonEmpty option frag(
h2("Moderation history"),
div(cls := "history")(
history.map { e =>
div(
userIdLink(e.mod.some),
" ",
b(e.showAction),
" ",
u.username,
" ",
e.details,
" ",
momentFromNowOnce(e.date)
)
}
)
),
notes.nonEmpty option frag(
h2("Notes from other users"),
div(cls := "notes")(
notes.map { note =>
(isGranted(_.Admin) || !note.dox) option
div(
userIdLink(note.from.some),
" ",
momentFromNowOnce(note.date),
": ",
richText(note.text)
)
}
)
),
h2("Dubious public chats"),
if (publicLines.isEmpty) strong("None!")
else
ul(cls := "public_chats")(
publicLines.reverse.map { line =>
li(cls := "line author")(
line.date.fold[Frag]("[OLD]")(momentFromNowOnce),
" ",
line.from.map {
case PublicSource.Tournament(id) => tournamentLink(id)
case PublicSource.Simul(id) => views.html.simul.bits.link(id)
case PublicSource.Team(id) => views.html.team.bits.link(id)
case PublicSource.Watcher(id) => a(href := routes.Round.watcher(id, "white"))("Game #", id)
case PublicSource.Study(id) => a(href := routes.Study.show(id))("Study #", id)
case PublicSource.Swiss(id) => views.html.swiss.bits.link(lila.swiss.Swiss.Id(id))
},
nbsp,
span(cls := "message")(highlightBad(line.text))
)
}
),
priv option frag(
h2("Recent private chats"),
div(cls := "player_chats")(
players.map { case (pov, chat) =>
div(cls := "game")(
a(
href := routes.Round.player(pov.fullId),
cls := List(
"title" -> true,
"friend_title" -> pov.game.fromFriend
),
title := pov.game.fromFriend.option("Friend game")
)(
titleNameOrAnon(pov.opponent.userId),
" ",
momentFromNowOnce(pov.game.movedAt)
),
div(cls := "chat")(
chat.lines.map { line =>
div(
cls := List(
"line" -> true,
"author" -> (line.author.toLowerCase == u.id)
)
)(
userIdLink(line.userIdMaybe, withOnline = false, withTitle = false),
nbsp,
span(cls := "message")(highlightBad(line.text))
)
}
)
)
}
),
div(cls := "threads")(
h2("Recent inbox messages"),
convos.map { modConvo =>
div(cls := "thread")(
p(cls := "title")(strong(userLink(modConvo.contact), showSbMark(modConvo.contact))),
table(cls := "slist")(
tbody(
modConvo.truncated option div(cls := "truncated-convo")(
s"Truncated, showing last ${modConvo.msgs.length} messages"
),
modConvo.msgs.reverse.map { msg =>
val author = msg.user == u.id
tr(cls := List("post" -> true, "author" -> author))(
td(momentFromNowOnce(msg.date)),
td(strong(if (author) u.username else modConvo.contact.username)),
td(cls := "message")(highlightBad(msg.text))
)
}
)
)
)
}
)
)
)
}
// incompatible with richText
def highlightBad(text: String): Frag = {
val words = Analyser(text).badWords
if (words.isEmpty) frag(text)
else {
val regex = ("""(?iu)\b""" + words.mkString("(", "|", ")") + """\b""").r
def tag(word: String) = s"<bad>$word</bad>"
raw(regex.replaceAllIn(escapeHtmlRaw(text), m => tag(m.toString)))
}
}
private def showSbMark(u: User) = u.marks.troll option span(cls := "user_marks")(iconTag(""))
}