Skip to content

Commit

Permalink
Merge branch 'master' into if-challenge-has-rules-dont-accept-immedia…
Browse files Browse the repository at this point in the history
…tely
  • Loading branch information
ornicar committed Jun 27, 2024
2 parents fb53283 + 59fdaaf commit 5536d41
Show file tree
Hide file tree
Showing 126 changed files with 638 additions and 443 deletions.
1 change: 1 addition & 0 deletions app/controllers/Account.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ final class Account(
me.value,
withFollows = apiC.userWithFollows,
withTrophies = false,
withCanChallenge = false,
forWiki = wikiGranted
)
.dmap { JsonOk(_) }
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ final class Api(
.extended(
name,
withFollows = userWithFollows,
withTrophies = getBool("trophies")
withTrophies = getBool("trophies"),
withCanChallenge = getBool("challenge")
)
.map(toApiResult)
.map(toHttp)
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/Challenge.scala
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ final class Challenge(
case None => redir
case Some(dest) if ctx.is(dest) => redir
case Some(dest) =>
env.challenge.granter.isDenied(dest, c.perfType).flatMap {
env.challenge.granter.isDenied(dest, c.perfType.key.some).flatMap {
case Some(denied) =>
showChallenge(c, lila.challenge.ChallengeDenied.translated(denied).some)
case None => api.setDestUser(c, dest).inject(redir)
Expand Down Expand Up @@ -303,7 +303,7 @@ final class Challenge(
limit.challengeUser(me, rateLimited, cost = cost):
for
challenge <- makeOauthChallenge(config, me, destUser)
grant <- env.challenge.granter.isDenied(destUser, config.perfType)
grant <- env.challenge.granter.isDenied(destUser, config.perfKey.some)
res <- grant match
case Some(denied) =>
fuccess:
Expand Down Expand Up @@ -376,7 +376,7 @@ final class Challenge(
NoBot:
Found(env.game.gameRepo.game(gameId)): g =>
g.opponentOf(me).flatMap(_.userId).so(env.user.repo.byId).orNotFound { opponent =>
env.challenge.granter.isDenied(opponent, g.perfKey).flatMap {
env.challenge.granter.isDenied(opponent, g.perfKey.some).flatMap {
case Some(d) => BadRequest(jsonError(lila.challenge.ChallengeDenied.translated(d)))
case _ =>
api.offerRematchForGame(g, me).map {
Expand Down
9 changes: 8 additions & 1 deletion app/controllers/RelayRound.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ final class RelayRound(
studyC.CanView(study)(
for
group <- env.relay.api.withTours.get(rt.tour.id)
previews <- env.study.preview.jsonList(study.id)
previews <- env.study.preview.jsonList.withoutInitialEmpty(study.id)
yield JsonOk(env.relay.jsonView.withUrlAndPreviews(rt.withStudy(study), previews, group))
)(studyC.privateUnauthorizedJson, studyC.privateForbiddenJson)

Expand Down Expand Up @@ -187,6 +187,13 @@ final class RelayRound(
env.relay.teamTable.tableJson(rt.relay).map(JsonStrOk)
}(Unauthorized, Forbidden)

def stats(id: RelayRoundId) = Open:
env.relay.stats
.get(id)
.map: stats =>
import lila.relay.JsonView.given
JsonOk(stats)

private def WithRoundAndTour(@nowarn ts: String, @nowarn rs: String, id: RelayRoundId)(
f: RoundModel.WithTour => Fu[Result]
)(using ctx: Context): Fu[Result] =
Expand Down
7 changes: 0 additions & 7 deletions app/controllers/RelayTour.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,6 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env):
asAttachmentStream(s"${env.relay.pgnStream.filename(tour)}.pgn"):
Ok.chunked(source).as(pgnContentType)

def stats(id: RelayTourId) = Open:
Found(env.relay.api.tourById(id)): tour =>
env.relay.stats
.get(tour.id)
.flatMap: stats =>
Ok.page(views.relay.tour.stats(tour, stats))

def apiIndex = Anon:
apiC.jsonDownload:
env.relay.tourStream
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ final class Setup(
for
origUser <- ctx.user.soFu(env.user.perfsRepo.withPerf(_, config.perfType))
destUser <- userId.so(env.user.api.enabledWithPerf(_, config.perfType))
denied <- destUser.so(u => env.challenge.granter.isDenied(u.user, config.perfType))
denied <- destUser.so(u => env.challenge.granter.isDenied(u.user, config.perfKey.some))
result <- denied match
case Some(denied) =>
val message = lila.challenge.ChallengeDenied.translated(denied)
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/TeamApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ final class TeamApi(env: Env, apiC: => Api) extends LilaController(env):
else ctx.me.so(api.belongsTo(team.id, _))
canView.map:
if _ then
val full = getBool("full")
apiC.jsonDownload(
env.team
.memberStream(team, MaxPerSecond(20))
.memberStream(team, full)
.map: (user, joinedAt) =>
env.api.userApi.one(user, joinedAt.some)
)
Expand Down
2 changes: 1 addition & 1 deletion conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ GET /broadcast/all-private controllers.RelayTour.allPrivate(p
GET /broadcast/:ts/$id<\w{8}> controllers.RelayTour.show(ts, id: RelayTourId)
GET /api/broadcast/$id<\w{8}> controllers.RelayTour.apiShow(id: RelayTourId)
GET /api/broadcast/$tourId<\w{8}>.pgn controllers.RelayTour.pgn(tourId: RelayTourId)
GET /broadcast/$tourId<\w{8}>/stats controllers.RelayTour.stats(tourId: RelayTourId)
GET /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.edit(tourId: RelayTourId)
POST /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.update(tourId: RelayTourId)
POST /broadcast/$tourId<\w{8}>/delete controllers.RelayTour.delete(tourId: RelayTourId)
Expand All @@ -278,6 +277,7 @@ GET /broadcast/round/$roundId<\w{8}>/edit controllers.RelayRound.edit(roundI
POST /broadcast/round/$roundId<\w{8}>/edit controllers.RelayRound.update(roundId: RelayRoundId)
POST /broadcast/round/$roundId<\w{8}>/reset controllers.RelayRound.reset(roundId: RelayRoundId)
POST /broadcast/round/$roundId<\w{8}>/push controllers.RelayRound.push(roundId: RelayRoundId)
GET /broadcast/round/$roundId<\w{8}>/stats controllers.RelayRound.stats(roundId: RelayRoundId)
POST /api/broadcast/round/$roundId<\w{8}>/push controllers.RelayRound.push(roundId: RelayRoundId)
GET /broadcast/:ts/:rs/$roundId<\w{8}>.pgn controllers.RelayRound.pgn(ts, rs, roundId: RelayRoundId)
GET /broadcast/$roundId<\w{8}>/teams controllers.RelayRound.teamsView(roundId: RelayRoundId)
Expand Down
20 changes: 15 additions & 5 deletions modules/api/src/main/UserApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import lila.core.perm.Granter
import lila.user.Trophy
import lila.rating.PerfType
import lila.core.perf.UserWithPerfs
import lila.core.LightUser

final class UserApi(
jsonView: lila.user.JsonView,
Expand All @@ -27,27 +28,33 @@ final class UserApi(
trophyApi: lila.user.TrophyApi,
shieldApi: lila.tournament.TournamentShieldApi,
revolutionApi: lila.tournament.RevolutionApi,
challengeGranter: lila.challenge.ChallengeGranter,
net: NetConfig
)(using Executor, lila.core.i18n.Translator):

def one(u: UserWithPerfs, joinedAt: Option[Instant] = None): JsObject = {
addStreaming(jsonView.full(u.user, u.perfs.some, withProfile = true), u.id) ++
Json.obj("url" -> makeUrl(s"@/${u.username}")) // for app BC
def one(u: UserWithPerfs | LightUser, joinedAt: Option[Instant] = None): JsObject = {
val (light, userJson) = u match
case u: UserWithPerfs => (u.user.light, jsonView.full(u.user, u.perfs.some, withProfile = false))
case u: LightUser => (u, Json.toJsObject(u))
addStreaming(userJson, light.id) ++
Json.obj("url" -> makeUrl(s"@/${light.name}")) // for app BC
}.add("joinedTeamAt", joinedAt)

def extended(
username: UserStr,
withFollows: Boolean,
withTrophies: Boolean
withTrophies: Boolean,
withCanChallenge: Boolean
)(using Option[Me], Lang): Fu[Option[JsObject]] =
userApi.withPerfs(username).flatMapz {
extended(_, withFollows, withTrophies).dmap(some)
extended(_, withFollows, withTrophies, withCanChallenge).dmap(some)
}

def extended(
u: User | UserWithPerfs,
withFollows: Boolean,
withTrophies: Boolean,
withCanChallenge: Boolean,
forWiki: Boolean = false
)(using as: Option[Me], lang: Lang): Fu[JsObject] =
u.match
Expand All @@ -69,6 +76,7 @@ final class UserApi(
gameCache.nbImportedBy(u.id),
(withTrophies && !u.lame).soFu(getTrophiesAndAwards(u.user)),
streamerApi.listed(u.user),
withCanChallenge.so(challengeGranter.mayChallenge(u.user).dmap(some)),
forWiki.soFu(userRepo.email(u.id))
).mapN:
(
Expand All @@ -83,6 +91,7 @@ final class UserApi(
nbImported,
trophiesAndAwards,
streamer,
canChallenge,
email
) =>
jsonView.full(u.user, u.perfs.some, withProfile = true) ++ {
Expand Down Expand Up @@ -112,6 +121,7 @@ final class UserApi(
.add("nbFollowing", following)
.add("nbFollowers", withFollows.option(0))
.add("trophies", trophiesAndAwards.map(trophiesJson))
.add("canChallenge", canChallenge)
.add(
"streamer",
streamer.map: s =>
Expand Down
64 changes: 34 additions & 30 deletions modules/challenge/src/main/ChallengeGranter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,38 +42,42 @@ final class ChallengeGranter(

val ratingThreshold = 300

def isDenied(dest: User, perfKey: PerfKey)(using
def mayChallenge(dest: User)(using Executor)(using me: Option[Me]): Fu[Boolean] =
isDenied(dest, None).map(_.isEmpty)

// perfkey is None when we're not yet trying to challenge
def isDenied(dest: User, perfKey: Option[PerfKey])(using
Executor
)(using me: Option[Me]): Fu[Option[ChallengeDenied]] = me
.fold[Fu[Option[ChallengeDenied.Reason]]] {
prefApi.getChallenge(dest.id).map {
case lila.core.pref.Challenge.ALWAYS => none
case _ => YouAreAnon.some
}
} { from =>
type Res = Option[ChallengeDenied.Reason]
given Conversion[Res, Fu[Res]] = fuccess
relationApi.fetchRelation(dest.id, from.userId).zip(prefApi.getChallenge(dest.id)).flatMap {
case (Some(Block), _) => YouAreBlocked.some
case (_, lila.core.pref.Challenge.NEVER) => TheyDontAcceptChallenges.some
case (Some(Follow), _) => none // always accept from followed
case (_, _) if from.marks.engine && !dest.marks.engine => YouAreBlocked.some
case (_, lila.core.pref.Challenge.FRIEND) => FriendsOnly.some
case (_, lila.core.pref.Challenge.RATING) =>
userApi
.perfsOf(from.value -> dest, primary = false)
.map: (fromPerfs, destPerfs) =>
if fromPerfs(perfKey).provisional || destPerfs(perfKey).provisional
then RatingIsProvisional(perfKey).some
else
val diff =
math.abs(fromPerfs(perfKey).intRating.value - destPerfs(perfKey).intRating.value)
(diff > ratingThreshold).option(RatingOutsideRange(perfKey))
case (_, lila.core.pref.Challenge.REGISTERED) => none
case _ if from == dest => SelfChallenge.some
case _ => none
}
}
.match
case None =>
prefApi.getChallenge(dest.id).map {
case lila.core.pref.Challenge.ALWAYS => none
case _ => YouAreAnon.some
}
case Some(from) =>
type Res = Option[ChallengeDenied.Reason]
given Conversion[Res, Fu[Res]] = fuccess
relationApi.fetchRelation(dest.id, from.userId).zip(prefApi.getChallenge(dest.id)).flatMap {
case (Some(Block), _) => YouAreBlocked.some
case (_, lila.core.pref.Challenge.NEVER) => TheyDontAcceptChallenges.some
case (Some(Follow), _) => none // always accept from followed
case (_, _) if from.marks.engine && !dest.marks.engine => YouAreBlocked.some
case (_, lila.core.pref.Challenge.FRIEND) => FriendsOnly.some
case (_, lila.core.pref.Challenge.RATING) =>
perfKey.so: pk =>
userApi
.perfsOf(from.value -> dest, primary = false)
.map: (fromPerfs, destPerfs) =>
if fromPerfs(pk).provisional || destPerfs(pk).provisional
then RatingIsProvisional(pk).some
else
val diff = math.abs(fromPerfs(pk).intRating.value - destPerfs(pk).intRating.value)
(diff > ratingThreshold).option(RatingOutsideRange(pk))
case (_, lila.core.pref.Challenge.REGISTERED) => none
case _ if from == dest => SelfChallenge.some
case _ => none
}
.map:
case None if dest.isBot && perfKey == PerfKey.ultraBullet => BotUltraBullet.some
case res => res
Expand Down
9 changes: 9 additions & 0 deletions modules/coreI18n/src/main/key.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,15 @@ object I18nKey:
val `replacePlayerTags`: I18nKey = "broadcast:replacePlayerTags"
val `periodInSeconds`: I18nKey = "broadcast:periodInSeconds"
val `periodInSecondsHelp`: I18nKey = "broadcast:periodInSecondsHelp"
val `fideFederations`: I18nKey = "broadcast:fideFederations"
val `top10Rating`: I18nKey = "broadcast:top10Rating"
val `fidePlayers`: I18nKey = "broadcast:fidePlayers"
val `fidePlayerNotFound`: I18nKey = "broadcast:fidePlayerNotFound"
val `fideProfile`: I18nKey = "broadcast:fideProfile"
val `federation`: I18nKey = "broadcast:federation"
val `ageThisYear`: I18nKey = "broadcast:ageThisYear"
val `unrated`: I18nKey = "broadcast:unrated"
val `recentTournaments`: I18nKey = "broadcast:recentTournaments"
val `nbBroadcasts`: I18nKey = "broadcast:nbBroadcasts"

object streamer:
Expand Down
42 changes: 21 additions & 21 deletions modules/fide/src/main/ui/FideUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
td(if stats.top10Rating > 0 then stats.top10Rating else "-")
page("FIDE federations", "federations")(
cls := "fide-federations",
boxTop(h1("FIDE federations")),
boxTop(h1(trans.broadcast.fideFederations())),
table(cls := "slist slist-pad")(
thead:
tr(
th("Name"),
th("Players"),
th("Classic"),
th("Rapid"),
th("Blitz")
th(trans.site.name()),
th(trans.site.players()),
th(trans.site.classical()),
th(trans.site.rapid()),
th(trans.site.blitz())
)
,
tbody(cls := "infinite-scroll")(
Expand Down Expand Up @@ -72,9 +72,9 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
card(
name(),
frag(
p("Rank", strong(stats.get.rank)),
p("Top 10 rating", strong(stats.get.top10Rating)),
p("Players", strong(stats.get.nbPlayers.localize))
p(trans.site.rank(), strong(stats.get.rank)),
p(trans.broadcast.top10Rating(), strong(stats.get.top10Rating)),
p(trans.site.players(), strong(stats.get.nbPlayers.localize))
)
)
),
Expand Down Expand Up @@ -104,7 +104,7 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
page("FIDE players", "players")(
cls := "fide-players",
boxTop(
h1("FIDE players"),
h1(trans.broadcast.fidePlayers()),
div(cls := "box__top__actions"):
searchForm(query)
),
Expand All @@ -115,7 +115,7 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
page("FIDE player not found", "players")(
cls := "fide-players",
boxTop(
h1("FIDE player not found"),
h1(trans.broadcast.fidePlayerNotFound()),
div(cls := "box__top__actions"):
searchForm("")
),
Expand Down Expand Up @@ -158,12 +158,12 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
table(cls := "slist slist-pad")(
thead:
tr(
th(title),
th(trans.site.name()),
withFlag.option(th(iconTag(Icon.FlagOutline))),
th("Classic"),
th("Rapid"),
th("Blitz"),
th("Age this year")
th(trans.site.classical()),
th(trans.site.rapid()),
th(trans.site.blitz()),
th(trans.broadcast.ageThisYear())
)
,
tbody(cls := "infinite-scroll")(
Expand Down Expand Up @@ -194,7 +194,7 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
div(cls := "fide-cards fide-player__cards")(
player.fed.map: fed =>
card(
"Federation",
trans.broadcast.federation(),
if fed == Federation.idNone then "None"
else
a(cls := "fide-player__federation", href := routes.Fide.federation(Federation.idToSlug(fed)))(
Expand All @@ -203,16 +203,16 @@ final class FideUi(helpers: Helpers)(menu: String => Context ?=> Frag):
)
),
card(
"FIDE profile",
trans.broadcast.fideProfile(),
a(href := s"https://ratings.fide.com/profile/${player.id}")(player.id)
),
card(
"Age this year",
trans.broadcast.ageThisYear(),
player.age
),
tcTrans.map: (tc, name) =>
card(name(), player.ratingOf(tc).fold("Unrated")(_.toString)),
card(name(), player.ratingOf(tc).fold(trans.broadcast.unrated())(_.toString)),
),
tours.map: tours =>
div(cls := "fide-player__tours")(h2("Recent tournaments"), tours)
div(cls := "fide-player__tours")(h2(trans.broadcast.recentTournaments()), tours)
)
Loading

0 comments on commit 5536d41

Please sign in to comment.