Scala DeadboltAction и затем пользовательская игра ActionBuilder

Вот моя проблема: мне нужно проверить в контроллере разрешение пользователя, используя deadbolt, а затем добавить что-то в запрос (используя ActionBuilder). Обычно использование Play Action Builders будет (action1 andThen action2) но это не работает с DeadboltActions.

Вот некоторый код:

ActionBuilder

import javax.inject.Inject
import models.Item
import modules.item.services.ItemServiceClient
import play.api.mvc._

import scala.concurrent.{ExecutionContext, Future}

class ItemRequest[A](val items: Seq[Item], request: Request[A]) extends WrappedRequest[A](request)

class ItemAction @Inject()(val parser: BodyParsers.Default)(implicit val executionContext: ExecutionContext)
  extends ActionBuilder[ItemRequest, AnyContent] with ActionTransformer[Request, ItemRequest] {
  def transform[A](request: Request[A]): Future[ItemRequest[A]] = {
    ItemServiceClient.getItems.map{
      new ItemRequest(_, request)
    }recover{
      case _ => new ItemRequest(Seq(), request)
    }

  }
}

контроллер:

@Singleton
class ItemController @Inject()(cc: ControllerComponents, deadbolt: DeadboltActions, itemAction: ItemAction) extends AbstractController(cc) with I18nSupport {

def createSomething: Action[AnyContent] = (deadbolt.Pattern("Create_Something", PatternType.EQUALITY) andThen itemAction) { implicit request: ItemRequest[AnyContent] =>
            Ok(modules.item.views.html.createSomething(Something.form, request.items))
    }
}

[ошибка] Непримененные методы преобразуются в функции только тогда, когда ожидается тип функции. Вы можете сделать это преобразование явным, написав Pattern _ или же Pattern(_,_,_,_,_)(_)(_) вместо Pattern,

[ошибка] def createSomething: Action[AnyContent] = (deadbolt.Pattern("Create_Deck", PatternType.EQUALITY)() и затем itemAction).synchronized() {неявный запрос: ItemRequest[AnyContent] =>

Кто-нибудь, кто уже имел дело с этим?

2 ответа

Поскольку DeadboltActions#Pattern возвращает ActionЯ не думаю, что вы можете использовать его для композиции действий. Вместо этого, по крайней мере, с Deadbolt 2.5.1, вы можете искать be.objectify.deadbolt.scala.SubjectActionBuilder, который является ActionBuilder[AuthenticatedRequest], то вы можете составить это с вашим ItemAction,

Вот простой пример:

class MyRequest[A](request: Request[A]) extends WrappedRequest(request)
val handler: DeadboltHandler = ???
val action1: ActionFunction[Request, AuthenticatedRequest] = SubjectActionBuilder(None)
val action2: ActionTransformer[Request, MyRequest] = new ActionTransformer[Request, MyRequest] {
  override protected def transform[A](request: Request[A]): Future[MyRequest[A]] = Future.successful(new MyRequest(request))
}
val action3: ActionFunction[Request, MyRequest] = action1 andThen action2

Вот пример, который завершает то, что, я думаю, вы хотите сделать, но НЕ использует композицию действий (по крайней мере, в том смысле, в котором я думаю, что вы имеете в виду):

class MyRequest[A](request: Request[A]) extends WrappedRequest[A](request)
class MyAction extends ActionTransformer[Request, MyRequest] {
  override protected def transform[A](request: Request[A]): Future[MyRequest[A]] =
    Future.successful(new MyRequest(request))
}

val deadboltActions: DeadboltActions = ???

def createSomething: Action[AnyContent] = deadboltActions.Pattern("Create_Something")() { authRequest =>
  ((new MyAction) compose Action).async { request: MyRequest[AnyContent] =>
    Future.successful(Ok(""))
  }(authRequest)
}

Как уже упоминал Джейми, когда стандартные утилиты для компоновки не применимы напрямую, мы можем вернуться к компоновке Actionс использованием следующего шаблона:

OuterAction { outerRequest =>
  InnerAction { request =>
    // ... some Result
  } (outerRequest)
}

Например, в вашем случае может сработать следующее:

val deadboltAction =
  deadbolt.Pattern[AnyContent](
    value = "admin.printer",
    patternType = PatternType.EQUALITY
  )() _

val itemAction = ...

deadboltAction { implicit authRequest: AuthenticatedRequest[AnyContent] =>
  itemAction { implicit request: ItemRequest[AnyContent] => 
    Ok(modules.item.views.html.createSomething(Something.form, request.items))
  } (authRequest)
}

Чтобы привести его в порядок, мы могли бы создать следующий служебный метод

def deadboltActionWithItemAction(block: ItemRequest[AnyContent] => Result): Action[AnyContent] =
  deadboltAction { implicit authRequest =>
    itemAction { 
      block 
    }(authRequest)
  }

и тогда сайт вызова выглядит примерно так

deadboltActionWithItemAction { implicit request: ItemRequest[AnyContent] =>
  Ok(modules.item.views.html.createSomething(Something.form, request.items))
}
Другие вопросы по тегам