Merge remote-tracking branch 'refs/remotes/Kwoth/dev' into dev

This commit is contained in:
samvaio 2017-01-11 20:36:38 +05:30
commit 0bd0cacfca
36 changed files with 3939 additions and 567 deletions

View File

@ -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 <https://togethertube.com> 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`

View File

@ -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 <https://github.com/Kwoth/NadekoBot>
## 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 <http://nadekobot.readthedocs.io/en/latest> guides.

View File

@ -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

View File

@ -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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<int>("AutoDeleteByeMessagesTimer");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<bool>("CleverbotEnabled");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("MuteRoleName");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<ulong?>("ChannelCreatedId");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong?>("ChannelDestroyedId");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<ulong?>("ChannelUpdatedId");
b.Property<bool>("IsLogging");
b.Property<ulong?>("LogOtherId");
b.Property<bool>("LogUserPresence");
b.Property<ulong?>("LogUserPresenceId");
b.Property<bool>("LogVoicePresence");
b.Property<ulong?>("LogVoicePresenceId");
b.Property<ulong?>("LogVoicePresenceTTSId");
b.Property<bool>("MessageDeleted");
b.Property<ulong?>("MessageDeletedId");
b.Property<bool>("MessageUpdated");
b.Property<ulong?>("MessageUpdatedId");
b.Property<bool>("UserBanned");
b.Property<ulong?>("UserBannedId");
b.Property<bool>("UserJoined");
b.Property<ulong?>("UserJoinedId");
b.Property<bool>("UserLeft");
b.Property<ulong?>("UserLeftId");
b.Property<ulong?>("UserMutedId");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<ulong?>("UserUnbannedId");
b.Property<bool>("UserUpdated");
b.Property<ulong?>("UserUpdatedId");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("MutedUserId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("UserId");
b.Property<string>("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");
});
}
}
}

View File

@ -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<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
GuildId = table.Column<ulong>(nullable: false),
Interval = table.Column<TimeSpan>(nullable: false),
Message = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Repeaters", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_Repeaters_ChannelId",
table: "Repeaters",
column: "ChannelId",
unique: true);
}
}
}

View File

@ -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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<int>("AutoDeleteByeMessagesTimer");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<bool>("CleverbotEnabled");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("MuteRoleName");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GuildRepeater");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<ulong?>("ChannelCreatedId");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong?>("ChannelDestroyedId");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<ulong?>("ChannelUpdatedId");
b.Property<bool>("IsLogging");
b.Property<ulong?>("LogOtherId");
b.Property<bool>("LogUserPresence");
b.Property<ulong?>("LogUserPresenceId");
b.Property<bool>("LogVoicePresence");
b.Property<ulong?>("LogVoicePresenceId");
b.Property<ulong?>("LogVoicePresenceTTSId");
b.Property<bool>("MessageDeleted");
b.Property<ulong?>("MessageDeletedId");
b.Property<bool>("MessageUpdated");
b.Property<ulong?>("MessageUpdatedId");
b.Property<bool>("UserBanned");
b.Property<ulong?>("UserBannedId");
b.Property<bool>("UserJoined");
b.Property<ulong?>("UserJoinedId");
b.Property<bool>("UserLeft");
b.Property<ulong?>("UserLeftId");
b.Property<ulong?>("UserMutedId");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<ulong?>("UserUnbannedId");
b.Property<bool>("UserUpdated");
b.Property<ulong?>("UserUpdatedId");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("MutedUserId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("UserId");
b.Property<string>("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");
});
}
}
}

View File

@ -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<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
GuildConfigId = table.Column<int>(nullable: true),
GuildId = table.Column<ulong>(nullable: false),
Interval = table.Column<TimeSpan>(nullable: false),
Message = table.Column<string>(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");
}
}
}

View File

