lila/modules/appeal/src/main/AppealApi.scala

131 lines
3.8 KiB
Scala

package lila.appeal
import org.joda.time.DateTime
import lila.db.dsl._
import lila.user.{ Holder, NoteApi, User, UserRepo }
import reactivemongo.api.ReadPreference
final class AppealApi(
coll: Coll,
userRepo: UserRepo,
noteApi: NoteApi,
snoozer: lila.memo.Snoozer[Appeal.SnoozeKey]
)(implicit ec: scala.concurrent.ExecutionContext) {
import BsonHandlers._
def mine(me: User): Fu[Option[Appeal]] = coll.byId[Appeal](me.id)
def get(user: User) = coll.byId[Appeal](user.id)
def byUserIds(userIds: List[User.ID]) = coll.byIds[Appeal](userIds)
def byId(appealId: User.ID) = coll.byId[Appeal](appealId)
def exists(user: User) = coll.exists($id(user.id))
def post(text: String, me: User) =
mine(me) flatMap {
case None =>
val appeal =
Appeal(
_id = me.id,
msgs = Vector(
AppealMsg(
by = me.id,
text = text,
at = DateTime.now
)
),
status = Appeal.Status.Unread,
createdAt = DateTime.now,
updatedAt = DateTime.now,
firstUnrepliedAt = DateTime.now
)
coll.insert.one(appeal) inject appeal
case Some(prev) =>
val appeal = prev.post(text, me)
coll.update.one($id(appeal.id), appeal) inject appeal
}
def reply(text: String, prev: Appeal, mod: Holder, preset: Option[String]) = {
val appeal = prev.post(text, mod.user)
coll.update.one($id(appeal.id), appeal) >> {
preset ?? { note =>
userRepo.byId(appeal.id) flatMap {
_ ?? { noteApi.write(_, s"Appeal reply: $note", mod.user, modOnly = true, dox = false) }
}
}
} inject appeal
}
def countUnread = coll.countSel($doc("status" -> Appeal.Status.Unread.key))
def queueOf(mod: User) = bothQueues(snoozer snoozedKeysOf mod.id map (_.appealId))
private def bothQueues(exceptIds: Iterable[User.ID]): Fu[List[Appeal.WithUser]] =
fetchQueue(
selector = $doc("status" -> Appeal.Status.Unread.key) ++ {
exceptIds.nonEmpty ?? $doc("_id" $nin exceptIds)
},
ascending = true,
nb = 30
) flatMap { unreads =>
fetchQueue(
selector = $doc("status" $ne Appeal.Status.Unread.key),
ascending = false,
nb = 40 - unreads.size
) map { unreads ::: _ }
}
private def fetchQueue(selector: Bdoc, ascending: Boolean, nb: Int): Fu[List[Appeal.WithUser]] =
coll
.aggregateList(
maxDocs = nb,
ReadPreference.secondaryPreferred
) { framework =>
import framework._
Match(selector) -> List(
Sort((if (ascending) Ascending.apply _ else Descending.apply _)("firstUnrepliedAt")),
Limit(nb),
PipelineOperator(
$lookup.simple(
from = userRepo.coll,
as = "user",
local = "_id",
foreign = "_id"
)
),
UnwindField("user")
)
}
.map { docs =>
for {
doc <- docs
appeal <- doc.asOpt[Appeal]
user <- doc.getAsOpt[User]("user")
} yield Appeal.WithUser(appeal, user)
}
def setRead(appeal: Appeal) =
coll.update.one($id(appeal.id), appeal.read).void
def setUnread(appeal: Appeal) =
coll.update.one($id(appeal.id), appeal.unread).void
def toggleMute(appeal: Appeal) =
coll.update.one($id(appeal.id), appeal.toggleMute).void
def setReadById(userId: User.ID) =
byId(userId) flatMap { _ ?? setRead }
def setUnreadById(userId: User.ID) =
byId(userId) flatMap { _ ?? setUnread }
def onAccountClose(user: User) = setReadById(user.id)
def snooze(mod: User, appealId: User.ID, duration: String): Unit =
snoozer.set(Appeal.SnoozeKey(mod.id, appealId), duration)
}