use crate::{config, flags};
use super::{get_input_theme, prompt_select_item};
pub fn assign_task(
args: flags::AssignArgs,
app: toado::Server,
) -> Result<(String, String), toado::Error> {
let (task_term, project_term) = parse_search_terms(&args);
let task_term = match task_term {
Some(term) => term,
None => return Err(Into::into("task search term should be Some")),
};
let project_term = match project_term {
Some(term) => term,
None => return Err(Into::into("project search term should be Some")),
};
let (task_id, task_name, project_id, project_name) =
match_single_task_and_project(task_term, project_term, &app)?;
app.assign_task(task_id, project_id)?;
Ok((task_name, project_name))
}
pub fn assign_multiple_tasks(
args: flags::AssignArgs,
app: toado::Server,
config: &config::Config,
) -> Result<Vec<(String, String)>, toado::Error> {
let (task_term, project_term) = parse_search_terms(&args);
let theme = get_input_theme();
let tasks = prompt_select_item(task_term, &app, &theme, true, false, config)?.tasks();
let projects = prompt_select_item(project_term, &app, &theme, true, true, config)?.projects();
let (task_ids, task_names) = parse_task_names_and_ids(tasks)?;
let (project_ids, project_names) = parse_project_names_and_ids(projects)?;
let assignment_ids = create_id_pairs(task_ids, project_ids);
let assignment_names = create_name_pairs(task_names, project_names);
app.batch_assign_tasks(assignment_ids)?;
Ok(assignment_names)
}
pub fn unassign_task(
args: flags::AssignArgs,
app: toado::Server,
) -> Result<(String, String), toado::Error> {
let (task_term, project_term) = parse_search_terms(&args);
let task_term = match task_term {
Some(term) => term,
None => return Err(Into::into("task search term should be Some")),
};
let project_term = match project_term {
Some(term) => term,
None => return Err(Into::into("project search term should be Some")),
};
let (task_id, task_name, project_id, project_name) =
match_single_task_and_project(task_term, project_term, &app)?;
app.unassign_task(task_id, project_id)?;
Ok((task_name, project_name))
}
pub fn unassign_multiple_tasks(
args: flags::AssignArgs,
app: toado::Server,
config: &config::Config,
) -> Result<Vec<(String, String)>, toado::Error> {
let theme = get_input_theme();
let (task_term, project_term) = parse_search_terms(&args);
let tasks = prompt_select_item(task_term, &app, &theme, true, false, config)?.tasks();
let projects = prompt_select_item(project_term, &app, &theme, true, true, config)?.projects();
let (task_ids, task_names) = parse_task_names_and_ids(tasks)?;
let (project_ids, project_names) = parse_project_names_and_ids(projects)?;
let unassignment_ids = create_id_pairs(task_ids, project_ids);
let unassignment_names = create_name_pairs(task_names, project_names);
app.batch_unassign_tasks(unassignment_ids)?;
Ok(unassignment_names)
}
fn parse_search_terms(args: &flags::AssignArgs) -> (Option<String>, Option<String>) {
let task_term = match (&args.task, &args.task_term) {
(Some(term), _) => Some(term.clone()), (None, Some(term)) => Some(term.clone()), (None, None) => None,
};
let project_term = match (&args.project, &args.project_term) {
(Some(term), _) => Some(term.clone()), (None, Some(term)) => Some(term.clone()), (None, None) => None,
};
(task_term, project_term)
}
fn match_single_task_and_project(
task_term: String,
project_term: String,
app: &toado::Server,
) -> Result<(i64, String, i64, String), toado::Error> {
let tasks = app.select_tasks(
toado::QueryCols::Some(vec!["id", "name"]),
Some(
match task_term.parse::<i64>() {
Ok(num) => toado::QueryConditions::Equal {
col: "id",
value: num.to_string(),
},
Err(_) => toado::QueryConditions::Like {
col: "name",
value: format!("'%{task_term}%'"),
},
}
.to_string(),
),
Some(toado::OrderBy::Name),
None,
None,
None,
)?;
if tasks.is_empty() {
return Err(Into::into(format!("no tasks match '{task_term}'")));
}
let projects = app.select_project(
toado::QueryCols::Some(vec!["id", "name"]),
Some(
match project_term.parse::<i64>() {
Ok(num) => toado::QueryConditions::Equal {
col: "id",
value: num.to_string(),
},
Err(_) => toado::QueryConditions::Like {
col: "name",
value: format!("'%{project_term}%'"),
},
}
.to_string(),
),
Some(toado::OrderBy::Name),
None,
None,
None,
)?;
if projects.is_empty() {
return Err(Into::into(format!("no project match '{project_term}'")));
}
let task = &tasks[0];
let project = &projects[0];
let (task_id, task_name) = (
match &task.id {
Some(id) => *id,
None => return Err(Into::into("task should have id")),
},
match &task.name {
Some(name) => name.clone(),
None => return Err(Into::into("task should have name")),
},
);
let (project_id, project_name) = (
match &project.id {
Some(id) => *id,
None => return Err(Into::into("project should have id")),
},
match &project.name {
Some(name) => name.clone(),
None => return Err(Into::into("project should have name")),
},
);
Ok((task_id, task_name, project_id, project_name))
}
fn parse_task_names_and_ids(
tasks: Vec<toado::Task>,
) -> Result<(Vec<i64>, Vec<String>), toado::Error> {
Ok(tasks
.into_iter()
.map(|task| match (task.id, task.name) {
(Some(id), Some(name)) => Ok((id, name)),
(None, _) => Err("Error: couldn't get task id"),
(_, None) => Err("Error: couldn't get task name"),
})
.collect::<Result<Vec<(i64, String)>, &str>>()?
.into_iter()
.unzip())
}
fn parse_project_names_and_ids(
projects: Vec<toado::Project>,
) -> Result<(Vec<i64>, Vec<String>), toado::Error> {
Ok(projects
.into_iter()
.map(|project| match (project.id, project.name) {
(Some(id), Some(name)) => Ok((id, name)),
(None, _) => Err("Error: couldn't get project id"),
(_, None) => Err("Error: couldn't get project name"),
})
.collect::<Result<Vec<(i64, String)>, &str>>()?
.into_iter()
.unzip())
}
fn create_id_pairs(task_ids: Vec<i64>, project_ids: Vec<i64>) -> Vec<(i64, i64)> {
task_ids
.into_iter()
.flat_map(|task_id| {
project_ids
.clone()
.into_iter()
.map(|project_id| (task_id, project_id))
.collect::<Vec<(i64, i64)>>()
})
.collect::<Vec<(i64, i64)>>()
}
fn create_name_pairs(task_names: Vec<String>, project_names: Vec<String>) -> Vec<(String, String)> {
task_names
.into_iter()
.flat_map(|task_name| {
project_names
.clone()
.into_iter()
.map(|project_name| (task_name.clone(), project_name))
.collect::<Vec<(String, String)>>()
})
.collect::<Vec<(String, String)>>()
}