@ -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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Action");
b.Property<int>("GuildConfigId");
b.Property<int>("Seconds");
b.Property<int>("UserThreshold");
b.HasKey("Id");
b.HasIndex("GuildConfigId")
.IsUnique();
b.ToTable("AntiRaidSetting");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("AntiSpamSettingId");
b.Property<ulong>("ChannelId");
b.HasKey("Id");
b.HasIndex("AntiSpamSettingId");
b.ToTable("AntiSpamIgnore");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Action");
b.Property<int>("GuildConfigId");
b.Property<int>("MessageThreshold");
b.HasKey("Id");
b.HasIndex("GuildConfigId")
.IsUnique();
b.ToTable("AntiSpamSetting");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<int>("AutoDeleteByeMessagesTimer");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<bool>("CleverbotEnabled");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("MuteRoleName");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GuildRepeater");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<ulong?>("ChannelCreatedId");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong?>("ChannelDestroyedId");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<ulong?>("ChannelUpdatedId");
b.Property<bool>("IsLogging");
b.Property<ulong?>("LogOtherId");
b.Property<bool>("LogUserPresence");
b.Property<ulong?>("LogUserPresenceId");
b.Property<bool>("LogVoicePresence");
b.Property<ulong?>("LogVoicePresenceId");
b.Property<ulong?>("LogVoicePresenceTTSId");
b.Property<bool>("MessageDeleted");
b.Property<ulong?>("MessageDeletedId");
b.Property<bool>("MessageUpdated");
b.Property<ulong?>("MessageUpdatedId");
b.Property<bool>("UserBanned");
b.Property<ulong?>("UserBannedId");
b.Property<bool>("UserJoined");
b.Property<ulong?>("UserJoinedId");
b.Property<bool>("UserLeft");
b.Property<ulong?>("UserLeftId");
b.Property<ulong?>("UserMutedId");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<ulong?>("UserUnbannedId");
b.Property<bool>("UserUpdated");
b.Property<ulong?>("UserUpdatedId");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("MutedUserId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("UserId");
b.Property<string>("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");
});
}
}
}

View File

@ -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<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Action = table.Column<int>(nullable: false),
GuildConfigId = table.Column<int>(nullable: false),
Seconds = table.Column<int>(nullable: false),
UserThreshold = table.Column<int>(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<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Action = table.Column<int>(nullable: false),
GuildConfigId = table.Column<int>(nullable: false),
MessageThreshold = table.Column<int>(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<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
AntiSpamSettingId = table.Column<int>(nullable: true),
ChannelId = table.Column<ulong>(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");
}
}
}

View File

@ -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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Action");
b.Property<int>("GuildConfigId");
b.Property<int>("Seconds");
b.Property<int>("UserThreshold");
b.HasKey("Id");
b.HasIndex("GuildConfigId")
.IsUnique();
b.ToTable("AntiRaidSetting");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("AntiSpamSettingId");
b.Property<ulong>("ChannelId");
b.HasKey("Id");
b.HasIndex("AntiSpamSettingId");
b.ToTable("AntiSpamIgnore");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Action");
b.Property<int>("GuildConfigId");
b.Property<int>("MessageThreshold");
b.HasKey("Id");
b.HasIndex("GuildConfigId")
.IsUnique();
b.ToTable("AntiSpamSetting");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
@ -381,6 +440,28 @@ namespace NadekoBot.Migrations
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GuildRepeater");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
@ -663,27 +744,6 @@ namespace NadekoBot.Migrations
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("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")

View File

@ -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<IMessage>(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)]

View File

@ -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<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
}
private class AntiSpamSetting
{
public PunishmentAction Action { get; set; }
public int MessageThreshold { get; set; } = 3;
public ConcurrentDictionary<ulong, UserSpamStats> UserStats { get; set; }
= new ConcurrentDictionary<ulong, UserSpamStats>();
}
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<ulong, AntiRaidSetting> antiRaidGuilds =
new ConcurrentDictionary<ulong, AntiRaidSetting>();
// guildId | (userId|messages)
private static ConcurrentDictionary<ulong, AntiSpamSetting> antiSpamGuilds =
new ConcurrentDictionary<ulong, AntiSpamSetting>();
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);
}
}
}
}
}

View File

@ -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))

View File

@ -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<ulong, RepeatRunner> 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<ulong, RepeatRunner>(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);
}
}
}
}

View File

