use std::io::Error;
use crate::args::commands::ProjectArgs;
use crate::config::config_file::{AuthData, ConfigFile};
use async_trait::async_trait;
use jira_v3_openapi::apis::configuration::Configuration;
use jira_v3_openapi::apis::issues_api::{
get_create_issue_meta_issue_type_id, get_create_issue_meta_issue_types,
};
use jira_v3_openapi::apis::projects_api::{create_project, search_projects};
use jira_v3_openapi::models::create_project_details::{AssigneeType, ProjectTypeKey};
use jira_v3_openapi::models::{CreateProjectDetails, ProjectIdentifiers};
use jira_v3_openapi::models::{
FieldCreateMetadata, IssueTypeIssueCreateMetadata, project::Project,
};
#[cfg(test)]
use mockall::automock;
pub struct ProjectCmdRunner {
cfg: Configuration,
}
impl ProjectCmdRunner {
pub fn new(cfg_file: &ConfigFile) -> ProjectCmdRunner {
let mut config = Configuration::new();
let auth_data = AuthData::from_base64(cfg_file.get_auth_key());
config.base_path = cfg_file.get_jira_url().to_string();
config.basic_auth = Some((auth_data.0, Some(auth_data.1)));
ProjectCmdRunner { cfg: config }
}
pub async fn create_jira_project(
&self,
params: ProjectCmdParams,
) -> Result<ProjectIdentifiers, Box<dyn std::error::Error>> {
let p_key = params
.project_key
.as_deref()
.ok_or_else(|| Box::new(Error::other("Error creating project: Empty project key")))?;
let p_name = params
.project_name
.as_deref()
.ok_or_else(|| Box::new(Error::other("Error creating project: Empty project name")))?;
let mut project_data = CreateProjectDetails::new(p_key.to_string(), p_name.to_string());
project_data.description = params.project_description;
project_data.field_configuration_scheme = params.project_field_configuration_id;
project_data.issue_security_scheme = params.project_issue_security_scheme_id;
project_data.issue_type_scheme = params.project_issue_type_scheme_id;
project_data.issue_type_screen_scheme = params.project_issue_type_screen_scheme_id;
project_data.notification_scheme = params.project_notification_scheme_id;
project_data.permission_scheme = params.project_permission_scheme_id;
project_data.workflow_scheme = params.project_workflow_scheme_id;
project_data.lead_account_id = params.project_lead_account_id;
project_data.assignee_type = if params
.project_assignee_type
.unwrap_or("unassigned".to_string())
== "lead"
{
Some(AssigneeType::ProjectLead)
} else {
Some(AssigneeType::Unassigned)
};
project_data.project_type_key = Some(ProjectTypeKey::Software);
Ok(create_project(&self.cfg, project_data).await?)
}
pub async fn list_jira_projects(
&self,
params: ProjectCmdParams,
) -> Result<Vec<Project>, Box<dyn std::error::Error>> {
let page_size = Some(params.projects_page_size.unwrap_or(10));
let page_offset = Some(i64::from(params.projects_page_offset.unwrap_or(0)));
match search_projects(
&self.cfg,
page_offset,
page_size,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
)
.await?
.values
{
Some(values) => Ok(values),
None => Ok(vec![]),
}
}
pub async fn get_jira_project_issue_types(
&self,
params: ProjectCmdParams,
) -> Result<Vec<IssueTypeIssueCreateMetadata>, Box<dyn std::error::Error>> {
let p_key = if let Some(key) = ¶ms.project_key {
key.as_str()
} else {
return Err(Box::new(Error::other(
"Error retrieving project issue types: Empty project key".to_string(),
)));
};
let page_size = Some(params.projects_page_size.unwrap_or(10));
let page_offset = Some(params.projects_page_offset.unwrap_or(0));
match get_create_issue_meta_issue_types(&self.cfg, p_key, page_offset, page_size)
.await?
.issue_types
{
Some(issue_types) => Ok(issue_types),
None => Ok(vec![]),
}
}
pub async fn get_jira_project_issue_type_id(
&self,
params: ProjectCmdParams,
) -> Result<Vec<FieldCreateMetadata>, Box<dyn std::error::Error>> {
let p_key = if let Some(key) = ¶ms.project_key {
key.as_str()
} else {
return Err(Box::new(Error::other(
"Error retrieving project issue types ids: Empty project key".to_string(),
)));
};
let issue_type = if let Some(key) = ¶ms.project_issue_type {
key.as_str()
} else {
return Err(Box::new(Error::other(
"Error retrieving project issue types ids: Empty project issue type key"
.to_string(),
)));
};
let page_size = Some(params.projects_page_size.unwrap_or(10));
let page_offset = Some(params.projects_page_offset.unwrap_or(0));
match get_create_issue_meta_issue_type_id(
&self.cfg,
p_key,
issue_type,
page_offset,
page_size,
)
.await?
.fields
{
Some(id) => Ok(id),
None => Ok(vec![]),
}
}
}
pub struct ProjectCmdParams {
pub project_key: Option<String>,
pub project_issue_type: Option<String>,
pub project_name: Option<String>,
pub project_description: Option<String>,
pub project_field_configuration_id: Option<i64>,
pub project_issue_security_scheme_id: Option<i64>,
pub project_issue_type_scheme_id: Option<i64>,
pub project_issue_type_screen_scheme_id: Option<i64>,
pub project_notification_scheme_id: Option<i64>,
pub project_permission_scheme_id: Option<i64>,
pub project_workflow_scheme_id: Option<i64>,
pub project_lead_account_id: Option<String>,
pub project_assignee_type: Option<String>,
pub projects_page_size: Option<i32>,
pub projects_page_offset: Option<i32>,
}
impl ProjectCmdParams {
pub fn new() -> ProjectCmdParams {
ProjectCmdParams {
project_key: None,
project_issue_type: None,
project_name: None,
project_description: None,
project_field_configuration_id: None,
project_issue_security_scheme_id: None,
project_issue_type_scheme_id: None,
project_issue_type_screen_scheme_id: None,
project_notification_scheme_id: None,
project_permission_scheme_id: None,
project_workflow_scheme_id: None,
project_lead_account_id: None,
project_assignee_type: None,
projects_page_size: None,
projects_page_offset: None,
}
}
}
impl From<&ProjectArgs> for ProjectCmdParams {
fn from(value: &ProjectArgs) -> Self {
ProjectCmdParams {
project_key: value.project_key.clone(),
project_issue_type: value.project_issue_type.clone(),
project_name: value.project_name.clone(),
project_description: value.project_description.clone(),
project_field_configuration_id: value.project_field_configuration_id,
project_issue_security_scheme_id: value.project_issue_security_scheme_id,
project_issue_type_scheme_id: value.project_issue_type_scheme_id,
project_issue_type_screen_scheme_id: value.project_issue_type_screen_scheme_id,
project_notification_scheme_id: value.project_notification_scheme_id,
project_permission_scheme_id: value.project_permission_scheme_id,
project_workflow_scheme_id: value.project_workflow_scheme_id,
project_lead_account_id: value.project_lead_account_id.clone(),
project_assignee_type: value.project_assignee_type.clone(),
projects_page_size: value.pagination.page_size,
projects_page_offset: Some(
i32::try_from(value.pagination.page_offset.unwrap_or(0))
.expect("Invalid page offset, should fit an i32!"),
),
}
}
}
impl Default for ProjectCmdParams {
fn default() -> Self {
ProjectCmdParams::new()
}
}
#[cfg_attr(test, automock)]
#[async_trait(?Send)]
pub trait ProjectCmdRunnerApi: Send + Sync {
async fn create_jira_project(
&self,
params: ProjectCmdParams,
) -> Result<ProjectIdentifiers, Box<dyn std::error::Error>>;
async fn list_jira_projects(
&self,
params: ProjectCmdParams,
) -> Result<Vec<Project>, Box<dyn std::error::Error>>;
async fn get_jira_project_issue_types(
&self,
params: ProjectCmdParams,
) -> Result<Vec<IssueTypeIssueCreateMetadata>, Box<dyn std::error::Error>>;
async fn get_jira_project_issue_type_id(
&self,
params: ProjectCmdParams,
) -> Result<Vec<FieldCreateMetadata>, Box<dyn std::error::Error>>;
}
#[async_trait(?Send)]
impl ProjectCmdRunnerApi for ProjectCmdRunner {
async fn create_jira_project(
&self,
params: ProjectCmdParams,
) -> Result<ProjectIdentifiers, Box<dyn std::error::Error>> {
ProjectCmdRunner::create_jira_project(self, params).await
}
async fn list_jira_projects(
&self,
params: ProjectCmdParams,
) -> Result<Vec<Project>, Box<dyn std::error::Error>> {
ProjectCmdRunner::list_jira_projects(self, params).await
}
async fn get_jira_project_issue_types(
&self,
params: ProjectCmdParams,
) -> Result<Vec<IssueTypeIssueCreateMetadata>, Box<dyn std::error::Error>> {
ProjectCmdRunner::get_jira_project_issue_types(self, params).await
}
async fn get_jira_project_issue_type_id(
&self,
params: ProjectCmdParams,
) -> Result<Vec<FieldCreateMetadata>, Box<dyn std::error::Error>> {
ProjectCmdRunner::get_jira_project_issue_type_id(self, params).await
}
}