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