diff --git a/README.org b/README.org new file mode 100644 index 0000000..9320f6b --- /dev/null +++ b/README.org @@ -0,0 +1,343 @@ +#+title: Pluralsync (Codename pluralshit) +#+author: Jvnko + +#+seq_todo: Backlog LowPriority HighPriority InProgress | Finished + +* Table of contents :toc_4: +- [[#about][About]] +- [[#configuration][Configuration]] +- [[#code][Code]] + - [[#cargotoml][Cargo.toml]] + - [[#mainrs][Main.rs]] + - [[#imports][Imports]] + - [[#constants][Constants]] + - [[#structs][Structs]] + - [[#main][Main]] + - [[#functions][Functions]] + - [[#main-commands][Main commands]] + - [[#pluralkit][Pluralkit]] + - [[#simplyplural][Simplyplural]] + - [[#utilities][Utilities]] + - [[#http-request-handler][Http Request handler]] +- [[#organization][Organization]] + - [[#tasks][Tasks]] + - [[#milestone-10-1119][Milestone 1.0]] + - [[#main-functions-1911][Main functions]] + - [[#commands-00100][Commands]] + - [[#utils-020][Utils]] + - [[#kanban][Kanban]] + +* About +* Configuration +#+begin_src json :tangle config.example.json +{ + "pk_key": "// Pluralkit token", + "sp_key": "// Simplplural token" +} +#+end_src + +* Code +** Cargo.toml +#+begin_src toml :tangle Cargo.toml +[package] +name = "pluralshit" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dirs = "5.0.1" +serde = { version = "1.0.192", features = ["derive"] } +serde_json = "1.0" +reqwest = "0.11.22" +rofi = "0.3.0" +tokio = { version = "1", features = ["full"] } +#+end_src + +** Main.rs +*** Imports +#+begin_src rust :tangle src/main.rs :comments link +use std::path::Path; +use std::{fs, collections::HashMap}; +use reqwest::header::{USER_AGENT, AUTHORIZATION}; +use serde::{Serialize, Deserialize}; +use serde_json::Value; +use dirs; +#+end_src + +*** Constants +#+begin_src rust :tangle src/main.rs :comments link +const PK_URL: &str = "https://api.pluralkit.me/v2"; +const SP_URL: &str = "https://api.apparyllis.com/v1"; +#+end_src + +*** Structs +#+begin_src rust :tangle src/main.rs :comments link +#[derive(Debug)] +#[derive(Serialize)] +struct System { + pk_userid: String, + sp_userid: String, + members: Vec, +} + +#[derive(Debug)] +#[derive(Serialize)] +#[derive(Clone)] +struct Member { + pk_id: String, + sp_id: String, + name: String, + alias: String +} + +#+end_src + +*** Main +#+begin_src rust :tangle src/main.rs :comments link +fn main() { + if std::env::args().len() > 1 { + let command = std::env::args().nth(1).expect("No command given"); + let config_path: String; + match dirs::config_dir() { + Some(x) => { + config_path = format!("{}/pluralshit", x.display()); + match command.as_str() { + "sync" => sync(config_path), + "set" => { + if std::env::args().len() > 2 { + set_member(config_path, std::env::args().nth(2).expect("No member given")); + } else { + set_empty(config_path); + } + }, + &_ => println!("Invalid command"), + } + }, + None => println!("Something went wrong") + } + } else { + println!("No arguments given"); + } +} +#+end_src + +*** Functions +**** Main commands +#+begin_src rust :tangle src/main.rs :comments link +fn set_member(config_path: String, member: String) { + let config = load_json(format!("{}/config.json", config_path)); + let system = get_system(config_path); + + //for mem in system["members"].as_str().unwrap() { + // TODO + // TODO Hacer que devuelva el json en forma de Vec + // TODO + //} +} + +fn set_empty(config_path: String) { + let config = load_json(format!("{}/config.json", config_path)); + let system = get_system(config_path); +} + +fn sync(config_path: String) { + // Get config + let config = load_json(format!("{}/config.json", config_path)); + let pk_key = &config["pk_key"].as_str().unwrap(); + let sp_key = &config["sp_key"].as_str().unwrap(); + + // Get Pluralkit system id + let pk_sys = pk_get_system(pk_key); + let pk_sysid = pk_sys["id"].as_str().unwrap(); + + // Get Simplyplural user id + let sp_user_id = sp_get_userid(sp_key); + + // Get Simplyplural member ids + let sp_member_ids = sp_get_memberids(sp_key, &sp_user_id); + + // get members + let pk_members = pk_get_members(pk_key, pk_sysid); + let mut members: Vec = Vec::new(); + for member in pk_members { + let mut m = Member { + pk_id: member["id"].as_str().unwrap().to_string(), + sp_id: String::new(), + name: member["name"].as_str().unwrap().to_string(), + alias: String::new() + }; + + if member["display_name"].as_str() != None { + m.alias = member["display_name"].as_str().unwrap().to_string(); + } else { + m.alias = String::from(&m.name); + } + + m.sp_id = get_sp_id(&m, &sp_member_ids); + + members.push(m); + } + + let sys = System { + pk_userid: pk_sysid.to_string(), + sp_userid: sp_user_id, + members: members.clone(), + }; + + let json = serde_json::to_string(&sys); + let _ = fs::write(format!("{}/system.json", config_path), &json.unwrap()); + +} +#+end_src + +**** Pluralkit +#+begin_src rust :tangle src/main.rs :comments link +fn pk_get_system(key: &str) -> Value { + let url = format!("{}/systems/@me", PK_URL); + + let res = http_request(url,key); + return serde_json::from_str(&res.unwrap()).unwrap(); +} + +fn pk_get_members(key: &str, sysid: &str) -> Vec { + let url = format!("{}/systems/{}/members", PK_URL, sysid); + + let res = http_request(url,key); + let datas: Vec = serde_json::from_str(&res.unwrap()).unwrap(); + + return datas; +} +#+end_src + +**** Simplyplural +#+begin_src rust :tangle src/main.rs :comments link +fn sp_get_userid(key: &str) -> String { + let url = format!("{}/me", SP_URL); + + let res = http_request(url,key); + let json_res : Value = serde_json::from_str(&res.unwrap()).unwrap(); + return json_res["id"].as_str().unwrap().to_string(); +} + +fn sp_get_memberids(key: &str, system_id: &str) -> HashMap { + let url = format!("{}/members/{}", SP_URL, system_id); + + let res = http_request(url,key); + let datas: Vec = serde_json::from_str(&res.unwrap()).unwrap(); + + let mut sp_memberdata: HashMap = HashMap::new(); + for data in datas { + sp_memberdata.insert(String::from(data["content"]["name"].as_str().unwrap()), String::from(data["id"].as_str().unwrap())); + } + + return sp_memberdata; +} + +fn get_sp_id(mem: &Member, ids: &HashMap) -> String { + + let mut member_id = String::new(); + + for (mn, mid) in ids { + if &mem.name == mn || &mem.alias == mn { + member_id = String::from(mid); + } + } + + return member_id; +} +#+end_src + +**** Utilities +#+begin_src rust :tangle src/main.rs :comments link +fn load_json(path: String) -> Value { + if Path::new(&path).exists() { + let config_data = fs::read_to_string(path).expect("File not found"); + return serde_json::from_str(&config_data).unwrap(); + } else { + println!("Config file in {path} not found"); + return Value::Null; + } +} + +// TODO +// TODO fn get_config() -> Value { +// TODO load_json +// TODO if Value:null - > mkconfig dir - > make empty config.json +// TODO else -> return +// TODO } +// TODO + +fn get_system(config_path: String) -> Value{ + let path = format!("{}/system.json", config_path); + + // TODO + // TODO load_json + // TODO if Value:null - > sync - > load_json + // TODO + + if Path::new(&path).exists() { + let config_data = fs::read_to_string(path).expect("File not found"); + return serde_json::from_str(&config_data).unwrap(); + } else { + println!("System file in {path} not found. Syncing"); + sync(config_path); + let config_data = fs::read_to_string(path).expect("File not found"); + return serde_json::from_str(&config_data).unwrap(); + } +} +#+end_src + +**** Http Request handler +#+begin_src rust :tangle src/main.rs :comments link +#[tokio::main] +async fn http_request(url: String, key: &str) -> Result> { + let client = reqwest::Client::new(); + let res = client + .get(url) + .header(USER_AGENT, "Pluralsync") + .header(AUTHORIZATION, key) + .send() + .await? + .text() + .await?; + Ok(res) +} +#+end_src + +* Organization +** Tasks +:PROPERTIES: +:COOKIE_DATA: recursive +:END: +*** Milestone 1.0 [1/11][9%] +**** Main functions [1/9][11%] +***** Finished Add `sync` command +***** InProgress Add `set` command [0/2] +****** HighPriority [SET] Add empty +****** InProgress [SET] Add set +***** HighPriority Add `get` command +***** LowPriority Add `Add` command [0/2] +****** LowPriority [ADD] Add empty +****** LowPriority [ADD] Add set +***** LowPriority Add `setgroup` command +**** Commands [0/0][100%] +**** Utils [0/2][0%] +***** Json loading [0/2] +****** HighPriority Add new function to get the config create empty in path if not exists +****** HighPriority `Get system` if Value::Null sync and load json +** Kanban +| Backlog | LowPriority | HighPriority | InProgress | Finished | +|---------+-------------------------+--------------------------------+-------------------------+--------------------| +| | [[/home/alicia/git/pluralshit/README.org::Add `Add` command \[0/2\]][Add `Add` command {0/2}]] | [[/home/alicia/git/pluralshit/README.org::\[SET\] Add empty][{SET} Add empty]] | [[/home/alicia/git/pluralshit/README.org::Add `set` command \[0/2\]][Add `set` command {0/2}]] | [[/home/alicia/git/pluralshit/README.org::Add `sync` command][Add `sync` command]] | +| | [[/home/alicia/git/pluralshit/README.org::\[ADD\] Add empty][{ADD} Add empty]] | [[/home/alicia/git/pluralshit/README.org::Add `get` command][Add `get` command]] | [[/home/alicia/git/pluralshit/README.org::\[SET\] Add set][{SET} Add set]] | | +| | [[/home/alicia/git/pluralshit/README.org::\[ADD\] Add set][{ADD} Add set]] | [[/home/alicia/git/pluralshit/README.org::Add new function to get the config create empty in path if not exists][Add new function to get the co]] | | | +| | [[/home/alicia/git/pluralshit/README.org::Add `setgroup` command][Add `setgroup` command]] | [[/home/alicia/git/pluralshit/README.org::`Get system` if Value::Null sync and load json][`Get system` if Value::Null sy]] | | | +| | | | | | +| | | | | | +| | | | | | +| | | | | | +| | | | | | +| | | | | | +#+TBLFM: @1='(kanban-headers $#)::@2$1..@>$>='(kanban-zero @# $# nil (list (buffer-file-name))) diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..7fde0d2 --- /dev/null +++ b/config.example.json @@ -0,0 +1,4 @@ +{ + "pk_key": "// Pluralkit token", + "sp_key": "// Simplplural token" +} diff --git a/src/main.rs b/src/main.rs index 98073fc..1e3b99b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,18 @@ +// [[file:../README.org::*Imports][Imports:1]] use std::path::Path; use std::{fs, collections::HashMap}; use reqwest::header::{USER_AGENT, AUTHORIZATION}; use serde::{Serialize, Deserialize}; use serde_json::Value; use dirs; +// Imports:1 ends here +// [[file:../README.org::*Constants][Constants:1]] const PK_URL: &str = "https://api.pluralkit.me/v2"; const SP_URL: &str = "https://api.apparyllis.com/v1"; +// Constants:1 ends here +// [[file:../README.org::*Structs][Structs:1]] #[derive(Debug)] #[derive(Serialize)] struct System { @@ -25,7 +30,9 @@ struct Member { name: String, alias: String } +// Structs:1 ends here +// [[file:../README.org::*Main][Main:1]] fn main() { if std::env::args().len() > 1 { let command = std::env::args().nth(1).expect("No command given"); @@ -42,9 +49,6 @@ fn main() { set_empty(config_path); } }, - // TODO "get" => get() - // TODO "add op$2" => add() or add($2) - // TODO "setgroup" => setgroup() &_ => println!("Invalid command"), } }, @@ -54,7 +58,9 @@ fn main() { println!("No arguments given"); } } +// Main:1 ends here +// [[file:../README.org::*Main commands][Main commands:1]] fn set_member(config_path: String, member: String) { let config = load_json(format!("{}/config.json", config_path)); let system = get_system(config_path); @@ -119,8 +125,64 @@ fn sync(config_path: String) { let _ = fs::write(format!("{}/system.json", config_path), &json.unwrap()); } +// Main commands:1 ends here -// Utilities +// [[file:../README.org::*Pluralkit][Pluralkit:1]] +fn pk_get_system(key: &str) -> Value { + let url = format!("{}/systems/@me", PK_URL); + + let res = http_request(url,key); + return serde_json::from_str(&res.unwrap()).unwrap(); +} + +fn pk_get_members(key: &str, sysid: &str) -> Vec { + let url = format!("{}/systems/{}/members", PK_URL, sysid); + + let res = http_request(url,key); + let datas: Vec = serde_json::from_str(&res.unwrap()).unwrap(); + + return datas; +} +// Pluralkit:1 ends here + +// [[file:../README.org::*Simplyplural][Simplyplural:1]] +fn sp_get_userid(key: &str) -> String { + let url = format!("{}/me", SP_URL); + + let res = http_request(url,key); + let json_res : Value = serde_json::from_str(&res.unwrap()).unwrap(); + return json_res["id"].as_str().unwrap().to_string(); +} + +fn sp_get_memberids(key: &str, system_id: &str) -> HashMap { + let url = format!("{}/members/{}", SP_URL, system_id); + + let res = http_request(url,key); + let datas: Vec = serde_json::from_str(&res.unwrap()).unwrap(); + + let mut sp_memberdata: HashMap = HashMap::new(); + for data in datas { + sp_memberdata.insert(String::from(data["content"]["name"].as_str().unwrap()), String::from(data["id"].as_str().unwrap())); + } + + return sp_memberdata; +} + +fn get_sp_id(mem: &Member, ids: &HashMap) -> String { + + let mut member_id = String::new(); + + for (mn, mid) in ids { + if &mem.name == mn || &mem.alias == mn { + member_id = String::from(mid); + } + } + + return member_id; +} +// Simplyplural:1 ends here + +// [[file:../README.org::*Utilities][Utilities:1]] fn load_json(path: String) -> Value { if Path::new(&path).exists() { let config_data = fs::read_to_string(path).expect("File not found"); @@ -157,61 +219,9 @@ fn get_system(config_path: String) -> Value{ return serde_json::from_str(&config_data).unwrap(); } } +// Utilities:1 ends here -// Simplyplural -fn sp_get_userid(key: &str) -> String { - let url = format!("{}/me", SP_URL); - - let res = http_request(url,key); - let json_res : Value = serde_json::from_str(&res.unwrap()).unwrap(); - return json_res["id"].as_str().unwrap().to_string(); -} - -fn sp_get_memberids(key: &str, system_id: &str) -> HashMap { - let url = format!("{}/members/{}", SP_URL, system_id); - - let res = http_request(url,key); - let datas: Vec = serde_json::from_str(&res.unwrap()).unwrap(); - - let mut sp_memberdata: HashMap = HashMap::new(); - for data in datas { - sp_memberdata.insert(String::from(data["content"]["name"].as_str().unwrap()), String::from(data["id"].as_str().unwrap())); - } - - return sp_memberdata; -} - -fn get_sp_id(mem: &Member, ids: &HashMap) -> String { - - let mut member_id = String::new(); - - for (mn, mid) in ids { - if &mem.name == mn || &mem.alias == mn { - member_id = String::from(mid); - } - } - - return member_id; -} - -// Pluralkit -fn pk_get_system(key: &str) -> Value { - let url = format!("{}/systems/@me", PK_URL); - - let res = http_request(url,key); - return serde_json::from_str(&res.unwrap()).unwrap(); -} - -fn pk_get_members(key: &str, sysid: &str) -> Vec { - let url = format!("{}/systems/{}/members", PK_URL, sysid); - - let res = http_request(url,key); - let datas: Vec = serde_json::from_str(&res.unwrap()).unwrap(); - - return datas; -} - -// HTTP Request +// [[file:../README.org::*Http Request handler][Http Request handler:1]] #[tokio::main] async fn http_request(url: String, key: &str) -> Result> { let client = reqwest::Client::new(); @@ -225,3 +235,4 @@ async fn http_request(url: String, key: &str) -> Result