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::Or<redfish_core::privilege::ConfigureManager,redfish_core::privilege::ConfigureSelf>;
9 type Put = redfish_core::privilege::Or<redfish_core::privilege::ConfigureManager,redfish_core::privilege::ConfigureSelf>;
10 type Patch = redfish_core::privilege::Or<redfish_core::privilege::ConfigureManager,redfish_core::privilege::ConfigureSelf>;
11 type Delete = redfish_core::privilege::Or<redfish_core::privilege::ConfigureManager,redfish_core::privilege::ConfigureSelf>;
12}
13
14pub struct EventDestination<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 client_certificates: Option<axum::Router<S>>,
26 certificates: Option<axum::Router<S>>,
27 resume_subscription: Option<axum::routing::MethodRouter<S>>,
28 suspend_subscription: Option<axum::routing::MethodRouter<S>>,
29}
30
31impl<S> Default for EventDestination<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 client_certificates: Default::default(),
41 certificates: Default::default(),
42 resume_subscription: Default::default(),
43 suspend_subscription: Default::default(),
44 }
45 }
46}
47
48impl<S, P> EventDestination<S, P>
49where
50 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
51 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
52 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
53 <P as redfish_core::privilege::OperationPrivilegeMapping>::Put: Send,
54 <P as redfish_core::privilege::OperationPrivilegeMapping>::Patch: Send,
55 <P as redfish_core::privilege::OperationPrivilegeMapping>::Delete: Send,
56 <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
57{
58 pub fn get<H, T>(mut self, handler: H) -> Self
59 where
60 H: axum::handler::Handler<T, S, axum::body::Body>,
61 T: 'static,
62 {
63 let operation = axum::routing::get(
64 |auth: redfish_core::extract::RedfishAuth<P::Get>,
65 axum::extract::State(state): axum::extract::State<S>,
66 mut request: axum::http::Request<axum::body::Body>| async {
67 request.extensions_mut().insert(auth.user);
68 handler.call(request, state).await
69 },
70 );
71 self.router = self.router.get(operation);
72 self.allowed_methods.push(axum::http::method::Method::GET);
73 self
74 }
75
76 pub fn put<H, T>(mut self, handler: H) -> Self
77 where
78 H: axum::handler::Handler<T, S, axum::body::Body>,
79 T: 'static,
80 {
81 let operation = axum::routing::put(
82 |auth: redfish_core::extract::RedfishAuth<P::Put>,
83 axum::extract::State(state): axum::extract::State<S>,
84 mut request: axum::http::Request<axum::body::Body>| async {
85 request.extensions_mut().insert(auth.user);
86 handler.call(request, state).await
87 },
88 );
89 self.router = self.router.put(operation);
90 self.allowed_methods.push(axum::http::method::Method::PUT);
91 self
92 }
93
94 pub fn patch<H, T>(mut self, handler: H) -> Self
95 where
96 H: axum::handler::Handler<T, S, axum::body::Body>,
97 T: 'static,
98 {
99 let operation = axum::routing::patch(
100 |auth: redfish_core::extract::RedfishAuth<P::Patch>,
101 axum::extract::State(state): axum::extract::State<S>,
102 mut request: axum::http::Request<axum::body::Body>| async {
103 request.extensions_mut().insert(auth.user);
104 handler.call(request, state).await
105 },
106 );
107 self.router = self.router.patch(operation);
108 self.allowed_methods.push(axum::http::method::Method::PATCH);
109 self
110 }
111
112 pub fn delete<H, T>(mut self, handler: H) -> Self
113 where
114 H: axum::handler::Handler<T, S, axum::body::Body>,
115 T: 'static,
116 {
117 let operation = axum::routing::delete(
118 |auth: redfish_core::extract::RedfishAuth<P::Delete>,
119 axum::extract::State(state): axum::extract::State<S>,
120 mut request: axum::http::Request<axum::body::Body>| async {
121 request.extensions_mut().insert(auth.user);
122 handler.call(request, state).await
123 },
124 );
125 self.router = self.router.delete(operation);
126 self.allowed_methods.push(axum::http::method::Method::DELETE);
127 self
128 }
129
130 pub fn client_certificates(mut self, client_certificates: axum::Router<S>) -> Self {
132 self.client_certificates = Some(client_certificates);
133 self
134 }
135
136 pub fn certificates(mut self, certificates: axum::Router<S>) -> Self {
138 self.certificates = Some(certificates);
139 self
140 }
141
142 pub fn resume_subscription<H, T>(mut self, handler: H) -> Self
144 where
145 H: axum::handler::Handler<T, S, axum::body::Body>,
146 T: 'static,
147 {
148 self.resume_subscription = Some(axum::routing::post(
149 |auth: redfish_core::extract::RedfishAuth<P::Post>,
150 axum::extract::State(state): axum::extract::State<S>,
151 mut request: axum::http::Request<axum::body::Body>| async {
152 request.extensions_mut().insert(auth.user);
153 handler.call(request, state).await
154 },
155 ));
156 self
157 }
158
159 pub fn suspend_subscription<H, T>(mut self, handler: H) -> Self
161 where
162 H: axum::handler::Handler<T, S, axum::body::Body>,
163 T: 'static,
164 {
165 self.suspend_subscription = Some(axum::routing::post(
166 |auth: redfish_core::extract::RedfishAuth<P::Post>,
167 axum::extract::State(state): axum::extract::State<S>,
168 mut request: axum::http::Request<axum::body::Body>| async {
169 request.extensions_mut().insert(auth.user);
170 handler.call(request, state).await
171 },
172 ));
173 self
174 }
175
176 pub fn into_router(self) -> axum::Router<S> {
177 let Self {
178 router,
179 mut allowed_methods,
180 client_certificates,
181 certificates,
182 resume_subscription,
183 suspend_subscription,
184 ..
185 } = self;
186 let result = axum::Router::default();
187 let result = match client_certificates {
188 Some(router) => result.nest("/ClientCertificates", router),
189 None => result,
190 };
191 let result = match certificates {
192 Some(router) => result.nest("/Certificates", router),
193 None => result,
194 };
195 let result = match resume_subscription {
196 Some(router) => result.route("/Actions/EventDestination.ResumeSubscription", router),
197 None => result,
198 };
199 let result = match suspend_subscription {
200 Some(router) => result.route("/Actions/EventDestination.SuspendSubscription", router),
201 None => result,
202 };
203 allowed_methods.dedup();
204 let allow_header = allowed_methods
205 .into_iter()
206 .map(|method| method.to_string())
207 .reduce(|one, two| one + "," + &two)
208 .unwrap();
209 result.route(
210 "/",
211 router.fallback(|| async {
212 (
213 axum::http::StatusCode::METHOD_NOT_ALLOWED,
214 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
215 )
216 })
217 .route_layer(axum::middleware::from_fn_with_state(
218 allow_header,
219 |axum::extract::State(allow_header): axum::extract::State<String>,
220 request: axum::http::Request<axum::body::Body>,
221 next: axum::middleware::Next<axum::body::Body>| async move {
222 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
223 let mut response = next.run(request).await;
224 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
225 response.headers_mut().insert(
226 axum::http::header::ALLOW,
227 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
228 );
229 }
230 response
231 },
232 )),
233 )
234 }
235}