jirust_cli/runners/jira_cmd_runners/project_cmd_runner.rs
1use std::io::Error;
2
3use crate::args::commands::ProjectArgs;
4use crate::config::config_file::{AuthData, ConfigFile};
5use jira_v3_openapi::apis::configuration::Configuration;
6use jira_v3_openapi::apis::issues_api::{
7 get_create_issue_meta_issue_type_id, get_create_issue_meta_issue_types,
8};
9use jira_v3_openapi::apis::projects_api::{create_project, search_projects};
10use jira_v3_openapi::models::create_project_details::{AssigneeType, ProjectTypeKey};
11use jira_v3_openapi::models::{CreateProjectDetails, ProjectIdentifiers};
12use jira_v3_openapi::models::{
13 FieldCreateMetadata, IssueTypeIssueCreateMetadata, project::Project,
14};
15
16/// Project command runner struct.
17///
18/// This struct is responsible for holding the project commands parameters
19/// and it is used to pass the parameters to the project commands runner.
20pub struct ProjectCmdRunner {
21 cfg: Configuration,
22}
23
24/// Project command runner implementation.
25///
26/// # Methods
27///
28/// * `new` - Creates a new instance of the ProjectCmdRunner struct.
29/// * `list_jira_projects` - Lists Jira projects.
30/// * `get_jira_project_issue_types` - Gets Jira project issue types.
31/// * `get_jira_project_issue_type_id` - Gets Jira project issue fields by issue type ID.
32impl ProjectCmdRunner {
33 /// Creates a new instance of the ProjectCmdRunner struct.
34 ///
35 /// # Arguments
36 ///
37 /// * `cfg_file` - A ConfigFile struct.
38 ///
39 /// # Returns
40 ///
41 /// * A new instance of the ProjectCmdRunner struct.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use jirust_cli::config::config_file::ConfigFile;
47 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::ProjectCmdRunner;
48 /// use toml::Table;
49 ///
50 /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
51 ///
52 /// let project_cmd_runner = ProjectCmdRunner::new(&cfg_file);
53 /// ```
54 pub fn new(cfg_file: &ConfigFile) -> ProjectCmdRunner {
55 let mut config = Configuration::new();
56 let auth_data = AuthData::from_base64(cfg_file.get_auth_key());
57 config.base_path = cfg_file.get_jira_url().to_string();
58 config.basic_auth = Some((auth_data.0, Some(auth_data.1)));
59 ProjectCmdRunner { cfg: config }
60 }
61
62 /// Create a new Jira project using the provided parameters.
63 ///
64 /// # Arguments
65 /// * `params` - The parameters for creating the project.
66 ///
67 /// # Returns
68 /// A `Result` containing the project identifiers if successful, or an error if failed.
69 ///
70 /// # Examples
71 ///
72 /// ```no_run
73 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::{ProjectCmdRunner, ProjectCmdParams};
74 /// use jirust_cli::config::config_file::ConfigFile;
75 /// use toml::Table;
76 ///
77 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
78 /// # tokio_test::block_on(async {
79 /// let cfg_file = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
80 /// let project_cmd_runner = ProjectCmdRunner::new(&cfg_file);
81 ///
82 /// let mut params = ProjectCmdParams::new();
83 /// params.project_key = Some("TEST".to_string());
84 /// params.project_name = Some("Test Project".to_string());
85 /// params.project_description = Some("This is a test project".to_string());
86 /// params.project_field_configuration_id = Some(12345);
87 /// params.project_issue_security_scheme_id = Some(67890);
88 /// params.project_issue_type_scheme_id = Some(54321);
89 ///
90 /// let projects = project_cmd_runner.create_jira_project(params).await?;
91 ///
92 /// # Ok(())
93 /// # })
94 /// # }
95 /// ```
96 pub async fn create_jira_project(
97 &self,
98 params: ProjectCmdParams,
99 ) -> Result<ProjectIdentifiers, Box<dyn std::error::Error>> {
100 let p_key = params
101 .project_key
102 .as_deref()
103 .ok_or_else(|| Box::new(Error::other("Error creating project: Empty project key")))?;
104 let p_name = params
105 .project_name
106 .as_deref()
107 .ok_or_else(|| Box::new(Error::other("Error creating project: Empty project name")))?;
108
109 let mut project_data = CreateProjectDetails::new(p_key.to_string(), p_name.to_string());
110 project_data.description = params.project_description;
111 project_data.field_configuration_scheme = params.project_field_configuration_id;
112 project_data.issue_security_scheme = params.project_issue_security_scheme_id;
113 project_data.issue_type_scheme = params.project_issue_type_scheme_id;
114 project_data.issue_type_screen_scheme = params.project_issue_type_screen_scheme_id;
115 project_data.notification_scheme = params.project_notification_scheme_id;
116 project_data.permission_scheme = params.project_permission_scheme_id;
117 project_data.workflow_scheme = params.project_workflow_scheme_id;
118 project_data.lead_account_id = params.project_lead_account_id;
119 project_data.assignee_type = if params
120 .project_assignee_type
121 .unwrap_or("unassigned".to_string())
122 == "lead"
123 {
124 Some(AssigneeType::ProjectLead)
125 } else {
126 Some(AssigneeType::Unassigned)
127 };
128 project_data.project_type_key = Some(ProjectTypeKey::Software);
129 Ok(create_project(&self.cfg, project_data).await?)
130 }
131
132 /// Lists Jira projects.
133 ///
134 /// # Arguments
135 ///
136 /// * `params` - A ProjectCmdParams struct.
137 ///
138 /// # Returns
139 ///
140 /// * A Result with a vector of Project structs or an error message.
141 ///
142 /// # Examples
143 ///
144 /// ```no_run
145 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::{ProjectCmdRunner, ProjectCmdParams};
146 /// use jirust_cli::config::config_file::ConfigFile;
147 /// use toml::Table;
148 ///
149 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
150 /// # tokio_test::block_on(async {
151 /// let cfg_file = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
152 /// let project_cmd_runner = ProjectCmdRunner::new(&cfg_file);
153 /// let params = ProjectCmdParams::new();
154 ///
155 /// let projects = project_cmd_runner.list_jira_projects(params).await?;
156 /// # Ok(())
157 /// # })
158 /// # }
159 /// ```
160 pub async fn list_jira_projects(
161 &self,
162 params: ProjectCmdParams,
163 ) -> Result<Vec<Project>, Box<dyn std::error::Error>> {
164 let page_size = Some(params.projects_page_size.unwrap_or(10));
165 let page_offset = Some(i64::from(params.projects_page_offset.unwrap_or(0)));
166 match search_projects(
167 &self.cfg,
168 page_offset,
169 page_size,
170 None,
171 None,
172 None,
173 None,
174 None,
175 None,
176 None,
177 None,
178 None,
179 None,
180 None,
181 )
182 .await?
183 .values
184 {
185 Some(values) => Ok(values),
186 None => Ok(vec![]),
187 }
188 }
189
190 /// Gets Jira project issue types.
191 ///
192 /// # Arguments
193 ///
194 /// * `params` - A ProjectCmdParams struct.
195 ///
196 /// # Returns
197 /// * A Result with a vector of IssueTypeIssueCreateMetadata structs or an error message.
198 ///
199 /// # Examples
200 ///
201 /// ```no_run
202 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::{ProjectCmdRunner, ProjectCmdParams};
203 /// use jirust_cli::config::config_file::ConfigFile;
204 /// use toml::Table;
205 ///
206 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
207 /// # tokio_test::block_on(async {
208 /// let cfg_file = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
209 /// let project_cmd_runner = ProjectCmdRunner::new(&cfg_file);
210 /// let params = ProjectCmdParams::new();
211 ///
212 /// let issue_types = project_cmd_runner.get_jira_project_issue_types(params).await?;
213 /// # Ok(())
214 /// # })
215 /// # }
216 /// ```
217 pub async fn get_jira_project_issue_types(
218 &self,
219 params: ProjectCmdParams,
220 ) -> Result<Vec<IssueTypeIssueCreateMetadata>, Box<dyn std::error::Error>> {
221 let p_key = if let Some(key) = ¶ms.project_key {
222 key.as_str()
223 } else {
224 return Err(Box::new(Error::other(
225 "Error retrieving project issue types: Empty project key".to_string(),
226 )));
227 };
228 let page_size = Some(params.projects_page_size.unwrap_or(10));
229 let page_offset = Some(params.projects_page_offset.unwrap_or(0));
230 match get_create_issue_meta_issue_types(&self.cfg, p_key, page_offset, page_size)
231 .await?
232 .issue_types
233 {
234 Some(issue_types) => Ok(issue_types),
235 None => Ok(vec![]),
236 }
237 }
238
239 /// Gets Jira project issue fields by issue type id.
240 ///
241 /// # Arguments
242 ///
243 /// * `params` - A ProjectCmdParams struct.
244 ///
245 /// # Returns
246 ///
247 /// * A Result with a vector of FieldCreateMetadata structs or an error message.
248 ///
249 /// # Examples
250 ///
251 /// ```no_run
252 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::{ProjectCmdRunner, ProjectCmdParams};
253 /// use jirust_cli::config::config_file::ConfigFile;
254 /// use toml::Table;
255 ///
256 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
257 /// # tokio_test::block_on(async {
258 /// let cfg_file = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
259 /// let project_cmd_runner = ProjectCmdRunner::new(&cfg_file);
260 /// let params = ProjectCmdParams::new();
261 ///
262 /// let issue_fields = project_cmd_runner.get_jira_project_issue_type_id(params).await?;
263 /// # Ok(())
264 /// # })
265 /// # }
266 /// ```
267 pub async fn get_jira_project_issue_type_id(
268 &self,
269 params: ProjectCmdParams,
270 ) -> Result<Vec<FieldCreateMetadata>, Box<dyn std::error::Error>> {
271 let p_key = if let Some(key) = ¶ms.project_key {
272 key.as_str()
273 } else {
274 return Err(Box::new(Error::other(
275 "Error retrieving project issue types ids: Empty project key".to_string(),
276 )));
277 };
278 let issue_type = if let Some(key) = ¶ms.project_issue_type {
279 key.as_str()
280 } else {
281 return Err(Box::new(Error::other(
282 "Error retrieving project issue types ids: Empty project issue type key"
283 .to_string(),
284 )));
285 };
286 let page_size = Some(params.projects_page_size.unwrap_or(10));
287 let page_offset = Some(params.projects_page_offset.unwrap_or(0));
288 match get_create_issue_meta_issue_type_id(
289 &self.cfg,
290 p_key,
291 issue_type,
292 page_offset,
293 page_size,
294 )
295 .await?
296 .fields
297 {
298 Some(id) => Ok(id),
299 None => Ok(vec![]),
300 }
301 }
302}
303
304/// This struct defines the parameters for the Project commands
305///
306/// # Fields
307///
308/// * `project_key` - The project key, **required** for get project issue types and issue fields commands.
309/// * `project_issue_type` - The project issue type, **required** for get issue fields command.
310/// * `projects_page_size` - The page size for the project command, optional.
311/// * `projects_page_offset` - The page offset for the project command, optional.
312pub struct ProjectCmdParams {
313 pub project_key: Option<String>,
314 pub project_issue_type: Option<String>,
315 pub project_name: Option<String>,
316 pub project_description: Option<String>,
317 pub project_field_configuration_id: Option<i64>,
318 pub project_issue_security_scheme_id: Option<i64>,
319 pub project_issue_type_scheme_id: Option<i64>,
320 pub project_issue_type_screen_scheme_id: Option<i64>,
321 pub project_notification_scheme_id: Option<i64>,
322 pub project_permission_scheme_id: Option<i64>,
323 pub project_workflow_scheme_id: Option<i64>,
324 pub project_lead_account_id: Option<String>,
325 pub project_assignee_type: Option<String>,
326 pub projects_page_size: Option<i32>,
327 pub projects_page_offset: Option<i32>,
328}
329
330/// Implementation of the ProjectCmdParams struct
331///
332/// # Methods
333///
334/// * `new` - Creates a new ProjectCmdParams struct.
335///
336impl ProjectCmdParams {
337 /// Creates a new ProjectCmdParams struct instance.
338 ///
339 /// # Returns
340 ///
341 /// * A ProjectCmdParams struct instance.
342 ///
343 /// # Examples
344 ///
345 /// ```
346 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::ProjectCmdParams;
347 ///
348 /// let params = ProjectCmdParams::new();
349 /// ```
350 pub fn new() -> ProjectCmdParams {
351 ProjectCmdParams {
352 project_key: None,
353 project_issue_type: None,
354 project_name: None,
355 project_description: None,
356 project_field_configuration_id: None,
357 project_issue_security_scheme_id: None,
358 project_issue_type_scheme_id: None,
359 project_issue_type_screen_scheme_id: None,
360 project_notification_scheme_id: None,
361 project_permission_scheme_id: None,
362 project_workflow_scheme_id: None,
363 project_lead_account_id: None,
364 project_assignee_type: None,
365 projects_page_size: None,
366 projects_page_offset: None,
367 }
368 }
369}
370
371/// Implementation of the From trait for the ProjectCmdParams struct
372/// to convert from ProjectArgs to ProjectCmdParams.
373impl From<&ProjectArgs> for ProjectCmdParams {
374 /// Converts from ProjectArgs to ProjectCmdParams.
375 ///
376 /// # Arguments
377 ///
378 /// * `value` - A ProjectArgs struct.
379 ///
380 /// # Returns
381 ///
382 /// * A ProjectCmdParams struct instance.
383 ///
384 /// # Examples
385 ///
386 /// ```
387 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::ProjectCmdParams;
388 /// use jirust_cli::args::commands::{ProjectArgs, ProjectActionValues, PaginationArgs, OutputArgs};
389 ///
390 /// let project_args = ProjectArgs {
391 /// project_act: ProjectActionValues::GetIssueTypeFields,
392 /// project_key: Some("project_key".to_string()),
393 /// project_issue_type: Some("project_issue_type".to_string()),
394 /// project_name: None,
395 /// project_description: None,
396 /// project_field_configuration_id: None,
397 /// project_issue_security_scheme_id: None,
398 /// project_issue_type_scheme_id: None,
399 /// project_issue_type_screen_scheme_id: None,
400 /// project_notification_scheme_id: None,
401 /// project_permission_scheme_id: None,
402 /// project_workflow_scheme_id: None,
403 /// project_lead_account_id: None,
404 /// project_assignee_type: None,
405 /// pagination: PaginationArgs { page_size: Some(10), page_offset: None },
406 /// output: OutputArgs { output_format: None, output_type: None },
407 /// };
408 ///
409 /// let params = ProjectCmdParams::from(&project_args);
410 ///
411 /// assert_eq!(params.project_key, Some("project_key".to_string()));
412 /// assert_eq!(params.project_issue_type, Some("project_issue_type".to_string()));
413 /// assert_eq!(params.projects_page_size, Some(10));
414 /// assert_eq!(params.projects_page_offset, Some(0));
415 /// ```
416 fn from(value: &ProjectArgs) -> Self {
417 ProjectCmdParams {
418 project_key: value.project_key.clone(),
419 project_issue_type: value.project_issue_type.clone(),
420 project_name: value.project_name.clone(),
421 project_description: value.project_description.clone(),
422 project_field_configuration_id: value.project_field_configuration_id,
423 project_issue_security_scheme_id: value.project_issue_security_scheme_id,
424 project_issue_type_scheme_id: value.project_issue_type_scheme_id,
425 project_issue_type_screen_scheme_id: value.project_issue_type_screen_scheme_id,
426 project_notification_scheme_id: value.project_notification_scheme_id,
427 project_permission_scheme_id: value.project_permission_scheme_id,
428 project_workflow_scheme_id: value.project_workflow_scheme_id,
429 project_lead_account_id: value.project_lead_account_id.clone(),
430 project_assignee_type: value.project_assignee_type.clone(),
431 projects_page_size: value.pagination.page_size,
432 projects_page_offset: Some(
433 i32::try_from(value.pagination.page_offset.unwrap_or(0))
434 .expect("Invalid page offset, should fit an i32!"),
435 ),
436 }
437 }
438}
439
440/// Implementation of the Default trait for the ProjectCmdParams struct
441impl Default for ProjectCmdParams {
442 /// Creates a default ProjectCmdParams struct instance.
443 ///
444 /// # Returns
445 ///
446 /// * A ProjectCmdParams struct instance with default values.
447 ///
448 /// # Examples
449 ///
450 /// ```
451 /// use jirust_cli::runners::jira_cmd_runners::project_cmd_runner::ProjectCmdParams;
452 ///
453 /// let params = ProjectCmdParams::default();
454 ///
455 /// assert_eq!(params.project_key, None);
456 /// assert_eq!(params.project_issue_type, None);
457 /// assert_eq!(params.projects_page_size, None);
458 /// assert_eq!(params.projects_page_offset, None);
459 /// ```
460 fn default() -> Self {
461 ProjectCmdParams::new()
462 }
463}