lila/modules/playban/src/main/PlaybanApi.scala

113 lines
3.6 KiB
Scala
Raw Normal View History

2015-04-25 12:48:13 -06:00
package lila.playban
import org.joda.time.DateTime
import reactivemongo.bson._
import reactivemongo.bson.Macros
import scala.concurrent.duration._
2015-04-25 15:06:44 -06:00
import chess.Color
2015-04-25 12:48:13 -06:00
import lila.db.BSON._
import lila.db.dsl._
2015-04-25 15:06:44 -06:00
import lila.game.{ Pov, Game, Player, Source }
2015-04-25 12:48:13 -06:00
2015-04-27 06:07:35 -06:00
final class PlaybanApi(
coll: Coll,
isRematch: String => Boolean) {
2015-04-25 12:48:13 -06:00
import lila.db.BSON.BSONJodaDateTimeHandler
import reactivemongo.bson.Macros
private implicit val OutcomeBSONHandler = new BSONHandler[BSONInteger, Outcome] {
def read(bsonInt: BSONInteger): Outcome = Outcome(bsonInt.value) err s"No such playban outcome: ${bsonInt.value}"
def write(x: Outcome) = BSONInteger(x.id)
}
2015-04-25 15:06:44 -06:00
private implicit val banBSONHandler = Macros.handler[TempBan]
2015-04-25 12:48:13 -06:00
private implicit val UserRecordBSONHandler = Macros.handler[UserRecord]
2015-04-25 15:06:44 -06:00
private case class Blame(player: Player, outcome: Outcome)
2015-04-27 06:07:35 -06:00
private def blameable(game: Game) =
2015-06-11 03:49:59 -06:00
game.source.contains(Source.Lobby) &&
2015-04-27 06:07:35 -06:00
game.hasClock &&
!isRematch(game.id)
2015-04-25 15:06:44 -06:00
def abort(pov: Pov): Funit = blameable(pov.game) ?? {
2015-04-26 05:04:22 -06:00
if (pov.game olderThan 45) pov.game.playerWhoDidNotMove map { Blame(_, Outcome.NoPlay) }
else if (pov.game olderThan 15) none
else pov.player.some map { Blame(_, Outcome.Abort) }
} ?? {
case Blame(player, outcome) => player.userId.??(save(outcome))
}
2015-04-25 15:06:44 -06:00
2015-04-26 05:21:35 -06:00
def rageQuit(game: Game, quitterColor: Color): Funit = blameable(game) ?? {
game.player(quitterColor).userId ?? save(Outcome.RageQuit)
2015-04-26 05:04:22 -06:00
}
2015-04-25 15:06:44 -06:00
def sittingOrGood(game: Game, sitterColor: Color): Funit = blameable(game) ?? {
(for {
userId <- game.player(sitterColor).userId
lmt <- game.lastMoveTimeInSeconds
seconds = nowSeconds - lmt
clock <- game.clock
// a tenth of the total time, at least 15s, at most 3 minutes
limit = (clock.estimateTotalTime / 10) max 15 min (3 * 60)
if seconds >= limit
} yield save(Outcome.Sitting)(userId)) | goodFinish(game)
}
2015-04-26 05:04:22 -06:00
def goodFinish(game: Game): Funit = blameable(game) ?? {
game.userIds.map(save(Outcome.Good)).sequenceFu.void
2015-04-25 15:06:44 -06:00
}
2015-04-26 04:08:13 -06:00
def currentBan(userId: String): Fu[Option[TempBan]] = coll.find(
$doc("_id" -> userId, "b.0" $exists true),
$doc("_id" -> false, "b" -> $doc("$slice" -> -1))
).uno[Bdoc].map {
2015-04-26 04:08:13 -06:00
_.flatMap(_.getAs[List[TempBan]]("b")).??(_.find(_.inEffect))
}
2015-04-25 15:06:44 -06:00
def bans(userId: String): Fu[List[TempBan]] = coll.find(
$doc("_id" -> userId, "b.0" $exists true),
$doc("_id" -> false, "b" -> true)
).uno[Bdoc].map {
2015-04-25 15:06:44 -06:00
~_.flatMap(_.getAs[List[TempBan]]("b"))
}
2015-04-25 23:44:35 -06:00
def bans(userIds: List[String]): Fu[Map[String, Int]] = coll.find(
$inIds(userIds),
$doc("b" -> true)
).cursor[Bdoc]().gather[List]().map {
2015-04-25 23:44:35 -06:00
_.flatMap { obj =>
obj.getAs[String]("_id") flatMap { id =>
obj.getAs[Barr]("b") map { id -> _.stream.size }
2015-04-25 23:44:35 -06:00
}
}.toMap
}
2015-07-13 09:32:14 -06:00
private def save(outcome: Outcome): String => Funit = userId => {
coll.findAndUpdate(
selector = $doc("_id" -> userId),
update = $doc("$push" -> $doc(
"o" -> $doc(
2015-07-13 09:32:14 -06:00
"$each" -> List(outcome),
"$slice" -> -20)
)),
fetchNewObject = true,
upsert = true).map(_.value)
2015-04-25 12:48:13 -06:00
} map2 UserRecordBSONHandler.read flatMap {
2015-04-25 15:06:44 -06:00
case None => fufail(s"can't find record for user $userId")
case Some(record) => legiferate(record)
2016-03-20 03:31:09 -06:00
} logFailure lila.log("playban")
2015-04-25 15:06:44 -06:00
private def legiferate(record: UserRecord): Funit = record.newBan ?? { ban =>
coll.update(
$id(record.userId),
$unset("o") ++
$push(
"b" -> $doc(
2015-04-25 15:06:44 -06:00
"$each" -> List(ban),
"$slice" -> -30)
)
).void
}
2015-04-25 12:48:13 -06:00
}