From ab93380d7c0977f0cc64777f5dda87c9a3fefcad Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 13 Jun 2024 18:54:21 +0000 Subject: [PATCH] 5.1 --- CHANGELOG.md | 31 + .../Db/Models/support/PatronQuota.cs | 24 - src/NadekoBot/Db/NadekoContext.cs | 12 - ...611180516_remove-patron-limits.Designer.cs | 3784 +++++++++++++++++ .../20240611180516_remove-patron-limits.cs | 44 + .../Mysql/MysqlContextModelSnapshot.cs | 35 - ...611180506_remove-patron-limits.Designer.cs | 3781 ++++++++++++++++ .../20240611180506_remove-patron-limits.cs | 42 + .../PostgreSqlContextModelSnapshot.cs | 35 - ...611180456_remove-patron-limits.Designer.cs | 2921 +++++++++++++ .../20240611180456_remove-patron-limits.cs | 42 + .../NadekoSqliteContextModelSnapshot.cs | 27 - .../DangerousCommands/CleanupService.cs | 55 +- .../Administration/Prune/PruneCommands.cs | 36 +- .../Administration/Prune/PruneResult.cs | 9 + .../Administration/Prune/PruneService.cs | 23 +- .../Role/IReactionRoleService.cs | 2 +- .../Role/ReactionRoleCommands.cs | 6 +- .../Role/ReactionRolesService.cs | 23 +- .../Gambling/BlackJack/BlackJackCommands.cs | 1 + src/NadekoBot/Modules/Gambling/Gambling.cs | 21 +- .../Modules/Gambling/Shop/ShopCommands.cs | 10 +- .../Modules/Gambling/Slot/SlotCommands.cs | 1 + ...erBotCommands.cs => ChatterBotCommands.cs} | 7 +- ...tterbotService.cs => ChatterBotService.cs} | 140 +- .../Games/ChatterBot/_common/Gpt3Response.cs | 17 +- .../ChatterBot/_common/IChatterBotSession.cs | 5 +- .../_common/OfficialCleverbotSession.cs | 15 +- .../ChatterBot/_common/OfficialGpt3Session.cs | 105 - .../ChatterBot/_common/OfficialGptSession.cs | 141 + src/NadekoBot/Modules/Games/GamesConfig.cs | 28 +- .../Modules/Games/GamesConfigService.cs | 23 +- src/NadekoBot/Modules/Music/Music.cs | 1 + .../Modules/Music/Services/MusicService.cs | 2 +- .../Patronage/Config/PatronageConfig.cs | 9 + .../Modules/Patronage/InsufficientTier.cs | 11 - .../Patronage/Patreon/PatreonMemberData.cs | 5 - .../Modules/Patronage/PatronageCommands.cs | 58 +- .../Modules/Patronage/PatronageService.cs | 643 +-- .../Crypto/DefaultStockDataService.cs | 43 +- .../Modules/Searches/PathOfExileCommands.cs | 312 -- src/NadekoBot/Modules/Searches/Searches.cs | 3 +- .../Modules/Utility/Ai/AiAssistantService.cs | 314 ++ .../Modules/Utility/Ai/AiCommandModel.cs | 15 + .../Modules/Utility/Ai/AiCommandParamModel.cs | 12 + .../Utility/Ai/CommandPromptResultModel.cs | 16 + .../Modules/Utility/Ai/IAiAssistantService.cs | 20 + .../Utility/Ai/NadekoCommandCallModel.cs | 8 + .../Modules/Utility/Ai/UtilityCommands.cs | 23 + .../Modules/Utility/Info/InfoCommands.cs | 4 +- .../Modules/Utility/Remind/RemindCommands.cs | 12 +- src/NadekoBot/Modules/Xp/Xp.cs | 1 + src/NadekoBot/Modules/Xp/XpService.cs | 6 +- src/NadekoBot/NadekoBot.csproj | 4 +- .../Services/Impl/BotCredsProvider.cs | 6 + src/NadekoBot/Services/Impl/RedisBotCache.cs | 2 + .../Abstractions/creds/IBotCredentials.cs | 3 +- src/NadekoBot/_common/Creds.cs | 11 +- .../Models/NadekoButtonInteraction.cs | 1 + .../_common/Interaction/NadekoInteraction.cs | 3 + .../JsonConverters/CultureInfoConverter.cs | 2 +- .../JsonConverters/NumberToStringConverter.cs | 30 + .../_common/Patronage/FeatureLimitKey.cs | 7 + .../_common/Patronage/FeatureQuotaStats.cs | 8 - .../_common/Patronage/IPatronageService.cs | 25 +- src/NadekoBot/_common/Patronage/Patron.cs | 2 +- .../_common/Patronage/PatronConfigData.cs | 28 +- .../_common/Patronage/PatronExtensions.cs | 9 - src/NadekoBot/_common/Patronage/QuotaLimit.cs | 49 +- src/NadekoBot/_common/Patronage/QuotaPer.cs | 1 + .../_common/Patronage/UserQuotaStats.cs | 25 - .../ResponseBuilder.PaginationSender.cs | 20 +- .../_common/Services/CommandHandler.cs | 4 +- .../_Extensions/CommandContextExtensions.cs | 10 + .../_common/_Extensions/Extensions.cs | 1 + src/NadekoBot/data/aliases.yml | 14 +- src/NadekoBot/data/games.yml | 25 +- src/NadekoBot/data/patron.yml | 119 +- .../data/strings/commands/commands.en-US.yml | 389 +- .../strings/responses/responses.en-US.json | 8 +- 80 files changed, 12076 insertions(+), 1694 deletions(-) create mode 100644 src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs create mode 100644 src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs create mode 100644 src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs create mode 100644 src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs create mode 100644 src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs create mode 100644 src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs create mode 100644 src/NadekoBot/Modules/Administration/Prune/PruneResult.cs rename src/NadekoBot/Modules/Games/ChatterBot/{CleverBotCommands.cs => ChatterBotCommands.cs} (85%) rename src/NadekoBot/Modules/Games/ChatterBot/{ChatterbotService.cs => ChatterBotService.cs} (59%) delete mode 100644 src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs create mode 100644 src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs delete mode 100644 src/NadekoBot/Modules/Patronage/InsufficientTier.cs delete mode 100644 src/NadekoBot/Modules/Searches/PathOfExileCommands.cs create mode 100644 src/NadekoBot/Modules/Utility/Ai/AiAssistantService.cs create mode 100644 src/NadekoBot/Modules/Utility/Ai/AiCommandModel.cs create mode 100644 src/NadekoBot/Modules/Utility/Ai/AiCommandParamModel.cs create mode 100644 src/NadekoBot/Modules/Utility/Ai/CommandPromptResultModel.cs create mode 100644 src/NadekoBot/Modules/Utility/Ai/IAiAssistantService.cs create mode 100644 src/NadekoBot/Modules/Utility/Ai/NadekoCommandCallModel.cs create mode 100644 src/NadekoBot/Modules/Utility/Ai/UtilityCommands.cs create mode 100644 src/NadekoBot/_common/JsonConverters/NumberToStringConverter.cs delete mode 100644 src/NadekoBot/_common/Patronage/FeatureQuotaStats.cs delete mode 100644 src/NadekoBot/_common/Patronage/UserQuotaStats.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 2566ccd80..791346119 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,37 @@ Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o +## [5.1.0] - 02.06.2024 + +### Added + +- Added `.prompt` command, Nadeko Ai Assistant + - You can send natural language questions, queries or execute commands. For example "@Nadeko how's the weather in paris" and it will return `.we Paris` and run it for you. + - In case the bot can't execute a command using your query, It will fall back to your chatter bot, in case you have it enabled in data/games.yml. (Cleverbot or chatgpt) + - (It's far from perfect so please don't ask the bot to do dangerous things like banning or pruning) + - Requires Patreon subscription, after which you'll be able to run it on global @Nadeko bot. If you're selfhosting, you also will need to acquire the api key from (coming soon(ish)...) +- Added support for `gpt-4o` in `data/games.yml` +- Added nadekoAiToken to `creds.yml` + + +### Changed + +- Remind will now show a timestamp tag for durations +- Only `Gpt35Turbo` and `Gpt4o` are valid inputs in games.yml now +- `data/patron.yml` changed. It now has limits. The entire feature limit system has been reworked. Your previous settings will be reset +- A lot of updates to bot strings (thanks Ene) +- Improved cleanup command to delete a lot more data once cleanup is ran, not only guild configs (please don't use this command unless you have your database bakced up and you know 100% what you're doing) + +### Fixed + +- Fixed xp bg buy button not working, and possibly some other buttons too +- Fixed shopbuy %user% placeholders and updated help text + +### Removed + +- Removed PoE related commands +- dev: Removed patron quota data from the database, it will now be stored in redis + ## [5.0.8] - 21.05.2024 ### Added diff --git a/src/NadekoBot/Db/Models/support/PatronQuota.cs b/src/NadekoBot/Db/Models/support/PatronQuota.cs index 863dcd961..8568ead25 100644 --- a/src/NadekoBot/Db/Models/support/PatronQuota.cs +++ b/src/NadekoBot/Db/Models/support/PatronQuota.cs @@ -1,30 +1,6 @@ #nullable disable namespace NadekoBot.Db.Models; -/// -/// Contains data about usage of Patron-Only commands per user -/// in order to provide support for quota limitations -/// (allow user x who is pledging amount y to use the specified command only -/// x amount of times in the specified time period) -/// -public class PatronQuota -{ - public ulong UserId { get; set; } - public FeatureType FeatureType { get; set; } - public string Feature { get; set; } - public uint HourlyCount { get; set; } - public uint DailyCount { get; set; } - public uint MonthlyCount { get; set; } -} - -public enum FeatureType -{ - Command, - Group, - Module, - Limit -} - public class PatronUser { public string UniquePlatformUserId { get; set; } diff --git a/src/NadekoBot/Db/NadekoContext.cs b/src/NadekoBot/Db/NadekoContext.cs index e9e0d5b93..9fbc46e3b 100644 --- a/src/NadekoBot/Db/NadekoContext.cs +++ b/src/NadekoBot/Db/NadekoContext.cs @@ -53,8 +53,6 @@ public abstract class NadekoContext : DbContext public DbSet Patrons { get; set; } - public DbSet PatronQuotas { get; set; } - public DbSet StreamOnlineMessages { get; set; } public DbSet StickyRoles { get; set; } @@ -597,16 +595,6 @@ public abstract class NadekoContext : DbContext }); // quotes are per user id - modelBuilder.Entity(pq => - { - pq.HasIndex(x => x.UserId).IsUnique(false); - pq.HasKey(x => new - { - x.UserId, - x.FeatureType, - x.Feature - }); - }); #endregion diff --git a/src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs b/src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs new file mode 100644 index 000000000..1d52e8797 --- /dev/null +++ b/src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs @@ -0,0 +1,3784 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NadekoBot.Db; + +#nullable disable + +namespace NadekoBot.Migrations.Mysql +{ + [DbContext(typeof(MysqlContext))] + [Migration("20240611180516_remove-patron-limits")] + partial class removepatronlimits + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("int") + .HasColumnName("action"); + + b.Property("ActionDurationMinutes") + .HasColumnType("int") + .HasColumnName("actiondurationminutes"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("MinAge") + .HasColumnType("time(6)") + .HasColumnName("minage"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antialtsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antialtsetting_guildconfigid"); + + b.ToTable("antialtsetting", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("int") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("PunishDuration") + .HasColumnType("int") + .HasColumnName("punishduration"); + + b.Property("Seconds") + .HasColumnType("int") + .HasColumnName("seconds"); + + b.Property("UserThreshold") + .HasColumnType("int") + .HasColumnName("userthreshold"); + + b.HasKey("Id") + .HasName("pk_antiraidsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antiraidsetting_guildconfigid"); + + b.ToTable("antiraidsetting", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AntiSpamSettingId") + .HasColumnType("int") + .HasColumnName("antispamsettingid"); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.HasKey("Id") + .HasName("pk_antispamignore"); + + b.HasIndex("AntiSpamSettingId") + .HasDatabaseName("ix_antispamignore_antispamsettingid"); + + b.ToTable("antispamignore", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("int") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("MessageThreshold") + .HasColumnType("int") + .HasColumnName("messagethreshold"); + + b.Property("MuteTime") + .HasColumnType("int") + .HasColumnName("mutetime"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antispamsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antispamsetting_guildconfigid"); + + b.ToTable("antispamsetting", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ArchivedTodoListModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todosarchive"); + + b.ToTable("todosarchive", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("ChannelName") + .HasColumnType("longtext") + .HasColumnName("channelname"); + + b.Property("CommandText") + .HasColumnType("longtext") + .HasColumnName("commandtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("GuildName") + .HasColumnType("longtext") + .HasColumnName("guildname"); + + b.Property("Interval") + .HasColumnType("int") + .HasColumnName("interval"); + + b.Property("VoiceChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("voicechannelid"); + + b.Property("VoiceChannelName") + .HasColumnType("longtext") + .HasColumnName("voicechannelname"); + + b.HasKey("Id") + .HasName("pk_autocommands"); + + b.ToTable("autocommands", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoPublishChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autopublishchannel"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_autopublishchannel_guildid"); + + b.ToTable("autopublishchannel", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AutoDelete") + .HasColumnType("tinyint(1)") + .HasColumnName("autodelete"); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autotranslatechannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_autotranslatechannels_channelid"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_autotranslatechannels_guildid"); + + b.ToTable("autotranslatechannels", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("int") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Source") + .HasColumnType("longtext") + .HasColumnName("source"); + + b.Property("Target") + .HasColumnType("longtext") + .HasColumnName("target"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_autotranslateusers"); + + b.HasAlternateKey("ChannelId", "UserId") + .HasName("ak_autotranslateusers_channelid_userid"); + + b.ToTable("autotranslateusers", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BanTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("PruneDays") + .HasColumnType("int") + .HasColumnName("prunedays"); + + b.Property("Text") + .HasColumnType("longtext") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_bantemplates"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_bantemplates_guildid"); + + b.ToTable("bantemplates", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Balance") + .HasColumnType("bigint") + .HasColumnName("balance"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_bankusers"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_bankusers_userid"); + + b.ToTable("bankusers", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BlacklistEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("bigint unsigned") + .HasColumnName("itemid"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_blacklist"); + + b.ToTable("blacklist", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b => + { + b.Property("ClubId") + .HasColumnType("int") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("int") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubapplicants"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubapplicants_userid"); + + b.ToTable("clubapplicants", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b => + { + b.Property("ClubId") + .HasColumnType("int") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("int") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubbans"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubbans_userid"); + + b.ToTable("clubbans", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Description") + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("ImageUrl") + .HasColumnType("longtext") + .HasColumnName("imageurl"); + + b.Property("Name") + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name") + .UseCollation("utf8mb4_bin"); + + b.Property("OwnerId") + .HasColumnType("int") + .HasColumnName("ownerid"); + + b.Property("Xp") + .HasColumnType("int") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_clubs"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_clubs_name"); + + b.HasIndex("OwnerId") + .IsUnique() + .HasDatabaseName("ix_clubs_ownerid"); + + b.ToTable("clubs", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Mapping") + .HasColumnType("longtext") + .HasColumnName("mapping"); + + b.Property("Trigger") + .HasColumnType("longtext") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_commandalias"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandalias_guildconfigid"); + + b.ToTable("commandalias", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CommandName") + .HasColumnType("longtext") + .HasColumnName("commandname"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Seconds") + .HasColumnType("int") + .HasColumnName("seconds"); + + b.HasKey("Id") + .HasName("pk_commandcooldown"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandcooldown_guildconfigid"); + + b.ToTable("commandcooldown", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("extra"); + + b.Property("Note") + .HasColumnType("longtext") + .HasColumnName("note"); + + b.Property("OtherId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint unsigned") + .HasColumnName("otherid") + .HasDefaultValueSql("NULL"); + + b.Property("Type") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_currencytransactions"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_currencytransactions_userid"); + + b.ToTable("currencytransactions", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("State") + .HasColumnType("tinyint(1)") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_delmsgoncmdchannel"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_delmsgoncmdchannel_guildconfigid"); + + b.ToTable("delmsgoncmdchannel", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordPermOverride", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Command") + .HasColumnType("varchar(255)") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Perm") + .HasColumnType("bigint unsigned") + .HasColumnName("perm"); + + b.HasKey("Id") + .HasName("pk_discordpermoverrides"); + + b.HasIndex("GuildId", "Command") + .IsUnique() + .HasDatabaseName("ix_discordpermoverrides_guildid_command"); + + b.ToTable("discordpermoverrides", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AvatarId") + .HasColumnType("longtext") + .HasColumnName("avatarid"); + + b.Property("ClubId") + .HasColumnType("int") + .HasColumnName("clubid"); + + b.Property("CurrencyAmount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("currencyamount"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Discriminator") + .HasColumnType("longtext") + .HasColumnName("discriminator"); + + b.Property("IsClubAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("isclubadmin"); + + b.Property("NotifyOnLevelUp") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("notifyonlevelup"); + + b.Property("TotalXp") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("totalxp"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_discorduser"); + + b.HasAlternateKey("UserId") + .HasName("ak_discorduser_userid"); + + b.HasIndex("ClubId") + .HasDatabaseName("ix_discorduser_clubid"); + + b.HasIndex("CurrencyAmount") + .HasDatabaseName("ix_discorduser_currencyamount"); + + b.HasIndex("TotalXp") + .HasDatabaseName("ix_discorduser_totalxp"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_discorduser_userid"); + + b.ToTable("discorduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("bigint unsigned") + .HasColumnName("itemid"); + + b.Property("ItemType") + .HasColumnType("int") + .HasColumnName("itemtype"); + + b.Property("XpSettingsId") + .HasColumnType("int") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_excludeditem"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_excludeditem_xpsettingsid"); + + b.ToTable("excludeditem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("Url") + .IsRequired() + .HasColumnType("varchar(255)") + .HasColumnName("url"); + + b.HasKey("Id") + .HasName("pk_feedsub"); + + b.HasAlternateKey("GuildConfigId", "Url") + .HasName("ak_feedsub_guildconfigid_url"); + + b.ToTable("feedsub", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterchannelid_guildconfigid"); + + b.ToTable("filterchannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterLinksChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterlinkschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterlinkschannelid_guildconfigid"); + + b.ToTable("filterlinkschannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterWordsChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterwordschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterwordschannelid_guildconfigid"); + + b.ToTable("filterwordschannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Word") + .HasColumnType("longtext") + .HasColumnName("word"); + + b.HasKey("Id") + .HasName("pk_filteredword"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filteredword_guildconfigid"); + + b.ToTable("filteredword", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_followedstream"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_followedstream_guildconfigid"); + + b.ToTable("followedstream", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_gcchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_gcchannelid_guildconfigid"); + + b.ToTable("gcchannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GamblingStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Bet") + .HasColumnType("decimal(65,30)") + .HasColumnName("bet"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Feature") + .HasColumnType("varchar(255)") + .HasColumnName("feature"); + + b.Property("PaidOut") + .HasColumnType("decimal(65,30)") + .HasColumnName("paidout"); + + b.HasKey("Id") + .HasName("pk_gamblingstats"); + + b.HasIndex("Feature") + .IsUnique() + .HasDatabaseName("ix_gamblingstats_feature"); + + b.ToTable("gamblingstats", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("EndsAt") + .HasColumnType("datetime(6)") + .HasColumnName("endsat"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.HasKey("Id") + .HasName("pk_giveawaymodel"); + + b.ToTable("giveawaymodel", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("GiveawayId") + .HasColumnType("int") + .HasColumnName("giveawayid"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_giveawayuser"); + + b.HasIndex("GiveawayId", "UserId") + .IsUnique() + .HasDatabaseName("ix_giveawayuser_giveawayid_userid"); + + b.ToTable("giveawayuser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("Number") + .HasColumnType("int") + .HasColumnName("number"); + + b.HasKey("Id") + .HasName("pk_groupname"); + + b.HasIndex("GuildConfigId", "Number") + .IsUnique() + .HasDatabaseName("ix_groupname_guildconfigid_number"); + + b.ToTable("groupname", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AutoAssignRoleIds") + .HasColumnType("longtext") + .HasColumnName("autoassignroleids"); + + b.Property("AutoDeleteByeMessagesTimer") + .HasColumnType("int") + .HasColumnName("autodeletebyemessagestimer"); + + b.Property("AutoDeleteGreetMessagesTimer") + .HasColumnType("int") + .HasColumnName("autodeletegreetmessagestimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages") + .HasColumnType("tinyint(1)") + .HasColumnName("autodeleteselfassignedrolemessages"); + + b.Property("BoostMessage") + .HasColumnType("longtext") + .HasColumnName("boostmessage"); + + b.Property("BoostMessageChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("boostmessagechannelid"); + + b.Property("BoostMessageDeleteAfter") + .HasColumnType("int") + .HasColumnName("boostmessagedeleteafter"); + + b.Property("ByeMessageChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("byemessagechannelid"); + + b.Property("ChannelByeMessageText") + .HasColumnType("longtext") + .HasColumnName("channelbyemessagetext"); + + b.Property("ChannelGreetMessageText") + .HasColumnType("longtext") + .HasColumnName("channelgreetmessagetext"); + + b.Property("CleverbotEnabled") + .HasColumnType("tinyint(1)") + .HasColumnName("cleverbotenabled"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("DeleteMessageOnCommand") + .HasColumnType("tinyint(1)") + .HasColumnName("deletemessageoncommand"); + + b.Property("DeleteStreamOnlineMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("deletestreamonlinemessage"); + + b.Property("DisableGlobalExpressions") + .HasColumnType("tinyint(1)") + .HasColumnName("disableglobalexpressions"); + + b.Property("DmGreetMessageText") + .HasColumnType("longtext") + .HasColumnName("dmgreetmessagetext"); + + b.Property("ExclusiveSelfAssignedRoles") + .HasColumnType("tinyint(1)") + .HasColumnName("exclusiveselfassignedroles"); + + b.Property("FilterInvites") + .HasColumnType("tinyint(1)") + .HasColumnName("filterinvites"); + + b.Property("FilterLinks") + .HasColumnType("tinyint(1)") + .HasColumnName("filterlinks"); + + b.Property("FilterWords") + .HasColumnType("tinyint(1)") + .HasColumnName("filterwords"); + + b.Property("GameVoiceChannel") + .HasColumnType("bigint unsigned") + .HasColumnName("gamevoicechannel"); + + b.Property("GreetMessageChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("greetmessagechannelid"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Locale") + .HasColumnType("longtext") + .HasColumnName("locale"); + + b.Property("MuteRoleName") + .HasColumnType("longtext") + .HasColumnName("muterolename"); + + b.Property("NotifyStreamOffline") + .HasColumnType("tinyint(1)") + .HasColumnName("notifystreamoffline"); + + b.Property("PermissionRole") + .HasColumnType("longtext") + .HasColumnName("permissionrole"); + + b.Property("Prefix") + .HasColumnType("longtext") + .HasColumnName("prefix"); + + b.Property("SendBoostMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("sendboostmessage"); + + b.Property("SendChannelByeMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("sendchannelbyemessage"); + + b.Property("SendChannelGreetMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("sendchannelgreetmessage"); + + b.Property("SendDmGreetMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("senddmgreetmessage"); + + b.Property("StickyRoles") + .HasColumnType("tinyint(1)") + .HasColumnName("stickyroles"); + + b.Property("TimeZoneId") + .HasColumnType("longtext") + .HasColumnName("timezoneid"); + + b.Property("VerboseErrors") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true) + .HasColumnName("verboseerrors"); + + b.Property("VerbosePermissions") + .HasColumnType("tinyint(1)") + .HasColumnName("verbosepermissions"); + + b.Property("WarnExpireAction") + .HasColumnType("int") + .HasColumnName("warnexpireaction"); + + b.Property("WarnExpireHours") + .HasColumnType("int") + .HasColumnName("warnexpirehours"); + + b.Property("WarningsInitialized") + .HasColumnType("tinyint(1)") + .HasColumnName("warningsinitialized"); + + b.HasKey("Id") + .HasName("pk_guildconfigs"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_guildconfigs_guildid"); + + b.HasIndex("WarnExpireHours") + .HasDatabaseName("ix_guildconfigs_warnexpirehours"); + + b.ToTable("guildconfigs", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemType") + .HasColumnType("int") + .HasColumnName("itemtype"); + + b.Property("LogItemId") + .HasColumnType("bigint unsigned") + .HasColumnName("logitemid"); + + b.Property("LogSettingId") + .HasColumnType("int") + .HasColumnName("logsettingid"); + + b.HasKey("Id") + .HasName("pk_ignoredlogchannels"); + + b.HasIndex("LogSettingId", "LogItemId", "ItemType") + .IsUnique() + .HasDatabaseName("ix_ignoredlogchannels_logsettingid_logitemid_itemtype"); + + b.ToTable("ignoredlogchannels", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ImageOnlyChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_imageonlychannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_imageonlychannels_channelid"); + + b.ToTable("imageonlychannels", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelCreatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelcreatedid"); + + b.Property("ChannelDestroyedId") + .HasColumnType("bigint unsigned") + .HasColumnName("channeldestroyedid"); + + b.Property("ChannelUpdatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelupdatedid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("LogOtherId") + .HasColumnType("bigint unsigned") + .HasColumnName("logotherid"); + + b.Property("LogUserPresenceId") + .HasColumnType("bigint unsigned") + .HasColumnName("loguserpresenceid"); + + b.Property("LogVoicePresenceId") + .HasColumnType("bigint unsigned") + .HasColumnName("logvoicepresenceid"); + + b.Property("LogVoicePresenceTTSId") + .HasColumnType("bigint unsigned") + .HasColumnName("logvoicepresencettsid"); + + b.Property("LogWarnsId") + .HasColumnType("bigint unsigned") + .HasColumnName("logwarnsid"); + + b.Property("MessageDeletedId") + .HasColumnType("bigint unsigned") + .HasColumnName("messagedeletedid"); + + b.Property("MessageUpdatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageupdatedid"); + + b.Property("ThreadCreatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("threadcreatedid"); + + b.Property("ThreadDeletedId") + .HasColumnType("bigint unsigned") + .HasColumnName("threaddeletedid"); + + b.Property("UserBannedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userbannedid"); + + b.Property("UserJoinedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userjoinedid"); + + b.Property("UserLeftId") + .HasColumnType("bigint unsigned") + .HasColumnName("userleftid"); + + b.Property("UserMutedId") + .HasColumnType("bigint unsigned") + .HasColumnName("usermutedid"); + + b.Property("UserUnbannedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userunbannedid"); + + b.Property("UserUpdatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userupdatedid"); + + b.HasKey("Id") + .HasName("pk_logsettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_logsettings_guildid"); + + b.ToTable("logsettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlayerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AutoDisconnect") + .HasColumnType("tinyint(1)") + .HasColumnName("autodisconnect"); + + b.Property("AutoPlay") + .HasColumnType("tinyint(1)") + .HasColumnName("autoplay"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("MusicChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("musicchannelid"); + + b.Property("PlayerRepeat") + .HasColumnType("int") + .HasColumnName("playerrepeat"); + + b.Property("QualityPreset") + .HasColumnType("int") + .HasColumnName("qualitypreset"); + + b.Property("Volume") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(100) + .HasColumnName("volume"); + + b.HasKey("Id") + .HasName("pk_musicplayersettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_musicplayersettings_guildid"); + + b.ToTable("musicplayersettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Author") + .HasColumnType("longtext") + .HasColumnName("author"); + + b.Property("AuthorId") + .HasColumnType("bigint unsigned") + .HasColumnName("authorid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("pk_musicplaylists"); + + b.ToTable("musicplaylists", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_muteduserid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_muteduserid_guildconfigid"); + + b.ToTable("muteduserid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.NadekoExpression", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AllowTarget") + .HasColumnType("tinyint(1)") + .HasColumnName("allowtarget"); + + b.Property("AutoDeleteTrigger") + .HasColumnType("tinyint(1)") + .HasColumnName("autodeletetrigger"); + + b.Property("ContainsAnywhere") + .HasColumnType("tinyint(1)") + .HasColumnName("containsanywhere"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("DmResponse") + .HasColumnType("tinyint(1)") + .HasColumnName("dmresponse"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Reactions") + .HasColumnType("longtext") + .HasColumnName("reactions"); + + b.Property("Response") + .HasColumnType("longtext") + .HasColumnName("response"); + + b.Property("Trigger") + .HasColumnType("longtext") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_expressions"); + + b.ToTable("expressions", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UserId")); + + b.Property("AmountCents") + .HasColumnType("int") + .HasColumnName("amountcents"); + + b.Property("LastCharge") + .HasColumnType("datetime(6)") + .HasColumnName("lastcharge"); + + b.Property("UniquePlatformUserId") + .HasColumnType("varchar(255)") + .HasColumnName("uniqueplatformuserid"); + + b.Property("ValidThru") + .HasColumnType("datetime(6)") + .HasColumnName("validthru"); + + b.HasKey("UserId") + .HasName("pk_patrons"); + + b.HasIndex("UniquePlatformUserId") + .IsUnique() + .HasDatabaseName("ix_patrons_uniqueplatformuserid"); + + b.ToTable("patrons", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("int") + .HasColumnName("index"); + + b.Property("IsCustomCommand") + .HasColumnType("tinyint(1)") + .HasColumnName("iscustomcommand"); + + b.Property("PrimaryTarget") + .HasColumnType("int") + .HasColumnName("primarytarget"); + + b.Property("PrimaryTargetId") + .HasColumnType("bigint unsigned") + .HasColumnName("primarytargetid"); + + b.Property("SecondaryTarget") + .HasColumnType("int") + .HasColumnName("secondarytarget"); + + b.Property("SecondaryTargetName") + .HasColumnType("longtext") + .HasColumnName("secondarytargetname"); + + b.Property("State") + .HasColumnType("tinyint(1)") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_permissions"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_permissions_guildconfigid"); + + b.ToTable("permissions", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlantedCurrency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.Property("Password") + .HasColumnType("longtext") + .HasColumnName("password"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_plantedcurrency"); + + b.HasIndex("ChannelId") + .HasDatabaseName("ix_plantedcurrency_channelid"); + + b.HasIndex("MessageId") + .IsUnique() + .HasDatabaseName("ix_plantedcurrency_messageid"); + + b.ToTable("plantedcurrency", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("MusicPlaylistId") + .HasColumnType("int") + .HasColumnName("musicplaylistid"); + + b.Property("Provider") + .HasColumnType("longtext") + .HasColumnName("provider"); + + b.Property("ProviderType") + .HasColumnType("int") + .HasColumnName("providertype"); + + b.Property("Query") + .HasColumnType("longtext") + .HasColumnName("query"); + + b.Property("Title") + .HasColumnType("longtext") + .HasColumnName("title"); + + b.Property("Uri") + .HasColumnType("longtext") + .HasColumnName("uri"); + + b.HasKey("Id") + .HasName("pk_playlistsong"); + + b.HasIndex("MusicPlaylistId") + .HasDatabaseName("ix_playlistsong_musicplaylistid"); + + b.ToTable("playlistsong", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("bigint unsigned") + .HasColumnName("authorid"); + + b.Property("AuthorName") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("authorname"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Keyword") + .IsRequired() + .HasColumnType("varchar(255)") + .HasColumnName("keyword"); + + b.Property("Text") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_quotes"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_quotes_guildid"); + + b.HasIndex("Keyword") + .HasDatabaseName("ix_quotes_keyword"); + + b.ToTable("quotes", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ReactionRoleV2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Emote") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("emote"); + + b.Property("Group") + .HasColumnType("int") + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("LevelReq") + .HasColumnType("int") + .HasColumnName("levelreq"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_reactionroles"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_reactionroles_guildid"); + + b.HasIndex("MessageId", "Emote") + .IsUnique() + .HasDatabaseName("ix_reactionroles_messageid_emote"); + + b.ToTable("reactionroles", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("IsPrivate") + .HasColumnType("tinyint(1)") + .HasColumnName("isprivate"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("ServerId") + .HasColumnType("bigint unsigned") + .HasColumnName("serverid"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("When") + .HasColumnType("datetime(6)") + .HasColumnName("when"); + + b.HasKey("Id") + .HasName("pk_reminders"); + + b.HasIndex("When") + .HasDatabaseName("ix_reminders_when"); + + b.ToTable("reminders", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Interval") + .HasColumnType("time(6)") + .HasColumnName("interval"); + + b.Property("LastMessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("lastmessageid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("NoRedundant") + .HasColumnType("tinyint(1)") + .HasColumnName("noredundant"); + + b.Property("StartTimeOfDay") + .HasColumnType("time(6)") + .HasColumnName("starttimeofday"); + + b.HasKey("Id") + .HasName("pk_repeaters"); + + b.ToTable("repeaters", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AmountRewardedThisMonth") + .HasColumnType("bigint") + .HasColumnName("amountrewardedthismonth"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("LastReward") + .HasColumnType("datetime(6)") + .HasColumnName("lastreward"); + + b.Property("PlatformUserId") + .HasColumnType("varchar(255)") + .HasColumnName("platformuserid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_rewardedusers"); + + b.HasIndex("PlatformUserId") + .IsUnique() + .HasDatabaseName("ix_rewardedusers_platformuserid"); + + b.ToTable("rewardedusers", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.RotatingPlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Status") + .HasColumnType("longtext") + .HasColumnName("status"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_rotatingstatus"); + + b.ToTable("rotatingstatus", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Group") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("LevelRequirement") + .HasColumnType("int") + .HasColumnName("levelrequirement"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_selfassignableroles"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique() + .HasDatabaseName("ix_selfassignableroles_guildid_roleid"); + + b.ToTable("selfassignableroles", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("bigint unsigned") + .HasColumnName("authorid"); + + b.Property("Command") + .HasColumnType("longtext") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("int") + .HasColumnName("index"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("Price") + .HasColumnType("int") + .HasColumnName("price"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("RoleName") + .HasColumnType("longtext") + .HasColumnName("rolename"); + + b.Property("RoleRequirement") + .HasColumnType("bigint unsigned") + .HasColumnName("rolerequirement"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_shopentry"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_shopentry_guildconfigid"); + + b.ToTable("shopentry", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ShopEntryId") + .HasColumnType("int") + .HasColumnName("shopentryid"); + + b.Property("Text") + .HasColumnType("longtext") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_shopentryitem"); + + b.HasIndex("ShopEntryId") + .HasDatabaseName("ix_shopentryitem_shopentryid"); + + b.ToTable("shopentryitem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoredrole"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoredrole_guildconfigid"); + + b.ToTable("slowmodeignoredrole", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoreduser"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoreduser_guildconfigid"); + + b.ToTable("slowmodeignoreduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StickyRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("RoleIds") + .HasColumnType("longtext") + .HasColumnName("roleids"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_stickyroles"); + + b.HasIndex("GuildId", "UserId") + .IsUnique() + .HasDatabaseName("ix_stickyroles_guildid_userid"); + + b.ToTable("stickyroles", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamOnlineMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_streamonlinemessages"); + + b.ToTable("streamonlinemessages", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("int") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamroleblacklisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamroleblacklisteduser_streamrolesettingsid"); + + b.ToTable("streamroleblacklisteduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AddRoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("addroleid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)") + .HasColumnName("enabled"); + + b.Property("FromRoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("fromroleid"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Keyword") + .HasColumnType("longtext") + .HasColumnName("keyword"); + + b.HasKey("Id") + .HasName("pk_streamrolesettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_streamrolesettings_guildconfigid"); + + b.ToTable("streamrolesettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("int") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamrolewhitelisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamrolewhitelisteduser_streamrolesettingsid"); + + b.ToTable("streamrolewhitelisteduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArchiveId") + .HasColumnType("int") + .HasColumnName("archiveid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("IsDone") + .HasColumnType("tinyint(1)") + .HasColumnName("isdone"); + + b.Property("Todo") + .HasColumnType("longtext") + .HasColumnName("todo"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todos"); + + b.HasIndex("ArchiveId") + .HasDatabaseName("ix_todos_archiveid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_todos_userid"); + + b.ToTable("todos", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnbanTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UnbanAt") + .HasColumnType("datetime(6)") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unbantimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unbantimer_guildconfigid"); + + b.ToTable("unbantimer", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UnmuteAt") + .HasColumnType("datetime(6)") + .HasColumnName("unmuteat"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unmutetimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unmutetimer_guildconfigid"); + + b.ToTable("unmutetimer", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnroleTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("UnbanAt") + .HasColumnType("datetime(6)") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unroletimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unroletimer_guildconfigid"); + + b.ToTable("unroletimer", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AwardedXp") + .HasColumnType("bigint") + .HasColumnName("awardedxp"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("NotifyOnLevelUp") + .HasColumnType("int") + .HasColumnName("notifyonlevelup"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Xp") + .HasColumnType("bigint") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_userxpstats"); + + b.HasIndex("AwardedXp") + .HasDatabaseName("ix_userxpstats_awardedxp"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_userxpstats_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_userxpstats_userid"); + + b.HasIndex("Xp") + .HasDatabaseName("ix_userxpstats_xp"); + + b.HasIndex("UserId", "GuildId") + .IsUnique() + .HasDatabaseName("ix_userxpstats_userid_guildid"); + + b.ToTable("userxpstats", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("VoiceChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("voicechannelid"); + + b.HasKey("Id") + .HasName("pk_vcroleinfo"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_vcroleinfo_guildconfigid"); + + b.ToTable("vcroleinfo", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AffinityId") + .HasColumnType("int") + .HasColumnName("affinityid"); + + b.Property("ClaimerId") + .HasColumnType("int") + .HasColumnName("claimerid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Price") + .HasColumnType("bigint") + .HasColumnName("price"); + + b.Property("WaifuId") + .HasColumnType("int") + .HasColumnName("waifuid"); + + b.HasKey("Id") + .HasName("pk_waifuinfo"); + + b.HasIndex("AffinityId") + .HasDatabaseName("ix_waifuinfo_affinityid"); + + b.HasIndex("ClaimerId") + .HasDatabaseName("ix_waifuinfo_claimerid"); + + b.HasIndex("Price") + .HasDatabaseName("ix_waifuinfo_price"); + + b.HasIndex("WaifuId") + .IsUnique() + .HasDatabaseName("ix_waifuinfo_waifuid"); + + b.ToTable("waifuinfo", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemEmoji") + .HasColumnType("longtext") + .HasColumnName("itememoji"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("WaifuInfoId") + .HasColumnType("int") + .HasColumnName("waifuinfoid"); + + b.HasKey("Id") + .HasName("pk_waifuitem"); + + b.HasIndex("WaifuInfoId") + .HasDatabaseName("ix_waifuitem_waifuinfoid"); + + b.ToTable("waifuitem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("NewId") + .HasColumnType("int") + .HasColumnName("newid"); + + b.Property("OldId") + .HasColumnType("int") + .HasColumnName("oldid"); + + b.Property("UpdateType") + .HasColumnType("int") + .HasColumnName("updatetype"); + + b.Property("UserId") + .HasColumnType("int") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_waifuupdates"); + + b.HasIndex("NewId") + .HasDatabaseName("ix_waifuupdates_newid"); + + b.HasIndex("OldId") + .HasDatabaseName("ix_waifuupdates_oldid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_waifuupdates_userid"); + + b.ToTable("waifuupdates", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Forgiven") + .HasColumnType("tinyint(1)") + .HasColumnName("forgiven"); + + b.Property("ForgivenBy") + .HasColumnType("longtext") + .HasColumnName("forgivenby"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Moderator") + .HasColumnType("longtext") + .HasColumnName("moderator"); + + b.Property("Reason") + .HasColumnType("longtext") + .HasColumnName("reason"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Weight") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(1L) + .HasColumnName("weight"); + + b.HasKey("Id") + .HasName("pk_warnings"); + + b.HasIndex("DateAdded") + .HasDatabaseName("ix_warnings_dateadded"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_warnings_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_warnings_userid"); + + b.ToTable("warnings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int") + .HasColumnName("count"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Punishment") + .HasColumnType("int") + .HasColumnName("punishment"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("Time") + .HasColumnType("int") + .HasColumnName("time"); + + b.HasKey("Id") + .HasName("pk_warningpunishment"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_warningpunishment_guildconfigid"); + + b.ToTable("warningpunishment", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("int") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("int") + .HasColumnName("level"); + + b.Property("XpSettingsId") + .HasColumnType("int") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xpcurrencyreward"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_xpcurrencyreward_xpsettingsid"); + + b.ToTable("xpcurrencyreward", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("int") + .HasColumnName("level"); + + b.Property("Remove") + .HasColumnType("tinyint(1)") + .HasColumnName("remove"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("XpSettingsId") + .HasColumnType("int") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xprolereward"); + + b.HasIndex("XpSettingsId", "Level") + .IsUnique() + .HasDatabaseName("ix_xprolereward_xpsettingsid_level"); + + b.ToTable("xprolereward", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("ServerExcluded") + .HasColumnType("tinyint(1)") + .HasColumnName("serverexcluded"); + + b.HasKey("Id") + .HasName("pk_xpsettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_xpsettings_guildconfigid"); + + b.ToTable("xpsettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpShopOwnedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("IsUsing") + .HasColumnType("tinyint(1)") + .HasColumnName("isusing"); + + b.Property("ItemKey") + .IsRequired() + .HasColumnType("varchar(255)") + .HasColumnName("itemkey"); + + b.Property("ItemType") + .HasColumnType("int") + .HasColumnName("itemtype"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_xpshopowneditem"); + + b.HasIndex("UserId", "ItemType", "ItemKey") + .IsUnique() + .HasDatabaseName("ix_xpshopowneditem_userid_itemtype_itemkey"); + + b.ToTable("xpshopowneditem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiAltSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiAltSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antialtsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antiraidsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Db.Models.AntiSpamSetting", null) + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_antispamignore_antispamsetting_antispamsettingid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antispamsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b => + { + b.HasOne("NadekoBot.Db.Models.AutoTranslateChannel", "Channel") + .WithMany("Users") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_autotranslateusers_autotranslatechannels_channelid"); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_clubs_clubid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_clubs_clubid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("NadekoBot.Db.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_clubs_discorduser_ownerid"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandalias_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandcooldown_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("DelMsgOnCmdChannels") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_delmsgoncmdchannel_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Members") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.NoAction) + .HasConstraintName("fk_discorduser_clubs_clubid"); + + b.Navigation("Club"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_feedsub_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterchannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterLinksChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterLinksChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterlinkschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterWordsChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterwordschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filteredword_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_followedstream_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_gcchannelid_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayUser", b => + { + b.HasOne("NadekoBot.Db.Models.GiveawayModel", null) + .WithMany("Participants") + .HasForeignKey("GiveawayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_giveawayuser_giveawaymodel_giveawayid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("SelfAssignableRoleGroupNames") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_groupname_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b => + { + b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting") + .WithMany("LogIgnores") + .HasForeignKey("LogSettingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ignoredlogchannels_logsettings_logsettingid"); + + b.Navigation("LogSetting"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_muteduserid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("Permissions") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_permissions_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Db.Models.MusicPlaylist", null) + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_playlistsong_musicplaylists_musicplaylistid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentry_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Db.Models.ShopEntry", null) + .WithMany("Items") + .HasForeignKey("ShopEntryId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentryitem_shopentry_shopentryid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoredrole_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoreduser_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamroleblacklisteduser_streamrolesettings_streamrolesetti~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("NadekoBot.Db.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolesettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolewhitelisteduser_streamrolesettings_streamrolesetti~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b => + { + b.HasOne("NadekoBot.Db.Models.ArchivedTodoListModel", null) + .WithMany("Items") + .HasForeignKey("ArchiveId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_todos_todosarchive_archiveid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnbanTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnbanTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unbantimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unmutetimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnroleTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnroleTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unroletimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_vcroleinfo_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId") + .HasConstraintName("fk_waifuinfo_discorduser_affinityid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId") + .HasConstraintName("fk_waifuinfo_discorduser_claimerid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Db.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuinfo_discorduser_waifuid"); + + b.Navigation("Affinity"); + + b.Navigation("Claimer"); + + b.Navigation("Waifu"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuItem", b => + { + b.HasOne("NadekoBot.Db.Models.WaifuInfo", "WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId") + .HasConstraintName("fk_waifuitem_waifuinfo_waifuinfoid"); + + b.Navigation("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId") + .HasConstraintName("fk_waifuupdates_discorduser_newid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId") + .HasConstraintName("fk_waifuupdates_discorduser_oldid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuupdates_discorduser_userid"); + + b.Navigation("New"); + + b.Navigation("Old"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_warningpunishment_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("CurrencyRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpcurrencyreward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpRoleReward", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xprolereward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("NadekoBot.Db.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpsettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.Navigation("IgnoredChannels"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ArchivedTodoListModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateChannel", b => + { + b.Navigation("Users"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.Navigation("Applicants"); + + b.Navigation("Bans"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayModel", b => + { + b.Navigation("Participants"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b => + { + b.Navigation("AntiAltSetting"); + + b.Navigation("AntiRaidSetting"); + + b.Navigation("AntiSpamSetting"); + + b.Navigation("CommandAliases"); + + b.Navigation("CommandCooldowns"); + + b.Navigation("DelMsgOnCmdChannels"); + + b.Navigation("FeedSubs"); + + b.Navigation("FilterInvitesChannelIds"); + + b.Navigation("FilterLinksChannelIds"); + + b.Navigation("FilterWordsChannelIds"); + + b.Navigation("FilteredWords"); + + b.Navigation("FollowedStreams"); + + b.Navigation("GenerateCurrencyChannelIds"); + + b.Navigation("MutedUsers"); + + b.Navigation("Permissions"); + + b.Navigation("SelfAssignableRoleGroupNames"); + + b.Navigation("ShopEntries"); + + b.Navigation("SlowmodeIgnoredRoles"); + + b.Navigation("SlowmodeIgnoredUsers"); + + b.Navigation("StreamRole"); + + b.Navigation("UnbanTimer"); + + b.Navigation("UnmuteTimers"); + + b.Navigation("UnroleTimer"); + + b.Navigation("VcRoleInfos"); + + b.Navigation("WarnPunishments"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.LogSetting", b => + { + b.Navigation("LogIgnores"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlaylist", b => + { + b.Navigation("Songs"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.Navigation("Blacklist"); + + b.Navigation("Whitelist"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.Navigation("CurrencyRewards"); + + b.Navigation("ExclusionList"); + + b.Navigation("RoleRewards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs b/src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs new file mode 100644 index 000000000..9ef2db7f0 --- /dev/null +++ b/src/NadekoBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace NadekoBot.Migrations.Mysql +{ + /// + public partial class removepatronlimits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "patronquotas"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "patronquotas", + columns: table => new + { + userid = table.Column(type: "bigint unsigned", nullable: false), + featuretype = table.Column(type: "int", nullable: false), + feature = table.Column(type: "varchar(255)", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + dailycount = table.Column(type: "int unsigned", nullable: false), + hourlycount = table.Column(type: "int unsigned", nullable: false), + monthlycount = table.Column(type: "int unsigned", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_patronquotas", x => new { x.userid, x.featuretype, x.feature }); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "ix_patronquotas_userid", + table: "patronquotas", + column: "userid"); + } + } +} diff --git a/src/NadekoBot/Migrations/Mysql/MysqlContextModelSnapshot.cs b/src/NadekoBot/Migrations/Mysql/MysqlContextModelSnapshot.cs index d71992d9d..a61c82515 100644 --- a/src/NadekoBot/Migrations/Mysql/MysqlContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/Mysql/MysqlContextModelSnapshot.cs @@ -1718,41 +1718,6 @@ namespace NadekoBot.Migrations.Mysql b.ToTable("expressions", (string)null); }); - modelBuilder.Entity("NadekoBot.Db.Models.PatronQuota", b => - { - b.Property("UserId") - .HasColumnType("bigint unsigned") - .HasColumnName("userid"); - - b.Property("FeatureType") - .HasColumnType("int") - .HasColumnName("featuretype"); - - b.Property("Feature") - .HasColumnType("varchar(255)") - .HasColumnName("feature"); - - b.Property("DailyCount") - .HasColumnType("int unsigned") - .HasColumnName("dailycount"); - - b.Property("HourlyCount") - .HasColumnType("int unsigned") - .HasColumnName("hourlycount"); - - b.Property("MonthlyCount") - .HasColumnType("int unsigned") - .HasColumnName("monthlycount"); - - b.HasKey("UserId", "FeatureType", "Feature") - .HasName("pk_patronquotas"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_patronquotas_userid"); - - b.ToTable("patronquotas", (string)null); - }); - modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b => { b.Property("UserId") diff --git a/src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs b/src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs new file mode 100644 index 000000000..f4e5e0d09 --- /dev/null +++ b/src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs @@ -0,0 +1,3781 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NadekoBot.Db; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NadekoBot.Migrations.PostgreSql +{ + [DbContext(typeof(PostgreSqlContext))] + [Migration("20240611180506_remove-patron-limits")] + partial class removepatronlimits + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer") + .HasColumnName("action"); + + b.Property("ActionDurationMinutes") + .HasColumnType("integer") + .HasColumnName("actiondurationminutes"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("MinAge") + .HasColumnType("interval") + .HasColumnName("minage"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antialtsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antialtsetting_guildconfigid"); + + b.ToTable("antialtsetting", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("PunishDuration") + .HasColumnType("integer") + .HasColumnName("punishduration"); + + b.Property("Seconds") + .HasColumnType("integer") + .HasColumnName("seconds"); + + b.Property("UserThreshold") + .HasColumnType("integer") + .HasColumnName("userthreshold"); + + b.HasKey("Id") + .HasName("pk_antiraidsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antiraidsetting_guildconfigid"); + + b.ToTable("antiraidsetting", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AntiSpamSettingId") + .HasColumnType("integer") + .HasColumnName("antispamsettingid"); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.HasKey("Id") + .HasName("pk_antispamignore"); + + b.HasIndex("AntiSpamSettingId") + .HasDatabaseName("ix_antispamignore_antispamsettingid"); + + b.ToTable("antispamignore", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("MessageThreshold") + .HasColumnType("integer") + .HasColumnName("messagethreshold"); + + b.Property("MuteTime") + .HasColumnType("integer") + .HasColumnName("mutetime"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antispamsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antispamsetting_guildconfigid"); + + b.ToTable("antispamsetting", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ArchivedTodoListModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todosarchive"); + + b.ToTable("todosarchive", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("ChannelName") + .HasColumnType("text") + .HasColumnName("channelname"); + + b.Property("CommandText") + .HasColumnType("text") + .HasColumnName("commandtext"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("GuildName") + .HasColumnType("text") + .HasColumnName("guildname"); + + b.Property("Interval") + .HasColumnType("integer") + .HasColumnName("interval"); + + b.Property("VoiceChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("voicechannelid"); + + b.Property("VoiceChannelName") + .HasColumnType("text") + .HasColumnName("voicechannelname"); + + b.HasKey("Id") + .HasName("pk_autocommands"); + + b.ToTable("autocommands", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoPublishChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autopublishchannel"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_autopublishchannel_guildid"); + + b.ToTable("autopublishchannel", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoDelete") + .HasColumnType("boolean") + .HasColumnName("autodelete"); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autotranslatechannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_autotranslatechannels_channelid"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_autotranslatechannels_guildid"); + + b.ToTable("autotranslatechannels", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("integer") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Source") + .HasColumnType("text") + .HasColumnName("source"); + + b.Property("Target") + .HasColumnType("text") + .HasColumnName("target"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_autotranslateusers"); + + b.HasAlternateKey("ChannelId", "UserId") + .HasName("ak_autotranslateusers_channelid_userid"); + + b.ToTable("autotranslateusers", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BanTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("PruneDays") + .HasColumnType("integer") + .HasColumnName("prunedays"); + + b.Property("Text") + .HasColumnType("text") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_bantemplates"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_bantemplates_guildid"); + + b.ToTable("bantemplates", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Balance") + .HasColumnType("bigint") + .HasColumnName("balance"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_bankusers"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_bankusers_userid"); + + b.ToTable("bankusers", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BlacklistEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("numeric(20,0)") + .HasColumnName("itemid"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_blacklist"); + + b.ToTable("blacklist", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b => + { + b.Property("ClubId") + .HasColumnType("integer") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubapplicants"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubapplicants_userid"); + + b.ToTable("clubapplicants", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b => + { + b.Property("ClubId") + .HasColumnType("integer") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubbans"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubbans_userid"); + + b.ToTable("clubbans", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("ImageUrl") + .HasColumnType("text") + .HasColumnName("imageurl"); + + b.Property("Name") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("name"); + + b.Property("OwnerId") + .HasColumnType("integer") + .HasColumnName("ownerid"); + + b.Property("Xp") + .HasColumnType("integer") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_clubs"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_clubs_name"); + + b.HasIndex("OwnerId") + .IsUnique() + .HasDatabaseName("ix_clubs_ownerid"); + + b.ToTable("clubs", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Mapping") + .HasColumnType("text") + .HasColumnName("mapping"); + + b.Property("Trigger") + .HasColumnType("text") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_commandalias"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandalias_guildconfigid"); + + b.ToTable("commandalias", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CommandName") + .HasColumnType("text") + .HasColumnName("commandname"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Seconds") + .HasColumnType("integer") + .HasColumnName("seconds"); + + b.HasKey("Id") + .HasName("pk_commandcooldown"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandcooldown_guildconfigid"); + + b.ToTable("commandcooldown", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("text") + .HasColumnName("extra"); + + b.Property("Note") + .HasColumnType("text") + .HasColumnName("note"); + + b.Property("OtherId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("otherid") + .HasDefaultValueSql("NULL"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_currencytransactions"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_currencytransactions_userid"); + + b.ToTable("currencytransactions", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("State") + .HasColumnType("boolean") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_delmsgoncmdchannel"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_delmsgoncmdchannel_guildconfigid"); + + b.ToTable("delmsgoncmdchannel", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordPermOverride", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Command") + .HasColumnType("text") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Perm") + .HasColumnType("numeric(20,0)") + .HasColumnName("perm"); + + b.HasKey("Id") + .HasName("pk_discordpermoverrides"); + + b.HasIndex("GuildId", "Command") + .IsUnique() + .HasDatabaseName("ix_discordpermoverrides_guildid_command"); + + b.ToTable("discordpermoverrides", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvatarId") + .HasColumnType("text") + .HasColumnName("avatarid"); + + b.Property("ClubId") + .HasColumnType("integer") + .HasColumnName("clubid"); + + b.Property("CurrencyAmount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("currencyamount"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Discriminator") + .HasColumnType("text") + .HasColumnName("discriminator"); + + b.Property("IsClubAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("isclubadmin"); + + b.Property("NotifyOnLevelUp") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("notifyonlevelup"); + + b.Property("TotalXp") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("totalxp"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_discorduser"); + + b.HasAlternateKey("UserId") + .HasName("ak_discorduser_userid"); + + b.HasIndex("ClubId") + .HasDatabaseName("ix_discorduser_clubid"); + + b.HasIndex("CurrencyAmount") + .HasDatabaseName("ix_discorduser_currencyamount"); + + b.HasIndex("TotalXp") + .HasDatabaseName("ix_discorduser_totalxp"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_discorduser_userid"); + + b.ToTable("discorduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("numeric(20,0)") + .HasColumnName("itemid"); + + b.Property("ItemType") + .HasColumnType("integer") + .HasColumnName("itemtype"); + + b.Property("XpSettingsId") + .HasColumnType("integer") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_excludeditem"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_excludeditem_xpsettingsid"); + + b.ToTable("excludeditem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text") + .HasColumnName("url"); + + b.HasKey("Id") + .HasName("pk_feedsub"); + + b.HasAlternateKey("GuildConfigId", "Url") + .HasName("ak_feedsub_guildconfigid_url"); + + b.ToTable("feedsub", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterchannelid_guildconfigid"); + + b.ToTable("filterchannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterLinksChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterlinkschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterlinkschannelid_guildconfigid"); + + b.ToTable("filterlinkschannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterWordsChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterwordschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterwordschannelid_guildconfigid"); + + b.ToTable("filterwordschannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Word") + .HasColumnType("text") + .HasColumnName("word"); + + b.HasKey("Id") + .HasName("pk_filteredword"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filteredword_guildconfigid"); + + b.ToTable("filteredword", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_followedstream"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_followedstream_guildconfigid"); + + b.ToTable("followedstream", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_gcchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_gcchannelid_guildconfigid"); + + b.ToTable("gcchannelid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GamblingStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Bet") + .HasColumnType("numeric") + .HasColumnName("bet"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Feature") + .HasColumnType("text") + .HasColumnName("feature"); + + b.Property("PaidOut") + .HasColumnType("numeric") + .HasColumnName("paidout"); + + b.HasKey("Id") + .HasName("pk_gamblingstats"); + + b.HasIndex("Feature") + .IsUnique() + .HasDatabaseName("ix_gamblingstats_feature"); + + b.ToTable("gamblingstats", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("EndsAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("endsat"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.HasKey("Id") + .HasName("pk_giveawaymodel"); + + b.ToTable("giveawaymodel", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("GiveawayId") + .HasColumnType("integer") + .HasColumnName("giveawayid"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_giveawayuser"); + + b.HasIndex("GiveawayId", "UserId") + .IsUnique() + .HasDatabaseName("ix_giveawayuser_giveawayid_userid"); + + b.ToTable("giveawayuser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Number") + .HasColumnType("integer") + .HasColumnName("number"); + + b.HasKey("Id") + .HasName("pk_groupname"); + + b.HasIndex("GuildConfigId", "Number") + .IsUnique() + .HasDatabaseName("ix_groupname_guildconfigid_number"); + + b.ToTable("groupname", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoAssignRoleIds") + .HasColumnType("text") + .HasColumnName("autoassignroleids"); + + b.Property("AutoDeleteByeMessagesTimer") + .HasColumnType("integer") + .HasColumnName("autodeletebyemessagestimer"); + + b.Property("AutoDeleteGreetMessagesTimer") + .HasColumnType("integer") + .HasColumnName("autodeletegreetmessagestimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages") + .HasColumnType("boolean") + .HasColumnName("autodeleteselfassignedrolemessages"); + + b.Property("BoostMessage") + .HasColumnType("text") + .HasColumnName("boostmessage"); + + b.Property("BoostMessageChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("boostmessagechannelid"); + + b.Property("BoostMessageDeleteAfter") + .HasColumnType("integer") + .HasColumnName("boostmessagedeleteafter"); + + b.Property("ByeMessageChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("byemessagechannelid"); + + b.Property("ChannelByeMessageText") + .HasColumnType("text") + .HasColumnName("channelbyemessagetext"); + + b.Property("ChannelGreetMessageText") + .HasColumnType("text") + .HasColumnName("channelgreetmessagetext"); + + b.Property("CleverbotEnabled") + .HasColumnType("boolean") + .HasColumnName("cleverbotenabled"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("DeleteMessageOnCommand") + .HasColumnType("boolean") + .HasColumnName("deletemessageoncommand"); + + b.Property("DeleteStreamOnlineMessage") + .HasColumnType("boolean") + .HasColumnName("deletestreamonlinemessage"); + + b.Property("DisableGlobalExpressions") + .HasColumnType("boolean") + .HasColumnName("disableglobalexpressions"); + + b.Property("DmGreetMessageText") + .HasColumnType("text") + .HasColumnName("dmgreetmessagetext"); + + b.Property("ExclusiveSelfAssignedRoles") + .HasColumnType("boolean") + .HasColumnName("exclusiveselfassignedroles"); + + b.Property("FilterInvites") + .HasColumnType("boolean") + .HasColumnName("filterinvites"); + + b.Property("FilterLinks") + .HasColumnType("boolean") + .HasColumnName("filterlinks"); + + b.Property("FilterWords") + .HasColumnType("boolean") + .HasColumnName("filterwords"); + + b.Property("GameVoiceChannel") + .HasColumnType("numeric(20,0)") + .HasColumnName("gamevoicechannel"); + + b.Property("GreetMessageChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("greetmessagechannelid"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Locale") + .HasColumnType("text") + .HasColumnName("locale"); + + b.Property("MuteRoleName") + .HasColumnType("text") + .HasColumnName("muterolename"); + + b.Property("NotifyStreamOffline") + .HasColumnType("boolean") + .HasColumnName("notifystreamoffline"); + + b.Property("PermissionRole") + .HasColumnType("text") + .HasColumnName("permissionrole"); + + b.Property("Prefix") + .HasColumnType("text") + .HasColumnName("prefix"); + + b.Property("SendBoostMessage") + .HasColumnType("boolean") + .HasColumnName("sendboostmessage"); + + b.Property("SendChannelByeMessage") + .HasColumnType("boolean") + .HasColumnName("sendchannelbyemessage"); + + b.Property("SendChannelGreetMessage") + .HasColumnType("boolean") + .HasColumnName("sendchannelgreetmessage"); + + b.Property("SendDmGreetMessage") + .HasColumnType("boolean") + .HasColumnName("senddmgreetmessage"); + + b.Property("StickyRoles") + .HasColumnType("boolean") + .HasColumnName("stickyroles"); + + b.Property("TimeZoneId") + .HasColumnType("text") + .HasColumnName("timezoneid"); + + b.Property("VerboseErrors") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("verboseerrors"); + + b.Property("VerbosePermissions") + .HasColumnType("boolean") + .HasColumnName("verbosepermissions"); + + b.Property("WarnExpireAction") + .HasColumnType("integer") + .HasColumnName("warnexpireaction"); + + b.Property("WarnExpireHours") + .HasColumnType("integer") + .HasColumnName("warnexpirehours"); + + b.Property("WarningsInitialized") + .HasColumnType("boolean") + .HasColumnName("warningsinitialized"); + + b.HasKey("Id") + .HasName("pk_guildconfigs"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_guildconfigs_guildid"); + + b.HasIndex("WarnExpireHours") + .HasDatabaseName("ix_guildconfigs_warnexpirehours"); + + b.ToTable("guildconfigs", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemType") + .HasColumnType("integer") + .HasColumnName("itemtype"); + + b.Property("LogItemId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logitemid"); + + b.Property("LogSettingId") + .HasColumnType("integer") + .HasColumnName("logsettingid"); + + b.HasKey("Id") + .HasName("pk_ignoredlogchannels"); + + b.HasIndex("LogSettingId", "LogItemId", "ItemType") + .IsUnique() + .HasDatabaseName("ix_ignoredlogchannels_logsettingid_logitemid_itemtype"); + + b.ToTable("ignoredlogchannels", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ImageOnlyChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_imageonlychannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_imageonlychannels_channelid"); + + b.ToTable("imageonlychannels", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelCreatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelcreatedid"); + + b.Property("ChannelDestroyedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channeldestroyedid"); + + b.Property("ChannelUpdatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelupdatedid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("LogOtherId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logotherid"); + + b.Property("LogUserPresenceId") + .HasColumnType("numeric(20,0)") + .HasColumnName("loguserpresenceid"); + + b.Property("LogVoicePresenceId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logvoicepresenceid"); + + b.Property("LogVoicePresenceTTSId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logvoicepresencettsid"); + + b.Property("LogWarnsId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logwarnsid"); + + b.Property("MessageDeletedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messagedeletedid"); + + b.Property("MessageUpdatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageupdatedid"); + + b.Property("ThreadCreatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("threadcreatedid"); + + b.Property("ThreadDeletedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("threaddeletedid"); + + b.Property("UserBannedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userbannedid"); + + b.Property("UserJoinedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userjoinedid"); + + b.Property("UserLeftId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userleftid"); + + b.Property("UserMutedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("usermutedid"); + + b.Property("UserUnbannedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userunbannedid"); + + b.Property("UserUpdatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userupdatedid"); + + b.HasKey("Id") + .HasName("pk_logsettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_logsettings_guildid"); + + b.ToTable("logsettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlayerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoDisconnect") + .HasColumnType("boolean") + .HasColumnName("autodisconnect"); + + b.Property("AutoPlay") + .HasColumnType("boolean") + .HasColumnName("autoplay"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("MusicChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("musicchannelid"); + + b.Property("PlayerRepeat") + .HasColumnType("integer") + .HasColumnName("playerrepeat"); + + b.Property("QualityPreset") + .HasColumnType("integer") + .HasColumnName("qualitypreset"); + + b.Property("Volume") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(100) + .HasColumnName("volume"); + + b.HasKey("Id") + .HasName("pk_musicplayersettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_musicplayersettings_guildid"); + + b.ToTable("musicplayersettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Author") + .HasColumnType("text") + .HasColumnName("author"); + + b.Property("AuthorId") + .HasColumnType("numeric(20,0)") + .HasColumnName("authorid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("pk_musicplaylists"); + + b.ToTable("musicplaylists", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_muteduserid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_muteduserid_guildconfigid"); + + b.ToTable("muteduserid", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.NadekoExpression", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllowTarget") + .HasColumnType("boolean") + .HasColumnName("allowtarget"); + + b.Property("AutoDeleteTrigger") + .HasColumnType("boolean") + .HasColumnName("autodeletetrigger"); + + b.Property("ContainsAnywhere") + .HasColumnType("boolean") + .HasColumnName("containsanywhere"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("DmResponse") + .HasColumnType("boolean") + .HasColumnName("dmresponse"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Reactions") + .HasColumnType("text") + .HasColumnName("reactions"); + + b.Property("Response") + .HasColumnType("text") + .HasColumnName("response"); + + b.Property("Trigger") + .HasColumnType("text") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_expressions"); + + b.ToTable("expressions", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("AmountCents") + .HasColumnType("integer") + .HasColumnName("amountcents"); + + b.Property("LastCharge") + .HasColumnType("timestamp without time zone") + .HasColumnName("lastcharge"); + + b.Property("UniquePlatformUserId") + .HasColumnType("text") + .HasColumnName("uniqueplatformuserid"); + + b.Property("ValidThru") + .HasColumnType("timestamp without time zone") + .HasColumnName("validthru"); + + b.HasKey("UserId") + .HasName("pk_patrons"); + + b.HasIndex("UniquePlatformUserId") + .IsUnique() + .HasDatabaseName("ix_patrons_uniqueplatformuserid"); + + b.ToTable("patrons", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("integer") + .HasColumnName("index"); + + b.Property("IsCustomCommand") + .HasColumnType("boolean") + .HasColumnName("iscustomcommand"); + + b.Property("PrimaryTarget") + .HasColumnType("integer") + .HasColumnName("primarytarget"); + + b.Property("PrimaryTargetId") + .HasColumnType("numeric(20,0)") + .HasColumnName("primarytargetid"); + + b.Property("SecondaryTarget") + .HasColumnType("integer") + .HasColumnName("secondarytarget"); + + b.Property("SecondaryTargetName") + .HasColumnType("text") + .HasColumnName("secondarytargetname"); + + b.Property("State") + .HasColumnType("boolean") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_permissions"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_permissions_guildconfigid"); + + b.ToTable("permissions", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlantedCurrency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.Property("Password") + .HasColumnType("text") + .HasColumnName("password"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_plantedcurrency"); + + b.HasIndex("ChannelId") + .HasDatabaseName("ix_plantedcurrency_channelid"); + + b.HasIndex("MessageId") + .IsUnique() + .HasDatabaseName("ix_plantedcurrency_messageid"); + + b.ToTable("plantedcurrency", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("MusicPlaylistId") + .HasColumnType("integer") + .HasColumnName("musicplaylistid"); + + b.Property("Provider") + .HasColumnType("text") + .HasColumnName("provider"); + + b.Property("ProviderType") + .HasColumnType("integer") + .HasColumnName("providertype"); + + b.Property("Query") + .HasColumnType("text") + .HasColumnName("query"); + + b.Property("Title") + .HasColumnType("text") + .HasColumnName("title"); + + b.Property("Uri") + .HasColumnType("text") + .HasColumnName("uri"); + + b.HasKey("Id") + .HasName("pk_playlistsong"); + + b.HasIndex("MusicPlaylistId") + .HasDatabaseName("ix_playlistsong_musicplaylistid"); + + b.ToTable("playlistsong", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("numeric(20,0)") + .HasColumnName("authorid"); + + b.Property("AuthorName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("authorname"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Keyword") + .IsRequired() + .HasColumnType("text") + .HasColumnName("keyword"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_quotes"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_quotes_guildid"); + + b.HasIndex("Keyword") + .HasDatabaseName("ix_quotes_keyword"); + + b.ToTable("quotes", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ReactionRoleV2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Emote") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("emote"); + + b.Property("Group") + .HasColumnType("integer") + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("LevelReq") + .HasColumnType("integer") + .HasColumnName("levelreq"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_reactionroles"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_reactionroles_guildid"); + + b.HasIndex("MessageId", "Emote") + .IsUnique() + .HasDatabaseName("ix_reactionroles_messageid_emote"); + + b.ToTable("reactionroles", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("IsPrivate") + .HasColumnType("boolean") + .HasColumnName("isprivate"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("ServerId") + .HasColumnType("numeric(20,0)") + .HasColumnName("serverid"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("When") + .HasColumnType("timestamp without time zone") + .HasColumnName("when"); + + b.HasKey("Id") + .HasName("pk_reminders"); + + b.HasIndex("When") + .HasDatabaseName("ix_reminders_when"); + + b.ToTable("reminders", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Interval") + .HasColumnType("interval") + .HasColumnName("interval"); + + b.Property("LastMessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("lastmessageid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("NoRedundant") + .HasColumnType("boolean") + .HasColumnName("noredundant"); + + b.Property("StartTimeOfDay") + .HasColumnType("interval") + .HasColumnName("starttimeofday"); + + b.HasKey("Id") + .HasName("pk_repeaters"); + + b.ToTable("repeaters", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AmountRewardedThisMonth") + .HasColumnType("bigint") + .HasColumnName("amountrewardedthismonth"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("LastReward") + .HasColumnType("timestamp without time zone") + .HasColumnName("lastreward"); + + b.Property("PlatformUserId") + .HasColumnType("text") + .HasColumnName("platformuserid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_rewardedusers"); + + b.HasIndex("PlatformUserId") + .IsUnique() + .HasDatabaseName("ix_rewardedusers_platformuserid"); + + b.ToTable("rewardedusers", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.RotatingPlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Status") + .HasColumnType("text") + .HasColumnName("status"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_rotatingstatus"); + + b.ToTable("rotatingstatus", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Group") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("LevelRequirement") + .HasColumnType("integer") + .HasColumnName("levelrequirement"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_selfassignableroles"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique() + .HasDatabaseName("ix_selfassignableroles_guildid_roleid"); + + b.ToTable("selfassignableroles", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("numeric(20,0)") + .HasColumnName("authorid"); + + b.Property("Command") + .HasColumnType("text") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("integer") + .HasColumnName("index"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Price") + .HasColumnType("integer") + .HasColumnName("price"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("RoleName") + .HasColumnType("text") + .HasColumnName("rolename"); + + b.Property("RoleRequirement") + .HasColumnType("numeric(20,0)") + .HasColumnName("rolerequirement"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_shopentry"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_shopentry_guildconfigid"); + + b.ToTable("shopentry", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ShopEntryId") + .HasColumnType("integer") + .HasColumnName("shopentryid"); + + b.Property("Text") + .HasColumnType("text") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_shopentryitem"); + + b.HasIndex("ShopEntryId") + .HasDatabaseName("ix_shopentryitem_shopentryid"); + + b.ToTable("shopentryitem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoredrole"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoredrole_guildconfigid"); + + b.ToTable("slowmodeignoredrole", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoreduser"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoreduser_guildconfigid"); + + b.ToTable("slowmodeignoreduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StickyRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("RoleIds") + .HasColumnType("text") + .HasColumnName("roleids"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_stickyroles"); + + b.HasIndex("GuildId", "UserId") + .IsUnique() + .HasDatabaseName("ix_stickyroles_guildid_userid"); + + b.ToTable("stickyroles", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamOnlineMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_streamonlinemessages"); + + b.ToTable("streamonlinemessages", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("integer") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamroleblacklisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamroleblacklisteduser_streamrolesettingsid"); + + b.ToTable("streamroleblacklisteduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddRoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("addroleid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Enabled") + .HasColumnType("boolean") + .HasColumnName("enabled"); + + b.Property("FromRoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("fromroleid"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Keyword") + .HasColumnType("text") + .HasColumnName("keyword"); + + b.HasKey("Id") + .HasName("pk_streamrolesettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_streamrolesettings_guildconfigid"); + + b.ToTable("streamrolesettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("integer") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamrolewhitelisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamrolewhitelisteduser_streamrolesettingsid"); + + b.ToTable("streamrolewhitelisteduser", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ArchiveId") + .HasColumnType("integer") + .HasColumnName("archiveid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("IsDone") + .HasColumnType("boolean") + .HasColumnName("isdone"); + + b.Property("Todo") + .HasColumnType("text") + .HasColumnName("todo"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todos"); + + b.HasIndex("ArchiveId") + .HasDatabaseName("ix_todos_archiveid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_todos_userid"); + + b.ToTable("todos", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnbanTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UnbanAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unbantimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unbantimer_guildconfigid"); + + b.ToTable("unbantimer", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UnmuteAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("unmuteat"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unmutetimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unmutetimer_guildconfigid"); + + b.ToTable("unmutetimer", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnroleTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("UnbanAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unroletimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unroletimer_guildconfigid"); + + b.ToTable("unroletimer", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AwardedXp") + .HasColumnType("bigint") + .HasColumnName("awardedxp"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("NotifyOnLevelUp") + .HasColumnType("integer") + .HasColumnName("notifyonlevelup"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Xp") + .HasColumnType("bigint") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_userxpstats"); + + b.HasIndex("AwardedXp") + .HasDatabaseName("ix_userxpstats_awardedxp"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_userxpstats_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_userxpstats_userid"); + + b.HasIndex("Xp") + .HasDatabaseName("ix_userxpstats_xp"); + + b.HasIndex("UserId", "GuildId") + .IsUnique() + .HasDatabaseName("ix_userxpstats_userid_guildid"); + + b.ToTable("userxpstats", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("VoiceChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("voicechannelid"); + + b.HasKey("Id") + .HasName("pk_vcroleinfo"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_vcroleinfo_guildconfigid"); + + b.ToTable("vcroleinfo", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AffinityId") + .HasColumnType("integer") + .HasColumnName("affinityid"); + + b.Property("ClaimerId") + .HasColumnType("integer") + .HasColumnName("claimerid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Price") + .HasColumnType("bigint") + .HasColumnName("price"); + + b.Property("WaifuId") + .HasColumnType("integer") + .HasColumnName("waifuid"); + + b.HasKey("Id") + .HasName("pk_waifuinfo"); + + b.HasIndex("AffinityId") + .HasDatabaseName("ix_waifuinfo_affinityid"); + + b.HasIndex("ClaimerId") + .HasDatabaseName("ix_waifuinfo_claimerid"); + + b.HasIndex("Price") + .HasDatabaseName("ix_waifuinfo_price"); + + b.HasIndex("WaifuId") + .IsUnique() + .HasDatabaseName("ix_waifuinfo_waifuid"); + + b.ToTable("waifuinfo", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemEmoji") + .HasColumnType("text") + .HasColumnName("itememoji"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("WaifuInfoId") + .HasColumnType("integer") + .HasColumnName("waifuinfoid"); + + b.HasKey("Id") + .HasName("pk_waifuitem"); + + b.HasIndex("WaifuInfoId") + .HasDatabaseName("ix_waifuitem_waifuinfoid"); + + b.ToTable("waifuitem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("NewId") + .HasColumnType("integer") + .HasColumnName("newid"); + + b.Property("OldId") + .HasColumnType("integer") + .HasColumnName("oldid"); + + b.Property("UpdateType") + .HasColumnType("integer") + .HasColumnName("updatetype"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_waifuupdates"); + + b.HasIndex("NewId") + .HasDatabaseName("ix_waifuupdates_newid"); + + b.HasIndex("OldId") + .HasDatabaseName("ix_waifuupdates_oldid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_waifuupdates_userid"); + + b.ToTable("waifuupdates", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Forgiven") + .HasColumnType("boolean") + .HasColumnName("forgiven"); + + b.Property("ForgivenBy") + .HasColumnType("text") + .HasColumnName("forgivenby"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Moderator") + .HasColumnType("text") + .HasColumnName("moderator"); + + b.Property("Reason") + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Weight") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(1L) + .HasColumnName("weight"); + + b.HasKey("Id") + .HasName("pk_warnings"); + + b.HasIndex("DateAdded") + .HasDatabaseName("ix_warnings_dateadded"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_warnings_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_warnings_userid"); + + b.ToTable("warnings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("integer") + .HasColumnName("count"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Punishment") + .HasColumnType("integer") + .HasColumnName("punishment"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("Time") + .HasColumnType("integer") + .HasColumnName("time"); + + b.HasKey("Id") + .HasName("pk_warningpunishment"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_warningpunishment_guildconfigid"); + + b.ToTable("warningpunishment", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("integer") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level"); + + b.Property("XpSettingsId") + .HasColumnType("integer") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xpcurrencyreward"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_xpcurrencyreward_xpsettingsid"); + + b.ToTable("xpcurrencyreward", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level"); + + b.Property("Remove") + .HasColumnType("boolean") + .HasColumnName("remove"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("XpSettingsId") + .HasColumnType("integer") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xprolereward"); + + b.HasIndex("XpSettingsId", "Level") + .IsUnique() + .HasDatabaseName("ix_xprolereward_xpsettingsid_level"); + + b.ToTable("xprolereward", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("ServerExcluded") + .HasColumnType("boolean") + .HasColumnName("serverexcluded"); + + b.HasKey("Id") + .HasName("pk_xpsettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_xpsettings_guildconfigid"); + + b.ToTable("xpsettings", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpShopOwnedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("IsUsing") + .HasColumnType("boolean") + .HasColumnName("isusing"); + + b.Property("ItemKey") + .IsRequired() + .HasColumnType("text") + .HasColumnName("itemkey"); + + b.Property("ItemType") + .HasColumnType("integer") + .HasColumnName("itemtype"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_xpshopowneditem"); + + b.HasIndex("UserId", "ItemType", "ItemKey") + .IsUnique() + .HasDatabaseName("ix_xpshopowneditem_userid_itemtype_itemkey"); + + b.ToTable("xpshopowneditem", (string)null); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiAltSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiAltSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antialtsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antiraidsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Db.Models.AntiSpamSetting", null) + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_antispamignore_antispamsetting_antispamsettingid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antispamsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b => + { + b.HasOne("NadekoBot.Db.Models.AutoTranslateChannel", "Channel") + .WithMany("Users") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_autotranslateusers_autotranslatechannels_channelid"); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_clubs_clubid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_clubs_clubid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("NadekoBot.Db.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_clubs_discorduser_ownerid"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandalias_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandcooldown_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("DelMsgOnCmdChannels") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_delmsgoncmdchannel_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Members") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.NoAction) + .HasConstraintName("fk_discorduser_clubs_clubid"); + + b.Navigation("Club"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_feedsub_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterchannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterLinksChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterLinksChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterlinkschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterWordsChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterwordschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filteredword_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_followedstream_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_gcchannelid_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayUser", b => + { + b.HasOne("NadekoBot.Db.Models.GiveawayModel", null) + .WithMany("Participants") + .HasForeignKey("GiveawayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_giveawayuser_giveawaymodel_giveawayid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("SelfAssignableRoleGroupNames") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_groupname_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b => + { + b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting") + .WithMany("LogIgnores") + .HasForeignKey("LogSettingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ignoredlogchannels_logsettings_logsettingid"); + + b.Navigation("LogSetting"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_muteduserid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("Permissions") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_permissions_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Db.Models.MusicPlaylist", null) + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_playlistsong_musicplaylists_musicplaylistid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentry_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Db.Models.ShopEntry", null) + .WithMany("Items") + .HasForeignKey("ShopEntryId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentryitem_shopentry_shopentryid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoredrole_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoreduser_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamroleblacklisteduser_streamrolesettings_streamrolesett~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("NadekoBot.Db.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolesettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolewhitelisteduser_streamrolesettings_streamrolesett~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b => + { + b.HasOne("NadekoBot.Db.Models.ArchivedTodoListModel", null) + .WithMany("Items") + .HasForeignKey("ArchiveId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_todos_todosarchive_archiveid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnbanTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnbanTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unbantimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unmutetimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnroleTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnroleTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unroletimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_vcroleinfo_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId") + .HasConstraintName("fk_waifuinfo_discorduser_affinityid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId") + .HasConstraintName("fk_waifuinfo_discorduser_claimerid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Db.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuinfo_discorduser_waifuid"); + + b.Navigation("Affinity"); + + b.Navigation("Claimer"); + + b.Navigation("Waifu"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuItem", b => + { + b.HasOne("NadekoBot.Db.Models.WaifuInfo", "WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId") + .HasConstraintName("fk_waifuitem_waifuinfo_waifuinfoid"); + + b.Navigation("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId") + .HasConstraintName("fk_waifuupdates_discorduser_newid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId") + .HasConstraintName("fk_waifuupdates_discorduser_oldid"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuupdates_discorduser_userid"); + + b.Navigation("New"); + + b.Navigation("Old"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_warningpunishment_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("CurrencyRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpcurrencyreward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpRoleReward", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xprolereward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("NadekoBot.Db.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpsettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.Navigation("IgnoredChannels"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ArchivedTodoListModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateChannel", b => + { + b.Navigation("Users"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.Navigation("Applicants"); + + b.Navigation("Bans"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayModel", b => + { + b.Navigation("Participants"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b => + { + b.Navigation("AntiAltSetting"); + + b.Navigation("AntiRaidSetting"); + + b.Navigation("AntiSpamSetting"); + + b.Navigation("CommandAliases"); + + b.Navigation("CommandCooldowns"); + + b.Navigation("DelMsgOnCmdChannels"); + + b.Navigation("FeedSubs"); + + b.Navigation("FilterInvitesChannelIds"); + + b.Navigation("FilterLinksChannelIds"); + + b.Navigation("FilterWordsChannelIds"); + + b.Navigation("FilteredWords"); + + b.Navigation("FollowedStreams"); + + b.Navigation("GenerateCurrencyChannelIds"); + + b.Navigation("MutedUsers"); + + b.Navigation("Permissions"); + + b.Navigation("SelfAssignableRoleGroupNames"); + + b.Navigation("ShopEntries"); + + b.Navigation("SlowmodeIgnoredRoles"); + + b.Navigation("SlowmodeIgnoredUsers"); + + b.Navigation("StreamRole"); + + b.Navigation("UnbanTimer"); + + b.Navigation("UnmuteTimers"); + + b.Navigation("UnroleTimer"); + + b.Navigation("VcRoleInfos"); + + b.Navigation("WarnPunishments"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.LogSetting", b => + { + b.Navigation("LogIgnores"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlaylist", b => + { + b.Navigation("Songs"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.Navigation("Blacklist"); + + b.Navigation("Whitelist"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.Navigation("CurrencyRewards"); + + b.Navigation("ExclusionList"); + + b.Navigation("RoleRewards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs b/src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs new file mode 100644 index 000000000..04e7008d6 --- /dev/null +++ b/src/NadekoBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace NadekoBot.Migrations.PostgreSql +{ + /// + public partial class removepatronlimits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "patronquotas"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "patronquotas", + columns: table => new + { + userid = table.Column(type: "numeric(20,0)", nullable: false), + featuretype = table.Column(type: "integer", nullable: false), + feature = table.Column(type: "text", nullable: false), + dailycount = table.Column(type: "bigint", nullable: false), + hourlycount = table.Column(type: "bigint", nullable: false), + monthlycount = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_patronquotas", x => new { x.userid, x.featuretype, x.feature }); + }); + + migrationBuilder.CreateIndex( + name: "ix_patronquotas_userid", + table: "patronquotas", + column: "userid"); + } + } +} diff --git a/src/NadekoBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs b/src/NadekoBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs index 5ba227456..31733c1b4 100644 --- a/src/NadekoBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs @@ -1717,41 +1717,6 @@ namespace NadekoBot.Migrations.PostgreSql b.ToTable("expressions", (string)null); }); - modelBuilder.Entity("NadekoBot.Db.Models.PatronQuota", b => - { - b.Property("UserId") - .HasColumnType("numeric(20,0)") - .HasColumnName("userid"); - - b.Property("FeatureType") - .HasColumnType("integer") - .HasColumnName("featuretype"); - - b.Property("Feature") - .HasColumnType("text") - .HasColumnName("feature"); - - b.Property("DailyCount") - .HasColumnType("bigint") - .HasColumnName("dailycount"); - - b.Property("HourlyCount") - .HasColumnType("bigint") - .HasColumnName("hourlycount"); - - b.Property("MonthlyCount") - .HasColumnType("bigint") - .HasColumnName("monthlycount"); - - b.HasKey("UserId", "FeatureType", "Feature") - .HasName("pk_patronquotas"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_patronquotas_userid"); - - b.ToTable("patronquotas", (string)null); - }); - modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b => { b.Property("UserId") diff --git a/src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs b/src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs new file mode 100644 index 000000000..f294e637d --- /dev/null +++ b/src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs @@ -0,0 +1,2921 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NadekoBot.Db; + +#nullable disable + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(SqliteContext))] + [Migration("20240611180456_remove-patron-limits")] + partial class removepatronlimits + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.4"); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasColumnType("INTEGER"); + + b.Property("ActionDurationMinutes") + .HasColumnType("INTEGER"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("MinAge") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiAltSetting"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("PunishDuration") + .HasColumnType("INTEGER"); + + b.Property("Seconds") + .HasColumnType("INTEGER"); + + b.Property("UserThreshold") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AntiSpamSettingId") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("MessageThreshold") + .HasColumnType("INTEGER"); + + b.Property("MuteTime") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ArchivedTodoListModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("TodosArchive"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("ChannelName") + .HasColumnType("TEXT"); + + b.Property("CommandText") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("GuildName") + .HasColumnType("TEXT"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("VoiceChannelId") + .HasColumnType("INTEGER"); + + b.Property("VoiceChannelName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AutoCommands"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoPublishChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("AutoPublishChannel"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoDelete") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId") + .IsUnique(); + + b.HasIndex("GuildId"); + + b.ToTable("AutoTranslateChannels"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Source") + .HasColumnType("TEXT"); + + b.Property("Target") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasAlternateKey("ChannelId", "UserId"); + + b.ToTable("AutoTranslateUsers"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BanTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("PruneDays") + .HasColumnType("INTEGER"); + + b.Property("Text") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("BanTemplates"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Balance") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("BankUsers"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.BlacklistEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Blacklist"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b => + { + b.Property("ClubId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubApplicants"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b => + { + b.Property("ClubId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubBans"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("ImageUrl") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("Xp") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("OwnerId") + .IsUnique(); + + b.ToTable("Clubs"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Mapping") + .HasColumnType("TEXT"); + + b.Property("Trigger") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CommandName") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Seconds") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Note") + .HasColumnType("TEXT"); + + b.Property("OtherId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValueSql("NULL"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("DelMsgOnCmdChannel"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordPermOverride", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Command") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Perm") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "Command") + .IsUnique(); + + b.ToTable("DiscordPermOverrides"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AvatarId") + .HasColumnType("TEXT"); + + b.Property("ClubId") + .HasColumnType("INTEGER"); + + b.Property("CurrencyAmount") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0L); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Discriminator") + .HasColumnType("TEXT"); + + b.Property("IsClubAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("NotifyOnLevelUp") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("TotalXp") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0L); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.HasIndex("ClubId"); + + b.HasIndex("CurrencyAmount"); + + b.HasIndex("TotalXp"); + + b.HasIndex("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("INTEGER"); + + b.Property("ItemType") + .HasColumnType("INTEGER"); + + b.Property("XpSettingsId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId"); + + b.ToTable("ExcludedItem"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasAlternateKey("GuildConfigId", "Url"); + + b.ToTable("FeedSub"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterLinksChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilterLinksChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterWordsChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilterWordsChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Word") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GamblingStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Bet") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Feature") + .HasColumnType("TEXT"); + + b.Property("PaidOut") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Feature") + .IsUnique(); + + b.ToTable("GamblingStats"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("EndsAt") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("GiveawayModel"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("GiveawayId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GiveawayId", "UserId") + .IsUnique(); + + b.ToTable("GiveawayUser"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId", "Number") + .IsUnique(); + + b.ToTable("GroupName"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoAssignRoleIds") + .HasColumnType("TEXT"); + + b.Property("AutoDeleteByeMessagesTimer") + .HasColumnType("INTEGER"); + + b.Property("AutoDeleteGreetMessagesTimer") + .HasColumnType("INTEGER"); + + b.Property("AutoDeleteSelfAssignedRoleMessages") + .HasColumnType("INTEGER"); + + b.Property("BoostMessage") + .HasColumnType("TEXT"); + + b.Property("BoostMessageChannelId") + .HasColumnType("INTEGER"); + + b.Property("BoostMessageDeleteAfter") + .HasColumnType("INTEGER"); + + b.Property("ByeMessageChannelId") + .HasColumnType("INTEGER"); + + b.Property("ChannelByeMessageText") + .HasColumnType("TEXT"); + + b.Property("ChannelGreetMessageText") + .HasColumnType("TEXT"); + + b.Property("CleverbotEnabled") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DeleteMessageOnCommand") + .HasColumnType("INTEGER"); + + b.Property("DeleteStreamOnlineMessage") + .HasColumnType("INTEGER"); + + b.Property("DisableGlobalExpressions") + .HasColumnType("INTEGER"); + + b.Property("DmGreetMessageText") + .HasColumnType("TEXT"); + + b.Property("ExclusiveSelfAssignedRoles") + .HasColumnType("INTEGER"); + + b.Property("FilterInvites") + .HasColumnType("INTEGER"); + + b.Property("FilterLinks") + .HasColumnType("INTEGER"); + + b.Property("FilterWords") + .HasColumnType("INTEGER"); + + b.Property("GameVoiceChannel") + .HasColumnType("INTEGER"); + + b.Property("GreetMessageChannelId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Locale") + .HasColumnType("TEXT"); + + b.Property("MuteRoleName") + .HasColumnType("TEXT"); + + b.Property("NotifyStreamOffline") + .HasColumnType("INTEGER"); + + b.Property("PermissionRole") + .HasColumnType("TEXT"); + + b.Property("Prefix") + .HasColumnType("TEXT"); + + b.Property("SendBoostMessage") + .HasColumnType("INTEGER"); + + b.Property("SendChannelByeMessage") + .HasColumnType("INTEGER"); + + b.Property("SendChannelGreetMessage") + .HasColumnType("INTEGER"); + + b.Property("SendDmGreetMessage") + .HasColumnType("INTEGER"); + + b.Property("StickyRoles") + .HasColumnType("INTEGER"); + + b.Property("TimeZoneId") + .HasColumnType("TEXT"); + + b.Property("VerboseErrors") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("VerbosePermissions") + .HasColumnType("INTEGER"); + + b.Property("WarnExpireAction") + .HasColumnType("INTEGER"); + + b.Property("WarnExpireHours") + .HasColumnType("INTEGER"); + + b.Property("WarningsInitialized") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("WarnExpireHours"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemType") + .HasColumnType("INTEGER"); + + b.Property("LogItemId") + .HasColumnType("INTEGER"); + + b.Property("LogSettingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId", "LogItemId", "ItemType") + .IsUnique(); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ImageOnlyChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId") + .IsUnique(); + + b.ToTable("ImageOnlyChannels"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelCreatedId") + .HasColumnType("INTEGER"); + + b.Property("ChannelDestroyedId") + .HasColumnType("INTEGER"); + + b.Property("ChannelUpdatedId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LogOtherId") + .HasColumnType("INTEGER"); + + b.Property("LogUserPresenceId") + .HasColumnType("INTEGER"); + + b.Property("LogVoicePresenceId") + .HasColumnType("INTEGER"); + + b.Property("LogVoicePresenceTTSId") + .HasColumnType("INTEGER"); + + b.Property("LogWarnsId") + .HasColumnType("INTEGER"); + + b.Property("MessageDeletedId") + .HasColumnType("INTEGER"); + + b.Property("MessageUpdatedId") + .HasColumnType("INTEGER"); + + b.Property("ThreadCreatedId") + .HasColumnType("INTEGER"); + + b.Property("ThreadDeletedId") + .HasColumnType("INTEGER"); + + b.Property("UserBannedId") + .HasColumnType("INTEGER"); + + b.Property("UserJoinedId") + .HasColumnType("INTEGER"); + + b.Property("UserLeftId") + .HasColumnType("INTEGER"); + + b.Property("UserMutedId") + .HasColumnType("INTEGER"); + + b.Property("UserUnbannedId") + .HasColumnType("INTEGER"); + + b.Property("UserUpdatedId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlayerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoDisconnect") + .HasColumnType("INTEGER"); + + b.Property("AutoPlay") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("MusicChannelId") + .HasColumnType("INTEGER"); + + b.Property("PlayerRepeat") + .HasColumnType("INTEGER"); + + b.Property("QualityPreset") + .HasColumnType("INTEGER"); + + b.Property("Volume") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(100); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("MusicPlayerSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Author") + .HasColumnType("TEXT"); + + b.Property("AuthorId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.NadekoExpression", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AllowTarget") + .HasColumnType("INTEGER"); + + b.Property("AutoDeleteTrigger") + .HasColumnType("INTEGER"); + + b.Property("ContainsAnywhere") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DmResponse") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Reactions") + .HasColumnType("TEXT"); + + b.Property("Response") + .HasColumnType("TEXT"); + + b.Property("Trigger") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Expressions"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AmountCents") + .HasColumnType("INTEGER"); + + b.Property("LastCharge") + .HasColumnType("TEXT"); + + b.Property("UniquePlatformUserId") + .HasColumnType("TEXT"); + + b.Property("ValidThru") + .HasColumnType("TEXT"); + + b.HasKey("UserId"); + + b.HasIndex("UniquePlatformUserId") + .IsUnique(); + + b.ToTable("Patrons"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("IsCustomCommand") + .HasColumnType("INTEGER"); + + b.Property("PrimaryTarget") + .HasColumnType("INTEGER"); + + b.Property("PrimaryTargetId") + .HasColumnType("INTEGER"); + + b.Property("SecondaryTarget") + .HasColumnType("INTEGER"); + + b.Property("SecondaryTargetName") + .HasColumnType("TEXT"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlantedCurrency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId"); + + b.HasIndex("MessageId") + .IsUnique(); + + b.ToTable("PlantedCurrency"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("MusicPlaylistId") + .HasColumnType("INTEGER"); + + b.Property("Provider") + .HasColumnType("TEXT"); + + b.Property("ProviderType") + .HasColumnType("INTEGER"); + + b.Property("Query") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Uri") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AuthorId") + .HasColumnType("INTEGER"); + + b.Property("AuthorName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Keyword") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Text") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.HasIndex("Keyword"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ReactionRoleV2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Emote") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Group") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LevelReq") + .HasColumnType("INTEGER"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.HasIndex("MessageId", "Emote") + .IsUnique(); + + b.ToTable("ReactionRoles"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("IsPrivate") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("When") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("When"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("TEXT"); + + b.Property("LastMessageId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("NoRedundant") + .HasColumnType("INTEGER"); + + b.Property("StartTimeOfDay") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Repeaters"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AmountRewardedThisMonth") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("LastReward") + .HasColumnType("TEXT"); + + b.Property("PlatformUserId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PlatformUserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.RotatingPlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("RotatingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Group") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LevelRequirement") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AuthorId") + .HasColumnType("INTEGER"); + + b.Property("Command") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("RoleName") + .HasColumnType("TEXT"); + + b.Property("RoleRequirement") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ShopEntryId") + .HasColumnType("INTEGER"); + + b.Property("Text") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StickyRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("RoleIds") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "UserId") + .IsUnique(); + + b.ToTable("StickyRoles"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamOnlineMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("StreamOnlineMessages"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleBlacklistedUser"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddRoleId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("FromRoleId") + .HasColumnType("INTEGER"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Keyword") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleWhitelistedUser"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArchiveId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("IsDone") + .HasColumnType("INTEGER"); + + b.Property("Todo") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArchiveId"); + + b.HasIndex("UserId"); + + b.ToTable("Todos"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnbanTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UnbanAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnbanTimer"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UnmuteAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnroleTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UnbanAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnroleTimer"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AwardedXp") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("NotifyOnLevelUp") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Xp") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AwardedXp"); + + b.HasIndex("GuildId"); + + b.HasIndex("UserId"); + + b.HasIndex("Xp"); + + b.HasIndex("UserId", "GuildId") + .IsUnique(); + + b.ToTable("UserXpStats"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("VoiceChannelId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AffinityId") + .HasColumnType("INTEGER"); + + b.Property("ClaimerId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("WaifuId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("Price"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemEmoji") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("WaifuInfoId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("WaifuInfoId"); + + b.ToTable("WaifuItem"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("NewId") + .HasColumnType("INTEGER"); + + b.Property("OldId") + .HasColumnType("INTEGER"); + + b.Property("UpdateType") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Forgiven") + .HasColumnType("INTEGER"); + + b.Property("ForgivenBy") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Moderator") + .HasColumnType("TEXT"); + + b.Property("Reason") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Weight") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(1L); + + b.HasKey("Id"); + + b.HasIndex("DateAdded"); + + b.HasIndex("GuildId"); + + b.HasIndex("UserId"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Punishment") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("Time") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("XpSettingsId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId"); + + b.ToTable("XpCurrencyReward"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("Remove") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("XpSettingsId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId", "Level") + .IsUnique(); + + b.ToTable("XpRoleReward"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("ServerExcluded") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpShopOwnedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("IsUsing") + .HasColumnType("INTEGER"); + + b.Property("ItemKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ItemType") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemType", "ItemKey") + .IsUnique(); + + b.ToTable("XpShopOwnedItem"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiAltSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiAltSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiAltSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Db.Models.AntiSpamSetting", null) + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Db.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateUser", b => + { + b.HasOne("NadekoBot.Db.Models.AutoTranslateChannel", "Channel") + .WithMany("Users") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("NadekoBot.Db.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("DelMsgOnCmdChannels") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b => + { + b.HasOne("NadekoBot.Db.Models.ClubInfo", "Club") + .WithMany("Members") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Club"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ExcludedItem", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FeedSub", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterLinksChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterLinksChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilterWordsChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayUser", b => + { + b.HasOne("NadekoBot.Db.Models.GiveawayModel", null) + .WithMany("Participants") + .HasForeignKey("GiveawayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GroupName", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("SelfAssignableRoleGroupNames") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.IgnoredLogItem", b => + { + b.HasOne("NadekoBot.Db.Models.LogSetting", "LogSetting") + .WithMany("LogIgnores") + .HasForeignKey("LogSettingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LogSetting"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("Permissions") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Db.Models.MusicPlaylist", null) + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Db.Models.ShopEntry", null) + .WithMany("Items") + .HasForeignKey("ShopEntryId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("NadekoBot.Db.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("NadekoBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.TodoModel", b => + { + b.HasOne("NadekoBot.Db.Models.ArchivedTodoListModel", null) + .WithMany("Items") + .HasForeignKey("ArchiveId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnbanTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnbanTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.UnroleTimer", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("UnroleTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Db.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Affinity"); + + b.Navigation("Claimer"); + + b.Navigation("Waifu"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuItem", b => + { + b.HasOne("NadekoBot.Db.Models.WaifuInfo", "WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId"); + + b.Navigation("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Db.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("New"); + + b.Navigation("Old"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", null) + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpCurrencyReward", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("CurrencyRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpRoleReward", b => + { + b.HasOne("NadekoBot.Db.Models.XpSettings", "XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.HasOne("NadekoBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("NadekoBot.Db.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AntiSpamSetting", b => + { + b.Navigation("IgnoredChannels"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ArchivedTodoListModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.AutoTranslateChannel", b => + { + b.Navigation("Users"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => + { + b.Navigation("Applicants"); + + b.Navigation("Bans"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GiveawayModel", b => + { + b.Navigation("Participants"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.GuildConfig", b => + { + b.Navigation("AntiAltSetting"); + + b.Navigation("AntiRaidSetting"); + + b.Navigation("AntiSpamSetting"); + + b.Navigation("CommandAliases"); + + b.Navigation("CommandCooldowns"); + + b.Navigation("DelMsgOnCmdChannels"); + + b.Navigation("FeedSubs"); + + b.Navigation("FilterInvitesChannelIds"); + + b.Navigation("FilterLinksChannelIds"); + + b.Navigation("FilterWordsChannelIds"); + + b.Navigation("FilteredWords"); + + b.Navigation("FollowedStreams"); + + b.Navigation("GenerateCurrencyChannelIds"); + + b.Navigation("MutedUsers"); + + b.Navigation("Permissions"); + + b.Navigation("SelfAssignableRoleGroupNames"); + + b.Navigation("ShopEntries"); + + b.Navigation("SlowmodeIgnoredRoles"); + + b.Navigation("SlowmodeIgnoredUsers"); + + b.Navigation("StreamRole"); + + b.Navigation("UnbanTimer"); + + b.Navigation("UnmuteTimers"); + + b.Navigation("UnroleTimer"); + + b.Navigation("VcRoleInfos"); + + b.Navigation("WarnPunishments"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.LogSetting", b => + { + b.Navigation("LogIgnores"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.MusicPlaylist", b => + { + b.Navigation("Songs"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.ShopEntry", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.StreamRoleSettings", b => + { + b.Navigation("Blacklist"); + + b.Navigation("Whitelist"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.WaifuInfo", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("NadekoBot.Db.Models.XpSettings", b => + { + b.Navigation("CurrencyRewards"); + + b.Navigation("ExclusionList"); + + b.Navigation("RoleRewards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs b/src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs new file mode 100644 index 000000000..82e346675 --- /dev/null +++ b/src/NadekoBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace NadekoBot.Migrations +{ + /// + public partial class removepatronlimits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PatronQuotas"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "PatronQuotas", + columns: table => new + { + UserId = table.Column(type: "INTEGER", nullable: false), + FeatureType = table.Column(type: "INTEGER", nullable: false), + Feature = table.Column(type: "TEXT", nullable: false), + DailyCount = table.Column(type: "INTEGER", nullable: false), + HourlyCount = table.Column(type: "INTEGER", nullable: false), + MonthlyCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PatronQuotas", x => new { x.UserId, x.FeatureType, x.Feature }); + }); + + migrationBuilder.CreateIndex( + name: "IX_PatronQuotas_UserId", + table: "PatronQuotas", + column: "UserId"); + } + } +} diff --git a/src/NadekoBot/Migrations/Sqlite/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/Sqlite/NadekoSqliteContextModelSnapshot.cs index 63077f840..6bf656b1f 100644 --- a/src/NadekoBot/Migrations/Sqlite/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/Sqlite/NadekoSqliteContextModelSnapshot.cs @@ -1279,33 +1279,6 @@ namespace NadekoBot.Migrations b.ToTable("Expressions"); }); - modelBuilder.Entity("NadekoBot.Db.Models.PatronQuota", b => - { - b.Property("UserId") - .HasColumnType("INTEGER"); - - b.Property("FeatureType") - .HasColumnType("INTEGER"); - - b.Property("Feature") - .HasColumnType("TEXT"); - - b.Property("DailyCount") - .HasColumnType("INTEGER"); - - b.Property("HourlyCount") - .HasColumnType("INTEGER"); - - b.Property("MonthlyCount") - .HasColumnType("INTEGER"); - - b.HasKey("UserId", "FeatureType", "Feature"); - - b.HasIndex("UserId"); - - b.ToTable("PatronQuotas"); - }); - modelBuilder.Entity("NadekoBot.Db.Models.PatronUser", b => { b.Property("UserId") diff --git a/src/NadekoBot/Modules/Administration/DangerousCommands/CleanupService.cs b/src/NadekoBot/Modules/Administration/DangerousCommands/CleanupService.cs index e57d3a6c1..f3b759eb7 100644 --- a/src/NadekoBot/Modules/Administration/DangerousCommands/CleanupService.cs +++ b/src/NadekoBot/Modules/Administration/DangerousCommands/CleanupService.cs @@ -61,17 +61,66 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService })); } + // delete guild configs await ctx.GetTable() .Where(x => !tempTable.Select(x => x.GuildId) .Contains(x.GuildId)) .DeleteAsync(); - - + + // delete guild xp await ctx.GetTable() .Where(x => !tempTable.Select(x => x.GuildId) .Contains(x.GuildId)) .DeleteAsync(); - + + // delete expressions + await ctx.GetTable() + .Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId.Value)) + .DeleteAsync(); + + // delete quotes + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete planted currencies + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete image only channels + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete reaction roles + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete ignored users + await ctx.GetTable() + .Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId.Value)) + .DeleteAsync(); + + // delete perm overrides + await ctx.GetTable() + .Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId.Value)) + .DeleteAsync(); + + // delete repeaters + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + return new() { GuildCount = guildIds.Keys.Count, diff --git a/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs b/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs index 46f65bc36..7bf45df2a 100644 --- a/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs +++ b/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs @@ -45,23 +45,43 @@ public partial class Administration var progressMsg = await Response().Pending(strs.prune_progress(0, 100)).SendAsync(); var progress = GetProgressTracker(progressMsg); + PruneResult result; if (opts.Safe) - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id && !x.IsPinned, progress, opts.After); else - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id, progress, opts.After); ctx.Message.DeleteAfter(3); + + await SendResult(result); await progressMsg.DeleteAsync(); } + private async Task SendResult(PruneResult result) + { + switch (result) + { + case PruneResult.Success: + break; + case PruneResult.AlreadyRunning: + break; + case PruneResult.FeatureLimit: + await Response().Pending(strs.feature_limit_reached_owner).SendAsync(); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(result), result, null); + } + } + // prune x [Cmd] [RequireContext(ContextType.Guild)] @@ -83,19 +103,21 @@ public partial class Administration var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync(); var progress = GetProgressTracker(progressMsg); + PruneResult result; if (opts.Safe) - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, x => !x.IsPinned && x.Id != progressMsg.Id, progress, opts.After); else - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, x => x.Id != progressMsg.Id, progress, opts.After); + await SendResult(result); await progressMsg.DeleteAsync(); } @@ -155,9 +177,10 @@ public partial class Administration var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync(); var progress = GetProgressTracker(progressMsg); + PruneResult result; if (opts.Safe) { - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned, progress, @@ -166,7 +189,7 @@ public partial class Administration } else { - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks, progress, @@ -174,6 +197,7 @@ public partial class Administration ); } + await SendResult(result); await progressMsg.DeleteAsync(); } diff --git a/src/NadekoBot/Modules/Administration/Prune/PruneResult.cs b/src/NadekoBot/Modules/Administration/Prune/PruneResult.cs new file mode 100644 index 000000000..3fa03607d --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Prune/PruneResult.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace NadekoBot.Modules.Administration.Services; + +public enum PruneResult +{ + Success, + AlreadyRunning, + FeatureLimit, +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Prune/PruneService.cs b/src/NadekoBot/Modules/Administration/Prune/PruneService.cs index 6824831a4..f2796a72b 100644 --- a/src/NadekoBot/Modules/Administration/Prune/PruneService.cs +++ b/src/NadekoBot/Modules/Administration/Prune/PruneService.cs @@ -1,4 +1,6 @@ #nullable disable +using NadekoBot.Modules.Patronage; + namespace NadekoBot.Modules.Administration.Services; public class PruneService : INService @@ -7,11 +9,15 @@ public class PruneService : INService private readonly ConcurrentDictionary _pruningGuilds = new(); private readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14); private readonly ILogCommandService _logService; + private readonly IPatronageService _ps; - public PruneService(ILogCommandService logService) - => _logService = logService; + public PruneService(ILogCommandService logService, IPatronageService ps) + { + _logService = logService; + _ps = ps; + } - public async Task PruneWhere( + public async Task PruneWhere( ITextChannel channel, int amount, Func predicate, @@ -26,8 +32,13 @@ public class PruneService : INService using var cancelSource = new CancellationTokenSource(); if (!_pruningGuilds.TryAdd(channel.GuildId, cancelSource)) - return; + return PruneResult.AlreadyRunning; + if (!await _ps.LimitHitAsync(LimitedFeatureName.Prune, channel.Guild.OwnerId)) + { + return PruneResult.FeatureLimit; + } + try { var now = DateTime.UtcNow; @@ -47,7 +58,7 @@ public class PruneService : INService .ToArray(); if (!msgs.Any()) - return; + return PruneResult.Success; lastMessage = msgs[^1]; @@ -88,6 +99,8 @@ public class PruneService : INService { _pruningGuilds.TryRemove(channel.GuildId, out _); } + + return PruneResult.Success; } public async Task CancelAsync(ulong guildId) diff --git a/src/NadekoBot/Modules/Administration/Role/IReactionRoleService.cs b/src/NadekoBot/Modules/Administration/Role/IReactionRoleService.cs index 49678b5e6..c2d8f242a 100644 --- a/src/NadekoBot/Modules/Administration/Role/IReactionRoleService.cs +++ b/src/NadekoBot/Modules/Administration/Role/IReactionRoleService.cs @@ -18,7 +18,7 @@ public interface IReactionRoleService /// /// /// The result of the operation - Task> AddReactionRole( + Task> AddReactionRole( IGuild guild, IMessage msg, string emote, diff --git a/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs b/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs index 6f972043d..df8d23d3c 100644 --- a/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Role/ReactionRoleCommands.cs @@ -55,12 +55,10 @@ public partial class Administration await res.Match( _ => ctx.OkAsync(), - fl => + async fl => { _ = msg.RemoveReactionAsync(emote, ctx.Client.CurrentUser); - return !fl.IsPatronLimit - ? Response().Error(strs.limit_reached(fl.Quota)).SendAsync() - : Response().Pending(strs.feature_limit_reached_owner(fl.Quota, fl.Name)).SendAsync(); + await Response().Pending(strs.feature_limit_reached_owner).SendAsync(); }); } diff --git a/src/NadekoBot/Modules/Administration/Role/ReactionRolesService.cs b/src/NadekoBot/Modules/Administration/Role/ReactionRolesService.cs index 0d8bab39e..f45cf524f 100644 --- a/src/NadekoBot/Modules/Administration/Role/ReactionRolesService.cs +++ b/src/NadekoBot/Modules/Administration/Role/ReactionRolesService.cs @@ -21,22 +21,16 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR private readonly SemaphoreSlim _assignementLock = new(1, 1); private readonly IPatronageService _ps; - private static readonly FeatureLimitKey _reroFLKey = new() - { - Key = "rero:max_count", - PrettyName = "Reaction Role" - }; - public ReactionRolesService( DiscordSocketClient client, + IPatronageService ps, DbService db, - IBotCredentials creds, - IPatronageService ps) + IBotCredentials creds) { _db = db; - _ps = ps; _client = client; _creds = creds; + _ps = ps; _cache = new(); } @@ -242,7 +236,7 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR /// /// /// The result of the operation - public async Task> AddReactionRole( + public async Task> AddReactionRole( IGuild guild, IMessage msg, string emote, @@ -260,10 +254,13 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR var activeReactionRoles = await ctx.GetTable() .Where(x => x.GuildId == guild.Id) .CountAsync(); + + var limit = await _ps.GetUserLimit(LimitedFeatureName.ReactionRole, guild.OwnerId); - var result = await _ps.TryGetFeatureLimitAsync(_reroFLKey, guild.OwnerId, 50); - if (result.Quota != -1 && activeReactionRoles >= result.Quota) - return result; + if (!_creds.IsOwner(guild.OwnerId) && (activeReactionRoles >= limit.Quota && limit.Quota >= 0)) + { + return new Error(); + } await ctx.GetTable() .InsertOrUpdateAsync(() => new() diff --git a/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs b/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs index 22687eac4..4ad1585d6 100644 --- a/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs +++ b/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs @@ -3,6 +3,7 @@ using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Common.Blackjack; using NadekoBot.Modules.Gambling.Services; +using NadekoBot.Modules.Utility; namespace NadekoBot.Modules.Gambling; diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index bfa085da9..56779ccbb 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -14,6 +14,7 @@ using System.Text; using NadekoBot.Modules.Gambling.Rps; using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Patronage; +using NadekoBot.Modules.Utility; namespace NadekoBot.Modules.Gambling; @@ -27,9 +28,9 @@ public partial class Gambling : GamblingModule private readonly DownloadTracker _tracker; private readonly GamblingConfigService _configService; private readonly IBankService _bank; - private readonly IPatronageService _ps; private readonly IRemindService _remind; private readonly GamblingTxTracker _gamblingTxTracker; + private readonly IPatronageService _ps; private IUserMessage rdMsg; @@ -41,8 +42,8 @@ public partial class Gambling : GamblingModule DownloadTracker tracker, GamblingConfigService configService, IBankService bank, - IPatronageService ps, IRemindService remind, + IPatronageService patronage, GamblingTxTracker gamblingTxTracker) : base(configService) { @@ -51,9 +52,9 @@ public partial class Gambling : GamblingModule _cs = currency; _client = client; _bank = bank; - _ps = ps; _remind = remind; _gamblingTxTracker = gamblingTxTracker; + _ps = patronage; _enUsCulture = new CultureInfo("en-US", false).NumberFormat; _enUsCulture.NumberDecimalDigits = 0; @@ -133,12 +134,6 @@ public partial class Gambling : GamblingModule await Response().Embed(embed).SendAsync(); } - private static readonly FeatureLimitKey _timelyKey = new FeatureLimitKey() - { - Key = "timely:extra_percent", - PrettyName = "Timely" - }; - private async Task RemindTimelyAction(SocketMessageComponent smc, DateTime when) { var tt = TimestampTag.FromDateTime(when, TimestampTagStyles.Relative); @@ -191,9 +186,12 @@ public partial class Gambling : GamblingModule return; } - var result = await _ps.TryGetFeatureLimitAsync(_timelyKey, ctx.User.Id, 0); - val = (int)(val * (1 + (result.Quota! * 0.01f))); + var patron = await _ps.GetPatronAsync(ctx.User.Id); + + var percentBonus = (_ps.PercentBonus(patron) / 100f); + + val += (int)(val * percentBonus); await _cs.AddAsync(ctx.User.Id, val, new("timely", "claim")); @@ -892,6 +890,7 @@ public partial class Gambling : GamblingModule private static readonly ImmutableArray _emojis = new[] { "⬆", "↖", "⬅", "↙", "⬇", "↘", "➡", "↗" }.ToImmutableArray(); + [Cmd] public async Task LuckyLadder([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { diff --git a/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs b/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs index adc85b423..ef7534df8 100644 --- a/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs @@ -247,7 +247,14 @@ public partial class Gambling } else { - var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString()); + var buyer = (IGuildUser)ctx.User; + var cmd = entry.Command + .Replace("%you%", buyer.Mention) + .Replace("%you.mention%", buyer.Mention) + .Replace("%you.username%", buyer.Username) + .Replace("%you.name%", buyer.GlobalName ?? buyer.Username) + .Replace("%you.nick%", buyer.DisplayName); + var eb = _sender.CreateEmbed() .WithPendingColor() .WithTitle("Executing shop command") @@ -259,6 +266,7 @@ public partial class Gambling GetProfitAmount(entry.Price), new("shop", "sell", entry.Name)); + await Task.Delay(250); await _cmdHandler.TryRunCommand(guild, channel, new DoAsUserMessage( diff --git a/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs b/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs index f8975a353..5174a4913 100644 --- a/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs @@ -9,6 +9,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using NadekoBot.Modules.Gambling; using NadekoBot.Common.TypeReaders; +using NadekoBot.Modules.Utility; using Color = SixLabors.ImageSharp.Color; using Image = SixLabors.ImageSharp.Image; diff --git a/src/NadekoBot/Modules/Games/ChatterBot/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/ChatterBot/ChatterBotCommands.cs similarity index 85% rename from src/NadekoBot/Modules/Games/ChatterBot/CleverBotCommands.cs rename to src/NadekoBot/Modules/Games/ChatterBot/ChatterBotCommands.cs index 820c8aa75..ac8062aad 100644 --- a/src/NadekoBot/Modules/Games/ChatterBot/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/ChatterBot/ChatterBotCommands.cs @@ -18,7 +18,8 @@ public partial class Games [Cmd] [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageMessages)] - public async Task Cleverbot() + [NoPublicBot] + public async Task CleverBot() { var channel = (ITextChannel)ctx.Channel; @@ -30,7 +31,7 @@ public partial class Games await uow.SaveChangesAsync(); } - await Response().Confirm(strs.cleverbot_disabled).SendAsync(); + await Response().Confirm(strs.chatbot_disabled).SendAsync(); return; } @@ -42,7 +43,7 @@ public partial class Games await uow.SaveChangesAsync(); } - await Response().Confirm(strs.cleverbot_enabled).SendAsync(); + await Response().Confirm(strs.chatbot_enabled).SendAsync(); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/ChatterBot/ChatterbotService.cs b/src/NadekoBot/Modules/Games/ChatterBot/ChatterBotService.cs similarity index 59% rename from src/NadekoBot/Modules/Games/ChatterBot/ChatterbotService.cs rename to src/NadekoBot/Modules/Games/ChatterBot/ChatterBotService.cs index 1d1d79bca..23fa4da4d 100644 --- a/src/NadekoBot/Modules/Games/ChatterBot/ChatterbotService.cs +++ b/src/NadekoBot/Modules/Games/ChatterBot/ChatterBotService.cs @@ -15,43 +15,32 @@ public class ChatterBotService : IExecOnMessage public int Priority => 1; - private readonly FeatureLimitKey _flKey; - private readonly DiscordSocketClient _client; private readonly IPermissionChecker _perms; - private readonly CommandHandler _cmd; private readonly IBotCredentials _creds; private readonly IHttpClientFactory _httpFactory; - private readonly IPatronageService _ps; private readonly GamesConfigService _gcs; private readonly IMessageSenderService _sender; + public readonly IPatronageService _ps; public ChatterBotService( DiscordSocketClient client, IPermissionChecker perms, IBot bot, - CommandHandler cmd, + IPatronageService ps, IHttpClientFactory factory, IBotCredentials creds, - IPatronageService ps, GamesConfigService gcs, IMessageSenderService sender) { _client = client; _perms = perms; - _cmd = cmd; _creds = creds; _sender = sender; _httpFactory = factory; - _ps = ps; _perms = perms; _gcs = gcs; - - _flKey = new FeatureLimitKey() - { - Key = CleverBotResponseStr.CLEVERBOT_RESPONSE, - PrettyName = "Cleverbot Replies" - }; + _ps = ps; ChatterBotGuilds = new(bot.AllGuildConfigs .Where(gc => gc.CleverbotEnabled) @@ -69,9 +58,9 @@ public class ChatterBotService : IExecOnMessage Log.Information("Cleverbot will not work as the api key is missing"); return null; - case ChatBotImplementation.Gpt3: + case ChatBotImplementation.Gpt: if (!string.IsNullOrWhiteSpace(_creds.Gpt3ApiKey)) - return new OfficialGpt3Session(_creds.Gpt3ApiKey, + return new OfficialGptSession(_creds.Gpt3ApiKey, _gcs.Data.ChatGpt.ModelName, _gcs.Data.ChatGpt.ChatHistory, _gcs.Data.ChatGpt.MaxTokens, @@ -87,19 +76,18 @@ public class ChatterBotService : IExecOnMessage } } - public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot) + public IChatterBotSession GetOrCreateSession(ulong guildId) { - var channel = msg.Channel as ITextChannel; - cleverbot = null; + if (ChatterBotGuilds.TryGetValue(guildId, out var lazyChatBot)) + return lazyChatBot.Value; - if (channel is null) - return null; - - if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyCleverbot)) - return null; - - cleverbot = lazyCleverbot.Value; + lazyChatBot = new(() => CreateSession(), true); + ChatterBotGuilds.TryAdd(guildId, lazyChatBot); + return lazyChatBot.Value; + } + public string PrepareMessage(IUserMessage msg) + { var nadekoId = _client.CurrentUser.Id; var normalMention = $"<@{nadekoId}> "; var nickMention = $"<@!{nadekoId}> "; @@ -119,13 +107,31 @@ public class ChatterBotService : IExecOnMessage if (guild is not SocketGuild sg) return false; + var channel = usrMsg.Channel as ITextChannel; + if (channel is null) + return false; + + if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyChatBot)) + return false; + + var chatBot = lazyChatBot.Value; + var message = PrepareMessage(usrMsg); + if (message is null) + return false; + + return await RunChatterBot(sg, usrMsg, channel, chatBot, message); + } + + public async Task RunChatterBot( + SocketGuild guild, + IUserMessage usrMsg, + ITextChannel channel, + IChatterBotSession chatBot, + string message) + { try { - var message = PrepareMessage(usrMsg, out var cbs); - if (message is null || cbs is null) - return false; - - var res = await _perms.CheckPermsAsync(sg, + var res = await _perms.CheckPermsAsync(guild, usrMsg.Channel, usrMsg.Author, CleverBotResponseStr.CLEVERBOT_RESPONSE, @@ -134,59 +140,33 @@ public class ChatterBotService : IExecOnMessage if (!res.IsAllowed) return false; - var channel = (ITextChannel)usrMsg.Channel; - var conf = _ps.GetConfig(); - if (!_creds.IsOwner(sg.OwnerId) && conf.IsEnabled) + if (!await _ps.LimitHitAsync(LimitedFeatureName.ChatBot, usrMsg.Author.Id, 2048 / 2)) { - var quota = await _ps.TryGetFeatureLimitAsync(_flKey, sg.OwnerId, 0); - - uint? daily = quota.Quota is int dVal and < 0 - ? (uint)-dVal - : null; - - uint? monthly = quota.Quota is int mVal and >= 0 - ? (uint)mVal - : null; - - var maybeLimit = await _ps.TryIncrementQuotaCounterAsync(sg.OwnerId, - sg.OwnerId == usrMsg.Author.Id, - FeatureType.Limit, - _flKey.Key, - null, - daily, - monthly); - - if (maybeLimit.TryPickT1(out var ql, out var counters)) - { - if (ql.Quota == 0) - { - await _sender.Response(channel) - .Error(null, - text: - "In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/nadekobot) on patreon.", - footer: - "You may disable the cleverbot feature, and this message via '.cleverbot' command") - .SendAsync(); - - return true; - } - - await _sender.Response(channel) - .Error( - null!, - $"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.", - footer: "You may wait for the quota reset or .") - .SendAsync(); - - return true; - } + // limit exceeded + return false; } _ = channel.TriggerTypingAsync(); - var response = await cbs.Think(message, usrMsg.Author.ToString()); - await _sender.Response(channel) - .Confirm(response) - .SendAsync(); + var response = await chatBot.Think(message, usrMsg.Author.ToString()); + + if (response.TryPickT0(out var result, out var error)) + { + // calculate the diff in case we overestimated user's usage + var inTokens = (result.TokensIn - 2048) / 2; + + // add the output tokens to the limit + await _ps.LimitForceHit(LimitedFeatureName.ChatBot, + usrMsg.Author.Id, + (inTokens) + (result.TokensOut / 2 * 3)); + + await _sender.Response(channel) + .Confirm(result.Text) + .SendAsync(); + } + else + { + Log.Warning("Error in chatterbot: {Error}", error); + } Log.Information(""" CleverBot Executed diff --git a/src/NadekoBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs b/src/NadekoBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs index 80c24c1d3..297e1ec9e 100644 --- a/src/NadekoBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs +++ b/src/NadekoBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs @@ -3,10 +3,25 @@ using System.Text.Json.Serialization; namespace NadekoBot.Modules.Games.Common.ChatterBot; -public class Gpt3Response +public class OpenAiCompletionResponse { [JsonPropertyName("choices")] public Choice[] Choices { get; set; } + + [JsonPropertyName("usage")] + public OpenAiUsageData Usage { get; set; } +} + +public class OpenAiUsageData +{ + [JsonPropertyName("prompt_tokens")] + public int PromptTokens { get; set; } + + [JsonPropertyName("completion_tokens")] + public int CompletionTokens { get; set; } + + [JsonPropertyName("total_tokens")] + public int TotalTokens { get; set; } } public class Choice diff --git a/src/NadekoBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs b/src/NadekoBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs index 15a93406d..e75c27dd8 100644 --- a/src/NadekoBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs +++ b/src/NadekoBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs @@ -1,7 +1,10 @@ #nullable disable +using OneOf; +using OneOf.Types; + namespace NadekoBot.Modules.Games.Common.ChatterBot; public interface IChatterBotSession { - Task Think(string input, string username); + Task>> Think(string input, string username); } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs b/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs index 71979d2f0..850bb69c2 100644 --- a/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs +++ b/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs @@ -1,5 +1,7 @@ #nullable disable using Newtonsoft.Json; +using OneOf; +using OneOf.Types; namespace NadekoBot.Modules.Games.Common.ChatterBot; @@ -18,7 +20,7 @@ public class OfficialCleverbotSession : IChatterBotSession _httpFactory = factory; } - public async Task Think(string input, string username) + public async Task>> Think(string input, string username) { using var http = _httpFactory.CreateClient(); var dataString = await http.GetStringAsync(string.Format(QueryString, input, cs ?? "")); @@ -27,12 +29,17 @@ public class OfficialCleverbotSession : IChatterBotSession var data = JsonConvert.DeserializeObject(dataString); cs = data?.Cs; - return data?.Output; + return new ThinkResult + { + Text = data?.Output, + TokensIn = 2, + TokensOut = 1 + }; } catch { - Log.Warning("Unexpected cleverbot response received: {ResponseString}", dataString); - return null; + Log.Warning("Unexpected response from CleverBot: {ResponseString}", dataString); + return new Error("Unexpected CleverBot response received"); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs b/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs deleted file mode 100644 index 75f4d3d3d..000000000 --- a/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs +++ /dev/null @@ -1,105 +0,0 @@ -#nullable disable -using Newtonsoft.Json; -using System.Net.Http.Json; -using SharpToken; - -namespace NadekoBot.Modules.Games.Common.ChatterBot; - -public class OfficialGpt3Session : IChatterBotSession -{ - private string Uri - => $"https://api.openai.com/v1/chat/completions"; - - private readonly string _apiKey; - private readonly string _model; - private readonly int _maxHistory; - private readonly int _maxTokens; - private readonly int _minTokens; - private readonly string _nadekoUsername; - private readonly GptEncoding _encoding; - private List messages = new(); - private readonly IHttpClientFactory _httpFactory; - - - - public OfficialGpt3Session( - string apiKey, - ChatGptModel model, - int chatHistory, - int maxTokens, - int minTokens, - string personality, - string nadekoUsername, - IHttpClientFactory factory) - { - _apiKey = apiKey; - _httpFactory = factory; - switch (model) - { - case ChatGptModel.Gpt35Turbo: - _model = "gpt-3.5-turbo"; - break; - case ChatGptModel.Gpt4: - _model = "gpt-4"; - break; - case ChatGptModel.Gpt432k: - _model = "gpt-4-32k"; - break; - } - _maxHistory = chatHistory; - _maxTokens = maxTokens; - _minTokens = minTokens; - _nadekoUsername = nadekoUsername; - _encoding = GptEncoding.GetEncodingForModel(_model); - messages.Add(new GPTMessage(){Role = "user", Content = personality, Name = _nadekoUsername}); - } - - public async Task Think(string input, string username) - { - messages.Add(new GPTMessage(){Role = "user", Content = input, Name = username}); - while(messages.Count > _maxHistory + 2){ - messages.RemoveAt(1); - } - int tokensUsed = 0; - foreach(GPTMessage message in messages){ - tokensUsed += _encoding.Encode(message.Content).Count; - } - tokensUsed *= 2; //Unsure why this is the case, but the token count chatgpt reports back is double what I calculate. - //check if we have the minimum number of tokens available to use. Remove messages until we have enough, otherwise exit out and inform the user why. - while(_maxTokens - tokensUsed <= _minTokens){ - if(messages.Count > 2){ - int tokens = _encoding.Encode(messages[1].Content).Count * 2; - tokensUsed -= tokens; - messages.RemoveAt(1); - } - else{ - return "Token count exceeded, please increase the number of tokens in the bot config and restart."; - } - } - using var http = _httpFactory.CreateClient(); - http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey); - var data = await http.PostAsJsonAsync(Uri, new Gpt3ApiRequest() - { - Model = _model, - Messages = messages, - MaxTokens = _maxTokens - tokensUsed, - Temperature = 1, - }); - var dataString = await data.Content.ReadAsStringAsync(); - try - { - var response = JsonConvert.DeserializeObject(dataString); - string message = response?.Choices[0]?.Message?.Content; - //Can't rely on the return to except, now that we need to add it to the messages list. - _ = message ?? throw new ArgumentNullException(nameof(message)); - messages.Add(new GPTMessage(){Role = "assistant", Content = message, Name = _nadekoUsername}); - return message; - } - catch - { - Log.Warning("Unexpected GPT-3 response received: {ResponseString}", dataString); - return null; - } - } -} - diff --git a/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs b/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs new file mode 100644 index 000000000..ece06a700 --- /dev/null +++ b/src/NadekoBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs @@ -0,0 +1,141 @@ +#nullable disable +using Newtonsoft.Json; +using OneOf.Types; +using System.Net.Http.Json; +using SharpToken; + +namespace NadekoBot.Modules.Games.Common.ChatterBot; + +public class OfficialGptSession : IChatterBotSession +{ + private string Uri + => $"https://api.openai.com/v1/chat/completions"; + + private readonly string _apiKey; + private readonly string _model; + private readonly int _maxHistory; + private readonly int _maxTokens; + private readonly int _minTokens; + private readonly string _nadekoUsername; + private readonly GptEncoding _encoding; + private List messages = new(); + private readonly IHttpClientFactory _httpFactory; + + + public OfficialGptSession( + string apiKey, + ChatGptModel model, + int chatHistory, + int maxTokens, + int minTokens, + string personality, + string nadekoUsername, + IHttpClientFactory factory) + { + _apiKey = apiKey; + _httpFactory = factory; + + _model = model switch + { + ChatGptModel.Gpt35Turbo => "gpt-3.5-turbo", + ChatGptModel.Gpt4o => "gpt-4o", + _ => throw new ArgumentException("Unknown, unsupported or obsolete model", nameof(model)) + }; + + _maxHistory = chatHistory; + _maxTokens = maxTokens; + _minTokens = minTokens; + _nadekoUsername = nadekoUsername; + _encoding = GptEncoding.GetEncodingForModel(_model); + messages.Add(new() + { + Role = "system", + Content = personality, + Name = _nadekoUsername + }); + } + + public async Task>> Think(string input, string username) + { + messages.Add(new() + { + Role = "user", + Content = input, + Name = username + }); + while (messages.Count > _maxHistory + 2) + { + messages.RemoveAt(1); + } + + var tokensUsed = messages.Sum(message => _encoding.Encode(message.Content).Count); + + tokensUsed *= 2; + + //check if we have the minimum number of tokens available to use. Remove messages until we have enough, otherwise exit out and inform the user why. + while (_maxTokens - tokensUsed <= _minTokens) + { + if (messages.Count > 2) + { + var tokens = _encoding.Encode(messages[1].Content).Count * 2; + tokensUsed -= tokens; + messages.RemoveAt(1); + } + else + { + return new Error("Token count exceeded, please increase the number of tokens in the bot config and restart."); + } + } + + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey); + + var data = await http.PostAsJsonAsync(Uri, + new Gpt3ApiRequest() + { + Model = _model, + Messages = messages, + MaxTokens = _maxTokens - tokensUsed, + Temperature = 1, + }); + + var dataString = await data.Content.ReadAsStringAsync(); + try + { + var response = JsonConvert.DeserializeObject(dataString); + var res = response?.Choices?[0]; + var message = res?.Message?.Content; + + if (message is null) + { + return new Error("ChatGpt: Received no response."); + } + + messages.Add(new() + { + Role = "assistant", + Content = message, + Name = _nadekoUsername + }); + + return new ThinkResult() + { + Text = message, + TokensIn = response.Usage.PromptTokens, + TokensOut = response.Usage.CompletionTokens + }; + } + catch + { + Log.Warning("Unexpected response received from OpenAI: {ResponseString}", dataString); + return new Error("Unexpected response received"); + } + } +} + +public sealed class ThinkResult +{ + public string Text { get; set; } + public int TokensIn { get; set; } + public int TokensOut { get; set; } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/GamesConfig.cs b/src/NadekoBot/Modules/Games/GamesConfig.cs index 7996a3f9b..7fbcb4fbf 100644 --- a/src/NadekoBot/Modules/Games/GamesConfig.cs +++ b/src/NadekoBot/Modules/Games/GamesConfig.cs @@ -8,7 +8,7 @@ namespace NadekoBot.Modules.Games.Common; public sealed partial class GamesConfig : ICloneable { [Comment("DO NOT CHANGE")] - public int Version { get; set; } = 3; + public int Version { get; set; } = 4; [Comment("Hangman related settings (.hangman command)")] public HangmanConfig Hangman { get; set; } = new() @@ -105,8 +105,8 @@ public sealed partial class GamesConfig : ICloneable [Comment(@"Which chatbot API should bot use. 'cleverbot' - bot will use Cleverbot API. -'gpt3' - bot will use GPT-3 API")] - public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt3; +'gpt' - bot will use GPT API")] + public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt; public ChatGptConfig ChatGpt { get; set; } = new(); } @@ -114,10 +114,10 @@ public sealed partial class GamesConfig : ICloneable [Cloneable] public sealed partial class ChatGptConfig { - [Comment(@"Which GPT-3 Model should bot use. + [Comment(@"Which GPT Model should bot use. gpt35turbo - cheapest - gpt4 - 30x more expensive, higher quality - gp432k - same model as above, but with a 32k token limit")] + gpt4o - more expensive, higher quality +")] public ChatGptModel ModelName { get; set; } = ChatGptModel.Gpt35Turbo; [Comment(@"How should the chat bot behave, what's its personality? (Usage of this counts towards the max tokens)")] @@ -126,10 +126,10 @@ public sealed partial class ChatGptConfig [Comment(@"The maximum number of messages in a conversation that can be remembered. (This will increase the number of tokens used)")] public int ChatHistory { get; set; } = 5; - [Comment(@"The maximum number of tokens to use per GPT-3 API call")] + [Comment(@"The maximum number of tokens to use per GPT API call")] public int MaxTokens { get; set; } = 100; - [Comment(@"The minimum number of tokens to use per GPT-3 API call, such that chat history is removed to make room.")] + [Comment(@"The minimum number of tokens to use per GPT API call, such that chat history is removed to make room.")] public int MinTokens { get; set; } = 30; } @@ -163,12 +163,18 @@ public sealed partial class RaceAnimal public enum ChatBotImplementation { Cleverbot, - Gpt3 + Gpt = 1, + [Obsolete] + Gpt3 = 1, } public enum ChatGptModel { - Gpt35Turbo, + [Obsolete] Gpt4, - Gpt432k + [Obsolete] + Gpt432k, + + Gpt35Turbo, + Gpt4o, } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/GamesConfigService.cs b/src/NadekoBot/Modules/Games/GamesConfigService.cs index 4f08b6106..92897591e 100644 --- a/src/NadekoBot/Modules/Games/GamesConfigService.cs +++ b/src/NadekoBot/Modules/Games/GamesConfigService.cs @@ -73,15 +73,6 @@ public sealed class GamesConfigService : ConfigServiceBase }); } - if (data.Version < 2) - { - ModifyConfig(c => - { - c.Version = 2; - c.ChatBot = ChatBotImplementation.Cleverbot; - }); - } - if (data.Version < 3) { ModifyConfig(c => @@ -90,5 +81,19 @@ public sealed class GamesConfigService : ConfigServiceBase c.ChatGpt.ModelName = ChatGptModel.Gpt35Turbo; }); } + + if (data.Version < 4) + { + ModifyConfig(c => + { + c.Version = 4; +#pragma warning disable CS0612 // Type or member is obsolete + c.ChatGpt.ModelName = + c.ChatGpt.ModelName == ChatGptModel.Gpt4 || c.ChatGpt.ModelName == ChatGptModel.Gpt432k + ? ChatGptModel.Gpt4o + : c.ChatGpt.ModelName; +#pragma warning restore CS0612 // Type or member is obsolete + }); + } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index be182bca0..2a1f8d467 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -1,6 +1,7 @@ #nullable disable using NadekoBot.Modules.Music.Services; using NadekoBot.Db.Models; +using NadekoBot.Modules.Utility; namespace NadekoBot.Modules.Music; diff --git a/src/NadekoBot/Modules/Music/Services/MusicService.cs b/src/NadekoBot/Modules/Music/Services/MusicService.cs index 070636039..73c813664 100644 --- a/src/NadekoBot/Modules/Music/Services/MusicService.cs +++ b/src/NadekoBot/Modules/Music/Services/MusicService.cs @@ -212,7 +212,7 @@ public sealed class MusicService : IMusicService, IPlaceholderProvider if (settings.AutoDisconnect) return LeaveVoiceChannelAsync(guildId); } - + return Task.CompletedTask; }; diff --git a/src/NadekoBot/Modules/Patronage/Config/PatronageConfig.cs b/src/NadekoBot/Modules/Patronage/Config/PatronageConfig.cs index e4c9339b4..9fb968ffa 100644 --- a/src/NadekoBot/Modules/Patronage/Config/PatronageConfig.cs +++ b/src/NadekoBot/Modules/Patronage/Config/PatronageConfig.cs @@ -32,5 +32,14 @@ public class PatronageConfig : ConfigServiceBase c.IsEnabled = false; } }); + + + ModifyConfig(c => + { + if (c.Version == 2) + { + c.Version = 3; + } + }); } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Patronage/InsufficientTier.cs b/src/NadekoBot/Modules/Patronage/InsufficientTier.cs deleted file mode 100644 index 3bd213498..000000000 --- a/src/NadekoBot/Modules/Patronage/InsufficientTier.cs +++ /dev/null @@ -1,11 +0,0 @@ -using NadekoBot.Db.Models; - -namespace NadekoBot.Modules.Patronage; - -public readonly struct InsufficientTier -{ - public FeatureType FeatureType { get; init; } - public string Feature { get; init; } - public PatronTier RequiredTier { get; init; } - public PatronTier UserTier { get; init; } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Patronage/Patreon/PatreonMemberData.cs b/src/NadekoBot/Modules/Patronage/Patreon/PatreonMemberData.cs index 6a5035f2a..eb2235328 100644 --- a/src/NadekoBot/Modules/Patronage/Patreon/PatreonMemberData.cs +++ b/src/NadekoBot/Modules/Patronage/Patreon/PatreonMemberData.cs @@ -25,9 +25,4 @@ public sealed class PatreonMemberData : ISubscriberData "Declined" or "Pending" => SubscriptionChargeStatus.Unpaid, _ => SubscriptionChargeStatus.Other, }; -} - -public sealed class PatreonPledgeData -{ - } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Patronage/PatronageCommands.cs b/src/NadekoBot/Modules/Patronage/PatronageCommands.cs index 3b63e3a8f..43cbb17cd 100644 --- a/src/NadekoBot/Modules/Patronage/PatronageCommands.cs +++ b/src/NadekoBot/Modules/Patronage/PatronageCommands.cs @@ -71,17 +71,16 @@ public partial class Help return; } - var patron = await _service.GetPatronAsync(user.Id); - var quotaStats = await _service.GetUserQuotaStatistic(user.Id); + var maybePatron = await _service.GetPatronAsync(user.Id); + + var quotaStats = await _service.LimitStats(user.Id); var eb = _sender.CreateEmbed() .WithAuthor(user) .WithTitle(GetText(strs.patron_info)) .WithOkColor(); - if (quotaStats.Commands.Count == 0 - && quotaStats.Groups.Count == 0 - && quotaStats.Modules.Count == 0) + if (quotaStats.Count == 0 || maybePatron is not { } patron) { eb.WithDescription(GetText(strs.no_quota_found)); } @@ -97,26 +96,9 @@ public partial class Help eb.AddField(GetText(strs.quotas), "⁣", false); - if (quotaStats.Commands.Count > 0) - { - var text = GetQuotaList(quotaStats.Commands); - if (!string.IsNullOrWhiteSpace(text)) - eb.AddField(GetText(strs.commands), text, true); - } - - if (quotaStats.Groups.Count > 0) - { - var text = GetQuotaList(quotaStats.Groups); - if (!string.IsNullOrWhiteSpace(text)) - eb.AddField(GetText(strs.groups), text, true); - } - - if (quotaStats.Modules.Count > 0) - { - var text = GetQuotaList(quotaStats.Modules); - if (!string.IsNullOrWhiteSpace(text)) - eb.AddField(GetText(strs.modules), text, true); - } + var text = GetQuotaList(quotaStats); + if (!string.IsNullOrWhiteSpace(text)) + eb.AddField(GetText(strs.modules), text, true); } @@ -131,26 +113,28 @@ public partial class Help } } - private string GetQuotaList(IReadOnlyDictionary featureQuotaStats) + private string GetQuotaList( + IReadOnlyDictionary featureQuotaStats) { var text = string.Empty; - foreach (var (key, q) in featureQuotaStats) + foreach (var (key, (cur, quota)) in featureQuotaStats) { text += $"\n⁣\t`{key}`\n"; - if (q.Hourly != default) - text += $"⁣ ⁣ {GetEmoji(q.Hourly)} {q.Hourly.Cur}/{q.Hourly.Max} per hour\n"; - if (q.Daily != default) - text += $"⁣ ⁣ {GetEmoji(q.Daily)} {q.Daily.Cur}/{q.Daily.Max} per day\n"; - if (q.Monthly != default) - text += $"⁣ ⁣ {GetEmoji(q.Monthly)} {q.Monthly.Cur}/{q.Monthly.Max} per month\n"; + if (quota.QuotaPeriod == QuotaPer.PerHour) + text += $"⁣ ⁣ {cur}/{(quota.Quota == -1 ? "∞" : quota.Quota)} {QuotaPeriodToString(quota.QuotaPeriod)}\n"; } return text; } - private string GetEmoji((uint Cur, uint Max) limit) - => limit.Cur < limit.Max - ? "✅" - : "⚠️"; + public string QuotaPeriodToString(QuotaPer per) + => per switch + { + QuotaPer.PerHour => "per hour", + QuotaPer.PerDay => "per day", + QuotaPer.PerMonth => "per month", + QuotaPer.Total => "total", + _ => throw new ArgumentOutOfRangeException(nameof(per), per, null) + }; } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Patronage/PatronageService.cs b/src/NadekoBot/Modules/Patronage/PatronageService.cs index 98b72d538..54c427d1e 100644 --- a/src/NadekoBot/Modules/Patronage/PatronageService.cs +++ b/src/NadekoBot/Modules/Patronage/PatronageService.cs @@ -2,9 +2,8 @@ using LinqToDB.EntityFrameworkCore; using NadekoBot.Common.ModuleBehaviors; using NadekoBot.Db.Models; -using OneOf; -using OneOf.Types; -using CommandInfo = Discord.Commands.CommandInfo; +using StackExchange.Redis; +using System.Diagnostics; namespace NadekoBot.Modules.Patronage; @@ -12,7 +11,6 @@ namespace NadekoBot.Modules.Patronage; public sealed class PatronageService : IPatronageService, IReadyExecutor, - IExecPreCommand, INService { public event Func OnNewPatronPayment = static delegate { return Task.CompletedTask; }; @@ -60,7 +58,7 @@ public sealed class PatronageService if (_client.ShardId != 0) return Task.CompletedTask; - return Task.WhenAll(ResetLoopAsync(), LoadSubscribersLoopAsync()); + return Task.WhenAll(LoadSubscribersLoopAsync()); } private async Task LoadSubscribersLoopAsync() @@ -85,71 +83,6 @@ public sealed class PatronageService } } - public async Task ResetLoopAsync() - { - await Task.Delay(1.Minutes()); - while (true) - { - try - { - if (!_pConf.Data.IsEnabled) - { - await Task.Delay(1.Minutes()); - continue; - } - - var now = DateTime.UtcNow; - var lastRun = DateTime.MinValue; - - var result = await _cache.GetAsync(_quotaKey); - if (result.TryGetValue(out var lastVal) && lastVal != default) - { - lastRun = DateTime.FromBinary(lastVal); - } - - var nowDate = now.ToDateOnly(); - var lastDate = lastRun.ToDateOnly(); - - await using var ctx = _db.GetDbContext(); - - if ((lastDate.Day == 1 || (lastDate.Month != nowDate.Month)) && nowDate.Day > 1) - { - // assumes bot won't be offline for a year - await ctx.GetTable() - .TruncateAsync(); - } - else if (nowDate.DayNumber != lastDate.DayNumber) - { - // day is different, means hour is different. - // reset both hourly and daily quota counts. - await ctx.GetTable() - .UpdateAsync((old) => new() - { - HourlyCount = 0, - DailyCount = 0, - }); - } - else if (now.Hour != lastRun.Hour) // if it's not, just reset hourly quotas - { - await ctx.GetTable() - .UpdateAsync((old) => new() - { - HourlyCount = 0 - }); - } - - // assumes that the code above runs in less than an hour - await _cache.AddAsync(_quotaKey, now.ToBinary()); - } - catch (Exception ex) - { - Log.Error(ex, "Error in quota reset loop. Message: {ErrorMessage}", ex.Message); - } - - await Task.Delay(TimeSpan.FromHours(1).Add(TimeSpan.FromMinutes(1))); - } - } - private async Task ProcesssPatronsAsync(IReadOnlyCollection subscribersEnum) { // process only users who have discord accounts connected @@ -284,313 +217,7 @@ public sealed class PatronageService } } - public async Task ExecPreCommandAsync( - ICommandContext ctx, - string moduleName, - CommandInfo command) - { - var ownerId = ctx.Guild?.OwnerId ?? 0; - - var result = await AttemptRunCommand( - ctx.User.Id, - ownerId: ownerId, - command.Aliases.First().ToLowerInvariant(), - command.Module.Parent == null ? string.Empty : command.Module.GetGroupName().ToLowerInvariant(), - moduleName.ToLowerInvariant() - ); - - return result.Match( - _ => false, - ins => - { - var eb = _sender.CreateEmbed() - .WithPendingColor() - .WithTitle("Insufficient Patron Tier") - .AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true) - .AddField("Required Tier", - $"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/nadekobot)", - true); - - if (ctx.Guild is null || ctx.Guild?.OwnerId == ctx.User.Id) - eb.WithDescription("You don't have the sufficent Patron Tier to run this command.") - .WithFooter("You can use '.patron' and '.donate' commands for more info"); - else - eb.WithDescription( - "Neither you nor the server owner have the sufficent Patron Tier to run this command.") - .WithFooter("You can use '.patron' and '.donate' commands for more info"); - - _ = ctx.WarningAsync(); - - if (ctx.Guild?.OwnerId == ctx.User.Id) - _ = _sender.Response(ctx) - .Context(ctx) - .Embed(eb) - .SendAsync(); - else - _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync(); - - return true; - }, - quota => - { - var eb = _sender.CreateEmbed() - .WithPendingColor() - .WithTitle("Quota Limit Reached"); - - if (quota.IsOwnQuota || ctx.User.Id == ownerId) - { - eb.WithDescription($"You've reached your quota of `{quota.Quota} {quota.QuotaPeriod.ToFullName()}`") - .WithFooter("You may want to check your quota by using the '.patron' command."); - } - else - { - eb.WithDescription( - $"This server reached the quota of {quota.Quota} `{quota.QuotaPeriod.ToFullName()}`") - .WithFooter("You may contact the server owner about this issue.\n" - + "Alternatively, you can become patron yourself by using the '.donate' command.\n" - + "If you're already a patron, it means you've reached your quota.\n" - + "You can use '.patron' command to check your quota status."); - } - - eb.AddField("For", $"{quota.FeatureType}: `{quota.Feature}`", true) - .AddField("Resets At", quota.ResetsAt.ToShortAndRelativeTimestampTag(), true); - - _ = ctx.WarningAsync(); - - // send the message in the server in case it's the owner - if (ctx.Guild?.OwnerId == ctx.User.Id) - _ = _sender.Response(ctx) - .Embed(eb) - .SendAsync(); - else - _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync(); - - return true; - }); - } - - private async ValueTask> AttemptRunCommand( - ulong userId, - ulong ownerId, - string commandName, - string groupName, - string moduleName) - { - // try to run as a user - var res = await AttemptRunCommand(userId, commandName, groupName, moduleName, true); - - // if it fails, try to run as an owner - // but only if the command is ran in a server - // and if the owner is not the user - if (!res.IsT0 && ownerId != 0 && ownerId != userId) - res = await AttemptRunCommand(ownerId, commandName, groupName, moduleName, false); - - return res; - } - - /// - /// Returns either the current usage counter if limit wasn't reached, or QuotaLimit if it is. - /// - public async ValueTask> TryIncrementQuotaCounterAsync( - ulong userId, - bool isSelf, - FeatureType featureType, - string featureName, - uint? maybeHourly, - uint? maybeDaily, - uint? maybeMonthly) - { - await using var ctx = _db.GetDbContext(); - - var now = DateTime.UtcNow; - await using var tran = await ctx.Database.BeginTransactionAsync(); - - var userQuotaData = await ctx.GetTable() - .FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId - && x.Feature == featureName) - ?? new PatronQuota(); - - // if hourly exists, if daily exists, etc... - if (maybeHourly is uint hourly && userQuotaData.HourlyCount >= hourly) - { - return new QuotaLimit() - { - QuotaPeriod = QuotaPer.PerHour, - Quota = hourly, - // quite a neat trick. https://stackoverflow.com/a/5733560 - ResetsAt = now.Date.AddHours(now.Hour + 1), - Feature = featureName, - FeatureType = featureType, - IsOwnQuota = isSelf - }; - } - - if (maybeDaily is uint daily - && userQuotaData.DailyCount >= daily) - { - return new QuotaLimit() - { - QuotaPeriod = QuotaPer.PerDay, - Quota = daily, - ResetsAt = now.Date.AddDays(1), - Feature = featureName, - FeatureType = featureType, - IsOwnQuota = isSelf - }; - } - - if (maybeMonthly is uint monthly && userQuotaData.MonthlyCount >= monthly) - { - return new QuotaLimit() - { - QuotaPeriod = QuotaPer.PerMonth, - Quota = monthly, - ResetsAt = now.Date.SecondOfNextMonth(), - Feature = featureName, - FeatureType = featureType, - IsOwnQuota = isSelf - }; - } - - await ctx.GetTable() - .InsertOrUpdateAsync(() => new() - { - UserId = userId, - FeatureType = featureType, - Feature = featureName, - DailyCount = 1, - MonthlyCount = 1, - HourlyCount = 1, - }, - (old) => new() - { - HourlyCount = old.HourlyCount + 1, - DailyCount = old.DailyCount + 1, - MonthlyCount = old.MonthlyCount + 1, - }, - () => new() - { - UserId = userId, - FeatureType = featureType, - Feature = featureName, - }); - - await tran.CommitAsync(); - - return (userQuotaData.HourlyCount + 1, userQuotaData.DailyCount + 1, userQuotaData.MonthlyCount + 1); - } - - /// - /// Attempts to add 1 to user's quota for the command, group and module. - /// Input MUST BE lowercase - /// - /// Id of the user who is attempting to run the command - /// Name of the command the user is trying to run - /// Name of the command's group - /// Name of the command's top level module - /// Whether this is check is for the user himself. False if it's someone else's id (owner) - /// Either a succcess (user can run the command) or one of the error values. - private async ValueTask> AttemptRunCommand( - ulong userId, - string commandName, - string groupName, - string moduleName, - bool isSelf) - { - var confData = _pConf.Data; - - if (!confData.IsEnabled) - return default; - - if (_creds.GetCreds().IsOwner(userId)) - return default; - - // get user tier - var patron = await GetPatronAsync(userId); - FeatureType quotaForFeatureType; - - if (confData.Quotas.Commands.TryGetValue(commandName, out var quotaData)) - { - quotaForFeatureType = FeatureType.Command; - } - else if (confData.Quotas.Groups.TryGetValue(groupName, out quotaData)) - { - quotaForFeatureType = FeatureType.Group; - } - else if (confData.Quotas.Modules.TryGetValue(moduleName, out quotaData)) - { - quotaForFeatureType = FeatureType.Module; - } - else - { - return default; - } - - var featureName = quotaForFeatureType switch - { - FeatureType.Command => commandName, - FeatureType.Group => groupName, - FeatureType.Module => moduleName, - _ => throw new ArgumentOutOfRangeException(nameof(quotaForFeatureType)) - }; - - if (!TryGetTierDataOrLower(quotaData, patron.Tier, out var data)) - { - return new InsufficientTier() - { - Feature = featureName, - FeatureType = quotaForFeatureType, - RequiredTier = quotaData.Count == 0 - ? PatronTier.ComingSoon - : quotaData.Keys.First(), - UserTier = patron.Tier, - }; - } - - // no quota limits for this tier - if (data is null) - return default; - - var quotaCheckResult = await TryIncrementQuotaCounterAsync(userId, - isSelf, - quotaForFeatureType, - featureName, - data.TryGetValue(QuotaPer.PerHour, out var hourly) ? hourly : null, - data.TryGetValue(QuotaPer.PerDay, out var daily) ? daily : null, - data.TryGetValue(QuotaPer.PerMonth, out var monthly) ? monthly : null - ); - - return quotaCheckResult.Match>( - _ => new Success(), - x => x); - } - - private bool TryGetTierDataOrLower( - IReadOnlyDictionary data, - PatronTier tier, - out T? o) - { - // check for quotas on this tier - if (data.TryGetValue(tier, out o)) - return true; - - // if there are none, get the quota first tier below this one - // which has quotas specified - for (var i = _tiers.Length - 1; i >= 0; i--) - { - var lowerTier = _tiers[i]; - if (lowerTier < tier && data.TryGetValue(lowerTier, out o)) - return true; - } - - // if there are none, that means the feature is intended - // to be patron-only but the quotas haven't been specified yet - // so it will be marked as "Coming Soon" - o = default; - return false; - } - - public async Task GetPatronAsync(ulong userId) + public async Task GetPatronAsync(ulong userId) { await using var ctx = _db.GetDbContext(); @@ -616,128 +243,126 @@ public sealed class PatronageService return PatronUserToPatron(max); } - public async Task GetUserQuotaStatistic(ulong userId) + public async Task LimitHitAsync(LimitedFeatureName key, ulong userId, int amount = 1) { - var pConfData = _pConf.Data; + if (_creds.GetCreds().IsOwner(userId)) + return true; + + if (!_pConf.Data.IsEnabled) + return true; - if (!pConfData.IsEnabled) - return new(); + var userLimit = await GetUserLimit(key, userId); - var patron = await GetPatronAsync(userId); + if (userLimit.Quota == 0) + return false; - await using var ctx = _db.GetDbContext(); - var allPatronQuotas = await ctx.GetTable() - .Where(x => x.UserId == userId) - .ToListAsync(); + if (userLimit.Quota == -1) + return true; - var allQuotasDict = allPatronQuotas - .GroupBy(static x => x.FeatureType) - .ToDictionary(static x => x.Key, static x => x.ToDictionary(static y => y.Feature)); - - allQuotasDict.TryGetValue(FeatureType.Command, out var data); - var userCommandQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Commands); - - allQuotasDict.TryGetValue(FeatureType.Group, out data); - var userGroupQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Groups); - - allQuotasDict.TryGetValue(FeatureType.Module, out data); - var userModuleQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Modules); - - return new UserQuotaStats() - { - Tier = patron.Tier, - Commands = userCommandQuotaStats, - Groups = userGroupQuotaStats, - Modules = userModuleQuotaStats, - }; + return await TryAddLimit(key, userLimit, userId, amount); } - private IReadOnlyDictionary GetFeatureQuotaStats( - PatronTier patronTier, - IReadOnlyDictionary? allQuotasDict, - Dictionary?>> commands) + public async Task LimitForceHit(LimitedFeatureName key, ulong userId, int amount) { - var userCommandQuotaStats = new Dictionary(); - foreach (var (key, quotaData) in commands) + if (_creds.GetCreds().IsOwner(userId)) + return true; + + if (!_pConf.Data.IsEnabled) + return true; + + var userLimit = await GetUserLimit(key, userId); + + var cacheKey = CreateKey(key, userId); + await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit)); + + return await TryAddLimit(key, userLimit, userId, amount); + } + + private async Task TryAddLimit( + LimitedFeatureName key, + QuotaLimit userLimit, + ulong userId, + int amount) + { + var cacheKey = CreateKey(key, userId); + var cur = await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit)); + + if (cur + amount < userLimit.Quota) { - if (TryGetTierDataOrLower(quotaData, patronTier, out var data)) + await _cache.AddAsync(cacheKey, cur + amount); + return true; + } + + return false; + } + + private TimeSpan? GetExpiry(QuotaLimit userLimit) + { + var now = DateTime.UtcNow; + switch (userLimit.QuotaPeriod) + { + case QuotaPer.PerHour: + return TimeSpan.FromMinutes(60 - now.Minute); + case QuotaPer.PerDay: + return TimeSpan.FromMinutes((24 * 60) - ((now.Hour * 60) + now.Minute)); + case QuotaPer.PerMonth: + var firstOfNextMonth = now.FirstOfNextMonth(); + return firstOfNextMonth - now; + default: + return null; + } + } + + private TypedKey CreateKey(LimitedFeatureName key, ulong userId) + => new($"limited_feature:{key}:{userId}"); + + private QuotaLimit _emptyQuota = new QuotaLimit() + { + Quota = 0, + QuotaPeriod = QuotaPer.PerDay, + }; + + public async Task GetUserLimit(LimitedFeatureName name, ulong userId) + { + var maybePatron = await GetPatronAsync(userId); + + if (maybePatron is not { } patron) + return _emptyQuota; + + if (patron.ValidThru < DateTime.UtcNow) + return _emptyQuota; + + foreach (var (key, value) in _pConf.Data.Limits) + { + if (patron.Amount >= key) { - // if data is null that means the quota for the user's tier is unlimited - // no point in returning it? - - if (data is null) - continue; - - var (daily, hourly, monthly) = default((uint, uint, uint)); - // try to get users stats for this feature - // if it fails just leave them at 0 - if (allQuotasDict?.TryGetValue(key, out var quota) ?? false) - (daily, hourly, monthly) = (quota.DailyCount, quota.HourlyCount, quota.MonthlyCount); - - userCommandQuotaStats[key] = new FeatureQuotaStats() + if (value.TryGetValue(name, out var quotaLimit)) { - Hourly = data.TryGetValue(QuotaPer.PerHour, out var hourD) - ? (hourly, hourD) - : default, - Daily = data.TryGetValue(QuotaPer.PerDay, out var maxD) - ? (daily, maxD) - : default, - Monthly = data.TryGetValue(QuotaPer.PerMonth, out var maxM) - ? (monthly, maxM) - : default, - }; + return quotaLimit; + } + + break; } } - return userCommandQuotaStats; + return _emptyQuota; } - public async Task TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue) + public async Task> LimitStats(ulong userId) { - var conf = _pConf.Data; - - // if patron system is disabled, the quota is just default - if (!conf.IsEnabled) - return new() - { - Name = key.PrettyName, - Quota = defaultValue, - IsPatronLimit = false - }; - - - if (!conf.Quotas.Features.TryGetValue(key.Key, out var data)) - return new() - { - Name = key.PrettyName, - Quota = defaultValue, - IsPatronLimit = false, - }; - - var patron = await GetPatronAsync(userId); - if (!TryGetTierDataOrLower(data, patron.Tier, out var limit)) - return new() - { - Name = key.PrettyName, - Quota = 0, - IsPatronLimit = true, - }; - - return new() + var dict = new Dictionary(); + foreach (var featureName in Enum.GetValues()) { - Name = key.PrettyName, - Quota = limit, - IsPatronLimit = true - }; + var cacheKey = CreateKey(featureName, userId); + var userLimit = await GetUserLimit(featureName, userId); + var cur = await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit)); + + dict[featureName] = (cur, userLimit); + } + + return dict; } - // public async Task GiftPatronAsync(IUser user, int amount) - // { - // if (amount < 1) - // throw new ArgumentOutOfRangeException(nameof(amount)); - // - // - // } private Patron PatronUserToPatron(PatronUser user) => new Patron() @@ -767,6 +392,22 @@ public sealed class PatronageService }; } + public int PercentBonus(Patron? maybePatron) + => maybePatron is { } user && user.ValidThru > DateTime.UtcNow + ? PercentBonus(user.Amount) + : 0; + + public int PercentBonus(long amount) + => amount switch + { + >= 10_000 => 100, + >= 5000 => 50, + >= 2000 => 20, + >= 1000 => 10, + >= 500 => 5, + _ => 0 + }; + private async Task SendWelcomeMessage(Patron patron) { try @@ -776,28 +417,28 @@ public sealed class PatronageService return; var eb = _sender.CreateEmbed() - .WithOkColor() - .WithTitle("❤️ Thank you for supporting NadekoBot! ❤️") - .WithDescription( - "Your donation has been processed and you will receive the rewards shortly.\n" - + "You can visit to see rewards for your tier. 🎉") - .AddField("Tier", Format.Bold(patron.Tier.ToString()), true) - .AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true) - .AddField("Expires", - patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), - true) - .AddField("Instructions", - """ - *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.* - *- You can check your benefits on * - *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands* - *- **ALL** of the servers that you **own** will enjoy your Patron benefits.* - *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)* - *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.* - *- Permission guide can be found here if you're not familiar with it: * - """, - inline: false) - .WithFooter($"platform id: {patron.UniquePlatformUserId}"); + .WithOkColor() + .WithTitle("❤️ Thank you for supporting NadekoBot! ❤️") + .WithDescription( + "Your donation has been processed and you will receive the rewards shortly.\n" + + "You can visit to see rewards for your tier. 🎉") + .AddField("Tier", Format.Bold(patron.Tier.ToString()), true) + .AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true) + .AddField("Expires", + patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), + true) + .AddField("Instructions", + """ + *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.* + *- You can check your benefits on * + *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands* + *- **ALL** of the servers that you **own** will enjoy your Patron benefits.* + *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)* + *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.* + *- Permission guide can be found here if you're not familiar with it: * + """, + inline: false) + .WithFooter($"platform id: {patron.UniquePlatformUserId}"); await _sender.Response(user).Embed(eb).SendAsync(); } diff --git a/src/NadekoBot/Modules/Searches/Crypto/DefaultStockDataService.cs b/src/NadekoBot/Modules/Searches/Crypto/DefaultStockDataService.cs index 6c13bf927..779a5a10c 100644 --- a/src/NadekoBot/Modules/Searches/Crypto/DefaultStockDataService.cs +++ b/src/NadekoBot/Modules/Searches/Crypto/DefaultStockDataService.cs @@ -1,6 +1,7 @@ using AngleSharp; using CsvHelper; using CsvHelper.Configuration; +using System.Diagnostics; using System.Globalization; using System.Text.Json; @@ -22,46 +23,32 @@ public sealed class DefaultStockDataService : IStockDataService, INService using var http = _httpClientFactory.CreateClient(); - - var quoteHtmlPage = $"https://finance.yahoo.com/quote/{query.ToUpperInvariant()}"; var config = Configuration.Default.WithDefaultLoader(); using var document = await BrowsingContext.New(config).OpenAsync(quoteHtmlPage); - var divElem = - document.QuerySelector( - "#quote-header-info > div:nth-child(2) > div > div > h1"); - var tickerName = (divElem)?.TextContent; + var tickerName = document.QuerySelector("div.top > .left > .container > h1") + ?.TextContent; + + if (tickerName is null) + return default; + var marketcap = document - .QuerySelectorAll("table") - .Skip(1) - .First() - .QuerySelector("tbody > tr > td:nth-child(2)") + .QuerySelector("li > span > fin-streamer[data-field='marketCap']") ?.TextContent; - var volume = document.QuerySelector("td[data-test='AVERAGE_VOLUME_3MONTH-value']") + var volume = document.QuerySelector("li > span > fin-streamer[data-field='regularMarketVolume']") ?.TextContent; - - var close= document.QuerySelector("td[data-test='PREV_CLOSE-value']") - ?.TextContent ?? "0"; - - var price = document - .QuerySelector("#quote-header-info") - ?.QuerySelector("fin-streamer[data-field='regularMarketPrice']") - ?.TextContent ?? close; - - // var data = await http.GetFromJsonAsync( - // $"https://query1.finance.yahoo.com/v7/finance/quote?symbols={query}"); - // - // if (data is null) - // return default; - // var symbol = data.QuoteResponse.Result.FirstOrDefault(); + var close = document.QuerySelector("li > span > fin-streamer[data-field='regularMarketPreviousClose']") + ?.TextContent + ?? "0"; - // if (symbol is null) - // return default; + var price = document.QuerySelector("fin-streamer.livePrice > span") + ?.TextContent + ?? "0"; return new() { diff --git a/src/NadekoBot/Modules/Searches/PathOfExileCommands.cs b/src/NadekoBot/Modules/Searches/PathOfExileCommands.cs deleted file mode 100644 index ddc271c38..000000000 --- a/src/NadekoBot/Modules/Searches/PathOfExileCommands.cs +++ /dev/null @@ -1,312 +0,0 @@ -#nullable disable -using NadekoBot.Modules.Searches.Common; -using NadekoBot.Modules.Searches.Services; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.Globalization; -using System.Text; - -namespace NadekoBot.Modules.Searches; - -public partial class Searches -{ - [Group] - public partial class PathOfExileCommands : NadekoModule - { - private const string POE_URL = "https://www.pathofexile.com/character-window/get-characters?accountName="; - private const string PON_URL = "http://poe.ninja/api/Data/GetCurrencyOverview?league="; - private const string POGS_URL = "http://pathofexile.gamepedia.com/api.php?action=opensearch&search="; - - private const string POG_URL = - "https://pathofexile.gamepedia.com/api.php?action=browsebysubject&format=json&subject="; - - private const string POGI_URL = - "https://pathofexile.gamepedia.com/api.php?action=query&prop=imageinfo&iiprop=url&format=json&titles=File:"; - - private const string PROFILE_URL = "https://www.pathofexile.com/account/view-profile/"; - - private readonly IHttpClientFactory _httpFactory; - - private Dictionary currencyDictionary = new(StringComparer.OrdinalIgnoreCase) - { - { "Chaos Orb", "Chaos Orb" }, - { "Orb of Alchemy", "Orb of Alchemy" }, - { "Jeweller's Orb", "Jeweller's Orb" }, - { "Exalted Orb", "Exalted Orb" }, - { "Mirror of Kalandra", "Mirror of Kalandra" }, - { "Vaal Orb", "Vaal Orb" }, - { "Orb of Alteration", "Orb of Alteration" }, - { "Orb of Scouring", "Orb of Scouring" }, - { "Divine Orb", "Divine Orb" }, - { "Orb of Annulment", "Orb of Annulment" }, - { "Master Cartographer's Sextant", "Master Cartographer's Sextant" }, - { "Journeyman Cartographer's Sextant", "Journeyman Cartographer's Sextant" }, - { "Apprentice Cartographer's Sextant", "Apprentice Cartographer's Sextant" }, - { "Blessed Orb", "Blessed Orb" }, - { "Orb of Regret", "Orb of Regret" }, - { "Gemcutter's Prism", "Gemcutter's Prism" }, - { "Glassblower's Bauble", "Glassblower's Bauble" }, - { "Orb of Fusing", "Orb of Fusing" }, - { "Cartographer's Chisel", "Cartographer's Chisel" }, - { "Chromatic Orb", "Chromatic Orb" }, - { "Orb of Augmentation", "Orb of Augmentation" }, - { "Blacksmith's Whetstone", "Blacksmith's Whetstone" }, - { "Orb of Transmutation", "Orb of Transmutation" }, - { "Armourer's Scrap", "Armourer's Scrap" }, - { "Scroll of Wisdom", "Scroll of Wisdom" }, - { "Regal Orb", "Regal Orb" }, - { "Chaos", "Chaos Orb" }, - { "Alch", "Orb of Alchemy" }, - { "Alchs", "Orb of Alchemy" }, - { "Jews", "Jeweller's Orb" }, - { "Jeweller", "Jeweller's Orb" }, - { "Jewellers", "Jeweller's Orb" }, - { "Jeweller's", "Jeweller's Orb" }, - { "X", "Exalted Orb" }, - { "Ex", "Exalted Orb" }, - { "Exalt", "Exalted Orb" }, - { "Exalts", "Exalted Orb" }, - { "Mirror", "Mirror of Kalandra" }, - { "Mirrors", "Mirror of Kalandra" }, - { "Vaal", "Vaal Orb" }, - { "Alt", "Orb of Alteration" }, - { "Alts", "Orb of Alteration" }, - { "Scour", "Orb of Scouring" }, - { "Scours", "Orb of Scouring" }, - { "Divine", "Divine Orb" }, - { "Annul", "Orb of Annulment" }, - { "Annulment", "Orb of Annulment" }, - { "Master Sextant", "Master Cartographer's Sextant" }, - { "Journeyman Sextant", "Journeyman Cartographer's Sextant" }, - { "Apprentice Sextant", "Apprentice Cartographer's Sextant" }, - { "Blessed", "Blessed Orb" }, - { "Regret", "Orb of Regret" }, - { "Regrets", "Orb of Regret" }, - { "Gcp", "Gemcutter's Prism" }, - { "Glassblowers", "Glassblower's Bauble" }, - { "Glassblower's", "Glassblower's Bauble" }, - { "Fusing", "Orb of Fusing" }, - { "Fuses", "Orb of Fusing" }, - { "Fuse", "Orb of Fusing" }, - { "Chisel", "Cartographer's Chisel" }, - { "Chisels", "Cartographer's Chisel" }, - { "Chance", "Orb of Chance" }, - { "Chances", "Orb of Chance" }, - { "Chrome", "Chromatic Orb" }, - { "Chromes", "Chromatic Orb" }, - { "Aug", "Orb of Augmentation" }, - { "Augmentation", "Orb of Augmentation" }, - { "Augment", "Orb of Augmentation" }, - { "Augments", "Orb of Augmentation" }, - { "Whetstone", "Blacksmith's Whetstone" }, - { "Whetstones", "Blacksmith's Whetstone" }, - { "Transmute", "Orb of Transmutation" }, - { "Transmutes", "Orb of Transmutation" }, - { "Armourers", "Armourer's Scrap" }, - { "Armourer's", "Armourer's Scrap" }, - { "Wisdom Scroll", "Scroll of Wisdom" }, - { "Wisdom Scrolls", "Scroll of Wisdom" }, - { "Regal", "Regal Orb" }, - { "Regals", "Regal Orb" } - }; - - public PathOfExileCommands(IHttpClientFactory httpFactory) - => _httpFactory = httpFactory; - - [Cmd] - public async Task PathOfExile(string usr, string league = "", int page = 1) - { - if (--page < 0) - return; - - if (string.IsNullOrWhiteSpace(usr)) - { - await Response().Error("Please provide an account name.").SendAsync(); - return; - } - - var characters = new List(); - - try - { - using var http = _httpFactory.CreateClient(); - var res = await http.GetStringAsync($"{POE_URL}{usr}"); - characters = JsonConvert.DeserializeObject>(res); - } - catch - { - var embed = _sender.CreateEmbed().WithDescription(GetText(strs.account_not_found)).WithErrorColor(); - - await Response().Embed(embed).SendAsync(); - return; - } - - if (!string.IsNullOrWhiteSpace(league)) - characters.RemoveAll(c => c.League != league); - - await Response() - .Paginated() - .Items(characters) - .PageSize(9) - .CurrentPage(page) - .Page((items, curPage) => - { - var embed = _sender.CreateEmbed() - .WithAuthor($"Characters on {usr}'s account", - "https://web.poecdn.com/image/favicon/ogimage.png", - $"{PROFILE_URL}{usr}") - .WithOkColor(); - - if (characters.Count == 0) - return embed.WithDescription("This account has no characters."); - - var sb = new StringBuilder(); - sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}"); - for (var i = 0; i < items.Count; i++) - { - var character = items[i]; - - sb.AppendLine( - $"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}"); - } - - sb.AppendLine("```"); - embed.WithDescription(sb.ToString()); - - return embed; - }) - .SendAsync(); - } - - [Cmd] - public async Task PathOfExileLeagues() - { - var leagues = new List(); - - try - { - using var http = _httpFactory.CreateClient(); - var res = await http.GetStringAsync("http://api.pathofexile.com/leagues?type=main&compact=1"); - leagues = JsonConvert.DeserializeObject>(res); - } - catch - { - var eembed = _sender.CreateEmbed().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor(); - - await Response().Embed(eembed).SendAsync(); - return; - } - - var embed = _sender.CreateEmbed() - .WithAuthor("Path of Exile Leagues", - "https://web.poecdn.com/image/favicon/ogimage.png", - "https://www.pathofexile.com") - .WithOkColor(); - - var sb = new StringBuilder(); - sb.AppendLine($"```{"#",-5}{"League Name",-23}"); - for (var i = 0; i < leagues.Count; i++) - { - var league = leagues[i]; - - sb.AppendLine($"#{i + 1,-4}{league.Id,-23}"); - } - - sb.AppendLine("```"); - - embed.WithDescription(sb.ToString()); - - await Response().Embed(embed).SendAsync(); - } - - [Cmd] - public async Task PathOfExileCurrency( - string leagueName, - string currencyName, - string convertName = "Chaos Orb") - { - if (string.IsNullOrWhiteSpace(leagueName)) - { - await Response().Error("Please provide league name.").SendAsync(); - return; - } - - if (string.IsNullOrWhiteSpace(currencyName)) - { - await Response().Error("Please provide currency name.").SendAsync(); - return; - } - - var cleanCurrency = ShortCurrencyName(currencyName); - var cleanConvert = ShortCurrencyName(convertName); - - try - { - var res = $"{PON_URL}{leagueName}"; - using var http = _httpFactory.CreateClient(); - var obj = JObject.Parse(await http.GetStringAsync(res)); - - var chaosEquivalent = 0.0F; - var conversionEquivalent = 0.0F; - - // poe.ninja API does not include a "chaosEquivalent" property for Chaos Orbs. - if (cleanCurrency == "Chaos Orb") - chaosEquivalent = 1.0F; - else - { - var currencyInput = obj["lines"] - .Values() - .Where(i => i["currencyTypeName"].Value() == cleanCurrency) - .FirstOrDefault(); - chaosEquivalent = float.Parse(currencyInput["chaosEquivalent"].ToString(), - CultureInfo.InvariantCulture); - } - - if (cleanConvert == "Chaos Orb") - conversionEquivalent = 1.0F; - else - { - var currencyOutput = obj["lines"] - .Values() - .Where(i => i["currencyTypeName"].Value() == cleanConvert) - .FirstOrDefault(); - conversionEquivalent = float.Parse(currencyOutput["chaosEquivalent"].ToString(), - CultureInfo.InvariantCulture); - } - - var embed = _sender.CreateEmbed() - .WithAuthor($"{leagueName} Currency Exchange", - "https://web.poecdn.com/image/favicon/ogimage.png", - "http://poe.ninja") - .AddField("Currency Type", cleanCurrency, true) - .AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true) - .WithOkColor(); - - await Response().Embed(embed).SendAsync(); - } - catch - { - var embed = _sender.CreateEmbed().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor(); - - await Response().Embed(embed).SendAsync(); - } - } - - private string ShortCurrencyName(string str) - { - if (currencyDictionary.ContainsValue(str)) - return str; - - var currency = currencyDictionary[str]; - - return currency; - } - - private static string ShortLeagueName(string str) - { - var league = str.Replace("Hardcore", "HC", StringComparison.InvariantCultureIgnoreCase); - - return league; - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 995f94c90..28af76d88 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Caching.Memory; using NadekoBot.Modules.Searches.Common; using NadekoBot.Modules.Searches.Services; +using NadekoBot.Modules.Utility; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SixLabors.ImageSharp; @@ -168,7 +169,7 @@ public partial class Searches : NadekoModule .AddField("Rating", movie.ImdbRating, true) .AddField("Genre", movie.Genre, true) .AddField("Year", movie.Year, true) - .WithImageUrl(movie.Poster)) + .WithImageUrl(Uri.IsWellFormedUriString(movie.Poster, UriKind.Absolute) ? movie.Poster : null)) .SendAsync(); } diff --git a/src/NadekoBot/Modules/Utility/Ai/AiAssistantService.cs b/src/NadekoBot/Modules/Utility/Ai/AiAssistantService.cs new file mode 100644 index 000000000..805d9bdb5 --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Ai/AiAssistantService.cs @@ -0,0 +1,314 @@ +using NadekoBot.Common.ModuleBehaviors; +using NadekoBot.Modules.Administration; +using NadekoBot.Modules.Games.Services; +using System.Net; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using JsonSerializer = System.Text.Json.JsonSerializer; + +namespace NadekoBot.Modules.Utility; + +public enum GetCommandErrorResult +{ + RateLimitHit, + NotAuthorized, + Disregard, + Unknown +} + +public sealed class AiAssistantService + : IAiAssistantService, IReadyExecutor, + IExecOnMessage, + INService +{ + private IReadOnlyCollection _commands = []; + + private readonly IBotStrings _strings; + private readonly IHttpClientFactory _httpFactory; + private readonly CommandService _cmds; + private readonly IBotCredsProvider _credsProvider; + private readonly DiscordSocketClient _client; + private readonly ICommandHandler _cmdHandler; + private readonly BotConfigService _bcs; + private readonly IMessageSenderService _sender; + + private readonly JsonSerializerOptions _serializerOptions = new(); + private readonly IPermissionChecker _permChecker; + private readonly IBotCache _botCache; + private readonly ChatterBotService _cbs; + + public AiAssistantService( + DiscordSocketClient client, + IBotStrings strings, + IHttpClientFactory httpFactory, + CommandService cmds, + IBotCredsProvider credsProvider, + ICommandHandler cmdHandler, + BotConfigService bcs, + IPermissionChecker permChecker, + IBotCache botCache, + ChatterBotService cbs, + IMessageSenderService sender) + { + _client = client; + _strings = strings; + _httpFactory = httpFactory; + _cmds = cmds; + _credsProvider = credsProvider; + _cmdHandler = cmdHandler; + _bcs = bcs; + _sender = sender; + _permChecker = permChecker; + _botCache = botCache; + _cbs = cbs; + } + + public async Task> TryGetCommandAsync( + ulong userId, + string prompt, + IReadOnlyCollection commands, + string prefix) + { + using var content = new StringContent( + JsonSerializer.Serialize(new + { + query = prompt, + commands = commands.ToDictionary(x => x.Name, + x => new AiCommandModel() + { + Desc = string.Format(x.Desc ?? "", prefix), + Params = x.Params, + Name = x.Name + }), + }), + Encoding.UTF8, + "application/json" + ); + + using var request = new HttpRequestMessage(); + request.Method = HttpMethod.Post; + // request.RequestUri = new("https://nai.nadeko.bot/get-command"); + request.RequestUri = new("https://nai.nadeko.bot/get-command"); + request.Content = content; + + var creds = _credsProvider.GetCreds(); + + request.Headers.TryAddWithoutValidation("x-auth-token", creds.NadekoAiToken); + request.Headers.TryAddWithoutValidation("x-auth-userid", userId.ToString()); + + + using var client = _httpFactory.CreateClient(); + + // todo customize according to the bot's config + // - CurrencyName + // - + + using var response = await client.SendAsync(request); + + if (response.StatusCode == HttpStatusCode.TooManyRequests) + { + return GetCommandErrorResult.RateLimitHit; + } + else if (response.StatusCode == HttpStatusCode.Unauthorized) + { + return GetCommandErrorResult.NotAuthorized; + } + + var funcModel = await response.Content.ReadFromJsonAsync(); + + + if (funcModel?.Name == "disregard") + { + Log.Warning("Disregarding the prompt: {Prompt}", prompt); + return GetCommandErrorResult.Disregard; + } + + if (funcModel is null) + return GetCommandErrorResult.Unknown; + + var comModel = new NadekoCommandCallModel() + { + Name = funcModel.Name, + Arguments = funcModel.Arguments + .OrderBy(param => _commands.FirstOrDefault(x => x.Name == funcModel.Name) + ?.Params + .Select((x, i) => (x, i)) + .Where(x => x.x.Name == param.Key) + .Select(x => x.i) + .FirstOrDefault()) + .Select(x => x.Value) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToArray(), + Remaining = funcModel.Remaining + }; + + return comModel; + } + + public IReadOnlyCollection GetCommands() + => _commands; + + public Task OnReadyAsync() + { + var cmds = _cmds.Commands + .Select(x => (MethodName: x.Summary, CommandName: x.Aliases[0])) + .Where(x => !x.MethodName.Contains("///")) + .Distinct() + .ToList(); + + var funcs = new List(); + foreach (var (method, cmd) in cmds) + { + var commandStrings = _strings.GetCommandStrings(method); + + if (commandStrings is null) + continue; + + funcs.Add(new() + { + Name = cmd, + Desc = commandStrings?.Desc?.Replace("currency", "flowers") ?? string.Empty, + Params = commandStrings?.Params.FirstOrDefault() + ?.Select(x => new AiCommandParamModel() + { + Desc = x.Value.Desc, + Name = x.Key, + }) + .ToArray() + ?? [] + }); + } + + _commands = funcs; + + return Task.CompletedTask; + } + + public int Priority + => 2; + + public async Task ExecOnMessageAsync(IGuild guild, IUserMessage msg) + { + if (string.IsNullOrWhiteSpace(_credsProvider.GetCreds().NadekoAiToken)) + return false; + + if (guild is not SocketGuild sg) + return false; + + var nadekoId = _client.CurrentUser.Id; + + var channel = msg.Channel as ITextChannel; + if (channel is null) + return false; + + var normalMention = $"<@{nadekoId}> "; + var nickMention = $"<@!{nadekoId}> "; + string query; + if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture)) + query = msg.Content[normalMention.Length..].Trim(); + else if (msg.Content.StartsWith(nickMention, StringComparison.InvariantCulture)) + query = msg.Content[nickMention.Length..].Trim(); + else + return false; + + var success = await TryExecuteAiCommand(guild, msg, channel, query); + + return success; + } + + public async Task TryExecuteAiCommand( + IGuild guild, + IUserMessage msg, + ITextChannel channel, + string query) + { + // check permissions + var pcResult = await _permChecker.CheckPermsAsync( + guild, + msg.Channel, + msg.Author, + "Utility", + "prompt" + ); + + if (!pcResult.IsAllowed) + return false; + + using var _ = channel.EnterTypingState(); + + var result = await TryGetCommandAsync(msg.Author.Id, query, _commands, _cmdHandler.GetPrefix(guild.Id)); + + if (result.TryPickT0(out var model, out var error)) + { + if (model.Name == ".ai_chat") + { + if (guild is not SocketGuild sg) + return false; + + var sess = _cbs.GetOrCreateSession(guild.Id); + if (sess is null) + return false; + + await _cbs.RunChatterBot(sg, msg, channel, sess, query); + return false; + } + + var commandString = GetCommandString(model); + + var msgTask = _sender.Response(channel) + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithAuthor(msg.Author.GlobalName, + msg.Author.RealAvatarUrl().ToString()) + .WithDescription(commandString)) + .SendAsync(); + + + await _cmdHandler.TryRunCommand( + (SocketGuild)guild, + (ISocketMessageChannel)channel, + new DoAsUserMessage((SocketUserMessage)msg, msg.Author, commandString)); + + var cmdMsg = await msgTask; + + cmdMsg.DeleteAfter(5); + + return true; + } + + if (error == GetCommandErrorResult.Disregard) + { + // await msg.ErrorAsync(); + return false; + } + + var key = new TypedKey($"sub_error:{msg.Author.Id}:{error}"); + + if (!await _botCache.AddAsync(key, true, TimeSpan.FromDays(1), overwrite: false)) + return false; + + var errorMsg = error switch + { + GetCommandErrorResult.RateLimitHit + => "You've spent your daily requests quota.", + GetCommandErrorResult.NotAuthorized + => "In order to use this command you have to have a 5$ or higher subscription at ", + GetCommandErrorResult.Unknown + => "The service is temporarily unavailable.", + _ => throw new ArgumentOutOfRangeException() + }; + + await _sender.Response(channel) + .Error(errorMsg) + .SendAsync(); + + return true; + } + + private string GetCommandString(NadekoCommandCallModel res) + => $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}"; + + private static string GetParamString(string val, bool isLast) + => isLast ? val : "\"" + val + "\""; +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Ai/AiCommandModel.cs b/src/NadekoBot/Modules/Utility/Ai/AiCommandModel.cs new file mode 100644 index 000000000..95682956e --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Ai/AiCommandModel.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace NadekoBot.Modules.Utility; + +public sealed class AiCommandModel +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("desc")] + public required string Desc { get; set; } + + [JsonPropertyName("params")] + public required IReadOnlyList Params { get; set; } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Ai/AiCommandParamModel.cs b/src/NadekoBot/Modules/Utility/Ai/AiCommandParamModel.cs new file mode 100644 index 000000000..b91cc0490 --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Ai/AiCommandParamModel.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace NadekoBot.Modules.Utility; + +public sealed class AiCommandParamModel +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("desc")] + public required string Desc { get; set; } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Ai/CommandPromptResultModel.cs b/src/NadekoBot/Modules/Utility/Ai/CommandPromptResultModel.cs new file mode 100644 index 000000000..306b4924e --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Ai/CommandPromptResultModel.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace NadekoBot.Modules.Utility; + +public sealed class CommandPromptResultModel +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("arguments")] + public required Dictionary Arguments { get; set; } + + [JsonPropertyName("remaining")] + [JsonConverter(typeof(NumberToStringConverter))] + public required string Remaining { get; set; } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Ai/IAiAssistantService.cs b/src/NadekoBot/Modules/Utility/Ai/IAiAssistantService.cs new file mode 100644 index 000000000..14e9b7036 --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Ai/IAiAssistantService.cs @@ -0,0 +1,20 @@ +using OneOf; + +namespace NadekoBot.Modules.Utility; + +public interface IAiAssistantService +{ + Task> TryGetCommandAsync( + ulong userId, + string prompt, + IReadOnlyCollection commands, + string prefix); + + IReadOnlyCollection GetCommands(); + + Task TryExecuteAiCommand( + IGuild guild, + IUserMessage msg, + ITextChannel channel, + string query); +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Ai/NadekoCommandCallModel.cs b/src/NadekoBot/Modules/Utility/Ai/NadekoCommandCallModel.cs new file mode 100644 index 000000000..98467297c --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Ai/NadekoCommandCallModel.cs @@ -0,0 +1,8 @@ +namespace NadekoBot.Modules.Utility; + +public sealed class NadekoCommandCallModel +{ + public required string Name { get; set; } + public required IReadOnlyList Arguments { get; set; } + public required string Remaining { get; set; } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Ai/UtilityCommands.cs b/src/NadekoBot/Modules/Utility/Ai/UtilityCommands.cs new file mode 100644 index 000000000..97836c267 --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Ai/UtilityCommands.cs @@ -0,0 +1,23 @@ +using NadekoBot.Modules.Administration; + +namespace NadekoBot.Modules.Utility; + +public partial class UtilityCommands +{ + public class PromptCommands : NadekoModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Prompt([Leftover] string query) + { + await ctx.Channel.TriggerTypingAsync(); + var res = await _service.TryExecuteAiCommand(ctx.Guild, ctx.Message, (ITextChannel)ctx.Channel, query); + } + + private string GetCommandString(NadekoCommandCallModel res) + => $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}"; + + private static string GetParamString(string val, bool isLast) + => isLast ? val : "\"" + val + "\""; + } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs index 67d2165be..1ae949789 100644 --- a/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Info/InfoCommands.cs @@ -144,9 +144,9 @@ public partial class Utility true) .WithOkColor(); - var patron = await _ps.GetPatronAsync(user.Id); + var mPatron = await _ps.GetPatronAsync(user.Id); - if (patron.Tier != PatronTier.None) + if (mPatron is {} patron && patron.Tier != PatronTier.None) { embed.WithFooter(patron.Tier switch { diff --git a/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs b/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs index 51be0ce61..34be44ec1 100644 --- a/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs +++ b/src/NadekoBot/Modules/Utility/Remind/RemindCommands.cs @@ -113,10 +113,9 @@ public partial class Utility foreach (var rem in rems) { var when = rem.When; - var diff = when - DateTime.UtcNow; embed.AddField( $"#{++i + (page * 10)} {rem.When:HH:mm yyyy-MM-dd} UTC " - + $"(in {diff.ToPrettyStringHm()})", + + $"{TimestampTag.FromDateTime(when)}", $@"`Target:` {(rem.IsPrivate ? "DM" : "Channel")} `TargetId:` {rem.ChannelId} `Message:` {rem.Message?.TrimTo(50)}"); @@ -203,16 +202,15 @@ public partial class Utility await uow.SaveChangesAsync(); } - var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id)); + // var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id)); try { await Response() - .Confirm($"\u23f0 {GetText(strs.remind( + .Confirm($"\u23f0 {GetText(strs.remind2( Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username), Format.Bold(message), - ts.ToPrettyStringHm(), - gTime, - gTime))}") + TimestampTag.FromDateTime(DateTime.UtcNow.Add(ts), TimestampTagStyles.Relative), + TimestampTag.FormatFromDateTime(time, TimestampTagStyles.ShortDateTime)))}") .SendAsync(); } catch diff --git a/src/NadekoBot/Modules/Xp/Xp.cs b/src/NadekoBot/Modules/Xp/Xp.cs index fd9570002..89882bb18 100644 --- a/src/NadekoBot/Modules/Xp/Xp.cs +++ b/src/NadekoBot/Modules/Xp/Xp.cs @@ -2,6 +2,7 @@ using NadekoBot.Modules.Xp.Services; using NadekoBot.Db.Models; using NadekoBot.Modules.Patronage; +using NadekoBot.Modules.Utility; namespace NadekoBot.Modules.Xp; diff --git a/src/NadekoBot/Modules/Xp/XpService.cs b/src/NadekoBot/Modules/Xp/XpService.cs index ddee73c2e..9643adc1a 100644 --- a/src/NadekoBot/Modules/Xp/XpService.cs +++ b/src/NadekoBot/Modules/Xp/XpService.cs @@ -1286,9 +1286,9 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand Image? frame = null; if (item is null) { - if (patron.Tier == PatronTier.V) + if (patron?.Tier == PatronTier.V) frame = Image.Load(File.OpenRead("data/images/frame_silver.png")); - else if (patron.Tier >= PatronTier.X || _creds.IsOwner(userId)) + else if (patron?.Tier >= PatronTier.X || _creds.IsOwner(userId)) frame = Image.Load(File.OpenRead("data/images/frame_gold.png")); } else @@ -1465,7 +1465,7 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand { var patron = await _ps.GetPatronAsync(userId); - if ((int)patron.Tier < (int)req) + if (patron is null || (int)patron.Value.Tier < (int)req) return BuyResult.InsufficientPatronTier; } diff --git a/src/NadekoBot/NadekoBot.csproj b/src/NadekoBot/NadekoBot.csproj index 33cc7cf99..339ad07e7 100644 --- a/src/NadekoBot/NadekoBot.csproj +++ b/src/NadekoBot/NadekoBot.csproj @@ -4,7 +4,7 @@ enable true en - 5.0.8 + 5.1.0 $(MSBuildProjectDirectory) @@ -75,7 +75,7 @@ - + diff --git a/src/NadekoBot/Services/Impl/BotCredsProvider.cs b/src/NadekoBot/Services/Impl/BotCredsProvider.cs index 3bef56503..696035aff 100644 --- a/src/NadekoBot/Services/Impl/BotCredsProvider.cs +++ b/src/NadekoBot/Services/Impl/BotCredsProvider.cs @@ -191,6 +191,12 @@ public sealed class BotCredsProvider : IBotCredsProvider creds.Version = 7; File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds)); } + + if (creds.Version <= 7) + { + creds.Version = 8; + File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds)); + } } } diff --git a/src/NadekoBot/Services/Impl/RedisBotCache.cs b/src/NadekoBot/Services/Impl/RedisBotCache.cs index 2797aefbd..a94e3e506 100644 --- a/src/NadekoBot/Services/Impl/RedisBotCache.cs +++ b/src/NadekoBot/Services/Impl/RedisBotCache.cs @@ -3,6 +3,7 @@ using OneOf.Types; using StackExchange.Redis; using System.Text.Json; using System.Text.Json.Serialization; +using YamlDotNet.Core.Tokens; namespace NadekoBot.Common; @@ -47,6 +48,7 @@ public sealed class RedisBotCache : IBotCache var success = await db.StringSetAsync(key.Key, val, expiry: expiry, + keepTtl: true, when: overwrite ? When.Always : When.NotExists); return success; diff --git a/src/NadekoBot/_common/Abstractions/creds/IBotCredentials.cs b/src/NadekoBot/_common/Abstractions/creds/IBotCredentials.cs index 6216f25e4..fc2edca2d 100644 --- a/src/NadekoBot/_common/Abstractions/creds/IBotCredentials.cs +++ b/src/NadekoBot/_common/Abstractions/creds/IBotCredentials.cs @@ -4,8 +4,9 @@ namespace NadekoBot; public interface IBotCredentials { string Token { get; } - string GoogleApiKey { get; } + string NadekoAiToken { get; } ICollection OwnerIds { get; set; } + string GoogleApiKey { get; } bool UsePrivilegedIntents { get; } string RapidApiKey { get; } diff --git a/src/NadekoBot/_common/Creds.cs b/src/NadekoBot/_common/Creds.cs index d3f20ff6c..b9cd49049 100644 --- a/src/NadekoBot/_common/Creds.cs +++ b/src/NadekoBot/_common/Creds.cs @@ -29,6 +29,15 @@ public sealed class Creds : IBotCredentials """)] public int TotalShards { get; set; } + [Comment(""" + Pledge 5$ or more on https://patreon.com/nadekobot and connect your discord account to Patreon. + Go to https://dashy.nadeko.bot and login with your discord account + Go to the Keys page and click "Generate New Key" and copy it here + You and anyone else with the permission to run `.prompt` command will be able to use natural language to run bot's commands. + For example '@Bot how's the weather in Paris' will return the current weather in Paris as if you were to run `.weather Paris` command + """)] + public string NadekoAiToken { get; set; } + [Comment( """ Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it. @@ -64,7 +73,7 @@ public sealed class Creds : IBotCredentials [Comment("""Official cleverbot api key.""")] public string CleverbotApiKey { get; set; } - [Comment(@"Official GPT-3 api key.")] + [Comment(@"OpenAi api key.")] public string Gpt3ApiKey { get; set; } [Comment(""" diff --git a/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs b/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs index 9cb2cd8e8..da6676fb1 100644 --- a/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs +++ b/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs @@ -18,4 +18,5 @@ public sealed class NadekoButtonInteractionHandler : NadekoInteractionBase public override void AddTo(ComponentBuilder cb) => cb.WithButton(Button); + } \ No newline at end of file diff --git a/src/NadekoBot/_common/Interaction/NadekoInteraction.cs b/src/NadekoBot/_common/Interaction/NadekoInteraction.cs index e8734be9a..d785c0ceb 100644 --- a/src/NadekoBot/_common/Interaction/NadekoInteraction.cs +++ b/src/NadekoBot/_common/Interaction/NadekoInteraction.cs @@ -85,6 +85,9 @@ public abstract class NadekoInteractionBase public Task ExecuteOnActionAsync(SocketMessageComponent smc) => _onAction(smc); + + public void SetCompleted() + => _interactionCompletedSource.TrySetResult(true); } public sealed class NadekoModalSubmitHandler diff --git a/src/NadekoBot/_common/JsonConverters/CultureInfoConverter.cs b/src/NadekoBot/_common/JsonConverters/CultureInfoConverter.cs index 452bc7bb0..896ab5137 100644 --- a/src/NadekoBot/_common/JsonConverters/CultureInfoConverter.cs +++ b/src/NadekoBot/_common/JsonConverters/CultureInfoConverter.cs @@ -11,4 +11,4 @@ public class CultureInfoConverter : JsonConverter public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) => writer.WriteStringValue(value.Name); -} \ No newline at end of file +} diff --git a/src/NadekoBot/_common/JsonConverters/NumberToStringConverter.cs b/src/NadekoBot/_common/JsonConverters/NumberToStringConverter.cs new file mode 100644 index 000000000..bc20b100b --- /dev/null +++ b/src/NadekoBot/_common/JsonConverters/NumberToStringConverter.cs @@ -0,0 +1,30 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +public class NumberToStringConverter : JsonConverter +{ + public override bool CanConvert(Type typeToConvert) + => typeof(string) == typeToConvert; + + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + switch (reader.TokenType) + { + case JsonTokenType.Number: + return reader.TryGetInt64(out var l) + ? l.ToString() + : reader.GetDouble().ToString(CultureInfo.InvariantCulture); + case JsonTokenType.String: + return reader.GetString() ?? string.Empty; + default: + { + using var document = JsonDocument.ParseValue(ref reader); + return document.RootElement.Clone().ToString(); + } + } + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString()); +} \ No newline at end of file diff --git a/src/NadekoBot/_common/Patronage/FeatureLimitKey.cs b/src/NadekoBot/_common/Patronage/FeatureLimitKey.cs index 17a42bc61..b59f1afe4 100644 --- a/src/NadekoBot/_common/Patronage/FeatureLimitKey.cs +++ b/src/NadekoBot/_common/Patronage/FeatureLimitKey.cs @@ -1,5 +1,12 @@ namespace NadekoBot.Modules.Patronage; +public enum LimitedFeatureName +{ + ChatBot, + ReactionRole, + Prune, + +} public readonly struct FeatureLimitKey { public string PrettyName { get; init; } diff --git a/src/NadekoBot/_common/Patronage/FeatureQuotaStats.cs b/src/NadekoBot/_common/Patronage/FeatureQuotaStats.cs deleted file mode 100644 index 538088ef4..000000000 --- a/src/NadekoBot/_common/Patronage/FeatureQuotaStats.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace NadekoBot.Modules.Patronage; - -public readonly struct FeatureQuotaStats -{ - public (uint Cur, uint Max) Hourly { get; init; } - public (uint Cur, uint Max) Daily { get; init; } - public (uint Cur, uint Max) Monthly { get; init; } -} \ No newline at end of file diff --git a/src/NadekoBot/_common/Patronage/IPatronageService.cs b/src/NadekoBot/_common/Patronage/IPatronageService.cs index 48eb061f8..82e26faee 100644 --- a/src/NadekoBot/_common/Patronage/IPatronageService.cs +++ b/src/NadekoBot/_common/Patronage/IPatronageService.cs @@ -31,26 +31,15 @@ public interface IPatronageService /// /// UserId for which to get the patron data for. /// A patron with the specifeid userId - public Task GetPatronAsync(ulong userId); + public Task GetPatronAsync(ulong userId); - /// - /// Gets the quota statistic for the user/patron specified by the userId - /// - /// UserId of the user for which to get the quota statistic for - /// Quota stats for the specified user - Task GetUserQuotaStatistic(ulong userId); - + Task LimitHitAsync(LimitedFeatureName key, ulong userId, int amount = 1); + Task LimitForceHit(LimitedFeatureName key, ulong userId, int amount); + Task GetUserLimit(LimitedFeatureName name, ulong userId); - Task TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue); - - ValueTask> TryIncrementQuotaCounterAsync( - ulong userId, - bool isSelf, - FeatureType featureType, - string featureName, - uint? maybeHourly, - uint? maybeDaily, - uint? maybeMonthly); + Task> LimitStats(ulong userId); PatronConfigData GetConfig(); + int PercentBonus(Patron? user); + int PercentBonus(long amount); } \ No newline at end of file diff --git a/src/NadekoBot/_common/Patronage/Patron.cs b/src/NadekoBot/_common/Patronage/Patron.cs index 1dfc5df86..766b0ee38 100644 --- a/src/NadekoBot/_common/Patronage/Patron.cs +++ b/src/NadekoBot/_common/Patronage/Patron.cs @@ -13,7 +13,7 @@ public readonly struct Patron public ulong UserId { get; init; } /// - /// Amount the Patron is currently pledging or paid + /// Amount the Patron is currently pledging or paid in cents /// public int Amount { get; init; } diff --git a/src/NadekoBot/_common/Patronage/PatronConfigData.cs b/src/NadekoBot/_common/Patronage/PatronConfigData.cs index 223019eff..2c1e11d3d 100644 --- a/src/NadekoBot/_common/Patronage/PatronConfigData.cs +++ b/src/NadekoBot/_common/Patronage/PatronConfigData.cs @@ -7,31 +7,11 @@ namespace NadekoBot.Modules.Patronage; public partial class PatronConfigData : ICloneable { [Comment("DO NOT CHANGE")] - public int Version { get; set; } = 2; - + public int Version { get; set; } = 3; + [Comment("Whether the patronage feature is enabled")] public bool IsEnabled { get; set; } - [Comment("List of patron only features and relevant quota data")] - public FeatureQuotas Quotas { get; set; } - - public PatronConfigData() - { - Quotas = new(); - } - - public class FeatureQuotas - { - [Comment("Dictionary of feature names with their respective limits. Set to null for unlimited")] - public Dictionary> Features { get; set; } = new(); - - [Comment("Dictionary of commands with their respective quota data")] - public Dictionary?>> Commands { get; set; } = new(); - - [Comment("Dictionary of groups with their respective quota data")] - public Dictionary?>> Groups { get; set; } = new(); - - [Comment("Dictionary of modules with their respective quota data")] - public Dictionary?>> Modules { get; set; } = new(); - } + [Comment("Who can do how much of what")] + public Dictionary> Limits { get; set; } = new(); } \ No newline at end of file diff --git a/src/NadekoBot/_common/Patronage/PatronExtensions.cs b/src/NadekoBot/_common/Patronage/PatronExtensions.cs index b5e29d52b..a90463c8d 100644 --- a/src/NadekoBot/_common/Patronage/PatronExtensions.cs +++ b/src/NadekoBot/_common/Patronage/PatronExtensions.cs @@ -8,15 +8,6 @@ public static class PatronExtensions _ => $"Patron Tier {tier}", }; - public static string ToFullName(this QuotaPer per) - => per switch - { - QuotaPer.PerDay => "per day", - QuotaPer.PerHour => "per hour", - QuotaPer.PerMonth => "per month", - _ => "Unknown", - }; - public static DateTime DayOfNextMonth(this DateTime date, int day) { var nextMonth = date.AddMonths(1); diff --git a/src/NadekoBot/_common/Patronage/QuotaLimit.cs b/src/NadekoBot/_common/Patronage/QuotaLimit.cs index ff4336376..2cf00808a 100644 --- a/src/NadekoBot/_common/Patronage/QuotaLimit.cs +++ b/src/NadekoBot/_common/Patronage/QuotaLimit.cs @@ -10,57 +10,16 @@ public readonly struct QuotaLimit /// /// Amount of usages reached, which is the limit /// - public uint Quota { get; init; } + public int Quota { get; init; } /// /// Which period is this quota limit for (hourly, daily, monthly, etc...) /// public QuotaPer QuotaPeriod { get; init; } - /// - /// When does this quota limit reset - /// - public DateTime ResetsAt { get; init; } - - /// - /// Type of the feature this quota limit is for - /// - public FeatureType FeatureType { get; init; } - - /// - /// Name of the feature this quota limit is for - /// - public string Feature { get; init; } - - /// - /// Whether it is the user's own quota (true), or server owners (false) - /// - public bool IsOwnQuota { get; init; } -} - - -/// -/// Respresent information about the feature limit -/// -public readonly struct FeatureLimit -{ - - /// - /// Whether this limit comes from the patronage system - /// - public bool IsPatronLimit { get; init; } = false; - - /// - /// Maximum limit allowed - /// - public int? Quota { get; init; } = null; - - /// - /// Name of the limit - /// - public string Name { get; init; } = string.Empty; - - public FeatureLimit() + public QuotaLimit(int quota, QuotaPer quotaPeriod) { + Quota = quota; + QuotaPeriod = quotaPeriod; } } \ No newline at end of file diff --git a/src/NadekoBot/_common/Patronage/QuotaPer.cs b/src/NadekoBot/_common/Patronage/QuotaPer.cs index a93d8979c..b6a321cef 100644 --- a/src/NadekoBot/_common/Patronage/QuotaPer.cs +++ b/src/NadekoBot/_common/Patronage/QuotaPer.cs @@ -5,4 +5,5 @@ public enum QuotaPer PerHour, PerDay, PerMonth, + Total, } \ No newline at end of file diff --git a/src/NadekoBot/_common/Patronage/UserQuotaStats.cs b/src/NadekoBot/_common/Patronage/UserQuotaStats.cs deleted file mode 100644 index d36f756c8..000000000 --- a/src/NadekoBot/_common/Patronage/UserQuotaStats.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace NadekoBot.Modules.Patronage; - -public readonly struct UserQuotaStats -{ - private static readonly IReadOnlyDictionary _emptyDictionary - = new Dictionary(); - public PatronTier Tier { get; init; } - = PatronTier.None; - - public IReadOnlyDictionary Features { get; init; } - = _emptyDictionary; - - public IReadOnlyDictionary Commands { get; init; } - = _emptyDictionary; - - public IReadOnlyDictionary Groups { get; init; } - = _emptyDictionary; - - public IReadOnlyDictionary Modules { get; init; } - = _emptyDictionary; - - public UserQuotaStats() - { - } -} \ No newline at end of file diff --git a/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs b/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs index 4048fa268..0e1c21512 100644 --- a/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs +++ b/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs @@ -11,6 +11,10 @@ public partial class ResponseBuilder private readonly ResponseBuilder _builder; private readonly DiscordSocketClient _client; private int currentPage; + + private NadekoButtonInteractionHandler left; + private NadekoButtonInteractionHandler right; + private NadekoInteractionBase? extra; public PaginationSender( SourcedPaginatedResponseBuilder paginationBuilder, @@ -106,6 +110,8 @@ public partial class ResponseBuilder return (leftBtnInter, maybeInter, rightBtnInter); } + + (left, extra, right) = await GetInteractions(); async Task UpdatePageAsync(SocketMessageComponent smc) { @@ -114,21 +120,25 @@ public partial class ResponseBuilder if (_paginationBuilder.AddPaginatedFooter) toSend.AddPaginatedFooter(currentPage, lastPage); - var (left, extra, right) = (await GetInteractions()); + left.SetCompleted(); + right.SetCompleted(); + extra?.SetCompleted(); + (left, extra, right) = (await GetInteractions()); var cb = new ComponentBuilder(); left.AddTo(cb); right.AddTo(cb); extra?.AddTo(cb); - + await smc.ModifyOriginalResponseAsync(x => { x.Embed = toSend.Build(); x.Components = cb.Build(); }); + + await Task.WhenAll(left.RunAsync(smc.Message), extra?.RunAsync(smc.Message) ?? Task.CompletedTask, right.RunAsync(smc.Message)); } - var (left, extra, right) = await GetInteractions(); var cb = new ComponentBuilder(); left.AddTo(cb); @@ -144,9 +154,11 @@ public partial class ResponseBuilder if (lastPage == 0 && _paginationBuilder.InteractionFunc is null) return; - + await Task.WhenAll(left.RunAsync(msg), extra?.RunAsync(msg) ?? Task.CompletedTask, right.RunAsync(msg)); + await Task.Delay(30_000); + await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build()); } } diff --git a/src/NadekoBot/_common/Services/CommandHandler.cs b/src/NadekoBot/_common/Services/CommandHandler.cs index 519ab1c2b..9ebe18f19 100644 --- a/src/NadekoBot/_common/Services/CommandHandler.cs +++ b/src/NadekoBot/_common/Services/CommandHandler.cs @@ -9,7 +9,7 @@ namespace NadekoBot.Services; public class CommandHandler : INService, IReadyExecutor, ICommandHandler { - private const int GLOBAL_COMMANDS_COOLDOWN = 750; + private const int GLOBAL_COMMANDS_COOLDOWN = 200; private const float ONE_THOUSANDTH = 1.0f / 1000; @@ -262,7 +262,7 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler var blockTime = Environment.TickCount - startTime; var messageContent = await _behaviorHandler.RunInputTransformersAsync(guild, usrMsg); - + var prefix = GetPrefix(guild?.Id); var isPrefixCommand = messageContent.StartsWith(".prefix", StringComparison.InvariantCultureIgnoreCase); // execute the command and measure the time it took diff --git a/src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs b/src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs index 5db6ae628..b17c4d087 100644 --- a/src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs +++ b/src/NadekoBot/_common/_Extensions/CommandContextExtensions.cs @@ -27,4 +27,14 @@ public static class CommandContextExtensions public static Task WarningAsync(this ICommandContext ctx) => ctx.ReactAsync(MsgType.Pending); + + + public static Task OkAsync(this IUserMessage msg) + => msg.AddReactionAsync(_okEmoji); + + public static Task ErrorAsync(this IUserMessage msg) + => msg.AddReactionAsync(_errorEmoji); + + public static Task WarningAsync(this IUserMessage msg) + => msg.AddReactionAsync(_warnEmoji); } \ No newline at end of file diff --git a/src/NadekoBot/_common/_Extensions/Extensions.cs b/src/NadekoBot/_common/_Extensions/Extensions.cs index cb519a48e..484af6c5e 100644 --- a/src/NadekoBot/_common/_Extensions/Extensions.cs +++ b/src/NadekoBot/_common/_Extensions/Extensions.cs @@ -229,6 +229,7 @@ public static class Extensions public static IEnumerable GetRoles(this IGuildUser user) => user.RoleIds.Select(r => user.Guild.GetRole(r)).Where(r => r is not null); + // todo remove public static void Lap(this Stopwatch sw, string checkpoint) { Log.Information("Checkpoint {CheckPoint}: {Time}ms", checkpoint, sw.Elapsed.TotalMilliseconds); diff --git a/src/NadekoBot/data/aliases.yml b/src/NadekoBot/data/aliases.yml index 7cd878f96..7704785e5 100644 --- a/src/NadekoBot/data/aliases.yml +++ b/src/NadekoBot/data/aliases.yml @@ -773,6 +773,7 @@ listservers: - listservers cleverbot: - cleverbot + - chatbot - chatgpt shorten: - shorten @@ -1161,15 +1162,6 @@ massban: - massban masskill: - masskill -pathofexile: - - pathofexile - - poe -pathofexileleagues: - - pathofexileleagues - - poel -pathofexilecurrency: - - pathofexilecurrency - - poec rollduel: - rollduel reroadd: @@ -1406,4 +1398,6 @@ todoshow: stickyroles: - stickyroles cleanupguilddata: - - cleanupguilddata \ No newline at end of file + - cleanupguilddata +prompt: + - prompt \ No newline at end of file diff --git a/src/NadekoBot/data/games.yml b/src/NadekoBot/data/games.yml index 5d0c369f8..1dfb2825c 100644 --- a/src/NadekoBot/data/games.yml +++ b/src/NadekoBot/data/games.yml @@ -1,12 +1,12 @@ # DO NOT CHANGE -version: 3 +version: 4 # Hangman related settings (.hangman command) hangman: -# The amount of currency awarded to the winner of a hangman game + # The amount of currency awarded to the winner of a hangman game currencyReward: 0 # Trivia related settings (.t command) trivia: -# The amount of currency awarded to the winner of the trivia game. + # The amount of currency awarded to the winner of the trivia game. currencyReward: 0 # Users won't be able to start trivia games which have # a smaller win requirement than the one specified by this setting. @@ -56,20 +56,19 @@ raceAnimals: name: Unicorn # Which chatbot API should bot use. # 'cleverbot' - bot will use Cleverbot API. -# 'gpt3' - bot will use GPT-3 API -chatBot: Gpt3 - +# 'gpt' - bot will use GPT API +chatBot: Gpt chatGpt: -# Which GPT-3 Model should bot use. + # Which GPT Model should bot use. # gpt35turbo - cheapest - # gpt4 - 30x more expensive, higher quality - # gp432k - same model as above, but with a 32k token limit + # gpt4o - more expensive, higher quality + # modelName: Gpt35Turbo - # How should the chat bot behave, whats its personality? (Usage of this counts towards the max tokens) + # How should the chat bot behave, what's its personality? (Usage of this counts towards the max tokens) personalityPrompt: You are a chat bot willing to have a conversation with anyone about anything. # The maximum number of messages in a conversation that can be remembered. (This will increase the number of tokens used) chatHistory: 5 - # The maximum number of tokens to use per GPT-3 API call + # The maximum number of tokens to use per GPT API call maxTokens: 100 - # The minimum number of tokens to use per GPT-3 API call, such that chat history is removed to make room. - minTokens: 30 \ No newline at end of file + # The minimum number of tokens to use per GPT API call, such that chat history is removed to make room. + minTokens: 30 diff --git a/src/NadekoBot/data/patron.yml b/src/NadekoBot/data/patron.yml index 40da7bba7..632a3e6f5 100644 --- a/src/NadekoBot/data/patron.yml +++ b/src/NadekoBot/data/patron.yml @@ -1,69 +1,56 @@ # DO NOT CHANGE -version: 2 +version: 3 # Whether the patronage feature is enabled isEnabled: false -# List of patron only features and relevant quota data -quotas: - # Dictionary of feature names with their respective limits. Set to null for unlimited - features: - timely:extra_percent: - V: 10 - X: 22 - XX: 50 - L: 150 - C: 350 - rero:max_count: - V: 25 - X: 50 - cleverbot:response: - V: -20 - X: 5000 - XX: 12000 - L: 35000 - C: 100000 - # Dictionary of commands with their respective quota data - commands: - cleverbot: - V: - prune: - X: - PerHour: 1 - XX: - PerHour: 3 - google: - V: - PerDay: 15 - X: - PerDay: 30 - XX: - PerDay: 60 - L: - PerDay: 150 - C: - PerDay: 300 - image: - V: - PerDay: 15 - X: - PerDay: 30 - XX: - PerDay: 60 - L: - PerDay: 150 - C: - PerDay: 300 - youtube: - V: - PerDay: 25 - X: - PerDay: 50 - XX: - PerDay: 100 - L: - PerDay: 250 - C: - PerDay: 500 - # Dictionary of groups with their respective quota data - groups: {} - # Dictionary of modules with their respective quota data - modules: {} +# Who can do how much of what +limits: + 100: + ChatBot: + quota: 50000000 + quotaPeriod: PerMonth + ReactionRole: + quota: -1 + quotaPeriod: Total + Prune: + quota: -1 + quotaPeriod: PerDay + 50: + ChatBot: + quota: 20000000 + quotaPeriod: PerMonth + ReactionRole: + quota: -1 + quotaPeriod: Total + Prune: + quota: -1 + quotaPeriod: PerDay + 20: + ChatBot: + quota: 6500000 + quotaPeriod: PerMonth + ReactionRole: + quota: -1 + quotaPeriod: Total + Prune: + quota: 20 + quotaPeriod: PerDay + 10: + ChatBot: + quota: 2500000 + quotaPeriod: PerMonth + ReactionRole: + quota: 50 + quotaPeriod: Total + Prune: + quota: 5 + quotaPeriod: PerDay + 5: + ChatBot: + quota: 1000000 + quotaPeriod: PerMonth + ReactionRole: + quota: 25 + quotaPeriod: Total + Prune: + quota: 2 + quotaPeriod: PerDay diff --git a/src/NadekoBot/data/strings/commands/commands.en-US.yml b/src/NadekoBot/data/strings/commands/commands.en-US.yml index b0f51c72d..a66e91468 100644 --- a/src/NadekoBot/data/strings/commands/commands.en-US.yml +++ b/src/NadekoBot/data/strings/commands/commands.en-US.yml @@ -1,51 +1,59 @@ h: - desc: Either shows a help for a single command, or DMs you help link if no parameters are specified. + desc: |- + Shows help for a single command. + Command help contains instructions on how to use the command with examples and a list of parameters. + DMs you helpful links if no parameters are specified. ex: - '{0}cmds' - '' params: + - com: + desc: "The command that help is being requested for." - fail: desc: "Fallback parameter if the command is not found." - - com: - desc: "The command information that the help is being requested for." gencmdlist: - desc: Generates the command list and sends it to the chat. Optionally also uploads it to DO spaces (not supported). + desc: Generates a json of the commands list and sends it to the chat. ex: - '' params: - {} donate: - desc: Instructions for helping the project financially. + desc: Provides instructions for helping the project financially. ex: - '' params: - {} modules: - desc: Lists all bot modules. + desc: |- + List all of the bot's modules. + Each module contains commands that you can use. ex: - '' params: - page: - desc: "The number of the page to display in the list of bot modules." + desc: "The page number to display in the list of modules." commands: - desc: List all of the bot's commands from the specified module. You can either specify the full name or only the first few letters of the module name. Specifying no module will show the list of modules instead. + desc: |- + List all of the bot's commands in the specified module. + You can either specify the full name or only the first few letters of the module name. + Specifying no module will show the list of modules instead. ex: - Admin - Admin --view 1 - '' params: - module: - desc: "The name of a module to retrieve command information for." + desc: "The name of the module to retrieve commands from." params: - desc: "The names of one or more modules to retrieve commands from, allowing for partial matching and optional omission." + desc: "How to display the list of commands." greetdel: - desc: Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. + desc: Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to `0` to disable automatic deletion. ex: - 0 - 30 params: - timer: - desc: "The amount of time before greeting messages are automatically deleted from the chat." + desc: "The amount of seconds before greeting messages are automatically deleted." greet: desc: Toggles announcements on the current channel when someone joins the server. ex: @@ -54,11 +62,11 @@ greet: - {} greetmsg: desc: |- - Sets a new join announcement message which will be shown in the server's channel. - Type `%user.mention%` if you want to mention the new member. + Sets a new join announcement message which will be shown in the current channel. + Write `%user.mention%` if you want to mention the new member. Full list of placeholders can be found here - Using it with no message will show the current greet message. - You can use embed json from instead of a regular text, if you want the message to be embedded. + Using this command with no message will show the current greet message. + You can use embed json from instead of regular text, if you want the message to be embedded. ex: - Welcome, %user.mention%. params: @@ -72,16 +80,16 @@ bye: - {} byemsg: desc: |- - Sets a new leave announcement message. - Type `%user.mention%` if you want to show the name the user who left. + Sets a new leave announcement message which will be shown in the current channel. + Type `%user.name%` to show the name of the user who left. Full list of placeholders can be found here Using this command with no message will show the current bye message. - You can use embed json from instead of a regular text, if you want the message to be embedded. + You can use embed json from instead of regular text, if you want the message to be embedded. ex: - - '%user.mention% has left.' + - '%user.name% has left.' params: - text: - desc: "The user's farewell message to display when they leave the chat." + desc: "The new announcement message to be displayed when a user leaves the server." byedel: desc: Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. ex: @@ -89,9 +97,9 @@ byedel: - 30 params: - timer: - desc: "The amount of time before a bye message is automatically deleted." + desc: "The amount of seconds before goodbye messages are automatically deleted." greetdm: - desc: Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). + desc: Toggles whether greet messages will be sent in a DM (This is separate from `{0}greet` - you can have both, one or neither enabled). ex: - '' params: @@ -103,7 +111,7 @@ greettest: - '@SomeoneElse' params: - user: - desc: "The user to impersonate when sending the greeting, or null for the bot's own account." + desc: "The user to impersonate when sending the greeting, defaulting to yourself if not specified." greetdmtest: desc: Sends the greet direct message to you as if you just joined the server. You can optionally specify a different user. ex: @@ -111,7 +119,7 @@ greetdmtest: - '@SomeoneElse' params: - user: - desc: "The recipient of the greeting, which defaults to the caller if not specified." + desc: "The recipient of the greeting, defaulting to yourself if not specified." byetest: desc: Sends the bye message in the current channel as if you just left the server. You can optionally specify a different user. ex: @@ -119,7 +127,7 @@ byetest: - '@SomeoneElse' params: - user: - desc: "The user who is leaving the channel, or whose account is being represented as leaving the channel." + desc: "The user to impersonate when sending the farewell, defaulting to yourself if not specified." boost: desc: Toggles announcements on the current channel when someone boosts the server. ex: @@ -128,16 +136,16 @@ boost: - {} boostmsg: desc: |- - Sets a new boost announcement message. - Type `%user.mention%` if you want to show the name the user who left. + Sets a new boost announcement message which will be shown in the current channel. + Type `%user.mention%` if you want to mention the booster. Full list of placeholders can be found here Using this command with no message will show the current boost message. - You can use embed json from instead of a regular text, if you want the message to be embedded. + You can use embed json from instead of regular text, if you want the message to be embedded. ex: - '%user.mention% has boosted the server!!!' params: - text: - desc: "The text to set as the new announcement message." + desc: "The new announcement message to be displayed when a user boosts the server." boostdel: desc: Sets the time it takes (in seconds) for boost messages to be auto-deleted. Set it to `0` to disable automatic deletion. ex: @@ -145,7 +153,7 @@ boostdel: - 30 params: - timer: - desc: "The amount of time before boost messages are automatically deleted." + desc: "The amount of seconds before boost messages are automatically deleted." logserver: desc: Enables or Disables ALL log events. If enabled, all log events will log to this channel. ex: @@ -153,9 +161,9 @@ logserver: - disable params: - action: - desc: "The type of action to take on the log event." + desc: "The type of action to take." logignore: - desc: Toggles whether the `{0}logserver` command ignores the specified channel or user. Provide no arguments to see the list of currently ignored users and channels + desc: Toggles whether the `{0}log` and `{0}logserver` commands ignore the specified channel or user. Provide no arguments to see the list of currently ignored users and channels. ex: - '' - '@SomeUser' @@ -167,32 +175,32 @@ logignore: - target: desc: "The user or channel being targeted for logging ignore or inclusion." repeatlist: - desc: Shows currently repeating messages and their indexes. + desc: Lists currently repeating messages and their indexes. ex: - '' params: - {} repeatremove: - desc: Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + desc: Removes a repeating message by index. Use `{0}replst` to see indexes. ex: - 2 params: - index: - desc: "The index at which the repeating message should be removed." + desc: "The index of the repeating message to be removed." repeatinvoke: - desc: Immediately shows the repeat message on a certain index and restarts its timer. + desc: Immediately post the repeat message on a certain index and restarts its timer. ex: - 1 params: - index: - desc: "The index at which to display the repeat message." + desc: "The index of the repeating message to post." repeat: desc: |- - Repeat a message once every specified amount of time in the current channel. - You can specify a different channel as the first argument. - You can instead specify time of day for the message to be repeated daily (make sure you've set your server's timezone). - If you've specified time of day, you can still override the default daily interval with your own interval. - You can have up to 5 repeating messages on the server in total. + Repeat a message once per specified time increment in the current channel. + You can specify a different channel as the first argument instead. + You can also specify time of day for the message to be repeated daily (make sure you've set your server's `{0}timezone`). + If you specify time of day, you can still override the default daily interval with your own interval. + You can have up to 5 repeating messages on one server in total. ex: - Hello there - '#other-channel hello there' @@ -202,59 +210,63 @@ repeat: - '21:00 30m Starting at 21 and every 30 minutes after that i will send this message!' params: - message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be repeated." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be sent." interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be repeated." timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be repeated." timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." repeatredundant: - desc: Specify repeater's index (use `{0}repli` to find it) to toggle whether that repeater's message should be reposted if the last message in the channel is the same repeater's message. This is useful if you want to remind everyone to be nice in the channel every so often, but don't want to have the bot spam the channel. This is NOT useful if you want to periodically ping someone. + desc: |- + Specify repeater's index (Use `{0}replst` to see indexes) to toggle whether the message should be reposted if the last message in the channel is the same repeater's message. + This is useful if you want to remind everyone to be nice every so often, but don't want to have the bot spam the channel. This is NOT useful if you want to periodically ping someone. ex: - 1 params: - index: - desc: "The number of times a message should be repeated before reposting." + desc: "The index of the repeating message to modify." repeatskip: - desc: Specify a repeater's ID to toggle whether the next trigger of the repeater will be skipped. This setting is not stored in the database and will get reset if the bot is restarted. + desc: |- + Specify a repeater's ID to toggle whether the next trigger of the repeater will be skipped. + This setting is not stored in the database and will get reset if the bot is restarted. ex: - 3 params: - index: - desc: "The number of times to skip before triggering again." + desc: "The index of the repeating message to skip." rotateplaying: desc: Toggles rotation of playing status of the dynamic strings you previously specified. ex: @@ -262,28 +274,28 @@ rotateplaying: params: - {} addplaying: - desc: Adds a specified string to the list of playing strings to rotate. You have to pick either 'Playing', 'Watching' or 'Listening' as the first parameter. + desc: Adds a specified string to the list of playing strings to rotate. You have to pick either `Playing`, `Watching` or `Listening` as the first parameter. ex: - Playing with you - Watching you sleep params: - t: - desc: "The type of status, allowed values are 'Playing', 'Watching', or 'Listening'." + desc: "The type of status, allowed values are `Playing`, `Watching`, or `Listening`." status: desc: "The status text." listplaying: - desc: Lists all playing statuses with their corresponding number. + desc: Lists all playing statuses and their indexes. ex: - '' params: - {} removeplaying: - desc: Removes a playing string on a given number. + desc: Removes a playing status by index. Use `{0}lipl` to see indexes. ex: - '' params: - index: - desc: "The position in the list where the playing string should be removed." + desc: "The index of the playing string to be removed." vcrolelist: desc: Shows a list of currently set voice channel roles. ex: @@ -297,16 +309,16 @@ vcrole: - '' params: - role: - desc: "The role that is assigned to new members of the voice channel." + desc: "The role to assign to users who join the voice channel." vcrolerm: - desc: Removes vcrole associated with the specified voice channel ID. This is useful if your vcrole has been enabled on a VC which has been deleted. + desc: Removes any `{0}vcrole` associated with the specified channel ID. This is useful if your vcrole has been enabled on a VC which has been deleted. ex: - 123123123123123 params: - vcId: - desc: "The unique identifier of the voice channel to remove the vcrole from." + desc: "The voice channel ID to remove the vcrole from." asar: - desc: Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled, users will be able to pick one role per group. + desc: Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled (`{0}tesar`), users will be able to pick one role per group. ex: - Gamer - 1 Alliance @@ -315,7 +327,7 @@ asar: - role: desc: "The role that can be assigned by the user." - group: - desc: "The ID of a group that the new role should belong to." + desc: "The ID of a group that the designated role should belong to." role: desc: "The role that can be assigned by the user." rsar: @@ -326,7 +338,7 @@ rsar: - Horde params: - role: - desc: "The role being removed from the list of self-assignable roles." + desc: "The role to remove from the list of self-assignable roles." lsar: desc: Lists self-assignable roles. Shows 20 roles per page. ex: @@ -334,7 +346,7 @@ lsar: - 2 params: - page: - desc: "The current page number for the list of roles." + desc: "The page number to show." sargn: desc: Sets a self assignable role group name. Provide no name to remove. ex: @@ -342,59 +354,58 @@ sargn: - 2 params: - group: - desc: "The ID of the group to set as self-assignable." + desc: "The ID of the group to name." name: - desc: "The name of the new or existing role group to set." + desc: "The name to assign." togglexclsar: - desc: Toggles whether the self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group. + desc: Toggles whether self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group. ex: - '' params: - {} iam: - desc: Adds a role to you that you choose. Role must be on a list of self-assignable roles. + desc: Adds a role to you that you choose. Role must be on the list of self-assignable roles. ex: - Gamer params: - role: - desc: "The type of access or permission granted to the user." + desc: "The role to assign." iamnot: - desc: Removes a specified role from you. Role must be on a list of self-assignable roles. + desc: Removes a specified role from you. Role must be on the list of self-assignable roles. ex: - Gamer params: - role: - desc: "The role being removed from the user's assignment." + desc: "The role to remove." expradd: - desc: 'Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide here: ' + desc: 'Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in a server requires the Administrator permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide [here]()' ex: - '"hello" Hi there %user.mention%' params: - trigger: - desc: "The trigger word that sets off the response when typed by a user." + desc: "The trigger word or phrase for the bot to respond to users typing." response: desc: "The text of the message that shows up when a user types the trigger word." expraddserver: - desc: 'Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. Guide here: ' + desc: 'Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. This command is useful if you want to lower the permission requirement for managing expressions by using `{0}dpo`. Guide [here]().' ex: - '"hello" Hi there %user.mention%' params: - key: - desc: "The unique identifier for the expression to be added in this server." + desc: "The trigger word or phrase for the bot to respond to users typing." message: - desc: "The text of the message that triggers the bot's response." + desc: "The text of the message that shows up when a user types the trigger word." exprlist: desc: |- - Lists global or server expressions (20 commands per page). + Lists global or server expressions (20 expressions per page). Running the command in DM will list global expressions, while running it in a server will list server expressions. Shows enabled settings, followed by id, followed by the trigger. **Settings:** - • 🗯️ Triggered if trigger matches any word (`{0}h {0}exca`) - • ✉️ Response will be DMed (`{0}h {0}exdm`) - • ❌ Trigger will be deleted (`{0}h {0}exad`) + • 🗯️ Triggered if trigger matches any phrase (`{0}h exca`) + • ✉️ Response will be DMed (`{0}h exdm`) + • ❌ Trigger message will be deleted (`{0}h exad`) ex: - 1 - - all params: - page: desc: "The number of pages to display in the list." @@ -404,21 +415,21 @@ exprshow: - 1 params: - id: - desc: "The identifier for the entity whose response is being displayed." + desc: "The expression ID to show." exprdelete: - desc: Deletes an expression on a specific index. If ran in DM, it is bot owner only and deletes a global expression. If ran in a server, it requires Administration privileges and removes server expression. + desc: Deletes an expression by index. If ran in DM, it is bot owner only and deletes a global expression. Running this command in a server requires the Administrator permission and deletes a server expression. ex: - 5 params: - id: - desc: "The identifier of the expression to be deleted." + desc: "The ID of the expression to delete." exprdeleteserver: - desc: Deletes an expression on a specific index on this server. + desc: Deletes an expression on a specific index on this server. This command is useful if you want to lower the permission requirement for managing expressions by using `{0}dpo`. ex: - 5c params: - id: - desc: "The identifier of the expression to be deleted." + desc: "The ID of the expression to delete." exprclear: desc: Deletes all expression on this server. ex: @@ -843,7 +854,12 @@ savechat: - cnt: desc: "The number of messages to be saved." remind: - desc: "Sends a message to you or a channel after certain amount of time (max 2 months). First parameter is `me`/`here`/'channelname'. Second parameter is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third parameter is a (multiword) message. Requires ManageMessages server permission if you're targeting a different channel." + desc: |- + Sets a reminder which will be sent to you or to the targeted channel after certain amount of time (max 2 months). + First parameter is `me` / `here` / 'channelname' + Second parameter is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. + Third parameter is a (multiword) message. + Requires ManageMessages server permission if you're targeting a different channel. ex: - me 1d5h Do something - '#general 1m Start now!' @@ -1336,7 +1352,11 @@ flip: - count: desc: "The number of times the coin is flipped." betflip: - desc: Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. + desc: |- + Bet to guess will the result be heads or tails. + Guessing awards you 1.95x the currency you've bet (rounded up). + Multiplier can be changed by the bot owner. + ex: - 5 heads - 3 t @@ -1482,38 +1502,52 @@ take: usrId: desc: "The ID of the user whose funds are being taken." betroll: - desc: Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. + desc: |- + Bets the specified amount of currency and rolls a dice. + Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - 5 params: - amount: desc: "The amount to be wagered on the roll of the dice." luckyladder: - desc: Bets a certain amount of currency on the lucky ladder. You can stop on one of many different multipliers. Won amount is rounded down to the nearest whole number. + desc: + Bets the specified amount of currency on the lucky ladder. + You can stop on one of many different multipliers. + The won amount is rounded down to the nearest whole number. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - 10 params: - amount: desc: "The total value of the bet being placed." leaderboard: - desc: Displays the bot's currency leaderboard. + desc: |- + Displays the bot's currency leaderboard, or in other words, the richest users. + Specifying -c flag will show only users who are in this server. + Paginated with 10 users per page. ex: - '' + - '-c' params: - params: - desc: "The list of player names or IDs to display in the leaderboard." + desc: "Optional -c flag" - page: - desc: "The number of pages to display in the leaderboard." + desc: "The page number to display." params: - desc: "The list of player names or IDs to display in the leaderboard." + desc: "Optional -c flag." trivia: - desc: Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. + desc: |- + Starts a game of trivia. + First player to get to 10 points wins by default. + 30 seconds per question. ex: - '' - --timeout 5 -p -w 3 -q 10 params: - params: - desc: "The list of questions and answers for the trivia game." + desc: "Options. --timeout , --pokemon, --win --question " tl: desc: Shows a current trivia leaderboard. ex: @@ -1585,7 +1619,10 @@ choose: - list: desc: "The type of items in the collection being searched." rps: - desc: Play a game of Rocket-Paperclip-Scissors with Nadeko. You can bet on it. Multiplier is the same as on betflip. + desc: |- + Play a game of Rocket-Paperclip-Scissors with Nadeko. + You can bet on it. Multiplier is the same as on betflip. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - r 100 - scissors @@ -1593,7 +1630,7 @@ rps: - pick: desc: "The user's chosen move in the game, such as rock, paper or scissors." amount: - desc: "The stake to be wagered on the outcome of the game." + desc: "Optional amount of currency to be wagered on the outcome of the game." next: desc: Goes to the next song in the queue. You have to be in the same voice channel as the bot ex: @@ -1601,7 +1638,12 @@ next: params: - {} play: - desc: If no parameters are specified, acts as `{0}next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `{0}q` command + desc: |- + Queues up and plays a song or video based on a search query, song name, artist name or youtube link. + If no parameters are specified, it will skip the current song. + If you specify a song number, it will jump to that song. + If you specify a search query, acts as a `{0}q` command + **You must be in a voice channel**. ex: - '' - 5 @@ -1631,7 +1673,10 @@ pause: params: - {} queue: - desc: Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. + desc: |- + Queues up and plays a song or video based on a search query, song name, artist name, search query or youtube link. + Bot will join your voice channel. + **You must be in a voice channel**. ex: - Dream Of Venice params: @@ -1946,12 +1991,12 @@ memegen: memeText: desc: "The user-provided text to be displayed on the generated meme." weather: - desc: Shows weather data for a specified city. You can also specify a country after a comma. + desc: Shows current weather data for the specified city. ex: - Moscow, RU params: - query: - desc: "The location to retrieve weather information for." + desc: "The name of the place or city for which to show the weather data." youtube: desc: Searches youtubes and shows the first result ex: @@ -2142,7 +2187,9 @@ greetdmmsg: - text: desc: "The new join announcement message that will be sent to the user who joined." cash: - desc: Check how much currency a person has. If no argument is provided it will check your own balance. + desc: |- + Check how much currency a person has. + If no argument is provided it will check your own balance. ex: - '' - '@Someone' @@ -2493,7 +2540,10 @@ listservers: - page: desc: "The number of pages to retrieve from the server list." cleverbot: - desc: Toggles cleverbot/chatgpt session. When enabled, the bot will reply to messages starting with bot mention in the server. Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled. + desc: |- + Toggles cleverbot/chatgpt session. + When enabled, the bot will reply to messages starting with bot mention in the server. + Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled. ex: - '' params: @@ -2628,7 +2678,9 @@ antispamignore: params: - {} eventstart: - desc: 'Starts one of the events seen on public nadeko. Events: `reaction`, `gamestatus`' + desc: |- + Starts one of the events seen on public Nadeko. + Events: `reaction`, `gamestatus` ex: - reaction - reaction -d 1 -a 50 --pot-size 1500 @@ -2636,20 +2688,24 @@ eventstart: - ev: desc: "The type of event being started." options: - desc: "The types of events that can be started." + desc: "The optional option flags for the event." betstats: - desc: Shows the total stats of several gambling features. Updates once an hour. + desc: |- + Shows the total stats of several gambling features. + Updates once an hour. ex: - '' params: - {} slot: - desc: Play Nadeko slots. 1 second cooldown per user. + desc: |- + Play Nadeko slots by placing your bet. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - 5 params: - amount: - desc: "The number of spins to perform in the game." + desc: "The amount of currency to bet." affinity: desc: Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. Provide no parameters to clear your affinity. 30 minutes cooldown. ex: @@ -2687,7 +2743,11 @@ waifutransfer: newOwner: desc: "The user to whom ownership of the waifu is being transferred." waifugift: - desc: -| Gift an item to someone. This will increase their waifu value by a percentage of the gift's value. Negative gifts will not show up in waifuinfo. Provide no parameters to see a list of items that you can gift. + desc: -| + Gift an item to someone. + This will increase their waifu value by a percentage of the gift's value. + Negative gifts will not show up in waifuinfo. + Provide no parameters to see a list of items that you can gift. ex: - '' - Rose @Himesama @@ -2782,7 +2842,10 @@ restartshard: - shardId: desc: "The ID of the shard to be restarted or reconnected." tictactoe: - desc: Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. + desc: |- + Starts a game of tic tac toe. + Another user must run the command in the same channel in order to accept the challenge. + Use numbers 1-9 to play. ex: - '' params: @@ -3146,27 +3209,38 @@ shop: - page: desc: "The number of the page to retrieve from the list of administrators' shops." shopadd: - desc: "- Available types are role, list and command.\n- If the item is a role, specify a role id or a role name.\n- If the item is a command, specify the full command, replacing the user with %user% (for a mention) or %user.id% for user id.\n90% of currency from each purchase will be received by the user who added the item to the shop. " + desc: |- + Adds an item to the shop. + First you begin by specifying the type of the item you wish to add. + Available types are role, list and command. + If the item is a role, specify a role id or a role name. + In case you're selling a command, and you need user's name, id etc, you can use the following placeholders: + - `%you%` - Buyer mention + - `%you.id%` - Buyer's user ID + - `%you.username%` - Buyer's username + - `%you.name%` - Buyer's global name + - `%you.nick%` - Buyer's display name + 90% of currency from each purchase will be received by the user who added the item to the shop. This is configurable by the bot owner ex: - role 1000 Rich - cmd 1000 .setrole %user% Rich params: - _: - desc: "The command to be executed when an item is purchased." + desc: "This value has to be 'cmd'" price: - desc: "The cost at which the item is available for purchase." + desc: "The cost at which the command is available for purchase." command: - desc: "The full command, replacing the user with %user% (for a mention) or %user.id% for user id. This allows users to specify custom" + desc: "The full command, replacing the buyer info (if required) with some of the special %you% placeholders." - _: - desc: "The role that should be granted to users when they purchase this item." + desc: "This value has to be 'list'" price: desc: "The cost at which the item is available for purchase." role: - desc: "The ID or name of a predefined role in the system, used to specify the type of item being added to the shop." + desc: "The item (text) that is being sold." - _: - desc: "The list of items to be added to the shop." + desc: "This value has to be 'role'" price: - desc: "The cost at which the item is available for purchase." + desc: "The cost at which the role is available for purchase." name: desc: "The name of the role, command, or list being added to the shop." shopremove: @@ -3359,7 +3433,7 @@ experience: - '@someguy' params: - user: - desc: "The ID or handle of a player whose XP statistics are being displayed." + desc: "Optional name, mention or ID of the user" xptemplatereload: desc: Reloads the xp template file. Xp template file allows you to customize the position and color of elements on the `{0}xp` card. ex: @@ -3803,7 +3877,10 @@ timelyset: period: desc: "The time period within which a user's timely currency allowance can be used." timely: - desc: Use to claim your 'timely' currency. Bot owner has to specify the amount and the period on how often you can claim your currency. + desc: |- + Use to claim your timely currency. + This is usually set by the bot owners to be daily, hourly or once every 12 hours. + Bot owner has to specify the amount and the period on how often you can claim your currency. ex: - '' params: @@ -3848,40 +3925,12 @@ massban: - userStrings: desc: "The list of user IDs to ban, provided as a comma-separated string." masskill: - desc: Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their flowers taken away. + desc: Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their currency taken away. ex: - BadPerson#1234 Toxic person params: - people: desc: "The list of user IDs or usernames to ban from the server and blacklist from the bot." -pathofexile: - desc: Searches characters for a given Path of Exile account. May specify league name to filter results. - ex: - - '"Zizaran"' - params: - - usr: - desc: "The username or email address associated with the Path of Exile account being searched." - league: - desc: "The league in which the character is playing, allowing users to focus on a specific game mode or event." - page: - desc: "The number of pages to retrieve from the API." -pathofexileleagues: - desc: Returns a list of the main Path of Exile leagues. - ex: - - '' - params: - - {} -pathofexilecurrency: - desc: Returns the chaos equivalent of a given currency or exchange rate between two currencies. - ex: - - Standard "Mirror of Kalandra" - params: - - leagueName: - desc: "The name of the league in which the currency is used, such as \"Harbinger\" or \"Delve\"." - currencyName: - desc: "The type of currency being converted." - convertName: - desc: "The type of currency being converted from or to." rollduel: desc: Challenge someone to a roll duel by specifying the amount and the user you wish to challenge as the parameters. To accept the challenge, just specify the name of the user who challenged you, without the amount. ex: @@ -3946,12 +3995,17 @@ rerotransfer: toMessageId: desc: "The ID of the target message where the reaction roles should be transferred." blackjack: - desc: Start or join a blackjack game. You must specify the amount you're betting. Use `{0}hit`, `{0}stand` and `{0}double` commands to play. Game is played with 4 decks. Dealer hits on soft 17 and wins draws. + desc: |- + Start or join a blackjack game by specifying the amount you're betting. + You must specify the amount you're betting. + Use `{0}hit`, `{0}stand` and `{0}double` commands to play. + Game is played with 4 decks. + Dealer hits on soft 17 and wins draws. ex: - 50 params: - amount: - desc: "The minimum bet required to participate in the game." + desc: "The amount you want to bet in the blackjack game." hit: desc: In the blackjack game, ask the dealer for an extra card. ex: @@ -4184,7 +4238,10 @@ bankwithdraw: - amount: desc: "The amount of money to be withdrawn." bankbalance: - desc: Shows your current bank balance available for withdrawal. + desc: |- + Shows how much currency is in your bank account. + This differs from your cash amount, as the cash amount is publicly available, but only you have access to your bank balance. + However, you have to withdraw it first in order to use it. ex: - '' params: @@ -4456,4 +4513,14 @@ cleanupguilddata: ex: - '' params: - - {} \ No newline at end of file + - {} +prompt: + desc: |- + Ask the bot to do something for you. + This will fall back to the chatbot service in case of an error. + ex: + - What's the weather like today? + params: + - query: + desc: "The message to send to the bot." + \ No newline at end of file diff --git a/src/NadekoBot/data/strings/responses/responses.en-US.json b/src/NadekoBot/data/strings/responses/responses.en-US.json index 7fd3434bb..013120a54 100644 --- a/src/NadekoBot/data/strings/responses/responses.en-US.json +++ b/src/NadekoBot/data/strings/responses/responses.en-US.json @@ -345,8 +345,8 @@ "submissions_closed": "Submissions closed", "animal_race_already_started": "Animal Race is already running.", "category": "Category", - "cleverbot_disabled": "Disabled cleverbot on this server.", - "cleverbot_enabled": "Enabled cleverbot on this server.", + "chatbot_disabled": "Disabled chatbot on this server.", + "chatbot_enabled": "Enabled chatbot on this server.", "curgen_disabled": "Currency generation has been disabled on this channel.", "curgen_enabled": "Currency generation has been enabled on this channel.", "curgen_pl": "{0} random {1} appeared!", @@ -619,7 +619,7 @@ "quote_deleted": "Quote #{0} deleted.", "quote_edited": "Quote Edited", "region": "Region", - "remind": "I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})`", + "remind2": "I will remind {0} to {1} {2} ({3})`", "remind_timely": "I will remind you about your timely reward {0}", "remind_invalid": "Not a valid remind format. Remind must have a target, timer and a reason. Check the command list.", "remind_too_long": "Remind time has exceeded maximum.", @@ -1045,7 +1045,7 @@ "cmd_group_commands": "'{0}' command group", "limit_reached": "Feature limit of {0} reached.", "feature_limit_reached_you": "You've reached the limit of {0} for the {1} feature. You may be able to increase this limit by upgrading your patron tier.", - "feature_limit_reached_owner": "Server owner has reached the limit of {0} for the {1} feature. Server owner may be able to upgrade this limit by upgrading patron tier.", + "feature_limit_reached_owner": "Feature limit reached. Server owner may upgrade patron level to increase the limit.", "feature_limit_reached_either": "The limit of {0} for the {1} feature has been reached. Either you or the server owner may able to upgrade this limit by upgrading the patron tier.", "xp_shop_buy_required_tier": "Buying items from this shop requires Patron Tier {0} or higher.", "available_commands": "Available Commands",