[Activity] Add activity auto close

This commit is contained in:
2023-03-26 14:44:24 +02:00
parent 63e464e602
commit 1083f604f7
15 changed files with 1800 additions and 112 deletions

View File

@@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AppAny.Quartz.EntityFrameworkCore.Migrations.SQLite" Version="0.4.0" />
<PackageReference Include="Discord.Net" Version="3.9.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.4">
<PrivateAssets>all</PrivateAssets>
@@ -15,6 +16,10 @@
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Quartz" Version="3.6.2" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.6.2" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.6.2" />
<PackageReference Include="Quartz.Serialization.Json" Version="3.6.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,673 @@
// <auto-generated />
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("20230326095220_AddQuartz")]
partial class AddQuartz
{
/// <inheritdoc />
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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<byte[]>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("CalendarName")
.HasColumnType("text")
.HasColumnName("CALENDAR_NAME");
b.Property<byte[]>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<string>("CronExpression")
.IsRequired()
.HasColumnType("text")
.HasColumnName("CRON_EXPRESSION");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("EntryId")
.HasColumnType("text")
.HasColumnName("ENTRY_ID");
b.Property<long>("FiredTime")
.HasColumnType("bigint")
.HasColumnName("FIRED_TIME");
b.Property<string>("InstanceName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("INSTANCE_NAME");
b.Property<bool>("IsNonConcurrent")
.HasColumnType("bool")
.HasColumnName("IS_NONCONCURRENT");
b.Property<string>("JobGroup")
.HasColumnType("text")
.HasColumnName("JOB_GROUP");
b.Property<string>("JobName")
.HasColumnType("text")
.HasColumnName("JOB_NAME");
b.Property<int>("Priority")
.HasColumnType("integer")
.HasColumnName("PRIORITY");
b.Property<bool?>("RequestsRecovery")
.HasColumnType("bool")
.HasColumnName("REQUESTS_RECOVERY");
b.Property<long>("ScheduledTime")
.HasColumnType("bigint")
.HasColumnName("SCHED_TIME");
b.Property<string>("State")
.IsRequired()
.HasColumnType("text")
.HasColumnName("STATE");
b.Property<string>("TriggerGroup")
.IsRequired()
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("JobName")
.HasColumnType("text")
.HasColumnName("JOB_NAME");
b.Property<string>("JobGroup")
.HasColumnType("text")
.HasColumnName("JOB_GROUP");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("DESCRIPTION");
b.Property<bool>("IsDurable")
.HasColumnType("bool")
.HasColumnName("IS_DURABLE");
b.Property<bool>("IsNonConcurrent")
.HasColumnType("bool")
.HasColumnName("IS_NONCONCURRENT");
b.Property<bool>("IsUpdateData")
.HasColumnType("bool")
.HasColumnName("IS_UPDATE_DATA");
b.Property<string>("JobClassName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("JOB_CLASS_NAME");
b.Property<byte[]>("JobData")
.HasColumnType("bytea")
.HasColumnName("JOB_DATA");
b.Property<bool>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("InstanceName")
.HasColumnType("text")
.HasColumnName("INSTANCE_NAME");
b.Property<long>("CheckInInterval")
.HasColumnType("bigint")
.HasColumnName("CHECKIN_INTERVAL");
b.Property<long>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<bool?>("BooleanProperty1")
.HasColumnType("bool")
.HasColumnName("BOOL_PROP_1");
b.Property<bool?>("BooleanProperty2")
.HasColumnType("bool")
.HasColumnName("BOOL_PROP_2");
b.Property<decimal?>("DecimalProperty1")
.HasColumnType("numeric")
.HasColumnName("DEC_PROP_1");
b.Property<decimal?>("DecimalProperty2")
.HasColumnType("numeric")
.HasColumnName("DEC_PROP_2");
b.Property<int?>("IntegerProperty1")
.HasColumnType("integer")
.HasColumnName("INT_PROP_1");
b.Property<int?>("IntegerProperty2")
.HasColumnType("integer")
.HasColumnName("INT_PROP_2");
b.Property<long?>("LongProperty1")
.HasColumnType("bigint")
.HasColumnName("LONG_PROP_1");
b.Property<long?>("LongProperty2")
.HasColumnType("bigint")
.HasColumnName("LONG_PROP_2");
b.Property<string>("StringProperty1")
.HasColumnType("text")
.HasColumnName("STR_PROP_1");
b.Property<string>("StringProperty2")
.HasColumnType("text")
.HasColumnName("STR_PROP_2");
b.Property<string>("StringProperty3")
.HasColumnType("text")
.HasColumnName("STR_PROP_3");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<long>("RepeatCount")
.HasColumnType("bigint")
.HasColumnName("REPEAT_COUNT");
b.Property<long>("RepeatInterval")
.HasColumnType("bigint")
.HasColumnName("REPEAT_INTERVAL");
b.Property<long>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<string>("CalendarName")
.HasColumnType("text")
.HasColumnName("CALENDAR_NAME");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("DESCRIPTION");
b.Property<long?>("EndTime")
.HasColumnType("bigint")
.HasColumnName("END_TIME");
b.Property<byte[]>("JobData")
.HasColumnType("bytea")
.HasColumnName("JOB_DATA");
b.Property<string>("JobGroup")
.IsRequired()
.HasColumnType("text")
.HasColumnName("JOB_GROUP");
b.Property<string>("JobName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("JOB_NAME");
b.Property<short?>("MisfireInstruction")
.HasColumnType("smallint")
.HasColumnName("MISFIRE_INSTR");
b.Property<long?>("NextFireTime")
.HasColumnType("bigint")
.HasColumnName("NEXT_FIRE_TIME");
b.Property<long?>("PreviousFireTime")
.HasColumnType("bigint")
.HasColumnName("PREV_FIRE_TIME");
b.Property<int?>("Priority")
.HasColumnType("integer")
.HasColumnName("PRIORITY");
b.Property<long>("StartTime")
.HasColumnType("bigint")
.HasColumnName("START_TIME");
b.Property<string>("TriggerState")
.IsRequired()
.HasColumnType("text")
.HasColumnName("TRIGGER_STATE");
b.Property<string>("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<ulong>("GuildId")
.HasColumnType("INTEGER");
b.Property<ulong>("ChannelId")
.HasColumnType("INTEGER");
b.Property<ulong>("MessageId")
.HasColumnType("INTEGER");
b.Property<bool>("AreRolesEnabled")
.HasColumnType("INTEGER");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<string>("CreatorDisplayName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<ulong>("CreatorUserId")
.HasColumnType("INTEGER");
b.Property<string>("Description")
.HasColumnType("TEXT");
b.Property<string>("Discriminator")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime?>("DueDateTime")
.HasColumnType("TEXT");
b.Property<uint>("MaxPlayers")
.HasColumnType("INTEGER");
b.Property<int>("Name")
.HasColumnType("INTEGER");
b.Property<ulong>("ThreadId")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("GuildId", "ChannelId", "MessageId");
b.HasIndex("ThreadId");
b.ToTable("Activities");
b.HasDiscriminator<string>("Discriminator").HasValue("Activity");
b.UseTphMappingStrategy();
});
modelBuilder.Entity("Cocotte.Modules.Activities.Models.ActivityPlayer", b =>
{
b.Property<ulong>("GuildId")
.HasColumnType("INTEGER");
b.Property<ulong>("ChannelId")
.HasColumnType("INTEGER");
b.Property<ulong>("MessageId")
.HasColumnType("INTEGER");
b.Property<ulong>("UserId")
.HasColumnType("INTEGER");
b.Property<string>("Discriminator")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("GuildId", "ChannelId", "MessageId", "UserId");
b.ToTable("ActivityPlayers");
b.HasDiscriminator<string>("Discriminator").HasValue("ActivityPlayer");
b.UseTphMappingStrategy();
});
modelBuilder.Entity("Cocotte.Modules.Activities.Models.InterstellarActivity", b =>
{
b.HasBaseType("Cocotte.Modules.Activities.Models.Activity");
b.Property<int>("Color")
.HasColumnType("INTEGER");
b.HasDiscriminator().HasValue("InterstellarActivity");
});
modelBuilder.Entity("Cocotte.Modules.Activities.Models.StagedActivity", b =>
{
b.HasBaseType("Cocotte.Modules.Activities.Models.Activity");
b.Property<uint>("Stage")
.HasColumnType("INTEGER");
b.HasDiscriminator().HasValue("StagedActivity");
});
modelBuilder.Entity("Cocotte.Modules.Activities.Models.ActivityRolePlayer", b =>
{
b.HasBaseType("Cocotte.Modules.Activities.Models.ActivityPlayer");
b.Property<byte>("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
}
}
}

View File

@@ -0,0 +1,331 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Cocotte.Migrations
{
/// <inheritdoc />
public partial class AddQuartz : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "QRTZ_CALENDARS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
CALENDAR_NAME = table.Column<string>(type: "text", nullable: false),
CALENDAR = table.Column<byte[]>(type: "bytea", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_CALENDARS", x => new { x.SCHED_NAME, x.CALENDAR_NAME });
});
migrationBuilder.CreateTable(
name: "QRTZ_FIRED_TRIGGERS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
ENTRY_ID = table.Column<string>(type: "text", nullable: false),
TRIGGER_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_GROUP = table.Column<string>(type: "text", nullable: false),
INSTANCE_NAME = table.Column<string>(type: "text", nullable: false),
FIRED_TIME = table.Column<long>(type: "bigint", nullable: false),
SCHED_TIME = table.Column<long>(type: "bigint", nullable: false),
PRIORITY = table.Column<int>(type: "integer", nullable: false),
STATE = table.Column<string>(type: "text", nullable: false),
JOB_NAME = table.Column<string>(type: "text", nullable: true),
JOB_GROUP = table.Column<string>(type: "text", nullable: true),
IS_NONCONCURRENT = table.Column<bool>(type: "bool", nullable: false),
REQUESTS_RECOVERY = table.Column<bool>(type: "bool", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_FIRED_TRIGGERS", x => new { x.SCHED_NAME, x.ENTRY_ID });
});
migrationBuilder.CreateTable(
name: "QRTZ_JOB_DETAILS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
JOB_NAME = table.Column<string>(type: "text", nullable: false),
JOB_GROUP = table.Column<string>(type: "text", nullable: false),
DESCRIPTION = table.Column<string>(type: "text", nullable: true),
JOB_CLASS_NAME = table.Column<string>(type: "text", nullable: false),
IS_DURABLE = table.Column<bool>(type: "bool", nullable: false),
IS_NONCONCURRENT = table.Column<bool>(type: "bool", nullable: false),
IS_UPDATE_DATA = table.Column<bool>(type: "bool", nullable: false),
REQUESTS_RECOVERY = table.Column<bool>(type: "bool", nullable: false),
JOB_DATA = table.Column<byte[]>(type: "bytea", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_JOB_DETAILS", x => new { x.SCHED_NAME, x.JOB_NAME, x.JOB_GROUP });
});
migrationBuilder.CreateTable(
name: "QRTZ_LOCKS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
LOCK_NAME = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_LOCKS", x => new { x.SCHED_NAME, x.LOCK_NAME });
});
migrationBuilder.CreateTable(
name: "QRTZ_PAUSED_TRIGGER_GRPS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_GROUP = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_PAUSED_TRIGGER_GRPS", x => new { x.SCHED_NAME, x.TRIGGER_GROUP });
});
migrationBuilder.CreateTable(
name: "QRTZ_SCHEDULER_STATE",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
INSTANCE_NAME = table.Column<string>(type: "text", nullable: false),
LAST_CHECKIN_TIME = table.Column<long>(type: "bigint", nullable: false),
CHECKIN_INTERVAL = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_SCHEDULER_STATE", x => new { x.SCHED_NAME, x.INSTANCE_NAME });
});
migrationBuilder.CreateTable(
name: "QRTZ_TRIGGERS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_GROUP = table.Column<string>(type: "text", nullable: false),
JOB_NAME = table.Column<string>(type: "text", nullable: false),
JOB_GROUP = table.Column<string>(type: "text", nullable: false),
DESCRIPTION = table.Column<string>(type: "text", nullable: true),
NEXT_FIRE_TIME = table.Column<long>(type: "bigint", nullable: true),
PREV_FIRE_TIME = table.Column<long>(type: "bigint", nullable: true),
PRIORITY = table.Column<int>(type: "integer", nullable: true),
TRIGGER_STATE = table.Column<string>(type: "text", nullable: false),
TRIGGER_TYPE = table.Column<string>(type: "text", nullable: false),
START_TIME = table.Column<long>(type: "bigint", nullable: false),
END_TIME = table.Column<long>(type: "bigint", nullable: true),
CALENDAR_NAME = table.Column<string>(type: "text", nullable: true),
MISFIRE_INSTR = table.Column<short>(type: "smallint", nullable: true),
JOB_DATA = table.Column<byte[]>(type: "bytea", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_TRIGGERS", x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP });
table.ForeignKey(
name: "FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS_SCHED_NAME_JOB_NAME_JOB_GROUP",
columns: x => new { x.SCHED_NAME, x.JOB_NAME, x.JOB_GROUP },
principalTable: "QRTZ_JOB_DETAILS",
principalColumns: new[] { "SCHED_NAME", "JOB_NAME", "JOB_GROUP" },
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "QRTZ_BLOB_TRIGGERS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_GROUP = table.Column<string>(type: "text", nullable: false),
BLOB_DATA = table.Column<byte[]>(type: "bytea", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_BLOB_TRIGGERS", x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP });
table.ForeignKey(
name: "FK_QRTZ_BLOB_TRIGGERS_QRTZ_TRIGGERS_SCHED_NAME_TRIGGER_NAME_TRIGGER_GROUP",
columns: x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP },
principalTable: "QRTZ_TRIGGERS",
principalColumns: new[] { "SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP" },
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "QRTZ_CRON_TRIGGERS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_GROUP = table.Column<string>(type: "text", nullable: false),
CRON_EXPRESSION = table.Column<string>(type: "text", nullable: false),
TIME_ZONE_ID = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_CRON_TRIGGERS", x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP });
table.ForeignKey(
name: "FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS_SCHED_NAME_TRIGGER_NAME_TRIGGER_GROUP",
columns: x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP },
principalTable: "QRTZ_TRIGGERS",
principalColumns: new[] { "SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP" },
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "QRTZ_SIMPLE_TRIGGERS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_GROUP = table.Column<string>(type: "text", nullable: false),
REPEAT_COUNT = table.Column<long>(type: "bigint", nullable: false),
REPEAT_INTERVAL = table.Column<long>(type: "bigint", nullable: false),
TIMES_TRIGGERED = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_SIMPLE_TRIGGERS", x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP });
table.ForeignKey(
name: "FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS_SCHED_NAME_TRIGGER_NAME_TRIGGER_GROUP",
columns: x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP },
principalTable: "QRTZ_TRIGGERS",
principalColumns: new[] { "SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP" },
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "QRTZ_SIMPROP_TRIGGERS",
columns: table => new
{
SCHED_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_NAME = table.Column<string>(type: "text", nullable: false),
TRIGGER_GROUP = table.Column<string>(type: "text", nullable: false),
STR_PROP_1 = table.Column<string>(type: "text", nullable: true),
STR_PROP_2 = table.Column<string>(type: "text", nullable: true),
STR_PROP_3 = table.Column<string>(type: "text", nullable: true),
INT_PROP_1 = table.Column<int>(type: "integer", nullable: true),
INT_PROP_2 = table.Column<int>(type: "integer", nullable: true),
LONG_PROP_1 = table.Column<long>(type: "bigint", nullable: true),
LONG_PROP_2 = table.Column<long>(type: "bigint", nullable: true),
DEC_PROP_1 = table.Column<decimal>(type: "numeric", nullable: true),
DEC_PROP_2 = table.Column<decimal>(type: "numeric", nullable: true),
BOOL_PROP_1 = table.Column<bool>(type: "bool", nullable: true),
BOOL_PROP_2 = table.Column<bool>(type: "bool", nullable: true),
TIME_ZONE_ID = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_QRTZ_SIMPROP_TRIGGERS", x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP });
table.ForeignKey(
name: "FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS_SCHED_NAME_TRIGGER_NAME_TRIGGER_GROUP",
columns: x => new { x.SCHED_NAME, x.TRIGGER_NAME, x.TRIGGER_GROUP },
principalTable: "QRTZ_TRIGGERS",
principalColumns: new[] { "SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP" },
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_FT_JOB_GROUP",
table: "QRTZ_FIRED_TRIGGERS",
column: "JOB_GROUP");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_FT_JOB_NAME",
table: "QRTZ_FIRED_TRIGGERS",
column: "JOB_NAME");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_FT_JOB_REQ_RECOVERY",
table: "QRTZ_FIRED_TRIGGERS",
column: "REQUESTS_RECOVERY");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_FT_TRIG_GROUP",
table: "QRTZ_FIRED_TRIGGERS",
column: "TRIGGER_GROUP");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_FT_TRIG_INST_NAME",
table: "QRTZ_FIRED_TRIGGERS",
column: "INSTANCE_NAME");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_FT_TRIG_NAME",
table: "QRTZ_FIRED_TRIGGERS",
column: "TRIGGER_NAME");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_FT_TRIG_NM_GP",
table: "QRTZ_FIRED_TRIGGERS",
columns: new[] { "SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP" });
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_J_REQ_RECOVERY",
table: "QRTZ_JOB_DETAILS",
column: "REQUESTS_RECOVERY");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_T_NEXT_FIRE_TIME",
table: "QRTZ_TRIGGERS",
column: "NEXT_FIRE_TIME");
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_T_NFT_ST",
table: "QRTZ_TRIGGERS",
columns: new[] { "NEXT_FIRE_TIME", "TRIGGER_STATE" });
migrationBuilder.CreateIndex(
name: "IDX_QRTZ_T_STATE",
table: "QRTZ_TRIGGERS",
column: "TRIGGER_STATE");
migrationBuilder.CreateIndex(
name: "IX_QRTZ_TRIGGERS_SCHED_NAME_JOB_NAME_JOB_GROUP",
table: "QRTZ_TRIGGERS",
columns: new[] { "SCHED_NAME", "JOB_NAME", "JOB_GROUP" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "QRTZ_BLOB_TRIGGERS");
migrationBuilder.DropTable(
name: "QRTZ_CALENDARS");
migrationBuilder.DropTable(
name: "QRTZ_CRON_TRIGGERS");
migrationBuilder.DropTable(
name: "QRTZ_FIRED_TRIGGERS");
migrationBuilder.DropTable(
name: "QRTZ_LOCKS");
migrationBuilder.DropTable(
name: "QRTZ_PAUSED_TRIGGER_GRPS");
migrationBuilder.DropTable(
name: "QRTZ_SCHEDULER_STATE");
migrationBuilder.DropTable(
name: "QRTZ_SIMPLE_TRIGGERS");
migrationBuilder.DropTable(
name: "QRTZ_SIMPROP_TRIGGERS");
migrationBuilder.DropTable(
name: "QRTZ_TRIGGERS");
migrationBuilder.DropTable(
name: "QRTZ_JOB_DETAILS");
}
}
}

