diff --git a/.arcconfig b/.arcconfig --- a/.arcconfig +++ b/.arcconfig @@ -1,4 +1,4 @@ { "phabricator.uri": "https://devcentral.nasqueron.org/", "repository.callsign": "NPUSH" -} \ No newline at end of file +} diff --git a/Cargo.toml b/Cargo.toml --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,10 @@ [dependencies] clap = { version = "4.1.1", features = ["derive"] } +reqwest = { version = "0.11.14", features = ["json"] } serde = { version = "1.0.152", features = ["derive"] } serde_json = "1.0.91" -reqwest = { version = "0.11.14", features = ["json"] } -openssl-sys = "0.9.80" +serde_yaml = "0.9.19" +tokio = { version = "1.12.0", features = ["full"] } openssl = "0.10.45" -tokio = { version = "1.12.0", features = ["full"] } \ No newline at end of file +openssl-sys = "0.9.80" diff --git a/settings/notification-push.yml b/settings/notification-push.yml new file mode 100644 --- /dev/null +++ b/settings/notification-push.yml @@ -0,0 +1,10 @@ +# api_endpoint: https://notifications.integration.nasqueron.org/ +api_endpoint: https://notifications.nasqueron.org/ + +default_payload: + service: "" + project: "Nasqueron" + group: "" + type: "" + text: "" + link: "" diff --git a/src/clap_args.rs b/src/clap_args.rs deleted file mode 100644 --- a/src/clap_args.rs +++ /dev/null @@ -1,24 +0,0 @@ -use clap::Parser; - -#[derive(Debug, Parser)] -#[clap(author, version, about)] -pub struct ClapArgs { - /// The notification's source service (e.g. GitHub, Phabricator, Jenkins) - pub clap_service: String, - - /// The notification's target project (e.g. Wikimedia, Nasqueron, Wolfplex) - pub clap_project: String, - - /// The notification's target group (e.g. Tasacora, Operations) - pub clap_group: String, - - /// The notification's type (e.g. "commits", "task") - pub clap_type: String, - - /// The notification's text - pub clap_text: Option<String>, - - /// The notification's URL, to be used as the main link for widgets - pub clap_link: Option<String>, - -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs --- a/src/main.rs +++ b/src/main.rs @@ -1,48 +1,64 @@ -mod clap_args; +mod notification; + +use notification::Notification; -use clap_args::ClapArgs; use clap::Parser; -use serde::{Serialize}; use reqwest; +use serde::{Deserialize, Serialize}; +use serde_yaml::{self}; + use std::process::exit; +use std::path::Path; -#[derive(Serialize)] -struct Notification { - service: String, - project: String, - group: String, - #[serde(rename = "type")] - _type: String, - text: String, - link: String, +#[derive(Debug, Serialize, Deserialize)] +struct Config { + default_payload: Notification, + api_endpoint: String, } #[tokio::main] async fn main() { - // Environment variables - let api_endpoint = "https://eo4a3aeazbbb14z.m.pipedream.net"; + // Checks and set yaml file location + let locations = vec![ + "settings/notification-push.yml", + "$HOME/.config/notification-push.yml", + "/usr/local/etc/notification-push.yml", + "/etc/notification-push.yml", + ]; + let mut yaml_file = ""; + + for location in locations { + if Path::new(location).exists() { + yaml_file = location; + break; + } + } + + // Open/read yaml file + let f = std::fs::File::open(yaml_file).expect("Could not open file."); + let yaml_config: Config = serde_yaml::from_reader(f).expect("Could not read values."); // ======================================================== // 1. Validating user's arguments while parsing (clap) - let _args:ClapArgs = ClapArgs::parse(); + let _args: Notification = Notification::parse(); // 2. Converting user's arguments to ready-to-post JSON (serde) let populated_notification = Notification { - service: _args.clap_service, - project: _args.clap_project, - group: _args.clap_group, - _type: _args.clap_type, - text: _args.clap_text.unwrap_or("".to_string()), - link: _args.clap_link.unwrap_or("".to_string()), + service: _args.service.or(yaml_config.default_payload.service).or_else(|| arg_panic("service")), + project: _args.project.or(yaml_config.default_payload.project).or_else(|| arg_panic("project")), + group: _args.group.or(yaml_config.default_payload.group).or_else(|| arg_panic("group")), + _type: _args._type.or(yaml_config.default_payload._type).or_else(|| arg_panic("type")), + text: _args.text.or(yaml_config.default_payload.text), + link: _args.link.or(yaml_config.default_payload.link), }; // 3. Sending JSON as HTTP request (reqwest) let client = reqwest::Client::new(); - let res = client.post(api_endpoint) + let res = client.post(&yaml_config.api_endpoint) .json(&populated_notification) .send() - .await; + .await; if let Err(error) = res { eprintln!("{}", &error); @@ -56,4 +72,9 @@ exit(2); // Let's use another code so a script can know at what step it failed. } -} \ No newline at end of file +} + +fn arg_panic(arg: &str) -> Option<String> { + eprintln!("You must provide {arg}, either with --{arg} or in notification-push.yml"); + exit(4); +} diff --git a/src/notification.rs b/src/notification.rs new file mode 100644 --- /dev/null +++ b/src/notification.rs @@ -0,0 +1,31 @@ +use clap::Parser; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Parser, Serialize, Deserialize)] +#[clap(author, version, about)] +pub struct Notification { + /// The notification's source service (e.g. GitHub, Phabricator, Jenkins) + #[arg(long)] + pub service: Option<String>, + + /// The notification's target project (e.g. Wikimedia, Nasqueron, Wolfplex) + #[arg(long)] + pub project: Option<String>, + + /// The notification's target group (e.g. Tasacora, Operations) + #[arg(long)] + pub group: Option<String>, + + /// The notification's type (e.g. "commits", "task") + #[arg(long, name = "type")] + #[serde(rename = "type")] + pub _type: Option<String>, + + /// The notification's text + #[arg(long)] + pub text: Option<String>, + + /// The notification's URL, to be used as the main link for widgets + #[arg(long)] + pub link: Option<String>, +}