From 1e17d0d9612a3909de9fc55f34f6bd6453e19a6b Mon Sep 17 00:00:00 2001 From: gakuzzzz Date: Mon, 18 Feb 2013 22:49:54 +0900 Subject: [PATCH] Applied Stackable Controller --- app/controllers/Application.scala | 38 ++++++++----------- module/build.sbt | 8 ++-- .../scala/jp/t2v/lab/play20/auth/Auth.scala | 4 +- .../jp/t2v/lab/play20/auth/AuthElement.scala | 35 +++++++++++++++++ project/Build.scala | 8 +++- project/plugins.sbt | 3 +- 6 files changed, 65 insertions(+), 31 deletions(-) create mode 100644 module/src/main/scala/jp/t2v/lab/play20/auth/AuthElement.scala diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala index 3de533a..6150ca7 100644 --- a/app/controllers/Application.scala +++ b/app/controllers/Application.scala @@ -10,7 +10,8 @@ import play.api.mvc.Results._ import jp.t2v.lab.play20.auth._ import play.api.Play._ import play.api.cache.Cache -import scala.reflect.classTag +import reflect.{ClassTag, classTag} +import jp.t2v.lab.play2.stackc.{RequestWithAttributes, RequestAttributeKey, StackableController} object Application extends Controller with LoginLogout with AuthConfigImpl { @@ -37,25 +38,25 @@ object Application extends Controller with LoginLogout with AuthConfigImpl { } } -object Message extends Base { +object Message extends Controller with Pjax with AuthElement with AuthConfigImpl { - def main = compositeAction(NormalUser) { user => implicit template => implicit request => + def main = StackAction(AuthorityKey -> NormalUser) { implicit request => val title = "message main" Cache.set("hoge", "testtttttt") Ok(html.message.main(title)) } - def list = compositeAction(NormalUser) { user => implicit template => implicit request => + def list = StackAction(AuthorityKey -> NormalUser) { implicit request => val title = Cache.getAs[String]("hoge").getOrElse("all messages") Ok(html.message.list(title)) } - def detail(id: Int) = compositeAction(NormalUser) { user => implicit template => implicit request => + def detail(id: Int) = StackAction(AuthorityKey -> NormalUser) { implicit request => val title = "messages detail " Ok(html.message.detail(title + id)) } - def write = compositeAction(Administrator) { user => implicit template => implicit request => + def write = StackAction(AuthorityKey -> Administrator) { implicit request => val title = "write message" Ok(html.message.write(title)) } @@ -93,25 +94,18 @@ trait AuthConfigImpl extends AuthConfig { } -trait Base extends Controller with Auth with Pjax with AuthConfigImpl { +trait Pjax extends StackableController { + self: Controller with AuthElement with AuthConfigImpl => - def compositeAction(permission: Permission)(f: Account => Template => RequestHeader => PlainResult) = - Action { implicit request => - (for { - user <- authorized(permission).right - template <- pjax(user).right - } yield f(user)(template)(request)).merge - } - -} + type Template = String => Html => Html -trait Pjax { - self: Controller => + case object TemplateKey extends RequestAttributeKey - type Template = String => Html => Html - def pjax(user: Account)(implicit request: RequestHeader): Either[PlainResult, Template] = Right { - if (request.headers.keys("X-PJAX")) html.pjaxTemplate.apply - else html.fullTemplate.apply(user) + abstract override def proceed[A](req: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Result): Result = { + val template: Template = if (req.headers.keys("X-Pjax")) html.pjaxTemplate.apply else html.fullTemplate.apply(loggedIn(req)) + super.proceed(req.set(TemplateKey, template))(f) } + implicit def template[A](implicit req: RequestWithAttributes[A]): Template = req.getAs[Template](TemplateKey).get + } diff --git a/module/build.sbt b/module/build.sbt index 504e20a..1689b66 100644 --- a/module/build.sbt +++ b/module/build.sbt @@ -1,15 +1,17 @@ name := "play21.auth" -version := "0.7" +version := "0.8-SNAPSHOT" scalaVersion := "2.10.0" resolvers ++= Seq( - "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/" + "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/", + "Sonatype Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" ) libraryDependencies ++= Seq( - "play" %% "play" % "2.1.0" + "play" %% "play" % "2.1.0", + "jp.t2v" %% "stackable-controller" % "0.1-SNAPSHOT" ) organization := "jp.t2v" diff --git a/module/src/main/scala/jp/t2v/lab/play20/auth/Auth.scala b/module/src/main/scala/jp/t2v/lab/play20/auth/Auth.scala index 9727589..5f7f34a 100644 --- a/module/src/main/scala/jp/t2v/lab/play20/auth/Auth.scala +++ b/module/src/main/scala/jp/t2v/lab/play20/auth/Auth.scala @@ -4,7 +4,7 @@ import play.api.mvc._ import play.api.libs.iteratee.{Input, Done} trait Auth { - self: Controller with AuthConfig => + self: AuthConfig => def authorizedAction(authority: Authority)(f: User => Request[AnyContent] => Result): Action[(AnyContent, User)] = authorizedAction(BodyParsers.parse.anyContent, authority)(f) @@ -30,7 +30,7 @@ trait Auth { _ <- Either.cond(authorize(user, authority), (), authorizationFailed(request)).right } yield user - private def restoreUser(implicit request: RequestHeader): Option[User] = for { + private[auth] def restoreUser(implicit request: RequestHeader): Option[User] = for { cookie <- request.cookies.get(cookieName) token <- CookieUtil.verifyHmac(cookie) userId <- idContainer.get(token) diff --git a/module/src/main/scala/jp/t2v/lab/play20/auth/AuthElement.scala b/module/src/main/scala/jp/t2v/lab/play20/auth/AuthElement.scala new file mode 100644 index 0000000..da83b73 --- /dev/null +++ b/module/src/main/scala/jp/t2v/lab/play20/auth/AuthElement.scala @@ -0,0 +1,35 @@ +package jp.t2v.lab.play20.auth + +import play.api.mvc.{Result, Controller} +import jp.t2v.lab.play2.stackc.{RequestWithAttributes, RequestAttributeKey, StackableController} + +trait AuthElement extends StackableController with Auth { + self: Controller with AuthConfig => + + case object AuthKey extends RequestAttributeKey + case object AuthorityKey extends RequestAttributeKey + + abstract override def proceed[A](req: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Result): Result = { + (for { + authority <- req.getAs[Authority](AuthorityKey).toRight(authorizationFailed(req)).right + user <- authorized(authority)(req).right + } yield super.proceed(req.set(AuthKey, user))(f)).merge + } + + implicit def loggedIn[A](implicit req: RequestWithAttributes[A]): User = req.getAs[User](AuthKey).get + +} + + +trait OptionalAuthElement extends StackableController with Auth { + self: Controller with AuthConfig => + + case object AuthKey extends RequestAttributeKey + + abstract override def proceed[A](req: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Result): Result = { + val maybeUser = restoreUser(req) + super.proceed(req.set(AuthKey, maybeUser.getOrElse(null)))(f) + } + + implicit def loggedIn[A](implicit req: RequestWithAttributes[A]): Option[User] = req.getAs[User](AuthKey) +} \ No newline at end of file diff --git a/project/Build.scala b/project/Build.scala index 9676369..a96f503 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -15,8 +15,12 @@ object ApplicationBuild extends Build { "org.mindrot" % "jbcrypt" % "0.3m" ) - lazy val root = play.Project(appName, appVersion, appDependencies).settings( - resolvers += "jbcrypt repo" at "http://mvnrepository.com/" + lazy val root = play.Project(appName, appVersion, appDependencies, path = file(".")).settings( + resolvers ++= Seq( + "jbcrypt repo" at "http://mvnrepository.com/", + "Sonatype Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" + ) ).dependsOn(module) + } diff --git a/project/plugins.sbt b/project/plugins.sbt index 710afe0..d9dacd0 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -3,8 +3,7 @@ logLevel := Level.Warn // The Typesafe repository resolvers ++= Seq( - "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/", - "sbt-idea-repo" at "http://mpeltonen.github.com/maven/" + "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/" ) // Use the Play sbt plugin for Play projects