lila/modules/chat/src/main/Line.scala

109 lines
2.7 KiB
Scala

package lila.chat
import chess.Color
import lila.user.{ Title, User }
sealed trait Line {
def text: String
def author: String
def deleted: Boolean
def isSystem = author == systemUserId
def isHuman = !isSystem
def humanAuthor = isHuman option author
def troll: Boolean
def userIdMaybe: Option[User.ID]
}
case class UserLine(
username: String,
title: Option[Title],
patron: Boolean,
text: String,
troll: Boolean,
deleted: Boolean
) extends Line {
def author = username
def userId = User normalize username
def userIdMaybe = userId.some
def delete = copy(deleted = true)
def isVisible = !troll && !deleted
def isLichess = userId == User.lichessId
}
case class PlayerLine(
color: Color,
text: String
) extends Line {
def deleted = false
def author = color.name
def troll = false
def userIdMaybe = none
}
object Line {
val textMaxSize = 140
val titleSep = '~'
import reactivemongo.api.bson._
private val invalidLine = UserLine("", None, false, "[invalid character]", troll = false, deleted = true)
implicit private[chat] val userLineBSONHandler = BSONStringHandler.as[UserLine](
v => strToUserLine(v) getOrElse invalidLine,
userLineToStr
)
implicit private[chat] val lineBSONHandler = BSONStringHandler.as[Line](
v => strToLine(v) getOrElse invalidLine,
lineToStr
)
private val trollChar = "!"
private val deletedChar = "?"
private val patronChar = "&"
private val UserLineRegex = {
"""(?s)([\w-~]{2,}+)([ """ + s"$trollChar$deletedChar$patronChar" + """])(.++)"""
}.r
private def strToUserLine(str: String): Option[UserLine] =
str match {
case UserLineRegex(username, sep, text) =>
val troll = sep == trollChar
val deleted = sep == deletedChar
val patron = sep == patronChar
username split titleSep match {
case Array(title, name) =>
UserLine(name, Title get title, patron, text, troll = troll, deleted = deleted).some
case _ => UserLine(username, None, patron, text, troll = troll, deleted = deleted).some
}
case _ => none
}
def userLineToStr(x: UserLine): String = {
val sep =
if (x.troll) trollChar
else if (x.deleted) deletedChar
else if (x.patron) patronChar
else " "
val tit = x.title.??(_.value + titleSep)
s"$tit${x.username}$sep${x.text}"
}
def strToLine(str: String): Option[Line] =
strToUserLine(str) orElse {
str.headOption flatMap Color.apply map { color =>
PlayerLine(color, str drop 2)
}
}
def lineToStr(x: Line) =
x match {
case u: UserLine => userLineToStr(u)
case p: PlayerLine => s"${p.color.letter} ${p.text}"
}
}