actix_permissions/
builder.rs

1//! [`Builder`] struct and function implementations.
2use std::future::ready;
3use std::marker::PhantomData;
4
5use actix_web::http::StatusCode;
6use actix_web::{FromRequest, Handler, HttpRequest, HttpResponse, Responder, Route};
7
8use crate::{fn_factory, Permission, PermissionService};
9
10/// Permission builder, combines route, handler and permission check, so
11/// you can write something more fluent like:
12/// ```
13/// use actix_web::web;
14/// use actix_web::HttpRequest;
15/// use actix_permissions::builder::Builder;
16///
17/// async fn permission_check(_req: HttpRequest) -> actix_web::Result<bool>{
18///     Ok(true)
19/// }
20/// async fn index() -> actix_web::Result<String> {
21///     Ok("".to_string())
22/// }
23///
24/// Builder::default().check(web::get()).validate(permission_check).to(index);
25/// ```
26pub struct Builder<F, Args, P1, P1Args> {
27    route: Option<Route>,
28    permission: Option<P1>,
29    handler: Option<F>,
30    pd_handler: PhantomData<Args>,
31    deny_handler: fn(HttpRequest) -> HttpResponse,
32    pd_permission1: PhantomData<P1Args>,
33}
34
35impl<F, Args, P1, P1Args> Builder<F, Args, P1, P1Args>
36where
37    F: Handler<Args>,
38    Args: FromRequest + 'static,
39    P1: Permission<P1Args>,
40    P1Args: FromRequest + 'static,
41    F::Output: Responder,
42{
43    /// Appends route to builder.
44    pub fn check(&mut self, route: Route) -> &mut Self {
45        self.route = Some(route);
46        self
47    }
48
49    /// Appends permission to builder.
50    pub fn validate(&mut self, permission: P1) -> &mut Self {
51        self.permission = Some(permission);
52        self
53    }
54
55    /// Returns new builder with custom deny
56    pub fn with_deny_handler(&mut self, handler: fn(HttpRequest) -> HttpResponse) -> Self {
57        Self {
58            route: self.route.take(),
59            permission: self.permission.take(),
60            handler: self.handler.take(),
61            deny_handler: handler,
62            pd_handler: self.pd_handler,
63            pd_permission1: Default::default(),
64        }
65    }
66
67    /// Appends handler to builder.
68    pub fn to(&mut self, handler: F) -> &mut Self {
69        self.handler = Some(handler);
70        self
71    }
72
73    /// Builds a `Route` from permission `Builder` properties.
74    /// `Route` that checks a `route` if passes a `permission`, then responds with `handler`.
75    /// Otherwise a `deny_handler` is called.
76    pub fn build(&mut self) -> Route {
77        let permission = self.permission.take().unwrap();
78        let handler = self.handler.take().unwrap();
79        let deny_handler = self.deny_handler;
80
81        self.route.take().unwrap().service(fn_factory(move || {
82            ready(Ok(PermissionService::new(
83                permission.clone(),
84                handler.clone(),
85                deny_handler,
86            )))
87        }))
88    }
89}
90
91impl<F, Args, P1, P1Args> Default for Builder<F, Args, P1, P1Args> {
92    fn default() -> Self {
93        Self {
94            handler: None,
95            deny_handler: default_deny_handler,
96            permission: None,
97            pd_handler: PhantomData,
98            pd_permission1: PhantomData,
99            route: None,
100        }
101    }
102}
103
104/// Default deny handler, returns Forbidden.
105pub fn default_deny_handler(_req: HttpRequest) -> HttpResponse {
106    HttpResponse::new(StatusCode::FORBIDDEN)
107}