diff --git a/Cocotte/Cocotte.csproj b/Cocotte/Cocotte.csproj
index 7f7576f..9399762 100644
--- a/Cocotte/Cocotte.csproj
+++ b/Cocotte/Cocotte.csproj
@@ -9,6 +9,18 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+ PreserveNewest
+
+
diff --git a/Cocotte/Migrations/20230320145030_InitialCreate.Designer.cs b/Cocotte/Migrations/20230320145030_InitialCreate.Designer.cs
new file mode 100644
index 0000000..b20a371
--- /dev/null
+++ b/Cocotte/Migrations/20230320145030_InitialCreate.Designer.cs
@@ -0,0 +1,122 @@
+//
+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
new file mode 100644
index 0000000..5dc3fcc
--- /dev/null
+++ b/Cocotte/Migrations/20230320145030_InitialCreate.cs
@@ -0,0 +1,70 @@
+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
new file mode 100644
index 0000000..a22a5e9
--- /dev/null
+++ b/Cocotte/Migrations/CocotteContextModelSnapshot.cs
@@ -0,0 +1,119 @@
+//
+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/Activity/Activity.cs b/Cocotte/Modules/Activity/Activity.cs
deleted file mode 100644
index 2bf01ad..0000000
--- a/Cocotte/Modules/Activity/Activity.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace Cocotte.Modules.Activity;
-
-public abstract record Activity(ulong Owner, string Description, ActivityType ActivityType, ActivityName ActivityName, uint MaxPlayers);
diff --git a/Cocotte/Modules/Activity/ActivityModule.cs b/Cocotte/Modules/Activity/ActivityModule.cs
index b295c2f..79915fc 100644
--- a/Cocotte/Modules/Activity/ActivityModule.cs
+++ b/Cocotte/Modules/Activity/ActivityModule.cs
@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
+using Cocotte.Modules.Activity.Models;
using Cocotte.Options;
using Cocotte.Utils;
using Discord;
@@ -18,11 +19,13 @@ public class ActivityModule : InteractionModuleBase
private readonly ILogger _logger;
private readonly ActivityOptions _options;
private readonly ActivityHelper _activityHelper;
+ private readonly ActivitiesRepository _activitiesRepository;
- public ActivityModule(ILogger logger, IOptions options, ActivityHelper activityHelper)
+ public ActivityModule(ILogger logger, IOptions options, ActivityHelper activityHelper, ActivitiesRepository activitiesRepository)
{
_logger = logger;
_activityHelper = activityHelper;
+ _activitiesRepository = activitiesRepository;
_options = options.Value;
}
@@ -39,19 +42,28 @@ public class ActivityModule : InteractionModuleBase
}
[SlashCommand("abyss", "Créer un groupe pour l'Abîme du Néant")]
- public async Task GroupAbyss([Summary("étage", "A quel étage êtes vous")] uint stage, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
+ 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;
var activityType = ActivityHelper.ActivityNameToType(activityName);
var maxPlayers = ActivityHelper.ActivityTypeToMaxPlayers(activityType);
- var activityId = Context.Interaction.Id;
- var activity = new StagedActivity(Context.User.Id, description, activityType, activityName, maxPlayers, stage);
+ var activity = new StagedActivity
+ {
+ ActivityId = 0,
+ CreatorId = Context.User.Id,
+ Description = description,
+ ActivityType = activityType,
+ ActivityName = activityName,
+ MaxPlayers = maxPlayers,
+ Stage = stage,
+ ActivityPlayers = new()
+ };
- await CreateActivity(activity);
+ await CreateRoleActivity(activity);
}
- private async Task CreateActivity(Activity activity)
+ private async Task CreateRoleActivity(Models.Activity activity)
{
_logger.LogTrace("Creating activity {Activity}", activity);
@@ -59,10 +71,13 @@ public class ActivityModule : InteractionModuleBase
await RespondAsync("`Création de l'activité en cours...`");
var response = await GetOriginalResponseAsync();
- var activityId = response.Id;
+ activity.ActivityId = response.Id;
+
+ // Add activity to db
+ await _activitiesRepository.AddActivity(activity);
// Add components
- var components = ActivityComponent(activityId);
+ var components = ActivityRoleComponent(activity.ActivityId);
await ModifyOriginalResponseAsync(m =>
{
@@ -72,15 +87,41 @@ public class ActivityModule : InteractionModuleBase
});
}
- [ComponentInteraction("activity join:*", ignoreGroupNames: true)]
- private async Task JoinActivity(ulong activityId)
+ [ComponentInteraction("activity join_role:*", ignoreGroupNames: true)]
+ private async Task JoinActivityRole(ulong activityId)
{
var user = (SocketGuildUser)Context.User;
+ // Check if activity exists
+ if (await _activitiesRepository.FindActivity(activityId) is not { } activity)
+ {
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.ErrorEmbed("Cette activité n'existe plus").Build()
+ );
+
+ return;
+ }
+
+ // If player is already registered
+ if (await _activitiesRepository.FindActivityRolePlayer(activityId, user.Id) is not null)
+ {
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.ErrorEmbed("Vous êtes déjà inscrit à cette activité").Build()
+ );
+
+ return;
+ }
+
_logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, activityId);
var roles = _activityHelper.GetPlayerRoles(user.Roles);
- var activityPlayer = new ActivityRolePlayer(user.Id, user.DisplayName, roles);
+ var activityRolePlayer = new ActivityRolePlayer { UserId = user.Id, PlayerName = user.DisplayName, Roles = roles, ActivityId = activityId, Activity = activity };
+
+ // Add player to activity
+ activity.ActivityPlayers.Add(activityRolePlayer);
+ await _activitiesRepository.SaveChanges();
await RespondAsync(
ephemeral: true,
@@ -88,14 +129,37 @@ public class ActivityModule : InteractionModuleBase
);
}
- [ComponentInteraction("activity leave:*", ignoreGroupNames: true)]
- private async Task LeaveActivity(ulong activityId)
+ [ComponentInteraction("activity leave_role:*", ignoreGroupNames: true)]
+ private async Task LeaveActivityRole(ulong activityId)
{
- var user = (SocketGuildUser)Context.User;
+ var user = (IGuildUser)Context.User;
+
+ // Check if activity exists
+ if (await _activitiesRepository.FindActivity(activityId) is not { } activity)
+ {
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.ErrorEmbed("Cette activité n'existe plus").Build()
+ );
+
+ return;
+ }
+
+ // Check if player is in activity
+ if (await _activitiesRepository.FindActivityPlayer(activityId, user.Id) is not { } activityPlayer)
+ {
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.ErrorEmbed("Vous n'êtes pas inscrit à cette activité").Build()
+ );
+
+ return;
+ }
_logger.LogTrace("Player {Player} left activity {Id}", user.DisplayName, activityId);
- // TODO: remove the user from the activity
+ activity.ActivityPlayers.Remove(activityPlayer);
+ await _activitiesRepository.SaveChanges();
await RespondAsync(
ephemeral: true,
@@ -106,23 +170,23 @@ public class ActivityModule : InteractionModuleBase
[ComponentInteraction("activity event_join:*", ignoreGroupNames: true)]
private async Task JoinEventActivity(ulong activityId)
{
- _logger.LogTrace("Player {Player} joined activity {Id}", ((SocketGuildUser)Context.User).DisplayName, activityId);
+ _logger.LogTrace("Player {Player} joined activity {Id}", ((IGuildUser)Context.User).DisplayName, activityId);
await RespondAsync(activityId.ToString());
}
- private static ComponentBuilder ActivityComponent(ulong activityId)
+ private static ComponentBuilder ActivityRoleComponent(ulong activityId)
{
return new ComponentBuilder()
.AddRow(new ActionRowBuilder()
.WithButton(new ButtonBuilder()
.WithLabel("Rejoindre l'activité")
- .WithCustomId($"activity join:{activityId}")
+ .WithCustomId($"activity join_role:{activityId}")
.WithStyle(ButtonStyle.Primary)
)
.WithButton(new ButtonBuilder()
.WithLabel("Se désinscrire de l'activité")
- .WithCustomId($"activity leave:{activityId}")
+ .WithCustomId($"activity leave_role:{activityId}")
.WithStyle(ButtonStyle.Danger)
)
);
diff --git a/Cocotte/Modules/Activity/ActivityPlayer.cs b/Cocotte/Modules/Activity/ActivityPlayer.cs
deleted file mode 100644
index 8234862..0000000
--- a/Cocotte/Modules/Activity/ActivityPlayer.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace Cocotte.Modules.Activity;
-
-public record ActivityPlayer(ulong UserId, string PlayerName);
\ No newline at end of file
diff --git a/Cocotte/Modules/Activity/ActivityRolePlayer.cs b/Cocotte/Modules/Activity/ActivityRolePlayer.cs
deleted file mode 100644
index 407b678..0000000
--- a/Cocotte/Modules/Activity/ActivityRolePlayer.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace Cocotte.Modules.Activity;
-
-public record ActivityRolePlayer(ulong UserId, string PlayerName, ActivityRoles Roles) : ActivityPlayer(UserId, PlayerName);
\ No newline at end of file
diff --git a/Cocotte/Modules/Activity/Models/ActivitiesRepository.cs b/Cocotte/Modules/Activity/Models/ActivitiesRepository.cs
new file mode 100644
index 0000000..2aeeef4
--- /dev/null
+++ b/Cocotte/Modules/Activity/Models/ActivitiesRepository.cs
@@ -0,0 +1,45 @@
+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
new file mode 100644
index 0000000..366e119
--- /dev/null
+++ b/Cocotte/Modules/Activity/Models/Activity.cs
@@ -0,0 +1,23 @@
+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
new file mode 100644
index 0000000..25579f8
--- /dev/null
+++ b/Cocotte/Modules/Activity/Models/ActivityPlayer.cs
@@ -0,0 +1,20 @@
+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/Modules/Activity/Models/ActivityRolePlayer.cs b/Cocotte/Modules/Activity/Models/ActivityRolePlayer.cs
new file mode 100644
index 0000000..c325230
--- /dev/null
+++ b/Cocotte/Modules/Activity/Models/ActivityRolePlayer.cs
@@ -0,0 +1,6 @@
+namespace Cocotte.Modules.Activity.Models;
+
+public class ActivityRolePlayer : ActivityPlayer
+{
+ public required ActivityRoles Roles { get; init; }
+}
\ No newline at end of file
diff --git a/Cocotte/Modules/Activity/Models/StagedActivity.cs b/Cocotte/Modules/Activity/Models/StagedActivity.cs
new file mode 100644
index 0000000..789f765
--- /dev/null
+++ b/Cocotte/Modules/Activity/Models/StagedActivity.cs
@@ -0,0 +1,11 @@
+namespace Cocotte.Modules.Activity.Models;
+
+public class StagedActivity : Activity
+{
+ public uint Stage { get; set; }
+
+ public override string ToString()
+ {
+ return $"{base.ToString()}, {nameof(Stage)}: {Stage}";
+ }
+}
\ No newline at end of file
diff --git a/Cocotte/Modules/Activity/StagedActivity.cs b/Cocotte/Modules/Activity/StagedActivity.cs
deleted file mode 100644
index 5537349..0000000
--- a/Cocotte/Modules/Activity/StagedActivity.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace Cocotte.Modules.Activity;
-
-public record StagedActivity(ulong Owner, string Description, ActivityType ActivityType, ActivityName ActivityName, uint MaxPlayers, uint Stage)
- : Activity(Owner, Description, ActivityType, ActivityName, MaxPlayers);
\ No newline at end of file
diff --git a/Cocotte/Program.cs b/Cocotte/Program.cs
index 31045d2..1fd388a 100644
--- a/Cocotte/Program.cs
+++ b/Cocotte/Program.cs
@@ -1,4 +1,5 @@
using Cocotte.Modules.Activity;
+using Cocotte.Modules.Activity.Models;
using Cocotte.Modules.Raids;
using Cocotte.Options;
using Cocotte.Services;
@@ -6,6 +7,7 @@ using Discord;
using Discord.Commands;
using Discord.Interactions;
using Discord.WebSocket;
+using Microsoft.EntityFrameworkCore;
DiscordSocketConfig discordSocketConfig = new()
{
@@ -26,6 +28,11 @@ IHost host = Host.CreateDefaultBuilder(args)
services.Configure(context.Configuration.GetSection(DiscordOptions.SectionName));
services.Configure(context.Configuration.GetSection(ActivityOptions.SectionName));
+ // Database
+ services.AddDbContext(options =>
+ options.UseSqlite(context.Configuration.GetConnectionString("CocotteContext")), ServiceLifetime.Transient, ServiceLifetime.Transient);
+ services.AddTransient();
+
// Discord.Net
services.AddHostedService();
diff --git a/Cocotte/Services/CocotteContext.cs b/Cocotte/Services/CocotteContext.cs
new file mode 100644
index 0000000..f64327c
--- /dev/null
+++ b/Cocotte/Services/CocotteContext.cs
@@ -0,0 +1,18 @@
+using Cocotte.Modules.Activity.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace Cocotte.Services;
+
+public class CocotteContext : DbContext
+{
+ public DbSet Activities => Set();
+ public DbSet StagedActivities => Set();
+
+ public DbSet ActivityPlayers => Set();
+ public DbSet ActivityRolePlayers => Set();
+
+ public CocotteContext(DbContextOptions options) : base(options)
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Cocotte/appsettings.json b/Cocotte/appsettings.json
index b2dcdb6..8e13436 100644
--- a/Cocotte/appsettings.json
+++ b/Cocotte/appsettings.json
@@ -4,5 +4,8 @@
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
+ },
+ "ConnectionStrings": {
+ "CocotteContext": "Data Source=cocotte.db"
}
}
diff --git a/Cocotte/cocotte.db b/Cocotte/cocotte.db
new file mode 100644
index 0000000..980611f
Binary files /dev/null and b/Cocotte/cocotte.db differ