diff --git a/Commands/InteractionCommands/TrackingInteractions.cs b/Commands/InteractionCommands/TrackingInteractions.cs index a2e55d2..b00f9a7 100644 --- a/Commands/InteractionCommands/TrackingInteractions.cs +++ b/Commands/InteractionCommands/TrackingInteractions.cs @@ -7,12 +7,85 @@ internal class TrackingInteractions : ApplicationCommandModule public class TrackingSlashCommands { [SlashCommand("add", "Track a users messages.")] - public async Task TrackingAddSlashCmd(InteractionContext ctx, [Option("member", "The member to track.")] DiscordUser discordUser) + public async Task TrackingAddSlashCmd(InteractionContext ctx, [Option("member", "The member to track.")] DiscordUser discordUser, [Option("channels", "Optional channels to filter to. Use IDs or mentions, and separate with commas or spaces.")] string channels = "") { await ctx.DeferAsync(ephemeral: false); + + var channelsUpdated = false; + + // Resolve list of filter channels + List filterChannels = new(); + if (!string.IsNullOrEmpty(channels)) + { + channels = Regex.Replace(channels, ", +", ",").Trim(); // "#general-chat, #lounge" ~> "#general-chat,#lounge" & trim + var channelIds = channels.Split(' ', ','); + foreach (var channel in channelIds) + { + // If this is a channel mention, get the ID first + var channelId = channel.Replace("<#", "").Replace(">", ""); + + if (ulong.TryParse(channelId, out var id)) + { + if (!filterChannels.Contains(id)) + filterChannels.Add(id); + } + else + { + // Invalid ID; couldn't parse as ulong + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent($"{Program.cfgjson.Emoji.Error} I couldn't parse \"{channel}\" as a channel ID or mention! Please double-check it and try again.")); + return; + } + } + } + + // If we were passed nothing, filterChannels remains an empty List. Otherwise, it is populated with the parsed channel IDs + + // Compare to db; if there is a mismatch, replace whatever is already in the db with what was passed to this command + if (Program.db.HashExists("trackingChannels", discordUser.Id)) + { + var dbChannels = Program.db.HashGet("trackingChannels", discordUser.Id).ToString(); + string cmdChannels; + if (filterChannels.Count < 1) + { + // No channels were passed. If there are any in the db, remove them + if (await Program.db.HashExistsAsync("trackingChannels", discordUser.Id)) + { + await Program.db.HashDeleteAsync("trackingChannels", discordUser.Id); + channelsUpdated = true; + } + } + else + { + cmdChannels = JsonConvert.SerializeObject(filterChannels); + if (dbChannels != cmdChannels) + { + // Passed channels do not match db channels, update db + var newChannels = JsonConvert.SerializeObject(filterChannels); + await Program.db.HashSetAsync("trackingChannels", discordUser.Id, newChannels); + channelsUpdated = true; + } + } + } + else + { + // No channels in db; just add whatever was passed + // If nothing was passed, don't add anything + if (filterChannels.Count > 0) + { + var newChannels = JsonConvert.SerializeObject(filterChannels); + await Program.db.HashSetAsync("trackingChannels", discordUser.Id, newChannels); + channelsUpdated = true; + } + } if (Program.db.SetContains("trackedUsers", discordUser.Id)) { + if (channelsUpdated) + { + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent($"{Program.cfgjson.Emoji.Success} Successfully updated tracking for {discordUser.Mention}!")); + return; + } + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().WithContent($"{Program.cfgjson.Emoji.Error} This user is already tracked!")); return; } @@ -51,6 +124,7 @@ public async Task TrackingRemoveSlashCmd(InteractionContext ctx, [Option("member } await Program.db.SetRemoveAsync("trackedUsers", discordUser.Id); + await Program.db.HashDeleteAsync("trackingChannels", discordUser.Id); var channelId = Program.db.HashGet("trackingThreads", discordUser.Id); DiscordThreadChannel thread = (DiscordThreadChannel)await ctx.Client.GetChannelAsync((ulong)channelId); diff --git a/Events/MessageEvent.cs b/Events/MessageEvent.cs index 5ffbe77..e39c843 100644 --- a/Events/MessageEvent.cs +++ b/Events/MessageEvent.cs @@ -142,19 +142,26 @@ public static async Task MessageHandlerAsync(DiscordClient client, MockDiscordMe { if (Program.db.SetContains("trackedUsers", message.Author.Id)) { - DiscordThreadChannel relayThread; - - if (trackingThreadCache.ContainsKey(message.Author.Id)) - { - relayThread = trackingThreadCache[message.Author.Id]; - } - else + // Check current channel against tracking channels + var trackingChannels = await Program.db.HashGetAsync("trackingChannels", message.Author.Id); + if (trackingChannels.HasValue) { - relayThread = (DiscordThreadChannel)await client.GetChannelAsync((ulong)await Program.db.HashGetAsync("trackingThreads", message.Author.Id)); - trackingThreadCache.Add(message.Author.Id, relayThread); + var trackingChannelsList = JsonConvert.DeserializeObject>(trackingChannels); + if (trackingChannelsList.Count > 0) + { + // This user's tracking is filtered to channels; check the channel before relaying the msg to the tracking thread + var channels = JsonConvert.DeserializeObject>(trackingChannels); + if (channels.Contains(channel.Id) || channels.Contains(channel.Parent.Id)) + { + await RelayTrackedMessageAsync(client, message); + } + } + else + { + // This user's tracking is not filtered to channels, so just relay the msg to the tracking thread + await RelayTrackedMessageAsync(client, message); + } } - var _ = await relayThread.SendMessageAsync(await DiscordHelpers.GenerateMessageRelay(message.BaseMessage, true, true)); - } if (!isAnEdit && channel.IsPrivate && Program.cfgjson.LogChannels.ContainsKey("dms")) @@ -938,6 +945,29 @@ public static async Task InviteCheck(DiscordInvite? invite, MockDiscordMes return false; } } + + private static async Task RelayTrackedMessageAsync(DiscordClient client, DiscordMessage message) + { + await RelayTrackedMessageAsync(client, new MockDiscordMessage(message)); + } + private static async Task RelayTrackedMessageAsync(DiscordClient client, MockDiscordMessage message) + { + DiscordThreadChannel relayThread; + + if (trackingThreadCache.ContainsKey(message.Author.Id)) + { + relayThread = trackingThreadCache[message.Author.Id]; + } + else + { + relayThread = (DiscordThreadChannel)await client.GetChannelAsync( + (ulong)await Program.db.HashGetAsync("trackingThreads", message.Author.Id)); + trackingThreadCache.Add(message.Author.Id, relayThread); + } + + var _ = await relayThread.SendMessageAsync( + await DiscordHelpers.GenerateMessageRelay(message.BaseMessage, true, true)); + } } }