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