diff --git a/src/config.rs b/src/config.rs index d0e2881..ba7a60c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,4 @@ -// std use std::fs::read_to_string; - -// toml use serde::Deserialize; /// General configuration Struct diff --git a/src/lib.rs b/src/lib.rs index f7834f6..779cb7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -// auto-imports mod error; use crate::error::ScootalooError; @@ -19,22 +18,13 @@ mod state; use state::{read_state, write_state, TweetToToot}; pub use state::init_db; -// std use std::borrow::Cow; - -// tokio use tokio::fs::remove_file; - -// elefren use elefren::{ prelude::*, status_builder::StatusBuilder, }; - -// log use log::{info, warn, error, debug}; - -// rusqlite use rusqlite::Connection; /// This is where the magic happens @@ -72,6 +62,8 @@ pub async fn run(config: Config) { for tweet in &feed { debug!("Treating Tweet {} inside feed", tweet.id); + // initiate the toot_reply_id var + let mut toot_reply_id: Option = None; // determine if the tweet is part of a thread (response to self) or a standard response if let Some(r) = &tweet.in_reply_to_screen_name { if &r.to_lowercase() != &config.twitter.username.to_lowercase() { @@ -79,6 +71,11 @@ pub async fn run(config: Config) { info!("Tweet is a direct response, skipping"); continue; } + + let searched_toot = read_state(&conn, tweet.in_reply_to_status_id).unwrap_or(None); + if let Some(i) = searched_toot { + toot_reply_id = Some(i.toot_id); + }; }; // build basic status by just yielding text and dereferencing contained urls @@ -125,10 +122,17 @@ pub async fn run(config: Config) { // finished reuploading attachments, now let’s do the toot baby! debug!("Building corresponding Mastodon status"); - let status = StatusBuilder::new() - .status(&status_text) - .media_ids(status_medias) - .build() + + let mut status_builder = StatusBuilder::new(); + + status_builder.status(&status_text) + .media_ids(status_medias); + + if let Some(i) = toot_reply_id { + status_builder.in_reply_to(&i); + } + + let status = status_builder.build() .expect(&format!("Cannot build status with text {}", &status_text)); // publish status diff --git a/src/main.rs b/src/main.rs index 80c9bfb..60d22ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,7 @@ -// self use scootaloo::*; - -// clap use clap::{App, Arg, SubCommand}; - -// log use log::{LevelFilter, error}; use simple_logger::SimpleLogger; - -// std use std::str::FromStr; const DEFAULT_CONFIG_PATH: &'static str = "/usr/local/etc/scootaloo.toml"; @@ -21,7 +14,7 @@ fn main() { .short("c") .long("config") .value_name("CONFIG_FILE") - .help(&*format!("TOML config file for scootaloo (default {})", DEFAULT_CONFIG_PATH)) + .help(&format!("TOML config file for scootaloo (default {})", DEFAULT_CONFIG_PATH)) .takes_value(true) .display_order(1)) .arg(Arg::with_name("log_level") @@ -49,7 +42,7 @@ fn main() { .short("c") .long("config") .value_name("CONFIG_FILE") - .help(&*format!("TOML config file for scootaloo (default {})", DEFAULT_CONFIG_PATH)) + .help(&format!("TOML config file for scootaloo (default {})", DEFAULT_CONFIG_PATH)) .takes_value(true) .display_order(1))) .get_matches(); diff --git a/src/mastodon.rs b/src/mastodon.rs index 68d3353..d2a51a1 100644 --- a/src/mastodon.rs +++ b/src/mastodon.rs @@ -1,24 +1,16 @@ -// 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, diff --git a/src/state.rs b/src/state.rs index d4e91f6..93c103d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,13 +1,7 @@ -// auto-imports use crate::config::ScootalooConfig; -// std use std::error::Error; - -// log use log::debug; - -// rusqlite use rusqlite::{Connection, params, OptionalExtension}; /// Struct for each query line @@ -50,9 +44,6 @@ pub fn write_state(conn: &Connection, t: TweetToToot) -> Result<(), Box Result<(), Box> { debug!("Initializing DB for Scootaloo"); @@ -78,7 +69,7 @@ mod tests { }; #[test] - fn test_db() { + fn test_init_db() { let scootaloo_config = ScootalooConfig { db_path: String::from("/tmp/test_init_db.sqlite"), cache_path: String::from("/tmp/scootaloo"), @@ -96,57 +87,136 @@ mod tests { [], ).unwrap(); - // write a state to DB - let t = TweetToToot { + remove_file(scootaloo_config.db_path).unwrap(); + } + + #[test] + fn test_write_state() { + let scootaloo_config = ScootalooConfig { + db_path: String::from("/tmp/test_write_state.sqlite"), + cache_path: String::from("/tmp/scootaloo"), + }; + + init_db(&scootaloo_config).unwrap(); + + let conn = Connection::open(&scootaloo_config.db_path).unwrap(); + + let t_in = TweetToToot { tweet_id: 123456789, toot_id: String::from("987654321"), }; - write_state(&conn, t).unwrap(); - let mut stmt = conn.prepare("SELECT * FROM tweet_to_toot limit 1;").unwrap(); - let mut rows = stmt.query([]).unwrap(); + write_state(&conn, t_in).unwrap(); - while let Some(row) = rows.next().unwrap() { - assert_eq!(123456789 as u64, row.get::<_, u64>(0).unwrap()); - assert_eq!("987654321", row.get::<_, String>(1).unwrap()); - } + let mut stmt = conn.prepare("SELECT * FROM tweet_to_toot;").unwrap(); - // write several other states - let (t1, t2) = ( - TweetToToot { - tweet_id: 11111111, - toot_id: String::from("tamerelol"), - }, - TweetToToot { - tweet_id: 1123456789, - toot_id: String::from("tonperemdr"), - }); + let t_out = stmt.query_row([], |row| { + Ok(TweetToToot { + tweet_id: row.get(0).unwrap(), + toot_id: row.get(1).unwrap(), + }) + }).unwrap(); - write_state(&conn, t1).unwrap(); - write_state(&conn, t2).unwrap(); - - match read_state(&conn, None).unwrap() { - Some(i) => { - assert_eq!(1123456789, i.tweet_id); - assert_eq!("tonperemdr", &i.toot_id); - }, - None => panic!("This should not happen!"), - } - - match read_state(&conn, Some(11111111)).unwrap() { - Some(i) => { - assert_eq!(11111111, i.tweet_id); - assert_eq!("tamerelol", &i.toot_id); - }, - None => panic!("This should not happen!"), - } - - match read_state(&conn, Some(0000000)).unwrap() { - Some(_) => panic!("This should not happen"), - _ => (), - } + assert_eq!(t_out.tweet_id, 123456789); + assert_eq!(t_out.toot_id, String::from("987654321")); remove_file(&scootaloo_config.db_path).unwrap(); } + + #[test] + fn test_none_to_tweet_id_read_state() { + let scootaloo_config = ScootalooConfig { + db_path: String::from("/tmp/test_none_to_tweet_id_read_state.sqlite"), + cache_path: String::from("/tmp/scootaloo"), + }; + + init_db(&scootaloo_config).unwrap(); + + let conn = Connection::open(&scootaloo_config.db_path).unwrap(); + + conn.execute( + "INSERT INTO tweet_to_toot (tweet_id, toot_id) + VALUES + (101, 'A'), + (102, 'B');", + [], + ).unwrap(); + + let t_out = read_state(&conn, None).unwrap().unwrap(); + + remove_file(&scootaloo_config.db_path).unwrap(); + + assert_eq!(t_out.tweet_id, 102); + assert_eq!(t_out.toot_id, "B"); + } + + #[test] + fn test_none_to_none_read_state() { + let scootaloo_config = ScootalooConfig { + db_path: String::from("/tmp/test_none_to_none_read_state.sqlite"), + cache_path: String::from("/tmp/scootaloo"), + }; + + init_db(&scootaloo_config).unwrap(); + + let conn = Connection::open(&scootaloo_config.db_path).unwrap(); + + let t_out = read_state(&conn, None).unwrap(); + + remove_file(&scootaloo_config.db_path).unwrap(); + + assert!(t_out.is_none()); + } + + #[test] + fn test_tweet_id_to_none_read_state() { + let scootaloo_config = ScootalooConfig { + db_path: String::from("/tmp/test_tweet_id_to_none_read_state.sqlite"), + cache_path: String::from("/tmp/scootaloo"), + }; + + init_db(&scootaloo_config).unwrap(); + + let conn = Connection::open(&scootaloo_config.db_path).unwrap(); + + conn.execute( + "INSERT INTO tweet_to_toot (tweet_id, toot_id) + VALUES + (100, 'A');", + [], + ).unwrap(); + + let t_out = read_state(&conn, Some(101)).unwrap(); + + remove_file(&scootaloo_config.db_path).unwrap(); + + assert!(t_out.is_none()); + } + + #[test] + fn test_tweet_id_to_tweet_id_read_state() { + let scootaloo_config = ScootalooConfig { + db_path: String::from("/tmp/test_tweet_id_to_tweet_id_read_state.sqlite"), + cache_path: String::from("/tmp/scootaloo"), + }; + + init_db(&scootaloo_config).unwrap(); + + let conn = Connection::open(&scootaloo_config.db_path).unwrap(); + + conn.execute( + "INSERT INTO tweet_to_toot (tweet_id, toot_id) + VALUES + (100, 'A');", + [], + ).unwrap(); + + let t_out = read_state(&conn, Some(100)).unwrap().unwrap(); + + remove_file(&scootaloo_config.db_path).unwrap(); + + assert_eq!(t_out.tweet_id, 100); + assert_eq!(t_out.toot_id, "A"); + } }