From c603a6af338b9d3ed3ac3e7682cba11d8d5ba918 Mon Sep 17 00:00:00 2001 From: Nickiel Date: Mon, 11 Sep 2023 15:31:44 -0700 Subject: [PATCH 01/12] added missing reference --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index defc7f4..eb9919f 100644 --- a/flake.nix +++ b/flake.nix @@ -80,7 +80,7 @@ rust-project TODO: write shell script for automatically updating `cargoHash` postFixup = '' wrapProgram $out/bin/time_tracker \ - --prefix PATH : "${lib.makeBinPath [ msmtp ]}" + --prefix PATH : "${nixpkgs.lib.makeBinPath [ msmtp ]}" ''; }); }; From 3c3c30f801649e60dcaa75d0479db209d795fb08 Mon Sep 17 00:00:00 2001 From: Nickiel Date: Mon, 11 Sep 2023 15:32:52 -0700 Subject: [PATCH 02/12] added pkgs to msmtp reference --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index eb9919f..fa50b68 100644 --- a/flake.nix +++ b/flake.nix @@ -80,7 +80,7 @@ rust-project TODO: write shell script for automatically updating `cargoHash` postFixup = '' wrapProgram $out/bin/time_tracker \ - --prefix PATH : "${nixpkgs.lib.makeBinPath [ msmtp ]}" + --prefix PATH : "${nixpkgs.lib.makeBinPath [ pkgs.msmtp ]}" ''; }); }; From 919d7f476928f6651c82ce2dd01693541095c633 Mon Sep 17 00:00:00 2001 From: Nickiel Date: Mon, 11 Sep 2023 15:41:23 -0700 Subject: [PATCH 03/12] added wrapProgram to bulid inputs --- flake.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index fa50b68..04c2c84 100644 --- a/flake.nix +++ b/flake.nix @@ -37,7 +37,8 @@ rust-project TODO: write shell script for automatically updating `cargoHash` rustSettings = with pkgs; { src = ./.; nativeBuildInputs = [ pkg-config ]; - buildInputs = [ openssl hddtemp msmtp ]; + # move makeWrapper to nativeBuildInputs + buildInputs = [ openssl hddtemp msmtp makeWrapper ]; cargoHash = nixpkgs.lib.fakeHash; }; meta = with nixpkgs.lib; { From 24b29f2bbdc074033ad41949fb4907909de11310 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 16:37:16 -0700 Subject: [PATCH 04/12] testing attachments --- time_tracker/src/main.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/time_tracker/src/main.rs b/time_tracker/src/main.rs index 7ca3091..696e4d9 100644 --- a/time_tracker/src/main.rs +++ b/time_tracker/src/main.rs @@ -370,11 +370,13 @@ fn send_email_summary(config: &Config, body_content: Vec) { .to("Nicholas Young ".parse().unwrap()) .subject("Testing email") .header(ContentType::TEXT_PLAIN) - .multipart( - MultiPart::mixed() - .singlepart(SinglePart::plain("Hello World".to_string())) - .singlepart(attachment) - ).unwrap(); + .singlepart(attachment) + .unwrap(); + // .multipart( + // MultiPart::mixed() + // .singlepart(SinglePart::plain("Hello World".to_string())) + // .singlepart(attachment) + // ).unwrap(); let mailer = SendmailTransport::new(); From 02b7127d302fdc10f16174451bda2dacd193955a Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 16:56:59 -0700 Subject: [PATCH 05/12] added html template with attachment --- time_tracker/src/main.rs | 45 +++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/time_tracker/src/main.rs b/time_tracker/src/main.rs index 696e4d9..4ea2a49 100644 --- a/time_tracker/src/main.rs +++ b/time_tracker/src/main.rs @@ -365,18 +365,43 @@ fn send_email_summary(config: &Config, body_content: Vec) { let attachment = Attachment::new("TimeSummary.csv".to_string()).body(data, ContentType::parse("text/csv").unwrap()); + const HTML: &str = r#" + !DOCTYPE html> + + + + + Hello from Lettre! + + +
+

Hello from Lettre!

+

A mailer library for Rust

+
+ +"#; + let email = Message::builder() - .from("NoReplay ".parse().unwrap()) - .to("Nicholas Young ".parse().unwrap()) + .from("NoReply@nickiel.net ".parse().unwrap()) + .to(config.email_addr.parse().unwrap()) .subject("Testing email") - .header(ContentType::TEXT_PLAIN) - .singlepart(attachment) - .unwrap(); - // .multipart( - // MultiPart::mixed() - // .singlepart(SinglePart::plain("Hello World".to_string())) - // .singlepart(attachment) - // ).unwrap(); + .multipart( + MultiPart::mixed() + .multipart( + MultiPart::alternative() + .singlepart( + SinglePart::builder() + .header(ContentType::TEXT_PLAIN) + .body(String::from("Hello world")) + ) + .singlepart( + SinglePart::builder() + .header(ContentType::TEXT_HTML) + .body(String::from(HTML)) + ) + ) + .singlepart(attachment) + ).unwrap(); let mailer = SendmailTransport::new(); From c728c445210ef0ffc5ac9d35d4ef24b0dbefb1e1 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 17:53:21 -0700 Subject: [PATCH 06/12] renamed time_tracker to chrono_track --- Cargo.toml | 2 +- {time_tracker => chrono_track}/Cargo.toml | 0 {time_tracker => chrono_track}/src/main.rs | 86 +++++++++++++++------- 3 files changed, 62 insertions(+), 26 deletions(-) rename {time_tracker => chrono_track}/Cargo.toml (100%) rename {time_tracker => chrono_track}/src/main.rs (82%) diff --git a/Cargo.toml b/Cargo.toml index a19461f..273f454 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] members = [ "status_cloud", - "time_tracker" + "chrono_track" ] diff --git a/time_tracker/Cargo.toml b/chrono_track/Cargo.toml similarity index 100% rename from time_tracker/Cargo.toml rename to chrono_track/Cargo.toml diff --git a/time_tracker/src/main.rs b/chrono_track/src/main.rs similarity index 82% rename from time_tracker/src/main.rs rename to chrono_track/src/main.rs index 4ea2a49..16ce56f 100644 --- a/time_tracker/src/main.rs +++ b/chrono_track/src/main.rs @@ -2,7 +2,7 @@ use chrono::{DateTime, Datelike, Utc}; use chrono_tz::US::Central; use clap::Parser; use lettre::{ - message::{Message, header::ContentType, Attachment, MultiPart, SinglePart}, + message::{header::ContentType, Attachment, Message, 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); + send_email_summary(&cfg, body_content, &args); } Ok(()) @@ -236,6 +236,9 @@ struct CliArgs { #[arg(short, long)] config_file: PathBuf, + #[arg(short, long)] + from_addr: String, + #[arg(short, long)] debug: bool, } @@ -299,14 +302,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) { +fn send_email_summary(config: &Config, body_content: Vec, cliargs: &CliArgs) { 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: {line}"); + error!("There was an issue with this line. 3 splits not found: {line}"); continue; } let date: String = match split.pop() { @@ -355,36 +358,70 @@ fn send_email_summary(config: &Config, body_content: Vec) { .to_string() .replace("### ", ""); - wtr.serialize(SummaryRow { date: date.trim().to_string(), total_time: time, task_name }).unwrap(); + 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; + } + }; } } - let data = String::from_utf8(wtr.into_inner().unwrap()).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; + } + }; debug!("{:#?}", data); - let attachment = Attachment::new("TimeSummary.csv".to_string()).body(data, ContentType::parse("text/csv").unwrap()); + 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#" - !DOCTYPE html> + - Hello from Lettre! + ChronoTrack Export -
-

