// 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.Net; using Catalogger.Backend.Api.Middleware; using Catalogger.Backend.Extensions; using Microsoft.AspNetCore.Mvc; using Remora.Discord.API; using Remora.Discord.API.Abstractions.Objects; namespace Catalogger.Backend.Api; public partial class GuildsController { [HttpGet("ignored-users")] public async Task GetIgnoredUsersAsync(string id, CancellationToken ct = default) { var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); // not actually sure how long fetching members might take. timing it out after 10 seconds just in case // the underlying redis library doesn't support CancellationTokens so we don't pass it down // we just end the loop early if it expires cts.CancelAfter(TimeSpan.FromSeconds(10)); var (guildId, _) = await ParseGuildAsync(id); var guildConfig = await guildRepository.GetAsync(guildId); var output = new List(); foreach (var userId in guildConfig.Messages.IgnoredUsers) { if (cts.Token.IsCancellationRequested) break; var member = await memberCache.TryGetAsync(guildId, DiscordSnowflake.New(userId)); output.Add( new IgnoredUser( Id: userId, Tag: member != null ? member.User.Value.Tag() : "unknown user" ) ); } return Ok(output.OrderBy(i => i.Id)); } private record IgnoredUser(ulong Id, string Tag); [HttpPut("ignored-users/{userId}")] public async Task AddIgnoredUserAsync(string id, ulong userId) { var (guildId, _) = await ParseGuildAsync(id); var guildConfig = await guildRepository.GetAsync(guildId); IUser? user; var member = await memberCache.TryGetAsync(guildId, DiscordSnowflake.New(userId)); if (member != null) user = member.User.Value; else user = await userCache.GetUserAsync(DiscordSnowflake.New(userId)); if (user == null) throw new ApiError(HttpStatusCode.NotFound, ErrorCode.BadRequest, "User not found"); if (guildConfig.Messages.IgnoredUsers.Contains(user.ID.Value)) return Ok(new IgnoredUser(user.ID.Value, user.Tag())); guildConfig.Messages.IgnoredUsers.Add(user.ID.Value); await guildRepository.UpdateConfigAsync(guildId, guildConfig); return Ok(new IgnoredUser(user.ID.Value, user.Tag())); } [HttpDelete("ignored-users/{userId}")] public async Task RemoveIgnoredUserAsync(string id, ulong userId) { var (guildId, _) = await ParseGuildAsync(id); var guildConfig = await guildRepository.GetAsync(guildId); guildConfig.Messages.IgnoredUsers.Remove(userId); await guildRepository.UpdateConfigAsync(guildId, guildConfig); return NoContent(); } [HttpGet("users")] public async Task ListUsersAsync(string id, [FromQuery] string query) { var (guildId, _) = await ParseGuildAsync(id); var members = await memberCache.GetMemberNamesAsync(guildId, query); return Ok(members.OrderBy(m => m.Name).Select(m => new UserQueryResponse(m.Name, m.Id))); } private record UserQueryResponse(string Name, string Id); }