summary refs log tree commit diff
path: root/src/system/plugin/edit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/system/plugin/edit.rs')
-rw-r--r--src/system/plugin/edit.rs123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/system/plugin/edit.rs b/src/system/plugin/edit.rs
new file mode 100644
index 0000000..bbd5801
--- /dev/null
+++ b/src/system/plugin/edit.rs
@@ -0,0 +1,123 @@
+use async_trait::async_trait;
+use regex::RegexBuilder;
+use twilight_model::channel::message::MessageReference;
+use twilight_model::id::{marker::ChannelMarker, Id};
+use twilight_model::channel::Message;
+use crate::system::{log::Logger, types::{Response, System}};
+
+use super::{PluginCommand, SeancePlugin};
+
+pub struct Edit;
+
+impl Edit {
+    pub fn new() -> Self {
+        Self
+    }
+}
+
+#[async_trait]
+impl<'system> SeancePlugin<'system> for Edit {
+    fn get_commands(&self) -> Vec<PluginCommand> {
+        vec![
+            PluginCommand::Long("edit"),
+            PluginCommand::Short("s"),
+        ]
+    }
+
+    async fn handle_command<'message>(&self, logger: &'system Logger, system: &'system System, message: &'message Message, command: PluginCommand, args: Vec<&'message str>) {
+        let most_recent_message = system.get_most_recent_message(message.channel_id).await;
+
+        if let Some((edit_target, update_most_recent)) = match message.kind {
+            twilight_model::channel::message::MessageType::Regular => most_recent_message.map(|(message, _)| (message, true)),
+            twilight_model::channel::message::MessageType::Reply => async {Some((
+                message.referenced_message.as_ref()?.as_ref().clone(),
+                message.referenced_message.as_ref()?.id == most_recent_message?.0.id
+            ))}.await,
+            _ => todo!(),
+        } {
+            if let Some(authoring_member) = system.get_member_by_id(edit_target.author.id).await {
+                if let Some(edit_contents) = match command {
+                    PluginCommand::Long("edit") => Some(args.join(" ")),
+                    PluginCommand::Short("s") => async {
+                        let replacement_command = args.join(" ");
+                        let separator = replacement_command.chars().nth(1).unwrap();
+                        let parts: Vec<&str> = replacement_command.split(separator).collect();
+
+                        if parts.len() != 3 && parts.len() != 4 {
+                            None?
+                        }
+
+                        let pattern = parts.get(1).unwrap();
+                        let replacement = parts.get(2).unwrap();
+                        let flags = parts.get(3).unwrap_or(&"");
+
+                        let mut global = false;
+                        let mut regex = RegexBuilder::new(pattern);
+
+                        for flag in flags.chars() {match flag {
+                            'i' => {regex.case_insensitive(true);},
+                            'm' => {regex.multi_line(true);},
+                            'g' => {global = true;},
+                            'x' => {regex.ignore_whitespace(true);},
+                            'R' => {regex.crlf(true);},
+                            's' => {regex.dot_matches_new_line(true);},
+                            'U' => {regex.swap_greed(true);},
+                            other => {
+                                logger.log_err(Some(authoring_member.discord_token.clone()), format!("Unknown regex flag {other}")).await;
+                                None?
+                            },
+                        }};
+
+                        let valid_regex = regex.build();
+                        let original_content = edit_target.content;
+
+                        // If the regex parses, replace with that
+                        let result = if let Ok(regex) = valid_regex {
+                            if global {
+                                regex.replace_all(original_content.as_str(), *replacement).to_string()
+                            } else {
+                                regex.replace(original_content.as_str(), *replacement).to_string()
+                            }
+
+                        // Else attempt replace as string
+                        } else {
+                            original_content.replace(pattern, replacement)
+                        };
+                        Some(result)
+                    }.await,
+                    _ => unreachable!("Unknown command"),
+                } {
+                    let result = {authoring_member.client.lock().await.update_message(edit_target.channel_id, edit_target.id)
+                        .content(Some(edit_contents.as_str()))
+                        .expect("Invalid edit contents")
+                        .await
+                        .expect("Could not edit")
+                        .model()
+                        .await
+                        .expect("Could not parse response")};
+
+                    if update_most_recent {
+                        system.cache_most_recent_message(result.channel_id, result, authoring_member.clone()).await;
+                    }
+
+                    let _ = {authoring_member.client.lock().await.delete_message(message.channel_id, message.id).await};
+                } else {
+                    logger.log_err(None, format!("Could not determine edit contents")).await;
+                }
+            } else {
+                logger.log_err(None, format!("Cannot edit message not sent by system member")).await;
+            }
+
+        } else {
+            logger.log_err(None, format!("Cannot find edit target")).await;
+        }
+    }
+
+    async fn handle_message<'message>(&self, _logger: &'system Logger, _system: &'system System, _message: &'message Message, _response: &'message mut Response) {
+        // noop
+    }
+
+    async fn post_response<'message>(&self, _logger: &'system Logger, _system: &'system System, _message: &'message Message, _channel: Id<ChannelMarker>, _response: &'message Response) {
+        // noop
+    }
+}