diff --git a/Cocotte/Migrations/20230326133102_AddActivityIsClosed.Designer.cs b/Cocotte/Migrations/20230326133102_AddActivityIsClosed.Designer.cs
new file mode 100644
index 0000000..925c85a
--- /dev/null
+++ b/Cocotte/Migrations/20230326133102_AddActivityIsClosed.Designer.cs
@@ -0,0 +1,676 @@
+//
+using System;
+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(CocotteDbContext))]
+ [Migration("20230326133102_AddActivityIsClosed")]
+ partial class AddActivityIsClosed
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.4");
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_NAME");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_GROUP");
+
+ b.Property("BlobData")
+ .HasColumnType("bytea")
+ .HasColumnName("BLOB_DATA");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("QRTZ_BLOB_TRIGGERS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCalendar", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("CalendarName")
+ .HasColumnType("text")
+ .HasColumnName("CALENDAR_NAME");
+
+ b.Property("Calendar")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("CALENDAR");
+
+ b.HasKey("SchedulerName", "CalendarName");
+
+ b.ToTable("QRTZ_CALENDARS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCronTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_NAME");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_GROUP");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("CRON_EXPRESSION");
+
+ b.Property("TimeZoneId")
+ .HasColumnType("text")
+ .HasColumnName("TIME_ZONE_ID");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("QRTZ_CRON_TRIGGERS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzFiredTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("EntryId")
+ .HasColumnType("text")
+ .HasColumnName("ENTRY_ID");
+
+ b.Property("FiredTime")
+ .HasColumnType("bigint")
+ .HasColumnName("FIRED_TIME");
+
+ b.Property("InstanceName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("INSTANCE_NAME");
+
+ b.Property("IsNonConcurrent")
+ .HasColumnType("bool")
+ .HasColumnName("IS_NONCONCURRENT");
+
+ b.Property("JobGroup")
+ .HasColumnType("text")
+ .HasColumnName("JOB_GROUP");
+
+ b.Property("JobName")
+ .HasColumnType("text")
+ .HasColumnName("JOB_NAME");
+
+ b.Property("Priority")
+ .HasColumnType("integer")
+ .HasColumnName("PRIORITY");
+
+ b.Property("RequestsRecovery")
+ .HasColumnType("bool")
+ .HasColumnName("REQUESTS_RECOVERY");
+
+ b.Property("ScheduledTime")
+ .HasColumnType("bigint")
+ .HasColumnName("SCHED_TIME");
+
+ b.Property("State")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("STATE");
+
+ b.Property("TriggerGroup")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_GROUP");
+
+ b.Property("TriggerName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_NAME");
+
+ b.HasKey("SchedulerName", "EntryId");
+
+ b.HasIndex("InstanceName")
+ .HasDatabaseName("IDX_QRTZ_FT_TRIG_INST_NAME");
+
+ b.HasIndex("JobGroup")
+ .HasDatabaseName("IDX_QRTZ_FT_JOB_GROUP");
+
+ b.HasIndex("JobName")
+ .HasDatabaseName("IDX_QRTZ_FT_JOB_NAME");
+
+ b.HasIndex("RequestsRecovery")
+ .HasDatabaseName("IDX_QRTZ_FT_JOB_REQ_RECOVERY");
+
+ b.HasIndex("TriggerGroup")
+ .HasDatabaseName("IDX_QRTZ_FT_TRIG_GROUP");
+
+ b.HasIndex("TriggerName")
+ .HasDatabaseName("IDX_QRTZ_FT_TRIG_NAME");
+
+ b.HasIndex("SchedulerName", "TriggerName", "TriggerGroup")
+ .HasDatabaseName("IDX_QRTZ_FT_TRIG_NM_GP");
+
+ b.ToTable("QRTZ_FIRED_TRIGGERS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("JobName")
+ .HasColumnType("text")
+ .HasColumnName("JOB_NAME");
+
+ b.Property("JobGroup")
+ .HasColumnType("text")
+ .HasColumnName("JOB_GROUP");
+
+ b.Property("Description")
+ .HasColumnType("text")
+ .HasColumnName("DESCRIPTION");
+
+ b.Property("IsDurable")
+ .HasColumnType("bool")
+ .HasColumnName("IS_DURABLE");
+
+ b.Property("IsNonConcurrent")
+ .HasColumnType("bool")
+ .HasColumnName("IS_NONCONCURRENT");
+
+ b.Property("IsUpdateData")
+ .HasColumnType("bool")
+ .HasColumnName("IS_UPDATE_DATA");
+
+ b.Property("JobClassName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("JOB_CLASS_NAME");
+
+ b.Property("JobData")
+ .HasColumnType("bytea")
+ .HasColumnName("JOB_DATA");
+
+ b.Property("RequestsRecovery")
+ .HasColumnType("bool")
+ .HasColumnName("REQUESTS_RECOVERY");
+
+ b.HasKey("SchedulerName", "JobName", "JobGroup");
+
+ b.HasIndex("RequestsRecovery")
+ .HasDatabaseName("IDX_QRTZ_J_REQ_RECOVERY");
+
+ b.ToTable("QRTZ_JOB_DETAILS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzLock", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("LockName")
+ .HasColumnType("text")
+ .HasColumnName("LOCK_NAME");
+
+ b.HasKey("SchedulerName", "LockName");
+
+ b.ToTable("QRTZ_LOCKS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzPausedTriggerGroup", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_GROUP");
+
+ b.HasKey("SchedulerName", "TriggerGroup");
+
+ b.ToTable("QRTZ_PAUSED_TRIGGER_GRPS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSchedulerState", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("InstanceName")
+ .HasColumnType("text")
+ .HasColumnName("INSTANCE_NAME");
+
+ b.Property("CheckInInterval")
+ .HasColumnType("bigint")
+ .HasColumnName("CHECKIN_INTERVAL");
+
+ b.Property("LastCheckInTime")
+ .HasColumnType("bigint")
+ .HasColumnName("LAST_CHECKIN_TIME");
+
+ b.HasKey("SchedulerName", "InstanceName");
+
+ b.ToTable("QRTZ_SCHEDULER_STATE", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimplePropertyTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_NAME");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_GROUP");
+
+ b.Property("BooleanProperty1")
+ .HasColumnType("bool")
+ .HasColumnName("BOOL_PROP_1");
+
+ b.Property("BooleanProperty2")
+ .HasColumnType("bool")
+ .HasColumnName("BOOL_PROP_2");
+
+ b.Property("DecimalProperty1")
+ .HasColumnType("numeric")
+ .HasColumnName("DEC_PROP_1");
+
+ b.Property("DecimalProperty2")
+ .HasColumnType("numeric")
+ .HasColumnName("DEC_PROP_2");
+
+ b.Property("IntegerProperty1")
+ .HasColumnType("integer")
+ .HasColumnName("INT_PROP_1");
+
+ b.Property("IntegerProperty2")
+ .HasColumnType("integer")
+ .HasColumnName("INT_PROP_2");
+
+ b.Property("LongProperty1")
+ .HasColumnType("bigint")
+ .HasColumnName("LONG_PROP_1");
+
+ b.Property("LongProperty2")
+ .HasColumnType("bigint")
+ .HasColumnName("LONG_PROP_2");
+
+ b.Property("StringProperty1")
+ .HasColumnType("text")
+ .HasColumnName("STR_PROP_1");
+
+ b.Property("StringProperty2")
+ .HasColumnType("text")
+ .HasColumnName("STR_PROP_2");
+
+ b.Property("StringProperty3")
+ .HasColumnType("text")
+ .HasColumnName("STR_PROP_3");
+
+ b.Property("TimeZoneId")
+ .HasColumnType("text")
+ .HasColumnName("TIME_ZONE_ID");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("QRTZ_SIMPROP_TRIGGERS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimpleTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_NAME");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_GROUP");
+
+ b.Property("RepeatCount")
+ .HasColumnType("bigint")
+ .HasColumnName("REPEAT_COUNT");
+
+ b.Property("RepeatInterval")
+ .HasColumnType("bigint")
+ .HasColumnName("REPEAT_INTERVAL");
+
+ b.Property("TimesTriggered")
+ .HasColumnType("bigint")
+ .HasColumnName("TIMES_TRIGGERED");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("QRTZ_SIMPLE_TRIGGERS", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("SCHED_NAME");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_NAME");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_GROUP");
+
+ b.Property("CalendarName")
+ .HasColumnType("text")
+ .HasColumnName("CALENDAR_NAME");
+
+ b.Property("Description")
+ .HasColumnType("text")
+ .HasColumnName("DESCRIPTION");
+
+ b.Property("EndTime")
+ .HasColumnType("bigint")
+ .HasColumnName("END_TIME");
+
+ b.Property("JobData")
+ .HasColumnType("bytea")
+ .HasColumnName("JOB_DATA");
+
+ b.Property("JobGroup")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("JOB_GROUP");
+
+ b.Property("JobName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("JOB_NAME");
+
+ b.Property("MisfireInstruction")
+ .HasColumnType("smallint")
+ .HasColumnName("MISFIRE_INSTR");
+
+ b.Property("NextFireTime")
+ .HasColumnType("bigint")
+ .HasColumnName("NEXT_FIRE_TIME");
+
+ b.Property("PreviousFireTime")
+ .HasColumnType("bigint")
+ .HasColumnName("PREV_FIRE_TIME");
+
+ b.Property("Priority")
+ .HasColumnType("integer")
+ .HasColumnName("PRIORITY");
+
+ b.Property("StartTime")
+ .HasColumnType("bigint")
+ .HasColumnName("START_TIME");
+
+ b.Property("TriggerState")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_STATE");
+
+ b.Property("TriggerType")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("TRIGGER_TYPE");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.HasIndex("NextFireTime")
+ .HasDatabaseName("IDX_QRTZ_T_NEXT_FIRE_TIME");
+
+ b.HasIndex("TriggerState")
+ .HasDatabaseName("IDX_QRTZ_T_STATE");
+
+ b.HasIndex("NextFireTime", "TriggerState")
+ .HasDatabaseName("IDX_QRTZ_T_NFT_ST");
+
+ b.HasIndex("SchedulerName", "JobName", "JobGroup");
+
+ b.ToTable("QRTZ_TRIGGERS", (string)null);
+ });
+
+ modelBuilder.Entity("Cocotte.Modules.Activities.Models.Activity", b =>
+ {
+ b.Property("GuildId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ChannelId")
+ .HasColumnType("INTEGER");
+
+ b.Property("MessageId")
+ .HasColumnType("INTEGER");
+
+ b.Property("AreRolesEnabled")
+ .HasColumnType("INTEGER");
+
+ b.Property("CreationDate")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatorDisplayName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("CreatorUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Description")
+ .HasColumnType("TEXT");
+
+ b.Property("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("DueDateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("IsClosed")
+ .HasColumnType("INTEGER");
+
+ b.Property("MaxPlayers")
+ .HasColumnType("INTEGER");
+
+ b.Property("Name")
+ .HasColumnType("INTEGER");
+
+ b.Property("ThreadId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("GuildId", "ChannelId", "MessageId");
+
+ b.HasIndex("ThreadId");
+
+ b.ToTable("Activities");
+
+ b.HasDiscriminator("Discriminator").HasValue("Activity");
+
+ b.UseTphMappingStrategy();
+ });
+
+ modelBuilder.Entity("Cocotte.Modules.Activities.Models.ActivityPlayer", b =>
+ {
+ b.Property("GuildId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ChannelId")
+ .HasColumnType("INTEGER");
+
+ b.Property("MessageId")
+ .HasColumnType("INTEGER");
+
+ b.Property("UserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("GuildId", "ChannelId", "MessageId", "UserId");
+
+ b.ToTable("ActivityPlayers");
+
+ b.HasDiscriminator("Discriminator").HasValue("ActivityPlayer");
+
+ b.UseTphMappingStrategy();
+ });
+
+ modelBuilder.Entity("Cocotte.Modules.Activities.Models.InterstellarActivity", b =>
+ {
+ b.HasBaseType("Cocotte.Modules.Activities.Models.Activity");
+
+ b.Property("Color")
+ .HasColumnType("INTEGER");
+
+ b.HasDiscriminator().HasValue("InterstellarActivity");
+ });
+
+ modelBuilder.Entity("Cocotte.Modules.Activities.Models.StagedActivity", b =>
+ {
+ b.HasBaseType("Cocotte.Modules.Activities.Models.Activity");
+
+ b.Property("Stage")
+ .HasColumnType("INTEGER");
+
+ b.HasDiscriminator().HasValue("StagedActivity");
+ });
+
+ modelBuilder.Entity("Cocotte.Modules.Activities.Models.ActivityRolePlayer", b =>
+ {
+ b.HasBaseType("Cocotte.Modules.Activities.Models.ActivityPlayer");
+
+ b.Property("Roles")
+ .HasColumnType("INTEGER");
+
+ b.HasDiscriminator().HasValue("ActivityRolePlayer");
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b =>
+ {
+ b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger")
+ .WithMany("BlobTriggers")
+ .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Trigger");
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCronTrigger", b =>
+ {
+ b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger")
+ .WithMany("CronTriggers")
+ .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Trigger");
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimplePropertyTrigger", b =>
+ {
+ b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger")
+ .WithMany("SimplePropertyTriggers")
+ .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Trigger");
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimpleTrigger", b =>
+ {
+ b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger")
+ .WithMany("SimpleTriggers")
+ .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Trigger");
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b =>
+ {
+ b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", "JobDetail")
+ .WithMany("Triggers")
+ .HasForeignKey("SchedulerName", "JobName", "JobGroup")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("JobDetail");
+ });
+
+ modelBuilder.Entity("Cocotte.Modules.Activities.Models.ActivityPlayer", b =>
+ {
+ b.HasOne("Cocotte.Modules.Activities.Models.Activity", "Activity")
+ .WithMany("ActivityPlayers")
+ .HasForeignKey("GuildId", "ChannelId", "MessageId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Activity");
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", b =>
+ {
+ b.Navigation("Triggers");
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b =>
+ {
+ b.Navigation("BlobTriggers");
+
+ b.Navigation("CronTriggers");
+
+ b.Navigation("SimplePropertyTriggers");
+
+ b.Navigation("SimpleTriggers");
+ });
+
+ modelBuilder.Entity("Cocotte.Modules.Activities.Models.Activity", b =>
+ {
+ b.Navigation("ActivityPlayers");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Cocotte/Migrations/20230326133102_AddActivityIsClosed.cs b/Cocotte/Migrations/20230326133102_AddActivityIsClosed.cs
new file mode 100644
index 0000000..6ee7d67
--- /dev/null
+++ b/Cocotte/Migrations/20230326133102_AddActivityIsClosed.cs
@@ -0,0 +1,29 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Cocotte.Migrations
+{
+ ///
+ public partial class AddActivityIsClosed : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "IsClosed",
+ table: "Activities",
+ type: "INTEGER",
+ nullable: false,
+ defaultValue: false);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "IsClosed",
+ table: "Activities");
+ }
+ }
+}
diff --git a/Cocotte/Migrations/CocotteDbContextModelSnapshot.cs b/Cocotte/Migrations/CocotteDbContextModelSnapshot.cs
index 4d9376c..76c8bb0 100644
--- a/Cocotte/Migrations/CocotteDbContextModelSnapshot.cs
+++ b/Cocotte/Migrations/CocotteDbContextModelSnapshot.cs
@@ -494,6 +494,9 @@ namespace Cocotte.Migrations
b.Property("DueDateTime")
.HasColumnType("TEXT");
+ b.Property("IsClosed")
+ .HasColumnType("INTEGER");
+
b.Property("MaxPlayers")
.HasColumnType("INTEGER");
diff --git a/Cocotte/Modules/Activities/ActivityCloseJob.cs b/Cocotte/Modules/Activities/ActivityCloseJob.cs
index 2526ac8..4180325 100644
--- a/Cocotte/Modules/Activities/ActivityCloseJob.cs
+++ b/Cocotte/Modules/Activities/ActivityCloseJob.cs
@@ -47,6 +47,5 @@ public class ActivityCloseJob : IJob
// Update embed
await _activityHelper.UpdateActivityEmbed(channel, activity, ActivityUpdateReason.Update);
-
}
}
\ No newline at end of file
diff --git a/Cocotte/Modules/Activities/ActivityModuleThread.cs b/Cocotte/Modules/Activities/ActivityModuleThread.cs
index b09851b..06eb08e 100644
--- a/Cocotte/Modules/Activities/ActivityModuleThread.cs
+++ b/Cocotte/Modules/Activities/ActivityModuleThread.cs
@@ -18,9 +18,14 @@ public partial class ActivityModule
**― Commandes ―**
- `/activite ajouter ` - **Ajoute un joueur** à cette activité
- - `/activite supprimer ` - **Supprime un joueur** de cette activité
+ - `/activite enlever ` - **Enlève un joueur** de cette activité
+
+ - `/activite fermer` - **Ferme l'activité**, désactive les inscriptions
+ - `/activite ouvrir` - **Ouvre l'activité**, réactive les inscriptions après une fermeture
+
- `/activite ping` - **Ping les joueurs** inscrits à cette activité
- `/activite description` - **Modifie la description** de l'activité
+
- `/activite etage` - Pour l'abîme du néant et l'origine de la guerre, **modifie l'étage** de l'activité
""";
@@ -65,7 +70,7 @@ public partial class ActivityModule
// Get activity linked to this thread
var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id);
- if (!await CheckCommandInThread(activity) || activity is null)
+ if (!await CheckCommandInThread(activity, checkCreator: true) || activity is null)
{
return;
}
@@ -73,6 +78,80 @@ public partial class ActivityModule
await RemovePlayerFromActivity(activity, (SocketGuildUser) user, self: false);
}
+ [SlashCommand("fermer", "Fermer l'activité, désactivant les inscriptions")]
+ public async Task ThreadCloseActivity()
+ {
+ // Get activity linked to this thread
+ var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id);
+
+ if (!await CheckCommandInThread(activity, checkCreator: true) || activity is null)
+ {
+ return;
+ }
+
+ // Do nothing if already closed
+ if (activity.IsClosed)
+ {
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.InfoEmbed("Cette activité est **déjà fermée**").Build()
+ );
+
+ return;
+ }
+
+ activity.IsClosed = true;
+ await _activitiesRepository.SaveChanges();
+
+ // Get activity channel to update
+ if (Context.Guild.GetChannel(activity.ChannelId) is ITextChannel channel)
+ {
+ await _activityHelper.UpdateActivityEmbed(channel, activity, ActivityUpdateReason.Update);
+ }
+
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.InfoEmbed("L'activité a bien été **fermée**").Build()
+ );
+ }
+
+ [SlashCommand("ouvrir", "Ouvrir l'activité, réactivant les inscriptions")]
+ public async Task ThreadOpenActivity()
+ {
+ // Get activity linked to this thread
+ var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id);
+
+ if (!await CheckCommandInThread(activity, checkCreator: true) || activity is null)
+ {
+ return;
+ }
+
+ // Do nothing if already opened
+ if (!activity.IsClosed)
+ {
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.InfoEmbed("Cette activité est **déjà ouverte**").Build()
+ );
+
+ return;
+ }
+
+ activity.IsClosed = false;
+ await _activitiesRepository.SaveChanges();
+
+ // Get activity channel to update
+ if (Context.Guild.GetChannel(activity.ChannelId) is ITextChannel channel)
+ {
+ await _activityHelper.UpdateActivityEmbed(channel, activity, ActivityUpdateReason.Update);
+ }
+
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.InfoEmbed("L'activité a bien été **ouverte**").Build()
+ );
+ }
+
[SlashCommand("ping", "Ping les joueurs inscrits à cette activité")]
public async Task ThreadPingPlayers(string message = "**Appel de groupe**")
{
@@ -87,7 +166,6 @@ public partial class ActivityModule
// Get user ids
var userIds = await _activitiesRepository.GetActivityPlayerIds(activity);
-
// Generate message
var pingMessageBuilder = new StringBuilder(message);
pingMessageBuilder.AppendLine("\n");
@@ -96,7 +174,7 @@ public partial class ActivityModule
await RespondAsync(pingMessageBuilder.ToString());
}
- private async Task CheckCommandInThread(Activity? activity)
+ private async Task CheckCommandInThread(Activity? activity, bool checkCreator = false)
{
// Check if activity is not null (means we are in a valid thread)
if (activity is null)
@@ -109,6 +187,16 @@ public partial class ActivityModule
return false;
}
+ if (checkCreator && User.Id != activity.CreatorUserId)
+ {
+ await RespondAsync(
+ ephemeral: true,
+ embed: EmbedUtils.ErrorEmbed("Seul le **créateur de l'activité** a le droit d’exécuter cette action").Build()
+ );
+
+ return false;
+ }
+
return true;
}
}
\ No newline at end of file
diff --git a/Cocotte/Modules/Ping/PingModule.cs b/Cocotte/Modules/Ping/PingModule.cs
index ebfc7c4..ceddb25 100644
--- a/Cocotte/Modules/Ping/PingModule.cs
+++ b/Cocotte/Modules/Ping/PingModule.cs
@@ -19,15 +19,11 @@ namespace Cocotte.Modules.Ping;
public class PingModule : InteractionModuleBase
{
private readonly ILogger _logger;
- private readonly SharedCounter _sharedCounter;
- private readonly TransientCounter _transientCounter;
private static readonly SemaphoreSlim CounterWait = new(0);
- public PingModule(ILogger logger, SharedCounter sharedCounter, TransientCounter transientCounter)
+ public PingModule(ILogger logger)
{
_logger = logger;
- _sharedCounter = sharedCounter;
- _transientCounter = transientCounter;
}
[SlashCommand("runtime-info", "Get runtime info")]
@@ -167,94 +163,6 @@ public class PingModule : InteractionModuleBase
await RespondAsync($"{userName} clicked on button: {buttonId}");
}
- [SlashCommand("counter-shared", "Spawn a shared counter")]
- public async Task CounterShared()
- {
- var component = new ComponentBuilder()
- .WithButton("Increment", "increment_shared");
-
- await RespondAsync($"Counter: {_sharedCounter.Count}", components: component.Build());
- }
-
- [ComponentInteraction("increment_shared")]
- public async Task SharedCounterIncrement()
- {
- _logger.LogTrace("Received increment on shared counter");
- _sharedCounter.Count++;
-
- try
- {
- await (Context.Interaction as IComponentInteraction)!.UpdateAsync(msg =>
- {
- msg.Content = $"Counter: {_sharedCounter.Count}";
- });
- }
- catch (Exception e)
- {
- _logger.LogError(e, "An error occured while updating original message:");
- }
- await RespondAsync();
- }
-
- [SlashCommand("counter-transient", "Spawn a transient counter")]
- public async Task CounterTransient()
- {
- var component = new ComponentBuilder()
- .WithButton("Increment", "increment_transient");
-
- await RespondAsync($"Counter: {_transientCounter.Count}", components: component.Build());
- }
-
- [ComponentInteraction("increment_transient")]
- public async Task TransientCounterIncrement()
- {
- _logger.LogTrace("Received increment on transient counter");
- _transientCounter.Count++;
-
- try
- {
- await (Context.Interaction as IComponentInteraction)!.UpdateAsync(msg =>
- {
- msg.Content = $"Counter: {_transientCounter.Count}";
- });
- }
- catch (Exception e)
- {
- _logger.LogError(e, "An error occured while updating original message:");
- }
- await RespondAsync();
- }
-
- [SlashCommand("counter-transient-wait", "Spawn a transient counter using wait")]
- public async Task CounterTransientWait()
- {
- var component = new ComponentBuilder()
- .WithButton("Increment", "increment_transient_wait");
-
- await RespondAsync($"Counter: {_transientCounter.Count}", components: component.Build());
- var response = await GetOriginalResponseAsync();
-
- while (true)
- {
- // Wait for the button to be clicked
- _logger.LogTrace("Waiting for semaphore release");
- await CounterWait.WaitAsync();
-
- _logger.LogTrace("Received increment on transient wait counter");
- _transientCounter.Count++;
-
- await ModifyOriginalResponseAsync(m => m.Content = $"Counter: {_transientCounter.Count}");
- }
- }
-
- [ComponentInteraction("increment_transient_wait")]
- public async Task WaitCounterIncrement()
- {
- CounterWait.Release();
-
- await RespondAsync();
- }
-
[SlashCommand("select-test", "Test menu select")]
public async Task SelectTest()
{