From 29f97f37326ab6250850a511a7feb3e495df2843 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 27 Oct 2017 18:39:56 +0200 Subject: [PATCH] Polls persist restarts now. --- .../Common/Collections/IndexedCollection.cs | 4 + .../20171027155001_poll-rewrite.Designer.cs | 1992 +++++++++++++++++ .../Migrations/20171027155001_poll-rewrite.cs | 100 + .../NadekoSqliteContextModelSnapshot.cs | 75 + NadekoBot.Core/Modules/Games/Common/Poll.cs | 129 -- .../Modules/Games/Common/PollRunner.cs | 72 + NadekoBot.Core/Modules/Games/PollCommands.cs | 79 +- .../Modules/Games/Services/PollService.cs | 83 +- .../Services/Database/IUnitOfWork.cs | 1 + .../Services/Database/Models/Poll.cs | 7 +- .../Services/Database/Models/PollVote.cs | 25 +- .../Services/Database/NadekoContext.cs | 6 + .../Database/Repositories/IPollsRepository.cs | 15 + .../Repositories/Impl/PollsRepository.cs | 35 + .../Services/Database/UnitOfWork.cs | 3 + .../_strings/ResponseStrings.en-US.json | 3 +- 16 files changed, 2461 insertions(+), 168 deletions(-) create mode 100644 NadekoBot.Core/Migrations/20171027155001_poll-rewrite.Designer.cs create mode 100644 NadekoBot.Core/Migrations/20171027155001_poll-rewrite.cs delete mode 100644 NadekoBot.Core/Modules/Games/Common/Poll.cs create mode 100644 NadekoBot.Core/Modules/Games/Common/PollRunner.cs create mode 100644 NadekoBot.Core/Services/Database/Repositories/IPollsRepository.cs create mode 100644 NadekoBot.Core/Services/Database/Repositories/Impl/PollsRepository.cs diff --git a/NadekoBot.Core/Common/Collections/IndexedCollection.cs b/NadekoBot.Core/Common/Collections/IndexedCollection.cs index 31ad1f3d..64948970 100644 --- a/NadekoBot.Core/Common/Collections/IndexedCollection.cs +++ b/NadekoBot.Core/Common/Collections/IndexedCollection.cs @@ -10,6 +10,10 @@ namespace NadekoBot.Common.Collections public List Source { get; } private readonly object _locker = new object(); + public IndexedCollection() + { + Source = new List(); + } public IndexedCollection(IEnumerable source) { lock (_locker) diff --git a/NadekoBot.Core/Migrations/20171027155001_poll-rewrite.Designer.cs b/NadekoBot.Core/Migrations/20171027155001_poll-rewrite.Designer.cs new file mode 100644 index 00000000..d7348099 --- /dev/null +++ b/NadekoBot.Core/Migrations/20171027155001_poll-rewrite.Designer.cs @@ -0,0 +1,1992 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using NadekoBot.Core.Services.Database; +using NadekoBot.Core.Services.Database.Models; +using System; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20171027155001_poll-rewrite")] + partial class pollrewrite + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.Property("MuteTime"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlockedCmdOrMdl", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("BotConfigId1"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("BotConfigId1"); + + b.ToTable("BlockedCmdOrMdl"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyDropAmountMax"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("CustomReactionsStartWith"); + + b.Property("DMHelpString"); + + b.Property("DateAdded"); + + b.Property("DefaultPrefix"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("PermissionVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TimelyCurrency"); + + b.Property("TimelyCurrencyPeriod"); + + b.Property("TriviaCurrencyReward"); + + b.Property("XpMinutesTimeout") + .ValueGeneratedOnAdd() + .HasDefaultValue(5); + + b.Property("XpPerMessage") + .ValueGeneratedOnAdd() + .HasDefaultValue(3); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClubApplicants", b => + { + b.Property("ClubId"); + + b.Property("UserId"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubApplicants"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClubBans", b => + { + b.Property("ClubId"); + + b.Property("UserId"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubBans"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Discrim"); + + b.Property("ImageUrl"); + + b.Property("MinimumLevelReq"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20); + + b.Property("OwnerId"); + + b.Property("Xp"); + + b.HasKey("Id"); + + b.HasAlternateKey("Name", "Discrim"); + + b.HasIndex("OwnerId") + .IsUnique(); + + b.ToTable("Clubs"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoDeleteTrigger"); + + b.Property("ContainsAnywhere"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("ClubId"); + + b.Property("DateAdded"); + + b.Property("Discriminator"); + + b.Property("IsClubAdmin"); + + b.Property("LastLevelUp") + .ValueGeneratedOnAdd() + .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 305, DateTimeKind.Local)); + + b.Property("LastXpGain"); + + b.Property("NotifyOnLevelUp"); + + b.Property("TotalXp"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.HasIndex("ClubId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("ItemType"); + + b.Property("XpSettingsId"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId"); + + b.ToTable("ExcludedItem"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Url") + .IsRequired(); + + b.HasKey("Id"); + + b.HasAlternateKey("GuildConfigId", "Url"); + + b.ToTable("FeedSub"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDcFromVc"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GameVoiceChannel"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("Prefix"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerboseErrors"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.Property("StartTimeOfDay"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LoadedPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("LoadedPackages"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("DateAdded"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.NsfwBlacklitedTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Tag"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("NsfwBlacklitedTag"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Poll", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Question"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("Poll"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Index"); + + b.Property("PollId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("PollId"); + + b.ToTable("PollAnswer"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollVote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("PollId"); + + b.Property("UserId"); + + b.Property("VoteIndex"); + + b.HasKey("Id"); + + b.HasIndex("PollId"); + + b.ToTable("PollVote"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("PatreonUserId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Group") + .ValueGeneratedOnAdd() + .HasDefaultValue(0); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("Name"); + + b.Property("Price"); + + b.Property("RoleId"); + + b.Property("RoleName"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ShopEntryId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("StreamRoleSettingsId"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleBlacklistedUser"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddRoleId"); + + b.Property("DateAdded"); + + b.Property("Enabled"); + + b.Property("FromRoleId"); + + b.Property("GuildConfigId"); + + b.Property("Keyword"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("StreamRoleSettingsId"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleWhitelistedUser"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AwardedXp"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("LastLevelUp") + .ValueGeneratedOnAdd() + .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 307, DateTimeKind.Local)); + + b.Property("NotifyOnLevelUp"); + + b.Property("UserId"); + + b.Property("Xp"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "GuildId") + .IsUnique(); + + b.ToTable("UserXpStats"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Item"); + + b.Property("ItemEmoji"); + + b.Property("Price"); + + b.Property("WaifuInfoId"); + + b.HasKey("Id"); + + b.HasIndex("WaifuInfoId"); + + b.ToTable("WaifuItem"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Level"); + + b.Property("RoleId"); + + b.Property("XpSettingsId"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId", "Level") + .IsUnique(); + + b.ToTable("XpRoleReward"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("NotifyMessage"); + + b.Property("ServerExcluded"); + + b.Property("XpRoleRewardExclusive"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Core.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Core.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlockedCmdOrMdl", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("BlockedCommands") + .HasForeignKey("BotConfigId"); + + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("BlockedModules") + .HasForeignKey("BotConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClubApplicants", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClubBans", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClubInfo", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("NadekoBot.Core.Services.Database.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.DiscordUser", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.ClubInfo", "Club") + .WithMany("Users") + .HasForeignKey("ClubId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ExcludedItem", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FeedSub", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LoadedPackage", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("LoadedPackages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.NsfwBlacklitedTag", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("NsfwBlacklistedTags") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollAnswer", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.Poll") + .WithMany("Answers") + .HasForeignKey("PollId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollVote", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.Poll") + .WithMany("Votes") + .HasForeignKey("PollId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ShopEntry", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.ShopEntry") + .WithMany("Items") + .HasForeignKey("ShopEntryId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StreamRoleSettings", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("NadekoBot.Core.Services.Database.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Core.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WaifuItem", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Core.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpRoleReward", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.XpSettings", "XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpSettings", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("NadekoBot.Core.Services.Database.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/NadekoBot.Core/Migrations/20171027155001_poll-rewrite.cs b/NadekoBot.Core/Migrations/20171027155001_poll-rewrite.cs new file mode 100644 index 00000000..51e612d4 --- /dev/null +++ b/NadekoBot.Core/Migrations/20171027155001_poll-rewrite.cs @@ -0,0 +1,100 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace NadekoBot.Migrations +{ + public partial class pollrewrite : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Poll", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChannelId = table.Column(type: "INTEGER", nullable: false), + DateAdded = table.Column(type: "TEXT", nullable: true), + GuildId = table.Column(type: "INTEGER", nullable: false), + Question = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Poll", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "PollAnswer", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(type: "TEXT", nullable: true), + Index = table.Column(type: "INTEGER", nullable: false), + PollId = table.Column(type: "INTEGER", nullable: true), + Text = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PollAnswer", x => x.Id); + table.ForeignKey( + name: "FK_PollAnswer_Poll_PollId", + column: x => x.PollId, + principalTable: "Poll", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "PollVote", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(type: "TEXT", nullable: true), + PollId = table.Column(type: "INTEGER", nullable: true), + UserId = table.Column(type: "INTEGER", nullable: false), + VoteIndex = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PollVote", x => x.Id); + table.ForeignKey( + name: "FK_PollVote_Poll_PollId", + column: x => x.PollId, + principalTable: "Poll", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_Poll_GuildId", + table: "Poll", + column: "GuildId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_PollAnswer_PollId", + table: "PollAnswer", + column: "PollId"); + + migrationBuilder.CreateIndex( + name: "IX_PollVote_PollId", + table: "PollVote", + column: "PollId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PollAnswer"); + + migrationBuilder.DropTable( + name: "PollVote"); + + migrationBuilder.DropTable( + name: "Poll"); + } + } +} diff --git a/NadekoBot.Core/Migrations/NadekoSqliteContextModelSnapshot.cs b/NadekoBot.Core/Migrations/NadekoSqliteContextModelSnapshot.cs index 3f7949b1..ba578fa7 100644 --- a/NadekoBot.Core/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/NadekoBot.Core/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -983,6 +983,67 @@ namespace NadekoBot.Migrations b.ToTable("PlaylistSong"); }); + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Poll", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Question"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("Poll"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Index"); + + b.Property("PollId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("PollId"); + + b.ToTable("PollAnswer"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollVote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("PollId"); + + b.Property("UserId"); + + b.Property("VoteIndex"); + + b.HasKey("Id"); + + b.HasIndex("PollId"); + + b.ToTable("PollVote"); + }); + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b => { b.Property("Id") @@ -1771,6 +1832,20 @@ namespace NadekoBot.Migrations .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollAnswer", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.Poll") + .WithMany("Answers") + .HasForeignKey("PollId"); + }); + + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PollVote", b => + { + b.HasOne("NadekoBot.Core.Services.Database.Models.Poll") + .WithMany("Votes") + .HasForeignKey("PollId"); + }); + modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b => { b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig") diff --git a/NadekoBot.Core/Modules/Games/Common/Poll.cs b/NadekoBot.Core/Modules/Games/Common/Poll.cs deleted file mode 100644 index e1e3ee01..00000000 --- a/NadekoBot.Core/Modules/Games/Common/Poll.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Discord; -using Discord.WebSocket; -using NadekoBot.Extensions; -using NadekoBot.Core.Services.Impl; - -namespace NadekoBot.Modules.Games.Common -{ - public class Poll - { - private readonly IUserMessage _originalMessage; - private readonly IGuild _guild; - private readonly string[] answers; - private readonly ConcurrentDictionary _participants = new ConcurrentDictionary(); - private readonly string _question; - private readonly DiscordSocketClient _client; - private readonly NadekoStrings _strings; - private bool running = false; - - public event Action OnEnded = delegate { }; - - public Poll(DiscordSocketClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable enumerable) - { - _client = client; - _strings = strings; - - _originalMessage = umsg; - _guild = ((ITextChannel)umsg.Channel).Guild; - _question = question; - answers = enumerable as string[] ?? enumerable.ToArray(); - } - - public EmbedBuilder GetStats(string title) - { - var results = _participants.GroupBy(kvp => kvp.Value) - .ToDictionary(x => x.Key, x => x.Sum(kvp => 1)) - .OrderByDescending(kvp => kvp.Value) - .ToArray(); - - var eb = new EmbedBuilder().WithTitle(title); - - var sb = new StringBuilder() - .AppendLine(Format.Bold(_question)) - .AppendLine(); - - var totalVotesCast = 0; - if (results.Length == 0) - { - sb.AppendLine(GetText("no_votes_cast")); - } - else - { - for (int i = 0; i < results.Length; i++) - { - var result = results[i]; - sb.AppendLine(GetText("poll_result", - result.Key, - Format.Bold(answers[result.Key - 1]), - Format.Bold(result.Value.ToString()))); - totalVotesCast += result.Value; - } - } - - - eb.WithDescription(sb.ToString()) - .WithFooter(efb => efb.WithText(GetText("x_votes_cast", totalVotesCast))); - - return eb; - } - - public async Task StartPoll() - { - var msgToSend = GetText("poll_created", Format.Bold(_originalMessage.Author.Username)) + "\n\n" + Format.Bold(_question) + "\n"; - var num = 1; - msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n"); - msgToSend += "\n" + Format.Bold(GetText("poll_vote_public")); - - await _originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false); - running = true; - } - - public async Task StopPoll() - { - running = false; - OnEnded(_guild.Id); - await _originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false); - } - - public async Task TryVote(IUserMessage msg) - { - // has to be a user message - if (msg == null || msg.Author.IsBot || !running) - return false; - - // has to be an integer - if (!int.TryParse(msg.Content, out int vote)) - return false; - if (vote < 1 || vote > answers.Length) - return false; - - IMessageChannel ch; - //if public, channel must be the same the poll started in - if (_originalMessage.Channel.Id != msg.Channel.Id) - return false; - ch = msg.Channel; - - //user can vote only once - if (_participants.TryAdd(msg.Author.Id, vote)) - { - var toDelete = await ch.SendConfirmAsync(GetText("poll_voted", Format.Bold(msg.Author.ToString()))).ConfigureAwait(false); - toDelete.DeleteAfter(5); - try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } - return true; - } - return false; - } - - private string GetText(string key, params object[] replacements) - => _strings.GetText(key, - _guild.Id, - "Games".ToLowerInvariant(), - replacements); - } -} diff --git a/NadekoBot.Core/Modules/Games/Common/PollRunner.cs b/NadekoBot.Core/Modules/Games/Common/PollRunner.cs new file mode 100644 index 00000000..57bc658c --- /dev/null +++ b/NadekoBot.Core/Modules/Games/Common/PollRunner.cs @@ -0,0 +1,72 @@ +using System.Threading.Tasks; +using Discord; +using NadekoBot.Core.Services.Database.Models; +using NadekoBot.Core.Services; +using System; +using System.Threading; + +namespace NadekoBot.Modules.Games.Common +{ + public class PollRunner + { + public Poll Poll { get; } + private readonly DbService _db; + + public event Func OnVoted; + + private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1); + + public PollRunner(DbService db, Poll poll) + { + _db = db; + Poll = poll; + } + + public async Task TryVote(IUserMessage msg) + { + PollVote voteObj; + await _locker.WaitAsync().ConfigureAwait(false); + try + { + // has to be a user message + // channel must be the same the poll started in + if (msg == null || msg.Author.IsBot || msg.Channel.Id != Poll.ChannelId) + return false; + + // has to be an integer + if (!int.TryParse(msg.Content, out int vote)) + return false; + --vote; + if (vote < 0 || vote >= Poll.Answers.Count) + return false; + + var usr = msg.Author as IGuildUser; + if (usr == null) + return false; + + voteObj = new PollVote() + { + UserId = msg.Author.Id, + VoteIndex = vote, + }; + if (!Poll.Votes.Add(voteObj)) + return false; + + var _ = OnVoted?.Invoke(msg, usr); + } + finally { _locker.Release(); } + using (var uow = _db.UnitOfWork) + { + var trackedPoll = uow.Polls.Get(Poll.Id); + trackedPoll.Votes.Add(voteObj); + uow.Complete(); + } + return true; + } + + public void End() + { + OnVoted = null; + } + } +} diff --git a/NadekoBot.Core/Modules/Games/PollCommands.cs b/NadekoBot.Core/Modules/Games/PollCommands.cs index 471e2222..d375d55c 100644 --- a/NadekoBot.Core/Modules/Games/PollCommands.cs +++ b/NadekoBot.Core/Modules/Games/PollCommands.cs @@ -5,6 +5,9 @@ using NadekoBot.Extensions; using System.Threading.Tasks; using NadekoBot.Common.Attributes; using NadekoBot.Modules.Games.Services; +using NadekoBot.Core.Services.Database.Models; +using System.Text; +using System.Linq; namespace NadekoBot.Modules.Games { @@ -23,24 +26,33 @@ namespace NadekoBot.Modules.Games [NadekoCommand, Usage, Description, Aliases] [RequireUserPermission(GuildPermission.ManageMessages)] [RequireContext(ContextType.Guild)] - public Task Poll([Remainder] string arg = null) - => InternalStartPoll(arg); + public async Task Poll([Remainder] string arg) + { + if (string.IsNullOrWhiteSpace(arg)) + return; + + var poll = _service.CreatePoll(Context.Guild.Id, + Context.Channel.Id, arg); + if (_service.StartPoll(poll)) + await Context.Channel + .EmbedAsync(new EmbedBuilder() + .WithTitle(GetText("poll_created", Context.User.ToString())) + .WithDescription(string.Join("\n", poll.Answers + .Select(x => $"`{x.Index + 1}.` {Format.Bold(x.Text)}")))) + .ConfigureAwait(false); + else + await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false); + } [NadekoCommand, Usage, Description, Aliases] [RequireUserPermission(GuildPermission.ManageMessages)] [RequireContext(ContextType.Guild)] public async Task PollStats() { - if (!_service.ActivePolls.TryGetValue(Context.Guild.Id, out var poll)) + if (!_service.ActivePolls.TryGetValue(Context.Guild.Id, out var pr)) return; - await Context.Channel.EmbedAsync(poll.GetStats(GetText("current_poll_results"))); - } - - private async Task InternalStartPoll(string arg) - { - if(await _service.StartPoll(Context.Guild.Id, Context.Message, arg) == false) - await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false); + await Context.Channel.EmbedAsync(GetStats(pr.Poll, GetText("current_poll_results"))); } [NadekoCommand, Usage, Description, Aliases] @@ -50,9 +62,50 @@ namespace NadekoBot.Modules.Games { var channel = (ITextChannel)Context.Channel; - if(_service.ActivePolls.TryRemove(channel.Guild.Id, out var poll)) - await poll.StopPoll().ConfigureAwait(false); + Poll p; + if ((p = _service.StopPoll(Context.Guild.Id)) == null) + return; + + var embed = GetStats(p, GetText("poll_closed")); + await Context.Channel.EmbedAsync(embed) + .ConfigureAwait(false); } - } + + public EmbedBuilder GetStats(Poll poll, string title) + { + var results = poll.Votes.GroupBy(kvp => kvp.VoteIndex) + .ToDictionary(x => x.Key, x => x.Sum(kvp => 1)) + .OrderByDescending(kvp => kvp.Value) + .ToArray(); + + var eb = new EmbedBuilder().WithTitle(title); + + var sb = new StringBuilder() + .AppendLine(Format.Bold(poll.Question)) + .AppendLine(); + + var totalVotesCast = 0; + if (results.Length == 0) + { + sb.AppendLine(GetText("no_votes_cast")); + } + else + { + for (int i = 0; i < results.Length; i++) + { + var result = results[i]; + sb.AppendLine(GetText("poll_result", + result.Key + 1, + Format.Bold(poll.Answers[result.Key].Text), + Format.Bold(result.Value.ToString()))); + totalVotesCast += result.Value; + } + } + + return eb.WithDescription(sb.ToString()) + .WithFooter(efb => efb.WithText(GetText("x_votes_cast", totalVotesCast))) + .WithOkColor(); + } + } } } \ No newline at end of file diff --git a/NadekoBot.Core/Modules/Games/Services/PollService.cs b/NadekoBot.Core/Modules/Games/Services/PollService.cs index 5ca8e784..9e9666d1 100644 --- a/NadekoBot.Core/Modules/Games/Services/PollService.cs +++ b/NadekoBot.Core/Modules/Games/Services/PollService.cs @@ -9,45 +9,102 @@ using NadekoBot.Modules.Games.Common; using NadekoBot.Core.Services; using NadekoBot.Core.Services.Impl; using NLog; +using NadekoBot.Core.Services.Database.Models; +using NadekoBot.Common.Collections; +using NadekoBot.Extensions; +using NadekoBot.Core.Services.Database; namespace NadekoBot.Modules.Games.Services { public class PollService : IEarlyBlockingExecutor, INService { - public ConcurrentDictionary ActivePolls = new ConcurrentDictionary(); + public ConcurrentDictionary ActivePolls { get; } = new ConcurrentDictionary(); private readonly Logger _log; private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; + private readonly DbService _db; + private readonly NadekoStrings _strs; - public PollService(DiscordSocketClient client, NadekoStrings strings) + public PollService(DiscordSocketClient client, NadekoStrings strings, DbService db, + NadekoStrings strs, IUnitOfWork uow) { _log = LogManager.GetCurrentClassLogger(); _client = client; _strings = strings; + _db = db; + _strs = strs; + + ActivePolls = uow.Polls.GetAllPolls() + .ToDictionary(x => x.GuildId, x => + { + var pr = new PollRunner(db, x); + pr.OnVoted += Pr_OnVoted; + return pr; + }) + .ToConcurrent(); } - public async Task StartPoll(ulong guildId, IUserMessage msg, string arg) + public Poll CreatePoll(ulong guildId, ulong channelId, string input) { - if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";")) + if (string.IsNullOrWhiteSpace(input) || !input.Contains(";")) return null; - var data = arg.Split(';'); + var data = input.Split(';'); if (data.Length < 3) return null; - var poll = new Poll(_client, _strings, msg, data[0], data.Skip(1)); - if (ActivePolls.TryAdd(guildId, poll)) - { - poll.OnEnded += (gid) => - { - ActivePolls.TryRemove(gid, out _); - }; + var col = new IndexedCollection(data.Skip(1) + .Select(x => new PollAnswer() { Text = x })); - await poll.StartPoll().ConfigureAwait(false); + return new Poll() + { + Answers = col, + Question = data[0], + ChannelId = channelId, + GuildId = guildId, + Votes = new System.Collections.Generic.HashSet() + }; + } + + public bool StartPoll(Poll p) + { + var pr = new PollRunner(_db, p); + if (ActivePolls.TryAdd(p.GuildId, pr)) + { + using (var uow = _db.UnitOfWork) + { + uow.Polls.Add(p); + uow.Complete(); + } + + pr.OnVoted += Pr_OnVoted; return true; } return false; } + public Poll StopPoll(ulong guildId) + { + if (ActivePolls.TryRemove(guildId, out var pr)) + { + pr.OnVoted -= Pr_OnVoted; + using (var uow = _db.UnitOfWork) + { + uow.Polls.RemovePoll(pr.Poll.Id); + uow.Complete(); + } + return pr.Poll; + } + return null; + } + + private async Task Pr_OnVoted(IUserMessage msg, IGuildUser usr) + { + var toDelete = await msg.Channel.SendConfirmAsync(_strs.GetText("poll_voted", usr.Guild.Id, "Games".ToLowerInvariant(), Format.Bold(usr.ToString()))) + .ConfigureAwait(false); + toDelete.DeleteAfter(5); + try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } + } + public async Task TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg) { if (guild == null) diff --git a/NadekoBot.Core/Services/Database/IUnitOfWork.cs b/NadekoBot.Core/Services/Database/IUnitOfWork.cs index b981da9a..be53661a 100644 --- a/NadekoBot.Core/Services/Database/IUnitOfWork.cs +++ b/NadekoBot.Core/Services/Database/IUnitOfWork.cs @@ -24,6 +24,7 @@ namespace NadekoBot.Core.Services.Database IWarningsRepository Warnings { get; } IXpRepository Xp { get; } IClubRepository Clubs { get; } + IPollsRepository Polls { get; } int Complete(); Task CompleteAsync(); diff --git a/NadekoBot.Core/Services/Database/Models/Poll.cs b/NadekoBot.Core/Services/Database/Models/Poll.cs index a84a819a..16aba816 100644 --- a/NadekoBot.Core/Services/Database/Models/Poll.cs +++ b/NadekoBot.Core/Services/Database/Models/Poll.cs @@ -3,15 +3,16 @@ using System.Collections.Generic; namespace NadekoBot.Core.Services.Database.Models { - public class Poll + public class Poll : DbEntity { public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } public string Question { get; set; } public IndexedCollection Answers { get; set; } - public HashSet Votes { get; set; } + public HashSet Votes { get; set; } = new HashSet(); } - public class PollAnswer : IIndexed + public class PollAnswer : DbEntity, IIndexed { public int Index { get; set; } public string Text { get; set; } diff --git a/NadekoBot.Core/Services/Database/Models/PollVote.cs b/NadekoBot.Core/Services/Database/Models/PollVote.cs index b931aeba..16f84e8e 100644 --- a/NadekoBot.Core/Services/Database/Models/PollVote.cs +++ b/NadekoBot.Core/Services/Database/Models/PollVote.cs @@ -1,13 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NadekoBot.Core.Services.Database.Models +namespace NadekoBot.Core.Services.Database.Models { - public class PollVote + public class PollVote : DbEntity { - + public ulong UserId { get; set; } + public int VoteIndex { get; set; } + + public override int GetHashCode() + { + return UserId.GetHashCode(); + } + + public override bool Equals(object obj) + { + return obj is PollVote p + ? p.UserId == UserId + : false; + } } } diff --git a/NadekoBot.Core/Services/Database/NadekoContext.cs b/NadekoBot.Core/Services/Database/NadekoContext.cs index 804d702a..edae0dfb 100644 --- a/NadekoBot.Core/Services/Database/NadekoContext.cs +++ b/NadekoBot.Core/Services/Database/NadekoContext.cs @@ -341,6 +341,12 @@ namespace NadekoBot.Core.Services.Database .WithMany(x => x.Bans); #endregion + + #region Polls + modelBuilder.Entity() + .HasIndex(x => x.GuildId) + .IsUnique(); + #endregion } } } diff --git a/NadekoBot.Core/Services/Database/Repositories/IPollsRepository.cs b/NadekoBot.Core/Services/Database/Repositories/IPollsRepository.cs new file mode 100644 index 00000000..70af3a4b --- /dev/null +++ b/NadekoBot.Core/Services/Database/Repositories/IPollsRepository.cs @@ -0,0 +1,15 @@ +using NadekoBot.Core.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Core.Services.Database.Repositories +{ + public interface IPollsRepository : IRepository + { + IEnumerable GetAllPolls(); + void RemovePoll(int id); + } +} diff --git a/NadekoBot.Core/Services/Database/Repositories/Impl/PollsRepository.cs b/NadekoBot.Core/Services/Database/Repositories/Impl/PollsRepository.cs new file mode 100644 index 00000000..c62dfb39 --- /dev/null +++ b/NadekoBot.Core/Services/Database/Repositories/Impl/PollsRepository.cs @@ -0,0 +1,35 @@ +using NadekoBot.Core.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace NadekoBot.Core.Services.Database.Repositories.Impl +{ + public class PollsRepository : Repository, IPollsRepository + { + public PollsRepository(DbContext context) : base(context) + { + } + + public IEnumerable GetAllPolls() + { + return _set.Include(x => x.Answers) + .Include(x => x.Votes) + .ToArray(); + } + + public void RemovePoll(int id) + { + var p = _set + .Include(x => x.Answers) + .Include(x => x.Votes) + .FirstOrDefault(x => x.Id == id); + p.Votes.Clear(); + p.Answers.Clear(); + _set.Remove(p); + } + } +} diff --git a/NadekoBot.Core/Services/Database/UnitOfWork.cs b/NadekoBot.Core/Services/Database/UnitOfWork.cs index af660051..d0e14de4 100644 --- a/NadekoBot.Core/Services/Database/UnitOfWork.cs +++ b/NadekoBot.Core/Services/Database/UnitOfWork.cs @@ -57,6 +57,9 @@ namespace NadekoBot.Core.Services.Database private IClubRepository _clubs; public IClubRepository Clubs => _clubs ?? (_clubs = new ClubRepository(_context)); + private IPollsRepository _polls; + public IPollsRepository Polls => _polls ?? (_polls = new PollsRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context; diff --git a/src/NadekoBot/_strings/ResponseStrings.en-US.json b/src/NadekoBot/_strings/ResponseStrings.en-US.json index 10d2ee22..daa75cf7 100644 --- a/src/NadekoBot/_strings/ResponseStrings.en-US.json +++ b/src/NadekoBot/_strings/ResponseStrings.en-US.json @@ -713,7 +713,8 @@ "games_current_poll_results": "Current poll results", "games_no_votes_cast": "No votes cast.", "games_poll_already_running": "Poll is already running on this server.", - "games_poll_created": "📃 {0} has created a poll which requires your attention:", + "games_poll_created": "📃 {0} has created a poll", + "games_poll_closed": "Poll Closed!", "games_poll_result": "`{0}.` {1} with {2} votes.", "games_poll_voted": "{0} voted.", "games_poll_vote_private": "Private Message me with the corresponding number of the answer.",