@ -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<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
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<ulong, UserSpamStats> UserStats { get; set; }
= new ConcurrentDictionary<ulong, UserSpamStats>();
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<ulong, AntiRaidStats> antiRaidGuilds =
new ConcurrentDictionary<ulong, AntiRaidStats>();
// guildId | (userId|messages)
private static ConcurrentDictionary<ulong, AntiSpamStats> antiSpamGuilds =
new ConcurrentDictionary<ulong, AntiSpamStats>();
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);
}
}
}
}

View File

@ -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]

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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()));

View File

@ -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<ulong, ConcurrentQueue<RepeatRunner>> 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<ulong, ConcurrentQueue<RepeatRunner>>(NadekoBot.AllGuildConfigs
.ToDictionary(gc => gc.GuildId,
gc => new ConcurrentQueue<RepeatRunner>(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<RepeatRunner> 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<RepeatRunner> 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<RepeatRunner>(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<RepeatRunner>(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<RepeatRunner> 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);
}
}
}
}

View File

@ -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<IMessage>(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);
}
}
}

View File

@ -437,6 +437,33 @@ namespace NadekoBot.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to antilist antilst.
/// </summary>
public static string antilist_cmd {
get {
return ResourceManager.GetString("antilist_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Shows currently enabled protection features..
/// </summary>
public static string antilist_desc {
get {
return ResourceManager.GetString("antilist_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}antilist`.
/// </summary>
public static string antilist_usage {
get {
return ResourceManager.GetString("antilist_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to antiraid.
/// </summary>
@ -491,6 +518,33 @@ namespace NadekoBot.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to antispamignore.
/// </summary>
public static string antispamignore_cmd {
get {
return ResourceManager.GetString("antispamignore_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Toggles whether antispam ignores current channel. Antispam must be enabled..
/// </summary>
public static string antispamignore_desc {
get {
return ResourceManager.GetString("antispamignore_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}antispamignore`.
/// </summary>
public static string antispamignore_usage {
get {
return ResourceManager.GetString("antispamignore_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to asar.
/// </summary>
@ -5712,7 +5766,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// 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..
/// </summary>
public static string repeat_desc {
get {
@ -5739,7 +5793,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// 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..
/// </summary>
public static string repeatinvoke_desc {
get {
@ -5748,7 +5802,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to `{0}repinv`.
/// Looks up a localized string similar to `{0}repinv 1`.
/// </summary>
public static string repeatinvoke_usage {
get {
@ -5756,6 +5810,33 @@ namespace NadekoBot.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to repeatlist replst.
/// </summary>
public static string repeatlist_cmd {
get {
return ResourceManager.GetString("repeatlist_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Shows currently repeating messages and their indexes..
/// </summary>
public static string repeatlist_desc {
get {
return ResourceManager.GetString("repeatlist_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}repeatlist`.
/// </summary>
public static string repeatlist_usage {
get {
return ResourceManager.GetString("repeatlist_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to rpeatplaylst rpl.
/// </summary>
@ -5783,6 +5864,33 @@ namespace NadekoBot.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to repeatremove reprm.
/// </summary>
public static string repeatremove_cmd {
get {
return ResourceManager.GetString("repeatremove_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes..
/// </summary>
public static string repeatremove_desc {
get {
return ResourceManager.GetString("repeatremove_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}reprm 2`.
/// </summary>
public static string repeatremove_usage {
get {
return ResourceManager.GetString("repeatremove_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to reptcursong rcs.
/// </summary>

View File

@ -265,16 +265,16 @@
<value>repeatinvoke repinv</value>
</data>
<data name="repeatinvoke_desc" xml:space="preserve">
<value>Immediately shows the repeat message and restarts the timer.</value>
<value>Immediately shows the repeat message on a certain index and restarts its timer.</value>
</data>
<data name="repeatinvoke_usage" xml:space="preserve">
<value>`{0}repinv`</value>
<value>`{0}repinv 1`</value>
</data>
<data name="repeat_cmd" xml:space="preserve">
<value>repeat</value>
</data>
<data name="repeat_desc" xml:space="preserve">
<value>Repeat a message every X minutes. If no parameters are specified, repeat is disabled.</value>
<value>Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total.</value>
</data>
<data name="repeat_usage" xml:space="preserve">
<value>`{0}repeat 5 Hello there`</value>
@ -2889,4 +2889,40 @@
<data name="pollstats_usage" xml:space="preserve">
<value>`{0}pollstats`</value>
</data>
<data name="repeatlist_cmd" xml:space="preserve">
<value>repeatlist replst</value>
</data>
<data name="repeatlist_desc" xml:space="preserve">
<value>Shows currently repeating messages and their indexes.</value>
</data>
<data name="repeatlist_usage" xml:space="preserve">
<value>`{0}repeatlist`</value>
</data>
<data name="repeatremove_cmd" xml:space="preserve">
<value>repeatremove reprm</value>
</data>
<data name="repeatremove_desc" xml:space="preserve">
<value>Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes.</value>
</data>
<data name="repeatremove_usage" xml:space="preserve">
<value>`{0}reprm 2`</value>
</data>
<data name="antilist_cmd" xml:space="preserve">
<value>antilist antilst</value>
</data>
<data name="antilist_desc" xml:space="preserve">
<value>Shows currently enabled protection features.</value>
</data>
<data name="antilist_usage" xml:space="preserve">
<value>`{0}antilist`</value>
</data>
<data name="antispamignore_cmd" xml:space="preserve">
<value>antispamignore</value>
</data>
<data name="antispamignore_desc" xml:space="preserve">
<value>Toggles whether antispam ignores current channel. Antispam must be enabled.</value>
</data>
<data name="antispamignore_usage" xml:space="preserve">
<value>`{0}antispamignore`</value>
</data>
</root>

View File

@ -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)

View File

@ -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; }

View File

@ -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<AntiSpamIgnore> IgnoredChannels { get; set; } = new HashSet<AntiSpamIgnore>();
}
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;
}
}
}

View File

@ -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<GuildRepeater> GuildRepeaters { get; set; } = new HashSet<GuildRepeater>();
public AntiRaidSetting AntiRaidSetting { get; set; }
public AntiSpamSetting AntiSpamSetting { get; set; }
//public List<ProtectionIgnoredChannel> ProtectionIgnoredChannels { get; set; } = new List<ProtectionIgnoredChannel>();
}
public class FilterChannelId : DbEntity

View File

@ -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
{
}
}

View File

@ -16,7 +16,6 @@ namespace NadekoBot.Services.Database
public DbSet<Reminder> Reminders { get; set; }
public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; }
public DbSet<BotConfig> BotConfig { get; set; }
public DbSet<Repeater> Repeaters { get; set; }
public DbSet<Currency> Currency { get; set; }
public DbSet<ConvertUnit> ConversionUnits { get; set; }
public DbSet<MusicPlaylist> 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<AntiSpamSetting>()
.HasOne(x => x.GuildConfig)
.WithOne(x => x.AntiSpamSetting);
modelBuilder.Entity<AntiRaidSetting>()
.HasOne(x => x.GuildConfig)
.WithOne(x => x.AntiRaidSetting);
//modelBuilder.Entity<ProtectionIgnoredChannel>()
// .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<Repeater>();
repeaterEntity
.HasIndex(r => r.ChannelId)
.IsUnique();
#endregion
#region Currency
var currencyEntity = modelBuilder.Entity<Currency>();
@ -231,6 +232,11 @@ namespace NadekoBot.Services.Database
.IsUnique();
#endregion
#region Protection
#endregion
}
}

View File

@ -1,9 +0,0 @@
using NadekoBot.Services.Database.Models;
namespace NadekoBot.Services.Database.Repositories
{
public interface IRepeaterRepository : IRepository<Repeater>
{
}
}

View File

@ -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();
/// <summary>

View File

@ -1,12 +0,0 @@
using NadekoBot.Services.Database.Models;
using Microsoft.EntityFrameworkCore;
namespace NadekoBot.Services.Database.Repositories.Impl
{
public class RepeaterRepository : Repository<Repeater>, IRepeaterRepository
{
public RepeaterRepository(DbContext context) : base(context)
{
}
}
}

View File

@ -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));

View File

@ -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=)(?<id>[^#\\&\\?]*)", 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<IEnumerable<string>> GetRelatedVideosAsync(string id, int count = 1)
{