diff --git a/.gitignore b/.gitignore
index f81f644..b7ebbd1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ obj/
/ChaosBot/obj/
.idea/
/ChaosBot/appsettings.json
+/ChaosBot/appsettings.*.json
/ChaosBot/ChaosBotSQL.db
*.sln.DotSettings.user
/.vs
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..f540351
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "ChaosBot/wwwroot"]
+ path = ChaosBot/wwwroot
+ url = ssh://git@git.chaoticlogic.us:2302/discord-bots/chaosbot-frontend.git
diff --git a/ChaosBot/ChaosBot.csproj b/ChaosBot/ChaosBot.csproj
index 67c2ad6..c1053c2 100644
--- a/ChaosBot/ChaosBot.csproj
+++ b/ChaosBot/ChaosBot.csproj
@@ -23,13 +23,22 @@
-
- PreserveNewest
-
+
+ PreserveNewest
+
+
+
+
+
+
+ true
+ PreserveNewest
+ PreserveNewest
+
diff --git a/ChaosBot/Discord/Services/CommandHandler.cs b/ChaosBot/Discord/Services/CommandHandler.cs
index f2d2290..73841d7 100644
--- a/ChaosBot/Discord/Services/CommandHandler.cs
+++ b/ChaosBot/Discord/Services/CommandHandler.cs
@@ -76,8 +76,11 @@ namespace ChaosBot.Discord.Services
if(Convert.ToBoolean(ConfigurationRepository.GetValue("Experience:Commands", context.Guild.Id, "false")))
ExperienceHandler.AddXp(context);
+
+ bool customCommandExecuted = await CustomCommandHandler.CheckCommand(context, argPos);
- await _commands.ExecuteAsync(context, argPos, _services);
+ if (!customCommandExecuted)
+ await _commands.ExecuteAsync(context, argPos, _services);
}
catch (Exception ex)
{
diff --git a/ChaosBot/Discord/Services/CustomCommandHandler.cs b/ChaosBot/Discord/Services/CustomCommandHandler.cs
new file mode 100644
index 0000000..536b8de
--- /dev/null
+++ b/ChaosBot/Discord/Services/CustomCommandHandler.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using ChaosBot.Models;
+using Discord.Commands;
+using NLog;
+
+namespace ChaosBot.Discord.Services
+{
+ public static class CustomCommandHandler
+ {
+ private static readonly ILogger Logger = Program.Logger;
+
+ public static async Task CheckCommand(SocketCommandContext context, int argPos)
+ {
+ try
+ {
+ await using ChaosbotContext dbContext = new ChaosbotContext();
+ string command = context.Message.Content.Substring(argPos);
+
+ IQueryable customCommandQuery = dbContext.CustomCommands;
+ CustomCommand customCommand = customCommandQuery
+ .Where(cc => cc.DiscordGuildId == context.Guild.Id)
+ .FirstOrDefault(cc => command.StartsWith((string) cc.Command));
+
+ if (customCommand == null) return false;
+
+ if (customCommand.Type == CustomCommandType.Basic)
+ {
+ await context.Channel.SendMessageAsync(customCommand.Content);
+ }
+ else
+ {
+ throw new NotImplementedException($"No support for command type ${customCommand.Type}");
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error($"{MethodBase.GetCurrentMethod().ReflectedType.FullName}: Exception [{ex}] thrown, <[{ex.Message}]>.");
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChaosBot/Migrations/20200824124830_CustomCommand.Designer.cs b/ChaosBot/Migrations/20200824124830_CustomCommand.Designer.cs
new file mode 100644
index 0000000..f256454
--- /dev/null
+++ b/ChaosBot/Migrations/20200824124830_CustomCommand.Designer.cs
@@ -0,0 +1,182 @@
+//
+using System;
+using ChaosBot.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace ChaosBot.Migrations
+{
+ [DbContext(typeof(ChaosbotContext))]
+ [Migration("20200824124830_CustomCommand")]
+ partial class CustomCommand
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.6")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("ChaosBot.Models.CommandPermission", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Command")
+ .IsRequired()
+ .HasColumnType("varchar(128) CHARACTER SET utf8mb4")
+ .HasMaxLength(128);
+
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("TargetId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("TargetType")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.ToTable("CommandPermissions");
+ });
+
+ modelBuilder.Entity("ChaosBot.Models.Configuration", b =>
+ {
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Key")
+ .HasColumnType("varchar(128) CHARACTER SET utf8mb4")
+ .HasMaxLength(128);
+
+ b.Property("SerializedValue")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.HasKey("DiscordGuildId", "Key");
+
+ b.ToTable("Configuration");
+ });
+
+ modelBuilder.Entity("ChaosBot.Models.Experience", b =>
+ {
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordUserId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Amount")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("LastUpdated")
+ .HasColumnType("datetime");
+
+ b.Property("Level")
+ .HasColumnType("bigint unsigned");
+
+ b.HasKey("DiscordGuildId", "DiscordUserId");
+
+ b.ToTable("ExperiencePoints");
+ });
+
+ modelBuilder.Entity("ChaosBot.Models.LodestoneCharacter", b =>
+ {
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("LodestoneId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Avatar")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.Property("DiscordUserId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.HasKey("DiscordGuildId", "LodestoneId");
+
+ b.ToTable("LodestoneCharacter");
+ });
+
+ modelBuilder.Entity("ChaosBot.Models.LodestoneFreeCompany", b =>
+ {
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("LodestoneId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.HasKey("DiscordGuildId", "LodestoneId");
+
+ b.ToTable("LodestoneFreeCompany");
+ });
+
+ modelBuilder.Entity("ChaosBot.Models.Point", b =>
+ {
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordUserId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Amount")
+ .HasColumnType("bigint unsigned");
+
+ b.HasKey("DiscordGuildId", "DiscordUserId");
+
+ b.ToTable("Points");
+ });
+
+ modelBuilder.Entity("ChaosBot.Models.Raffle", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordUserId")
+ .HasColumnType("bigint unsigned");
+
+ b.HasKey("Id");
+
+ b.ToTable("Raffles");
+ });
+
+ modelBuilder.Entity("ChaosBot.Models.RoleReaction", b =>
+ {
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordMessageId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordRoleId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordEmoteNameEncoded")
+ .HasColumnType("varchar(95) CHARACTER SET utf8mb4");
+
+ b.HasKey("DiscordGuildId", "DiscordMessageId", "DiscordRoleId", "DiscordEmoteNameEncoded");
+
+ b.ToTable("RoleReactions");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/ChaosBot/Migrations/20200824124830_CustomCommand.cs b/ChaosBot/Migrations/20200824124830_CustomCommand.cs
new file mode 100644
index 0000000..ec5acb0
--- /dev/null
+++ b/ChaosBot/Migrations/20200824124830_CustomCommand.cs
@@ -0,0 +1,32 @@
+using ChaosBot.Models;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace ChaosBot.Migrations
+{
+ public partial class CustomCommand : Migration
+ {
+ private readonly string Table = "CustomCommands";
+
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: Table,
+ columns: table => new
+ {
+ DiscordGuildId = table.Column(nullable: false),
+ Command = table.Column(nullable: false, maxLength: 128),
+ Type = table.Column(nullable: false),
+ Content = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_CustomCommands", x => new { x.DiscordGuildId, x.Command });
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(name: Table);
+ }
+ }
+}
diff --git a/ChaosBot/Migrations/ChaosbotContextModelSnapshot.cs b/ChaosBot/Migrations/ChaosbotContextModelSnapshot.cs
index 449c819..9abe71a 100644
--- a/ChaosBot/Migrations/ChaosbotContextModelSnapshot.cs
+++ b/ChaosBot/Migrations/ChaosbotContextModelSnapshot.cs
@@ -155,6 +155,25 @@ namespace ChaosBot.Migrations
b.ToTable("Raffles");
});
+
+ modelBuilder.Entity("ChaosBot.Models.RoleReaction", b =>
+ {
+ b.Property("DiscordGuildId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordMessageId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordRoleId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DiscordEmoteNameEncoded")
+ .HasColumnType("varchar(95) CHARACTER SET utf8mb4");
+
+ b.HasKey("DiscordGuildId", "DiscordMessageId", "DiscordRoleId", "DiscordEmoteNameEncoded");
+
+ b.ToTable("RoleReactions");
+ });
#pragma warning restore 612, 618
}
}
diff --git a/ChaosBot/Models/ChaosbotContext.cs b/ChaosBot/Models/ChaosbotContext.cs
index bb6c866..ced2e6f 100644
--- a/ChaosBot/Models/ChaosbotContext.cs
+++ b/ChaosBot/Models/ChaosbotContext.cs
@@ -13,6 +13,7 @@ namespace ChaosBot.Models
public DbSet Configuration { get; set; }
public DbSet ExperiencePoints { get; set; }
public DbSet RoleReactions { get; set; }
+ public DbSet CustomCommands { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
@@ -49,6 +50,8 @@ namespace ChaosBot.Models
.HasKey(x => new {x.DiscordGuildId, x.Key});
modelBuilder.Entity()
.HasKey(x => new {x.DiscordGuildId, x.DiscordMessageId, x.DiscordRoleId, x.DiscordEmoteNameEncoded});
+ modelBuilder.Entity()
+ .HasKey(x => new {x.DiscordGuildId, x.Command});
}
}
}
\ No newline at end of file
diff --git a/ChaosBot/Models/CustomCommand.cs b/ChaosBot/Models/CustomCommand.cs
new file mode 100644
index 0000000..d6fa2bb
--- /dev/null
+++ b/ChaosBot/Models/CustomCommand.cs
@@ -0,0 +1,27 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Text;
+
+namespace ChaosBot.Models
+{
+ #region Required
+ public class CustomCommand
+ {
+ [Required]
+ public ulong DiscordGuildId { get; set; }
+ [Required]
+ [MaxLength(128)]
+ public string Command { get; set; }
+ [Required]
+ public CustomCommandType Type { get; set; }
+ [Required]
+ public string Content { get; set; }
+ }
+ #endregion
+
+ public enum CustomCommandType
+ {
+ Basic
+ }
+}
\ No newline at end of file
diff --git a/ChaosBot/WebServer/Startup.cs b/ChaosBot/WebServer/Startup.cs
index 626847d..c36d89e 100644
--- a/ChaosBot/WebServer/Startup.cs
+++ b/ChaosBot/WebServer/Startup.cs
@@ -1,3 +1,4 @@
+using System.IO;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -36,12 +37,20 @@ namespace ChaosBot.WebServer
{
_logger.Info("Initializing Kestrel Startup and Configuration");
+ if (Program.AppSettingsHandler.GetValue("WebServer:Debug", false))
+ app.UseDeveloperExceptionPage();
+
app.UseForwardedHeaders();
- app.UseDeveloperExceptionPage();
app.UseMiddleware();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
+
+ DefaultFilesOptions options = new DefaultFilesOptions();
+ options.DefaultFileNames.Clear();
+ options.DefaultFileNames.Add("index.html");
+ app.UseDefaultFiles(options);
+ app.UseStaticFiles();
}
}
}
\ No newline at end of file
diff --git a/ChaosBot/WebServer/WebServer.cs b/ChaosBot/WebServer/WebServer.cs
index c3a3970..f9c1492 100644
--- a/ChaosBot/WebServer/WebServer.cs
+++ b/ChaosBot/WebServer/WebServer.cs
@@ -1,3 +1,4 @@
+using System.IO;
using System.Net;
using NLog.Extensions.Logging;
@@ -19,6 +20,11 @@ namespace ChaosBot.WebServer
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
+ string contentRoot = Directory.GetCurrentDirectory();
+ string webRoot = Path.Combine(contentRoot, "wwwroot/dist");
+
+ webBuilder.UseContentRoot(contentRoot);
+ webBuilder.UseWebRoot(webRoot);
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Any, Program.AppSettingsHandler.GetValue("WebServer:Port"),
diff --git a/ChaosBot/wwwroot b/ChaosBot/wwwroot
new file mode 160000
index 0000000..ad857be
--- /dev/null
+++ b/ChaosBot/wwwroot
@@ -0,0 +1 @@
+Subproject commit ad857be54bdaf13813a00458c242bcc808db89ec