Hello from Lettre!

-

A mailer library for Rust

+
+
+ +

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

"#; let email = Message::builder() - .from("NoReply@nickiel.net ".parse().unwrap()) - .to(config.email_addr.parse().unwrap()) - .subject("Testing email") + .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") .multipart( MultiPart::mixed() .multipart( @@ -392,23 +429,22 @@ fn send_email_summary(config: &Config, body_content: Vec) { .singlepart( SinglePart::builder() .header(ContentType::TEXT_PLAIN) - .body(String::from("Hello world")) + .body(String::from("This is an automated email from ChronoTrack")), ) .singlepart( SinglePart::builder() .header(ContentType::TEXT_HTML) - .body(String::from(HTML)) - ) - ) - .singlepart(attachment) - ).unwrap(); - + .body(String::from(HTML)), + ), + ) + .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), }; - } From 36a1db441e812c5fe3f9ce97cc6795b5a23705d9 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 18:10:18 -0700 Subject: [PATCH 07/12] renamed chrono_track in flake.nix; updated cargohashes --- Cargo.lock | 34 +++++++++++++-------------- chrono_track/Cargo.toml | 2 +- flake.nix | 51 +++++++++++++++++++++++------------------ 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92f3eff..a639e60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,6 +332,23 @@ 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" @@ -1555,23 +1572,6 @@ 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/chrono_track/Cargo.toml b/chrono_track/Cargo.toml index cac90bc..3b44e57 100644 --- a/chrono_track/Cargo.toml +++ b/chrono_track/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "time_tracker" +name = "chrono_track" version = "0.1.0" edition = "2021" diff --git a/flake.nix b/flake.nix index 04c2c84..867bb8d 100644 --- a/flake.nix +++ b/flake.nix @@ -62,25 +62,26 @@ rust-project TODO: write shell script for automatically updating `cargoHash` pname = "status_cloud"; version = "0.1.0"; buildAndTestSubdir = "status_cloud"; - cargoHash = "sha256-XIonh2SQ8EichcZvHErSydt0qtKGodXE0yKz4BsntA8="; - preBuild = '' - sed -i 's/Command::new("hddtemp")/Command::new("${nixpkgs.lib.escape [ "/" ] "${pkgs.hddtemp}"}")/g' status_cloud/src/main.rs + cargoHash = "sha256-mXcD/92WJLgN2efX/8EiV3rOqUiNOKGC4puS8DvGFOc="; + postFixup = '' + wrapProgram $out/bin/status_cloud \ + --prefix PATH : "${nixpkgs.lib.makeBinPath [ pkgs.hddtemp ]}" ''; meta = meta // { description = "Server status saved to a nextcloud note service."; }; }); - time_tracker = pkgs.rustPlatform.buildRustPackage (rustSettings // { - pname = "time_tracker"; + chrono_track = pkgs.rustPlatform.buildRustPackage (rustSettings // { + pname = "chrono_track"; version = "0.1.0"; - buildAndTestSubdir = "time_tracker"; - cargoHash = "sha256-5Wy2+ef2BriKmvNhllDVh/clAZGV7myDc281ygj05vI="; + buildAndTestSubdir = "chrono_track"; + cargoHash = "sha256-51j5eG2ZBJg2TjbvYSEvvmOM4hhPyNohN+LUmvck88k="; meta = meta // { description = "Using nextcloud notes to track time usage."; }; postFixup = '' - wrapProgram $out/bin/time_tracker \ + wrapProgram $out/bin/chrono_track \ --prefix PATH : "${nixpkgs.lib.makeBinPath [ pkgs.msmtp ]}" ''; }); @@ -138,14 +139,14 @@ rust-project TODO: write shell script for automatically updating `cargoHash` # Time Tracker - options.services.time_tracker = { - enable = lib.mkEnableOption (lib.mdDoc "time tracker service"); + options.services.chrono_track = { + enable = lib.mkEnableOption (lib.mdDoc "chrono track, time tracking service"); package = lib.mkOption { type = lib.types.package; - default = self.packages.${system}.time_tracker; - defaultText = "pkgs.time_tracker"; + default = self.packages.${system}.chrono_track; + defaultText = "pkgs.chrono_track"; description = lib.mdDoc '' - The time_tracker package that should be used + The chrono_track package that should be used ''; }; config_path = lib.mkOption { @@ -154,6 +155,12 @@ 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 '' @@ -162,25 +169,25 @@ rust-project TODO: write shell script for automatically updating `cargoHash` }; }; - config.systemd.services.time_tracker = let - cfg = config.services.time_tracker; - pkg = self.packages.${system}.time_tracker; + config.systemd.services.chrono_track = let + cfg = config.services.chrono_track; + pkg = self.packages.${system}.chrono_track; in lib.mkIf cfg.enable { - description = "Nextcloud Time Tracker"; + description = "Chrono Track"; serviceConfig = { Type = "oneshot"; ExecStart = '' - ${cfg.package}/bin/time_tracker --config-file ${builtins.toString cfg.config_path} + ${cfg.package}/bin/chrono_track --config-file ${builtins.toString cfg.config_path} --from_addr ${cfg.from_address} ''; }; }; - config.systemd.timers.time_tracker = let - cfg = config.services.time_tracker; - pkg = self.packages.${system}.time_tracker; + config.systemd.timers.chrono_track = let + cfg = config.services.chrono_track; + pkg = self.packages.${system}.chrono_track; in lib.mkIf cfg.enable { wantedBy = [ "timers.target" ]; - partOf = [ "time_tracker.service" ]; + partOf = [ "chrono_track.service" ]; timerConfig.OnCalendar = [ "*:0/${builtins.toString cfg.frequency}" ]; }; From 913e030e4fcdfb298715b27fcc6481f338d91210 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 18:19:43 -0700 Subject: [PATCH 08/12] fixed argument for chrono_track --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 867bb8d..3c87fd2 100644 --- a/flake.nix +++ b/flake.nix @@ -177,7 +177,7 @@ rust-project TODO: write shell script for automatically updating `cargoHash` serviceConfig = { Type = "oneshot"; ExecStart = '' - ${cfg.package}/bin/chrono_track --config-file ${builtins.toString cfg.config_path} --from_addr ${cfg.from_address} + ${cfg.package}/bin/chrono_track --config-file ${builtins.toString cfg.config_path} --from-addr ${cfg.from_address} ''; }; }; From 45ea1fbfa96ad8c6e476b45c061b9bd24e5540b0 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 18:35:50 -0700 Subject: [PATCH 09/12] updated email template --- chrono_track/src/main.rs | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/chrono_track/src/main.rs b/chrono_track/src/main.rs index 16ce56f..ade86ba 100644 --- a/chrono_track/src/main.rs +++ b/chrono_track/src/main.rs @@ -387,22 +387,46 @@ fn send_email_summary(config: &Config, body_content: Vec, cliargs: &CliA .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) +
+
+ +

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

