From 1ec205155c920f900646541d92e393a0a1e32751 Mon Sep 17 00:00:00 2001 From: Zechiax <106590288+Zechiax@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:25:29 +0200 Subject: [PATCH 1/3] add custom ping role to db model --- Asterion/Database/Models/ModrinthEntry.cs | 1 + ...418182429_add custom ping role.Designer.cs | 312 ++++++++++++++++++ .../20240418182429_add custom ping role.cs | 28 ++ 3 files changed, 341 insertions(+) create mode 100644 Asterion/Migrations/20240418182429_add custom ping role.Designer.cs create mode 100644 Asterion/Migrations/20240418182429_add custom ping role.cs diff --git a/Asterion/Database/Models/ModrinthEntry.cs b/Asterion/Database/Models/ModrinthEntry.cs index b191acf..40494ab 100644 --- a/Asterion/Database/Models/ModrinthEntry.cs +++ b/Asterion/Database/Models/ModrinthEntry.cs @@ -13,6 +13,7 @@ public class ModrinthEntry public virtual Array Array { get; set; } = null!; public ulong? CustomUpdateChannel { get; set; } + public ulong? CustomPingRole { get; set; } [Required] public string ProjectId { get; set; } = null!; diff --git a/Asterion/Migrations/20240418182429_add custom ping role.Designer.cs b/Asterion/Migrations/20240418182429_add custom ping role.Designer.cs new file mode 100644 index 0000000..623a815 --- /dev/null +++ b/Asterion/Migrations/20240418182429_add custom ping role.Designer.cs @@ -0,0 +1,312 @@ +// +using System; +using Asterion.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Asterion.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20240418182429_add custom ping role")] + partial class addcustompingrole + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.4"); + + modelBuilder.Entity("Asterion.Database.Models.Array", b => + { + b.Property("ArrayId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("ArrayId"); + + b.ToTable("Arrays"); + }); + + modelBuilder.Entity("Asterion.Database.Models.Guild", b => + { + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Active") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("GuildSettingsId") + .HasColumnType("INTEGER"); + + b.Property("ManageRole") + .HasColumnType("INTEGER"); + + b.Property("ModrinthArrayId") + .HasColumnType("INTEGER"); + + b.Property("PingRole") + .HasColumnType("INTEGER"); + + b.HasKey("GuildId"); + + b.HasIndex("ModrinthArrayId") + .IsUnique(); + + b.ToTable("Guilds"); + }); + + modelBuilder.Entity("Asterion.Database.Models.GuildSettings", b => + { + b.Property("GuildSettingsId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChangeLogMaxLength") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(2000L); + + b.Property("ChangelogStyle") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("CheckMessagesForModrinthLink") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("MessageStyle") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("RemoveOnLeave") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ShowChannelSelection") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ShowSubscribeButton") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.HasKey("GuildSettingsId"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("GuildSettings"); + }); + + modelBuilder.Entity("Asterion.Database.Models.ModrinthEntry", b => + { + b.Property("EntryId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArrayId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("CustomPingRole") + .HasColumnType("INTEGER"); + + b.Property("CustomUpdateChannel") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("ProjectId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("EntryId"); + + b.HasIndex("ArrayId"); + + b.HasIndex("GuildId"); + + b.HasIndex("ProjectId"); + + b.ToTable("ModrinthEntries"); + }); + + modelBuilder.Entity("Asterion.Database.Models.ModrinthInstanceStatistics", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Authors") + .HasColumnType("INTEGER"); + + b.Property("Files") + .HasColumnType("INTEGER"); + + b.Property("Projects") + .HasColumnType("INTEGER"); + + b.Property("Versions") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("ModrinthInstanceStatistics"); + }); + + modelBuilder.Entity("Asterion.Database.Models.ModrinthProject", b => + { + b.Property("ProjectId") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastCheckVersion") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("ProjectId"); + + b.ToTable("ModrinthProjects"); + }); + + modelBuilder.Entity("Asterion.Database.Models.TotalDownloads", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Downloads") + .HasColumnType("INTEGER"); + + b.Property("Followers") + .HasColumnType("INTEGER"); + + b.Property("ProjectId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("TotalDownloads"); + }); + + modelBuilder.Entity("Asterion.Database.Models.Guild", b => + { + b.HasOne("Asterion.Database.Models.Array", "ModrinthArray") + .WithOne("Guild") + .HasForeignKey("Asterion.Database.Models.Guild", "ModrinthArrayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ModrinthArray"); + }); + + modelBuilder.Entity("Asterion.Database.Models.GuildSettings", b => + { + b.HasOne("Asterion.Database.Models.Guild", "Guild") + .WithOne("GuildSettings") + .HasForeignKey("Asterion.Database.Models.GuildSettings", "GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("Asterion.Database.Models.ModrinthEntry", b => + { + b.HasOne("Asterion.Database.Models.Array", "Array") + .WithMany() + .HasForeignKey("ArrayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Asterion.Database.Models.Guild", "Guild") + .WithMany() + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Asterion.Database.Models.ModrinthProject", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Array"); + + b.Navigation("Guild"); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("Asterion.Database.Models.TotalDownloads", b => + { + b.HasOne("Asterion.Database.Models.ModrinthProject", "Project") + .WithMany("TotalDownloads") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("Asterion.Database.Models.Array", b => + { + b.Navigation("Guild") + .IsRequired(); + }); + + modelBuilder.Entity("Asterion.Database.Models.Guild", b => + { + b.Navigation("GuildSettings") + .IsRequired(); + }); + + modelBuilder.Entity("Asterion.Database.Models.ModrinthProject", b => + { + b.Navigation("TotalDownloads"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Asterion/Migrations/20240418182429_add custom ping role.cs b/Asterion/Migrations/20240418182429_add custom ping role.cs new file mode 100644 index 0000000..2f27a7b --- /dev/null +++ b/Asterion/Migrations/20240418182429_add custom ping role.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Asterion.Migrations +{ + /// + public partial class addcustompingrole : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CustomPingRole", + table: "ModrinthEntries", + type: "INTEGER", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CustomPingRole", + table: "ModrinthEntries"); + } + } +} From 8a22e497c0a318d8c5c69f9be595f649135072a1 Mon Sep 17 00:00:00 2001 From: Zechiax <106590288+Zechiax@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:25:39 +0200 Subject: [PATCH 2/3] update migration --- Asterion/Migrations/DataContextModelSnapshot.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Asterion/Migrations/DataContextModelSnapshot.cs b/Asterion/Migrations/DataContextModelSnapshot.cs index 8a05216..65753d3 100644 --- a/Asterion/Migrations/DataContextModelSnapshot.cs +++ b/Asterion/Migrations/DataContextModelSnapshot.cs @@ -15,7 +15,7 @@ partial class DataContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.5"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.4"); modelBuilder.Entity("Asterion.Database.Models.Array", b => { @@ -131,6 +131,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Created") .HasColumnType("TEXT"); + b.Property("CustomPingRole") + .HasColumnType("INTEGER"); + b.Property("CustomUpdateChannel") .HasColumnType("INTEGER"); From f2549cce4a68a63580a59a71dc0cdf41c82ac5d6 Mon Sep 17 00:00:00 2001 From: Zechiax <106590288+Zechiax@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:41:04 +0200 Subject: [PATCH 3/3] implement setting custom ping role --- Asterion/Interfaces/IDataService.cs | 4 +-- Asterion/Modules/GuildManagement.cs | 27 ++++++++++++---- Asterion/Services/DataService.cs | 32 ++++++++++++++++--- .../Modrinth/SendDiscordNotificationJob.cs | 6 ++++ 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/Asterion/Interfaces/IDataService.cs b/Asterion/Interfaces/IDataService.cs index 5ec4475..04336ef 100644 --- a/Asterion/Interfaces/IDataService.cs +++ b/Asterion/Interfaces/IDataService.cs @@ -133,6 +133,6 @@ public Task UpdateModrinthProjectAsync(string projectId, string? newVersio /// public Task ChangeModrinthEntryChannel(ulong guildId, string projectId, ulong newChannelId); - public Task SetPingRoleAsync(ulong guildId, ulong? roleId); - public Task GetPingRoleIdAsync(ulong guildId); + public Task SetPingRoleAsync(ulong guildId, ulong? roleId, string? projectId = null); + public Task GetPingRoleIdAsync(ulong guildId, string? projectId = null); } \ No newline at end of file diff --git a/Asterion/Modules/GuildManagement.cs b/Asterion/Modules/GuildManagement.cs index e4cd412..4c570c5 100644 --- a/Asterion/Modules/GuildManagement.cs +++ b/Asterion/Modules/GuildManagement.cs @@ -1,5 +1,6 @@ using System.Text; using Asterion.Attributes; +using Asterion.AutocompleteHandlers; using Asterion.Common; using Asterion.Interfaces; using Discord; @@ -78,25 +79,37 @@ await ModifyOriginalResponseAsync(x => [RequireUserPermission(GuildPermission.Administrator, Group = "ManageSubs")] [DoManageSubsRoleCheck(Group = "ManageSubs")] [SlashCommand("set-ping-role", "Sets the role, which will be notified every time a project gets an update")] - public async Task SetPingRole(IRole role) + public async Task SetPingRole(IRole role, [Autocomplete(typeof(SubscribedIdAutocompletionHandler))] + string? projectId = null) { await DeferAsync(true); - var success = await _dataService.SetPingRoleAsync(Context.Guild.Id, role.Id); + var success = await _dataService.SetPingRoleAsync(Context.Guild.Id, role.Id, projectId); if (success) - await FollowupAsync( - $"Ping role set to role {role.Mention} :white_check_mark: This role will be notified with each update"); + { + if (projectId is not null) + await FollowupAsync( + $"Ping role set to role {role.Mention} for project {projectId} :white_check_mark: This role will be notified with each update"); + else + { + await FollowupAsync( + $"Ping role set to role {role.Mention} :white_check_mark: This role will be notified with each update"); + } + } else + { await FollowupAsync("There was an error while setting the ping role, please try again later"); + } } [RequireUserPermission(GuildPermission.Administrator, Group = "ManageSubs")] [DoManageSubsRoleCheck(Group = "ManageSubs")] [SlashCommand("remove-ping-role", "Removes the ping role")] - public async Task RemovePingRole() + public async Task RemovePingRole([Autocomplete(typeof(SubscribedIdAutocompletionHandler))] + string? projectId = null) { await DeferAsync(true); - var oldRole = await _dataService.GetPingRoleIdAsync(Context.Guild.Id); + var oldRole = await _dataService.GetPingRoleIdAsync(Context.Guild.Id, projectId); if (oldRole.HasValue == false) { @@ -104,7 +117,7 @@ public async Task RemovePingRole() return; } - var success = await _dataService.SetPingRoleAsync(Context.Guild.Id, null); + var success = await _dataService.SetPingRoleAsync(Context.Guild.Id, null, projectId); if (success) await FollowupAsync( diff --git a/Asterion/Services/DataService.cs b/Asterion/Services/DataService.cs index cd55172..648204b 100644 --- a/Asterion/Services/DataService.cs +++ b/Asterion/Services/DataService.cs @@ -362,7 +362,7 @@ public async Task ChangeModrinthEntryChannel(ulong guildId, string project return true; } - public async Task SetPingRoleAsync(ulong guildId, ulong? roleId) + public async Task SetPingRoleAsync(ulong guildId, ulong? roleId, string? projectId = null) { using var scope = _services.CreateScope(); await using var db = scope.ServiceProvider.GetRequiredService(); @@ -371,22 +371,44 @@ public async Task SetPingRoleAsync(ulong guildId, ulong? roleId) if (guild is null) return false; - guild.PingRole = roleId; + if (projectId is null) + { + guild.PingRole = roleId; + } + else + { + var entry = db.ModrinthEntries.FirstOrDefault(x => x.GuildId == guildId && x.ProjectId == projectId); + + if (entry is null) return false; + + entry.CustomPingRole = roleId; + } await db.SaveChangesAsync(); return true; } - public async Task GetPingRoleIdAsync(ulong guildId) + public async Task GetPingRoleIdAsync(ulong guildId, string? projectId = null) { using var scope = _services.CreateScope(); await using var db = scope.ServiceProvider.GetRequiredService(); var guild = await GetGuildByIdAsync(guildId); - // Return null if guild does not exists, otherwise return ManageRole value - return guild?.PingRole; + if (projectId is not null) + { + var entry = db.ModrinthEntries.FirstOrDefault(x => x.GuildId == guildId && x.ProjectId == projectId); + + if (entry is null) return null; + + return entry.CustomPingRole; + } + else + { + // Return null if guild does not exists, otherwise return ManageRole value + return guild?.PingRole; + } } private async Task JoinGuild(SocketGuild guild) diff --git a/Asterion/Services/Modrinth/SendDiscordNotificationJob.cs b/Asterion/Services/Modrinth/SendDiscordNotificationJob.cs index 1f21314..8754aa5 100644 --- a/Asterion/Services/Modrinth/SendDiscordNotificationJob.cs +++ b/Asterion/Services/Modrinth/SendDiscordNotificationJob.cs @@ -99,6 +99,12 @@ private async Task SendNotifications(Project project, Version[] versions) } var pingRole = guild.PingRole is null ? null : channel.Guild.GetRole((ulong) guild.PingRole); + var customPingRole = entry.CustomPingRole; + + if (customPingRole.HasValue) + { + pingRole = channel.Guild.GetRole(customPingRole.Value); + } foreach (var version in versions.OrderBy(x => x.DatePublished)) {