Skip to content

Commit

Permalink
improve content negotiation and not found pages
Browse files Browse the repository at this point in the history
while refactoring lila controllers some more
  • Loading branch information
ornicar committed Jun 23, 2023
1 parent 5e80317 commit b3ae8fd
Show file tree
Hide file tree
Showing 42 changed files with 292 additions and 358 deletions.
13 changes: 6 additions & 7 deletions app/controllers/Account.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ final class Account(
}

def apiEmail = Scoped(_.Email.Read) { _ ?=> me ?=>
env.user.repo email me mapz { email =>
env.user.repo email me orNotFound { email =>
JsonOk(Json.obj("email" -> email.value))
}
}
Expand All @@ -175,16 +175,15 @@ final class Account(
}

def emailConfirm(token: String) = Open:
env.security.emailChange.confirm(token) flatMapz { (user, prevEmail) =>
env.security.emailChange.confirm(token) orNotFound { (user, prevEmail) =>
(prevEmail.exists(_.isNoReply) so env.clas.api.student.release(user)) >>
auth.authenticateUser(
user,
remember = true,
result =
if (prevEmail.exists(_.isNoReply))
Some(_ => Redirect(routes.User.show(user.username)).flashSuccess)
else
Some(_ => Redirect(routes.Account.email).flashSuccess)
if prevEmail.exists(_.isNoReply)
then Some(_ => Redirect(routes.User.show(user.username)).flashSuccess)
else Some(_ => Redirect(routes.Account.email).flashSuccess)
)
}

Expand Down Expand Up @@ -367,7 +366,7 @@ final class Account(
val userId: UserId = getUserStr("user")
.map(_.id)
.filter(id => me.is(id) || isGranted(_.Impersonate)) | me.userId
env.user.repo byId userId flatMapz { user =>
env.user.repo byId userId orNotFound { user =>
if getBool("text") then
apiC.GlobalConcurrencyLimitUser(me)(env.api.personalDataExport(user)): source =>
Ok.chunked(source.map(_ + "\n"))
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/Analyse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class Analyse(
) extends LilaController(env):

def requestAnalysis(id: GameId) = Auth { ctx ?=> me ?=>
OptionFuResult(env.game.gameRepo game id): game =>
IfFound(env.game.gameRepo game id): game =>
env.fishnet
.analyser(
game,
Expand Down
20 changes: 10 additions & 10 deletions app/controllers/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ final class Api(

def tournamentGames(id: TourId) =
AnonOrScoped(): ctx ?=>
env.tournament.tournamentRepo byId id flatMapz { tour =>
env.tournament.tournamentRepo byId id orNotFound { tour =>
val onlyUserId = getUserStr("player").map(_.id)
val config = GameApiV2.ByTournamentConfig(
tour = tour,
Expand All @@ -199,7 +199,7 @@ final class Api(

def tournamentResults(id: TourId) = Anon:
val csv = HTTPRequest.acceptsCsv(req) || get("as").has("csv")
env.tournament.tournamentRepo byId id mapz { tour =>
env.tournament.tournamentRepo byId id orNotFound { tour =>
import lila.tournament.JsonView.playerResultWrites
val withSheet = getBool("sheet")
val perSecond = MaxPerSecond:
Expand All @@ -214,13 +214,13 @@ final class Api(
withSheet = withSheet
)
val result =
if (csv) csvDownload(lila.tournament.TournamentCsv(source))
if csv then csvDownload(lila.tournament.TournamentCsv(source))
else jsonDownload(source.map(lila.tournament.JsonView.playerResultWrites.writes))
result.pipe(asAttachment(env.api.gameApiV2.filename(tour, if (csv) "csv" else "ndjson")))
}

def tournamentTeams(id: TourId) = Anon:
env.tournament.tournamentRepo byId id flatMapz { tour =>
env.tournament.tournamentRepo byId id orNotFound { tour =>
env.tournament.jsonView.apiTeamStanding(tour) map { arr =>
JsonOk:
Json.obj(
Expand All @@ -231,7 +231,7 @@ final class Api(
}

def tournamentsByOwner(name: UserStr, status: List[Int]) = Anon:
(name.id != lila.user.User.lichessId) so env.user.repo.byId(name) flatMapz { user =>
(name.id != lila.user.User.lichessId) so env.user.repo.byId(name) orNotFound { user =>
val nb = getInt("nb") | Int.MaxValue
jsonDownload:
env.tournament.api
Expand All @@ -240,7 +240,7 @@ final class Api(
}

def swissGames(id: SwissId) = AnonOrScoped(): ctx ?=>
env.swiss.cache.swissCache byId id flatMapz { swiss =>
env.swiss.cache.swissCache byId id orNotFound { swiss =>
val config = GameApiV2.BySwissConfig(
swissId = swiss.id,
format = GameApiV2.Format byRequest req,
Expand All @@ -261,20 +261,20 @@ final class Api(

def swissResults(id: SwissId) = Anon:
val csv = HTTPRequest.acceptsCsv(req) || get("as").has("csv")
env.swiss.cache.swissCache byId id mapz { swiss =>
env.swiss.cache.swissCache byId id orNotFound { swiss =>
val source = env.swiss.api
.resultStream(swiss, MaxPerSecond(50), getInt("nb") | Int.MaxValue)
.mapAsync(8) { p =>
.mapAsync(8): p =>
env.user.lightUserApi.asyncFallback(p.player.userId) map p.withUser
}
val result =
if csv then csvDownload(lila.swiss.SwissCsv(source))
else jsonDownload(source.map(env.swiss.json.playerResult))
result.pipe(asAttachment(env.api.gameApiV2.filename(swiss, if csv then "csv" else "ndjson")))
}

def gamesByUsersStream = AnonOrScopedBody(parse.tolerantText)(): ctx ?=>
val max = ctx.me.fold(300) { u => if u is lila.user.User.lichess4545Id then 900 else 500 }
val max = ctx.me.fold(300): u =>
if u is lila.user.User.lichess4545Id then 900 else 500
withIdsFromReqBody[UserId](ctx.body, max, id => UserStr.read(id).map(_.id)): ids =>
GlobalConcurrencyLimitPerIP.events(ctx.ip)(
addKeepAlive:
Expand Down
8 changes: 3 additions & 5 deletions app/controllers/Blog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,15 @@ final class Blog(
env.forum.topicRepo.existsByTree(categId, topicSlug) flatMap {
if _ then redirect
else
blogApi.one(prismic.api, none, id) flatMapz { doc =>
env.forum.categRepo.byId(categId) flatMapz { categ =>
IfFound(blogApi.one(prismic.api, none, id)): doc =>
IfFound(env.forum.categRepo.byId(categId)): categ =>
env.forum.topicApi.makeBlogDiscuss(
categ = categ,
slug = topicSlug,
name = doc.getText("blog.title") | "New blog post",
url = s"${env.net.baseUrl}${routes.Blog.show(doc.id, doc.slug)}"
)
} inject redirect
}
}
} inject redirect
}

private def WithPrismic(f: Context ?=> BlogApi.Context ?=> Fu[Result]) = Open:
Expand Down
16 changes: 8 additions & 8 deletions app/controllers/Challenge.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ final class Challenge(
showId(id)

protected[controllers] def showId(id: ChallengeId)(using Context): Fu[Result] =
OptionFuResult(api byId id)(showChallenge(_))
IfFound(api byId id)(showChallenge(_))

protected[controllers] def showChallenge(
c: ChallengeModel,
Expand Down Expand Up @@ -84,7 +84,7 @@ final class Challenge(
!challenge.challengerUserId.so(orig => me.exists(_ is orig))

def accept(id: ChallengeId, color: Option[String]) = Open:
OptionFuResult(api byId id): c =>
IfFound(api byId id): c =>
val cc = color flatMap chess.Color.fromName
isForMe(c) so api
.accept(c, ctx.req.sid, cc)
Expand Down Expand Up @@ -142,7 +142,7 @@ final class Challenge(
}

def decline(id: ChallengeId) = AuthBody { ctx ?=> _ ?=>
OptionFuResult(api byId id): c =>
IfFound(api byId id): c =>
isForMe(c) so
api.decline(
c,
Expand Down Expand Up @@ -170,7 +170,7 @@ final class Challenge(

def cancel(id: ChallengeId) =
Open:
OptionFuResult(api byId id): c =>
IfFound(api byId id): c =>
if isMine(c) then api cancel c else notFound

def apiCancel(id: ChallengeId) = Scoped(_.Challenge.Write, _.Bot.Play, _.Board.Play) { ctx ?=> me ?=>
Expand Down Expand Up @@ -227,7 +227,7 @@ final class Challenge(
env.game.gameRepo game id flatMapz { g =>
env.round.proxyRepo.upgradeIfPresent(g) dmap some dmap
(_.filter(_.hasUserIds(u1.id, u2.id)))
} mapz { game =>
} orNotFound { game =>
env.round.tellRound(game.id, lila.round.actorApi.round.StartClock)
jsonOkResult
}
Expand All @@ -254,7 +254,7 @@ final class Challenge(
def toFriend(id: ChallengeId) = AuthBody { ctx ?=> _ ?=>
import play.api.data.*
import play.api.data.Forms.*
OptionFuResult(api byId id): c =>
IfFound(api byId id): c =>
if isMine(c) then
Form(single("username" -> lila.user.UserForm.historicalUsernameField))
.bindFromRequest()
Expand Down Expand Up @@ -382,8 +382,8 @@ final class Challenge(

def offerRematchForGame(gameId: GameId) = Auth { _ ?=> me ?=>
NoBot:
OptionFuResult(env.game.gameRepo game gameId): g =>
Pov.opponentOf(g, me).flatMap(_.userId) so env.user.repo.byId flatMapz { opponent =>
IfFound(env.game.gameRepo game gameId): g =>
Pov.opponentOf(g, me).flatMap(_.userId) so env.user.repo.byId orNotFound { opponent =>
env.challenge.granter.isDenied(me.some, opponent, g.perfType) flatMap {
case Some(d) => BadRequest(jsonError(lila.challenge.ChallengeDenied translated d))
case _ =>
Expand Down
56 changes: 22 additions & 34 deletions app/controllers/Clas.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
yield res

def teacher(username: UserStr) = Secure(_.Admin) { ctx ?=> _ ?=>
env.user.repo byId username flatMapz { teacher =>
Ok.pageAsync:
env.clas.api.clas.of(teacher) map {
html.mod.search.teacher(teacher.id, _)
}
}
OptionFuPage(env.user.repo byId username): teacher =>
env.clas.api.clas.of(teacher) map {
html.mod.search.teacher(teacher.id, _)
}
}

private def renderHome(using Context) =
Expand Down Expand Up @@ -88,16 +86,13 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
}
,
orDefault = _ =>
if isGranted(_.UserModView) then
env.clas.api.clas.byId(id) flatMapz { clas =>
isGranted(_.UserModView) so
OptionFuPage(env.clas.api.clas.byId(id)): clas =>
env.clas.api.student.allWithUsers(clas) flatMap { students =>
Ok.pageAsync:
env.user.repo.withEmails(students.map(_.user)) map {
html.mod.search.clas(clas, _)
}
env.user.repo.withEmails(students.map(_.user)) map {
html.mod.search.clas(clas, _)
}
}
}
else notFound
)
}

Expand All @@ -109,12 +104,11 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
isGranted(_.Teacher).so(env.clas.api.clas.isTeacherOf(me, id)) flatMap {
if _ then forTeacher
else
env.clas.api.clas.byId(id) flatMapz { clas =>
IfFound(env.clas.api.clas.byId(id)): clas =>
env.clas.api.student.activeWithUsers(clas) flatMap { students =>
if (students.exists(_.student is me)) forStudent(clas, students)
else orDefault(ctx)
}
}
}

def wall(id: ClasId) = Secure(_.Teacher) { ctx ?=> me ?=>
Expand Down Expand Up @@ -260,7 +254,7 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
}

def studentForm(id: ClasId) = Secure(_.Teacher) { ctx ?=> me ?=>
if getBool("gen") then env.clas.nameGenerator() mapz { Ok(_) }
if getBool("gen") then env.clas.nameGenerator() orNotFound { Ok(_) }
else
WithClassAndStudents(id): (clas, students) =>
for
Expand Down Expand Up @@ -361,7 +355,7 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
}
,
data =>
env.user.repo enabledById data.username flatMapz { user =>
IfFound(env.user.repo enabledById data.username): user =>
import lila.clas.ClasInvite.{ Feedback as F }
import lila.i18n.{ I18nKeys as trans }
env.clas.api.invite.create(clas, user, data.realName) map { feedback =>
Expand All @@ -375,7 +369,6 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
case F.CantMsgKid(url) =>
"warning" -> trans.clas.xIsAKidAccountWarning.txt(user.username, url)
}
}
)
}

Expand Down Expand Up @@ -475,7 +468,7 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
}

def becomeTeacher = AuthBody { ctx ?=> me ?=>
couldBeTeacher.flatMapz:
couldBeTeacher.elseNotFound:
val perm = lila.security.Permission.Teacher.dbKey
(!me.roles.has(perm) so env.user.repo.setRoles(me, perm :: me.roles).void) inject
Redirect(routes.Clas.index)
Expand All @@ -499,20 +492,16 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
_ => Redirect(routes.Clas.invitation(id)).toFuccess,
v =>
if v then
env.clas.api.invite.accept(id, me) mapz { student =>
IfFound(env.clas.api.invite.accept(id, me)): student =>
redirectTo(student.clasId)
}
else
env.clas.api.invite.decline(id) inject
Redirect(routes.Clas.invitation(id))
else env.clas.api.invite.decline(id) inject Redirect(routes.Clas.invitation(id))
)
}

def invitationRevoke(id: lila.clas.ClasInvite.Id) = Secure(_.Teacher) { _ ?=> me ?=>
env.clas.api.invite.get(id) flatMapz { invite =>
IfFound(env.clas.api.invite.get(id)): invite =>
WithClass(invite.clasId): clas =>
env.clas.api.invite.delete(invite._id) inject Redirect(routes.Clas.students(clas.id.value))
}
}

private def Reasonable(clas: lila.clas.Clas, students: List[lila.clas.Student.WithUser], active: String)(
Expand All @@ -521,21 +510,20 @@ final class Clas(env: Env, authC: Auth) extends LilaController(env):
if students.sizeIs <= lila.clas.Clas.maxStudents then f
else Unauthorized.page(views.html.clas.teacherDashboard.unreasonable(clas, students, active))

private def WithClass(clasId: ClasId)(f: lila.clas.Clas => Fu[Result])(using me: Me): Fu[Result] =
env.clas.api.clas.getAndView(clasId, me.user) flatMapz f
private def WithClass(clasId: ClasId)(f: lila.clas.Clas => Fu[Result])(using Context, Me): Fu[Result] =
IfFound(env.clas.api.clas.getAndView(clasId))(f)

private def WithClassAndStudents(clasId: ClasId)(
f: (lila.clas.Clas, List[lila.clas.Student]) => Fu[Result]
)(using Me): Fu[Result] =
)(using Context, Me): Fu[Result] =
WithClass(clasId): c =>
env.clas.api.student.activeOf(c) flatMap { f(c, _) }

private def WithStudent(clas: lila.clas.Clas, username: UserStr)(
f: lila.clas.Student.WithUser => Fu[Result]
): Fu[Result] =
env.user.repo byId username flatMapz { user =>
env.clas.api.student.get(clas, user) flatMapz f
}
)(using Context): Fu[Result] =
IfFound(env.user.repo byId username): user =>
IfFound(env.clas.api.student.get(clas, user))(f)

private def SafeTeacher(f: => Fu[Result])(using Context): Fu[Result] =
if ctx.me.exists(!_.lameOrTroll) then f
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/Coach.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class Coach(env: Env) extends LilaController(env):
yield Ok(page)

def show(username: UserStr) = Open:
OptionFuResult(api find username): c =>
IfFound(api find username): c =>
WithVisibleCoach(c):
for
stu <- env.study.api.publicByIds(c.coach.profile.studyIds)
Expand All @@ -53,7 +53,7 @@ final class Coach(env: Env) extends LilaController(env):
}

def editApply = SecureBody(_.Coach) { ctx ?=> me ?=>
OptionFuResult(api.findOrInit): c =>
IfFound(api.findOrInit): c =>
CoachProfileForm
.edit(c.coach)
.bindFromRequest()
Expand All @@ -68,7 +68,7 @@ final class Coach(env: Env) extends LilaController(env):
}

def pictureApply = SecureBody(parse.multipartFormData)(_.Coach) { ctx ?=> me ?=>
OptionFuResult(api.findOrInit): c =>
IfFound(api.findOrInit): c =>
ctx.body.body.file("picture") match
case Some(pic) =>
api.uploadPicture(c, pic) inject Redirect(routes.Coach.edit) recoverWith {
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/Event.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class Event(env: Env) extends LilaController(env):
}

def update(id: String) = SecureBody(_.ManageEvent) { ctx ?=> me ?=>
OptionFuResult(api one id): event =>
IfFound(api one id): event =>
api
.editForm(event)
.bindFromRequest()
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/ForumCateg.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class ForumCateg(env: Env) extends LilaController(env) with ForumControlle
else
NotForKids:
Reasonable(page, config.Max(50), notFound):
OptionFuResult(categApi.show(slug, page)): (categ, topics) =>
IfFound(categApi.show(slug, page)): (categ, topics) =>
for
canRead <- access.isGrantedRead(categ.id)
canWrite <- access.isGrantedWrite(categ.id)
Expand Down
Loading

0 comments on commit b3ae8fd

Please sign in to comment.