use crate::board;
use crate::common;
use crate::get_ticket_template_file;
use crate::state::model::State;
use crate::ticket;
use crate::ticket::model::Ticket;
use clap::Parser;
use std::env;
use std::fs;
use std::io::ErrorKind;
#[derive(Debug, Parser)]
pub struct TicketCli {
#[arg(short, long)]
create: bool,
#[arg(short, long, value_name = "ticket number")]
read: Option<usize>,
#[arg(short, long, value_name = "ticket number")]
update: Option<usize>,
#[arg(short, long, value_name = "ticket number")]
delete: Option<usize>,
#[arg(short, long)]
list: bool,
#[arg(short, long, num_args = 2, value_names = ["ticket number", "state"])]
state: Option<Vec<String>>,
}
impl TicketCli {
pub fn parse_options(self) {
let board_id = common::get_current_board().id;
if self.create {
create_new_ticket();
}
if let Some(ticket_number) = self.read {
read_ticket(board_id, ticket_number);
}
if let Some(ticket_number) = self.update {
update_ticket(board_id, ticket_number);
}
if let Some(ticket_number) = self.delete {
delete_ticket(board_id, ticket_number);
}
if self.list {
list_all_tickets(board_id);
}
if let Some(passed_values) = self.state {
let ticket_number: usize = passed_values[0].parse().unwrap();
let state: &String = &passed_values[1];
println!("{} - {}", ticket_number, state);
}
}
}
fn create_new_ticket() -> usize {
open_interactive_ticket_file();
let (title, description) = process_ticket_data();
let board_id = common::get_current_board().id;
let number = board::data::increment_and_get_ticket_count(board_id)
.expect("Failed to get new incremented ticket count.");
let ticket = Ticket::new(board_id, number, title, description);
match ticket::data::add(&ticket) {
Ok(_) => println!("'{}' Ticket created.", ticket.title),
Err(value) => println!("Error creating '{}' Ticket : {}", ticket.title, value),
}
remove_ticket_file();
number
}
fn read_ticket(board_id: usize, ticket_number: usize) {
let ticket =
ticket::data::get_by_number(board_id, ticket_number).expect("Failed to get Ticket.");
println!("{:#?}", ticket);
}
fn update_ticket(board_id: usize, ticket_number: usize) {
let ticket =
ticket::data::get_by_number(board_id, ticket_number).expect("Failed to get Ticket.");
let ticket_toml_string =
toml::to_string(&ticket).expect("Failed to serialize Ticket to TOML string.");
write_to_ticket_file(ticket_toml_string);
open_interactive_ticket_file();
let (title, description) = process_ticket_data();
ticket::data::update(board_id, ticket_number, &title, &description)
.expect("Failed to update Ticket.");
}
fn delete_ticket(board_id: usize, ticket_number: usize) {
ticket::data::delete(board_id, ticket_number).expect("Failed to delete Ticket.");
println!("Ticket number {} deleted successfully.", ticket_number);
}
fn list_all_tickets(board_id: usize) {
let tickets =
ticket::data::get_all_by_board_id(board_id).expect("Failed to retrieve all Tickets.");
for ticket in tickets {
if ticket.state == State::ToDo {
println!("{} - {}", ticket.id, ticket.title);
}
}
}
fn open_interactive_ticket_file() {
let editor = env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
let temp_file = get_ticket_template_file();
match std::process::Command::new(editor).arg(temp_file).status() {
Ok(ticket_template) => ticket_template,
Err(error) => match error.kind() {
ErrorKind::NotFound => panic!("Could not find editor provided."),
other_error => panic!("{:?}", other_error),
},
};
}
fn process_ticket_data() -> (String, String) {
let temp_file = get_ticket_template_file();
let content = fs::read_to_string(temp_file)
.expect("Failed to read content from new Ticket template file.");
let deserialized_content: toml::Value = match toml::from_str(&content) {
Ok(content) => content,
Err(error) => panic!(
"Error deserializing data from new ticket template: {}",
error
),
};
let title = deserialized_content
.get("title")
.expect("Key: Title, not found in 'ticket_template.toml")
.as_str()
.expect("Failed to parse provided title as str.")
.trim()
.to_string();
let description = deserialized_content
.get("description")
.expect("Key: Description, not found in 'ticket_template.toml")
.as_str()
.expect("Failed to parse provided description as str.")
.trim()
.to_string();
(title, description)
}
fn remove_ticket_file() {
let temp_file = get_ticket_template_file();
std::process::Command::new("rm")
.arg(temp_file)
.status()
.expect("Failed to remove temporary Ticket file.");
}
fn write_to_ticket_file(data: String) {
let file = get_ticket_template_file();
fs::write(file, data).expect("Failed to write to temporary Ticket file.");
}