summary refs log tree commit diff
path: root/src/system
diff options
context:
space:
mode:
authorAshelyn Rose <git@ashen.earth>2024-10-06 15:25:01 -0600
committerAshelyn Rose <git@ashen.earth>2024-10-06 15:25:01 -0600
commitec104a719f46d6812661c29355e7a9fea8418b49 (patch)
tree378eadd6183f5c9af997e52f89bdfa59570b0f7a /src/system
parent9e15bb9103ba054fa88501cbff2d5e121ffa8544 (diff)
Actually carries out !edit and !s commands
Diffstat (limited to 'src/system')
-rw-r--r--src/system/bot/client.rs7
-rw-r--r--src/system/bot/mod.rs4
-rw-r--r--src/system/message_parser.rs83
-rw-r--r--src/system/mod.rs16
4 files changed, 91 insertions, 19 deletions
diff --git a/src/system/bot/client.rs b/src/system/bot/client.rs
index 61d7515..4d4f7bb 100644
--- a/src/system/bot/client.rs
+++ b/src/system/bot/client.rs
@@ -90,6 +90,13 @@ impl Client {
         return Ok(())
     }
 
+    pub async fn edit_message(&self, channel_id: ChannelId, message_id: MessageId, new_content: String) -> Result<FullMessage, TwiError> {
+        Ok(self.client.lock().await.update_message(channel_id, message_id)
+            .content(Some(new_content.as_str())).expect("Invalid message contents")
+            .await.expect("Could not update message")
+            .model().await.unwrap())
+    }
+
     pub async fn duplicate_message(&self, message: &TwiMessage, content: &str) -> Result<TwiMessage, MessageDuplicateError> {
         let client = self.client.lock().await;
 
diff --git a/src/system/bot/mod.rs b/src/system/bot/mod.rs
index 2f38075..f0a2e45 100644
--- a/src/system/bot/mod.rs
+++ b/src/system/bot/mod.rs
@@ -74,6 +74,10 @@ impl Bot {
         self.client.resend_message(message_id, channel_id).await;
     }
 
+    pub async fn edit_message(&self, channel_id: ChannelId, message_id: MessageId, new_content: String) -> Result<FullMessage, TwiError> {
+        self.client.edit_message(channel_id, message_id, new_content).await
+    }
+
     pub async fn delete_message(&self, channel_id: ChannelId, message_id: MessageId) -> Result<(), TwiError> {
         self.client.delete_message(channel_id, message_id).await
     }
diff --git a/src/system/message_parser.rs b/src/system/message_parser.rs
index 31747a8..d161483 100644
--- a/src/system/message_parser.rs
+++ b/src/system/message_parser.rs
@@ -1,11 +1,11 @@
 use std::sync::LazyLock;
-use regex::Regex;
+use regex::{Regex, RegexBuilder};
 
 use crate::config::System;
 
 use twilight_mention::ParseMention;
 use twilight_model::id::{marker::UserMarker, Id};
-use super::{FullMessage, MemberId, MessageId, Timestamp};
+use super::{FullMessage, MemberId, MessageId, Timestamp, UserId};
 
 pub enum ParsedMessage {
     Command(Command),
@@ -23,12 +23,13 @@ pub enum ParsedMessage {
 }
 
 pub enum Command {
-    Edit(MessageId, String),
+    Edit(MemberId, MessageId, String),
     Reproxy(MemberId, MessageId),
     Nick(MemberId, String),
     ReloadSystemConfig,
     ExitSéance,
     UnknownCommand,
+    InvalidCommand
 }
 
 pub struct MessageParser {}
@@ -81,7 +82,10 @@ impl MessageParser {
 
         match first_word {
             Some(command_name) => match command_name {
-                "edit" => return Command::Edit(secondary_message.unwrap().id, words.remainder().unwrap().to_string()),
+                "edit" => {
+                    let editing_member = Self::get_member_id_from_user_id(secondary_message.as_ref().unwrap().author.id, system_config).unwrap();
+                    return Command::Edit(editing_member, secondary_message.unwrap().id, words.remainder().unwrap().to_string())
+                },
                 "nick" => {
                     if let Some(member) = MessageParser::match_member(words.next(), system_config) {
                         return Command::Nick(member, words.remainder().unwrap().to_string());
@@ -97,24 +101,48 @@ impl MessageParser {
             None => return Command::UnknownCommand,
         }
 
-        
-        // If unable to parse
-        Command::UnknownCommand
-    }
+        // Attempt matching !s
+        if message.content.chars().nth(1).unwrap() == 's' {
+            let separator = message.content.chars().nth(2).unwrap();
+            let parts: Vec<&str> = message.content.split(separator).collect();
 
-    fn match_member(maybe_mention: Option<&str>, system_config: &System) -> Option<MemberId> {
-        if let Some(maybe_mention) = maybe_mention {
-            if let Ok(mention) = Id::<UserMarker>::parse(maybe_mention) {
-                system_config.members.iter().enumerate()
-                    .filter(|(_id, m)| m.user_id.is_some())
-                    .find(|(_id, m)| m.user_id.unwrap() == mention)
-                    .map(|(id, _m)| id)
-            } else {
-                None
+            if parts.len() != 3 && parts.len() != 4 {
+                return Command::InvalidCommand
             }
-        } else {
-            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);},
+                _ => {return Command::InvalidCommand;},
+            }};
+
+            let regex = regex.build().unwrap();
+
+            let original_content = &secondary_message.as_ref().unwrap().content;
+            let new_content = if global {
+                regex.replace_all(original_content.as_str(), *replacement)
+            } else {
+                regex.replace(original_content.as_str(), *replacement)
+            };
+
+            let editing_member = Self::get_member_id_from_user_id(secondary_message.as_ref().unwrap().author.id, system_config).unwrap();
+            return Command::Edit(editing_member, secondary_message.as_ref().unwrap().id, new_content.to_string());
         }
+
+        // If unable to parse
+        Command::UnknownCommand
     }
 
     fn check_correction(message: &FullMessage, secondary_message: Option<FullMessage>) -> Option<ParsedMessage> {
@@ -148,6 +176,23 @@ impl MessageParser {
             None
         }
     }
+
+    fn match_member(maybe_mention: Option<&str>, system_config: &System) -> Option<MemberId> {
+        if let Some(maybe_mention) = maybe_mention {
+            if let Ok(mention) = Id::<UserMarker>::parse(maybe_mention) {
+                return MessageParser::get_member_id_from_user_id(mention, system_config)
+            }
+        }
+
+        None
+    }
+
+    fn get_member_id_from_user_id(user_id: UserId, system_config: &System) -> Option<MemberId> {
+        system_config.members.iter().enumerate()
+            .filter(|(_id, m)| m.user_id.is_some())
+            .find(|(_id, m)| m.user_id.unwrap() == user_id)
+            .map(|(id, _m)| id)
+    }
 }
 
 impl crate::config::Member {
diff --git a/src/system/mod.rs b/src/system/mod.rs
index 6c4d95f..b5cd1ab 100644
--- a/src/system/mod.rs
+++ b/src/system/mod.rs
@@ -206,6 +206,22 @@ impl Manager {
                 }
             },
 
+            message_parser::ParsedMessage::Command(Command::Edit(member_id, message_id, new_content)) => {
+                let bot = self.bots.get(&member_id).unwrap();
+
+                if let Ok(new_message) = bot.edit_message(message.channel_id, message_id, new_content).await {
+
+                    // If we just edited the most recently sent message in this channel, update
+                    // cache for future edit commands
+                    if self.send_cache.get(&new_message.channel_id).map_or(MessageId::new(1u64), |m| m.id) == message_id {
+                        self.send_cache.put(new_message.channel_id, new_message);
+                    }
+
+                    // Delete the command message
+                    let _ = bot.delete_message(message.channel_id, message.id).await;
+                }
+            }
+
             message_parser::ParsedMessage::Command(Command::UnknownCommand) => {
                 let member_id = if let Some((member_id, _)) = self.latch_state {
                     member_id