diff --git a/Cocotte/Migrations/20230320145030_InitialCreate.Designer.cs b/Cocotte/Migrations/20230320145030_InitialCreate.Designer.cs deleted file mode 100644 index b20a371..0000000 --- a/Cocotte/Migrations/20230320145030_InitialCreate.Designer.cs +++ /dev/null @@ -1,122 +0,0 @@ -// -using Cocotte.Services; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Cocotte.Migrations -{ - [DbContext(typeof(CocotteContext))] - [Migration("20230320145030_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.4"); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.Activity", b => - { - b.Property("ActivityId") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ActivityName") - .HasColumnType("INTEGER"); - - b.Property("ActivityType") - .HasColumnType("INTEGER"); - - b.Property("CreatorId") - .HasColumnType("INTEGER"); - - b.Property("Description") - .HasColumnType("TEXT"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("MaxPlayers") - .HasColumnType("INTEGER"); - - b.HasKey("ActivityId"); - - b.ToTable("Activities"); - - b.HasDiscriminator("Discriminator").HasValue("Activity"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.ActivityPlayer", b => - { - b.Property("UserId") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ActivityId") - .HasColumnType("INTEGER"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PlayerName") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("UserId"); - - b.HasIndex("ActivityId"); - - b.ToTable("ActivityPlayers"); - - b.HasDiscriminator("Discriminator").HasValue("ActivityPlayer"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.StagedActivity", b => - { - b.HasBaseType("Cocotte.Modules.Activity.Models.Activity"); - - b.Property("Stage") - .HasColumnType("INTEGER"); - - b.HasDiscriminator().HasValue("StagedActivity"); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.ActivityRolePlayer", b => - { - b.HasBaseType("Cocotte.Modules.Activity.Models.ActivityPlayer"); - - b.Property("Roles") - .HasColumnType("INTEGER"); - - b.HasDiscriminator().HasValue("ActivityRolePlayer"); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.ActivityPlayer", b => - { - b.HasOne("Cocotte.Modules.Activity.Models.Activity", "Activity") - .WithMany("ActivityPlayers") - .HasForeignKey("ActivityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Activity"); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.Activity", b => - { - b.Navigation("ActivityPlayers"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Cocotte/Migrations/20230320145030_InitialCreate.cs b/Cocotte/Migrations/20230320145030_InitialCreate.cs deleted file mode 100644 index 5dc3fcc..0000000 --- a/Cocotte/Migrations/20230320145030_InitialCreate.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Cocotte.Migrations -{ - /// - public partial class InitialCreate : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Activities", - columns: table => new - { - ActivityId = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - CreatorId = table.Column(type: "INTEGER", nullable: false), - Description = table.Column(type: "TEXT", nullable: true), - ActivityType = table.Column(type: "INTEGER", nullable: false), - ActivityName = table.Column(type: "INTEGER", nullable: false), - MaxPlayers = table.Column(type: "INTEGER", nullable: false), - Discriminator = table.Column(type: "TEXT", nullable: false), - Stage = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Activities", x => x.ActivityId); - }); - - migrationBuilder.CreateTable( - name: "ActivityPlayers", - columns: table => new - { - UserId = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - PlayerName = table.Column(type: "TEXT", nullable: false), - ActivityId = table.Column(type: "INTEGER", nullable: false), - Discriminator = table.Column(type: "TEXT", nullable: false), - Roles = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_ActivityPlayers", x => x.UserId); - table.ForeignKey( - name: "FK_ActivityPlayers_Activities_ActivityId", - column: x => x.ActivityId, - principalTable: "Activities", - principalColumn: "ActivityId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_ActivityPlayers_ActivityId", - table: "ActivityPlayers", - column: "ActivityId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ActivityPlayers"); - - migrationBuilder.DropTable( - name: "Activities"); - } - } -} diff --git a/Cocotte/Migrations/CocotteContextModelSnapshot.cs b/Cocotte/Migrations/CocotteContextModelSnapshot.cs deleted file mode 100644 index a22a5e9..0000000 --- a/Cocotte/Migrations/CocotteContextModelSnapshot.cs +++ /dev/null @@ -1,119 +0,0 @@ -// -using Cocotte.Services; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Cocotte.Migrations -{ - [DbContext(typeof(CocotteContext))] - partial class CocotteContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.4"); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.Activity", b => - { - b.Property("ActivityId") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ActivityName") - .HasColumnType("INTEGER"); - - b.Property("ActivityType") - .HasColumnType("INTEGER"); - - b.Property("CreatorId") - .HasColumnType("INTEGER"); - - b.Property("Description") - .HasColumnType("TEXT"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("MaxPlayers") - .HasColumnType("INTEGER"); - - b.HasKey("ActivityId"); - - b.ToTable("Activities"); - - b.HasDiscriminator("Discriminator").HasValue("Activity"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.ActivityPlayer", b => - { - b.Property("UserId") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ActivityId") - .HasColumnType("INTEGER"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("PlayerName") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("UserId"); - - b.HasIndex("ActivityId"); - - b.ToTable("ActivityPlayers"); - - b.HasDiscriminator("Discriminator").HasValue("ActivityPlayer"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.StagedActivity", b => - { - b.HasBaseType("Cocotte.Modules.Activity.Models.Activity"); - - b.Property("Stage") - .HasColumnType("INTEGER"); - - b.HasDiscriminator().HasValue("StagedActivity"); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.ActivityRolePlayer", b => - { - b.HasBaseType("Cocotte.Modules.Activity.Models.ActivityPlayer"); - - b.Property("Roles") - .HasColumnType("INTEGER"); - - b.HasDiscriminator().HasValue("ActivityRolePlayer"); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.ActivityPlayer", b => - { - b.HasOne("Cocotte.Modules.Activity.Models.Activity", "Activity") - .WithMany("ActivityPlayers") - .HasForeignKey("ActivityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Activity"); - }); - - modelBuilder.Entity("Cocotte.Modules.Activity.Models.Activity", b => - { - b.Navigation("ActivityPlayers"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Cocotte/Modules/Activities/ActivityFormatter.cs b/Cocotte/Modules/Activities/ActivityFormatter.cs new file mode 100644 index 0000000..64ce343 --- /dev/null +++ b/Cocotte/Modules/Activities/ActivityFormatter.cs @@ -0,0 +1,96 @@ +using System.Text; +using Cocotte.Modules.Activities.Models; +using Cocotte.Options; +using Cocotte.Utils; +using Discord; +using Microsoft.Extensions.Options; + +namespace Cocotte.Modules.Activities; + +public class ActivityFormatter +{ + private readonly ActivityOptions _options; + + public ActivityFormatter(IOptions options) + { + _options = options.Value; + } + + public static string FormatActivityName(ActivityName activityName) + { + return activityName switch + { + ActivityName.Abyss => "Abîme du Néant", + ActivityName.Raids => "Raids", + ActivityName.FrontierClash => "Conflit Frontalier", + ActivityName.VoidRift => "Failles du Néant", + ActivityName.OriginsOfWar => "Origines de la Guerre", + ActivityName.JointOperation => "Opération Conjointe", + ActivityName.InterstellarExploration => "Exploration Interstellaire", + ActivityName.BreakFromDestiny => "Échapper au Destin (3v3)", + ActivityName.CriticalAbyss => "Abîme Critique (8v8)", + ActivityName.Event => "Event", + ActivityName.Fishing => "Pêche", + ActivityName.MirroriaRace => "Course Mirroria", + _ => throw new ArgumentOutOfRangeException(nameof(activityName), activityName, null) + }; + } + + public EmbedBuilder ActivityEmbed(Activity activity, IEnumerable players) + { + // Get activity emote + var activityEmote = GetActivityEmote(activity.Name); + + // Players field + var playersField = new EmbedFieldBuilder() + .WithName("Joueurs inscrits") + .WithValue($"{(!players.Any() ? "*Aucun joueur inscrit*" : string.Join("\n", players.Select(FormatActivityPlayer)))}"); + + return new EmbedBuilder() + .WithColor(Colors.CocotteBlue) + .WithTitle($"{activityEmote} {FormatActivityName(activity.Name)} ({players.Count()}/{activity.MaxPlayers})") + .WithDescription($"{activity.Description}") + .WithFields(playersField); + } + + private static string GetActivityEmote(ActivityName activityName) => activityName switch + { + ActivityName.Abyss => ":fox:", + ActivityName.Raids => ":crossed_swords:", + ActivityName.Fishing => ":fishing_pole_and_fish:", + _ => ":white_circle:" + }; + + public string FormatActivityPlayer(ActivityPlayer player) => player switch + { + ActivityRolePlayer rolePlayer => $"{player.Name} {RolesToEmotes(rolePlayer.Roles)}", + _ => $"{player.Name})" + }; + + private string RolesToEmotes(ActivityRoles rolePlayerRoles) + { + var emotesBuilder = new StringBuilder(); + + if (rolePlayerRoles.HasFlag(ActivityRoles.Helper)) + { + emotesBuilder.Append($"{_options.HelperEmote}/"); + } + + if (rolePlayerRoles.HasFlag(ActivityRoles.Dps)) + { + emotesBuilder.Append(_options.DpsEmote); + } + + if (rolePlayerRoles.HasFlag(ActivityRoles.Tank)) + { + emotesBuilder.Append(_options.TankEmote); + } + + if (rolePlayerRoles.HasFlag(ActivityRoles.Support)) + { + emotesBuilder.Append(_options.SupportEmote); + } + + return emotesBuilder.ToString(); + } +} \ No newline at end of file diff --git a/Cocotte/Modules/Activity/ActivityHelper.cs b/Cocotte/Modules/Activities/ActivityHelper.cs similarity index 71% rename from Cocotte/Modules/Activity/ActivityHelper.cs rename to Cocotte/Modules/Activities/ActivityHelper.cs index fb3bf5f..fcf4f66 100644 --- a/Cocotte/Modules/Activity/ActivityHelper.cs +++ b/Cocotte/Modules/Activities/ActivityHelper.cs @@ -2,7 +2,7 @@ using Discord.WebSocket; using Microsoft.Extensions.Options; -namespace Cocotte.Modules.Activity; +namespace Cocotte.Modules.Activities; public class ActivityHelper { @@ -15,28 +15,20 @@ public class ActivityHelper _options = options.Value; } - public ActivityRoles GetPlayerRoles(IReadOnlyCollection userRoles) + public ActivityRoles GetPlayerRoles(IEnumerable userRoles) { var roles = ActivityRoles.None; foreach (var socketRole in userRoles) { - if (socketRole.Id == _options.HelperRoleId) + roles |= socketRole.Id switch { - roles |= ActivityRoles.Helper; - } - else if (socketRole.Id == _options.DpsRoleId) - { - roles |= ActivityRoles.Dps; - } - else if (socketRole.Id == _options.TankRoleId) - { - roles |= ActivityRoles.Tank; - } - else if (socketRole.Id == _options.SupportRoleId) - { - roles |= ActivityRoles.Support; - } + var role when role == _options.HelperRoleId => ActivityRoles.Helper, + var role when role == _options.DpsRoleId => ActivityRoles.Dps, + var role when role == _options.TankRoleId => ActivityRoles.Tank, + var role when role == _options.SupportRoleId => ActivityRoles.Support, + _ => ActivityRoles.None + }; } return roles; diff --git a/Cocotte/Modules/Activity/ActivityModule.cs b/Cocotte/Modules/Activities/ActivityModule.cs similarity index 70% rename from Cocotte/Modules/Activity/ActivityModule.cs rename to Cocotte/Modules/Activities/ActivityModule.cs index 79915fc..1759b67 100644 --- a/Cocotte/Modules/Activity/ActivityModule.cs +++ b/Cocotte/Modules/Activities/ActivityModule.cs @@ -1,5 +1,5 @@ using System.Diagnostics.CodeAnalysis; -using Cocotte.Modules.Activity.Models; +using Cocotte.Modules.Activities.Models; using Cocotte.Options; using Cocotte.Utils; using Discord; @@ -7,7 +7,7 @@ using Discord.Interactions; using Discord.WebSocket; using Microsoft.Extensions.Options; -namespace Cocotte.Modules.Activity; +namespace Cocotte.Modules.Activities; /// /// Module to ask and propose groups for different activities: Abyss, OOW, FC, ... @@ -20,12 +20,14 @@ public class ActivityModule : InteractionModuleBase private readonly ActivityOptions _options; private readonly ActivityHelper _activityHelper; private readonly ActivitiesRepository _activitiesRepository; + private readonly ActivityFormatter _activityFormatter; - public ActivityModule(ILogger logger, IOptions options, ActivityHelper activityHelper, ActivitiesRepository activitiesRepository) + public ActivityModule(ILogger logger, IOptions options, ActivityHelper activityHelper, ActivitiesRepository activitiesRepository, ActivityFormatter activityFormatter) { _logger = logger; _activityHelper = activityHelper; _activitiesRepository = activitiesRepository; + _activityFormatter = activityFormatter; _options = options.Value; } @@ -41,7 +43,7 @@ public class ActivityModule : InteractionModuleBase """); } - [SlashCommand("abyss", "Créer un groupe pour l'Abîme du Néant")] + [SlashCommand("abime", "Créer un groupe pour l'Abîme du Néant")] public async Task ActivityAbyss([Summary("étage", "A quel étage êtes vous")] uint stage, [Summary("description", "Message accompagnant la demande de groupe")] string description = "") { const ActivityName activityName = ActivityName.Abyss; @@ -51,24 +53,25 @@ public class ActivityModule : InteractionModuleBase var activity = new StagedActivity { ActivityId = 0, - CreatorId = Context.User.Id, + CreatorDiscordId = Context.User.Id, + CreatorDiscordName = ((SocketGuildUser)Context.User).DisplayName, Description = description, - ActivityType = activityType, - ActivityName = activityName, + Type = activityType, + Name = activityName, MaxPlayers = maxPlayers, - Stage = stage, - ActivityPlayers = new() + Stage = stage }; await CreateRoleActivity(activity); } - private async Task CreateRoleActivity(Models.Activity activity) + private async Task CreateRoleActivity(Activity activity) { - _logger.LogTrace("Creating activity {Activity}", activity); + var user = (SocketGuildUser)Context.User; + _logger.LogTrace("{User} is creating activity {Activity}", user.DisplayName, activity); // Activities are identified using their original message id - await RespondAsync("`Création de l'activité en cours...`"); + await RespondAsync("> *Création de l'activité en cours...*"); var response = await GetOriginalResponseAsync(); activity.ActivityId = response.Id; @@ -76,6 +79,18 @@ public class ActivityModule : InteractionModuleBase // Add activity to db await _activitiesRepository.AddActivity(activity); + // Add creator to activity + var rolePlayer = new ActivityRolePlayer + { + Activity = activity, + DiscordId = user.Id, + Name = user.DisplayName, + Roles = _activityHelper.GetPlayerRoles(user.Roles) + }; + + activity.ActivityPlayers.Add(rolePlayer); + await _activitiesRepository.SaveChanges(); + // Add components var components = ActivityRoleComponent(activity.ActivityId); @@ -83,7 +98,7 @@ public class ActivityModule : InteractionModuleBase { m.Content = ""; m.Components = components.Build(); - // m.Embed = embed.Build(); + m.Embed = _activityFormatter.ActivityEmbed(activity, Enumerable.Repeat(rolePlayer, 1)).Build(); }); } @@ -117,12 +132,21 @@ public class ActivityModule : InteractionModuleBase _logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, activityId); var roles = _activityHelper.GetPlayerRoles(user.Roles); - var activityRolePlayer = new ActivityRolePlayer { UserId = user.Id, PlayerName = user.DisplayName, Roles = roles, ActivityId = activityId, Activity = activity }; + var activityRolePlayer = new ActivityRolePlayer + { + Activity = activity, + DiscordId = user.Id, + Name = user.DisplayName, + Roles = roles + }; // Add player to activity activity.ActivityPlayers.Add(activityRolePlayer); await _activitiesRepository.SaveChanges(); + // Update activity embed + await UpdateActivityEmbed(activity); + await RespondAsync( ephemeral: true, embed: EmbedUtils.SuccessEmbed("Vous avez bien été inscrit pour cette activité").Build() @@ -161,18 +185,40 @@ public class ActivityModule : InteractionModuleBase activity.ActivityPlayers.Remove(activityPlayer); await _activitiesRepository.SaveChanges(); + // Update activity embed + await UpdateActivityEmbed(activity); + await RespondAsync( ephemeral: true, embed: EmbedUtils.SuccessEmbed("Vous avez bien été désinscrit pour cette activité").Build() ); } - [ComponentInteraction("activity event_join:*", ignoreGroupNames: true)] - private async Task JoinEventActivity(ulong activityId) - { - _logger.LogTrace("Player {Player} joined activity {Id}", ((IGuildUser)Context.User).DisplayName, activityId); + // [ComponentInteraction("activity event_join:*", ignoreGroupNames: true)] + // private async Task JoinEventActivity(ulong activityId) + // { + // _logger.LogTrace("Player {Player} joined activity {Id}", ((IGuildUser)Context.User).DisplayName, activityId); + // + // await RespondAsync(activityId.ToString()); + // } - await RespondAsync(activityId.ToString()); + private async Task UpdateActivityEmbed(Activity activity) + { + // Get channel + var channel = await Context.Interaction.GetChannelAsync(); + + if (channel is null) + { + return; + } + + // Fetch players + var players = await _activitiesRepository.LoadActivityPlayers(activity); + + await channel.ModifyMessageAsync(activity.ActivityId, properties => + { + properties.Embed = _activityFormatter.ActivityEmbed(activity, players).Build(); + }); } private static ComponentBuilder ActivityRoleComponent(ulong activityId) diff --git a/Cocotte/Modules/Activity/ActivityName.cs b/Cocotte/Modules/Activities/ActivityName.cs similarity index 85% rename from Cocotte/Modules/Activity/ActivityName.cs rename to Cocotte/Modules/Activities/ActivityName.cs index 671e094..1793a02 100644 --- a/Cocotte/Modules/Activity/ActivityName.cs +++ b/Cocotte/Modules/Activities/ActivityName.cs @@ -1,4 +1,4 @@ -namespace Cocotte.Modules.Activity; +namespace Cocotte.Modules.Activities; public enum ActivityName { diff --git a/Cocotte/Modules/Activity/ActivityRoles.cs b/Cocotte/Modules/Activities/ActivityRoles.cs similarity index 77% rename from Cocotte/Modules/Activity/ActivityRoles.cs rename to Cocotte/Modules/Activities/ActivityRoles.cs index ea6e32c..8157420 100644 --- a/Cocotte/Modules/Activity/ActivityRoles.cs +++ b/Cocotte/Modules/Activities/ActivityRoles.cs @@ -1,4 +1,4 @@ -namespace Cocotte.Modules.Activity; +namespace Cocotte.Modules.Activities; [Flags] public enum ActivityRoles : byte diff --git a/Cocotte/Modules/Activity/ActivityType.cs b/Cocotte/Modules/Activities/ActivityType.cs similarity index 77% rename from Cocotte/Modules/Activity/ActivityType.cs rename to Cocotte/Modules/Activities/ActivityType.cs index 60890e9..5e9bacf 100644 --- a/Cocotte/Modules/Activity/ActivityType.cs +++ b/Cocotte/Modules/Activities/ActivityType.cs @@ -1,4 +1,4 @@ -namespace Cocotte.Modules.Activity; +namespace Cocotte.Modules.Activities; public enum ActivityType { diff --git a/Cocotte/Modules/Activities/Models/ActivitiesRepository.cs b/Cocotte/Modules/Activities/Models/ActivitiesRepository.cs new file mode 100644 index 0000000..2b3bed7 --- /dev/null +++ b/Cocotte/Modules/Activities/Models/ActivitiesRepository.cs @@ -0,0 +1,53 @@ +using Cocotte.Services; + +namespace Cocotte.Modules.Activities.Models; + +public class ActivitiesRepository +{ + private readonly CocotteDbContext _cocotteDbContext; + + public ActivitiesRepository(CocotteDbContext cocotteDbContext) + { + _cocotteDbContext = cocotteDbContext; + } + + public async Task FindActivity(ulong activityId) + { + return await _cocotteDbContext.Activities.FindAsync(activityId); + } + + public async Task FindStagedActivity(ulong activityId) + { + return await _cocotteDbContext.StagedActivities.FindAsync(activityId); + } + + public async Task FindActivityPlayer(ulong activityId, ulong playerId) + { + return await _cocotteDbContext.ActivityPlayers.FindAsync(activityId, playerId); + } + + public async Task FindActivityRolePlayer(ulong activityId, ulong playerId) + { + return await _cocotteDbContext.ActivityRolePlayers.FindAsync(activityId, playerId); + } + + public async Task> LoadActivityPlayers(Activity activity) + { + await _cocotteDbContext + .Entry(activity) + .Collection(a => a.ActivityPlayers) + .LoadAsync(); + + return activity.ActivityPlayers; + } + + public async Task AddActivity(Activity activity) + { + await _cocotteDbContext.AddAsync(activity); + } + + public async Task SaveChanges() + { + await _cocotteDbContext.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/Cocotte/Modules/Activities/Models/Activity.cs b/Cocotte/Modules/Activities/Models/Activity.cs new file mode 100644 index 0000000..ec96a52 --- /dev/null +++ b/Cocotte/Modules/Activities/Models/Activity.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Cocotte.Modules.Activities.Models; + +public abstract class Activity +{ + [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] + public required ulong ActivityId { get; set; } + + public required ulong CreatorDiscordId { get; init; } + public required string CreatorDiscordName { get; set; } + public string? Description { get; init; } + public required ActivityType Type { get; init; } + public required ActivityName Name { get; init; } + public required uint MaxPlayers { get; set; } + + public List ActivityPlayers { get; init; } = new(); + + public override string ToString() + { + return $"{nameof(ActivityId)}: {ActivityId}, {nameof(CreatorDiscordId)}: {CreatorDiscordId}, {nameof(Description)}: {Description}, {nameof(Type)}: {Type}, {nameof(Name)}: {Name}, {nameof(MaxPlayers)}: {MaxPlayers}"; + } +} \ No newline at end of file diff --git a/Cocotte/Modules/Activities/Models/ActivityPlayer.cs b/Cocotte/Modules/Activities/Models/ActivityPlayer.cs new file mode 100644 index 0000000..b9fe0ad --- /dev/null +++ b/Cocotte/Modules/Activities/Models/ActivityPlayer.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; + +namespace Cocotte.Modules.Activities.Models; + +[PrimaryKey(nameof(ActivityId), nameof(DiscordId))] +public class ActivityPlayer +{ + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public required ulong DiscordId { get; init; } + + public required string Name { get; init; } + + public ulong ActivityId { get; init; } + public required Activity Activity { get; init; } + + public override string ToString() + { + return $"{nameof(DiscordId)}: {DiscordId}, {nameof(Name)}: {Name}"; + } +} \ No newline at end of file diff --git a/Cocotte/Modules/Activity/Models/ActivityRolePlayer.cs b/Cocotte/Modules/Activities/Models/ActivityRolePlayer.cs similarity index 69% rename from Cocotte/Modules/Activity/Models/ActivityRolePlayer.cs rename to Cocotte/Modules/Activities/Models/ActivityRolePlayer.cs index c325230..2557a0e 100644 --- a/Cocotte/Modules/Activity/Models/ActivityRolePlayer.cs +++ b/Cocotte/Modules/Activities/Models/ActivityRolePlayer.cs @@ -1,4 +1,4 @@ -namespace Cocotte.Modules.Activity.Models; +namespace Cocotte.Modules.Activities.Models; public class ActivityRolePlayer : ActivityPlayer { diff --git a/Cocotte/Modules/Activity/Models/StagedActivity.cs b/Cocotte/Modules/Activities/Models/StagedActivity.cs similarity index 80% rename from Cocotte/Modules/Activity/Models/StagedActivity.cs rename to Cocotte/Modules/Activities/Models/StagedActivity.cs index 789f765..4f2431b 100644 --- a/Cocotte/Modules/Activity/Models/StagedActivity.cs +++ b/Cocotte/Modules/Activities/Models/StagedActivity.cs @@ -1,4 +1,4 @@ -namespace Cocotte.Modules.Activity.Models; +namespace Cocotte.Modules.Activities.Models; public class StagedActivity : Activity { diff --git a/Cocotte/Modules/Activity/ActivityFormatter.cs b/Cocotte/Modules/Activity/ActivityFormatter.cs deleted file mode 100644 index 77e913c..0000000 --- a/Cocotte/Modules/Activity/ActivityFormatter.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Cocotte.Modules.Activity; - -public class ActivityFormatter -{ - public static string ActivityName(ActivityName activityName) - { - return activityName switch - { - Modules.Activity.ActivityName.Abyss => "Abîme du Néant", - Modules.Activity.ActivityName.Raids => "Raids", - Modules.Activity.ActivityName.FrontierClash => "Clash Frontalier", - Modules.Activity.ActivityName.VoidRift => "Failles du Néant", - Modules.Activity.ActivityName.OriginsOfWar => "Origines de la Guerre", - Modules.Activity.ActivityName.JointOperation => "Opération Conjointe", - Modules.Activity.ActivityName.InterstellarExploration => "Exploration Interstellaire", - Modules.Activity.ActivityName.BreakFromDestiny => "Échapper au Destin (3v3)", - Modules.Activity.ActivityName.CriticalAbyss => "Abîme Critique (8v8)", - Modules.Activity.ActivityName.Event => "Event", - Modules.Activity.ActivityName.Fishing => "Pêche", - Modules.Activity.ActivityName.MirroriaRace => "Course Mirroria", - _ => throw new ArgumentOutOfRangeException(nameof(activityName), activityName, null) - }; - } -} \ No newline at end of file diff --git a/Cocotte/Modules/Activity/Models/ActivitiesRepository.cs b/Cocotte/Modules/Activity/Models/ActivitiesRepository.cs deleted file mode 100644 index 2aeeef4..0000000 --- a/Cocotte/Modules/Activity/Models/ActivitiesRepository.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Cocotte.Services; -using Microsoft.EntityFrameworkCore; - -namespace Cocotte.Modules.Activity.Models; - -public class ActivitiesRepository -{ - private readonly CocotteContext _cocotteContext; - - public ActivitiesRepository(CocotteContext cocotteContext) - { - _cocotteContext = cocotteContext; - } - - public async Task FindActivity(ulong activityId) - { - return await _cocotteContext.Activities.FindAsync(activityId); - } - - public async Task FindStagedActivity(ulong activityId) - { - return await _cocotteContext.StagedActivities.FindAsync(activityId); - } - - public async Task FindActivityPlayer(ulong activityId, ulong playerId) - { - return await _cocotteContext.ActivityPlayers.FindAsync(activityId, playerId); - } - - public async Task FindActivityRolePlayer(ulong activityId, ulong playerId) - { - return await _cocotteContext.ActivityRolePlayers.FindAsync(activityId, playerId); - } - - public async Task AddActivity(Activity activity) - { - await _cocotteContext.AddAsync(activity); - await _cocotteContext.SaveChangesAsync(); - } - - public async Task SaveChanges() - { - await _cocotteContext.SaveChangesAsync(); - } -} \ No newline at end of file diff --git a/Cocotte/Modules/Activity/Models/Activity.cs b/Cocotte/Modules/Activity/Models/Activity.cs deleted file mode 100644 index 366e119..0000000 --- a/Cocotte/Modules/Activity/Models/Activity.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; - -namespace Cocotte.Modules.Activity.Models; - -public abstract class Activity -{ - [Key] - public ulong ActivityId { get; set; } - - public ulong CreatorId { get; init; } - public string? Description { get; init; } - public ActivityType ActivityType { get; init; } - public ActivityName ActivityName { get; init; } - public uint MaxPlayers { get; set; } - - public List ActivityPlayers { get; init; } = new(); - - public override string ToString() - { - return $"{nameof(ActivityId)}: {ActivityId}, {nameof(CreatorId)}: {CreatorId}, {nameof(Description)}: {Description}, {nameof(ActivityType)}: {ActivityType}, {nameof(ActivityName)}: {ActivityName}, {nameof(MaxPlayers)}: {MaxPlayers}"; - } -} \ No newline at end of file diff --git a/Cocotte/Modules/Activity/Models/ActivityPlayer.cs b/Cocotte/Modules/Activity/Models/ActivityPlayer.cs deleted file mode 100644 index 25579f8..0000000 --- a/Cocotte/Modules/Activity/Models/ActivityPlayer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; - -namespace Cocotte.Modules.Activity.Models; - -[PrimaryKey(nameof(ActivityId), nameof(UserId))] -public class ActivityPlayer -{ - public ulong UserId { get; init; } - - public required string PlayerName { get; init; } - - public ulong ActivityId { get; init; } - public required Activity Activity { get; init; } - - public override string ToString() - { - return $"{nameof(UserId)}: {UserId}, {nameof(PlayerName)}: {PlayerName}"; - } -} \ No newline at end of file diff --git a/Cocotte/Program.cs b/Cocotte/Program.cs index 1fd388a..6867f06 100644 --- a/Cocotte/Program.cs +++ b/Cocotte/Program.cs @@ -1,5 +1,5 @@ -using Cocotte.Modules.Activity; -using Cocotte.Modules.Activity.Models; +using Cocotte.Modules.Activities; +using Cocotte.Modules.Activities.Models; using Cocotte.Modules.Raids; using Cocotte.Options; using Cocotte.Services; @@ -13,7 +13,7 @@ DiscordSocketConfig discordSocketConfig = new() { LogLevel = LogSeverity.Debug, MessageCacheSize = 200, - GatewayIntents = GatewayIntents.AllUnprivileged + GatewayIntents = GatewayIntents.GuildMembers | GatewayIntents.Guilds }; IHost host = Host.CreateDefaultBuilder(args) @@ -29,7 +29,7 @@ IHost host = Host.CreateDefaultBuilder(args) services.Configure(context.Configuration.GetSection(ActivityOptions.SectionName)); // Database - services.AddDbContext(options => + services.AddDbContext(options => options.UseSqlite(context.Configuration.GetConnectionString("CocotteContext")), ServiceLifetime.Transient, ServiceLifetime.Transient); services.AddTransient(); @@ -63,4 +63,17 @@ IHost host = Host.CreateDefaultBuilder(args) }) .Build(); +// Recreate database if in development environment +await using(var scope = host.Services.CreateAsyncScope()) +{ + var hostEnvironment = scope.ServiceProvider.GetRequiredService(); + + if (hostEnvironment.IsDevelopment()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + // await dbContext.Database.EnsureDeletedAsync(); + await dbContext.Database.EnsureCreatedAsync(); + } +} + await host.RunAsync(); \ No newline at end of file diff --git a/Cocotte/Properties/launchSettings.json b/Cocotte/Properties/launchSettings.json index 0f53703..3e65de3 100644 --- a/Cocotte/Properties/launchSettings.json +++ b/Cocotte/Properties/launchSettings.json @@ -7,6 +7,14 @@ "DOTNET_ENVIRONMENT": "Development" }, "workingDirectory": "bin/Debug/net7.0" + }, + "Cocotte-Prod": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Production" + }, + "workingDirectory": "bin/Debug/net7.0" } } } diff --git a/Cocotte/Services/CocotteContext.cs b/Cocotte/Services/CocotteDbContext.cs similarity index 68% rename from Cocotte/Services/CocotteContext.cs rename to Cocotte/Services/CocotteDbContext.cs index f64327c..7f98625 100644 --- a/Cocotte/Services/CocotteContext.cs +++ b/Cocotte/Services/CocotteDbContext.cs @@ -1,9 +1,9 @@ -using Cocotte.Modules.Activity.Models; +using Cocotte.Modules.Activities.Models; using Microsoft.EntityFrameworkCore; namespace Cocotte.Services; -public class CocotteContext : DbContext +public class CocotteDbContext : DbContext { public DbSet Activities => Set(); public DbSet StagedActivities => Set(); @@ -11,7 +11,7 @@ public class CocotteContext : DbContext public DbSet ActivityPlayers => Set(); public DbSet ActivityRolePlayers => Set(); - public CocotteContext(DbContextOptions options) : base(options) + public CocotteDbContext(DbContextOptions options) : base(options) { } diff --git a/Cocotte/Services/CocotteService.cs b/Cocotte/Services/CocotteService.cs index 8504b12..db8a65c 100644 --- a/Cocotte/Services/CocotteService.cs +++ b/Cocotte/Services/CocotteService.cs @@ -1,4 +1,5 @@ using System.Reflection; +using Cocotte.Modules.Activities; using Cocotte.Options; using Discord; using Discord.Interactions; @@ -51,7 +52,11 @@ public class CocotteService : BackgroundService } // Initialize modules and commands - await _interactionService.AddModulesAsync(Assembly.GetEntryAssembly(), _serviceProvider); + // await _interactionService.AddModulesAsync(Assembly.GetEntryAssembly(), _serviceProvider); + #if DEBUG + await _interactionService.AddModuleAsync(typeof(Modules.Ping.PingModule), _serviceProvider); + #endif + await _interactionService.AddModuleAsync(typeof(ActivityModule), _serviceProvider); _client.Ready += ClientOnReady; _client.InteractionCreated += HandleInteraction; diff --git a/Cocotte/Utils/EmbedUtils.cs b/Cocotte/Utils/EmbedUtils.cs index f1a06fe..279461e 100644 --- a/Cocotte/Utils/EmbedUtils.cs +++ b/Cocotte/Utils/EmbedUtils.cs @@ -4,7 +4,7 @@ namespace Cocotte.Utils; public static class EmbedUtils { - public static EmbedBuilder ErrorEmbed(string message, string title = "Error") + public static EmbedBuilder ErrorEmbed(string message, string title = "Erreur") { return new EmbedBuilder() .WithColor(Colors.ErrorColor) @@ -25,8 +25,8 @@ public static class EmbedUtils ) .WithDescription(message); } - - public static EmbedBuilder SuccessEmbed(string message, string title = "Success") + + public static EmbedBuilder SuccessEmbed(string message, string title = "Succès") { return new EmbedBuilder() .WithColor(Colors.SuccessColor) @@ -36,8 +36,8 @@ public static class EmbedUtils ) .WithDescription(message); } - - public static EmbedBuilder WarningEmbed(string message, string title = "Warning") + + public static EmbedBuilder WarningEmbed(string message, string title = "Attention") { return new EmbedBuilder() .WithColor(Colors.WarningColor) diff --git a/Cocotte/cocotte.db b/Cocotte/cocotte.db index 980611f..e69de29 100644 Binary files a/Cocotte/cocotte.db and b/Cocotte/cocotte.db differ