diff --git a/data/lang/en.json b/data/lang/en.json index df224ae..1a779b9 100644 --- a/data/lang/en.json +++ b/data/lang/en.json @@ -1,4 +1,10 @@ { + "dc_btn_approve": "Approve", + "dc_btn_remove": "Remove", + "dc_btn_unapprove": "Disapprove", + "dc_btn_unremove": "Restore", + "dc_btn_unvote": "Un-vote", + "dc_btn_vote": "Vote", "dc_msg_8-ball_answer": "## You shook a magic 8-ball\nQ: {0}\nA: {1}", "dc_msg_add_to_data": "Added your server to my data! Thanks for letting me steal it! (/s)", "dc_msg_bound_channel": "Successfully bound channel ID `{0}` as the \"where all collected Reddit data gets dumped\" channel!", @@ -36,6 +42,17 @@ "dc_msg_re_vote_success": "Successfully voted!", "dc_msg_reload_cfg_python_fail": "Failed to reload configs: Failed-type response from Python.", "dc_msg_reload_cfg_success": "Successfully reloaded the configs!\nNew configs:\n```\n{0}\n```", + "dc_msg_removed_square_brackets": "[REMOVED] {0}", "dc_msg_shorturl": "ShortURL: <{0}>", - "log_lang_load_success": "Successfully loaded the english language file!" + "dc_msg_update_add": "{0}Adding new posts...", + "dc_msg_update_done": "{0}Done!", + "dc_msg_update_editing": "{0}Editing updated posts...", + "dc_msg_update_fetch": "{0}Fetching new posts & updating data file...", + "dc_msg_update_parse": "{0}Parsing messages to JSON...", + "dc_msg_update_read": "{0}Reading messages in <#{1}>...", + "dc_msg_update_removing_dupe": "{0}Removing duplicate posts...", + "dc_msg_update_removing_old": "{0}Removing old posts (threshold: {1}d)...", + "dc_msg_update_removing": "{0}Removing removed posts...", + "log_lang_load_success": "Successfully loaded the english language file!", + "none": "None" } \ No newline at end of file diff --git a/src/data.rs b/src/data.rs index c55c227..28437ec 100644 --- a/src/data.rs +++ b/src/data.rs @@ -83,7 +83,7 @@ pub async fn read_re_data(data: &Data, wipe: bool) { } let str_data = fs::read_to_string(DATA_PATH_RE).unwrap(); - let json_data = serde_json::from_str(&str_data).unwrap(); + let json_data: Option = serde_json::from_str(&str_data).unwrap(); let mut re_data = data.reddit_data.lock().await; *re_data = json_data; } diff --git a/src/events.rs b/src/events.rs index 5789f55..d58259e 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,7 +1,10 @@ -use crate::re_cmds::generic_fns::{embed_to_json, is_bk_mod_serenity, serenity_send_msg}; -use crate::{rs_println, Data, Error}; +use crate::data::{get_mutex_data, update_re_data}; +use crate::messages::make_post_embed; +use crate::re_cmds::generic_fns::{is_bk_mod_serenity, serenity_edit_msg_embed, serenity_send_msg}; +use crate::{lang, rs_println, websocket, Data, Error, CFG_DATA_RE}; use poise::serenity_prelude::{self as serenity, ActivityData, ComponentInteraction, Interaction, Member, Ready}; +use serde_json::json; use std::future::Future; use std::pin::Pin; @@ -47,14 +50,12 @@ async fn handle_buttons(ctx: &serenity::Context, data: &Data, interaction: &Inte let i_msg = interaction.clone().message_component(); if i_msg.is_none() { return Err(Error::from("message_component is None!")); } let i_embed = i_msg.unwrap().message.embeds[0].clone(); - - let json = embed_to_json(&i_embed); - if json.is_err() { return Err(Error::from("Failed to pase message JSON!")); } + let url = i_embed.url.clone().unwrap(); return match component.data.custom_id.as_str() { - "approve_btn" => approve_btn(ctx, data, &component.member.as_ref().unwrap(), component).await, + "approve_btn" => approve_btn(ctx, data, &component.member.as_ref().unwrap(), component, url, true).await, "remove_btn" => Ok(()), - "unapprove_btn" => Ok(()), + "unapprove_btn" => approve_btn(ctx, data, &component.member.as_ref().unwrap(), component, url, false).await, "unremove_btn" => Ok(()), "unvote_btn" => Ok(()), "vote_btn" => Ok(()), @@ -63,10 +64,28 @@ async fn handle_buttons(ctx: &serenity::Context, data: &Data, interaction: &Inte } -async fn approve_btn(ctx: &serenity::Context, data: &Data, c_member: &Member, component: &ComponentInteraction) -> Result<(), Error> { +async fn approve_btn(ctx: &serenity::Context, data: &Data, c_member: &Member, component: &ComponentInteraction, url: String, approve: bool) -> Result<(), Error> { if !is_bk_mod_serenity(ctx, data, c_member, component).await { return Ok(()); } - serenity_send_msg(ctx, component, "Hello from this stupid program that tastes oddly like pasta.".to_string(), true).await; + let r = websocket::send_cmd_json("set_approve_post", Some(json!([approve, url])), true).await.unwrap(); + + let c_id = component.channel_id; + let m_id = component.message.id; + + if r["value"].as_bool().unwrap() { + update_re_data(data).await; + let new_data = &get_mutex_data(&data.reddit_data).await.unwrap()[CFG_DATA_RE][&url]; + let e = make_post_embed(new_data, &url, true); + + if approve { + serenity_edit_msg_embed(ctx, &c_id, &m_id, e).await; + serenity_send_msg(ctx, component, lang!("dc_msg_re_post_approve_success"), true).await; + } + else { + serenity_edit_msg_embed(ctx, &c_id, &m_id, e).await; + serenity_send_msg(ctx, component, lang!("dc_msg_re_post_disapprove_success"), true).await; + } + } return Ok(()); } \ No newline at end of file diff --git a/src/messages.rs b/src/messages.rs index d8b3318..b058933 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -128,6 +128,7 @@ pub async fn send_embed( } +#[allow(dead_code)] pub async fn http_send_embed( http: &Http, c_id: ChannelId, @@ -231,11 +232,11 @@ pub fn make_post_embed(post_data: &Value, url: &str, ephemeral: bool) -> EmbedOp let media_urls = post_data["post_data"]["media_urls"].as_array().unwrap(); let action_row = CreateActionRow::Buttons(vec![ - CreateButton::new("vote_btn") .label("Vote") .emoji(ReactionType::Unicode("âŦ†ī¸".to_string())), - CreateButton::new("unvote_btn") .label("Un-vote"), - CreateButton::new("approve_btn") .label("Approve") .emoji(ReactionType::Unicode("✅".to_string())), - CreateButton::new("unapprove_btn").label("Disapprove") .emoji(ReactionType::Unicode("❌".to_string())), - CreateButton::new("remove_btn") .label("Remove") .emoji(ReactionType::Unicode("đŸ—‘ī¸".to_string())) + CreateButton::new("vote_btn") .label(lang!("dc_btn_vote")) .emoji(ReactionType::Unicode("âŦ†ī¸".to_string())), + CreateButton::new("unvote_btn") .label(lang!("dc_btn_unvote")), + CreateButton::new("approve_btn") .label(lang!("dc_btn_approve")) .emoji(ReactionType::Unicode("✅".to_string())), + CreateButton::new("unapprove_btn").label(lang!("dc_btn_unapprove")) .emoji(ReactionType::Unicode("❌".to_string())), + CreateButton::new("remove_btn") .label(lang!("dc_btn_remove")) .emoji(ReactionType::Unicode("đŸ—‘ī¸".to_string())) ]); return EmbedOptions { @@ -256,19 +257,21 @@ pub fn make_post_embed(post_data: &Value, url: &str, ephemeral: bool) -> EmbedOp pub fn make_removed_embed(post_data: &Value, url: &str, ephemeral: bool) -> EmbedOptions { let action_row = CreateActionRow::Buttons(vec![ - CreateButton::new("unremove_btn").label("Un-remove").emoji(ReactionType::Unicode("â†Šī¸".to_string())) + CreateButton::new("unremove_btn").label(lang!("dc_btn_unremove")).emoji(ReactionType::Unicode("â†Šī¸".to_string())) ]); + let none = lang!("none"); + let desc = lang!( "dc_msg_embed_re_removed", post_data["removed"]["by"].as_str().unwrap(), if !post_data["removed"]["reason"].is_null() { post_data["removed"]["reason"].as_str().unwrap() } - else { "None" }, + else { &none }, url ); return EmbedOptions { - title: Some(format!("[REMOVED] {}", post_data["post_data"]["title"])), + title: Some(lang!("dc_msg_removed_square_brackets", post_data["post_data"]["title"].clone())), desc: format!("{}\n\n{}{}{}", desc, JSON_TEXT_START, serde_json::to_string(&post_data).unwrap(), JSON_TEXT_END), col: Some(REMOVED_DC_COL), url: Some(url.to_string()), diff --git a/src/python/posts.py b/src/python/posts.py index 5677cd0..9a08a9e 100644 --- a/src/python/posts.py +++ b/src/python/posts.py @@ -45,8 +45,6 @@ async def add_new_posts(bot: botPy.Bot, max_age: int) -> bool: if not media[0]: without_media += 1 continue - - post_added = False post_added = data.add_post_to_data( bot, @@ -57,11 +55,13 @@ async def add_new_posts(bot: botPy.Bot, max_age: int) -> bool: else: not_added += 1 py_print(f"Successfully fetched {len(posts)} posts.\n" + - f" Out of which were {added_posts} added.\n" + - f" {without_media} had no media, " + + f" Out of which were {added_posts} added.\n" + + f" {without_media} had no media, " + f"{not_added} are removed or already existed, " + f"and {old_posts} were older than the max age threshold.") + data.write_data(bot) + return True diff --git a/src/re_cmds/add.rs b/src/re_cmds/add.rs index c623a95..6418a65 100644 --- a/src/re_cmds/add.rs +++ b/src/re_cmds/add.rs @@ -4,7 +4,7 @@ use crate::data::{get_mutex_data, update_re_data}; use crate::messages::send_msg; use crate::re_cmds::get::get_post_from_data; use crate::{data, websocket::send_cmd_json, Context, Error, CFG_DATA_RE}; -use crate::re_cmds::generic_fns::{get_readable_subreddits, is_bk_mod, send_embed_for_post, to_shorturl}; +use crate::re_cmds::generic_fns::{is_bk_mod_msg, send_embed_for_post, to_shorturl}; use crate::lang; #[poise::command( @@ -21,11 +21,7 @@ pub async fn cmd( #[description = "Wether to approve it after adding it"] approve: Option ) -> Result<(), Error> { - if !is_bk_mod(ctx.data().bk_mods.clone(), ctx.author().id.get()) { - let sr = get_readable_subreddits(ctx.data()).await?; - send_msg(ctx, lang!("dc_msg_re_permdeny_not_re_mod", sr), false, false).await; - return Ok(()); - } + if is_bk_mod_msg(ctx).await { return Ok(()); } let shorturl_u = to_shorturl(&url); let shorturl = &shorturl_u.unwrap_or(url.clone()); diff --git a/src/re_cmds/approve.rs b/src/re_cmds/approve.rs index 84ce74d..a023983 100644 --- a/src/re_cmds/approve.rs +++ b/src/re_cmds/approve.rs @@ -37,7 +37,7 @@ async fn approve_cmd(ctx: Context<'_>, url: &str, reddit_data: &Value, approve: } let r = websocket::send_cmd_json("set_approve_post", Some(json!([approve, &url])), true).await.unwrap(); - if r.get("value").is_some() { + if r["value"].as_bool().unwrap() { if approve { send_msg(ctx, lang!("dc_msg_re_post_approve_success"), true, true).await; } diff --git a/src/re_cmds/generic_fns.rs b/src/re_cmds/generic_fns.rs index f4aedce..df38e0c 100644 --- a/src/re_cmds/generic_fns.rs +++ b/src/re_cmds/generic_fns.rs @@ -1,8 +1,8 @@ -use poise::serenity_prelude::{self as serenity, ComponentInteraction, CreateInteractionResponse, CreateInteractionResponseMessage, Embed, Member}; +use poise::serenity_prelude::{self as serenity, ChannelId, ComponentInteraction, CreateInteractionResponse, CreateInteractionResponseMessage, EditMessage, Embed, Member, MessageId}; use regex::Regex; use serde_json::Value; -use crate::{data::get_toml_mutex, lang, messages::{make_post_embed, make_removed_embed, send_embed, send_msg, JSON_TEXT_END, JSON_TEXT_START}, Context, Data, Error}; +use crate::{data::get_toml_mutex, lang, messages::{embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg, EmbedOptions, JSON_TEXT_END, JSON_TEXT_START}, Context, Data, Error}; pub fn is_bk_mod(mod_list: Vec, uid: u64) -> bool { return mod_list.contains(&uid); @@ -33,6 +33,12 @@ pub async fn serenity_send_msg(ctx: &serenity::Context, component: &ComponentInt } +pub async fn serenity_edit_msg_embed(ctx: &serenity::Context, c_id: &ChannelId, m_id: &MessageId, e: EmbedOptions) { + let r = EditMessage::new().embed(embed_from_options(e)); + let _ = c_id.edit_message(ctx.http.clone(), m_id, r).await; +} + + pub fn to_shorturl(url: &str) -> Result { let re = Regex::new(r"comments/([a-zA-Z0-9]+)").unwrap(); @@ -51,6 +57,7 @@ pub async fn send_embed_for_post(ctx: Context<'_>, post: Value, url: &str) -> Re return Ok(()); } + pub async fn send_embed_for_removed(ctx: Context<'_>, url: &str, post: &Value) { send_embed( ctx, diff --git a/src/re_cmds/remove.rs b/src/re_cmds/remove.rs index bd240bd..c34cf69 100644 --- a/src/re_cmds/remove.rs +++ b/src/re_cmds/remove.rs @@ -1,6 +1,6 @@ use serde_json::json; -use crate::{data::{self, get_mutex_data}, lang, messages::send_msg, re_cmds::{generic_fns::{get_readable_subreddits, is_bk_mod, send_embed_for_removed}, get::get_post_from_data}, websocket::send_cmd_json, Context, Error}; +use crate::{data::{self, get_mutex_data}, lang, messages::send_msg, re_cmds::{generic_fns::{is_bk_mod_msg, send_embed_for_removed}, get::get_post_from_data}, websocket::send_cmd_json, Context, Error}; #[poise::command( slash_command, @@ -16,11 +16,7 @@ pub async fn cmd( #[description = "The reason of the removal."] reason: Option ) -> Result<(), Error> { - if !is_bk_mod(ctx.data().bk_mods.clone(), ctx.author().id.get()) { - let sr = get_readable_subreddits(ctx.data()).await?; - send_msg(ctx, lang!("dc_msg_re_permdeny_not_re_mod", sr), false, false).await; - return Ok(()); - } + if is_bk_mod_msg(ctx).await { return Ok(()); } let auth = &ctx.author().name; let r = send_cmd_json("remove_post_url", Some(json!([&url, &auth, &reason])), true).await.unwrap(); diff --git a/src/re_cmds/update.rs b/src/re_cmds/update.rs index efa36f5..0093867 100644 --- a/src/re_cmds/update.rs +++ b/src/re_cmds/update.rs @@ -3,7 +3,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use poise::{serenity_prelude::{ChannelId, EditMessage, GetMessages, Http, Message, MessageId, UserId}, ReplyHandle}; use serde_json::{json, Map, Value}; -use crate::{data::{self, get_mutex_data, DC_POSTS_CHANNEL_KEY}, lang, messages::{edit_reply, embed_from_options, http_send_embed, make_post_embed, make_removed_embed, send_msg}, re_cmds::generic_fns::embed_to_json, websocket::send_cmd_json, Context, Error, CFG_DATA_RE}; +use crate::{data::{self, get_mutex_data, DC_POSTS_CHANNEL_KEY}, lang, messages::{edit_reply, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg}, re_cmds::generic_fns::embed_to_json, rs_println, websocket::send_cmd_json, Context, Error, CFG_DATA_RE}; #[poise::command( slash_command, @@ -30,7 +30,7 @@ pub async fn cmd( let mut p_text = "`/re_updatediscord`:".to_string(); let progress = send_msg(ctx, p_text.clone(), true, true).await.unwrap(); - p_text = update_progress(ctx, progress.clone(), p_text, "\nFetching new posts & updating data file...".to_string()).await; + p_text = update_progress(ctx, progress.clone(), p_text, lang!("dc_msg_update_fetch", "\n")).await; let max_age_u = max_age.unwrap_or(8); let max_age_secs = max_age_u as u64 * (60 * 60 * 24); @@ -49,47 +49,47 @@ pub async fn cmd( let c_id = c_id_u.unwrap(); // Reading messages - p_text = update_progress(ctx, progress.clone(), p_text.clone(), format!("✅\nReading messages in <#{}>...", c_id)).await; + p_text = update_progress(ctx, progress.clone(), p_text.clone(), lang!("dc_msg_update_read", "✅\n", c_id)).await; let msgs = read_msgs(http, ctx.framework().bot_id, c_id).await; // Parsing messages to JSON - p_text = update_progress(ctx, progress.clone(), p_text.clone(), "✅\nParsing messages to JSON...".to_string()).await; + p_text = update_progress(ctx, progress.clone(), p_text.clone(), lang!("dc_msg_update_parse", "✅\n")).await; let msgs_json = msgs_to_json(msgs, &r_data, max_age_secs).await; // Adding new posts - p_text = update_progress(ctx, progress.clone(), p_text.clone(), "✅\nAdding new posts...".to_string()).await; + p_text = update_progress(ctx, progress.clone(), p_text.clone(), lang!("dc_msg_update_add", "✅\n")).await; let weekly_art = r_data[CFG_DATA_RE].as_object().unwrap(); - add_posts(http, c_id, weekly_art, &msgs_json, max_age_secs).await; + add_posts(ctx, weekly_art, &msgs_json, max_age_secs).await; // Stop if only_add if only_add.unwrap_or(false) { - send_msg(ctx, "`/bk_week_update`\n## Done!".to_string(), true, true).await; - update_progress(ctx, progress.clone(), p_text, "✅\n## Done!".to_string()).await; + send_msg(ctx, lang!("dc_msg_update_done", "`/bk_week_update`\n## "), true, true).await; + update_progress(ctx, progress.clone(), p_text, lang!("dc_msg_update_done", "✅\n## ")).await; return Ok(()); } // Editing updated posts - p_text = update_progress(ctx, progress.clone(), p_text.clone(), "✅\nEditing updated posts...".to_string()).await; + p_text = update_progress(ctx, progress.clone(), p_text.clone(), lang!("dc_msg_update_editing", "✅\n")).await; edit_posts(http, c_id, weekly_art, &msgs_json).await; // Removing removed posts - p_text = update_progress(ctx, progress.clone(), p_text.clone(), "✅\nRemoving removed posts...".to_string()).await; + p_text = update_progress(ctx, progress.clone(), p_text.clone(), lang!("dc_msg_update_removing", "✅\n")).await; remove_posts(http, c_id, weekly_art, &msgs_json).await; // Removing old posts if max_age_u > 0 { - p_text = update_progress(ctx, progress.clone(), p_text.clone(), format!("✅\nRemoving old posts (threshold: {}d)...", max_age_u)).await; + p_text = update_progress(ctx, progress.clone(), p_text.clone(), lang!("dc_msg_update_removing_old", "✅\n", max_age_u)).await; remove_old(http, c_id, &msgs_json).await; send_cmd_json("remove_old_posts", Some(json!([max_age_secs])), true).await; } // Removing duplicate posts - p_text = update_progress(ctx, progress.clone(), p_text.clone(), "✅\nRemoving duplicate posts...".to_string()).await; + p_text = update_progress(ctx, progress.clone(), p_text.clone(), lang!("dc_msg_update_removing_dupe", "✅\n")).await; remove_dupes(http, c_id, &msgs_json).await; // Done - update_progress(ctx, progress.clone(), p_text, "✅\n## Done!".to_string()).await; - send_msg(ctx, "`/bk_week_update`\n## Done!".to_string(), true, true).await; + update_progress(ctx, progress.clone(), p_text, lang!("dc_msg_update_done", "✅\n## ")).await; + send_msg(ctx, lang!("dc_msg_update_done", "`/bk_week_update`\n## "), true, true).await; return Ok(()); } @@ -178,14 +178,15 @@ async fn msgs_to_json(msgs: Vec, reddit_data: &Value, max_age: u64) -> let msg_json = embed_to_json(&msg.embeds[0]); if msg_json.is_err() { continue; } - let mut u_json: Value = msg_json.unwrap(); + let u_json: Value = msg_json.unwrap(); let re_url = &reddit_data[CFG_DATA_RE][&url]; let post_date = re_url["post_data"]["date_unix"].as_u64().unwrap_or(0); // old - if now - post_date > max_age { + if now - post_date > max_age && max_age > 0 { if let Some(obj) = msgs_json["old"].as_object_mut() { + rs_println!("old: {}", url); obj.insert(url.clone(), json!(msg.id.get())); continue; } @@ -209,13 +210,8 @@ async fn msgs_to_json(msgs: Vec, reddit_data: &Value, max_age: u64) -> } // updated - if u_json["added"] != re_url["added"] - || u_json["approved"] != re_url["approved"] - || u_json["post_data"]["upvotes"] != re_url["post_data"]["upvotes"] - || u_json["votes"]["mod_voters"] != re_url["votes"]["mod_voters"] + if &u_json != re_url { - u_json.as_object_mut().unwrap().insert("msg_id".to_string(), Value::String(msg.id.clone().to_string())); - if let Some(obj) = msgs_json["updated"].as_object_mut() { obj.insert(url.clone(), json!(msg.id.get())); continue; @@ -232,7 +228,7 @@ async fn msgs_to_json(msgs: Vec, reddit_data: &Value, max_age: u64) -> } -async fn add_posts(http: &Http, c_id: ChannelId, r_data: &Map, msgs_json: &Value, max_age: u64) { +async fn add_posts(ctx: Context<'_>, r_data: &Map, msgs_json: &Value, max_age: u64) { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("Time went backwards") @@ -245,14 +241,14 @@ async fn add_posts(http: &Http, c_id: ChannelId, r_data: &Map, ms { continue; } let post_date = r_data[url]["post_data"]["date_unix"].as_u64().unwrap(); - if now - post_date > max_age { continue; } + if now - post_date > max_age && max_age > 0 { continue; } - if r_data[url].get("removed").is_some() { - http_send_embed(http, c_id, make_removed_embed(&r_data[url], url, false)).await; + if r_data[url]["removed"]["removed"].as_bool().unwrap() { + send_embed(ctx, make_removed_embed(&r_data[url], url, false), false).await; continue; } - http_send_embed(http, c_id, make_post_embed(&r_data[url], url, false)).await; + send_embed(ctx, make_post_embed(&r_data[url], url, false), false).await; } }