override and with generic type parameter - scala

I'm using Play Scala 2.5, I would like to know how to override the invokeBlock method so that I could get the body of request as json.
case class AuthenticatedRequest[A](val username: Option[String], val param: Option[String], request: Request[A]) extends WrappedRequest[A](request)
object AuthenticatedAction extends ActionBuilder[AuthenticatedRequest] {
/**
* logger used to log actions.
*/
val logger: Logger = Logger("mylogger")
def invokeBlock[A](request: Request[A], block: AuthenticatedRequest[A] => Future[Result]): Future[Result] = {
request.session.get("username") match {
case Some(username) => {
val param = (request.body.asJson.get \ "param").as[String]
block(new AuthenticatedRequest(Some(username), Some(param), request))
}
case None => Future.successful(Results.Forbidden)
}
}
}
I have to following exception after compiling:
value asJson is not a member of type parameter A
[error] val param = (request.body.asJson.get \ "param").as[String]

The error is linked to the fact that your bodyis returning something of generic type A, for which the asJson method is not defined.
Unfortunately, you cannot use pattern matching directly to get the type of A, because of type-erasure of Scala (at run time, only the class exists, not its type parameters). One work-around is to use the reflection API, as follow :
import scala.reflect.runtime.universe._
def invokeBlock[A](request: Request[A]) = {
request match {
case specificRequest : Request[SpecificRequest] if (typeOf[A] =:= typeOf[SpecificRequest]) => // Do the request processing
}
}
That should allow you to retrieve the type, and be able to call specific methods on it.

Related

How to avoid duplication of mocked functions signatures in scalamock?

I'm using scalamock to mock this class:
class HttpService {
def post[In, Out]
(url: String, payload: In)
(implicit encoder: Encoder[In], decoder: Decoder[Out])
: Future[Out] = ...
...
}
...so my test class has a mock used like this:
val httpService = mock[HttpService]
(httpService.post[FormattedMessage, Unit](_ : String, _ : FormattedMessage) (_ : Encoder[FormattedMessage], _: Decoder[Unit]))
.expects("http://example.com/whatever",*, *, *)
.returning(Future.successful(()))
Apparently I have to write the whole mock function signature. If I only put the underscores in the signature, without the corresponding types, I get errors like this one:
[error] missing parameter type for expanded function ((x$1: <error>, x$2, x$3, x$4) => httpService.post[FormattedMessage, Unit](x$1, x$2)(x$3, x$4))
[error] (httpService.post[FormattedMessage, Unit](_, _) (_, _))
^
What I don't like about this code is that the mock expectation is used in several places in the tests and this ugly signature is repeated all over the place but with different In/Out type parameters and expectations.
So I thought I would write a class
class HttpServiceMock extends MockFactory {
val instance = mock[HttpService]
def post[In, Out] = instance.post[In, Out](_ : String, _ : In) (_ : Encoder[In], _: Decoder[Out])
}
...and use it like this:
val httpService = new HttpServiceMock()
...
httpService.post[FormattedMessage, Unit]
.expects("http://example.com/whatever",*, *, *)
.returning(Future.successful(()))
...which compiles fine but when I run the tests I get the following error:
java.lang.NoSuchMethodException: com.myapp.test.tools.HttpServiceMock.mock$post$0()
at java.lang.Class.getMethod(Class.java:1786)
at com.myapp.controllers.SlackControllerSpec.$anonfun$new$3(SlackControllerSpec.scala:160)
at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.WordSpecLike$$anon$1.apply(WordSpecLike.scala:1078)
at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
How can I fix this error? Are there other ways to avoid the re-writing of the mocked function signature over and over again?
UPDATE:
In the end the mock looks like this:
trait HttpServiceMock extends MockFactory {
object httpService {
val instance = mock[HttpService]
def post[In, Out] = toMockFunction4(instance.post[In, Out](_: String, _: In)(_: Encoder[In], _: Decoder[Out]))
}
}
You can use the below code:
trait HttpMockSupport {
this: MockFactory =>
val httpService = mock[HttpService]
def prettyPost[In, Out]: MockFunction4[String, In, Encoder[In], Decoder[Out], Future[Out]] = {
toMockFunction4(httpService.post[In, Out](_: String, _: In)(_: Encoder[In], _: Decoder[Out]))
}
}
class AClassThatNeedsHttpServiceMocking extends FreeSpec with Matchers with MockFactory with HttpMockSupport {
"HttpService should post" in {
val url = "http://localhost/1"
val input = "input"
implicit val encoder: Encoder[String] = new Encoder[String] {}
implicit val decoder: Decoder[String] = new Decoder[String] {}
prettyPost[String, String]
.expects(url, input, encoder, decoder)
.returns(Future.successful("result"))
httpService.post(url, input)
}
}
It puts the common mocking in a trait that can be extended in all the places that needs to mock HttpService and just call the non-ugly method :)
Update 1:
Updated it to accept the expected parameters.
Update 2:
Updated the prettyPost method to be generic so that we can set any kind of expectations.
Scalamock expects a MockFunctionX. So, in your case, all you have to do is to convert the ugly function to a pretty function and then convert it to a MockFunctionX.
Don't use Scalamock, make HttpService a trait and implement the trait directly to mock whatever you need. E.g. (you can paste this in the Scala REPL, but remember to press Enter and Ctrl+D at the end):
:rese
:pa
import scala.concurrent.Future
trait Encoder[A]
trait Decoder[A]
// HttpService.scala
trait HttpService {
def post[In: Encoder, Out: Decoder](
url: String, payload: In): Future[Out]
}
object HttpService extends HttpService {
override def post[In: Encoder, Out: Decoder](
url: String,
payload: In):
Future[Out] = ???
}
// HttpServiceSpec.scala
class Mock[Out](result: Future[Out]) extends HttpService {
override def post[In: Encoder, Out: Decoder](
url: String,
payload: In):
Future[Out] =
// This is fine because it's a mock.
result.asInstanceOf[Future[Out]]
}

