diff --git a/Cargo.lock b/Cargo.lock index a639e60..92f3eff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,23 +332,6 @@ dependencies = [ "phf_codegen", ] -[[package]] -name = "chrono_track" -version = "0.1.0" -dependencies = [ - "chrono", - "chrono-tz", - "clap", - "csv", - "lettre", - "log", - "reqwest", - "serde", - "serde_json", - "simplelog", - "toml", -] - [[package]] name = "clap" version = "4.4.2" @@ -1572,6 +1555,23 @@ dependencies = [ "time-core", ] +[[package]] +name = "time_tracker" +version = "0.1.0" +dependencies = [ + "chrono", + "chrono-tz", + "clap", + "csv", + "lettre", + "log", + "reqwest", + "serde", + "serde_json", + "simplelog", + "toml", +] + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 273f454..a19461f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] members = [ "status_cloud", - "chrono_track" + "time_tracker" ] diff --git a/flake.nix b/flake.nix index 3c87fd2..defc7f4 100644 --- a/flake.nix +++ b/flake.nix @@ -37,8 +37,7 @@ rust-project TODO: write shell script for automatically updating `cargoHash` rustSettings = with pkgs; { src = ./.; nativeBuildInputs = [ pkg-config ]; - # move makeWrapper to nativeBuildInputs - buildInputs = [ openssl hddtemp msmtp makeWrapper ]; + buildInputs = [ openssl hddtemp msmtp ]; cargoHash = nixpkgs.lib.fakeHash; }; meta = with nixpkgs.lib; { @@ -62,27 +61,26 @@ rust-project TODO: write shell script for automatically updating `cargoHash` pname = "status_cloud"; version = "0.1.0"; buildAndTestSubdir = "status_cloud"; - cargoHash = "sha256-mXcD/92WJLgN2efX/8EiV3rOqUiNOKGC4puS8DvGFOc="; - postFixup = '' - wrapProgram $out/bin/status_cloud \ - --prefix PATH : "${nixpkgs.lib.makeBinPath [ pkgs.hddtemp ]}" + cargoHash = "sha256-XIonh2SQ8EichcZvHErSydt0qtKGodXE0yKz4BsntA8="; + preBuild = '' + sed -i 's/Command::new("hddtemp")/Command::new("${nixpkgs.lib.escape [ "/" ] "${pkgs.hddtemp}"}")/g' status_cloud/src/main.rs ''; meta = meta // { description = "Server status saved to a nextcloud note service."; }; }); - chrono_track = pkgs.rustPlatform.buildRustPackage (rustSettings // { - pname = "chrono_track"; + time_tracker = pkgs.rustPlatform.buildRustPackage (rustSettings // { + pname = "time_tracker"; version = "0.1.0"; - buildAndTestSubdir = "chrono_track"; - cargoHash = "sha256-51j5eG2ZBJg2TjbvYSEvvmOM4hhPyNohN+LUmvck88k="; + buildAndTestSubdir = "time_tracker"; + cargoHash = "sha256-5Wy2+ef2BriKmvNhllDVh/clAZGV7myDc281ygj05vI="; meta = meta // { description = "Using nextcloud notes to track time usage."; }; postFixup = '' - wrapProgram $out/bin/chrono_track \ - --prefix PATH : "${nixpkgs.lib.makeBinPath [ pkgs.msmtp ]}" + wrapProgram $out/bin/time_tracker \ + --prefix PATH : "${lib.makeBinPath [ msmtp ]}" ''; }); }; @@ -139,14 +137,14 @@ rust-project TODO: write shell script for automatically updating `cargoHash` # Time Tracker - options.services.chrono_track = { - enable = lib.mkEnableOption (lib.mdDoc "chrono track, time tracking service"); + options.services.time_tracker = { + enable = lib.mkEnableOption (lib.mdDoc "time tracker service"); package = lib.mkOption { type = lib.types.package; - default = self.packages.${system}.chrono_track; - defaultText = "pkgs.chrono_track"; + default = self.packages.${system}.time_tracker; + defaultText = "pkgs.time_tracker"; description = lib.mdDoc '' - The chrono_track package that should be used + The time_tracker package that should be used ''; }; config_path = lib.mkOption { @@ -155,12 +153,6 @@ rust-project TODO: write shell script for automatically updating `cargoHash` The file path to the toml that contains user information secrets ''; }; - from_address = lib.mkOption { - type = lib.types.str; - description = lib.mdDoc '' - The from address for the emails. E.g. noreply@example.com - ''; - }; frequency = lib.mkOption { type = lib.types.int; description = lib.mdDoc '' @@ -169,25 +161,25 @@ rust-project TODO: write shell script for automatically updating `cargoHash` }; }; - config.systemd.services.chrono_track = let - cfg = config.services.chrono_track; - pkg = self.packages.${system}.chrono_track; + config.systemd.services.time_tracker = let + cfg = config.services.time_tracker; + pkg = self.packages.${system}.time_tracker; in lib.mkIf cfg.enable { - description = "Chrono Track"; + description = "Nextcloud Time Tracker"; serviceConfig = { Type = "oneshot"; ExecStart = '' - ${cfg.package}/bin/chrono_track --config-file ${builtins.toString cfg.config_path} --from-addr ${cfg.from_address} + ${cfg.package}/bin/time_tracker --config-file ${builtins.toString cfg.config_path} ''; }; }; - config.systemd.timers.chrono_track = let - cfg = config.services.chrono_track; - pkg = self.packages.${system}.chrono_track; + config.systemd.timers.time_tracker = let + cfg = config.services.time_tracker; + pkg = self.packages.${system}.time_tracker; in lib.mkIf cfg.enable { wantedBy = [ "timers.target" ]; - partOf = [ "chrono_track.service" ]; + partOf = [ "time_tracker.service" ]; timerConfig.OnCalendar = [ "*:0/${builtins.toString cfg.frequency}" ]; }; diff --git a/chrono_track/Cargo.toml b/time_tracker/Cargo.toml similarity index 96% rename from chrono_track/Cargo.toml rename to time_tracker/Cargo.toml index 3b44e57..cac90bc 100644 --- a/chrono_track/Cargo.toml +++ b/time_tracker/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "chrono_track" +name = "time_tracker" version = "0.1.0" edition = "2021" diff --git a/chrono_track/src/main.rs b/time_tracker/src/main.rs similarity index 78% rename from chrono_track/src/main.rs rename to time_tracker/src/main.rs index 5bb244b..7ca3091 100644 --- a/chrono_track/src/main.rs +++ b/time_tracker/src/main.rs @@ -2,7 +2,7 @@ use chrono::{DateTime, Datelike, Utc}; use chrono_tz::US::Central; use clap::Parser; use lettre::{ - message::{header::ContentType, Attachment, Message, MultiPart, SinglePart}, + message::{Message, header::ContentType, Attachment, MultiPart, SinglePart}, SendmailTransport, Transport, }; use log::{debug, error}; @@ -196,7 +196,7 @@ fn main() -> Result<(), Box> { if do_email_summary { debug!("Send email selected"); reset_email_checkbox(&cfg); - send_email_summary(&cfg, body_content, &args); + send_email_summary(&cfg, body_content); } Ok(()) @@ -236,9 +236,6 @@ struct CliArgs { #[arg(short, long)] config_file: PathBuf, - #[arg(short, long)] - from_addr: String, - #[arg(short, long)] debug: bool, } @@ -302,14 +299,14 @@ struct SummaryRow { // All calls after depend on the success of the one before, and cannot run // without. So it would be too much work to make an error type to handle an error // that would cause a crash anyways -fn send_email_summary(config: &Config, body_content: Vec, cliargs: &CliArgs) { +fn send_email_summary(config: &Config, body_content: Vec) { let mut wtr = csv::Writer::from_writer(vec![]); for line in body_content { if line.starts_with("### ") { let mut split: Vec<&str> = line.split('|').collect(); if split.len() != 3 { - error!("There was an issue with this line. 3 splits not found: {line}"); + error!("There was an issue with this line: {line}"); continue; } let date: String = match split.pop() { @@ -358,97 +355,33 @@ fn send_email_summary(config: &Config, body_content: Vec, cliargs: &CliA .to_string() .replace("### ", ""); - match wtr.serialize(SummaryRow { - date: date.trim().to_string(), - total_time: time, - task_name, - }) { - Ok(_) => continue, - Err(e) => { - error!("There was an error serializing the csv, aborting: {e}"); - return; - } - }; + wtr.serialize(SummaryRow { date: date.trim().to_string(), total_time: time, task_name }).unwrap(); } } - let data = match String::from_utf8(wtr.into_inner().unwrap()) { - Ok(val) => val, - Err(e) => { - error!("There was an error converting the csv writer to a string, aborting: {e}"); - return; - } - }; + let data = String::from_utf8(wtr.into_inner().unwrap()).unwrap(); debug!("{:#?}", data); - let attachment = Attachment::new("TimeSummary.csv".to_string()) - // The unwrap is on a constant value - .body(data, ContentType::parse("text/csv").unwrap()); - - const HTML: &str = r#" - - - - - - ChronoTrack Export - - -
-
- -
-
-
-

Prepared with care, and sent through the horrors of the interwebs, ChronoTrack presents! (see attached)

-
- - -"#; + let attachment = Attachment::new("TimeSummary.csv".to_string()).body(data, ContentType::parse("text/csv").unwrap()); let email = Message::builder() - .from(match cliargs.from_addr.parse() { - Ok(val) => val, - Err(e) => { - error!("The provided from_email address was unparsable:\n{e}"); - std::process::exit(1); - } - }) - .to(match config.email_addr.parse() { - Ok(val) => val, - Err(e) => { - error!( - "The provided destination email in the configuration file was unparsable:\n{e}" - ); - std::process::exit(1); - } - }) - .subject("ChronoTrack Export") + .from("NoReplay ".parse().unwrap()) + .to("Nicholas Young ".parse().unwrap()) + .subject("Testing email") + .header(ContentType::TEXT_PLAIN) .multipart( MultiPart::mixed() - .multipart( - MultiPart::alternative() - .singlepart( - SinglePart::builder() - .header(ContentType::TEXT_PLAIN) - .body(String::from("This is an automated email from ChronoTrack")), - ) - .singlepart( - SinglePart::builder() - .header(ContentType::TEXT_HTML) - .body(String::from(HTML)), - ), - ) - .singlepart(attachment), - ) - .unwrap(); + .singlepart(SinglePart::plain("Hello World".to_string())) + .singlepart(attachment) + ).unwrap(); + let mailer = SendmailTransport::new(); - + match mailer.send(&email) { Ok(val) => debug!("email sent: {:?}", val), - Err(e) => error!("Couldn't send email {}", e), + Err(e) => error!("Couldn't send email {}", e) }; + }