From fda66681b694f9e75f22eb9993fbf06417b3b6b4 Mon Sep 17 00:00:00 2001 From: skyjoshua Date: Sun, 1 Mar 2026 03:39:44 +0000 Subject: [PATCH] I am a failure :c --- Commands/AddCommand.cs | 52 ++++++++++++++++++ Commands/CreateCommand.cs | 73 ++++++++++++++++++++++++++ Commands/HelpCommand.cs | 1 + Services/DatabaseService.cs | 1 + Services/MessageService.cs | 43 +++++++++++++++ Services/ReactionRoleService.cs | 93 +++++++++++++++++++++++++++++++++ 6 files changed, 263 insertions(+) create mode 100644 Commands/AddCommand.cs create mode 100644 Commands/CreateCommand.cs diff --git a/Commands/AddCommand.cs b/Commands/AddCommand.cs new file mode 100644 index 0000000..f023d49 --- /dev/null +++ b/Commands/AddCommand.cs @@ -0,0 +1,52 @@ +using Reactor.Services; +using Valour.Sdk.Client; +using Valour.Sdk.Models; + +namespace Reactor.Commands +{ + public static class AddCommand + { + public static async Task Execute( + Dictionary channelCache, + long channelId, + long messageId, + string emoji, + long roleId, + ValourClient client, + Planet planet) + { + //Check if the current channel is in the cache (should never happen but you never know!) + if (!channelCache.TryGetValue(channelId, out var channel)) + { + Console.WriteLine($"Channel {channelId} not found in cache."); + return; + } + + //Check if the message id is a valid reaction message + if (!ReactionRoleService.Messages.TryGetValue(messageId, out var reactionMsg)) + { + await channel.SendMessageAsync($"Message ID {messageId} is not tracked as a reaction message."); + return; + } + + //Fetch recent messages + var recentMessages = await channel.GetLastMessagesAsync(50); + + //Try and find the message inside those recent messages + var message = recentMessages.FirstOrDefault(m => m.Id == messageId); + if (message == null) + { + await channel.SendMessageAsync("Could not find the message in the last 50 messages."); + return; + } + + // Add the emoji to the message + await message.AddReactionAsync(emoji); + + //Add reaction-role mapping to DB and Cache + await ReactionRoleService.AddReactionAsync(messageId, emoji, roleId); + + await channel.SendMessageAsync($"Added reaction {emoji} -> role {roleId} for message {messageId}"); + } + } +} \ No newline at end of file diff --git a/Commands/CreateCommand.cs b/Commands/CreateCommand.cs new file mode 100644 index 0000000..fae80e7 --- /dev/null +++ b/Commands/CreateCommand.cs @@ -0,0 +1,73 @@ +using Microsoft.Data.Sqlite; +using Reactor.Services; +using Valour.Sdk.Client; +using Valour.Sdk.Models; + +namespace Reactor.Commands +{ + public static class CreateCommand + { + //Sends a new Reaction Role Message and Stores it + public static async Task Execute( + ValourClient client, + Dictionary channelCache, + long channelId, + string content, + long planetId, + int deleteDelaySeconds = 5) + { + if (!channelCache.TryGetValue(channelId, out var channel)) + { + Console.WriteLine($"Channel {channelId} not found in cache."); + return; + } + + //Send the Message + var result = await channel.SendMessageAsync(content); + if (!result.Success || result.Data == null) + { + Console.WriteLine("Failed to send message."); + return; + } + + var sentMessage = result.Data; + await channel.SendMessageAsync($"This Reaction Message has the ID of: {sentMessage.Id}"); + + //Insert into DB + using var connection = new SqliteConnection("Data Source=reactor.db"); + await connection.OpenAsync(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = @" + INSERT INTO ReactionMessages (PlanetId, ChannelId, MessageId, DeleteDelaySeconds) + VALUES (@planetId, @channelId, @messageId, @delay); + SELECT last_insert_rowid(); + "; + cmd.Parameters.AddWithValue("@planetId", planetId); + cmd.Parameters.AddWithValue("@channelId", channelId); + cmd.Parameters.AddWithValue("@messageId", sentMessage.Id); + cmd.Parameters.AddWithValue("@delay", deleteDelaySeconds); + + var insertedId = (long)await cmd.ExecuteScalarAsync(); + + //Add to memory + ReactionRoleService.Messages[sentMessage.Id] = new Models.ReactionMessage + { + Id = insertedId, + PlanetId = planetId, + ChannelId = channelId, + MessageId = sentMessage.Id, + DeleteDelaySeconds = deleteDelaySeconds, + Reactions = new Dictionary() + }; + + //Subscribe events + sentMessage.ReactionAdded += async () => + { + await ReactionRoleService.HandleReactionAddedAsync(channelCache, sentMessage); + }; + + Console.WriteLine($"Created reaction message {sentMessage.Id} in channel {channelId}"); + } + } +} \ No newline at end of file diff --git a/Commands/HelpCommand.cs b/Commands/HelpCommand.cs index ff4e71a..6d488c8 100644 --- a/Commands/HelpCommand.cs +++ b/Commands/HelpCommand.cs @@ -9,6 +9,7 @@ public static class HelpCommand string helpMessage = $@"**Reactor Commands**: - `{prefix}help` - Shows this list. - `{prefix}source` - Shows my source code! + - `{prefix}create` - Creates the Reaction Message. "; if (channelCache.TryGetValue(channelId, out var channel)) diff --git a/Services/DatabaseService.cs b/Services/DatabaseService.cs index 771d3a9..76eee89 100644 --- a/Services/DatabaseService.cs +++ b/Services/DatabaseService.cs @@ -8,6 +8,7 @@ namespace Reactor.Services public static async Task InitializeAsync() { + //Connection frfr using var connection = new SqliteConnection(_connectionString); await connection.OpenAsync(); diff --git a/Services/MessageService.cs b/Services/MessageService.cs index c56af1a..39c5fbe 100644 --- a/Services/MessageService.cs +++ b/Services/MessageService.cs @@ -12,6 +12,7 @@ namespace Reactor.Services Message message, string prefix) { + //Bot cant reply to its self hahahahahaha loser! if (message.AuthorUserId == client.Me.Id) return; string content = message.Content ?? ""; @@ -31,6 +32,7 @@ namespace Reactor.Services string command = parts[0].ToLower(); string[] args = parts[1..]; + //Commands.. duh.. switch (command) { case "help": @@ -40,6 +42,47 @@ namespace Reactor.Services case "source": await SourceCommand.Execute(channelCache, channelId, memberPing); break; + + case "create": + if (parts.Length < 2) + { + await channelCache[channelId].SendMessageAsync($"{memberPing} Usage: {prefix}create "); + return; + } + + if (message.PlanetId == null) + { + await channelCache[channelId].SendMessageAsync($"{memberPing} Could not detect planet ID for this message. Please contact me if you are seeing this."); + return; + } + + var messageText = string.Join(' ', parts[1..]); + await CreateCommand.Execute(channelCache, channelId, messageText, message.PlanetId.Value); + break; + + case "add": + if (parts.Length < 4) + { + await channelCache[channelId].SendMessageAsync($"{memberPing} Usage: {prefix}add "); + return; + } + + if (!long.TryParse(parts[1], out var msgId)) + { + await channelCache[channelId].SendMessageAsync($"{memberPing} Invalid message ID."); + return; + } + + var emoji = parts[2]; + + if (!long.TryParse(parts[3], out var roleId)) + { + await channelCache[channelId].SendMessageAsync($"{memberPing} Invalid role ID."); + return; + } + + await AddCommand.Execute(channelCache, channelId, msgId, emoji, roleId, client, message.Planet); + break; } } } diff --git a/Services/ReactionRoleService.cs b/Services/ReactionRoleService.cs index 4573511..d0819b2 100644 --- a/Services/ReactionRoleService.cs +++ b/Services/ReactionRoleService.cs @@ -1,5 +1,7 @@ using Microsoft.Data.Sqlite; using Reactor.Models; +using Valour.Sdk.Client; +using Valour.Sdk.Models; namespace Reactor.Services { @@ -77,5 +79,96 @@ namespace Reactor.Services //Update Cache msg.Reactions[emoji] = roleId; } + + public static async Task HandleReactionAddedAsync( + Dictionary channelCache, + Message message) + { + if (!Messages.TryGetValue(message.Id, out var cachedMsg)) + return; + + if (!channelCache.TryGetValue(cachedMsg.ChannelId, out var channel)) + return; + + foreach (var kvp in message.Reactions) + { + string emoji = kvp.Emoji; + if (!cachedMsg.Reactions.TryGetValue(emoji, out var roleId)) + continue; + + //Fetch role name + var role = channel.Planet.Roles.FirstOrDefault(r => r.Id == roleId); + string roleName = role != null ? role.Name : $"Role {roleId}"; + + //Fetch member + var member = await channel.Planet.FetchMemberAsync(kvp.AuthorUserId); + if (member == null) return; + + //Apply role to user + await member.AddRoleAsync(roleId); + + //Confirmation + var confirm = await channel.SendMessageAsync($"«@m-{member.Id}» has been given the role {roleName}"); + await Task.Delay(cachedMsg.DeleteDelaySeconds * 1000); + await confirm.Data.DeleteAsync(); + } + } + + // public static async Task HandleReactionAddedAsync( + // ValourClient client, + // Dictionary channelCache, + // MessageReaction reaction) + // { + // if (!Messages.TryGetValue(reaction.MessageId, out var msg)) + // return; + + // if (!msg.Reactions.TryGetValue(reaction.Emoji, out var roleId)) + // return; + + // if (!channelCache.TryGetValue(msg.ChannelId, out var channel)) + // return; + + // var role = channel.Planet.Roles.FirstOrDefault(r => r.Id == roleId); + // string roleName = role != null ? role.Name : $"Role {roleId}"; + + // //Fetch the member + // var member = await channel.Planet.FetchMemberAsync(reaction.AuthorUserId); + // if (member == null) return; + + // //Add role + // await member.AddRoleAsync(roleId); + + // //Confirmation + // var confirm = await channel.SendMessageAsync($"«@m-{member.Id}» has been given the role {roleName}"); + // await Task.Delay(msg.DeleteDelaySeconds * 1000); + // await confirm.Data.DeleteAsync(); + // } + + // public static async Task HandleReactionRemovedAsync( + // ValourClient client, + // Dictionary channelCache, + // MessageReaction reaction) + // { + // if (!Messages.TryGetValue(reaction.MessageId, out var msg)) + // return; + + // if (!msg.Reactions.TryGetValue(reaction.Emoji, out var roleId)) + // return; + + // if (!channelCache.TryGetValue(msg.ChannelId, out var channel)) + // return; + + // var role = channel.Planet.Roles.FirstOrDefault(r => r.Id == roleId); + // string roleName = role != null ? role.Name : $"role {roleId}"; + + // var member = await channel.Planet.FetchMemberAsync(reaction.AuthorUserId); + // if (member == null) return; + + // await member.RemoveRoleAsync(roleId); + + // var confirm = await channel.SendMessageAsync($"«@m-{member.Id}» has been removed from the role {roleName}"); + // await Task.Delay(msg.DeleteDelaySeconds * 1000); + // await confirm.Data.DeleteAsync(); + // } } } \ No newline at end of file