View File

@@ -17,6 +17,449 @@ namespace Cocotte.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.4");
modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b =>
{
b.Property<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<byte[]>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("CalendarName")
.HasColumnType("text")
.HasColumnName("CALENDAR_NAME");
b.Property<byte[]>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<string>("CronExpression")
.IsRequired()
.HasColumnType("text")
.HasColumnName("CRON_EXPRESSION");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("EntryId")
.HasColumnType("text")
.HasColumnName("ENTRY_ID");
b.Property<long>("FiredTime")
.HasColumnType("bigint")
.HasColumnName("FIRED_TIME");
b.Property<string>("InstanceName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("INSTANCE_NAME");
b.Property<bool>("IsNonConcurrent")
.HasColumnType("bool")
.HasColumnName("IS_NONCONCURRENT");
b.Property<string>("JobGroup")
.HasColumnType("text")
.HasColumnName("JOB_GROUP");
b.Property<string>("JobName")
.HasColumnType("text")
.HasColumnName("JOB_NAME");
b.Property<int>("Priority")
.HasColumnType("integer")
.HasColumnName("PRIORITY");
b.Property<bool?>("RequestsRecovery")
.HasColumnType("bool")
.HasColumnName("REQUESTS_RECOVERY");
b.Property<long>("ScheduledTime")
.HasColumnType("bigint")
.HasColumnName("SCHED_TIME");
b.Property<string>("State")
.IsRequired()
.HasColumnType("text")
.HasColumnName("STATE");
b.Property<string>("TriggerGroup")
.IsRequired()
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("JobName")
.HasColumnType("text")
.HasColumnName("JOB_NAME");
b.Property<string>("JobGroup")
.HasColumnType("text")
.HasColumnName("JOB_GROUP");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("DESCRIPTION");
b.Property<bool>("IsDurable")
.HasColumnType("bool")
.HasColumnName("IS_DURABLE");
b.Property<bool>("IsNonConcurrent")
.HasColumnType("bool")
.HasColumnName("IS_NONCONCURRENT");
b.Property<bool>("IsUpdateData")
.HasColumnType("bool")
.HasColumnName("IS_UPDATE_DATA");
b.Property<string>("JobClassName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("JOB_CLASS_NAME");
b.Property<byte[]>("JobData")
.HasColumnType("bytea")
.HasColumnName("JOB_DATA");
b.Property<bool>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("InstanceName")
.HasColumnType("text")
.HasColumnName("INSTANCE_NAME");
b.Property<long>("CheckInInterval")
.HasColumnType("bigint")
.HasColumnName("CHECKIN_INTERVAL");
b.Property<long>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<bool?>("BooleanProperty1")
.HasColumnType("bool")
.HasColumnName("BOOL_PROP_1");
b.Property<bool?>("BooleanProperty2")
.HasColumnType("bool")
.HasColumnName("BOOL_PROP_2");
b.Property<decimal?>("DecimalProperty1")
.HasColumnType("numeric")
.HasColumnName("DEC_PROP_1");
b.Property<decimal?>("DecimalProperty2")
.HasColumnType("numeric")
.HasColumnName("DEC_PROP_2");
b.Property<int?>("IntegerProperty1")
.HasColumnType("integer")
.HasColumnName("INT_PROP_1");
b.Property<int?>("IntegerProperty2")
.HasColumnType("integer")
.HasColumnName("INT_PROP_2");
b.Property<long?>("LongProperty1")
.HasColumnType("bigint")
.HasColumnName("LONG_PROP_1");
b.Property<long?>("LongProperty2")
.HasColumnType("bigint")
.HasColumnName("LONG_PROP_2");
b.Property<string>("StringProperty1")
.HasColumnType("text")
.HasColumnName("STR_PROP_1");
b.Property<string>("StringProperty2")
.HasColumnType("text")
.HasColumnName("STR_PROP_2");
b.Property<string>("StringProperty3")
.HasColumnType("text")
.HasColumnName("STR_PROP_3");
b.Property<string>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<long>("RepeatCount")
.HasColumnType("bigint")
.HasColumnName("REPEAT_COUNT");
b.Property<long>("RepeatInterval")
.HasColumnType("bigint")
.HasColumnName("REPEAT_INTERVAL");
b.Property<long>("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<string>("SchedulerName")
.HasColumnType("text")
.HasColumnName("SCHED_NAME");
b.Property<string>("TriggerName")
.HasColumnType("text")
.HasColumnName("TRIGGER_NAME");
b.Property<string>("TriggerGroup")
.HasColumnType("text")
.HasColumnName("TRIGGER_GROUP");
b.Property<string>("CalendarName")
.HasColumnType("text")
.HasColumnName("CALENDAR_NAME");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("DESCRIPTION");
b.Property<long?>("EndTime")
.HasColumnType("bigint")
.HasColumnName("END_TIME");
b.Property<byte[]>("JobData")
.HasColumnType("bytea")
.HasColumnName("JOB_DATA");
b.Property<string>("JobGroup")
.IsRequired()
.HasColumnType("text")
.HasColumnName("JOB_GROUP");
b.Property<string>("JobName")
.IsRequired()
.HasColumnType("text")
.HasColumnName("JOB_NAME");
b.Property<short?>("MisfireInstruction")
.HasColumnType("smallint")
.HasColumnName("MISFIRE_INSTR");
b.Property<long?>("NextFireTime")
.HasColumnType("bigint")
.HasColumnName("NEXT_FIRE_TIME");
b.Property<long?>("PreviousFireTime")
.HasColumnType("bigint")
.HasColumnName("PREV_FIRE_TIME");
b.Property<int?>("Priority")
.HasColumnType("integer")
.HasColumnName("PRIORITY");
b.Property<long>("StartTime")
.HasColumnType("bigint")
.HasColumnName("START_TIME");
b.Property<string>("TriggerState")
.IsRequired()
.HasColumnType("text")
.HasColumnName("TRIGGER_STATE");
b.Property<string>("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<ulong>("GuildId")
@@ -135,6 +578,61 @@ namespace Cocotte.Migrations
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")
@@ -146,6 +644,22 @@ namespace Cocotte.Migrations
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");

View File

@@ -0,0 +1,52 @@
using Cocotte.Modules.Activities.Models;
using Discord.WebSocket;
using Quartz;
namespace Cocotte.Modules.Activities;
public class ActivityCloseJob : IJob
{
public long GuildId { private get; set; }
public long ChannelId { private get; set; }
public long MessageId { private get; set; }
private readonly ILogger<ActivityCloseJob> _logger;
private readonly ActivitiesRepository _activitiesRepository;
private readonly ActivityHelper _activityHelper;
private readonly DiscordSocketClient _discordClient;
public ActivityCloseJob(ILogger<ActivityCloseJob> logger, ActivitiesRepository activitiesRepository, ActivityHelper activityHelper, DiscordSocketClient discordClient)
{
_logger = logger;
_activitiesRepository = activitiesRepository;
_activityHelper = activityHelper;
_discordClient = discordClient;
}
public async Task Execute(IJobExecutionContext context)
{
// Get associated activity
if (await _activitiesRepository.FindActivity((ulong)GuildId, (ulong)ChannelId, (ulong)MessageId) is not { } activity)
{
_logger.LogTrace("Activity {MessageId} does not exist anymore", MessageId);
return;
}
// Close activity
activity.IsClosed = true;
await _activitiesRepository.SaveChanges();
_logger.LogInformation("Closed activity {Activity}", activity);
// Get channel
if (_discordClient.GetChannel(activity.ChannelId) is not SocketTextChannel channel)
{
return;
}
// Update embed
await _activityHelper.UpdateActivityEmbed(channel, activity, ActivityUpdateReason.Update);
}
}

View File

@@ -72,7 +72,7 @@ public class ActivityFormatter
// Add time if specified
if (activity.DueDateTime is { } dueDateTime)
{
descriptionBuilder.AppendLine($"**:clock2: {TimestampTag.FormatFromDateTime(dueDateTime, TimestampTagStyles.ShortTime)} ― {TimestampTag.FormatFromDateTime(dueDateTime, TimestampTagStyles.Relative)}**");
descriptionBuilder.AppendLine($"**:clock2: {TimestampTag.FormatFromDateTime(dueDateTime, TimestampTagStyles.ShortTime)} ― {(activity.IsClosed ? "Fermée" : TimestampTag.FormatFromDateTime(dueDateTime, TimestampTagStyles.Relative))}**");
}
else
{
@@ -92,7 +92,7 @@ public class ActivityFormatter
string bannerUrl = GetActivityBanner(activity.Name);
var color = activityFull ? Colors.CocotteOrange : Colors.CocotteBlue;
var color = activity.IsClosed ? Colors.CocotteRed : (activityFull ? Colors.CocotteOrange : Colors.CocotteBlue);
var builder = new EmbedBuilder()
.WithColor(color)

View File

@@ -1,4 +1,7 @@
using Cocotte.Options;
using Cocotte.Modules.Activities.Models;
using Cocotte.Options;
using Cocotte.Utils;
using Discord;
using Discord.WebSocket;
using Microsoft.Extensions.Options;
@@ -9,9 +12,13 @@ public class ActivityHelper
private const uint UnlimitedPlayers = uint.MaxValue;
private readonly ActivityOptions _options;
private readonly ActivitiesRepository _activitiesRepository;
private readonly ActivityFormatter _activityFormatter;
public ActivityHelper(IOptions<ActivityOptions> options)
public ActivityHelper(IOptions<ActivityOptions> options, ActivitiesRepository activitiesRepository, ActivityFormatter activityFormatter)
{
_activitiesRepository = activitiesRepository;
_activityFormatter = activityFormatter;
_options = options.Value;
}
@@ -72,4 +79,50 @@ public class ActivityHelper
_ => 0
};
public async Task UpdateActivityEmbed(IMessageChannel channel, Activity activity, ActivityUpdateReason updateReason)
{
// Fetch players
var players = await _activitiesRepository.LoadActivityPlayers(activity);
await channel.ModifyMessageAsync(activity.MessageId, properties =>
{
properties.Embed = _activityFormatter.ActivityEmbed(activity, players).Build();
// Disable join button if the activity is full on join, enable it on leave if activity is not full anymore
var isActivityFull = players.Count >= activity.MaxPlayers;
properties.Components = updateReason switch
{
ActivityUpdateReason.PlayerJoin when isActivityFull => ActivityComponents(activity.MessageId, disabled: true).Build(),
ActivityUpdateReason.PlayerLeave when !isActivityFull => ActivityComponents(activity.MessageId, disabled: false).Build(),
_ => Optional<MessageComponent>.Unspecified
};
});
}
public ComponentBuilder ActivityComponents(ulong activityId, bool disabled = false)
{
return new ComponentBuilder()
.AddRow(new ActionRowBuilder()
.WithButton(new ButtonBuilder()
.WithLabel("Rejoindre")
.WithCustomId($"activity join:{activityId}")
.WithEmote(":white_check_mark:".ToEmote())
.WithStyle(ButtonStyle.Primary)
.WithDisabled(disabled)
)
.WithButton(new ButtonBuilder()
.WithLabel("Se désinscrire")
.WithCustomId($"activity leave:{activityId}")
.WithEmote(":x:".ToEmote())
.WithStyle(ButtonStyle.Secondary)
)
.WithButton(new ButtonBuilder()
.WithLabel("Supprimer")
.WithCustomId($"activity delete:{activityId}")
.WithEmote(":wastebasket:".ToEmote())
.WithStyle(ButtonStyle.Danger)
)
);
}
}

View File

@@ -7,6 +7,7 @@ using Discord;
using Discord.Interactions;
using Discord.WebSocket;
using Microsoft.Extensions.Options;
using Quartz;
using Alias = Discord.Commands.AliasAttribute;
namespace Cocotte.Modules.Activities;
@@ -23,15 +24,19 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
private readonly ActivityHelper _activityHelper;
private readonly ActivitiesRepository _activitiesRepository;
private readonly ActivityFormatter _activityFormatter;
private readonly ISchedulerFactory _schedulerFactory;
private SocketGuildUser User => (SocketGuildUser) Context.User;
public ActivityModule(ILogger<ActivityModule> logger, IOptions<ActivityOptions> options, ActivityHelper activityHelper, ActivitiesRepository activitiesRepository, ActivityFormatter activityFormatter)
public ActivityModule(ILogger<ActivityModule> logger, IOptions<ActivityOptions> options,
ActivityHelper activityHelper, ActivitiesRepository activitiesRepository,
ActivityFormatter activityFormatter, ISchedulerFactory schedulerFactory)
{
_logger = logger;
_activityHelper = activityHelper;
_activitiesRepository = activitiesRepository;
_activityFormatter = activityFormatter;
_schedulerFactory = schedulerFactory;
_options = options.Value;
}
@@ -53,90 +58,122 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
[SlashCommand("abime-néant", "Créer un groupe pour l'Abîme du Néant")]
[Alias("abime", "abyss")]
public async Task ActivityVoidAbyss([Summary("étage", "A quel étage vous êtes")] [MinValue(1), MaxValue(6)] uint stage, [Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityVoidAbyss(
[Summary("étage", "A quel étage vous êtes")] [MinValue(1), MaxValue(6)] uint stage,
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.Abyss, timeInput, description, stage: stage);
}
[SlashCommand("origine-guerre", "Créer un groupe pour l'Origine de la guerre")]
[Alias("origine", "OOW")]
public async Task ActivityOrigins([Summary("étage", "A quel étage vous êtes")] [MinValue(1), MaxValue(25)] uint stage, [Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityOrigins(
[Summary("étage", "A quel étage vous êtes")] [MinValue(1), MaxValue(25)] uint stage,
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.OriginsOfWar, timeInput, description, stage: stage);
}
[SlashCommand("raids", "Créer un groupe pour les Raids")]
public async Task ActivityRaids([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityRaids(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.Raids, timeInput, description);
}
[SlashCommand("conflit-frontalier", "Créer un groupe pour Conflit frontalier")]
[Alias("conflit", "FC")]
public async Task ActivityFrontierClash([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityFrontierClash(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.FrontierClash, timeInput, description);
}
[SlashCommand("failles-neant", "Créer un groupe pour les Failles du néant")]
[Alias("failles", "rift")]
public async Task ActivityVoidRift([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityVoidRift(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.VoidRift, timeInput, description);
}
[SlashCommand("operations-conjointes", "Créer un groupe pour les Opérations conjointes")]
[Alias("operations", "JO")]
public async Task ActivityJointOperation([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityJointOperation(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.JointOperation, timeInput, description);
}
[SlashCommand("portes-interstellaires", "Créer un groupe pour les Portes interstellaires")]
[Alias("portes")]
public async Task ActivityInterstellarExploration([Summary("couleur", "De quel couleur de matériaux s'agît-il")] InterstellarColor color, [Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityInterstellarExploration(
[Summary("couleur", "De quel couleur de matériaux s'agît-il")] InterstellarColor color,
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.InterstellarExploration, timeInput, description, areRolesEnabled: false, interstellarColor: color);
await CreateActivity(ActivityName.InterstellarExploration, timeInput, description, areRolesEnabled: false,
interstellarColor: color);
}
[SlashCommand("3v3", "Créer un groupe pour le 3v3 (Échapper au destin)")]
[Alias("BR")]
public async Task ActivityBreakFromDestiny([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityBreakFromDestiny(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.BreakFromDestiny, timeInput, description, areRolesEnabled: false);
}
[SlashCommand("8v8", "Créer un groupe pour le 8v8 (Abîme critique)")]
[Alias("critical")]
public async Task ActivityCriticalAbyss([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityCriticalAbyss(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.CriticalAbyss, timeInput, description);
}
[SlashCommand("evenement", "Créer un groupe pour les évènements")]
[Alias("event")]
public async Task ActivityEvent([Summary("joueurs", "Nombre de joueurs maximum pour cette activité")] [MinValue(2), MaxValue(16)] uint maxPlayers = 8, [Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityEvent(
[Summary("joueurs", "Nombre de joueurs maximum pour cette activité")] [MinValue(2), MaxValue(16)]
uint maxPlayers = 8, [Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.Event, timeInput, description, areRolesEnabled: false, maxPlayers: maxPlayers);
await CreateActivity(ActivityName.Event, timeInput, description, areRolesEnabled: false,
maxPlayers: maxPlayers);
}
[SlashCommand("peche", "Créer un groupe pour de la pêche")]
[Alias("fishing")]
public async Task ActivityFishing([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityFishing(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.Fishing, timeInput, description, areRolesEnabled: false);
}
[SlashCommand("course", "Créer un groupe pour les courses de Mirroria")]
[Alias("BR")]
public async Task ActivityMirroriaRace([Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
public async Task ActivityMirroriaRace(
[Summary("heure", "Heure à laquelle l'activité est prévue")] string? timeInput = null,
[Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{
await CreateActivity(ActivityName.MirroriaRace, timeInput, description, areRolesEnabled: false);
}
#endregion
private async Task CreateActivity(ActivityName activityName, string? timeInput, string description, bool areRolesEnabled = true, uint? maxPlayers = null, uint? stage = null, InterstellarColor? interstellarColor = null)
private async Task CreateActivity(ActivityName activityName, string? timeInput, string description,
bool areRolesEnabled = true, uint? maxPlayers = null, uint? stage = null,
InterstellarColor? interstellarColor = null)
{
// Check time if it's specified
DateTime? dueDate = null;
@@ -146,7 +183,10 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed("**Heure invalide**, essayez avec le **format** `heure:minutes`\nPar exemple: `15:30`").Build()
embed: EmbedUtils
.ErrorEmbed(
"**Heure invalide**, essayez avec le **format** `heure:minutes`\nPar exemple: `15:30`")
.Build()
);
return;
@@ -237,37 +277,63 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
await _activitiesRepository.SaveChanges();
// Add components
var components = ActivityComponents(activity.MessageId);
var components = _activityHelper.ActivityComponents(activity.MessageId);
await ModifyOriginalResponseAsync(m =>
{
m.Content = "";
m.Components = components.Build();
m.Embed = _activityFormatter.ActivityEmbed(activity, Enumerable.Repeat(rolePlayer, 1).ToImmutableList()).Build();
m.Embed = _activityFormatter.ActivityEmbed(activity, Enumerable.Repeat(rolePlayer, 1).ToImmutableList())
.Build();
});
// Add job to close this activity in scheduler if due date is specified
if (dueDate is { } dueDateTime)
{
var scheduler = await _schedulerFactory.GetScheduler();
var job = JobBuilder.Create<ActivityCloseJob>()
.WithIdentity(activity.JobKey, "activity-close")
.WithDescription("Automatically close an activity after due date has passed")
.UsingJobData(nameof(ActivityCloseJob.GuildId), (long) activity.GuildId)
.UsingJobData(nameof(ActivityCloseJob.ChannelId), (long) activity.ChannelId)
.UsingJobData(nameof(ActivityCloseJob.MessageId), (long) activity.MessageId)
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity($"{activity.JobKey}-trigger", "activity-close")
.StartAt(dueDateTime)
.ForJob(job)
.Build();
await scheduler.ScheduleJob(job, trigger);
}
}
private ActivityPlayer CreateActivityPlayer(Activity activity, SocketGuildUser user, bool areRolesEnabled)
{
return areRolesEnabled ? new ActivityRolePlayer
{
Activity = activity,
UserId = user.Id,
Name = user.DisplayName,
Roles = _activityHelper.GetPlayerRoles(user.Roles)
} : new ActivityPlayer
{
Activity = activity,
UserId = user.Id,
Name = user.DisplayName
};
return areRolesEnabled
? new ActivityRolePlayer
{
Activity = activity,
UserId = user.Id,
Name = user.DisplayName,
Roles = _activityHelper.GetPlayerRoles(user.Roles)
}
: new ActivityPlayer
{
Activity = activity,
UserId = user.Id,
Name = user.DisplayName
};
}
[ComponentInteraction("activity join:*", ignoreGroupNames: true)]
public async Task JoinActivity(ulong messageId)
{
// Check if activity exists
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not
{ } activity)
{
await RespondAsync(
ephemeral: true,
@@ -292,7 +358,8 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
public async Task LeaveActivity(ulong messageId)
{
// Check if activity exists
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not
{ } activity)
{
await RespondAsync(
ephemeral: true,
@@ -317,7 +384,8 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
public async Task DeleteActivity(ulong messageId)
{
// Check if activity exists
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not
{ } activity)
{
await RespondAsync(
ephemeral: true,
@@ -352,12 +420,27 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
private async Task<bool> AddUserToActivity(Activity activity, SocketGuildUser user, bool self)
{
// If player is already registered
if (await _activitiesRepository.FindActivityPlayer(activity.GuildId, activity.ChannelId, activity.MessageId, user.Id) is not
if (await _activitiesRepository.FindActivityPlayer(activity.GuildId, activity.ChannelId, activity.MessageId,
user.Id) is not
null)
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed(self ? "Vous êtes **déjà inscrit** à cette activité" : $"{user.DisplayName} est **déjà inscrit** à cette activité").Build()
embed: EmbedUtils
.ErrorEmbed(self
? "Vous êtes **déjà inscrit** à cette activité"
: $"{user.DisplayName} est **déjà inscrit** à cette activité").Build()
);
return false;
}
// Check if activity is closed
if (activity.IsClosed)
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed("Cette activité est fermée").Build()
);
return false;
@@ -410,11 +493,15 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
private async Task<bool> RemovePlayerFromActivity(Activity activity, SocketGuildUser user, bool self)
{
// Check if player is in activity
if (await _activitiesRepository.FindActivityPlayer(activity.GuildId, activity.ChannelId, activity.MessageId, user.Id) is not { } activityPlayer)
if (await _activitiesRepository.FindActivityPlayer(activity.GuildId, activity.ChannelId, activity.MessageId,
user.Id) is not { } activityPlayer)
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed(self ? "Vous n'êtes **pas inscrit** à cette activité" : $"{user.DisplayName} n'est **pas inscrit** à cette activité").Build()
embed: EmbedUtils
.ErrorEmbed(self
? "Vous n'êtes **pas inscrit** à cette activité"
: $"{user.DisplayName} n'est **pas inscrit** à cette activité").Build()
);
return false;
@@ -458,47 +545,6 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
return;
}
// Fetch players
var players = await _activitiesRepository.LoadActivityPlayers(activity);
await channel.ModifyMessageAsync(activity.MessageId, properties =>
{
properties.Embed = _activityFormatter.ActivityEmbed(activity, players).Build();
// Disable join button if the activity is full on join, enable it on leave if activity is not full anymore
var isActivityFull = players.Count >= activity.MaxPlayers;
properties.Components = updateReason switch
{
ActivityUpdateReason.PlayerJoin when isActivityFull => ActivityComponents(activity.MessageId, disabled: true).Build(),
ActivityUpdateReason.PlayerLeave when !isActivityFull => ActivityComponents(activity.MessageId, disabled: false).Build(),
_ => Optional<MessageComponent>.Unspecified
};
});
await _activityHelper.UpdateActivityEmbed(channel, activity, updateReason);
}
private static ComponentBuilder ActivityComponents(ulong activityId, bool disabled = false)
{
return new ComponentBuilder()
.AddRow(new ActionRowBuilder()
.WithButton(new ButtonBuilder()
.WithLabel("Rejoindre")
.WithCustomId($"activity join:{activityId}")
.WithEmote(":white_check_mark:".ToEmote())
.WithStyle(ButtonStyle.Primary)
.WithDisabled(disabled)
)
.WithButton(new ButtonBuilder()
.WithLabel("Se désinscrire")
.WithCustomId($"activity leave:{activityId}")
.WithEmote(":x:".ToEmote())
.WithStyle(ButtonStyle.Secondary)
)
.WithButton(new ButtonBuilder()
.WithLabel("Supprimer")
.WithCustomId($"activity delete:{activityId}")
.WithEmote(":wastebasket:".ToEmote())
.WithStyle(ButtonStyle.Danger)
)
);
}
}
}

View File

@@ -25,9 +25,12 @@ public class Activity
public required uint MaxPlayers { get; set; }
public DateTime CreationDate { get; init; } = DateTime.Now;
public bool IsClosed { get; set; }
public List<ActivityPlayer> ActivityPlayers { get; init; } = new();
public string JobKey => $"{GuildId}/{ChannelId}/{MessageId}";
public override string ToString()
{
return $"{nameof(MessageId)}: {MessageId}, {nameof(CreatorUserId)}: {CreatorUserId}, {nameof(Description)}: {Description}, {nameof(Type)}: {Type}, {nameof(Name)}: {Name}, {nameof(MaxPlayers)}: {MaxPlayers}";

View File

@@ -8,6 +8,7 @@ using Discord.Commands;
using Discord.Interactions;
using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using Quartz;
DiscordSocketConfig discordSocketConfig = new()
{
@@ -25,6 +26,18 @@ IHost host = Host.CreateDefaultBuilder(args)
})
.ConfigureServices((context, services) =>
{
// Quartz service
services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionJobFactory();
q.UsePersistentStore(options =>
{
options.UseJsonSerializer();
options.UseMicrosoftSQLite("Data Source=cocotte.db");
});
});
services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true);
// Options
services.Configure<DiscordOptions>(context.Configuration.GetSection(DiscordOptions.SectionName));
services.Configure<ActivityOptions>(context.Configuration.GetSection(ActivityOptions.SectionName));
@@ -32,8 +45,8 @@ IHost host = Host.CreateDefaultBuilder(args)
// Database
services.AddDbContext<CocotteDbContext>(options =>
options.UseSqlite(context.Configuration.GetConnectionString("CocotteContext")), ServiceLifetime.Transient, ServiceLifetime.Transient);
services.AddTransient<ActivitiesRepository>();
options.UseSqlite(context.Configuration.GetConnectionString("CocotteContext")));
services.AddScoped<ActivitiesRepository>();
// Discord.Net
services.AddHostedService<DiscordLoggingService>();
@@ -53,19 +66,16 @@ IHost host = Host.CreateDefaultBuilder(args)
// Activities
services.AddTransient<ActivityFormatter>();
services.AddTransient<InterstellarFormatter>();
services.AddTransient<ActivityHelper>();
services.AddScoped<ActivityHelper>();
services.AddScoped<ActivityCloseJob>();
// Composite roles
services.AddSingleton<CompositeRolesListener>();
// Raids
services.AddTransient<RaidFormatter>();
services.AddSingleton<RaidRegisterManager>();
services.AddTransient<RosterAssigner>();
// Custom
services.AddSingleton<SharedCounter>();
services.AddTransient<TransientCounter>();
// services.AddTransient<RaidFormatter>();
// services.AddSingleton<RaidRegisterManager>();
// services.AddTransient<RosterAssigner>();
})
.Build();

View File

@@ -1,4 +1,6 @@
using Cocotte.Modules.Activities.Models;
using AppAny.Quartz.EntityFrameworkCore.Migrations;
using AppAny.Quartz.EntityFrameworkCore.Migrations.SQLite;
using Cocotte.Modules.Activities.Models;
using Microsoft.EntityFrameworkCore;
namespace Cocotte.Services;
@@ -16,4 +18,12 @@ public class CocotteDbContext : DbContext
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Adds Quartz.NET SQLite schema to EntityFrameworkCore
modelBuilder.AddQuartz(builder => builder.UseSqlite());
}
}

View File

@@ -52,11 +52,11 @@ public class CocotteService : BackgroundService
}
// Initialize modules and commands
// await _interactionService.AddModulesAsync(Assembly.GetEntryAssembly(), _serviceProvider);
using var scope = _serviceProvider.CreateScope();
#if DEBUG
await _interactionService.AddModuleAsync(typeof(Modules.Ping.PingModule), _serviceProvider);
await _interactionService.AddModuleAsync(typeof(Modules.Ping.PingModule), scope.ServiceProvider);
#endif
await _interactionService.AddModuleAsync(typeof(ActivityModule), _serviceProvider);
await _interactionService.AddModuleAsync(typeof(ActivityModule), scope.ServiceProvider);
_client.Ready += ClientOnReady;
_client.InteractionCreated += HandleInteraction;

View File

@@ -1,6 +0,0 @@
namespace Cocotte.Services;
public class SharedCounter
{
public int Count { get; set; } = 0;
}

View File

@@ -1,6 +0,0 @@
namespace Cocotte.Services;
public class TransientCounter
{
public int Count { get; set; } = 0;
}

View File

@@ -3,7 +3,10 @@
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information",
"Cocotte": "Trace"
"Cocotte": "Trace",
"Quartz": "Information",
"Quartz.Core.QuartzSchedulerThread": "Information",
"Quartz.Core.JobRunShell": "Information"
}
}
}