diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..412cbef --- /dev/null +++ b/.envrc @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# ^ make editor happy + +# +# Use https://direnv.net/ to automatically load the dev shell. +# + +if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4=" +fi + +watch_file nix/** +watch_file -- **/*.nix +# Adding files to git includes them in a flake +# But it is also a bit much reloading. +# watch_file .git/index .git/HEAD +use flake . --show-trace diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e5a49d8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'pluralsync'", + "cargo": { + "args": [ + "build", + "--bin=pluralsync", + "--package=pluralsync" + ], + "filter": { + "name": "pluralsync", + "kind": "bin" + } + }, + "args": ["add","aki"], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'pluralsync'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=pluralsync", + "--package=pluralsync" + ], + "filter": { + "name": "pluralsync", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6533d4f..159f8e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -870,7 +870,7 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "pluralsync" -version = "1.2.0" +version = "1.4.0" dependencies = [ "clap", "color-eyre", diff --git a/Cargo.toml b/Cargo.toml index 68f8466..e27ccc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pluralsync" -version = "1.2.0" +version = "1.4.0" edition = "2021" authors = ["jvnkyard@ak.lavenderfield.xyz"] @@ -18,7 +18,7 @@ crossterm = "0.27.0" color-eyre = "0.6.2" [features] -default = ["avatar"] +default = ["fedi","discord"]#,"jlog"] avatar = [] discord = ["avatar"] fedi = ["avatar"] diff --git a/README.org b/README.org index 60421ab..11d6151 100644 --- a/README.org +++ b/README.org @@ -36,9 +36,9 @@ On the first run, if it does not exist, PluralSync will create a configuration d Just fill it with PluralKit and SimplyPlural tokens associated to your account. ** Commands -- *Sync* - Once the configuration is ready, you can start by calling the =sync= command, which will get the list of members of the system and place their data in a =system.json= file inside the configuration folder. Running commands like =set= or =add= without a present =system.json= will automatically fetch the data for you. +- *Update* - Once the configuration is ready, you can start by calling the =update= command, which will get the list of members of the system and place their data in a =system.json= file inside the configuration folder. Running commands like =set= or =add= without a present =system.json= will automatically fetch the data for you. -*Remember to sync whenever you change the information of the system! i.e. adding a new member, rename...* +*Remember to update whenever you change the information of the system! i.e. adding a new member, rename...* - *Set* - Takes multiple arguments. Sets the current front to the selected list of members. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..ebd2742 --- /dev/null +++ b/flake.lock @@ -0,0 +1,130 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1712163089, + "narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "fd281bd6b7d3e32ddfa399853946f782553163b5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1706487304, + "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1712196778, + "narHash": "sha256-SOiwCr2HtmYpw8OvQQVRPtiCBWwndbIoPqtsamZK3J8=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "20e7895d1873cc64c14a9f024a8e04f5824bed28", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5412b80 --- /dev/null +++ b/flake.nix @@ -0,0 +1,43 @@ +{ + description = "rust"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + rust-overlay.url = "github:oxalica/rust-overlay"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = { nixpkgs, rust-overlay, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + bi = with pkgs; [ + openssl + pkg-config + rust-bin.nightly.latest.default + ]; + in + with pkgs; + { + packages.default = rustPlatform.buildRustPackage { + pname = "pluralsync"; + version = "1.4.0"; + src = ./.; + cargoLock.lockFile = ./Cargo.lock; + checkType = "release"; + nativeBuildInputs = [ pkgs.pkg-config ]; + buildNoDefaultFeatures = true; + buildFeatures = ["discord" "fedi"]; + buildInputs = bi; + }; + devShells.default = mkShell { + name = "rust"; + buildInputs = bi; + shellHook = '' + + ''; + }; + } + ); +} diff --git a/result b/result new file mode 120000 index 0000000..41003ea --- /dev/null +++ b/result @@ -0,0 +1 @@ +/nix/store/5h8kyc2m1gs0lyscwrsbvijp9l7b2pym-pluralsync-1.4.0 \ No newline at end of file diff --git a/src/api.rs b/src/api.rs index 14a1c62..4f7c3a0 100644 --- a/src/api.rs +++ b/src/api.rs @@ -163,8 +163,8 @@ pub mod sp { let datas: Vec = serde_json::from_str(&result)?; for data in datas { - let sp_f_id = &data["id"].to_string(); - let sp_id = &data["content"]["member"].to_string(); + let sp_f_id = &data["id"].as_str().unwrap().to_string(); + let sp_id = &data["content"]["member"].as_str().unwrap().to_string(); if sp_id.to_string() == to_id.sp_id { return Ok(sp_f_id.to_string()); } @@ -256,12 +256,40 @@ pub mod sp { } } +#[cfg(feature = "fedi")] +pub mod fedi { + + use std::fs; + + use reqwest::header::{USER_AGENT, AUTHORIZATION}; + use reqwest::multipart::{Part, Form}; + + use color_eyre::eyre::{eyre, Result}; + + use crate::configdata::Config; + use crate::api::request::http_request; + + pub fn fedi_request(config: &Config) -> Result<()> { + let client = reqwest::Client::new(); + let form = Form::new().part("avatar", Part::bytes(fs::read(config.avatar_module.avatar_output_path.clone()).unwrap()).file_name("face.png").mime_str("image/png").unwrap()); + let rb = client + .patch(config.fedi_module.instance.clone() + "/api/v1/accounts/update_credentials") + .multipart(form) + .header(USER_AGENT, "Pluralsync") + .header(AUTHORIZATION, format!("Bearer {}", &config.fedi_module.token).as_str()); + + println!("Fedi module finished"); + match http_request(rb) { + Ok(_) => Ok(()), + Err(e) => Err(eyre!("{}", e.to_string())), + } + } +} + pub mod request { use reqwest::RequestBuilder; use reqwest::header::{USER_AGENT, AUTHORIZATION}; - #[cfg(feature = "fedi")] - use reqwest::multipart::{Part, Form}; use color_eyre::eyre::Result; diff --git a/src/app.rs b/src/app.rs index e6e37a0..1522942 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,6 +6,7 @@ use color_eyre::eyre::{eyre, Result}; pub enum CurrentScreen { Dash, + Member, Configuration, Exit, } @@ -94,22 +95,24 @@ impl App { fn add(&mut self, to_front: Vec) -> Result<()> { - let aux_fronters: Fronters = Fronters::get(self, ForceFrom::None)?; + self.get(ForceFrom::None)?; + if let Some(aux_fronters) = &self.fronters { + let mut addfronters: Vec = Vec::new(); + addfronters.append(&mut aux_fronters.pk.clone()); + addfronters.append(&mut to_front.clone()); - let mut addfronters: Vec = Vec::new(); - addfronters.append(&mut aux_fronters.pk.clone()); - addfronters.append(&mut to_front.clone()); + self.fronters = Some(Fronters::set(self, addfronters)?); - self.fronters = Some(Fronters::set(self, addfronters)?); - - Ok(()) + return Ok(()); + } + Err(eyre!("Could not fetch the current front")) } pub fn memberlist(&self) -> Result<()> { if let Some(sys) = &self.sys { for member in &sys.members { - println!("{} / {}", member.name, member.aliases.join(" | ")); + println!("{} [ {} ]", member.name, member.aliases.join(" | ")); } } @@ -135,15 +138,15 @@ impl App { if to_front.len() == tf_members.len() { if !append { - self.set(to_front)?; + self.set(to_front.clone())?; } else { - self.add(to_front)?; + self.add(to_front.clone())?; } } else { println!("One or more members were not found. Known members:\n--------------------------"); self.memberlist()?; println!("--------------------------\nIf a member is missing from the system try running \"pluralsync update\" to refresh the local database"); - return Err(eyre!("Missing member")); + return Ok(()); } #[cfg(feature = "jlog")] { diff --git a/src/clap_ps.rs b/src/clap_ps.rs index 6eb5fcd..6415145 100644 --- a/src/clap_ps.rs +++ b/src/clap_ps.rs @@ -4,7 +4,7 @@ use clap::{Parser, Subcommand, ValueEnum}; #[clap(arg_required_else_help = true, verbatim_doc_comment, author)] #[command(name = "PluralSync")] #[command(author = "jvnkyard ")] -#[command(version = "1.2")] +#[command(version = "1.4")] #[command( help_template = "{name} Version {version} \n {author} \n {about-section} \n {usage-heading} {usage} \n \n {all-args} {tab}" )] @@ -67,6 +67,7 @@ pub enum Commands { fedi: bool, }, /// Displays a list with all members + #[clap(aliases = &["memberlist", "list"])] Members, } diff --git a/src/systemdata.rs b/src/systemdata.rs index 34eaae5..f2c7f15 100644 --- a/src/systemdata.rs +++ b/src/systemdata.rs @@ -96,7 +96,7 @@ impl System { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Fronters { pub sp: Vec, pub pk: Vec, @@ -120,9 +120,12 @@ impl Fronters { ForceFrom::SP => { fronters.pk = fronters.sp.clone(); } - _ => { + ForceFrom::PK => { fronters.sp = fronters.pk.clone(); } + ForceFrom::None => { + + } } } diff --git a/src/utils.rs b/src/utils.rs index 645054b..f1b1830 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -17,6 +17,9 @@ use { color_eyre::eyre::eyre, }; +#[cfg(feature = "fedi")] +use crate::api::fedi::*; + pub fn load_json(file_path: &str) -> Result { let file_data = fs::read_to_string(&file_path)?; @@ -28,18 +31,18 @@ pub fn load_json(file_path: &str) -> Result { #[cfg(feature = "avatar")] pub fn update_avatars(app: &mut App, #[cfg(feature = "discord")] discord: bool, #[cfg(feature = "fedi")] fedi: bool) -> Result<()>{ - if let Some(cfg) = app.cfg.clone() { + if let Some(mut cfg) = app.cfg.clone() { let names = &app.get_front(ForceFrom::None)?; // TODO CHANGE INTO USING LOCAL FRONT match avatar_module(&cfg, &names) { Ok(_) => { #[cfg(feature = "discord")] { - config.disc_module.enabled |= discord; - discord_module(&config); + cfg.disc_module.enabled |= discord; + discord_module(&cfg)?; } #[cfg(feature = "fedi")] { - config.fedi_module.enabled |= fedi; - fedi_module(&config); + cfg.fedi_module.enabled |= fedi; + fedi_module(&cfg)?; } }, Err(e) => println!("{}", e), @@ -50,7 +53,7 @@ pub fn update_avatars(app: &mut App, #[cfg(feature = "discord")] discord: bool, } #[cfg(feature = "avatar")] -fn avatar_module(config: &Config, names: &Vec) -> Result<(), &'static str>{ +fn avatar_module(config: &Config, names: &Vec) -> Result<()>{ if config.avatar_module.enabled { let mut whitelisted_names: Vec = names.iter().map(|i| i.to_lowercase()).collect(); let blacklist: Vec = config.avatar_module.blacklist.iter().map(|i| i.to_lowercase()).collect(); @@ -78,43 +81,33 @@ fn avatar_module(config: &Config, names: &Vec) -> Result<(), &'static st println!("Avatar module finished"); Ok(()) } else { - Err("Avatar module failed") + Err(eyre!("Avatar module failed")) } } else { - Err("Avatar mode disabled") + Err(eyre!("Avatar mode disabled")) } } #[cfg(feature = "discord")] -fn discord_module(config: &Config) { +fn discord_module(config: &Config) -> Result<()> { if config.disc_module.enabled { if cfg!(target_os = "windows") { - let mut c = Command::new("cmd").args(["/C", format!("{} {}", &config.disc_module.python_path, &config.disc_module.script_path).as_str()]).spawn().expect("Discord module error"); - let _ = c.wait().expect("Error"); + let mut c = Command::new("cmd").args(["/C", format!("{} {}", &config.disc_module.python_path, &config.disc_module.script_path).as_str()]).spawn()?; + let _ = c.wait()?; } else { - let mut c = Command::new("sh").arg("-c").arg(format!("{} {}", &config.disc_module.python_path, &config.disc_module.script_path)).spawn().expect("Discord module error"); - let _ = c.wait().expect("Error"); + let mut c = Command::new("sh").arg("-c").arg(format!("{} {}", &config.disc_module.python_path, &config.disc_module.script_path)).spawn()?; + let _ = c.wait()?; } } + Ok(()) } #[cfg(feature = "fedi")] -fn fedi_module(config: &Config) { +fn fedi_module(config: &Config) -> Result<()> { if config.fedi_module.enabled { - - let client = reqwest::Client::new(); - let form = Form::new().part("avatar", Part::bytes(fs::read(config.avatar_module.avatar_output_path.clone()).unwrap()).file_name("face.png").mime_str("image/png").unwrap()); - let rb = client - .patch(config.fedi_module.instance.clone() + "/api/v1/accounts/update_credentials") - .multipart(form) - .header(USER_AGENT, "Pluralsync") - .header(AUTHORIZATION, format!("Bearer {}", &config.fedi_module.token).as_str()); - - println!("Fedi module finished"); - match http_request(rb) { - Ok(_) => (), - Err(e) => println!("{}", e.to_string()), - } + fedi_request(config)?; } + + Ok(()) }