From a4622208c5cd930d6d46301de71d2abd94d519e2 Mon Sep 17 00:00:00 2001 From: GianniKoch Date: Mon, 23 Oct 2023 20:48:42 +0200 Subject: [PATCH 1/2] Added mod mail slash command to utils module. --- .../Modules/UtilSlashCommandsModule.cs | 4 + .../Utils/ModMailSlashCommands.cs | 50 +++++++ .../Utils/ServiceCollectionExtensions.cs | 2 +- .../POI.Persistence.Domain/ServerSettings.cs | 6 +- ...231023180711_ModMailMigrations.Designer.cs | 137 ++++++++++++++++++ .../20231023180711_ModMailMigrations.cs | 28 ++++ .../Migrations/AppDbContextModelSnapshot.cs | 5 +- 7 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs create mode 100644 source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.Designer.cs create mode 100644 source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.cs diff --git a/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs b/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs index 265abc2c..c595eb25 100644 --- a/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs +++ b/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs @@ -20,5 +20,9 @@ await ctx [SlashCommand("uppy", "Shows how long I've been online already 😅"), UsedImplicitly] public Task HandleUptimeCommand(InteractionContext ctx) => ctx.Services.GetRequiredService().Handle(ctx); + + [SlashCommand("modmail", "Send a message to the mods."), UsedImplicitly] + public Task HandleSilentMessageCommand(InteractionContext ctx, [Option("Message", "Your message for the moderators.", true)] string message) + => ctx.Services.GetRequiredService().Handle(ctx, message); } } \ No newline at end of file diff --git a/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs b/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs new file mode 100644 index 00000000..987fc533 --- /dev/null +++ b/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs @@ -0,0 +1,50 @@ +using DSharpPlus.Entities; +using DSharpPlus.SlashCommands; +using Microsoft.Extensions.Logging; +using POI.DiscordDotNet.Commands.SlashCommands.Modules; +using POI.Persistence.Repositories; + +namespace POI.DiscordDotNet.Commands.SlashCommands.Utils; + +public class ModMailSlashCommands : UtilSlashCommandsModule +{ + private readonly IServerSettingsRepository _serverSettingsRepository; + private readonly ILogger _logger + ; + + public ModMailSlashCommands(IServerSettingsRepository serverSettingsRepository, ILogger logger) + { + _serverSettingsRepository = serverSettingsRepository; + _logger = logger; + } + + public async Task Handle(InteractionContext ctx, string message) + { + await ctx.CreateResponseAsync("Message has been sent.", true).ConfigureAwait(false); + var serverId = ctx.Guild.Id; + var serverSettings = await _serverSettingsRepository.FindOneById(serverId); + if (serverSettings?.ModMailChannelId == null) + { + _logger.LogWarning("Server settings or ModMailChannelId for {ServerId} not found", serverId); + return; + } + + var channelId = serverSettings.ModMailChannelId!.Value; + DiscordChannel channel; + try{ + channel = await ctx.Client.GetChannelAsync(channelId); + } + catch (Exception e) + { + _logger.LogWarning(e, "Channel {ChannelId} not found for server {ServerId}",channelId, serverId); + return; + } + + var embed = new DiscordEmbedBuilder() + .WithTitle($"New mod mail from {ctx.User.Username}") + .WithDescription(message) + .WithTimestamp(DateTimeOffset.UtcNow) + .Build(); + await channel.SendMessageAsync(embed).ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ServiceCollectionExtensions.cs b/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ServiceCollectionExtensions.cs index afa37f87..bcc7beb2 100644 --- a/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ServiceCollectionExtensions.cs +++ b/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ServiceCollectionExtensions.cs @@ -5,5 +5,5 @@ namespace POI.DiscordDotNet.Commands.SlashCommands.Utils; public static class ServiceCollectionExtensions { public static IServiceCollection AddUtilitySlashCommands(this IServiceCollection services) => services - .AddTransient(); + .AddTransient().AddTransient(); } \ No newline at end of file diff --git a/source/POI.Persistence.Domain/ServerSettings.cs b/source/POI.Persistence.Domain/ServerSettings.cs index a5812071..d1f76abb 100644 --- a/source/POI.Persistence.Domain/ServerSettings.cs +++ b/source/POI.Persistence.Domain/ServerSettings.cs @@ -14,7 +14,10 @@ public class ServerSettings public uint? StarboardEmojiCount { get; set; } - public ServerSettings(ulong serverId, ulong? rankUpFeedChannelId = null, ulong? birthdayRoleId = null, ulong? starboardChannelId = null, ulong? eventsChannelId = null, uint? starboardEmojiCount = null) + public ulong? ModMailChannelId { get; set; } + + public ServerSettings(ulong serverId, ulong? rankUpFeedChannelId = null, ulong? birthdayRoleId = null, ulong? starboardChannelId = null, ulong? eventsChannelId = null, + uint? starboardEmojiCount = null, ulong? modMailChannelId = null) { ServerId = serverId; RankUpFeedChannelId = rankUpFeedChannelId; @@ -22,6 +25,7 @@ public ServerSettings(ulong serverId, ulong? rankUpFeedChannelId = null, ulong? StarboardChannelId = starboardChannelId; EventsChannelId = eventsChannelId; StarboardEmojiCount = starboardEmojiCount; + ModMailChannelId = modMailChannelId; } } } \ No newline at end of file diff --git a/source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.Designer.cs b/source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.Designer.cs new file mode 100644 index 00000000..b6747884 --- /dev/null +++ b/source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.Designer.cs @@ -0,0 +1,137 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using POI.Persistence.EFCore.Npgsql.Infrastructure; + +#nullable disable + +namespace POI.Persistence.EFCore.Npgsql.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20231023180711_ModMailMigrations")] + partial class ModMailMigrations + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("POI.Persistence.Domain.GlobalUserSettings", b => + { + b.Property("DiscordUserId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)"); + + b.Property("Birthday") + .HasColumnType("date"); + + b.Property("ScoreSaberId") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("DiscordUserId"); + + b.HasIndex("ScoreSaberId") + .IsUnique(); + + b.ToTable("GlobalUserSettings"); + }); + + modelBuilder.Entity("POI.Persistence.Domain.LeaderboardEntry", b => + { + b.Property("ScoreSaberId") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CountryRank") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Pp") + .HasColumnType("double precision"); + + b.HasKey("ScoreSaberId"); + + b.ToTable("LeaderboardEntries"); + }); + + modelBuilder.Entity("POI.Persistence.Domain.ServerDependentUserSettings", b => + { + b.Property("DiscordUserId") + .HasColumnType("numeric(20,0)"); + + b.Property("ServerId") + .HasColumnType("numeric(20,0)"); + + b.Property("Permissions") + .HasColumnType("integer"); + + b.HasKey("DiscordUserId", "ServerId"); + + b.ToTable("ServerDependentUserSettings"); + }); + + modelBuilder.Entity("POI.Persistence.Domain.ServerSettings", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)"); + + b.Property("BirthdayRoleId") + .HasColumnType("numeric(20,0)"); + + b.Property("EventsChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("ModMailChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("RankUpFeedChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("StarboardChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("StarboardEmojiCount") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.ToTable("ServerSettings"); + }); + + modelBuilder.Entity("POI.Persistence.Domain.StarboardMessages", b => + { + b.Property("ServerId") + .HasColumnType("numeric(20,0)"); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)"); + + b.Property("StarboardMessageId") + .HasColumnType("numeric(20,0)"); + + b.HasKey("ServerId", "ChannelId", "MessageId"); + + b.ToTable("StarboardMessages"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.cs b/source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.cs new file mode 100644 index 00000000..c2d149aa --- /dev/null +++ b/source/POI.Persistence.EFCore.Npgsql/Migrations/20231023180711_ModMailMigrations.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace POI.Persistence.EFCore.Npgsql.Migrations +{ + /// + public partial class ModMailMigrations : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ModMailChannelId", + table: "ServerSettings", + type: "numeric(20,0)", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ModMailChannelId", + table: "ServerSettings"); + } + } +} diff --git a/source/POI.Persistence.EFCore.Npgsql/Migrations/AppDbContextModelSnapshot.cs b/source/POI.Persistence.EFCore.Npgsql/Migrations/AppDbContextModelSnapshot.cs index e066f362..3f91e245 100644 --- a/source/POI.Persistence.EFCore.Npgsql/Migrations/AppDbContextModelSnapshot.cs +++ b/source/POI.Persistence.EFCore.Npgsql/Migrations/AppDbContextModelSnapshot.cs @@ -18,7 +18,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.9") + .HasAnnotation("ProductVersion", "7.0.10") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -93,6 +93,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EventsChannelId") .HasColumnType("numeric(20,0)"); + b.Property("ModMailChannelId") + .HasColumnType("numeric(20,0)"); + b.Property("RankUpFeedChannelId") .HasColumnType("numeric(20,0)"); From 12068c0e3920e5d80ea2c16e41ef501469481472 Mon Sep 17 00:00:00 2001 From: GianniKoch Date: Mon, 23 Oct 2023 20:55:38 +0200 Subject: [PATCH 2/2] Added option to for an anonymous message. --- .../SlashCommands/Modules/UtilSlashCommandsModule.cs | 4 ++-- .../Commands/SlashCommands/Utils/ModMailSlashCommands.cs | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs b/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs index c595eb25..43d7df7e 100644 --- a/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs +++ b/source/POI.DiscordDotNet/Commands/SlashCommands/Modules/UtilSlashCommandsModule.cs @@ -22,7 +22,7 @@ public Task HandleUptimeCommand(InteractionContext ctx) => ctx.Services.GetRequiredService().Handle(ctx); [SlashCommand("modmail", "Send a message to the mods."), UsedImplicitly] - public Task HandleSilentMessageCommand(InteractionContext ctx, [Option("Message", "Your message for the moderators.", true)] string message) - => ctx.Services.GetRequiredService().Handle(ctx, message); + public Task HandleSilentMessageCommand(InteractionContext ctx, [Option("Message", "Your message for the moderators.", true)] string message, [Option("Anonymously", "Whether you want to remain anonymously.")] bool anonymously = false) + => ctx.Services.GetRequiredService().Handle(ctx, message, anonymously); } } \ No newline at end of file diff --git a/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs b/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs index 987fc533..36f63dd5 100644 --- a/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs +++ b/source/POI.DiscordDotNet/Commands/SlashCommands/Utils/ModMailSlashCommands.cs @@ -18,7 +18,7 @@ public ModMailSlashCommands(IServerSettingsRepository serverSettingsRepository, _logger = logger; } - public async Task Handle(InteractionContext ctx, string message) + public async Task Handle(InteractionContext ctx, string message, bool anonymously) { await ctx.CreateResponseAsync("Message has been sent.", true).ConfigureAwait(false); var serverId = ctx.Guild.Id; @@ -39,12 +39,13 @@ public async Task Handle(InteractionContext ctx, string message) _logger.LogWarning(e, "Channel {ChannelId} not found for server {ServerId}",channelId, serverId); return; } - + var name = anonymously ? "Anonymous" : ctx.User.Username; var embed = new DiscordEmbedBuilder() - .WithTitle($"New mod mail from {ctx.User.Username}") + .WithTitle($"New mod mail from {name}") .WithDescription(message) .WithTimestamp(DateTimeOffset.UtcNow) .Build(); await channel.SendMessageAsync(embed).ConfigureAwait(false); + _logger.LogInformation("Mod mail sent from {UserId} to {ChannelId} on {ServerId}", name, channelId, serverId); } } \ No newline at end of file