From cd7e29d865fe569304784c88acb8afcd6b368475 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Sat, 31 May 2014 21:03:04 +0200 Subject: [PATCH] create blog module --- app/Env.scala | 6 +- app/controllers/Blog.scala | 22 +++-- app/controllers/Prismic.scala | 125 ---------------------------- app/views/blog/index.scala.html | 2 +- app/views/blog/meta.scala.html | 2 +- app/views/blog/show.scala.html | 4 +- modules/blog/src/main/BlogApi.scala | 40 +++++++++ modules/blog/src/main/Env.scala | 22 +++++ modules/blog/src/main/package.scala | 3 + project/Build.scala | 6 +- 10 files changed, 93 insertions(+), 139 deletions(-) delete mode 100644 app/controllers/Prismic.scala create mode 100644 modules/blog/src/main/BlogApi.scala create mode 100644 modules/blog/src/main/Env.scala create mode 100644 modules/blog/src/main/package.scala diff --git a/app/Env.scala b/app/Env.scala index a9cd22f5ca..b1fffca8f6 100644 --- a/app/Env.scala +++ b/app/Env.scala @@ -48,7 +48,7 @@ final class Env( if (!Env.ai.ServerOnly) { loginfo("[boot] Preloading modules") - (Env.socket, + List(Env.socket, Env.site, Env.tournament, Env.lobby, @@ -69,7 +69,8 @@ final class Env( Env.evaluation, Env.chat, Env.puzzle, - Env.tv) + Env.tv, + Env.blog) loginfo("[boot] Preloading complete") } @@ -124,4 +125,5 @@ object Env { def puzzle = lila.puzzle.Env.current def coordinate = lila.coordinate.Env.current def tv = lila.tv.Env.current + def blog = lila.blog.Env.current } diff --git a/app/controllers/Blog.scala b/app/controllers/Blog.scala index 6230aafe59..2d49f04b6c 100644 --- a/app/controllers/Blog.scala +++ b/app/controllers/Blog.scala @@ -2,32 +2,40 @@ package controllers import play.api.mvc._, Results._ -import io.prismic.Document +import io.prismic.{ Document, DocumentLinkResolver, Fragment } import lila.app._ import views._ object Blog extends LilaController { + private def blogApi = Env.blog.api + def index(ref: Option[String]) = Open { implicit ctx => - Prismic.WithPrismic(ref) { implicit prismic => - prismic.api.forms("blog").ref(prismic.ref).pageSize(20).page(1).submit() map { response => + blogApi context ref flatMap { implicit prismic => + blogApi recent 20 map { response => Ok(views.html.blog.index(response)) } - }(ctx.req) + } } def show(id: String, slug: String, ref: Option[String]) = Open { implicit ctx => - Prismic.WithPrismic(ref) { implicit prismic => - Prismic getDocument id flatMap { maybeDocument => + blogApi context ref flatMap { implicit prismic => + blogApi one id flatMap { maybeDocument => checkSlug(maybeDocument, slug) { case Left(newSlug) => MovedPermanently(routes.Blog.show(id, newSlug, ref).url) case Right(doc) => Ok(views.html.blog.show(doc)) } } - }(ctx.req) + } } + implicit def makeLinkResolver(prismicApi: io.prismic.Api, ref: Option[String]): DocumentLinkResolver = + DocumentLinkResolver(prismicApi) { + case (Fragment.DocumentLink(id, _, _, slug, false), _) => routes.Blog.show(id, slug, ref).url + case (Fragment.DocumentLink(_, _, _, _, true), _) => routes.Lobby.home.url + } + // -- Helper: Check if the slug is valid and redirect to the most recent version id needed private def checkSlug(document: Option[Document], slug: String)(callback: Either[String, Document] => SimpleResult)(implicit ctx: lila.api.Context) = document.collect { diff --git a/app/controllers/Prismic.scala b/app/controllers/Prismic.scala deleted file mode 100644 index 5a9f084654..0000000000 --- a/app/controllers/Prismic.scala +++ /dev/null @@ -1,125 +0,0 @@ -package controllers - -import play.api._ -import play.api.mvc._ - -import play.api.libs.json._ -import play.api.libs.ws._ - -import play.api.libs.concurrent.Execution.Implicits._ -import scala.concurrent._ - -import io.prismic.{ Api => PrismicApi, _ } - -object Prismic { - - private val ACCESS_TOKEN = "PRISMIC_TK" - private val Cache = BuiltInCache(200) - private val Logger = (level: Symbol, message: String) => level match { - case 'DEBUG => play.api.Logger("prismic").debug(message) - case 'ERROR => play.api.Logger("prismic").error(message) - case _ => play.api.Logger("prismic").info(message) - } - - private lazy val config = lila.common.PlayApp loadConfig "prismic" - private lazy val prismicToken = scala.util.Try(config getString "token").toOption - private lazy val apiUrl = config getString "api" - - def linkResolver(api: PrismicApi, ref: Option[String])(implicit request: RequestHeader) = DocumentLinkResolver(api) { - case (Fragment.DocumentLink(id, docType, tags, slug, false), maybeBookmarked) => - routes.Blog.show(id, slug, ref).absoluteURL() - case (link@Fragment.DocumentLink(_, _, _, _, true), _) => - routes.Lobby.home.absoluteURL() - } - - // Compute the callback URL to use for the OAuth worklow - // private def callbackUrl(implicit rh: RequestHeader) = - // routes.Prismic.callback(code = None, redirect_uri = rh.headers.get("referer")).absoluteURL() - - // -- A Prismic context that help to keep the reference to useful primisc.io contextual data - case class Context(api: PrismicApi, ref: String, accessToken: Option[String], linkResolver: DocumentLinkResolver) { - def maybeRef = Option(ref).filterNot(_ == api.master.ref) - def hasPrivilegedAccess = accessToken.isDefined - } - - // -- Build a Prismic context - def buildContext(ref: Option[String])(implicit request: RequestHeader) = - apiHome(request.session.get(ACCESS_TOKEN).orElse(prismicToken)) map { api => - Context(api, - ref.map(_.trim).filterNot(_.isEmpty).getOrElse(api.master.ref), - request.session.get(ACCESS_TOKEN), - linkResolver(api, ref.filterNot(_ == api.master.ref))(request)) - } - - def WithPrismic(ref: Option[String] = None)(block: Context => Future[SimpleResult])(implicit req: RequestHeader): Future[SimpleResult] = - buildContext(ref) flatMap block - - // -- Fetch the API entry document - def apiHome(accessToken: Option[String] = None) = - PrismicApi.get(apiUrl, accessToken = accessToken, cache = Cache, logger = Logger) - - // -- Helper: Retrieve a single document by Id - def getDocument(id: String)(implicit ctx: Prismic.Context): Future[Option[Document]] = - ctx.api.forms("everything") - .query(s"""[[:d = at(document.id, "$id")]]""") - .ref(ctx.ref).submit() map (_.results.headOption) - - // -- Helper: Retrieve several documents by Id - def getDocuments(ids: String*)(implicit ctx: Prismic.Context): Future[Seq[Document]] = - ids match { - case Nil => Future.successful(Nil) - case ids => ctx.api.forms("everything") - .query(s"""[[:d = any(document.id, ${ids.mkString("[\"", "\",\"", "\"]")})]]""") - .ref(ctx.ref).submit() map (_.results) - } - - // -- Helper: Retrieve a single document from its bookmark - def getBookmark(bookmark: String)(implicit ctx: Prismic.Context): Future[Option[Document]] = - ctx.api.bookmarks.get(bookmark).map(id => getDocument(id)).getOrElse(Future.successful(None)) - - // -- - // -- OAuth actions - // -- - - // def signin = Action.async { implicit req => - // apiHome().map(_.oauthInitiateEndpoint).recover { - // case InvalidToken(_, url) => url - // case AuthorizationNeeded(_, url) => url - // } map { url => - // Redirect(url, Map( - // "client_id" -> Seq(config("prismic.clientId")), - // "redirect_uri" -> Seq(callbackUrl), - // "scope" -> Seq("master+releases") - // )) - // } - // } - - // def signout = Action { - // Redirect(routes.Application.index(ref = None)).withNewSession - // } - - // def callback(code: Option[String], redirect_uri: Option[String]) = - // Action.async { implicit req => - // ( - // for { - // api <- apiHome() - // tokenResponse <- WS.url(api.oauthTokenEndpoint).post(Map( - // "grant_type" -> Seq("authorization_code"), - // "code" -> Seq(code.get), - // "redirect_uri" -> Seq(callbackUrl), - // "client_id" -> Seq(config("prismic.clientId")), - // "client_secret" -> Seq(config("prismic.clientSecret")) - // )).filter(_.status == 200).map(_.json) - // } yield { - // Redirect(redirect_uri.getOrElse(routes.Application.index(ref = None).url)).withSession( - // ACCESS_TOKEN -> (tokenResponse \ "access_token").as[String] - // ) - // } - // ).recover { - // case x: Throwable => - // Logger('ERROR, s"""Can't retrieve the OAuth token for code $code: ${x.getMessage}""".stripMargin) - // Unauthorized("Can't sign you in") - // } - // } - -} diff --git a/app/views/blog/index.scala.html b/app/views/blog/index.scala.html index 66e4ce1e62..75178f70fd 100644 --- a/app/views/blog/index.scala.html +++ b/app/views/blog/index.scala.html @@ -1,4 +1,4 @@ -@(pager: io.prismic.Response)(implicit ctx: Context, prismic: Prismic.Context) +@(pager: io.prismic.Response)(implicit ctx: Context, prismic: lila.blog.BlogApi.Context) @layout( title = "Blog") { diff --git a/app/views/blog/meta.scala.html b/app/views/blog/meta.scala.html index 5c3f57a0ab..c408b8c1e3 100644 --- a/app/views/blog/meta.scala.html +++ b/app/views/blog/meta.scala.html @@ -1,4 +1,4 @@ -@(doc: io.prismic.Document)(implicit ctx: Context, prismic: Prismic.Context) +@(doc: io.prismic.Document)(implicit ctx: Context, prismic: lila.blog.BlogApi.Context)
@doc.getText("blog.date").map { date => @date diff --git a/app/views/blog/show.scala.html b/app/views/blog/show.scala.html index 463e83679b..26756e52dc 100644 --- a/app/views/blog/show.scala.html +++ b/app/views/blog/show.scala.html @@ -1,4 +1,4 @@ -@(doc: io.prismic.Document)(implicit ctx: Context, prismic: Prismic.Context) +@(doc: io.prismic.Document)(implicit ctx: Context, prismic: lila.blog.BlogApi.Context) @goodies = {
@@ -30,5 +30,5 @@ goodies = goodies.some) { (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); - + } diff --git a/modules/blog/src/main/BlogApi.scala b/modules/blog/src/main/BlogApi.scala new file mode 100644 index 0000000000..9cafadcd99 --- /dev/null +++ b/modules/blog/src/main/BlogApi.scala @@ -0,0 +1,40 @@ +package lila.blog + +import io.prismic._ +import play.api.mvc.RequestHeader + +final class BlogApi(prismicUrl: String, collection: String) { + + def recent(nb: Int)(implicit ctx: BlogApi.Context) = + ctx.api.forms(collection).ref(ctx.ref).pageSize(nb).page(1).submit() + + def one(id: String)(implicit ctx: BlogApi.Context) = + ctx.api.forms(collection) + .query(s"""[[:d = at(document.id, "$id")]]""") + .ref(ctx.ref).submit() map (_.results.headOption) + + // -- Build a Prismic context + def context(ref: Option[String])(implicit linkResolver: (Api, Option[String]) => DocumentLinkResolver) = + prismicApi map { api => + BlogApi.Context( + api, + ref.map(_.trim).filterNot(_.isEmpty).getOrElse(api.master.ref), + linkResolver(api, ref)) + } + + private val cache = BuiltInCache(200) + private val logger = (level: Symbol, message: String) => level match { + case 'DEBUG => play.api.Logger("prismic") debug message + case 'ERROR => play.api.Logger("prismic") error message + case _ => play.api.Logger("prismic") info message + } + + private def prismicApi = Api.get(prismicUrl, cache = cache, logger = logger) +} + +object BlogApi { + + case class Context(api: Api, ref: String, linkResolver: DocumentLinkResolver) { + def maybeRef = Option(ref).filterNot(_ == api.master.ref) + } +} diff --git a/modules/blog/src/main/Env.scala b/modules/blog/src/main/Env.scala new file mode 100644 index 0000000000..64eb6209e9 --- /dev/null +++ b/modules/blog/src/main/Env.scala @@ -0,0 +1,22 @@ +package lila.blog + +import com.typesafe.config.Config + +import lila.common.PimpedConfig._ + +final class Env( + config: Config) { + + private val PrismicApiUrl = config getString "prismic.api_url" + private val PrismicCollection = config getString "prismic.collection" + + lazy val api = new BlogApi( + prismicUrl = PrismicApiUrl, + collection = PrismicCollection) +} + +object Env { + + lazy val current: Env = "[boot] blog" describes new Env( + config = lila.common.PlayApp loadConfig "blog") +} diff --git a/modules/blog/src/main/package.scala b/modules/blog/src/main/package.scala new file mode 100644 index 0000000000..62ea97a731 --- /dev/null +++ b/modules/blog/src/main/package.scala @@ -0,0 +1,3 @@ +package lila + +package object blog extends PackageObject with WithPlay diff --git a/project/Build.scala b/project/Build.scala index 10074fa578..1160a48544 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -32,7 +32,7 @@ object ApplicationBuild extends Build { gameSearch, timeline, forum, forumSearch, team, teamSearch, ai, analyse, mod, monitor, site, round, lobby, setup, importer, tournament, relation, report, pref, simulation, - evaluation, chat, puzzle, tv, coordinate) + evaluation, chat, puzzle, tv, coordinate, blog) lazy val moduleRefs = modules map projectToRef lazy val moduleCPDeps = moduleRefs map { new sbt.ClasspathDependency(_, None) } @@ -53,6 +53,10 @@ object ApplicationBuild extends Build { libraryDependencies ++= provided(play.api, RM, PRM) ) + lazy val blog = project("blog", Seq(common, message)).settings( + libraryDependencies ++= provided(play.api, prismic) + ) + lazy val evaluation = project("evaluation", Seq( common, hub, db, user, game)).settings( libraryDependencies ++= provided(play.api, RM, PRM)