Use of implicits in Play 2.5 ActionRefiner

I am trying to create my own ActionRefiner to accommodate authentication, but for some reason the compiler won't let me use implicit variables in the refine[A] function... I have the following code:
trait Auth {
object AuthenticatedAction extends ActionBuilder[AuthRequest] with ActionRefiner[Request, AuthRequest] {
def refine[A](request: Request[A])(implicit userCollection: UserCollection, ex: ExecutionContext): Future[Either[Result, AuthRequest[A]]] = {
request.session.get("username") match {
case Some(username) => userCollection.findByEmail(username).map { userOpt =>
userOpt.map(new AuthRequest(_, request)).toRight(Results.Redirect(routes.LoginController.login()))
}
case None => Future.successful(Left(Results.Redirect(routes.LoginController.login())))
}
}
}
}
class AuthRequest[A](val user: User, request: Request[A]) extends WrappedRequest[A](request)
The Scala compiler tells me that the method refine[A](request: R[A]): Future[Either[Result, P[A]]] is not defined. When I remove the implicit variables it registers, but that leaves me with no UserCollection...
So, How do I correctly use the ActionRefiner?
Thanks to this topic I found a way to make it work. Instead of using an implicit, I can define the UserCollection in the trait and pass it from my controller, like so:
trait Auth {
def userCollection: UserCollection
object AuthenticatedAction extends ActionBuilder[AuthRequest] with ActionRefiner[Request, AuthRequest] {
def refine[A](request: Request[A]): Future[Either[Result, AuthRequest[A]]] = {
...
}
}
}
class HomeController #Inject()(val userCollection: UserCollection)(implicit executionContext: ExecutionContext) extends Controller with Auth {
def index = AuthenticatedAction { implicit request =>
Ok(s"Hello ${request.user.name}")
}
}
I just had gotten so used to using implicits that I completely forgot about this.

Play Framework 2.3.x: Wrap Request object using Scala Oauth in Play Framework

I am trying to Create customize action for security. I am using Scala Oauth
for handling security in my application and trying to create custom action and wrap the Scala Oauth security in my custom action. According to Play Framework Documentation, i am using two ways for wrapped request object, but unfortunately, i am not getting my custom Request object in custom Action handler. Following are the Ways:
case class AuthRequest[A](user: User, request: Request[A]) extends WrappedRequest[A](request)
First Way
case class CustomSecurityAction[A](action: Action[A]) extends Action[A] with OAuth2Provider{
def apply(request: Request[A]): Future[Result] = {
implicit val executionContext: ExecutionContext = play.api.libs.concurrent.Execution.defaultContext
request.headers.get("Host").map { host =>
authorize(new SecurityDataHandler(host)) { authInfo =>
action(AuthRequest(authInfo.user, request))
}(request, executionContext)
} getOrElse {
Future.successful(Unauthorized("401 No user\n"))
}}
lazy val parser = action.parser
}
object SecurityAction extends ActionBuilder[Request] with OAuth2Provider {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
block(request)
}
override def composeAction[A](action: Action[A]) = new CustomSecurityAction(action)
}
Second Way
object SecurityAction extends ActionBuilder[Request] with OAuth2Provider {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
implicit val executionContext: ExecutionContext = play.api.libs.concurrent.Execution.defaultContext
request.headers.get("Host").map { host =>
authorize(new SecurityDataHandler(host)) { authInfo =>
block(AuthRequest(authInfo.user, request))
}(request, executionContext)
} getOrElse {
Future.successful(Unauthorized("401 No user\n"))
}
}
According to both ways, when i am trying to use user object in my custom handler i am getting following compile time error:
value user is not a member of play.api.mvc.Request[play.api.mvc.AnyContent]
val user = request.user
Following is my handler code:
def testCustomAction = SecurityAction { request =>
val user = request.user
Future.successful(Ok("Apna To Chal Gya"))
}
There is simple problem, in above code. I am using play.api.mvc.Request in invokeBlock method instead of AuthRequest. Please find below code for correction.
object SecurityAction extends ActionBuilder[AuthRequest] {
override def invokeBlock[A](request: Request[A], block: (AuthRequest[A]) => Future[Result]) = {
request match {
case re: AuthRequest[A] => block(re)
case _ => Future.successful(Results.Unauthorized("401 No user\n"))
}
}
override def composeAction[A](action: Action[A]) = CustomSecurityAction(action)
}

