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