// auto imports use crate::config::MastodonConfig; // std use std::{ borrow::Cow, error::Error, collections::HashMap, io::stdin, }; // htmlescape use htmlescape::decode_html; // egg-mode use egg_mode::{ tweet::Tweet, entities::{UrlEntity, MentionEntity}, }; // elefren use elefren::{ prelude::*, apps::App, scopes::Scopes, }; /// Decodes the Twitter mention to something that will make sense once Twitter has joined the /// Fediverse fn twitter_mentions(ums: &Vec) -> HashMap { let mut decoded_mentions = HashMap::new(); for um in ums { decoded_mentions.insert(format!("@{}", um.screen_name), format!("@{}@twitter.com", um.screen_name)); } decoded_mentions } /// Decodes urls from UrlEntities fn decode_urls(urls: &Vec) -> HashMap { let mut decoded_urls = HashMap::new(); for url in urls { if url.expanded_url.is_some() { // unwrap is safe here as we just verified that there is something inside expanded_url decoded_urls.insert(String::from(&url.url), String::from(url.expanded_url.as_deref().unwrap())); } } decoded_urls } /// Gets Mastodon Data pub fn get_mastodon_token(masto: &MastodonConfig) -> Mastodon { let data = Data { base: Cow::from(String::from(&masto.base)), client_id: Cow::from(String::from(&masto.client_id)), client_secret: Cow::from(String::from(&masto.client_secret)), redirect: Cow::from(String::from(&masto.redirect)), token: Cow::from(String::from(&masto.token)), }; Mastodon::from(data) } /// Builds toot text from tweet pub fn build_basic_status(tweet: &Tweet) -> Result> { let mut toot = String::from(&tweet.text); let decoded_urls = decode_urls(&tweet.entities.urls); for decoded_url in decoded_urls { toot = toot.replace(&decoded_url.0, &decoded_url.1); } let decoded_mentions = twitter_mentions(&tweet.entities.user_mentions); for decoded_mention in decoded_mentions { toot = toot.replace(&decoded_mention.0, &decoded_mention.1); } if let Ok(t) = decode_html(&toot) { toot = t; } Ok(toot) } /// Generic register function /// As this function is supposed to be run only once, it will panic for every error it encounters /// Most of this function is a direct copy/paste of the official `elefren` crate pub fn register(host: &str) { let mut builder = App::builder(); builder.client_name(Cow::from(String::from(env!("CARGO_PKG_NAME")))) .redirect_uris(Cow::from(String::from("urn:ietf:wg:oauth:2.0:oob"))) .scopes(Scopes::write_all()) .website(Cow::from(String::from("https://framagit.org/veretcle/scootaloo"))); let app = builder.build().expect("Cannot build the app"); let registration = Registration::new(host).register(app).expect("Cannot build registration object"); let url = registration.authorize_url().expect("Cannot generate registration URI!"); println!("Click this link to authorize on Mastodon: {}", url); println!("Paste the returned authorization code: "); let mut input = String::new(); stdin().read_line(&mut input).expect("Unable to read back registration code!"); let code = input.trim(); let mastodon = registration.complete(code).expect("Unable to create access token!"); let toml = toml::to_string(&*mastodon).unwrap(); println!("Please insert the following block at the end of your configuration file:\n[mastodon]\n{}", toml); } #[cfg(test)] mod tests { use super::*; #[test] fn test_twitter_mentions() { let mention_entity = MentionEntity { id: 12345, range: (1, 3), name: String::from("Ta Mere l0l"), screen_name: String::from("tamerelol"), }; let twitter_ums = vec![mention_entity]; let mut expected_mentions = HashMap::new(); expected_mentions.insert(String::from("@tamerelol"), String::from("@tamerelol@twitter.com")); let decoded_mentions = twitter_mentions(&twitter_ums); assert_eq!(expected_mentions, decoded_mentions); } #[test] fn test_decode_urls() { let url_entity1 = UrlEntity { display_url: String::from("tamerelol"), expanded_url: Some(String::from("https://www.nintendojo.fr/dojobar")), range: (1, 3), url: String::from("https://t.me/tamerelol"), }; let url_entity2 = UrlEntity { display_url: String::from("tamerelol"), expanded_url: None, range: (1, 3), url: String::from("https://t.me/tamerelol"), }; let twitter_urls = vec![url_entity1, url_entity2]; let mut expected_urls = HashMap::new(); expected_urls.insert(String::from("https://t.me/tamerelol"), String::from("https://www.nintendojo.fr/dojobar")); let decoded_urls = decode_urls(&twitter_urls); assert_eq!(expected_urls, decoded_urls); } }