PlayFramework 2.4 Scala ActionRefiner with parameter from url usage

I've made ActionRefiner to read language of current request from parameter in url:
class LangRequest[A](val lang: Lang, request: Request[A]) extends WrappedRequest[A](request)
def LangAction(lang: String) = new ActionRefiner[Request, LangRequest] {
def refine[A](input: Request[A]) = Future.successful {
val availLangs: List[String] = Play.current.configuration.getStringList("play.i18n.langs").get.toList
if (!availLangs.contains(lang))
Left {
input.acceptLanguages.head match {
case Lang(value, _) if availLangs.contains(value) => Redirect(controllers.routes.Application.index(value))
case _ => Redirect(controllers.routes.Application.index(availLangs.head))
}
}
else Right {
new LangRequest(Lang(lang), input)
}
}
}
and try to use it in action like this:
def login(lng: String) = LangAction(lng) { implicit request: Request[AnyContent] =>
Ok("Ok")
}
And I've got
"play.api.mvc.ActionRefiner[play.api.mvc.Request,controllers.actionbuilders.LangRequest]
does not take parameters"
error at compilation time. How can I use this ActionRefiner? In PlayFramework documentation https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition they show ActionRefiner usages with Filter, Transformer like this:
(UserAction andThen ItemAction(itemId) andThen PermissionCheckAction)
and this does work. But how to use one ActionRefiner?
I'm sorry; this is pretty old, but I am facing a similar problem and wanted to post the solution so others could find it. I suspect it is because the first item in the chain of actions should be an ActionBuilder, in addition to whatever else. ActionTransformer is not a subtype of ActionBuilder, though it can be an argument to ActionBuilder#andThen.
It is correct, the ActionBuilder has to be the first element in the chain based on https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition#Putting-it-all-together
On the other hand, there are scenarios where we need to pass arguments to the ActionRefiner due to interactions with the database (e.g. retrieve products using id). At this point, we need to #Inject dependencies like services to get access to DB and the function is a partial solution. So, we can wrap the function in class to inject the dependencies and also inherent from ActionBuilder due to we can have only one element in the chain and we need to start with an ActionBuilder.
class UserActionBuilder #Inject()(
val defaultBodyParsers: BodyParsers.Default,
userService: UserService
)(implicit val ec: ExecutionContext) {
def refine(userEmail: String): ActionRefiner[Request, UserRequest] with ActionBuilder[UserRequest, AnyContent] =
new ActionRefiner[Request, UserRequest] with ActionBuilder[UserRequest, AnyContent] {
def executionContext: ExecutionContext = ec
override def refine[A](request: Request[A]): Future[Either[Result, UserRequest[A]]] = {
userService.retrieveUserByEmail(userEmail)
.map {
case Some(user) if user.isActive => Right(UserRequest(user, request))
case _ => Left(Results.Forbidden("User is inactive"))
}
.recover { case ex: Throwable =>
Left(Results.InternalServerError(ex.getMessage))
}
}
override def parser: BodyParser[AnyContent] = defaultBodyParsers
}
}
case class UserRequest[A](user: User, request: Request[A])
extends WrappedRequest[A](request)
And then
class UserController #Inject()(
arguments...,
userAction: UserActionBuilder
)(implicit executionContext: ExecutionContext) {
def updateUserPurchase(emailUser: String): Action[UserPurchaseRequest] = {
userAction.refine(emailUser)).async(apiParser.parserOf[UserPurchaseRequest]) { implicit request =>
...
doUpdate(request.body, request.user)
...
}
}
}

Scala Play Action Composition : Declare ActionBuilder that produces Action by combining several ActionFunction

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
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
}
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)
}
}