diff --git a/EventBot/EventBot.csproj b/EventBot/EventBot.csproj
index b29189f..25ce4df 100644
--- a/EventBot/EventBot.csproj
+++ b/EventBot/EventBot.csproj
@@ -6,14 +6,7 @@
-
-
-
-
-
-
-
-
+
@@ -28,7 +21,6 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
@@ -37,8 +29,4 @@
-
-
-
-
diff --git a/EventBot/Migrations/Sqlite/20190618165006_InitialDatabase.Designer.cs b/EventBot/Migrations/Sqlite/20190618165006_InitialDatabase.Designer.cs
new file mode 100644
index 0000000..0c1d9bd
--- /dev/null
+++ b/EventBot/Migrations/Sqlite/20190618165006_InitialDatabase.Designer.cs
@@ -0,0 +1,140 @@
+//
+using System;
+using EventBot.Services;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace EventBot.Migrations.Sqlite
+{
+ [DbContext(typeof(SqliteDatabaseService))]
+ [Migration("20190618165006_InitialDatabase")]
+ partial class InitialDatabase
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
+
+ modelBuilder.Entity("EventBot.Entities.Event", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Active");
+
+ b.Property("Description");
+
+ b.Property("GuildId");
+
+ b.Property("MessageChannelId");
+
+ b.Property("MessageId");
+
+ b.Property("Opened");
+
+ b.Property("Title");
+
+ b.Property("Type");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GuildId");
+
+ b.ToTable("Events");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventParticipant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("EventId");
+
+ b.Property("EventRoleId");
+
+ b.Property("UserData");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EventId");
+
+ b.HasIndex("EventRoleId");
+
+ b.ToTable("EventParticipants");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Description");
+
+ b.Property("Emote");
+
+ b.Property("EventId");
+
+ b.Property("MaxParticipants");
+
+ b.Property("Title");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EventId");
+
+ b.ToTable("EventRoles");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.GuildConfig", b =>
+ {
+ b.Property("GuildId")
+ .ValueGeneratedOnAdd();
+
+ b.Property("EventRoleConfirmationChannelId");
+
+ b.Property("ParticipantRoleId");
+
+ b.Property("Prefix");
+
+ b.HasKey("GuildId");
+
+ b.ToTable("GuildConfigs");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.Event", b =>
+ {
+ b.HasOne("EventBot.Entities.GuildConfig", "Guild")
+ .WithMany("Events")
+ .HasForeignKey("GuildId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventParticipant", b =>
+ {
+ b.HasOne("EventBot.Entities.Event", "Event")
+ .WithMany("Participants")
+ .HasForeignKey("EventId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("EventBot.Entities.EventRole", "Role")
+ .WithMany("Participants")
+ .HasForeignKey("EventRoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventRole", b =>
+ {
+ b.HasOne("EventBot.Entities.Event", "Event")
+ .WithMany("Roles")
+ .HasForeignKey("EventId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/EventBot/Migrations/Sqlite/20190618165006_InitialDatabase.cs b/EventBot/Migrations/Sqlite/20190618165006_InitialDatabase.cs
new file mode 100644
index 0000000..fb61cbf
--- /dev/null
+++ b/EventBot/Migrations/Sqlite/20190618165006_InitialDatabase.cs
@@ -0,0 +1,138 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace EventBot.Migrations.Sqlite
+{
+ public partial class InitialDatabase : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "GuildConfigs",
+ columns: table => new
+ {
+ GuildId = table.Column(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Prefix = table.Column(nullable: true),
+ EventRoleConfirmationChannelId = table.Column(nullable: false),
+ ParticipantRoleId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_GuildConfigs", x => x.GuildId);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Events",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Title = table.Column(nullable: true),
+ Description = table.Column(nullable: true),
+ Active = table.Column(nullable: false),
+ MessageId = table.Column(nullable: false),
+ MessageChannelId = table.Column(nullable: false),
+ Opened = table.Column(nullable: false),
+ Type = table.Column(nullable: false),
+ GuildId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Events", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Events_GuildConfigs_GuildId",
+ column: x => x.GuildId,
+ principalTable: "GuildConfigs",
+ principalColumn: "GuildId",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "EventRoles",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Title = table.Column(nullable: true),
+ Description = table.Column(nullable: true),
+ Emote = table.Column(nullable: true),
+ MaxParticipants = table.Column(nullable: false),
+ EventId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_EventRoles", x => x.Id);
+ table.ForeignKey(
+ name: "FK_EventRoles_Events_EventId",
+ column: x => x.EventId,
+ principalTable: "Events",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "EventParticipants",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ EventRoleId = table.Column(nullable: false),
+ EventId = table.Column(nullable: false),
+ UserId = table.Column(nullable: false),
+ UserData = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_EventParticipants", x => x.Id);
+ table.ForeignKey(
+ name: "FK_EventParticipants_Events_EventId",
+ column: x => x.EventId,
+ principalTable: "Events",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_EventParticipants_EventRoles_EventRoleId",
+ column: x => x.EventRoleId,
+ principalTable: "EventRoles",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_EventParticipants_EventId",
+ table: "EventParticipants",
+ column: "EventId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_EventParticipants_EventRoleId",
+ table: "EventParticipants",
+ column: "EventRoleId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_EventRoles_EventId",
+ table: "EventRoles",
+ column: "EventId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Events_GuildId",
+ table: "Events",
+ column: "GuildId");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "EventParticipants");
+
+ migrationBuilder.DropTable(
+ name: "EventRoles");
+
+ migrationBuilder.DropTable(
+ name: "Events");
+
+ migrationBuilder.DropTable(
+ name: "GuildConfigs");
+ }
+ }
+}
diff --git a/EventBot/Migrations/Sqlite/SqliteDatabaseServiceModelSnapshot.cs b/EventBot/Migrations/Sqlite/SqliteDatabaseServiceModelSnapshot.cs
new file mode 100644
index 0000000..0ce9158
--- /dev/null
+++ b/EventBot/Migrations/Sqlite/SqliteDatabaseServiceModelSnapshot.cs
@@ -0,0 +1,138 @@
+//
+using System;
+using EventBot.Services;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace EventBot.Migrations.Sqlite
+{
+ [DbContext(typeof(SqliteDatabaseService))]
+ partial class SqliteDatabaseServiceModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
+
+ modelBuilder.Entity("EventBot.Entities.Event", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Active");
+
+ b.Property("Description");
+
+ b.Property("GuildId");
+
+ b.Property("MessageChannelId");
+
+ b.Property("MessageId");
+
+ b.Property("Opened");
+
+ b.Property("Title");
+
+ b.Property("Type");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GuildId");
+
+ b.ToTable("Events");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventParticipant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("EventId");
+
+ b.Property("EventRoleId");
+
+ b.Property("UserData");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EventId");
+
+ b.HasIndex("EventRoleId");
+
+ b.ToTable("EventParticipants");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Description");
+
+ b.Property("Emote");
+
+ b.Property("EventId");
+
+ b.Property("MaxParticipants");
+
+ b.Property("Title");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EventId");
+
+ b.ToTable("EventRoles");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.GuildConfig", b =>
+ {
+ b.Property("GuildId")
+ .ValueGeneratedOnAdd();
+
+ b.Property("EventRoleConfirmationChannelId");
+
+ b.Property("ParticipantRoleId");
+
+ b.Property("Prefix");
+
+ b.HasKey("GuildId");
+
+ b.ToTable("GuildConfigs");
+ });
+
+ modelBuilder.Entity("EventBot.Entities.Event", b =>
+ {
+ b.HasOne("EventBot.Entities.GuildConfig", "Guild")
+ .WithMany("Events")
+ .HasForeignKey("GuildId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventParticipant", b =>
+ {
+ b.HasOne("EventBot.Entities.Event", "Event")
+ .WithMany("Participants")
+ .HasForeignKey("EventId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("EventBot.Entities.EventRole", "Role")
+ .WithMany("Participants")
+ .HasForeignKey("EventRoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("EventBot.Entities.EventRole", b =>
+ {
+ b.HasOne("EventBot.Entities.Event", "Event")
+ .WithMany("Roles")
+ .HasForeignKey("EventId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/EventBot/Misc/EmoteHelper.cs b/EventBot/Misc/EmoteHelper.cs
new file mode 100644
index 0000000..a1cbeed
--- /dev/null
+++ b/EventBot/Misc/EmoteHelper.cs
@@ -0,0 +1,79 @@
+using Discord;
+using System;
+
+namespace EventBot.Services
+{
+
+ public static class EmoteHelper
+ {
+ //private IEnumerable emoji;
+
+ private static readonly int[] EmojiRanges =
+ {
+ 0x1F600,0x1F64F, // Emoticons
+ 0x1F300,0x1F5FF, // Misc Symbols and Pictographs
+ 0x1F680,0x1F6FF, // Transport and Map
+ 0x1F1E6,0x1F1FF, // Regional country flags
+ 0x2600,0x26FF, // Misc symbols
+ 0x2700,0x27BF, // Dingbats
+ 0xE0020,0xE007F, // Tags
+ 0xFE00,0xFE0F, // Variation Selectors
+ 0x1F900,0x1F9FF, // Supplemental Symbols and Pictographs
+ 0x1F018,0x1F270, // Various asian characters
+ 0x238C,0x2454, // Misc items
+ 0x20D0,0x20FF // Combining Diacritical Marks for Symbols
+ };
+
+ public static bool TryParse(string input, out IEmote emote)
+ {
+ if(Emote.TryParse(input, out Emote parsedEmote))
+ {
+ emote = parsedEmote;
+ return true;
+ }
+ if(isEmoji(input))
+ {
+ emote = new Emoji(input);
+ return true;
+ }
+ emote = null;
+ return false;
+ }
+
+ public static IEmote Parse(string input)
+ {
+ if (!TryParse(input, out IEmote parsed))
+ throw new ArgumentException("Failed to parse emote.");
+ return parsed;
+ }
+
+ public static bool isEmoji(string input)
+ {
+ if (input.Length % 2 == 1) {
+ return false;
+ }
+ for (var i = 0; i < input.Length; i += 2)
+ {
+ if (!char.IsSurrogatePair(input[i], input[i + 1]))
+ {
+ return false;
+ }
+ var utf32 = char.ConvertToUtf32(input[i], input[i + 1]);
+ if (utf32 != 0x200D && !isEmojiChar(utf32))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public static bool isEmojiChar(int u32)
+ {;
+ for (int i = 0; i < EmojiRanges.Length; i+= 2)
+ if (u32 >= EmojiRanges[i] && u32 <= EmojiRanges[i + 1])
+ return true;
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/EventBot/Misc/EventTypeReader.cs b/EventBot/Misc/EventTypeReader.cs
index 9e15100..9f8fae0 100644
--- a/EventBot/Misc/EventTypeReader.cs
+++ b/EventBot/Misc/EventTypeReader.cs
@@ -18,9 +18,9 @@ namespace EventBot.Misc
return Task.FromResult(TypeReaderResult.FromError(CommandError.UnmetPrecondition, "Events are avaivable only inside guild context."));
Event ev;
if (input == null)
- ev = events.FindEventBy(context.Guild);
+ ev = events.FindEventBy(context.Guild, true);
else if (int.TryParse(input, out int id))
- ev = events.FindEventBy(context.Guild, id);
+ ev = events.FindEventBy(context.Guild, id, true);
else
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Event id is not a number."));
diff --git a/EventBot/Modules/EventModule.cs b/EventBot/Modules/EventModule.cs
index 95d38c4..b46e8f6 100644
--- a/EventBot/Modules/EventModule.cs
+++ b/EventBot/Modules/EventModule.cs
@@ -9,6 +9,7 @@ using System.Linq;
using EventBot.Entities;
using Discord.WebSocket;
using NeoSmart.Unicode;
+using Discord.Addons.Interactive;
namespace EventBot.Modules
{
@@ -53,16 +54,14 @@ namespace EventBot.Modules
[RequireUserPermission(GuildPermission.Administrator, Group = "Permission")]
[RequireOwner(Group = "Permission")]
[Group("event")]
- public class EventManagementModule : ModuleBase
+ public class EventManagementModule : InteractiveBase
{
private readonly EventManagementService _events;
private readonly DatabaseService _database;
- private readonly EmoteService _emotes;
- public EventManagementModule(EventManagementService events, DatabaseService database, EmoteService emotes)
+ public EventManagementModule(EventManagementService events, DatabaseService database)
{
_events = events;
_database = database;
- _emotes = emotes;
}
[Command("config logchannel")]
@@ -128,6 +127,8 @@ namespace EventBot.Modules
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
+ if (!@event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
@event.Title = title;
await _database.SaveChangesAsync();
await ReplyAsync($"Updated event(`{@event.Id}`) title to `{@event.Title}`");
@@ -143,6 +144,8 @@ namespace EventBot.Modules
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
+ if (!@event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
@event.Description = description;
await _database.SaveChangesAsync();
await ReplyAsync($"Updated event(`{@event.Id}`) description to `{@event.Description}`");
@@ -161,6 +164,8 @@ namespace EventBot.Modules
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
+ if (!@event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
if (@event.MessageId != 0 && @event.Type != type)
throw new Exception("Can't change event registration type when it's open for registration. Maube you meant to set type to `Unspecified` (-1)");
if(@event.Type != type)
@@ -183,11 +188,13 @@ namespace EventBot.Modules
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
- if(@event.Roles != null && @event.Roles.Count >= 20)
+ if (!@event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
+ if (@event.Roles != null && @event.Roles.Count >= 20)
throw new Exception("There are too many roles for this event.");
if(@event.MessageId != 0)
throw new Exception("Can't add new roles to event with open reigstration.");
- if (!_emotes.TryParse(emote, out IEmote parsedEmote))
+ if (!EmoteHelper.TryParse(emote, out IEmote parsedEmote))
throw new ArgumentException("Invalid emote provided.");
if(@event.Roles != null && @event.Roles.Count(r => r.Emote == parsedEmote.ToString()) > 0)
throw new ArgumentException("This emote is already used by other role.");
@@ -212,6 +219,8 @@ namespace EventBot.Modules
{
if(eventRole == null)
throw new Exception("Please provide correct role.");
+ if (!eventRole.Event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
eventRole.Title = title;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Updated event role `{eventRole.Id}` title to `{eventRole.Title}`");
@@ -227,6 +236,8 @@ namespace EventBot.Modules
{
if (eventRole == null)
throw new Exception("Please provide correct role.");
+ if (!eventRole.Event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
eventRole.Description = description;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Updated event role `{eventRole.Id}` description to `{eventRole.Description}`");
@@ -242,6 +253,8 @@ namespace EventBot.Modules
{
if (eventRole == null)
throw new Exception("Please provide correct role.");
+ if (!eventRole.Event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
eventRole.MaxParticipants = maxParticipants;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Updated event role `{eventRole.Id}` maximum participant count to `{eventRole.MaxParticipants}`");
@@ -258,7 +271,11 @@ namespace EventBot.Modules
{
if (eventRole == null)
throw new Exception("Please provide correct role.");
- if (!_emotes.TryParse(emote, out IEmote parsedEmote))
+ if (eventRole.Event.MessageId != 0)
+ throw new Exception("Role emote can't be edited while event is open for registrasion.");
+ if (!eventRole.Event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
+ if (!EmoteHelper.TryParse(emote, out IEmote parsedEmote))
throw new ArgumentException("Invalid emote provided.");
if (eventRole.Event.Roles.Count(r => r.Emote == parsedEmote.ToString()) > 0)
@@ -331,6 +348,8 @@ namespace EventBot.Modules
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("No events were found for this guild.");
+ if (!@event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
await Context.Message.DeleteAsync();
var message = await ReplyAsync(embed: _events.GenerateEventEmbed(@event).Build());
@@ -343,7 +362,7 @@ namespace EventBot.Modules
case Event.EventParticipactionType.Unspecified:
throw new Exception("Event type was unspecified.");
case Event.EventParticipactionType.Quick:
- await message.AddReactionsAsync(@event.Roles.OrderBy(e => e.SortNumber).Select(r => _emotes.Parse(r.Emote)).ToArray());
+ await message.AddReactionsAsync(@event.Roles.OrderBy(e => e.SortNumber).Select(r => EmoteHelper.Parse(r.Emote)).ToArray());
break;
case Event.EventParticipactionType.Detailed:
break;
@@ -351,6 +370,83 @@ namespace EventBot.Modules
throw new Exception("Event type in not implemented.");
}
}
+
+ [Command("close")]
+ [Summary("Closes event registration.")]
+ public async Task EventClose(
+ [Summary("Event to close")] Event @event = null)
+ {
+ if (@event == null)
+ @event = _events.FindEventBy(Context.Guild);
+ if (@event == null)
+ throw new Exception("No events were found for this guild.");
+ if (!@event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
+ if (@event.MessageId == 0)
+ throw new Exception("This event is already closed for registration.");
+
+ @event.MessageId = 0;
+ @event.MessageChannelId = 0;
+ await _database.SaveChangesAsync();
+ await ReplyAsync($"Event `{@event.Id}` registration has been closed, it's registration message will now be normal message.");
+ }
+
+ [Command("finalize")]
+ [Summary("Archives event and reverts all role additions. This is irreversable.")]
+ public async Task EventFinilize(
+ [Summary("Event to finilize")] Event @event = null)
+ {
+ if (@event == null)
+ @event = _events.FindEventBy(Context.Guild);
+ if (@event == null)
+ throw new Exception("No events were found for this guild.");
+ if (!@event.Active)
+ throw new Exception("This event is already finalized.");
+
+ @event.Active = false;
+ await _database.SaveChangesAsync();
+
+ await ReplyAsync($"Event `{@event.Id}` has been finilized. Removing participant roles...");
+ if (@event.Guild.ParticipantRoleId != 0)
+ foreach (var participant in @event.Participants)
+ {
+ var user = Context.Guild.GetUser(participant.UserId);
+ await user.RemoveRoleAsync(Context.Guild.GetRole(@event.Guild.ParticipantRoleId));
+ }
+ await ReplyAsync($"Everyone's roles have been removed. I hope it was fun!");
+ }
+
+ [Command("list")]
+ [Summary("Lists all prevous events that took on this server.")]
+ public async Task EventArchive()
+ {
+ var guildEvents = _database.Events.Where(e => e.GuildId == Context.Guild.Id).OrderBy(e => e.Opened).ToList();
+ if (guildEvents.Count() == 0)
+ throw new Exception("There are no events that roon on this server.");
+
+ var pagedEvents = guildEvents
+ .Select((e, i) => new { Event = e, Index = i })
+ .GroupBy(o => o.Index / 6)
+ .Select(g => g.Select(o => o.Event));
+ var pager = new PaginatedMessage()
+ {
+ Title = "List al all prevous events.",
+ Color = Color.Blue,
+ Options = new PaginatedAppearanceOptions()
+ {
+ Timeout = new TimeSpan(0, 3, 0),
+ DisplayInformationIcon = false,
+ JumpDisplayOptions = JumpDisplayOptions.Never
+ }
+ };
+ pager.Pages = pagedEvents.Select(eg =>
+ string.Join("\r\n", eg.Select(e =>
+ $"`{e.Id}` **{e.Title}** {(e.Active ? "✅" : "❌")}\r\n" +
+ $"Opened at {e.Opened.ToShortDateString()} {e.Opened.ToShortTimeString()}"
+ ))
+ );
+ await PagedReplyAsync(pager);
+ }
[Command("participant add")]
[Summary("Add user to event role. Acts like join command.")]
@@ -367,12 +463,14 @@ namespace EventBot.Modules
@event = _events.FindEventBy(Context.Guild);
if (@event == null & !(int.TryParse(emoteOrId, out int roleId)))
throw new Exception("Unable to locate any events for this guild.");
- else if (@event == null)
+ else if (@event == null || roleId != 0)
er = _database.EventRoles.FirstOrDefault(r => r.Id == roleId);
else
er = @event.Roles.FirstOrDefault(r => r.Emote == emoteOrId);
if (er == null)
throw new ArgumentException("Invalid emote or event id specified");
+ if (!er.Event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
await _events.TryJoinEvent(guildUser, er, extraInformation, false);
await Context.Message.DeleteAsync(); // Protect somewhat sensitive data.
@@ -388,6 +486,8 @@ namespace EventBot.Modules
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("No events were found for this guild.");
+ if (!@event.Active)
+ throw new Exception("This event is finalized. Please make a new event.");
if (!(user is IGuildUser guildUser))
throw new Exception("This command must be executed inside guild.");
diff --git a/EventBot/Program.cs b/EventBot/Program.cs
index 5530885..abae2fe 100644
--- a/EventBot/Program.cs
+++ b/EventBot/Program.cs
@@ -63,7 +63,6 @@ namespace EventBot
return new SqliteDatabaseService(sp);
})
.AddSingleton()
- .AddSingleton()
//.AddSingleton()
//.AddSingleton()
.BuildServiceProvider();
diff --git a/EventBot/Services/DatabaseService.cs b/EventBot/Services/DatabaseService.cs
index 13fd72f..20866b7 100644
--- a/EventBot/Services/DatabaseService.cs
+++ b/EventBot/Services/DatabaseService.cs
@@ -11,7 +11,7 @@ using System.Linq;
namespace EventBot.Services
{
- public abstract class DatabaseService: DbContext
+ public abstract class DatabaseService : DbContext
{
private readonly IServiceProvider _services;
private readonly DiscordSocketClient _discord;
@@ -36,6 +36,7 @@ namespace EventBot.Services
_discord = services.GetRequiredService();
_discord.GuildAvailable += OnGuildAvaivable;
}
+ public DatabaseService(): base() {}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
diff --git a/EventBot/Services/EmoteService.cs b/EventBot/Services/EmoteService.cs
deleted file mode 100644
index fe39c07..0000000
--- a/EventBot/Services/EmoteService.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using NeoSmart.Unicode;
-using System.Linq;
-using Discord;
-using DEmoji = Discord.Emoji;
-using UEmoji = NeoSmart.Unicode.Emoji;
-
-namespace EventBot.Services
-{
-
- public class EmoteService
- {
- private IEnumerable emoji;
-
- public EmoteService()
- {
- emoji = UEmoji.All.Select(e => e.Sequence.AsString);
- }
-
- public bool TryParse(string input, out IEmote emote)
- {
- if(Emote.TryParse(input, out Emote parsedEmote))
- {
- emote = parsedEmote;
- return true;
- }
- if(emoji.Contains(input))
- {
- emote = new DEmoji(input);
- return true;
- }
- emote = null;
- return false;
- }
-
- public IEmote Parse(string input)
- {
- if (!TryParse(input, out IEmote parsed))
- throw new ArgumentException("Failed to parse emote.");
- return parsed;
- }
-
- }
-}
\ No newline at end of file
diff --git a/EventBot/Services/EventManagementService.cs b/EventBot/Services/EventManagementService.cs
index 811f611..923394b 100644
--- a/EventBot/Services/EventManagementService.cs
+++ b/EventBot/Services/EventManagementService.cs
@@ -15,14 +15,12 @@ namespace EventBot.Services
{
private readonly DiscordSocketClient _discord;
private readonly DatabaseService _database;
- private readonly EmoteService _emotes;
private readonly IServiceProvider _services;
public EventManagementService(IServiceProvider services)
{
_discord = services.GetRequiredService();
_database = services.GetRequiredService();
- _emotes = services.GetRequiredService();
_services = services;
_discord.ReactionAdded += ReactionAddedAsync;
@@ -128,7 +126,7 @@ namespace EventBot.Services
var @event = _database.Events.FirstOrDefault(e => e.MessageId == message.Id);
if (@event != null)
{
- var role = @event.Roles.FirstOrDefault(r => reaction.Emote.Equals(_emotes.Parse(r.Emote)));
+ var role = @event.Roles.FirstOrDefault(r => reaction.Emote.Equals(EmoteHelper.Parse(r.Emote)));
if(role != null)
{
var userMessage = await message.GetOrDownloadAsync();
diff --git a/EventBot/Services/MySqlDatabaseService.cs b/EventBot/Services/MySqlDatabaseService.cs
index d0a31e9..1f87ace 100644
--- a/EventBot/Services/MySqlDatabaseService.cs
+++ b/EventBot/Services/MySqlDatabaseService.cs
@@ -9,6 +9,8 @@ namespace EventBot.Services
{
public MySqlDatabaseService(IServiceProvider services, DbContextOptions options) : base(services, options) { }
public MySqlDatabaseService(IServiceProvider services) : base(services) { }
+ public MySqlDatabaseService() : base() { }
+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
diff --git a/EventBot/Services/SqliteDatabaseService.cs b/EventBot/Services/SqliteDatabaseService.cs
index 021fbd4..f6c6320 100644
--- a/EventBot/Services/SqliteDatabaseService.cs
+++ b/EventBot/Services/SqliteDatabaseService.cs
@@ -9,6 +9,7 @@ namespace EventBot.Services
{
public SqliteDatabaseService(IServiceProvider services, DbContextOptions options) : base(services, options) { }
public SqliteDatabaseService(IServiceProvider services) : base(services) {}
+ public SqliteDatabaseService() : base() { }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
diff --git a/README b/README
new file mode 100644
index 0000000..7e6de9b
--- /dev/null
+++ b/README
@@ -0,0 +1,6 @@
+
+`set dbconnection="Server=localhost;Database=eventbot;User=root;Password=password;"`
+
+
+`Add-Migration InitialDatabase -Context MySqlDatabaseService -OutputDir Migrations\MySql`
+`Add-Migration InitialDatabase -Context SqliteDatabaseService -OutputDir Migrations\Sqlite`
\ No newline at end of file