From 880cf89f0ce85451a465f18cf68610909bf7e3a8 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Thu, 26 Jan 2017 15:28:16 +0100 Subject: [PATCH] make controllers more async and readable --- app/controllers/Message.scala | 140 +++++++++++++++++----------------- app/controllers/Study.scala | 53 +++++++------ app/controllers/User.scala | 37 +++++---- 3 files changed, 112 insertions(+), 118 deletions(-) diff --git a/app/controllers/Message.scala b/app/controllers/Message.scala index dc1692de7e..20bbf7de92 100644 --- a/app/controllers/Message.scala +++ b/app/controllers/Message.scala @@ -1,8 +1,8 @@ package controllers import play.api.data.Form -import play.twirl.api.Html import play.api.libs.json._ +import play.twirl.api.Html import lila.api.Context import lila.app._ @@ -17,78 +17,76 @@ object Message extends LilaController { private def forms = Env.message.forms private def relationApi = Env.relation.api - def inbox(page: Int) = Auth { implicit ctx => - me => - NotForKids { - negotiate ( - html = api.inbox(me, page) map { html.message.inbox(me, _) }, - api = _ => api.inbox(me, page) map { Env.message.jsonView.inbox(me, _) } - ) - } + def inbox(page: Int) = Auth { implicit ctx => me => + NotForKids { + for { + pag <- api.inbox(me, page) + _ <- Env.user.lightUserApi preloadMany pag.currentPageResults.flatMap(_.userIds) + res <- negotiate( + html = fuccess(html.message.inbox(me, pag)), + api = _ => fuccess(Env.message.jsonView.inbox(me, pag))) + } yield res + } } - def thread(id: String) = Auth { implicit ctx => - implicit me => - NotForKids { - negotiate ( - html = OptionFuOk(api.thread(id, me)) { thread => - relationApi.fetchBlocks(thread otherUserId me, me.id) map { blocked => - html.message.thread(thread, forms.post, blocked) - } - } map NoCache, - api = _ => JsonOptionFuOk(api.thread(id, me)) { thread => Env.message.jsonView.thread(thread) } - ) - } - } - - def answer(id: String) = AuthBody { implicit ctx => - implicit me => - negotiate ( - html = OptionFuResult(api.thread(id, me)) { thread => - implicit val req = ctx.body - forms.post.bindFromRequest.fold( - err => relationApi.fetchBlocks(thread otherUserId me, me.id) map { blocked => - BadRequest(html.message.thread(thread, err, blocked)) - }, - text => api.makePost(thread, text, me) inject Redirect(routes.Message.thread(thread.id) + "#bottom") - ) - }, - api = _ => OptionFuResult(api.thread(id, me)) { thread => - implicit val req = ctx.body - forms.post.bindFromRequest.fold( - err => fuccess(BadRequest(Json.obj("err" -> "Malformed request"))), - text => api.makePost(thread, text, me) inject Ok(Json.obj("ok" -> true, "id" -> thread.id)) - ) + def thread(id: String) = Auth { implicit ctx => implicit me => + NotForKids { + negotiate( + html = OptionFuOk(api.thread(id, me)) { thread => + relationApi.fetchBlocks(thread otherUserId me, me.id) map { blocked => + html.message.thread(thread, forms.post, blocked) } + } map NoCache, + api = _ => JsonOptionFuOk(api.thread(id, me)) { thread => Env.message.jsonView.thread(thread) } ) + } } - def form = Auth { implicit ctx => - implicit me => - NotForKids { - renderForm(me, get("title"), identity) map { Ok(_) } + def answer(id: String) = AuthBody { implicit ctx => implicit me => + negotiate( + html = OptionFuResult(api.thread(id, me)) { thread => + implicit val req = ctx.body + forms.post.bindFromRequest.fold( + err => relationApi.fetchBlocks(thread otherUserId me, me.id) map { blocked => + BadRequest(html.message.thread(thread, err, blocked)) + }, + text => api.makePost(thread, text, me) inject Redirect(routes.Message.thread(thread.id) + "#bottom") + ) + }, + api = _ => OptionFuResult(api.thread(id, me)) { thread => + implicit val req = ctx.body + forms.post.bindFromRequest.fold( + err => fuccess(BadRequest(Json.obj("err" -> "Malformed request"))), + text => api.makePost(thread, text, me) inject Ok(Json.obj("ok" -> true, "id" -> thread.id)) + ) } + ) } - def create = AuthBody { implicit ctx => - implicit me => - NotForKids { + def form = Auth { implicit ctx => implicit me => + NotForKids { + renderForm(me, get("title"), identity) map { Ok(_) } + } + } + + def create = AuthBody { implicit ctx => implicit me => + NotForKids { import play.api.Play.current import play.api.i18n.Messages.Implicits._ - implicit val req = ctx.body - negotiate ( - html = forms.thread(me).bindFromRequest.fold( - err => renderForm(me, none, _ => err) map { BadRequest(_) }, - data => api.makeThread(data, me) map { thread => - Redirect(routes.Message.thread(thread.id)) - }), - api = _ => forms.thread(me).bindFromRequest.fold( - err => fuccess(BadRequest(errorsAsJson(err))), - data => api.makeThread(data, me) map { thread => - Ok(Json.obj("ok" -> true, "id" -> thread.id)) - }) - ) - } + implicit val req = ctx.body + negotiate( + html = forms.thread(me).bindFromRequest.fold( + err => renderForm(me, none, _ => err) map { BadRequest(_) }, + data => api.makeThread(data, me) map { thread => + Redirect(routes.Message.thread(thread.id)) + }), + api = _ => forms.thread(me).bindFromRequest.fold( + err => fuccess(BadRequest(errorsAsJson(err))), + data => api.makeThread(data, me) map { thread => + Ok(Json.obj("ok" -> true, "id" -> thread.id)) + }) + ) + } } private def renderForm(me: UserModel, title: Option[String], f: Form[_] => Form[_])(implicit ctx: Context): Fu[Html] = @@ -99,17 +97,15 @@ object Message extends LilaController { } } - def batch = AuthBody { implicit ctx => - implicit me => - val ids = get("ids").??(_.split(",").toList).distinct take 200 - Env.message.batch(me, ~get("action"), ids) inject Redirect(routes.Message.inbox(1)) + def batch = AuthBody { implicit ctx => implicit me => + val ids = get("ids").??(_.split(",").toList).distinct take 200 + Env.message.batch(me, ~get("action"), ids) inject Redirect(routes.Message.inbox(1)) } - def delete(id: String) = AuthBody { implicit ctx => - implicit me => - negotiate ( - html = api.deleteThread(id, me) inject Redirect(routes.Message.inbox(1)), - api = _ => api.deleteThread(id, me) inject Ok(Json.obj("ok" -> true)) - ) + def delete(id: String) = AuthBody { implicit ctx => implicit me => + negotiate( + html = api.deleteThread(id, me) inject Redirect(routes.Message.inbox(1)), + api = _ => api.deleteThread(id, me) inject Ok(Json.obj("ok" -> true)) + ) } } diff --git a/app/controllers/Study.scala b/app/controllers/Study.scala index 12c0dd4900..9fd0373a4d 100644 --- a/app/controllers/Study.scala +++ b/app/controllers/Study.scala @@ -85,33 +85,32 @@ object Study extends LilaController { private def showQuery(query: Fu[Option[WithChapter]])(implicit ctx: Context) = OptionFuResult(query) { - case WithChapter(study, chapter) => CanViewResult(study) { - env.chapterRepo.orderedMetadataByStudy(study.id) flatMap { chapters => - env.api.resetIfOld(study, chapters) flatMap { study => - if (HTTPRequest isSynchronousHttp ctx.req) env.studyRepo.incViews(study) - val pov = UserAnalysis.makePov(chapter.root.fen.value.some, chapter.setup.variant) - Env.round.jsonView.userAnalysisJson(pov, ctx.pref, chapter.setup.orientation, owner = false) zip - chatOf(study) zip - env.jsonView(study, chapters, chapter, ctx.me) zip - env.version(study.id) flatMap { - case (((baseData, chat), studyJson), sVersion) => - import lila.tree.Node.partitionTreeJsonWriter - val analysis = baseData ++ Json.obj( - "treeParts" -> partitionTreeJsonWriter.writes { - lila.study.TreeBuilder(chapter.root, chapter.setup.variant) - }) - val data = lila.study.JsonView.JsData( - study = studyJson, - analysis = analysis) - negotiate( - html = Ok(html.study.show(study, data, chat, sVersion)).fuccess, - api = _ => Ok(Json.obj( - "study" -> data.study, - "analysis" -> data.analysis)).fuccess - ) - } - } - } + case WithChapter(s, chapter) => CanViewResult(s) { + import lila.tree.Node.partitionTreeJsonWriter + for { + chapters <- env.chapterRepo.orderedMetadataByStudy(s.id) + study <- env.api.resetIfOld(s, chapters) + _ <- Env.user.lightUserApi preloadMany study.members.ids.toList + _ = if (HTTPRequest isSynchronousHttp ctx.req) env.studyRepo.incViews(study) + pov = UserAnalysis.makePov(chapter.root.fen.value.some, chapter.setup.variant) + baseData <- Env.round.jsonView.userAnalysisJson(pov, ctx.pref, chapter.setup.orientation, owner = false) + studyJson <- env.jsonView(study, chapters, chapter, ctx.me) + data = lila.study.JsonView.JsData( + study = studyJson, + analysis = baseData ++ Json.obj( + "treeParts" -> partitionTreeJsonWriter.writes { + lila.study.TreeBuilder(chapter.root, chapter.setup.variant) + })) + res <- negotiate( + html = for { + chat <- chatOf(study) + sVersion <- env.version(study.id) + } yield Ok(html.study.show(study, data, chat, sVersion)), + api = _ => Ok(Json.obj( + "study" -> data.study, + "analysis" -> data.analysis)).fuccess + ) + } yield res } } map NoCache diff --git a/app/controllers/User.scala b/app/controllers/User.scala index 1c0686d202..6a776fdef7 100644 --- a/app/controllers/User.scala +++ b/app/controllers/User.scala @@ -37,25 +37,24 @@ object User extends LilaController { def showMini(username: String) = Open { implicit ctx => OptionFuResult(UserRepo named username) { user => - if (user.enabled) GameRepo lastPlayedPlaying user zip - (ctx.userId ?? { relationApi.fetchBlocks(user.id, _) }) zip - (ctx.userId ?? { Env.game.crosstableApi(user.id, _) }) zip - (ctx.isAuth ?? { Env.pref.api.followable(user.id) }) zip - (ctx.userId ?? { relationApi.fetchRelation(_, user.id) }) flatMap { - case ((((pov, blocked), crosstable), followable), relation) => - negotiate( - html = fuccess { - Ok(html.user.mini(user, pov, blocked, followable, relation, crosstable)) - .withHeaders(CACHE_CONTROL -> "max-age=5") - }, - api = _ => { - import lila.game.JsonView.crosstableWrites - fuccess(Ok(Json.obj( - "crosstable" -> crosstable, - "perfs" -> lila.user.JsonView.perfs(user, user.best8Perfs) - ))) - }) - } + if (user.enabled) for { + blocked <- ctx.userId ?? { relationApi.fetchBlocks(user.id, _) } + crosstable <- ctx.userId ?? { Env.game.crosstableApi(user.id, _) } + followable <- ctx.isAuth ?? { Env.pref.api.followable(user.id) } + relation <- ctx.userId ?? { relationApi.fetchRelation(_, user.id) } + res <- negotiate( + html = GameRepo lastPlayedPlaying user map { pov => + Ok(html.user.mini(user, pov, blocked, followable, relation, crosstable)) + .withHeaders(CACHE_CONTROL -> "max-age=5") + }, + api = _ => { + import lila.game.JsonView.crosstableWrites + fuccess(Ok(Json.obj( + "crosstable" -> crosstable, + "perfs" -> lila.user.JsonView.perfs(user, user.best8Perfs) + ))) + }) + } yield res else fuccess(Ok(html.user.miniClosed(user))) } }