1pub struct DefaultPrivileges;
5impl redfish_core::privilege::OperationPrivilegeMapping for DefaultPrivileges {
6 type Get = redfish_core::privilege::Login;
7 type Head = redfish_core::privilege::Login;
8 type Post = redfish_core::privilege::ConfigureManager;
9 type Put = redfish_core::privilege::ConfigureManager;
10 type Patch = redfish_core::privilege::ConfigureManager;
11 type Delete = redfish_core::privilege::ConfigureManager;
12}
13
14pub struct Control<S, P>
19where
20 S: Clone,
21{
22 router: axum::routing::MethodRouter<S>,
23 privilege_marker: std::marker::PhantomData<fn() -> P>,
24 allowed_methods: Vec<axum::http::method::Method>,
25 reset_to_defaults: Option<axum::routing::MethodRouter<S>>,
26}
27
28impl<S> Default for Control<S, DefaultPrivileges>
29where
30 S: Clone,
31{
32 fn default() -> Self {
33 Self {
34 router: Default::default(),
35 privilege_marker: Default::default(),
36 allowed_methods: Vec::new(),
37 reset_to_defaults: Default::default(),
38 }
39 }
40}
41
42impl<S, P> Control<S, P>
43where
44 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
45 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
46 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
47 <P as redfish_core::privilege::OperationPrivilegeMapping>::Put: Send,
48 <P as redfish_core::privilege::OperationPrivilegeMapping>::Patch: Send,
49 <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
50{
51 pub fn get<H, T>(mut self, handler: H) -> Self
52 where
53 H: axum::handler::Handler<T, S, axum::body::Body>,
54 T: 'static,
55 {
56 let operation = axum::routing::get(
57 |auth: redfish_core::extract::RedfishAuth<P::Get>,
58 axum::extract::State(state): axum::extract::State<S>,
59 mut request: axum::http::Request<axum::body::Body>| async {
60 request.extensions_mut().insert(auth.user);
61 handler.call(request, state).await
62 },
63 );
64 self.router = self.router.get(operation);
65 self.allowed_methods.push(axum::http::method::Method::GET);
66 self
67 }
68
69 pub fn put<H, T>(mut self, handler: H) -> Self
70 where
71 H: axum::handler::Handler<T, S, axum::body::Body>,
72 T: 'static,
73 {
74 let operation = axum::routing::put(
75 |auth: redfish_core::extract::RedfishAuth<P::Put>,
76 axum::extract::State(state): axum::extract::State<S>,
77 mut request: axum::http::Request<axum::body::Body>| async {
78 request.extensions_mut().insert(auth.user);
79 handler.call(request, state).await
80 },
81 );
82 self.router = self.router.put(operation);
83 self.allowed_methods.push(axum::http::method::Method::PUT);
84 self
85 }
86
87 pub fn patch<H, T>(mut self, handler: H) -> Self
88 where
89 H: axum::handler::Handler<T, S, axum::body::Body>,
90 T: 'static,
91 {
92 let operation = axum::routing::patch(
93 |auth: redfish_core::extract::RedfishAuth<P::Patch>,
94 axum::extract::State(state): axum::extract::State<S>,
95 mut request: axum::http::Request<axum::body::Body>| async {
96 request.extensions_mut().insert(auth.user);
97 handler.call(request, state).await
98 },
99 );
100 self.router = self.router.patch(operation);
101 self.allowed_methods.push(axum::http::method::Method::PATCH);
102 self
103 }
104
105 pub fn reset_to_defaults<H, T>(mut self, handler: H) -> Self
107 where
108 H: axum::handler::Handler<T, S, axum::body::Body>,
109 T: 'static,
110 {
111 self.reset_to_defaults = Some(axum::routing::post(
112 |auth: redfish_core::extract::RedfishAuth<P::Post>,
113 axum::extract::State(state): axum::extract::State<S>,
114 mut request: axum::http::Request<axum::body::Body>| async {
115 request.extensions_mut().insert(auth.user);
116 handler.call(request, state).await
117 },
118 ));
119 self
120 }
121
122 pub fn into_router(self) -> axum::Router<S> {
123 let Self {
124 router,
125 mut allowed_methods,
126 reset_to_defaults,
127 ..
128 } = self;
129 let result = axum::Router::default();
130 let result = match reset_to_defaults {
131 Some(router) => result.route("/Actions/Control.ResetToDefaults", router),
132 None => result,
133 };
134 allowed_methods.dedup();
135 let allow_header = allowed_methods
136 .into_iter()
137 .map(|method| method.to_string())
138 .reduce(|one, two| one + "," + &two)
139 .unwrap();
140 result.route(
141 "/",
142 router.fallback(|| async {
143 (
144 axum::http::StatusCode::METHOD_NOT_ALLOWED,
145 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
146 )
147 })
148 .route_layer(axum::middleware::from_fn_with_state(
149 allow_header,
150 |axum::extract::State(allow_header): axum::extract::State<String>,
151 request: axum::http::Request<axum::body::Body>,
152 next: axum::middleware::Next<axum::body::Body>| async move {
153 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
154 let mut response = next.run(request).await;
155 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
156 response.headers_mut().insert(
157 axum::http::header::ALLOW,
158 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
159 );
160 }
161 response
162 },
163 )),
164 )
165 }
166}