diff --git a/docs/Commands List.md b/docs/Commands List.md index f435ab6d..049143f8 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -31,6 +31,7 @@ Command and aliases | Description | Usage `.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331` `.die` | Shuts the bot down. **Bot Owner only.** | `.die` `.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName` +`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner only.** | `.setstatus Idle` `.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg` `.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes` `.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello` @@ -56,8 +57,10 @@ Command and aliases | Description | Usage `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` `.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` `.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata` -`.repeatinvoke` `.repinv` | Immediately shows the repeat message and restarts the timer. **Requires ManageMessages server permission.** | `.repinv` -`.repeat` | Repeat a message every X minutes. If no parameters are specified, repeat is disabled. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` +`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1` +`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` +`.repeat` | Repeat a message every X minutes in the current channel. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` +`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` `.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable` `.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore` `.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents` @@ -160,13 +163,14 @@ Command and aliases | Description | Usage `>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3` `>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3` `>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3` +`>pollstats` | Shows the poll results without stopping the poll on this server. **Requires ManageMessages server permission.** | `>pollstats` `>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` `>pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `>pick` `>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant` `>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc` `>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist` `>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies` -`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages channel permission.** | `>cleverbot` +`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot` `>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` `>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more` `>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something` @@ -366,6 +370,7 @@ Command and aliases | Description | Usage `.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calcops` | Shows all available operations in .calc command | `.calcops` +`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` `.togethertube` `.totube` | Creates a new room on and shows the link in the chat. | `.totube` `.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch` `.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` @@ -375,6 +380,7 @@ Command and aliases | Description | Usage `.serverid` `.sid` | Shows current server ID. | `.sid` `.roles` | List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. | `.roles 2` or `.roles @Someone` `.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct` +`.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv` `.stats` | Shows some basic stats for Nadeko. | `.stats` `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` `.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3` diff --git a/docs/guides/Docker Guide.md b/docs/guides/Docker Guide.md index 9908a477..474337d6 100644 --- a/docs/guides/Docker Guide.md +++ b/docs/guides/Docker Guide.md @@ -1,34 +1,58 @@ # NadekoBot a Discord bot -Nadeko is written in C# and Discord.net for more information visit https://github.com/Kwoth/NadekoBot +Nadeko is written in C# and Discord.net for more information visit ## Install Docker -Follow the respective guide for your operating system found here https://docs.docker.com/engine/installation/ +Follow the respective guide for your operating system found here [Docker Engine Install Guide](https://docs.docker.com/engine/installation/) ## Nadeko Setup Guide For this guide we will be using the folder /nadeko as our config root folder. -``` -docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json kwoth/nadeko:dev +```bash +docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko ``` -If you are coming from a previous version of nadeko (the old docker) make sure your crednetials.json has been copied into this directory and is the only thing in this folder. --If you are making a fresh install, create your credentials.json from the following guide and palce it in the /nadeko folder -http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/ +-If you are making a fresh install, create your credentials.json from the following guide and palce it in the /nadeko folder [Nadeko JSON Guide](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) Next start the docker up with -```docker start nadeko; docker logs -f nadeko``` +`docker start nadeko; docker logs -f nadeko` The docker will start and the log file will start scrolling past. Depending on hardware the bot start can take up to 5 minutes on a small DigitalOcean droplet. Once the log ends with "NadekoBot | Starting NadekoBot v1.0-rc2" the bot is ready and can be invited to your server. Ctrl+C at this point to stop viewing the logs. After a few moments you should be able to invite Nadeko to your server. If you cannot check the log file for errors -## Updates / Monitoring +## Monitoring -* Upgrade to the latest version of Nadeko simply `docker restart nadeko`. * Monitor the logs of the container in realtime `docker logs -f nadeko`. +## Updates + +# Manual +Updates are handled by pulling the new layer of the Docker Container which contains a pre compiled update to Nadeko. +The following commands are required for the default options + +`docker pull uirel/nadeko:latest` + +`docker stop nadeko; docker rm nadeko` + +`docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko` + +`docker start nadeko` + + +# Automatic Updates +Automatic update are now handled by watchertower [WatchTower GitHub](https://github.com/CenturyLinkLabs/watchtower) +To setup watchtower to keep Nadeko up-to-date for you with the default settings use the following command + +```bash +docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko +``` + +This will check for updates to the docker every 5 minutes and update immediately. Alternatively using the `--interval X` command to change the interval, where X is the amount of time in seconds to wait. eg 21600 for 6 hours. + + If you have any issues with the docker setup, please ask in #help but indicate you are using the docker. -For information about configuring your bot or its functionality, please check the http://nadekobot.readthedocs.io/en/latest guides. +For information about configuring your bot or its functionality, please check the guides. diff --git a/docs/index.md b/docs/index.md index 872e2e40..c2dbfa0a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,6 +11,9 @@ NadekoBot is an open source project, and it can be found on our [GitHub][GitHub] Here you can read current [Issues][Issues]. If you want to contribute, be sure to PR on the **[dev][dev]** branch. + +**NadekoBot 1.1 release currently does not support x86/32bit architecture.** + ##Content - [About](about.md) - Guides @@ -34,14 +37,3 @@ If you want to contribute, be sure to PR on the **[dev][dev]** branch. [GitHub]: https://github.com/Kwoth/NadekoBot [Issues]: https://github.com/Kwoth/NadekoBot/issues [dev]: https://github.com/Kwoth/NadekoBot/tree/dev - -[Italian]: http://i.imgur.com/SsaTwOF.png?1 -[Russian]: http://i.imgur.com/wf9bc5G.png?1 -[German]: http://i.imgur.com/EM5qPzf.png?1 -[Chinese]: http://i.imgur.com/MVCNOjT.png?1 -[English]: http://i.imgur.com/jHTyZFS.png?1 -[Spanish]: http://i.imgur.com/9BsusB6.png?1 -[French]: http://i.imgur.com/g2ARPF6.png?1 -[Dutch]: http://i.imgur.com/SadddLj.png?1 -[Norwegian]: http://i.imgur.com/TCVa0V8.png?1 -[Serbian]: http://i.imgur.com/5evoUbU.png diff --git a/src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs b/src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs new file mode 100644 index 00000000..db95f728 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs @@ -0,0 +1,834 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170110111159_repeater-drop")] + partial class repeaterdrop + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BufferSize"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + 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("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.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("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.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + 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.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + 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.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170110111159_repeater-drop.cs b/src/NadekoBot/Migrations/20170110111159_repeater-drop.cs new file mode 100644 index 00000000..d05e6672 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111159_repeater-drop.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class repeaterdrop : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Repeaters"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Repeaters", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChannelId = table.Column(nullable: false), + GuildId = table.Column(nullable: false), + Interval = table.Column(nullable: false), + Message = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Repeaters", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Repeaters_ChannelId", + table: "Repeaters", + column: "ChannelId", + unique: true); + } + } +} diff --git a/src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs b/src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs new file mode 100644 index 00000000..09bee367 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs @@ -0,0 +1,863 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170110111302_repeater-new")] + partial class repeaternew + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BufferSize"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + 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("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.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("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.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + 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.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + 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.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170110111302_repeater-new.cs b/src/NadekoBot/Migrations/20170110111302_repeater-new.cs new file mode 100644 index 00000000..0decfad8 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111302_repeater-new.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class repeaternew : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "GuildRepeater", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChannelId = table.Column(nullable: false), + GuildConfigId = table.Column(nullable: true), + GuildId = table.Column(nullable: false), + Interval = table.Column(nullable: false), + Message = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_GuildRepeater", x => x.Id); + table.ForeignKey( + name: "FK_GuildRepeater_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_GuildRepeater_GuildConfigId", + table: "GuildRepeater", + column: "GuildConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "GuildRepeater"); + } + } +} diff --git a/src/NadekoBot/Migrations/20170110180534_protection.Designer.cs b/src/NadekoBot/Migrations/20170110180534_protection.Designer.cs new file mode 100644 index 00000000..ecc134cd --- /dev/null +++ b/src/NadekoBot/Migrations/20170110180534_protection.Designer.cs @@ -0,0 +1,942 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170110180534_protection")] + partial class protection + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BufferSize"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + 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("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.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("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.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + 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.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + 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.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170110180534_protection.cs b/src/NadekoBot/Migrations/20170110180534_protection.cs new file mode 100644 index 00000000..fca7f541 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110180534_protection.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class protection : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AntiRaidSetting", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Action = table.Column(nullable: false), + GuildConfigId = table.Column(nullable: false), + Seconds = table.Column(nullable: false), + UserThreshold = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AntiRaidSetting", x => x.Id); + table.ForeignKey( + name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "AntiSpamSetting", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Action = table.Column(nullable: false), + GuildConfigId = table.Column(nullable: false), + MessageThreshold = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AntiSpamSetting", x => x.Id); + table.ForeignKey( + name: "FK_AntiSpamSetting_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "AntiSpamIgnore", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AntiSpamSettingId = table.Column(nullable: true), + ChannelId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AntiSpamIgnore", x => x.Id); + table.ForeignKey( + name: "FK_AntiSpamIgnore_AntiSpamSetting_AntiSpamSettingId", + column: x => x.AntiSpamSettingId, + principalTable: "AntiSpamSetting", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_AntiRaidSetting_GuildConfigId", + table: "AntiRaidSetting", + column: "GuildConfigId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AntiSpamIgnore_AntiSpamSettingId", + table: "AntiSpamIgnore", + column: "AntiSpamSettingId"); + + migrationBuilder.CreateIndex( + name: "IX_AntiSpamSetting_GuildConfigId", + table: "AntiSpamSetting", + column: "GuildConfigId", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AntiRaidSetting"); + + migrationBuilder.DropTable( + name: "AntiSpamIgnore"); + + migrationBuilder.DropTable( + name: "AntiSpamSetting"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index c9b359e1..190e425e 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -2,7 +2,10 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; namespace NadekoBot.Migrations { @@ -14,6 +17,62 @@ namespace NadekoBot.Migrations modelBuilder .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => { b.Property("Id") @@ -381,6 +440,28 @@ namespace NadekoBot.Migrations b.ToTable("GuildConfigs"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => { b.Property("Id") @@ -663,27 +744,6 @@ namespace NadekoBot.Migrations b.ToTable("Reminders"); }); - modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("GuildId"); - - b.Property("Interval"); - - b.Property("Message"); - - b.HasKey("Id"); - - b.HasIndex("ChannelId") - .IsUnique(); - - b.ToTable("Repeaters"); - }); - modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => { b.Property("Id") @@ -718,6 +778,29 @@ namespace NadekoBot.Migrations b.ToTable("PokeGame"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => { b.HasOne("NadekoBot.Services.Database.Models.BotConfig") @@ -790,6 +873,13 @@ namespace NadekoBot.Migrations .HasForeignKey("RootPermissionId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => { b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 5b97b69a..cf431be1 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -460,6 +460,9 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(ChannelPermission.ManageMessages)] public async Task Prune(int count) { + if (count < 1) + return; + count += 1; await Context.Message.DeleteAsync().ConfigureAwait(false); int limit = (count < 100) ? count : 100; var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false)); @@ -472,30 +475,17 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(ChannelPermission.ManageMessages)] public async Task Prune(IGuildUser user, int count = 100) { + if (count < 1) + return; + + if (user.Id == Context.User.Id) + count += 1; int limit = (count < 100) ? count : 100; var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten()).Where(m => m.Author == user); await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false); } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [OwnerOnly] - public async Task SaveChat(int cnt) - { - var sb = new StringBuilder(); - var msgs = new List(cnt); - await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false); - - var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt"; - var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}") - .Select(g => new { date = g.Key, messages = g.OrderBy(x => x.CreatedAt).Select(s => $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s.ToString()) }); - await (Context.User as IGuildUser).SendFileAsync( - await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), -title, title).ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.MentionEveryone)] diff --git a/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs deleted file mode 100644 index 4551ef48..00000000 --- a/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs +++ /dev/null @@ -1,272 +0,0 @@ -using Discord; -using Discord.Commands; -using NadekoBot.Attributes; -using NadekoBot.Extensions; -using NLog; -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Threading.Tasks; - -namespace NadekoBot.Modules.Administration -{ - public partial class Administration - { - public enum PunishmentAction - { - Mute, - Kick, - Ban, - } - - public enum ProtectionType - { - Raiding, - Spamming, - } - - private class AntiRaidSetting - { - public int UserThreshold { get; set; } - public int Seconds { get; set; } - public PunishmentAction Action { get; set; } - public int UsersCount { get; set; } - public ConcurrentHashSet RaidUsers { get; set; } = new ConcurrentHashSet(); - } - - private class AntiSpamSetting - { - public PunishmentAction Action { get; set; } - public int MessageThreshold { get; set; } = 3; - public ConcurrentDictionary UserStats { get; set; } - = new ConcurrentDictionary(); - } - - private class UserSpamStats - { - public int Count { get; set; } - public string LastMessage { get; set; } - - public UserSpamStats(string msg) - { - Count = 1; - LastMessage = msg.ToUpperInvariant(); - } - - public void ApplyNextMessage(string message) - { - var upperMsg = message.ToUpperInvariant(); - if (upperMsg == LastMessage) - Count++; - else - { - LastMessage = upperMsg; - Count = 0; - } - } - } - - [Group] - public class AntiRaidCommands : ModuleBase - { - private static ConcurrentDictionary antiRaidGuilds = - new ConcurrentDictionary(); - // guildId | (userId|messages) - private static ConcurrentDictionary antiSpamGuilds = - new ConcurrentDictionary(); - - private static Logger _log { get; } - - static AntiRaidCommands() - { - _log = LogManager.GetCurrentClassLogger(); - - NadekoBot.Client.MessageReceived += async (imsg) => - { - - try - { - var msg = imsg as IUserMessage; - if (msg == null || msg.Author.IsBot) - return; - - var channel = msg.Channel as ITextChannel; - if (channel == null) - return; - AntiSpamSetting spamSettings; - if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings)) - return; - - var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), - (id, old) => { old.ApplyNextMessage(msg.Content); return old; }); - - if (stats.Count >= spamSettings.MessageThreshold) - { - if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) - { - await PunishUsers(spamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author) - .ConfigureAwait(false); - } - } - } - catch { } - }; - - NadekoBot.Client.UserJoined += async (usr) => - { - try - { - if (usr.IsBot) - return; - AntiRaidSetting settings; - if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) - return; - if (!settings.RaidUsers.Add(usr)) - return; - - ++settings.UsersCount; - - if (settings.UsersCount >= settings.UserThreshold) - { - var users = settings.RaidUsers.ToArray(); - settings.RaidUsers.Clear(); - - await PunishUsers(settings.Action, ProtectionType.Raiding, users).ConfigureAwait(false); - } - await Task.Delay(1000 * settings.Seconds).ConfigureAwait(false); - - settings.RaidUsers.TryRemove(usr); - --settings.UsersCount; - - } - catch { } - }; - } - - private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus) - { - foreach (var gu in gus) - { - switch (action) - { - case PunishmentAction.Mute: - try - { - await MuteCommands.MuteUser(gu).ConfigureAwait(false); - } - catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } - break; - case PunishmentAction.Kick: - try - { - await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); - try - { - await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); - } - catch - { - await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); - // try it twice, really don't want to ban user if - // only kick has been specified as the punishement - } - } - catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } - break; - case PunishmentAction.Ban: - try - { - await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); - } - catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } - break; - default: - break; - } - } - await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false); - } - - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.Administrator)] - public async Task AntiRaid(int userThreshold, int seconds, PunishmentAction action) - { - if (userThreshold < 2 || userThreshold > 30) - { - await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false); - return; - } - - if (seconds < 2 || seconds > 300) - { - await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false); - return; - } - - try - { - await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); - } - catch (Exception ex) - { - await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + - "or create 'nadeko-mute' role with disabled SendMessages and try again.") - .ConfigureAwait(false); - _log.Warn(ex); - return; - } - - var setting = new AntiRaidSetting() - { - Action = action, - Seconds = seconds, - UserThreshold = userThreshold, - }; - antiRaidGuilds.AddOrUpdate(Context.Guild.Id, setting, (id, old) => setting); - - await Context.Channel.SendConfirmAsync($"ℹ️ {Context.User.Mention} If **{userThreshold}** or more users join within **{seconds}** seconds, I will **{action}** them.") - .ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.Administrator)] - public async Task AntiSpam(int messageCount=3, PunishmentAction action = PunishmentAction.Mute) - { - if (messageCount < 2 || messageCount > 10) - return; - - AntiSpamSetting throwaway; - if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway)) - { - await Context.Channel.SendConfirmAsync("🆗 **Anti-Spam feature** has been **disabled** on this server.").ConfigureAwait(false); - } - else - { - try - { - await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); - } - catch (Exception ex) - { - await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + - "or create 'nadeko-mute' role with disabled SendMessages and try again.") - .ConfigureAwait(false); - _log.Warn(ex); - return; - } - - if (antiSpamGuilds.TryAdd(Context.Guild.Id, new AntiSpamSetting() - { - Action = action, - MessageThreshold = messageCount, - })) - await Context.Channel.SendConfirmAsync("✅ **Anti-Spam feature** has been **enabled** on this server.").ConfigureAwait(false); - } - - } - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index e4541afc..c7e5d513 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -651,7 +651,7 @@ namespace NadekoBot.Modules.Administration return; var embed = new EmbedBuilder() .WithOkColor() - .WithTitle("🗑 Message Deleted") + .WithTitle($"🗑 Message Deleted in {((ITextChannel)msg.Channel).Mention}") .WithDescription($"{msg.Author}") .AddField(efb => efb.WithName("Content").WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false)) @@ -695,7 +695,7 @@ namespace NadekoBot.Modules.Administration var embed = new EmbedBuilder() .WithOkColor() - .WithTitle("📝 Message Updated") + .WithTitle($"📝 Message Updated in {((ITextChannel)after.Channel).Mention}") .WithDescription(after.Author.ToString()) .AddField(efb => efb.WithName("Old Message").WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("New Message").WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs deleted file mode 100644 index 8d50a80e..00000000 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ /dev/null @@ -1,173 +0,0 @@ -using Discord; -using Discord.Commands; -using NadekoBot.Attributes; -using NadekoBot.Extensions; -using NadekoBot.Services; -using NadekoBot.Services.Database.Models; -using NLog; -using System; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace NadekoBot.Modules.Administration -{ - public partial class Administration - { - [Group] - public class RepeatCommands : ModuleBase - { - public static ConcurrentDictionary repeaters { get; } - - public class RepeatRunner - { - private Logger _log { get; } - - private CancellationTokenSource source { get; set; } - private CancellationToken token { get; set; } - public Repeater Repeater { get; } - public ITextChannel Channel { get; } - - public RepeatRunner(Repeater repeater, ITextChannel channel = null) - { - _log = LogManager.GetCurrentClassLogger(); - this.Repeater = repeater; - this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannelAsync(repeater.ChannelId).GetAwaiter().GetResult(); - if (Channel == null) - return; - Task.Run(Run); - } - - - private async Task Run() - { - source = new CancellationTokenSource(); - token = source.Token; - IUserMessage oldMsg = null; - try - { - while (!token.IsCancellationRequested) - { - var toSend = "🔄 " + Repeater.Message; - await Task.Delay(Repeater.Interval, token).ConfigureAwait(false); - - //var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault(); - // if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel - // continue; - - if (oldMsg != null) - try { await oldMsg.DeleteAsync(); } catch { } - try { oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } - } - } - catch (OperationCanceledException) { } - } - - public void Reset() - { - source.Cancel(); - var t = Task.Run(Run); - } - - public void Stop() - { - source.Cancel(); - } - } - - static RepeatCommands() - { - var _log = LogManager.GetCurrentClassLogger(); - var sw = Stopwatch.StartNew(); - using (var uow = DbHandler.UnitOfWork()) - { - repeaters = new ConcurrentDictionary(uow.Repeaters.GetAll().Select(r => new RepeatRunner(r)).Where(r => r != null).ToDictionary(r => r.Repeater.ChannelId)); - } - - sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.ManageMessages)] - public async Task RepeatInvoke() - { - RepeatRunner rep; - if (!repeaters.TryGetValue(Context.Channel.Id, out rep)) - { - await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false); - return; - } - rep.Reset(); - await Context.Channel.SendMessageAsync("🔄 " + rep.Repeater.Message).ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.ManageMessages)] - public async Task Repeat() - { - RepeatRunner rep; - if (repeaters.TryRemove(Context.Channel.Id, out rep)) - { - using (var uow = DbHandler.UnitOfWork()) - { - uow.Repeaters.Remove(rep.Repeater); - await uow.CompleteAsync(); - } - rep.Stop(); - await Context.Channel.SendConfirmAsync("✅ **Stopped repeating a message.**").ConfigureAwait(false); - } - else - await Context.Channel.SendConfirmAsync("ℹ️ **No message is repeating.**").ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.ManageMessages)] - public async Task Repeat(int minutes, [Remainder] string message) - { - if (minutes < 1 || minutes > 10080) - return; - - if (string.IsNullOrWhiteSpace(message)) - return; - - RepeatRunner rep; - - rep = repeaters.AddOrUpdate(Context.Channel.Id, (cid) => - { - using (var uow = DbHandler.UnitOfWork()) - { - var localRep = new Repeater - { - ChannelId = Context.Channel.Id, - GuildId = Context.Guild.Id, - Interval = TimeSpan.FromMinutes(minutes), - Message = message, - }; - uow.Repeaters.Add(localRep); - uow.Complete(); - return new RepeatRunner(localRep, (ITextChannel)Context.Channel); - } - }, (cid, old) => - { - using (var uow = DbHandler.UnitOfWork()) - { - old.Repeater.Message = message; - old.Repeater.Interval = TimeSpan.FromMinutes(minutes); - uow.Repeaters.Update(old.Repeater); - uow.Complete(); - } - old.Reset(); - return old; - }); - - await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false); - } - } - } -} diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs new file mode 100644 index 00000000..e37f4850 --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -0,0 +1,425 @@ +using Discord; +using Discord.Commands; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NLog; +using System; +using System.Collections.Concurrent; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Administration +{ + public partial class Administration + { + public enum ProtectionType + { + Raiding, + Spamming, + } + + public class AntiRaidStats + { + public AntiRaidSetting AntiRaidSettings { get; set; } + public int UsersCount { get; set; } = 0; + public ConcurrentHashSet RaidUsers { get; set; } = new ConcurrentHashSet(); + + public override string ToString() => + $"If **{AntiRaidSettings.UserThreshold}** or more users join within **{AntiRaidSettings.Seconds}** seconds," + + $" I will **{AntiRaidSettings.Action}** them."; + } + + public class AntiSpamStats + { + public AntiSpamSetting AntiSpamSettings { get; set; } + public ConcurrentDictionary UserStats { get; set; } + = new ConcurrentDictionary(); + + public override string ToString() + { + var ignoredString = string.Join(", ", AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>")); + + if (string.IsNullOrWhiteSpace(ignoredString)) + ignoredString = "none"; + return $"If a user posts **{AntiSpamSettings.MessageThreshold}** same messages in a row, I will **{AntiSpamSettings.Action}** them." + + $"\n\t__IgnoredChannels__: {ignoredString}"; + } + } + + public class UserSpamStats + { + public int Count { get; set; } + public string LastMessage { get; set; } + + public UserSpamStats(string msg) + { + Count = 1; + LastMessage = msg.ToUpperInvariant(); + } + + public void ApplyNextMessage(string message) + { + var upperMsg = message.ToUpperInvariant(); + if (upperMsg == LastMessage) + Count++; + else + { + LastMessage = upperMsg; + Count = 0; + } + } + } + + [Group] + public class ProtectionCommands : ModuleBase + { + private static ConcurrentDictionary antiRaidGuilds = + new ConcurrentDictionary(); + // guildId | (userId|messages) + private static ConcurrentDictionary antiSpamGuilds = + new ConcurrentDictionary(); + + private static Logger _log { get; } + + static ProtectionCommands() + { + _log = LogManager.GetCurrentClassLogger(); + + foreach (var gc in NadekoBot.AllGuildConfigs) + { + var raid = gc.AntiRaidSetting; + var spam = gc.AntiSpamSetting; + + if (raid != null) + { + var raidStats = new AntiRaidStats() { AntiRaidSettings = raid }; + antiRaidGuilds.TryAdd(gc.GuildId, raidStats); + } + + if (spam != null) + antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam }); + } + + NadekoBot.Client.MessageReceived += async (imsg) => + { + + try + { + var msg = imsg as IUserMessage; + if (msg == null || msg.Author.IsBot) + return; + + var channel = msg.Channel as ITextChannel; + if (channel == null) + return; + AntiSpamStats spamSettings; + if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) || + spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore() + { + ChannelId = channel.Id + })) + return; + + var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), + (id, old) => { old.ApplyNextMessage(msg.Content); return old; }); + + if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold) + { + if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) + { + await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author) + .ConfigureAwait(false); + } + } + } + catch { } + }; + + NadekoBot.Client.UserJoined += async (usr) => + { + try + { + if (usr.IsBot) + return; + AntiRaidStats settings; + if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) + return; + if (!settings.RaidUsers.Add(usr)) + return; + + ++settings.UsersCount; + + if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold) + { + var users = settings.RaidUsers.ToArray(); + settings.RaidUsers.Clear(); + + await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false); + } + await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false); + + settings.RaidUsers.TryRemove(usr); + --settings.UsersCount; + + } + catch { } + }; + } + + private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus) + { + foreach (var gu in gus) + { + switch (action) + { + case PunishmentAction.Mute: + try + { + await MuteCommands.MuteUser(gu).ConfigureAwait(false); + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } + break; + case PunishmentAction.Kick: + try + { + await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); + try + { + await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); + } + catch + { + await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); + // try it twice, really don't want to ban user if + // only kick has been specified as the punishement + } + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } + break; + case PunishmentAction.Ban: + try + { + await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } + break; + default: + break; + } + } + await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false); + } + + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task AntiRaid(int userThreshold = 5, int seconds = 10, PunishmentAction action = PunishmentAction.Mute) + { + if (userThreshold < 2 || userThreshold > 30) + { + await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false); + return; + } + + if (seconds < 2 || seconds > 300) + { + await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false); + return; + } + + AntiRaidStats throwaway; + if (antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting)); + + gc.AntiRaidSetting = null; + await uow.CompleteAsync().ConfigureAwait(false); + } + await Context.Channel.SendConfirmAsync("**Anti-Raid** feature has been **disabled** on this server.").ConfigureAwait(false); + return; + } + + try + { + await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); + } + catch (Exception ex) + { + await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + + "or create 'nadeko-mute' role with disabled SendMessages and try again.") + .ConfigureAwait(false); + _log.Warn(ex); + return; + } + + var stats = new AntiRaidStats() + { + AntiRaidSettings = new AntiRaidSetting() + { + Action = action, + Seconds = seconds, + UserThreshold = userThreshold, + } + }; + + antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); + + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting)); + + gc.AntiRaidSetting = stats.AntiRaidSettings; + await uow.CompleteAsync().ConfigureAwait(false); + } + + await Context.Channel.SendConfirmAsync("Anti-Raid Enabled", $"{Context.User.Mention} {stats.ToString()}") + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task AntiSpam(int messageCount = 3, PunishmentAction action = PunishmentAction.Mute) + { + if (messageCount < 2 || messageCount > 10) + return; + + AntiSpamStats throwaway; + if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting) + .ThenInclude(x => x.IgnoredChannels)); + + gc.AntiSpamSetting = null; + await uow.CompleteAsync().ConfigureAwait(false); + } + await Context.Channel.SendConfirmAsync("**Anti-Spam** has been **disabled** on this server.").ConfigureAwait(false); + return; + } + + try + { + await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); + } + catch (Exception ex) + { + await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + + "or create 'nadeko-mute' role with disabled SendMessages and try again.") + .ConfigureAwait(false); + _log.Warn(ex); + return; + } + + var stats = new AntiSpamStats + { + AntiSpamSettings = new AntiSpamSetting() + { + Action = action, + MessageThreshold = messageCount, + } + }; + + antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); + + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)); + + gc.AntiSpamSetting = stats.AntiSpamSettings; + await uow.CompleteAsync().ConfigureAwait(false); + } + + await Context.Channel.SendConfirmAsync("Anti-Spam Enabled", $"{Context.User.Mention} {stats.ToString()}").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task AntispamIgnore() + { + var channel = (ITextChannel)Context.Channel; + + var obj = new AntiSpamIgnore() + { + ChannelId = channel.Id + }; + bool added; + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels)); + var spam = gc.AntiSpamSetting; + if (spam == null) + { + return; + } + + if (spam.IgnoredChannels.Add(obj)) + { + AntiSpamStats temp; + if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) + temp.AntiSpamSettings.IgnoredChannels.Add(obj); + added = true; + } + else + { + spam.IgnoredChannels.Remove(obj); + AntiSpamStats temp; + if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) + temp.AntiSpamSettings.IgnoredChannels.Remove(obj); + added = false; + } + + await uow.CompleteAsync().ConfigureAwait(false); + } + if (added) + await Context.Channel.SendConfirmAsync("Anti-Spam will ignore this channel.").ConfigureAwait(false); + else + await Context.Channel.SendConfirmAsync("Anti-Spam will no longer ignore this channel.").ConfigureAwait(false); + + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task AntiList() + { + var channel = (ITextChannel)Context.Channel; + + AntiSpamStats spam; + antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam); + + AntiRaidStats raid; + antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid); + + if (spam == null && raid == null) + { + await Context.Channel.SendConfirmAsync("No protections enabled."); + return; + } + + var embed = new EmbedBuilder().WithOkColor() + .WithTitle("Protections Enabled"); + + if (spam != null) + embed.AddField(efb => efb.WithName("Anti-Spam") + .WithValue(spam.ToString()) + .WithIsInline(true)); + + if (raid != null) + embed.AddField(efb => efb.WithName("Anti-Raid") + .WithValue(raid.ToString()) + .WithIsInline(true)); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index b3bbe1bd..bbff2239 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -99,7 +99,7 @@ namespace NadekoBot.Modules.Gambling await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully awarded {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 58071453..23b76e9b 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman } } - public class HangmanGame + public class HangmanGame: IDisposable { private readonly Logger _log; @@ -196,5 +196,11 @@ namespace NadekoBot.Modules.Games.Commands.Hangman {(Errors > 1 ? "/" : " ")} {(Errors > 2 ? "|" : " ")} {(Errors > 3 ? "\\" : " ")} | {(Errors > 4 ? "/" : " ")} {(Errors > 5 ? "\\" : " ")} | /-\"; + + public void Dispose() + { + NadekoBot.Client.MessageReceived -= PotentialGuess; + OnEnded = null; + } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 0827ab94..50596e4c 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -52,8 +52,12 @@ namespace NadekoBot.Modules.Games { hm.Start(); } - catch (Exception ex) { + catch (Exception ex) + { try { await Context.Channel.SendErrorAsync($"Starting errored: {ex.Message}").ConfigureAwait(false); } catch { } + HangmanGame throwaway; + HangmanGames.TryRemove(Context.Channel.Id, out throwaway); + throwaway.Dispose(); return; } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 536a00ae..3ffb104c 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -300,7 +300,7 @@ $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {tota return; if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild) { - await Context.Channel.SendErrorAsync("💢 You need to be in a **voice channel** on this server.\n If you are already in a voice (ITextChannel)Context.Channel, try rejoining it.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"💢 You need to be in a **voice channel** on this server.").ConfigureAwait(false); return; } var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault(); diff --git a/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs similarity index 97% rename from src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs rename to src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs index 62af02da..b2ae710c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs @@ -9,9 +9,9 @@ using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; -namespace NadekoBot.Modules.Administration +namespace NadekoBot.Modules.Utility { - public partial class Administration + public partial class Utility { [Group] public class CrossServerTextChannel : ModuleBase diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 37d80ba6..8814c50c 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -102,7 +102,7 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [OwnerOnly] - public async Task Activity(IUserMessage imsg, int page = 1) + public async Task Activity(int page = 1) { const int activityPerPage = 15; page -= 1; @@ -118,7 +118,7 @@ namespace NadekoBot.Modules.Utility str.AppendLine($"`{++startCount}.` **{kvp.Key}** [{kvp.Value/NadekoBot.Stats.GetUptime().TotalSeconds:F2}/s] - {kvp.Value} total"); } - await imsg.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}") + await Context.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}") .WithOkColor() .WithFooter(efb => efb.WithText($"{NadekoBot.CommandHandler.UserMessagesSent.Count} users total.")) .WithDescription(str.ToString())); diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs new file mode 100644 index 00000000..71bd6748 --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -0,0 +1,238 @@ +using Discord; +using Discord.Commands; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NLog; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Utility +{ + public partial class Utility + { + [Group] + public class RepeatCommands : ModuleBase + { + //guildid/RepeatRunners + public static ConcurrentDictionary> repeaters { get; } + + public class RepeatRunner + { + private Logger _log { get; } + + private CancellationTokenSource source { get; set; } + private CancellationToken token { get; set; } + public Repeater Repeater { get; } + public ITextChannel Channel { get; } + + public RepeatRunner(Repeater repeater, ITextChannel channel = null) + { + _log = LogManager.GetCurrentClassLogger(); + this.Repeater = repeater; + this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannelAsync(repeater.ChannelId).GetAwaiter().GetResult(); + if (Channel == null) + return; + Task.Run(Run); + } + + + private async Task Run() + { + source = new CancellationTokenSource(); + token = source.Token; + IUserMessage oldMsg = null; + try + { + while (!token.IsCancellationRequested) + { + var toSend = "🔄 " + Repeater.Message; + await Task.Delay(Repeater.Interval, token).ConfigureAwait(false); + + //var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault(); + // if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel + // continue; + + if (oldMsg != null) + try { await oldMsg.DeleteAsync(); } catch { } + try { oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + } + } + catch (OperationCanceledException) { } + } + + public void Reset() + { + source.Cancel(); + var t = Task.Run(Run); + } + + public void Stop() + { + source.Cancel(); + } + + public override string ToString() + { + return $"{this.Channel.Mention} | {(int)this.Repeater.Interval.TotalHours}:{this.Repeater.Interval:mm} | {this.Repeater.Message.TrimTo(33)}"; + } + } + + static RepeatCommands() + { + var _log = LogManager.GetCurrentClassLogger(); + var sw = Stopwatch.StartNew(); + + repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs + .ToDictionary(gc => gc.GuildId, + gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) + .Where(gr => gr.Channel != null)))); + + sw.Stop(); + _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task RepeatInvoke(int index) + { + index -= 1; + ConcurrentQueue rep; + if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + { + await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false); + return; + } + + var repList = rep.ToList(); + + if (index >= repList.Count) + { + await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + return; + } + var repeater = repList[index].Repeater; + + await Context.Channel.SendMessageAsync("🔄 " + repeater.Message).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(0)] + public async Task RepeatRemove(int index) + { + if (index < 1) + return; + index -= 1; + + ConcurrentQueue rep; + if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + return; + + var repeaterList = rep.ToList(); + + if (index >= repeaterList.Count) + { + await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + return; + } + + var repeater = repeaterList[index]; + repeater.Stop(); + repeaterList.RemoveAt(index); + + using (var uow = DbHandler.UnitOfWork()) + { + var guildConfig = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.GuildRepeaters)); + + guildConfig.GuildRepeaters.RemoveWhere(r => r.Id == repeater.Repeater.Id); + await uow.CompleteAsync().ConfigureAwait(false); + } + + if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) + await Context.Channel.SendConfirmAsync("Message Repeater",$"#{index+1} stopped.\n\n{repeater.ToString()}").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(1)] + public async Task Repeat(int minutes, [Remainder] string message) + { + if (minutes < 1 || minutes > 10080) + return; + + if (string.IsNullOrWhiteSpace(message)) + return; + + var toAdd = new GuildRepeater() + { + ChannelId = Context.Channel.Id, + GuildId = Context.Guild.Id, + Interval = TimeSpan.FromMinutes(minutes), + Message = message + }; + + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.GuildRepeaters)); + + if (gc.GuildRepeaters.Count >= 5) + return; + gc.GuildRepeaters.Add(toAdd); + + await uow.CompleteAsync().ConfigureAwait(false); + } + + var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel); + + repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => + { + old.Enqueue(rep); + return old; + }); + + await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task RepeatList() + { + ConcurrentQueue repRunners; + if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners)) + { + await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false); + return; + } + + var replist = repRunners.ToList(); + var sb = new StringBuilder(); + + for (int i = 0; i < replist.Count; i++) + { + var rep = replist[i]; + + sb.AppendLine($"`{i + 1}.` {rep.ToString()}"); + } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("List Of Repeaters") + .WithDescription(sb.ToString())) + .ConfigureAwait(false); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 3c1150f3..4a581108 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -13,6 +13,8 @@ using System.Net.Http; using System.Collections.Concurrent; using System.Threading; using ImageSharp; +using System.Collections.Generic; +using Newtonsoft.Json; namespace NadekoBot.Modules.Utility { @@ -82,7 +84,7 @@ namespace NadekoBot.Modules.Utility old.Change(Timeout.Infinite, Timeout.Infinite); return t; }); - + await channel.SendFileAsync(images, "magicalgirl.jpg", $"Rotating **{role.Name}** role's color.").ConfigureAwait(false); } @@ -247,9 +249,9 @@ namespace NadekoBot.Modules.Utility var topic = channel.Topic; if (string.IsNullOrWhiteSpace(topic)) - await channel.SendErrorAsync("No topic set.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync("No topic set.").ConfigureAwait(false); else - await channel.SendConfirmAsync("Channel topic", topic).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync("Channel topic", topic).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -326,5 +328,22 @@ namespace NadekoBot.Modules.Utility .WithIsInline(false)))) .ConfigureAwait(false); } + + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task SaveChat(int cnt) + { + var sb = new StringBuilder(); + var msgs = new List(cnt); + await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false); + + var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt"; + var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}") + .Select(g => new { date = g.Key, messages = g.OrderBy(x => x.CreatedAt).Select(s => $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s.ToString()) }); + await Context.User.SendFileAsync( + await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 58126412..e58dbbbb 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -437,6 +437,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to antilist antilst. + /// + public static string antilist_cmd { + get { + return ResourceManager.GetString("antilist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows currently enabled protection features.. + /// + public static string antilist_desc { + get { + return ResourceManager.GetString("antilist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}antilist`. + /// + public static string antilist_usage { + get { + return ResourceManager.GetString("antilist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to antiraid. /// @@ -491,6 +518,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to antispamignore. + /// + public static string antispamignore_cmd { + get { + return ResourceManager.GetString("antispamignore_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggles whether antispam ignores current channel. Antispam must be enabled.. + /// + public static string antispamignore_desc { + get { + return ResourceManager.GetString("antispamignore_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}antispamignore`. + /// + public static string antispamignore_usage { + get { + return ResourceManager.GetString("antispamignore_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to asar. /// @@ -5712,7 +5766,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Repeat a message every X minutes. If no parameters are specified, repeat is disabled.. + /// Looks up a localized string similar to Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total.. /// public static string repeat_desc { get { @@ -5739,7 +5793,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Immediately shows the repeat message and restarts the timer.. + /// Looks up a localized string similar to Immediately shows the repeat message on a certain index and restarts its timer.. /// public static string repeatinvoke_desc { get { @@ -5748,7 +5802,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}repinv`. + /// Looks up a localized string similar to `{0}repinv 1`. /// public static string repeatinvoke_usage { get { @@ -5756,6 +5810,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to repeatlist replst. + /// + public static string repeatlist_cmd { + get { + return ResourceManager.GetString("repeatlist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows currently repeating messages and their indexes.. + /// + public static string repeatlist_desc { + get { + return ResourceManager.GetString("repeatlist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}repeatlist`. + /// + public static string repeatlist_usage { + get { + return ResourceManager.GetString("repeatlist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to rpeatplaylst rpl. /// @@ -5783,6 +5864,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to repeatremove reprm. + /// + public static string repeatremove_cmd { + get { + return ResourceManager.GetString("repeatremove_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes.. + /// + public static string repeatremove_desc { + get { + return ResourceManager.GetString("repeatremove_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}reprm 2`. + /// + public static string repeatremove_usage { + get { + return ResourceManager.GetString("repeatremove_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to reptcursong rcs. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 3b13300e..d2ef3388 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -265,16 +265,16 @@ repeatinvoke repinv - Immediately shows the repeat message and restarts the timer. + Immediately shows the repeat message on a certain index and restarts its timer. - `{0}repinv` + `{0}repinv 1` repeat - Repeat a message every X minutes. If no parameters are specified, repeat is disabled. + Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. `{0}repeat 5 Hello there` @@ -2889,4 +2889,40 @@ `{0}pollstats` + + repeatlist replst + + + Shows currently repeating messages and their indexes. + + + `{0}repeatlist` + + + repeatremove reprm + + + Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + + + `{0}reprm 2` + + + antilist antilst + + + Shows currently enabled protection features. + + + `{0}antilist` + + + antispamignore + + + Toggles whether antispam ignores current channel. Antispam must be enabled. + + + `{0}antispamignore` + \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs index 7b952b1c..08269207 100644 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs +++ b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs @@ -30,9 +30,9 @@ namespace Services.CleverBotApi public static ChatterBot Create(ChatterBotType type, object arg) { #if GLOBAL_NADEKO - var url = "http://www.cleverbot.com/webservicemin?uc=321&botapi=nadekobot"; + var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=nadekobot"; #else - var url = "http://www.cleverbot.com/webservicemin?uc=321"; + var url = "http://www.cleverbot.com/webservicemin?uc=3210"; #endif switch (type) diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index c90d9736..f17e1f6a 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -15,7 +15,6 @@ namespace NadekoBot.Services.Database IReminderRepository Reminders { get; } ISelfAssignedRolesRepository SelfAssignedRoles { get; } IBotConfigRepository BotConfig { get; } - IRepeaterRepository Repeaters { get; } IUnitConverterRepository ConverterUnits { get; } ICustomReactionRepository CustomReactions { get; } ICurrencyRepository Currency { get; } diff --git a/src/NadekoBot/Services/Database/Models/AntiProtection.cs b/src/NadekoBot/Services/Database/Models/AntiProtection.cs new file mode 100644 index 00000000..0172dd90 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/AntiProtection.cs @@ -0,0 +1,53 @@ +using Discord; +using NadekoBot.Services.Database.Models; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +namespace NadekoBot.Services.Database.Models +{ + public class AntiRaidSetting : DbEntity + { + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public int UserThreshold { get; set; } + public int Seconds { get; set; } + public PunishmentAction Action { get; set; } + } + + public class AntiSpamSetting : DbEntity + { + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public PunishmentAction Action { get; set; } + public int MessageThreshold { get; set; } = 3; + public HashSet IgnoredChannels { get; set; } = new HashSet(); + } + + + public enum PunishmentAction + { + Mute, + Kick, + Ban, + } + + public class AntiSpamIgnore : DbEntity + { + public ulong ChannelId { get; set; } + + public override int GetHashCode() => ChannelId.GetHashCode(); + + public override bool Equals(object obj) + { + var inst = obj as AntiSpamIgnore; + + if (inst == null) + return false; + + return inst.ChannelId == ChannelId; + + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 99608eff..7931e8c9 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using static NadekoBot.Modules.Administration.Administration; namespace NadekoBot.Services.Database.Models { @@ -58,6 +59,12 @@ namespace NadekoBot.Services.Database.Models public string MuteRoleName { get; set; } public bool CleverbotEnabled { get; set; } + public HashSet GuildRepeaters { get; set; } = new HashSet(); + + public AntiRaidSetting AntiRaidSetting { get; set; } + public AntiSpamSetting AntiSpamSetting { get; set; } + + //public List ProtectionIgnoredChannels { get; set; } = new List(); } public class FilterChannelId : DbEntity diff --git a/src/NadekoBot/Services/Database/Models/Repeater.cs b/src/NadekoBot/Services/Database/Models/Repeater.cs index cf887b43..f8c07bfe 100644 --- a/src/NadekoBot/Services/Database/Models/Repeater.cs +++ b/src/NadekoBot/Services/Database/Models/Repeater.cs @@ -2,11 +2,16 @@ namespace NadekoBot.Services.Database.Models { - public class Repeater :DbEntity + public class Repeater : DbEntity { public ulong GuildId { get; set; } public ulong ChannelId { get; set; } public string Message { get; set; } public TimeSpan Interval { get; set; } } + + public class GuildRepeater : Repeater + { + + } } diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index ec7c2288..e955409f 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -16,7 +16,6 @@ namespace NadekoBot.Services.Database public DbSet Reminders { get; set; } public DbSet SelfAssignableRoles { get; set; } public DbSet BotConfig { get; set; } - public DbSet Repeaters { get; set; } public DbSet Currency { get; set; } public DbSet ConversionUnits { get; set; } public DbSet MusicPlaylists { get; set; } @@ -44,6 +43,7 @@ namespace NadekoBot.Services.Database this.Database.Migrate(); EnsureSeedData(); } + ////Uncomment this to db initialisation with dotnet ef migration add [module] //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) //{ @@ -142,6 +142,17 @@ namespace NadekoBot.Services.Database .HasIndex(c => c.GuildId) .IsUnique(); + modelBuilder.Entity() + .HasOne(x => x.GuildConfig) + .WithOne(x => x.AntiSpamSetting); + + modelBuilder.Entity() + .HasOne(x => x.GuildConfig) + .WithOne(x => x.AntiRaidSetting); + + //modelBuilder.Entity() + // .HasAlternateKey(c => new { c.ChannelId, c.ProtectionType }); + #endregion #region BotConfig @@ -172,16 +183,6 @@ namespace NadekoBot.Services.Database #endregion - #region Repeater - - var repeaterEntity = modelBuilder.Entity(); - - repeaterEntity - .HasIndex(r => r.ChannelId) - .IsUnique(); - - #endregion - #region Currency var currencyEntity = modelBuilder.Entity(); @@ -231,6 +232,11 @@ namespace NadekoBot.Services.Database .IsUnique(); + #endregion + + #region Protection + + #endregion } } diff --git a/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs b/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs deleted file mode 100644 index 2446c275..00000000 --- a/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs +++ /dev/null @@ -1,9 +0,0 @@ -using NadekoBot.Services.Database.Models; - -namespace NadekoBot.Services.Database.Repositories -{ - public interface IRepeaterRepository : IRepository - { - - } -} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 0720e8ad..89c59419 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -26,6 +26,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(gc => gc.FilterWordsChannelIds) .Include(gc => gc.FilteredWords) .Include(gc => gc.CommandCooldowns) + .Include(gc => gc.GuildRepeaters) + .Include(gc => gc.AntiRaidSetting) + .Include(gc => gc.AntiSpamSetting) + .ThenInclude(x => x.IgnoredChannels) .ToList(); /// diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs deleted file mode 100644 index 94827f95..00000000 --- a/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using NadekoBot.Services.Database.Models; -using Microsoft.EntityFrameworkCore; - -namespace NadekoBot.Services.Database.Repositories.Impl -{ - public class RepeaterRepository : Repository, IRepeaterRepository - { - public RepeaterRepository(DbContext context) : base(context) - { - } - } -} diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 9601145d..88231d6b 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -30,9 +30,6 @@ namespace NadekoBot.Services.Database private IBotConfigRepository _botConfig; public IBotConfigRepository BotConfig => _botConfig ?? (_botConfig = new BotConfigRepository(_context)); - private IRepeaterRepository _repeaters; - public IRepeaterRepository Repeaters => _repeaters ?? (_repeaters = new RepeaterRepository(_context)); - private ICurrencyRepository _currency; public ICurrencyRepository Currency => _currency ?? (_currency = new CurrencyRepository(_context)); diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index 56a40965..eaa066ff 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -51,7 +51,7 @@ namespace NadekoBot.Services.Impl return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId); } - private readonly Regex YtVideoIdRegex = new Regex("(?:youtu\\.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|\\&v=)(?[^#\\&\\?]*)", RegexOptions.Compiled); + private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); public async Task> GetRelatedVideosAsync(string id, int count = 1) {