add endpoints to list and delete bulk pairings

pull/8068/head
Thibault Duplessis 2021-02-01 19:27:30 +01:00
parent f31cfc849c
commit 411b0752da
6 changed files with 102 additions and 48 deletions

View File

@ -154,6 +154,7 @@ final class LilaComponents(ctx: ApplicationLoader.Context) extends BuiltInCompon
lazy val swiss: Swiss = wire[Swiss]
lazy val dgt: DgtCtrl = wire[DgtCtrl]
lazy val storm: Storm = wire[Storm]
lazy val bulkPairing: BulkPairing = wire[BulkPairing]
// eagerly wire up all controllers
val router: Router = {

View File

@ -0,0 +1,59 @@
package controllers
import play.api.libs.json.Json
import lila.app._
import lila.setup.SetupBulk
final class BulkPairing(env: Env) extends LilaController(env) {
def list =
ScopedBody(_.Challenge.Bulk) { implicit req => me =>
env.challenge.bulk.scheduledBy(me) map { list =>
Ok(Json.obj("bulks" -> list.map(SetupBulk.toJson))) as JSON
}
}
def delete(id: String) =
ScopedBody(_.Challenge.Bulk) { implicit req => me =>
env.challenge.bulk.deleteBy(id, me) flatMap {
case true => jsonOkResult.fuccess
case _ => notFoundJson()
}
}
def create =
ScopedBody(_.Challenge.Bulk) { implicit req => me =>
implicit val lang = reqLang
import lila.setup.SetupBulk
lila.setup.SetupBulk.form
.bindFromRequest()
.fold(
newJsonFormError,
data =>
env.setup.bulk(data, me) flatMap {
case Left(SetupBulk.RateLimited) =>
TooManyRequests(
jsonError(s"Ratelimited! Max games per 10 minutes: ${SetupBulk.maxGames}")
).fuccess
case Left(SetupBulk.BadTokens(tokens)) =>
import lila.setup.SetupBulk.BadToken
import play.api.libs.json._
BadRequest(
Json.obj(
"tokens" -> JsObject {
tokens.map { case BadToken(token, error) =>
token.value -> JsString(error.message)
}
}
)
).fuccess
case Right(bulk) =>
env.challenge.bulk.schedule(bulk) map {
case Left(error) => BadRequest(jsonError(error))
case Right(bulk) => Ok(SetupBulk toJson bulk) as JSON
}
}
)
}
}

View File

@ -309,47 +309,6 @@ final class Challenge(
)
}
def bulk =
ScopedBody(_.Challenge.Bulk) { implicit req => me =>
implicit val lang = reqLang
import lila.setup.SetupBulk
lila.setup.SetupBulk.form
.bindFromRequest()
.fold(
newJsonFormError,
data =>
env.setup.bulk(data, me) flatMap {
case Left(SetupBulk.RateLimited) =>
TooManyRequests(
jsonError(s"Ratelimited! Max games per 10 minutes: ${SetupBulk.maxGames}")
).fuccess
case Left(SetupBulk.BadTokens(tokens)) =>
import lila.setup.SetupBulk.BadToken
import play.api.libs.json._
BadRequest(
Json.obj(
"tokens" -> JsObject {
tokens.map { case BadToken(token, error) =>
token.value -> JsString(error.message)
}
}
)
).fuccess
case Right(bulk) =>
env.challenge.bulk.schedule(bulk) map {
case Some(error) => BadRequest(jsonError(error))
case _ =>
Ok(Json.obj("games" -> bulk.games.map { g =>
Json.obj(
"gameId" -> g.id,
"userIds" -> Json.arr(g.white, g.black)
)
})) as JSON
}
}
)
}
def apiCreateAdmin(origName: String, destName: String) =
ScopedBody(_.Challenge.Write) { implicit req => admin =>
IfGranted(_.ApiChallengeAdmin, req, admin) {

View File

@ -612,7 +612,6 @@ GET /api/account/preferences controllers.Pref.apiGet
POST /api/challenge/ai controllers.Setup.apiAi
POST /api/challenge/open controllers.Challenge.openCreate
POST /api/challenge/admin/:orig/:dest controllers.Challenge.apiCreateAdmin(orig: String, dest: String)
POST /api/challenge/bulk controllers.Challenge.bulk
POST /api/challenge/:user controllers.Challenge.apiCreate(user: String)
POST /api/challenge/$id<\w{8}>/accept controllers.Challenge.apiAccept(id: String)
POST /api/challenge/$id<\w{8}>/decline controllers.Challenge.apiDecline(id: String)
@ -622,6 +621,9 @@ POST /api/round/$id<\w{8}>/add-time/:seconds controllers.Round.apiAddTime(id: S
GET /api/cloud-eval controllers.Api.cloudEval
GET /api/broadcast controllers.Relay.apiIndex
POST /api/import controllers.Importer.apiSendGame
GET /api/bulk-pairing controllers.BulkPairing.list
POST /api/bulk-pairing controllers.BulkPairing.create
DELETE /api/bulk-pairing/:id controllers.BulkPairing.delete(id: String)
GET /api/games/user/:username controllers.Game.apiExportByUser(username: String)

View File

@ -40,16 +40,22 @@ final class ChallengeBulkApi(
private val workQueue =
new DuctSequencers(maxSize = 16, expiration = 10 minutes, timeout = 10 seconds, name = "challenge.bulk")
def schedule(bulk: ScheduledBulk): Fu[Option[String]] = workQueue(bulk.by) {
if (bulk.pairAt.isBeforeNow) makePairings(bulk) inject none
def scheduledBy(me: User): Fu[List[ScheduledBulk]] =
coll.list[ScheduledBulk]($doc("by" -> me.id))
def deleteBy(id: String, me: User): Fu[Boolean] =
coll.delete.one($doc("_id" -> id, "by" -> me.id)).map(_.n == 1)
def schedule(bulk: ScheduledBulk): Fu[Either[String, ScheduledBulk]] = workQueue(bulk.by) {
if (bulk.pairAt.isBeforeNow) makePairings(bulk) inject Right(bulk.copy(pairedAt = DateTime.now.some))
else
coll.list[ScheduledBulk]($doc("by" -> bulk.by, "pairedAt" $exists false)) flatMap { bulks =>
val nbGames = bulks.map(_.games.size).sum
if (bulks.sizeIs >= 10) fuccess("Already too many bulks queued".some)
else if (bulks.map(_.games.size).sum >= 1000) fuccess("Already too many games queued".some)
if (bulks.sizeIs >= 10) fuccess(Left("Already too many bulks queued"))
else if (bulks.map(_.games.size).sum >= 1000) fuccess(Left("Already too many games queued"))
else if (bulks.exists(_ collidesWith bulk))
fuccess("A bulk containing the same players is scheduled at the same time".some)
else coll.insert.one(bulk) inject none
fuccess(Left("A bulk containing the same players is scheduled at the same time"))
else coll.insert.one(bulk) inject Right(bulk)
}
}

View File

@ -7,6 +7,7 @@ import chess.{ Clock, Mode, Speed }
import org.joda.time.DateTime
import play.api.data._
import play.api.data.Forms._
import play.api.libs.json.Json
import scala.concurrent.duration._
import lila.game.Game
@ -106,6 +107,32 @@ object SetupBulk {
sealed trait ScheduleError
case class BadTokens(tokens: List[BadToken]) extends ScheduleError
case object RateLimited extends ScheduleError
def toJson(bulk: ScheduledBulk) = {
import bulk._
import lila.common.Json.jodaWrites
Json.obj(
"id" -> _id,
"games" -> games.map { g =>
Json.obj(
"id" -> g.id,
"white" -> g.white,
"black" -> g.black
)
},
"variant" -> variant.key,
"clock" -> Json.obj(
"limit" -> clock.limitSeconds,
"increment" -> clock.incrementSeconds
),
"rated" -> mode.rated,
"pairAt" -> pairAt,
"startClocksAt" -> startClocksAt,
"scheduledAt" -> scheduledAt,
"pairedAt" -> pairedAt
)
}
}
final class BulkChallengeApi(oauthServer: OAuthServer, idGenerator: IdGenerator)(implicit