diff --git a/Catalogger.Backend/Api/Middleware/AuthenticationMiddleware.cs b/Catalogger.Backend/Api/Middleware/AuthenticationMiddleware.cs index 47447dc..5d2c888 100644 --- a/Catalogger.Backend/Api/Middleware/AuthenticationMiddleware.cs +++ b/Catalogger.Backend/Api/Middleware/AuthenticationMiddleware.cs @@ -16,12 +16,10 @@ using System.Net; using Catalogger.Backend.Database.Models; using Catalogger.Backend.Database.Repositories; -using NodaTime; namespace Catalogger.Backend.Api.Middleware; -public class AuthenticationMiddleware(ApiTokenRepository tokenRepository, IClock clock) - : IMiddleware +public class AuthenticationMiddleware(ApiTokenRepository tokenRepository) : IMiddleware { public async Task InvokeAsync(HttpContext ctx, RequestDelegate next) { diff --git a/Catalogger.Backend/Bot/Commands/IgnoreUserCommands.cs b/Catalogger.Backend/Bot/Commands/IgnoreUserCommands.cs new file mode 100644 index 0000000..2474031 --- /dev/null +++ b/Catalogger.Backend/Bot/Commands/IgnoreUserCommands.cs @@ -0,0 +1,117 @@ +// Copyright (C) 2021-present sam (starshines.gay) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +using System.ComponentModel; +using Catalogger.Backend.Cache; +using Catalogger.Backend.Cache.InMemoryCache; +using Catalogger.Backend.Database.Repositories; +using Catalogger.Backend.Extensions; +using Remora.Commands.Attributes; +using Remora.Commands.Groups; +using Remora.Discord.API; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Discord.Commands.Feedback.Services; +using Remora.Discord.Commands.Services; +using Remora.Discord.Pagination.Extensions; +using Remora.Rest.Core; +using IResult = Remora.Results.IResult; + +namespace Catalogger.Backend.Bot.Commands; + +[Group("ignored-users")] +[Description("Manage users ignored for logging.")] +public class IgnoreUserCommands( + GuildRepository guildRepository, + GuildCache guildCache, + IMemberCache memberCache, + UserCache userCache, + ContextInjectionService contextInjection, + FeedbackService feedbackService +) : CommandGroup +{ + [Command("add")] + [Description("Add a user to the list of ignored users.")] + public async Task AddIgnoredUserAsync([Description("The user to ignore")] IUser user) + { + var (_, guildId) = contextInjection.GetUserAndGuild(); + var guildConfig = await guildRepository.GetAsync(guildId); + + if (guildConfig.Channels.IgnoredUsers.Contains(user.ID.Value)) + return await feedbackService.ReplyAsync( + "That user is already being ignored.", + isEphemeral: true + ); + + guildConfig.Channels.IgnoredUsers.Add(user.ID.Value); + await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels); + + return await feedbackService.ReplyAsync( + $"Successfully added {user.PrettyFormat()} to the list of ignored users." + ); + } + + [Command("remove")] + [Description("Remove a user from the list of ignored users.")] + public async Task RemoveIgnoredUserAsync( + [Description("The user to stop ignoring")] IUser user + ) + { + var (_, guildId) = contextInjection.GetUserAndGuild(); + var guildConfig = await guildRepository.GetAsync(guildId); + + if (!guildConfig.Channels.IgnoredUsers.Contains(user.ID.Value)) + return await feedbackService.ReplyAsync( + "That user is already not ignored.", + isEphemeral: true + ); + + guildConfig.Channels.IgnoredUsers.Remove(user.ID.Value); + await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels); + + return await feedbackService.ReplyAsync( + $"Successfully removed {user.PrettyFormat()} from the list of ignored users." + ); + } + + [Command("list")] + [Description("List currently ignored users.")] + public async Task ListIgnoredUsersAsync() + { + var (userId, guildId) = contextInjection.GetUserAndGuild(); + if (!guildCache.TryGet(guildId, out var guild)) + throw new CataloggerError("Guild was not cached"); + + var guildConfig = await guildRepository.GetAsync(guildId); + + if (guildConfig.Channels.IgnoredUsers.Count == 0) + return await feedbackService.ReplyAsync("No users are being ignored right now."); + + var users = new List(); + foreach (var id in guildConfig.Channels.IgnoredUsers) + { + var user = await TryGetUserAsync(guildId, DiscordSnowflake.New(id)); + users.Add(user?.PrettyFormat() ?? $"*(unknown user {id})* <@{id}>"); + } + + return await feedbackService.SendContextualPaginatedMessageAsync( + userId, + DiscordUtils.PaginateStrings(users, $"Ignored users for {guild.Name} ({users.Count})") + ); + } + + private async Task TryGetUserAsync(Snowflake guildId, Snowflake userId) => + (await memberCache.TryGetAsync(guildId, userId))?.User.Value + ?? await userCache.GetUserAsync(userId); +} diff --git a/Catalogger.Backend/Bot/DiscordUtils.cs b/Catalogger.Backend/Bot/DiscordUtils.cs index 8e0a867..b6512d1 100644 --- a/Catalogger.Backend/Bot/DiscordUtils.cs +++ b/Catalogger.Backend/Bot/DiscordUtils.cs @@ -44,4 +44,28 @@ public static class DiscordUtils description, new Embed(Title: title, Colour: Purple) ); + + public static List PaginateStrings( + IEnumerable strings, + Optional title = default, + int stringsPerPage = 20 + ) + { + var pages = strings.ToArray().Split(stringsPerPage); + return pages + .Select(p => new Embed( + Title: title, + Colour: Purple, + Description: string.Join("\n", p.Select((row, i) => $"{i + 1}. {row}")) + )) + .ToList(); + } + + private static IEnumerable> Split(this T[] arr, int size) + { + for (var i = 0; i < arr.Length / size + 1; i++) + { + yield return arr.Skip(i * size).Take(size); + } + } } diff --git a/Catalogger.Backend/Program.cs b/Catalogger.Backend/Program.cs index 8516224..45d9904 100644 --- a/Catalogger.Backend/Program.cs +++ b/Catalogger.Backend/Program.cs @@ -94,6 +94,7 @@ builder .WithCommandGroup() .WithCommandGroup() .WithCommandGroup() + .WithCommandGroup() // End command tree .Finish() .AddPagination()