-"#; + + "#; let email = Message::builder() .from(match cliargs.from_addr.parse() { From 52d238fba54b94a11f680aff42c681f1bd5e658c Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 19:04:43 -0700 Subject: [PATCH 10/12] updated email template (again) --- chrono_track/src/main.rs | 42 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/chrono_track/src/main.rs b/chrono_track/src/main.rs index ade86ba..e91bc22 100644 --- a/chrono_track/src/main.rs +++ b/chrono_track/src/main.rs @@ -387,46 +387,28 @@ fn send_email_summary(config: &Config, body_content: Vec, cliargs: &CliA .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)

+
+
+

Chrono

+ +

Track!

+
+
+
+

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

- "#; +"#; let email = Message::builder() .from(match cliargs.from_addr.parse() { From f5a1abd8a12754103cb2dff8eff51b3af08f3f0d Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 19:19:14 -0700 Subject: [PATCH 11/12] removed header text in template --- chrono_track/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chrono_track/src/main.rs b/chrono_track/src/main.rs index e91bc22..be45550 100644 --- a/chrono_track/src/main.rs +++ b/chrono_track/src/main.rs @@ -396,7 +396,7 @@ fn send_email_summary(config: &Config, body_content: Vec, cliargs: &CliA
-
+

Chrono

From 0b5175f90a9679ba8402a40091c52d5ef0a79f08 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Mon, 11 Sep 2023 19:26:45 -0700 Subject: [PATCH 12/12] removed header text --- chrono_track/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/chrono_track/src/main.rs b/chrono_track/src/main.rs index be45550..5bb244b 100644 --- a/chrono_track/src/main.rs +++ b/chrono_track/src/main.rs @@ -397,10 +397,8 @@ fn send_email_summary(config: &Config, body_content: Vec, cliargs: &CliA
-

Chrono

-

Track!