195 lines
6.8 KiB
Scala
195 lines
6.8 KiB
Scala
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(""))
|
||
}
|