Skip to content

Commit

Permalink
add timetracking and begin report
Browse files Browse the repository at this point in the history
  • Loading branch information
bck01215 committed Jun 25, 2024
1 parent 245b349 commit c7a731b
Show file tree
Hide file tree
Showing 9 changed files with 395 additions and 98 deletions.
48 changes: 47 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "elasticnow"
version = "0.2.0"
version = "0.3.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -23,3 +23,4 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
urlencoding = "2.1.3"
openssl = { version = "0.10", features = ["vendored"] }
clap_complete = "4.5.6"
textplots = "0.8.6"
2 changes: 1 addition & 1 deletion ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ElasticNow CLI

This project was inspired by [Preston Gibbs](mailto:[email protected]) and his hate for time tracking.
This project simplifies timetracking in servicenow for those who find it difficult to navigate.

## Usage

Expand Down
73 changes: 70 additions & 3 deletions src/cli/args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::cli::config::get_config_dir;
use crate::elasticnow::servicenow_structs::SysIdResult;
use ansi_term::Colour;
use chrono::{Datelike, Local};
use clap::{Command, CommandFactory, Parser, Subcommand};
use clap_complete::{generate, Generator, Shell};
use dialoguer::{theme::ColorfulTheme, Select};
Expand All @@ -20,7 +21,7 @@ pub struct Args {
pub enum Commands {
/// Run time tracking options utilizing ElasticNow and ServiceNow
Timetrack {
#[clap(short, long, conflicts_with = "search", action = clap::ArgAction::SetTrue)]
#[clap(short, long, conflicts_with_all = ["search","no_tkt"], action = clap::ArgAction::SetTrue)]
/// Creates a new ticket instead of updating an existing one ( cannot be used with --search )
new: bool,
#[clap(short, long)]
Expand All @@ -29,15 +30,29 @@ pub enum Commands {
#[clap(
short,
long,
help = format!("Add time in the format of {} where 1 can be replaced with any number (hours must be less than 24)", Colour::Green.bold().paint("1h1m")))
help = format!("Add time in the format of {} where 1 can be replaced with any number (hours must be less than 20)", Colour::Green.bold().paint("1h1m")))
]
time_worked: String,
#[clap(short, long, required_unless_present = "new")]
#[clap(short, long, required_unless_present_any = ["new", "no_tkt"])]
/// Keyword search using ElasticNow (returns all tickets in bin by default)
search: Option<String>,
#[clap(short, long, visible_alias = "assignment-group")]
/// Override default bin for searching (defaults to user's assigned bin or override in config.toml)
bin: Option<String>,

#[clap(long, conflicts_with_all = ["search","new"], action = clap::ArgAction::SetTrue)]
/// Uses timetracking without a ticket
no_tkt: bool,
},
/// Get time tracking report showing hours worked and benefitting departments.
Report {
#[clap(short, long)]
/// Override the default user in the report
user: Option<String>,
#[clap(long, help = format!("Start date of search (defaults to {})", get_week_start()))]
since: Option<String>,
#[clap(long, help = format!("End date of search (defaults to {})", get_today()))]
until: Option<String>,
},

/// Create a std chg using a template
Expand Down Expand Up @@ -126,3 +141,55 @@ pub fn choose_chg_template(chg_templates: Vec<SysIdResult>) -> String {

chg_templates[selection].sys_id.clone()
}

pub fn choose_category() -> String {
let options = vec![
"Certs, Pro Dev, Training: Conferences, Studying or Taking Certifications, Webinars, On-boarding, or Employee to Employee Training",
"University Events: Convocation, You Matter",
"Clerical: Email, Operational Meetings, & Paperwork that cannot be tied to a task"
];
let items = vec!["certs_prodev_training", "clerical", "univ_events"];
let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt("Please choose a category for timetracking:")
.default(0)
.items(&options)
.interact()
.unwrap();

items[selection].to_string()
}

pub fn range_format_validate(date: &str) -> Result<(), Box<dyn std::error::Error>> {
let date = date.split('-').collect::<Vec<&str>>();
if date.len() != 3 {
return Err("Date must be in YYYY-M-D format".into());
}
let year = date[0].parse::<i32>()?;
let month = date[1].parse::<i32>()?;
let day = date[2].parse::<i32>()?;
if year < 2000 || year > 3000 {
return Err("Year must be between 2010 and 2100".into());
}
if month < 1 || month > 12 {
return Err("Month must be between 1 and 12".into());
}
if day < 1 || day > 31 {
return Err("Day must be between 1 and 31".into());
}
Ok(())
}

pub fn get_today() -> String {
let now = Local::now();
format!("{}-{:02}-{:02}", now.year(), now.month(), now.day())
}

pub fn get_week_start() -> String {
let now = Local::now();
format!(
"{}-{:02}-{:02}",
now.year(),
now.month(),
now.day() - now.weekday().num_days_from_monday()
)
}
9 changes: 9 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
pub mod args;
pub mod config;

#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_time_validator() {
assert_eq!(args::range_format_validate("2010-01-01").unwrap(), ());
}
}
55 changes: 55 additions & 0 deletions src/elasticnow/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
pub mod elasticnow;
pub mod servicenow;
pub mod servicenow_structs;

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_time_add_to_epoch_basic() {
assert_eq!(
servicenow::time_add_to_epoch("1h2m").unwrap(),
"1970-01-01+01:02:00"
);
}

#[test]
fn test_time_add_to_epoch_too_many_hours() {
assert_eq!(
servicenow::time_add_to_epoch("20h0m")
.unwrap_err()
.to_string(),
"Invalid time format. Values must be below 20 for hours, 60 for minutes"
);
}

#[test]
fn test_time_add_to_epoch_too_many_minutes() {
assert_eq!(
servicenow::time_add_to_epoch("0h60m")
.unwrap_err()
.to_string(),
"Invalid time format. Values must be below 20 for hours, 60 for minutes"
);
}
#[test]
fn test_time_only_hour() {
assert_eq!(
servicenow::time_add_to_epoch("1h").unwrap(),
"1970-01-01+01:00:00"
);
}

#[test]
fn test_time_only_minute() {
assert_eq!(
servicenow::time_add_to_epoch("1m").unwrap(),
"1970-01-01+00:01:00"
);
}

#[test]
fn test_time_no_time() {
assert_eq!(
servicenow::time_add_to_epoch("0h").unwrap_err().to_string(),
"Time worked must be greater than 0 minutes"
);
}
}
Loading

0 comments on commit c7a731b

Please sign in to comment.