1use chrono::NaiveDateTime;
5use manta_backend_dispatcher::error::Error;
6use manta_backend_dispatcher::interfaces::cfs::CfsTrait;
7use manta_backend_dispatcher::interfaces::delete_configurations_and_data_related::DeleteConfigurationsAndDataRelatedTrait;
8use manta_backend_dispatcher::interfaces::hsm::group::GroupTrait;
9use manta_backend_dispatcher::types::cfs::cfs_configuration_response::CfsConfigurationResponse;
10use manta_backend_dispatcher::types::cfs::session::CfsSessionGetResponse;
11
12use crate::server::common::app_context::InfraContext;
13use crate::service::authorization::{
14 validate_user_group_access, validate_user_group_vec_access,
15};
16pub use manta_shared::types::api::configuration::GetConfigurationParams;
17
18#[derive(serde::Serialize)]
20pub struct DeletionCandidates {
21 pub cfs_sessions_to_delete: Vec<CfsSessionGetResponse>,
23 pub bos_sessiontemplate_tuples: Vec<(String, String, String)>,
25 pub image_ids: Vec<String>,
27 pub configuration_names: Vec<String>,
29 pub cfs_session_tuples: Vec<(String, String, String)>,
31 pub configurations: Vec<CfsConfigurationResponse>,
33}
34
35pub async fn get_configurations(
42 infra: &InfraContext<'_>,
43 token: &str,
44 params: &GetConfigurationParams,
45) -> Result<Vec<CfsConfigurationResponse>, Error> {
46 let target_group_vec: Vec<String> = if let Some(group) = ¶ms.group_name {
48 vec![group.clone()]
49 } else {
50 infra
51 .backend
52 .get_group_available(token)
53 .await?
54 .iter()
55 .map(|group| group.label.clone())
56 .collect()
57 };
58
59 validate_user_group_vec_access(infra, token, &target_group_vec).await?;
61
62 let limit_ref = params.limit.as_ref();
63
64 let cfs_configuration_vec = infra
65 .backend
66 .get_and_filter_configuration(
67 token,
68 params.name.as_deref(),
69 params.pattern.as_deref(),
70 &target_group_vec,
71 params.since,
72 params.until,
73 limit_ref,
74 )
75 .await?;
76
77 Ok(cfs_configuration_vec)
78}
79
80pub async fn get_configurations_with_analysis(
91 infra: &InfraContext<'_>,
92 token: &str,
93 params: &GetConfigurationParams,
94) -> Result<Vec<crate::service::analysis::ConfigurationAnalysis>, Error> {
95 let configs = get_configurations(infra, token, params).await?;
96 let components = infra
97 .backend
98 .get_cfs_components(token, None, None, None)
99 .await?;
100 Ok(crate::service::analysis::build_configuration_analysis(
101 configs,
102 components,
103 vec![],
104 vec![],
105 ))
106}
107
108pub(crate) async fn get_deletion_candidates(
125 infra: &InfraContext<'_>,
126 token: &str,
127 settings_hsm_group_name_opt: Option<&str>,
128 configuration_name_pattern: Option<&str>,
129 since: Option<NaiveDateTime>,
130 until: Option<NaiveDateTime>,
131) -> Result<DeletionCandidates, Error> {
132 validate_date_range(since, until)?;
133
134 let target_hsm_group_vec =
135 if let Some(settings_hsm_group_name) = settings_hsm_group_name_opt {
136 validate_user_group_access(infra, token, settings_hsm_group_name).await?;
141 vec![settings_hsm_group_name.to_string()]
142 } else {
143 infra.backend.get_group_name_available(token).await?
144 };
145
146 let (
147 cfs_sessions_to_delete,
148 bos_sessiontemplate_tuples,
149 image_ids,
150 configuration_names,
151 cfs_session_tuples,
152 configurations,
153 ) = infra
154 .backend
155 .get_data_to_delete(
156 token,
157 &target_hsm_group_vec,
158 configuration_name_pattern,
159 since,
160 until,
161 )
162 .await?;
163 Ok(DeletionCandidates {
164 cfs_sessions_to_delete,
165 bos_sessiontemplate_tuples,
166 image_ids,
167 configuration_names,
168 cfs_session_tuples,
169 configurations,
170 })
171}
172
173pub fn validate_date_range(
178 since: Option<NaiveDateTime>,
179 until: Option<NaiveDateTime>,
180) -> Result<(), Error> {
181 if let (Some(s), Some(u)) = (since, until)
182 && s > u
183 {
184 return Err(Error::BadRequest(
185 "'since' date can't be after 'until' date".to_string(),
186 ));
187 }
188 Ok(())
189}
190
191pub(crate) async fn delete_configurations_and_derivatives(
200 infra: &InfraContext<'_>,
201 token: &str,
202 candidates: &DeletionCandidates,
203) -> Result<(), Error> {
204 let cfs_session_name_vec: Vec<String> = candidates
205 .cfs_session_tuples
206 .iter()
207 .map(|(session, _, _)| session.clone())
208 .collect();
209
210 let bos_sessiontemplate_name_vec: Vec<String> = candidates
211 .bos_sessiontemplate_tuples
212 .iter()
213 .map(|(sessiontemplate, _, _)| sessiontemplate.clone())
214 .collect();
215
216 infra
217 .backend
218 .delete(
219 token,
220 &candidates.configuration_names,
221 &candidates.image_ids,
222 &cfs_session_name_vec,
223 &bos_sessiontemplate_name_vec,
224 )
225 .await?;
226
227 Ok(())
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233 use chrono::NaiveDateTime;
234
235 fn dt(s: &str) -> NaiveDateTime {
236 NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S").unwrap()
237 }
238
239 #[test]
240 fn validate_date_range_ok_when_since_before_until() {
241 assert!(
242 validate_date_range(
243 Some(dt("2024-01-01T00:00:00")),
244 Some(dt("2024-01-02T00:00:00"))
245 )
246 .is_ok()
247 );
248 }
249
250 #[test]
251 fn validate_date_range_ok_when_equal() {
252 let d = dt("2024-01-01T00:00:00");
253 assert!(validate_date_range(Some(d), Some(d)).is_ok());
254 }
255
256 #[test]
257 fn validate_date_range_ok_when_either_none() {
258 let d = dt("2024-01-01T00:00:00");
259 assert!(validate_date_range(Some(d), None).is_ok());
260 assert!(validate_date_range(None, Some(d)).is_ok());
261 assert!(validate_date_range(None, None).is_ok());
262 }
263
264 #[test]
265 fn validate_date_range_err_when_since_after_until() {
266 let result = validate_date_range(
267 Some(dt("2024-01-02T00:00:00")),
268 Some(dt("2024-01-01T00:00:00")),
269 );
270 assert!(result.is_err());
271 assert!(
272 result
273 .unwrap_err()
274 .to_string()
275 .contains("'since' date can't be after 'until' date")
276 );
277 }
278}