Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose arena conditions in API response #583

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions modules/swiss/src/main/SwissApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,18 @@ final class SwissApi(

def join(id: Swiss.Id, me: User, isInTeam: TeamID => Boolean): Fu[Boolean] =
Sequencing(id)(notFinishedById) { swiss =>
colls.player // try a rejoin first
.updateField($id(SwissPlayer.makeId(swiss.id, me.id)), SwissPlayer.Fields.absent, false)
.flatMap { rejoin =>
fuccess(rejoin.n == 1) >>| { // if the match failed (not the update!), try a join
(swiss.isEnterable && isInTeam(swiss.teamId)) ?? {
colls.player.insert.one(SwissPlayer.make(swiss.id, me, swiss.perfLens)) zip
colls.swiss.update.one($id(swiss.id), $inc("nbPlayers" -> 1)) inject true
if (!isInTeam(swiss.teamId)) fuFalse
else
colls.player // try a rejoin first
.updateField($id(SwissPlayer.makeId(swiss.id, me.id)), SwissPlayer.Fields.absent, false)
.flatMap { rejoin =>
fuccess(rejoin.n == 1) >>| { // if the match failed (not the update!), try a join
swiss.isEnterable ?? {
colls.player.insert.one(SwissPlayer.make(swiss.id, me, swiss.perfLens)) zip
colls.swiss.update.one($id(swiss.id), $inc("nbPlayers" -> 1)) inject true
}
}
}
}
} flatMap { res =>
recomputeAndUpdateAll(id) inject res
}
Expand Down
6 changes: 4 additions & 2 deletions modules/swiss/src/main/SwissJson.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ final class SwissJson(
} yield swissJsonBase(swiss) ++ Json
.obj(
"canJoin" -> {
(swiss.isNotFinished && myInfo.exists(_.player.absent)) ||
(myInfo.isEmpty && swiss.isEnterable && isInTeam)
{
(swiss.isNotFinished && myInfo.exists(_.player.absent)) ||
(myInfo.isEmpty && swiss.isEnterable)
} && isInTeam
},
"standing" -> standing,
"situations" -> situations.map(situationJson)
Expand Down
8 changes: 7 additions & 1 deletion modules/tournament/src/main/ApiJsonView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import lila.user.LightUserApi
final class ApiJsonView(lightUserApi: LightUserApi)(implicit ec: scala.concurrent.ExecutionContext) {

import JsonView._
import Condition.JSONHandlers._

def apply(tournaments: VisibleTournaments)(implicit lang: Lang): Fu[JsObject] =
for {
Expand Down Expand Up @@ -55,7 +56,12 @@ final class ApiJsonView(lightUserApi: LightUserApi)(implicit ec: scala.concurren
"perf" -> tour.perfType.map(perfJson)
)
.add("secondsToStart", tour.secondsToStart.some.filter(0 <))
.add("hasMaxRating", tour.conditions.maxRating.isDefined)
.add("hasMaxRating", tour.conditions.maxRating.isDefined) // BC
.add[Condition.RatingCondition]("maxRating", tour.conditions.maxRating)
.add[Condition.RatingCondition]("minRating", tour.conditions.minRating)
.add("minRatedGames", tour.conditions.nbRatedGame)
.add("onlyTitled", tour.conditions.titled.isDefined)
.add("teamMember", tour.conditions.teamMember.map(_.teamId))
.add("private", tour.isPrivate)
.add("position", tour.position.map(sfen => positionJson(sfen, tour.variant)))
.add("schedule", tour.schedule map scheduleJson)
Expand Down
36 changes: 34 additions & 2 deletions modules/tournament/src/main/Condition.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ object Condition {
}
}

case class MaxRating(perf: PerfType, rating: Int) extends Condition {
abstract trait RatingCondition {
val perf: PerfType
val rating: Int
}

case class MaxRating(perf: PerfType, rating: Int) extends Condition with RatingCondition {

def apply(
getMaxRating: GetMaxRating
Expand All @@ -90,7 +95,7 @@ object Condition {
def name(implicit lang: Lang) = trans.ratedLessThanInPerf.txt(rating, perf.trans)
}

case class MinRating(perf: PerfType, rating: Int) extends Condition with FlatCond {
case class MinRating(perf: PerfType, rating: Int) extends Condition with RatingCondition with FlatCond {

def apply(user: User) =
if (user.hasTitle) Accepted
Expand Down Expand Up @@ -144,6 +149,14 @@ object Condition {
case c: TeamMember => c(user, getUserTeamIds) map { c withVerdict _ }
}.sequenceFu dmap All.WithVerdicts.apply

def withRejoinVerdicts(user: User, getUserTeamIds: User => Fu[List[TeamID]])(implicit
ec: scala.concurrent.ExecutionContext
): Fu[All.WithVerdicts] =
list.map {
case c: TeamMember => c(user, getUserTeamIds) map { c withVerdict _ }
case c => fuccess(WithVerdict(c, Accepted))
}.sequenceFu dmap All.WithVerdicts.apply

def accepted = All.WithVerdicts(list.map { WithVerdict(_, Accepted) })

def sameMaxRating(other: All) = maxRating.map(_.rating) == other.maxRating.map(_.rating)
Expand Down Expand Up @@ -177,6 +190,10 @@ object Condition {
val getMaxRating: GetMaxRating = perf => historyApi.lastWeekTopRating(user, perf)
all.withVerdicts(getMaxRating)(user, getUserTeamIds)
}
def rejoin(all: All, user: User, getUserTeamIds: User => Fu[List[TeamID]])(implicit
ec: scala.concurrent.ExecutionContext
): Fu[All.WithVerdicts] =
all.withRejoinVerdicts(user, getUserTeamIds)
def canEnter(user: User, getUserTeamIds: User => Fu[List[TeamID]])(
tour: Tournament
)(implicit ec: scala.concurrent.ExecutionContext): Fu[Boolean] =
Expand Down Expand Up @@ -213,6 +230,21 @@ object Condition {
},
"accepted" -> verdicts.accepted
)

implicit val ratingConditionWrites: OWrites[Condition.RatingCondition] =
OWrites[Condition.RatingCondition] { r =>
Json.obj(
"perf" -> r.perf.key,
"rating" -> r.rating
)
}

implicit val nbRatedGameConditionWrites: OWrites[Condition.NbRatedGame] =
OWrites[Condition.NbRatedGame] { r =>
Json
.obj("nb" -> r.nb)
.add("perf" -> r.perf.map(_.key))
}
}

object DataForm {
Expand Down
19 changes: 14 additions & 5 deletions modules/tournament/src/main/JsonView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ final class JsonView(
)(implicit ec: ExecutionContext) {

import JsonView._
import Condition.JSONHandlers._

private case class CachableData(
duels: JsArray,
Expand Down Expand Up @@ -68,10 +69,11 @@ final class JsonView(
playerInfoExtended(tour, pie).map(_.some)
}
verdicts <- full ?? {
me match {
case None => fuccess(tour.conditions.accepted.some)
case Some(_) if myInfo.isDefined => fuccess(tour.conditions.accepted.some)
case Some(user) => verify(tour.conditions, user, getUserTeamIds) map some
(me, myInfo) match {
case (None, _) => fuccess(tour.conditions.accepted.some)
case (Some(_), Some(myInfo)) if !myInfo.withdraw => fuccess(tour.conditions.accepted.some)
case (Some(user), Some(_)) => verify.rejoin(tour.conditions, user, getUserTeamIds) map some
case (Some(user), None) => verify(tour.conditions, user, getUserTeamIds) map some
}
}
stats <- statsApi(tour)
Expand Down Expand Up @@ -134,11 +136,18 @@ final class JsonView(
.obj(
"teams" -> JsObject(battle.sortedTeamIds.map { id =>
id -> JsString(getTeamName(id).getOrElse(id))
})
}),
"nbLeaders" -> battle.nbLeaders
)
.add("joinWith" -> me.isDefined.option(teamsToJoinWith.sorted))
})
.add("description" -> tour.description)
.add("myUsername" -> me.map(_.username))
.add[Condition.RatingCondition]("minRating", tour.conditions.minRating)
.add[Condition.RatingCondition]("maxRating", tour.conditions.maxRating)
.add("minRatedGames", tour.conditions.nbRatedGame)
.add("onlyTitled", tour.conditions.titled.isDefined)
.add("teamMember", tour.conditions.teamMember.map(_.teamId))
}

def clearCache(tour: Tournament): Unit = {
Expand Down
2 changes: 1 addition & 1 deletion modules/tournament/src/main/TournamentApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ final class TournamentApi(
{
tour.isStarted ?? playerRepo.exists(tour.id, user.id)
} flatMap {
case true => fuccess(tour.conditions.accepted)
case true => verify.rejoin(tour.conditions, user, getUserTeamIds)
case _ => verify(tour.conditions, user, getUserTeamIds)
}
}
Expand Down
13 changes: 13 additions & 0 deletions public/doc/lishogi-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5056,6 +5056,19 @@ components:
"name": "Blitz",
"position": 1
},
"maxRating": {
"perf": "blitz",
"rating": 2000
},
"minRating": {
"perf": "blitz",
"rating": 1500
},
"minRatedGames": {
"nb": 5,
"perf": "blitz"
},
"onlyTitled": true,
"schedule": {
"freq": "hourly",
"speed": "superblitz"
Expand Down