lila/modules/challenge/src/main/ChallengeRepo.scala

155 lines
4.6 KiB
Scala

package lila.challenge
import org.joda.time.DateTime
import scala.annotation.nowarn
import lila.common.config.Max
import lila.db.dsl._
final private class ChallengeRepo(coll: Coll, maxPerUser: Max)(implicit
ec: scala.concurrent.ExecutionContext
) {
import BSONHandlers._
import Challenge._
def byId(id: Challenge.ID) = coll.find($id(id)).one[Challenge]
def byIdFor(id: Challenge.ID, dest: lila.user.User) =
coll.find($id(id) ++ $doc("destUser.id" -> dest.id)).one[Challenge]
def byIdBy(id: Challenge.ID, orig: lila.user.User) =
coll.find($id(id) ++ $doc("challenger.id" -> orig.id)).one[Challenge]
def exists(id: Challenge.ID) = coll.countSel($id(id)).dmap(0 <)
def insert(c: Challenge): Funit =
coll.insert.one(c) >> c.challengerUser.?? { challenger =>
createdByChallengerId(challenger.id).flatMap {
case challenges if challenges.sizeIs <= maxPerUser.value => funit
case challenges => challenges.drop(maxPerUser.value).map(_.id).map(remove).sequenceFu.void
}
}
def update(c: Challenge): Funit = coll.update.one($id(c.id), c).void
def createdByChallengerId(userId: String): Fu[List[Challenge]] =
coll
.find(selectCreated ++ $doc("challenger.id" -> userId))
.sort($doc("createdAt" -> 1))
.cursor[Challenge]()
.list()
def createdByDestId(userId: String): Fu[List[Challenge]] =
coll
.find(selectCreated ++ $doc("destUser.id" -> userId))
.sort($doc("createdAt" -> 1))
.cursor[Challenge]()
.list()
def setChallenger(c: Challenge, color: Option[chess.Color]) =
coll.update
.one(
$id(c.id),
$set($doc("challenger" -> c.challenger) ++ color.?? { c =>
$doc("colorChoice" -> Challenge.ColorChoice(c), "finalColor" -> c)
})
)
.void
private[challenge] def allWithUserId(userId: String): Fu[List[Challenge]] =
createdByChallengerId(userId) zip createdByDestId(userId) dmap { case (x, y) =>
x ::: y
}
@nowarn("cat=unused") def like(c: Challenge) =
~(for {
challengerId <- c.challengerUserId
destUserId <- c.destUserId
if c.active
} yield coll.one[Challenge](
selectCreated ++ $doc(
"challenger.id" -> challengerId,
"destUser.id" -> destUserId
)
))
private[challenge] def countCreatedByDestId(userId: String): Fu[Int] =
coll.countSel(selectCreated ++ $doc("destUser.id" -> userId))
private[challenge] def realTimeUnseenSince(date: DateTime, max: Int): Fu[List[Challenge]] = {
val selector = $doc(
"seenAt" $lt date,
"status" -> Status.Created.id,
"timeControl" $exists true
)
coll
.find(selector)
.hint(coll hint $doc("seenAt" -> 1)) // partial index
.cursor[Challenge]()
.list(max)
.recoverWith { case _: reactivemongo.core.errors.DatabaseException =>
coll.list[Challenge](selector, max)
}
}
private[challenge] def expired(max: Int): Fu[List[Challenge]] =
coll.list[Challenge]($doc("expiresAt" $lt DateTime.now), max)
def setSeenAgain(id: Challenge.ID) =
coll.update
.one(
$id(id),
$doc(
"$set" -> $doc(
"status" -> Status.Created.id,
"seenAt" -> DateTime.now,
"expiresAt" -> inTwoWeeks
)
)
)
.void
def setSeen(id: Challenge.ID) =
coll.update
.one(
$id(id),
$doc("$set" -> $doc("seenAt" -> DateTime.now))
)
.void
def offline(challenge: Challenge) = setStatus(challenge, Status.Offline, Some(_ plusHours 3))
def cancel(challenge: Challenge) = setStatus(challenge, Status.Canceled, Some(_ plusHours 3))
def decline(challenge: Challenge) = setStatus(challenge, Status.Declined, Some(_ plusHours 3))
def accept(challenge: Challenge) = setStatus(challenge, Status.Accepted, Some(_ plusHours 3))
def statusById(id: Challenge.ID) =
coll
.find(
$id(id),
$doc("status" -> true, "_id" -> false).some
)
.one[Bdoc]
.map { _.flatMap(_.getAsOpt[Status]("status")) }
private def setStatus(
challenge: Challenge,
status: Status,
expiresAt: Option[DateTime => DateTime]
) =
coll.update
.one(
selectCreated ++ $id(challenge.id),
$doc(
"$set" -> $doc(
"status" -> status.id,
"expiresAt" -> expiresAt.fold(inTwoWeeks) { _(DateTime.now) }
)
)
)
.void
private[challenge] def remove(id: Challenge.ID) = coll.delete.one($id(id)).void
private val selectCreated = $doc("status" -> Status.Created.id)
}