diff --git a/Cargo.lock b/Cargo.lock index 5043242..b1fcf5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,21 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.4" @@ -65,6 +80,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + [[package]] name = "autocfg" version = "1.1.0" @@ -131,6 +152,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", +] + [[package]] name = "clap" version = "4.4.6" @@ -410,6 +445,29 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "idna" version = "0.4.0" @@ -535,6 +593,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -545,6 +612,12 @@ dependencies = [ "libc", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + [[package]] name = "object" version = "0.32.1" @@ -622,7 +695,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", "windows-targets", ] @@ -631,10 +704,15 @@ dependencies = [ name = "pastebin-cli" version = "0.1.0" dependencies = [ + "anyhow", + "chrono", "clap", "home", + "quick-xml", "reqwest", "rpassword", + "serde", + "termion", "tokio", ] @@ -671,6 +749,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quote" version = "1.0.33" @@ -680,6 +768,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -689,6 +786,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_termios" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" +dependencies = [ + "redox_syscall 0.2.16", +] + [[package]] name = "reqwest" version = "0.11.22" @@ -944,11 +1050,23 @@ checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys", ] +[[package]] +name = "termion" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659c1f379f3408c7e5e84c7d0da6d93404e3800b6b9d063ba24436419302ec90" +dependencies = [ + "libc", + "numtoa", + "redox_syscall 0.2.16", + "redox_termios", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1206,6 +1324,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index e09be79..f9241f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.75" +chrono = "0.4.31" clap = { version = "4.4.6", features = ["derive"] } home = "0.5.5" +quick-xml = { version = "0.31.0", features = ["serde", "serialize"] } reqwest = { version = "0.11.22", features = ["json"] } rpassword = "7.2.0" +serde = { version = "1.0.189", features = ["serde_derive", "derive"] } +termion = "2.0.1" tokio = { version = "1.33.0", features = ["full"] } diff --git a/src/main.rs b/src/main.rs index 2b462d2..821dd8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use chrono::prelude::*; +use chrono::DateTime; use clap::{Parser, Subcommand}; use std::fs; use std::path::PathBuf; @@ -16,12 +18,7 @@ struct Cli { enum Action { Create { file_path: std::path::PathBuf }, Delete { paste_id: String }, - /* - Edit { - paste_id: String, - file_path: std::path::PathBuf, - }, - */ + List { max_results: Option }, } #[tokio::main] @@ -34,6 +31,7 @@ async fn main() { match args.action { Action::Create { file_path } => create(file_path).await, Action::Delete { paste_id } => delete(paste_id).await, + Action::List { max_results } => list(max_results).await, }; } @@ -69,3 +67,31 @@ async fn delete(paste_id: String) { async fn edit(paste_id: String, file_path: PathBuf) { todo!("No offical way to do that yet"); } + +async fn list(max_results: Option) { + let (x, y) = termion::terminal_size().unwrap(); + let resp = pastebin::list_pastes( + &keys::API_KEY.lock().unwrap(), + &keys::USER_KEY.lock().unwrap(), + max_results.unwrap_or(10), + ) + .await + .unwrap(); + + let line = "-".repeat(((x - 15) / 2).into()); + println!("{}Top {} pastes{}", line, max_results.unwrap_or(10), line); + + for paste in resp { + let mut title = paste.paste_title; + if title == "" { + title = "Untitled".to_owned(); + } + + let naive = NaiveDateTime::from_timestamp_opt(paste.paste_date.into(), 0).unwrap(); + + let datetime: DateTime = DateTime::from_utc(naive, Utc); + let newdate = datetime.format("%Y-%m-%d %H:%M:%S"); + + println!("{}\t{}\t{}", title, newdate, paste.paste_url); + } +} diff --git a/src/pastebin.rs b/src/pastebin.rs index 576b53d..c03af55 100644 --- a/src/pastebin.rs +++ b/src/pastebin.rs @@ -1,5 +1,21 @@ +use anyhow::Result; +use serde::{Deserialize, Serialize}; use std::{collections::HashMap, error::Error}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Paste { + pub paste_key: String, + pub paste_date: i64, + pub paste_title: String, + pub paste_size: u64, + pub paste_expire_date: i64, + pub paste_private: u8, + pub paste_format_long: String, + pub paste_format_short: String, + pub paste_url: String, + pub paste_hits: u64, +} + pub async fn create_paste( api_key: &str, user_key: &str, @@ -61,11 +77,7 @@ pub async fn delete_paste( Ok(req.status().to_string() + "\n" + &req.text().await?) } -pub async fn get_user_key( - api_key: &str, - username: String, - password: String, -) -> Result> { +pub async fn get_user_key(api_key: &str, username: String, password: String) -> Result { let client = reqwest::Client::new(); let mut map = HashMap::new(); @@ -86,3 +98,31 @@ pub async fn get_user_key( println!("{}", req.text().await?); panic!("Error logging in."); } + +pub async fn list_pastes(api_key: &str, user_key: &str, max_results: u16) -> Result> { + let client = reqwest::Client::new(); + + let mut map = HashMap::new(); + map.insert("api_dev_key", api_key.trim().to_owned()); + map.insert("api_user_key", user_key.trim().to_owned()); + map.insert("api_option", "list".to_owned()); + map.insert("api_results_limit", max_results.to_string()); + + let req = client + .post("https://pastebin.com/api/api_post.php") + .form(&map) + .send() + .await?; + + if req.status() == 200 { + let data = req.text().await?; + let pastes: Vec = quick_xml::de::from_str(&data).unwrap(); + return Ok(pastes); + } + + return Err(anyhow::format_err!( + "{}\n{}", + req.status().to_string(), + req.text().await? + )); +}