0

I'm trying to wrap my head around Play action composition. My primary reference is: https://www.playframework.com/documentation/2.3.6/ScalaActionsComposition

Here's what I want to achieve (to be able to declare a function in my Controller this way):

def sensitiveOperation() = Protected {request => ...}

So, my action-plan is:

/**
 * Now I need to make an Action builder that wraps two things: 
 * UserAction (to make sure that request is transformed to UserRequest),
 * and then... an Action that checks if userId has a value (it proceeds by invoking the actual action)
 * , or otherwise return Unauthorized
 */

So... I have these three things:

class UserRequest[A](val userId: Option[String], request: Request[A]) extends WrappedRequest[A](request)

object UserAction extends ActionBuilder[UserRequest] with ActionTransformer[Request, UserRequest] {
  def transform[A](request: Request[A]) = Future.successful {
    new UserRequest(request.session.get("userId"), request)
  }
}

object CheckUserId extends ActionFilter[UserRequest] {
  def filter[A](userRequest: UserRequest[A]) = Future.successful {
    userRequest.userId match {
      case Some(userIdVal) => None
      case None => Some(Results.Unauthorized("User is not logged in. Log in first."))
    }
  }
}

All those three things compile.

My question is: how to declare an Action that makes use of UserAction and CheckUserId ?

object Protected extends ActionBuilder[Request] {
  def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
    block(request)
  }
  override def composeAction[A](action: Action[A]) = ... ?? how ?? ....
}

I've tried this one below, but it gives compile error:

override def composeAction[A](action: Action[A]) = UserAction andThen CheckUserId

ADDITIONAL ADDITIONAL

For now I can work around it using this:

def sensitiveOperation() = (UserAction andThen CheckUserId) {request => ...}

But, still, I think it would have been prettier if I can define a companion object named "Protected" that practically does the same (and-ing UserAction and CheckUserId)..., so I can go back with the original idea:

def sensitiveOperation() = Protected {request => ...}

How to achieve it?

Thanks in advance, Raka

Cokorda Raka
  • 4,375
  • 6
  • 36
  • 54

2 Answers2

3

You can't do it with an object because an object can not be the result of an expression. But you can make it a def or val, and you can put that in a package object if you want, eg:

package object security {
  val Protected = UserAction andThen CheckUserId
}
James Roper
  • 12,695
  • 46
  • 45
0

I think I've found how....

object Protected extends ActionBuilder[UserRequest] {
  def invokeBlock[A](request: Request[A], block: (UserRequest[A]) => Future[Result]) = {
    (UserAction andThen CheckUserId).invokeBlock(request, block)
  }
}
Cokorda Raka
  • 4,375
  • 6
  • 36
  • 54