Merge pull request #8 from Kwoth/1.0

1.0
This commit is contained in:
miraai 2016-10-16 23:43:21 +02:00 committed by GitHub
commit 7f6d02354d
49 changed files with 2292 additions and 462 deletions

View File

@ -16,8 +16,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "discord.net\
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "discord.net\src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "tests", "src\tests\tests.xproj", "{14CBADA0-971C-44E3-B331-C7D01DD74F0B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -43,18 +41,11 @@ Global
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.Build.0 = Release|Any CPU
{14CBADA0-971C-44E3-B331-C7D01DD74F0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14CBADA0-971C-44E3-B331-C7D01DD74F0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14CBADA0-971C-44E3-B331-C7D01DD74F0B}.GlobalNadeko|Any CPU.ActiveCfg = GlobalNadeko|Any CPU
{14CBADA0-971C-44E3-B331-C7D01DD74F0B}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
{14CBADA0-971C-44E3-B331-C7D01DD74F0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14CBADA0-971C-44E3-B331-C7D01DD74F0B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
{14CBADA0-971C-44E3-B331-C7D01DD74F0B} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
EndGlobalSection
EndGlobal

View File

@ -34,7 +34,7 @@ Command and aliases | Description | Usage
`.savechat` | Saves a number of messages to a text file and sends it to you. | `.savechat 150` **Bot owner only.**
`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `.menro RoleName` **Requires MentionEveryone server permission.**
`.donators` | List of lovely people who donated to keep this project alive. | `.donators`
`.donadd` | Add a donator to the database. **Kwoth Only** | `.donadd Donate Amount` **Bot owner only.**
`.donadd` | Add a donator to the database. | `.donadd Donate Amount` **Bot owner only.**
`.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. | `.aar` to disable, `.aar Role Name` to enable **Requires ManageRoles server permission.**
`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. | `.scsc` **Bot owner only.**
`.jcsc` | Joins current channel to an instance of cross server channel using the token. | `.jcsc TokenHere` **Requires ManageServer server permission.**
@ -53,7 +53,7 @@ Command and aliases | Description | Usage
`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. | `.lipl` **Bot owner only.**
`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. | `.rmpl` **Bot owner only.**
`.slowmode` | Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds. | `.slowmode` **Requires ManageMessages server permission.**
`.asar` | Adds a role, or list of roles separated by whitespace(use quotations for multiword roles) to the list of self-assignable roles. | `.asar Gamer` **Requires ManageRoles server permission.**
`.asar` | Adds a role to the list of self-assignable roles. | `.asar Gamer` **Requires ManageRoles server permission.**
`.rsar` | Removes a specified role from the list of self-assignable roles. | `.rsar` **Requires ManageRoles server permission.**
`.lsar` | Lists all self-assignable roles. | `.lsar`
`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) | `.tesar` **Requires ManageRoles server permission.**
@ -78,38 +78,39 @@ Command and aliases | Description | Usage
`,startwar` `,sw` | Starts a war with a given number. | `,sw 15`
`,listwar` `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `,lw [war_number] or ,lw`
`,claim` `,call` `,c` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | `,call [war_number] [base_number] [optional_other_name]`
`,claimfinish1` `,cf1` | Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument finishes for someone else. | `,cf1 2 SomeGirl`
`,claimfinish2` `,cf2` | Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument finishes for someone else. | `,cf2 1 SomeGuy`
`,claimfinish` `,cf` | Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument finishes for someone else. | `,cf 1 Someone`
`,claimfinish1` `,cf1` | Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf1 1` or `,cf1 1 5`
`,claimfinish2` `,cf2` | Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf2 1` or `,cf2 1 5`
`,claimfinish` `,cf` | Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf 1` or `,cf 1 5`
`,endwar` `,ew` | Ends the war with a given index. | `,ew [war_number]`
`,unclaim` `,ucall` `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `,uc [war_number] [optional_other_name]`
### CustomReactions
Command and aliases | Description | Usage
----------------|--------------|-------
`#addcustreact` `#acr` | Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/1.0/Custom%20Reactions/> | `.acr "hello" Hi there %user%`
`#listcustreact` `#lcr` | Lists global or server custom reactions (15 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcr 1`
`#delcustreact` `#dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. | `.dcr 5`
`.addcustreact` `.acr` | Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/1.0/Custom%20Reactions/> | `.acr "hello" Hi there %user%`
`.listcustreact` `.lcr` | Lists global or server custom reactions (15 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcr 1`
`.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1`
`.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. | `.dcr 5`
### Gambling
Command and aliases | Description | Usage
----------------|--------------|-------
`xraffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName`
`xcash` `x$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy`
`xgive` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
`xaward` | Awards someone a certain amount of currency. | `$award 100 @person` **Bot owner only.**
`xtake` | Takes a certain amount of flowers from someone. | `$take 1 "@someguy"` **Bot owner only.**
`xbetroll` `xbr` | Bets a certain amount of NadekoFlowers and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | `$br 5`
`xleaderboard` `xlb` | Displays bot currency leaderboard. | `$lb`
`xrace` | Starts a new animal race. | `$race`
`xjoinrace` `xjr` | Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
`xroll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$roll` or `$roll 7` or `$roll 3d5`
`xrolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5`
`xnroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
`xdraw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5`
`xshuffle` `xsh` | Reshuffles all cards back into the deck. | `$sh`
`xflip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`
`xbetflip` `xbf` | Bet to guess will the result be heads or tails. Guessing awards you double flowers you've bet. | `$bf 5 heads` or `$bf 3 t`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName`
`$cash` `$$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy`
`$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
`$award` | Awards someone a certain amount of currency. | `$award 100 @person` **Bot owner only.**
`$take` | Takes a certain amount of flowers from someone. | `$take 1 "@someguy"` **Bot owner only.**
`$betroll` `$br` | Bets a certain amount of NadekoFlowers and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | `$br 5`
`$leaderboard` `$lb` | Displays bot currency leaderboard. | `$lb`
`$race` | Starts a new animal race. | `$race`
`$joinrace` `$jr` | Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
`$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$roll` or `$roll 7` or `$roll 3d5`
`$rolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5`
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
`$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5`
`$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh`
`$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`
`$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you double flowers you've bet. | `$bf 5 heads` or `$bf 3 t`
### Games
Command and aliases | Description | Usage
@ -223,7 +224,7 @@ Command and aliases | Description | Usage
----------------|--------------|-------
`~weather` `~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | `~we Moscow RF`
`~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query`
`~imdb` | Queries imdb for movies or series, show first result. | `~imdb Batman vs Superman`
`~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman`
`~randomcat` `~meow` | Shows a random cat image. | `~meow`
`~randomdog` `~woof` | Shows a random dog image. | `~woof`
`~img` `~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | `~i cute kitten`
@ -257,7 +258,7 @@ Command and aliases | Description | Usage
`~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712`
`~osu5` | Displays a user's top 5 plays. | `~osu5 Name`
`~pokemon` `~poke` | Searches for a pokemon. | `~poke Sylveon`
`~pokemonability` `~pokeab` | Searches for a pokemon ability. | `~pokeab "water gun"`
`~pokemonability` `~pokeab` | Searches for a pokemon ability. | `~pokeab overgrow`
`~hitbox` `~hb` | Notifies this channel when a certain user starts streaming. | `~hitbox SomeStreamer` **Requires ManageMessages server permission.**
`~twitch` `~tw` | Notifies this channel when a certain user starts streaming. | `~twitch SomeStreamer` **Requires ManageMessages server permission.**
`~beam` `~bm` | Notifies this channel when a certain user starts streaming. | `~beam SomeStreamer` **Requires ManageMessages server permission.**
@ -274,7 +275,7 @@ Command and aliases | Description | Usage
`.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"`
`.channelid` `.cid` | Shows current channel ID. | `.cid`
`.serverid` `.sid` | Shows current server ID. | `.sid`
`.roles` | List all roles on this server or a single user if specified. | `.roles`
`.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`
`.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 SPECIALemojis`

View File

@ -35,7 +35,6 @@ There are currently three different placeholders which we will look at, with mor
|`%mention`|The `%mention%` placeholder is triggered when you type `@BotName` - It's important to note that if you've given the bot a custom nickname, this trigger won't work!|```.acr "Hello %mention%" I, %mention%, also say hello!```|Input: "Hello @BotName" Output: "I, @BotName, also say hello!"|
|`%user%`|The `%user%` placeholder mentions the person who said the command|`.acr "Who am I?" You are %user%!`|Input: "Who am I?" Output: "You are @Username!"|
|`%rng%`|The `%rng%` placeholder generates a random number between 0 and 10|`.acr "Random number" %rng%`|Input: "Random number" Output: "2"|
[//]: # (|`%target%`|The `%target%` placeholder is used to make Nadeko Mention another person or phrase|`.acr "Say this: " %target%|Input: "Say this: I, @BotName, am a parrot!". Output: "I, @BotName, am a parrot!".|)
|`%target%`|The `%target%` placeholder is used to make Nadeko Mention another person or phrase, it is only supported as part of the response|`.acr "Say this: " %target%`|Input: "Say this: I, @BotName, am a parrot!". Output: "I, @BotName, am a parrot!".|
Thanks to Nekai for being creative. <3

View File

@ -0,0 +1,775 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Services.Database.Impl;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoSqliteContext))]
[Migration("20161015005020_CurrencyTransaction")]
partial class CurrencyTransaction
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
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>("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<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
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>("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<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
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.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.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")
.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.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.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,33 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class CurrencyTransaction : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "CurrencyTransactions",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
Amount = table.Column<long>(nullable: false),
Reason = table.Column<string>(nullable: true),
UserId = table.Column<ulong>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CurrencyTransactions", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CurrencyTransactions");
}
}
}

View File

@ -0,0 +1,777 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Services.Database.Impl;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoSqliteContext))]
[Migration("20161015102407_coc")]
partial class coc
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
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<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
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>("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<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
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.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.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")
.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.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.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,24 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class coc : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "SequenceNumber",
table: "ClashCallers",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SequenceNumber",
table: "ClashCallers");
}
}
}

View File

@ -80,6 +80,8 @@ namespace NadekoBot.Migrations
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
@ -164,6 +166,22 @@ namespace NadekoBot.Migrations
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")

View File

@ -35,6 +35,7 @@ namespace NadekoBot.Modules.Administration
if (channel == null)
return;
//todo cache this
bool shouldDelete;
using (var uow = DbHandler.UnitOfWork())
{
@ -531,7 +532,7 @@ namespace NadekoBot.Modules.Administration
if (string.IsNullOrWhiteSpace(newName))
return;
await NadekoBot.Client.GetCurrentUser().ModifyAsync(u => u.Username = newName).ConfigureAwait(false);
await (await NadekoBot.Client.GetCurrentUserAsync()).ModifyAsync(u => u.Username = newName).ConfigureAwait(false);
await channel.SendMessageAsync($"Successfully changed name to {newName}").ConfigureAwait(false);
}
@ -554,7 +555,7 @@ namespace NadekoBot.Modules.Administration
await sr.CopyToAsync(imgStream);
imgStream.Position = 0;
await NadekoBot.Client.GetCurrentUser().ModifyAsync(u => u.Avatar = imgStream).ConfigureAwait(false);
await (await NadekoBot.Client.GetCurrentUserAsync().ConfigureAwait(false)).ModifyAsync(u => u.Avatar = imgStream).ConfigureAwait(false);
}
}
@ -695,12 +696,14 @@ namespace NadekoBot.Modules.Administration
await channel.SendMessageAsync(send).ConfigureAwait(false);
}
IGuild nadekoSupportServer;
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task Donators(IUserMessage umsg)
{
var channel = (ITextChannel)umsg.Channel;
IEnumerable<Donator> donatorsOrdered;
using (var uow = DbHandler.UnitOfWork())
{
donatorsOrdered = uow.Donators.GetDonatorsOrdered();
@ -708,6 +711,18 @@ namespace NadekoBot.Modules.Administration
string str = $"**Thanks to the people listed below for making this project happen!**\n";
await channel.SendMessageAsync(str + string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false);
nadekoSupportServer = nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850);
if (nadekoSupportServer == null)
return;
var patreonRole = nadekoSupportServer.GetRole(236667642088259585);
if (patreonRole == null)
return;
var usrs = nadekoSupportServer.GetUsers().Where(u => u.Roles.Contains(patreonRole));
await channel.SendMessageAsync("\n`Patreon supporters:`\n" + string.Join("⭐", usrs.Select(d => d.Username))).ConfigureAwait(false);
}

View File

@ -28,7 +28,6 @@ namespace NadekoBot.Modules.Administration
{
conf = uow.GuildConfigs.For(user.Guild.Id);
}
var aarType = conf.AutoAssignRoleId.GetType();
if (conf.AutoAssignRoleId == 0)
return;

View File

@ -411,11 +411,11 @@ namespace NadekoBot.Modules.Administration
{
return cr.Value.Select(res => new CustomReaction()
{
GuildId = 0,
GuildId = null,
IsRegex = false,
OwnerOnly = false,
Response = res,
Trigger = cr.Key,
Trigger = cr.Key.ToLowerInvariant(),
});
}).ToArray());

View File

@ -2,6 +2,7 @@
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database;
using NadekoBot.Services.Database.Models;
@ -21,6 +22,18 @@ namespace NadekoBot.Modules.Administration
public class PlayingRotateCommands
{
private Logger _log { get; }
public static List<PlayingStatus> RotatingStatusMessages { get; }
public static bool RotatingStatuses { get; private set; } = false;
static PlayingRotateCommands()
{
using (var uow = DbHandler.UnitOfWork())
{
var conf = uow.BotConfig.GetOrCreate();
RotatingStatusMessages = conf.RotatingStatusMessages;
RotatingStatuses = conf.RotatingStatuses;
}
}
public PlayingRotateCommands()
{
@ -32,25 +45,21 @@ namespace NadekoBot.Modules.Administration
{
try
{
BotConfig conf;
using (var uow = DbHandler.UnitOfWork())
{
conf = uow.BotConfig.GetOrCreate();
}
if (!conf.RotatingStatuses)
if (!RotatingStatuses)
continue;
else
{
if (index >= conf.RotatingStatusMessages.Count)
if (index >= RotatingStatusMessages.Count)
index = 0;
if (!conf.RotatingStatusMessages.Any())
if (!RotatingStatusMessages.Any())
continue;
await NadekoBot.Client
.GetCurrentUser()
.ModifyStatusAsync(mpp => mpp.Game = new Game(conf.RotatingStatusMessages[index++].Status))
var status = RotatingStatusMessages[index++].Status;
if (string.IsNullOrWhiteSpace(status))
continue;
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value()));
await (await NadekoBot.Client.GetCurrentUserAsync())
.ModifyStatusAsync(mpp => mpp.Game = new Game(status))
.ConfigureAwait(false);
}
}
@ -92,15 +101,14 @@ namespace NadekoBot.Modules.Administration
{
var channel = (ITextChannel)umsg.Channel;
bool status;
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.BotConfig.GetOrCreate();
status = config.RotatingStatuses = !config.RotatingStatuses;
RotatingStatuses = config.RotatingStatuses = !config.RotatingStatuses;
await uow.CompleteAsync();
}
if (status)
if (RotatingStatuses)
await channel.SendMessageAsync("`Rotating playing status enabled.`");
else
await channel.SendMessageAsync("`Rotating playing status disabled.`");
@ -116,7 +124,9 @@ namespace NadekoBot.Modules.Administration
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.BotConfig.GetOrCreate();
config.RotatingStatusMessages.Add(new PlayingStatus { Status = status });
var toAdd = new PlayingStatus { Status = status };
config.RotatingStatusMessages.Add(toAdd);
RotatingStatusMessages.Add(toAdd);
await uow.CompleteAsync();
}
@ -130,18 +140,13 @@ namespace NadekoBot.Modules.Administration
{
var channel = (ITextChannel)umsg.Channel;
List<PlayingStatus> statuses;
using (var uow = DbHandler.UnitOfWork())
{
statuses = uow.BotConfig.GetOrCreate().RotatingStatusMessages;
}
if (!statuses.Any())
if (!RotatingStatusMessages.Any())
await channel.SendMessageAsync("`No rotating playing statuses set.`");
else
{
var i = 1;
await channel.SendMessageAsync($"{umsg.Author.Mention} `Here is a list of rotating statuses:`\n\n\t" + string.Join("\n\t", statuses.Select(rs => $"`{i++}.` {rs.Status}")));
await channel.SendMessageAsync($"{umsg.Author.Mention} `Here is a list of rotating statuses:`\n\n\t" + string.Join("\n\t", RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")));
}
}
@ -163,6 +168,7 @@ namespace NadekoBot.Modules.Administration
return;
msg = config.RotatingStatusMessages[index].Status;
config.RotatingStatusMessages.RemoveAt(index);
RotatingStatusMessages.RemoveAt(index);
await uow.CompleteAsync();
}
await channel.SendMessageAsync($"`Removed the the playing message:` {msg}").ConfigureAwait(false);

View File

@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Administration
if (channel == null) //maybe warn the server owner that the channel is missing
return;
var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username + $" ({user.Id})").Replace("%server%", user.Guild.Name);
var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
if (string.IsNullOrWhiteSpace(msg))
return;
try
@ -78,7 +78,7 @@ namespace NadekoBot.Modules.Administration
var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId);
if (channel != null) //maybe warn the server owner that the channel is missing
{
var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%server%", user.Guild.Name);
var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
if (!string.IsNullOrWhiteSpace(msg))
{
try

View File

@ -21,23 +21,21 @@ namespace NadekoBot.Modules.ClashOfClans
static ClashOfClans()
{
//using (var uow = DbHandler.UnitOfWork())
//{
// ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(
// uow.ClashOfClans
// .GetAllWars()
// .Select(cw => {
// if (cw == null || cw.Bases == null)
// return null;
// cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId)
// ?.GetTextChannel(cw.ChannelId);
// cw.Bases.Capacity = cw.Size;
// return cw;
// })
// .Where(cw => cw?.Channel != null)
// .GroupBy(cw => cw.GuildId)
// .ToDictionary(g => g.Key, g => g.ToList()));
//}
using (var uow = DbHandler.UnitOfWork())
{
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(
uow.ClashOfClans
.GetAllWars()
.Select(cw =>
{
cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId)
?.GetTextChannel(cw.ChannelId);
return cw;
})
.Where(cw => cw?.Channel != null)
.GroupBy(cw => cw.GuildId)
.ToDictionary(g => g.Key, g => g.ToList()));
}
}
public ClashOfClans(ILocalization loc, CommandService cmds, ShardedDiscordClient client) : base(loc, cmds, client)
{
@ -46,9 +44,9 @@ namespace NadekoBot.Modules.ClashOfClans
private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
{
var Bases = war.Bases;
for (var i = 0; i < Bases.Capacity; i++)
for (var i = 0; i < Bases.Count; i++)
{
if (Bases[i] == null) continue;
if (Bases[i].CallUser == null) continue;
if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire)
{
Bases[i] = null;
@ -84,7 +82,6 @@ namespace NadekoBot.Modules.ClashOfClans
var cw = await CreateWar(enemyClan, size, channel.Guild.Id, umsg.Channel.Id);
//cw.Start();
wars.Add(cw);
await channel.SendMessageAsync($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
@ -191,26 +188,26 @@ namespace NadekoBot.Modules.ClashOfClans
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task ClaimFinish1(IUserMessage umsg, int number, int baseNumber, [Remainder] string other_name = null)
public async Task ClaimFinish1(IUserMessage umsg, int number, int baseNumber = 0)
{
var channel = (ITextChannel)umsg.Channel;
await FinishClaim(umsg, number, baseNumber, other_name, 1);
await FinishClaim(umsg, number, baseNumber - 1, 1);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task ClaimFinish2(IUserMessage umsg, int number, int baseNumber, [Remainder] string other_name = null)
public async Task ClaimFinish2(IUserMessage umsg, int number, int baseNumber = 0)
{
var channel = (ITextChannel)umsg.Channel;
await FinishClaim(umsg, number, baseNumber, other_name, 2);
await FinishClaim(umsg, number, baseNumber - 1, 2);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task ClaimFinish(IUserMessage umsg, int number, int baseNumber, [Remainder] string other_name = null)
public async Task ClaimFinish(IUserMessage umsg, int number, int baseNumber = 0)
{
var channel = (ITextChannel)umsg.Channel;
await FinishClaim(umsg, number, baseNumber, other_name);
await FinishClaim(umsg, number, baseNumber - 1);
}
[NadekoCommand, Usage, Description, Aliases]
@ -263,7 +260,7 @@ namespace NadekoBot.Modules.ClashOfClans
}
}
private async Task FinishClaim(IUserMessage umsg, int number, int baseNumber, [Remainder] string other_name, int stars = 3)
private async Task FinishClaim(IUserMessage umsg, int number, int baseNumber, int stars = 3)
{
var channel = (ITextChannel)umsg.Channel;
var warInfo = GetWarInfo(umsg, number);
@ -272,17 +269,19 @@ namespace NadekoBot.Modules.ClashOfClans
await channel.SendMessageAsync("💢🔰 **That war does not exist.**").ConfigureAwait(false);
return;
}
var usr =
string.IsNullOrWhiteSpace(other_name) ?
umsg.Author.Username :
other_name;
var war = warInfo.Item1[warInfo.Item2];
try
{
var baseNum = war.FinishClaim(usr, stars);
if (baseNumber == -1)
{
baseNumber = war.FinishClaim(umsg.Author.Username, stars);
SaveWar(war);
await channel.SendMessageAsync($"❗🔰{umsg.Author.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
}
else
{
war.FinishClaim(baseNumber, stars);
}
await channel.SendMessageAsync($"❗🔰{umsg.Author.Mention} **DESTROYED** a base #{baseNumber + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
}
catch (Exception ex)
{
@ -324,6 +323,16 @@ namespace NadekoBot.Modules.ClashOfClans
Channel = NadekoBot.Client.GetGuild(serverId)
?.GetTextChannel(channelId)
};
cw.Bases.Capacity = size;
for (int i = 0; i < size; i++)
{
cw.Bases.Add(new ClashCaller()
{
CallUser = null,
SequenceNumber = i,
});
}
Console.WriteLine(cw.Bases.Capacity);
uow.ClashOfClans.Add(cw);
await uow.CompleteAsync();
return cw;

View File

@ -30,21 +30,20 @@ namespace NadekoBot.Modules.ClashOfClans
public static void Call(this ClashWar cw, string u, int baseNumber)
{
if (baseNumber < 0 || baseNumber >= cw.Bases.Capacity)
if (baseNumber < 0 || baseNumber >= cw.Bases.Count)
throw new ArgumentException("Invalid base number");
if (cw.Bases[baseNumber] != null)
if (cw.Bases[baseNumber].CallUser != null)
throw new ArgumentException("That base is already claimed.");
for (var i = 0; i < cw.Bases.Capacity; i++)
for (var i = 0; i < cw.Bases.Count; i++)
{
if (cw.Bases[i]?.BaseDestroyed == false && cw.Bases[i]?.CallUser == u)
throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
}
cw.Bases[baseNumber] = new ClashCaller() {
CallUser = u.Trim(),
TimeAdded = DateTime.UtcNow,
BaseDestroyed = false
};
var cc = cw.Bases[baseNumber];
cc.CallUser = u.Trim();
cc.TimeAdded = DateTime.UtcNow;
cc.BaseDestroyed = false;
}
public static void Start(this ClashWar cw)
@ -56,7 +55,7 @@ namespace NadekoBot.Modules.ClashOfClans
//Started = true;
cw.WarState = StateOfWar.Started;
cw.StartedAt = DateTime.UtcNow;
foreach (var b in cw.Bases.Where(b => b != null))
foreach (var b in cw.Bases.Where(b => b.CallUser != null))
{
b.ResetTime();
}
@ -65,10 +64,10 @@ namespace NadekoBot.Modules.ClashOfClans
public static int Uncall(this ClashWar cw, string user)
{
user = user.Trim();
for (var i = 0; i < cw.Bases.Capacity; i++)
for (var i = 0; i < cw.Bases.Count; i++)
{
if (cw.Bases[i]?.CallUser != user) continue;
cw.Bases[i] = null;
cw.Bases[i].CallUser = null;
return i;
}
throw new InvalidOperationException("You are not participating in that war.");
@ -85,9 +84,9 @@ namespace NadekoBot.Modules.ClashOfClans
if (cw.WarState == StateOfWar.Created)
sb.AppendLine("`not started`");
var twoHours = new TimeSpan(2, 0, 0);
for (var i = 0; i < cw.Bases.Capacity; i++)
for (var i = 0; i < cw.Bases.Count; i++)
{
if (cw.Bases[i] == null)
if (cw.Bases[i].CallUser == null)
{
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
}
@ -111,7 +110,7 @@ namespace NadekoBot.Modules.ClashOfClans
public static int FinishClaim(this ClashWar cw, string user, int stars = 3)
{
user = user.Trim();
for (var i = 0; i < cw.Bases.Capacity; i++)
for (var i = 0; i < cw.Bases.Count; i++)
{
if (cw.Bases[i]?.BaseDestroyed != false || cw.Bases[i]?.CallUser != user) continue;
cw.Bases[i].BaseDestroyed = true;
@ -120,5 +119,16 @@ namespace NadekoBot.Modules.ClashOfClans
}
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
}
public static void FinishClaim(this ClashWar cw, int index, int stars = 3)
{
if (index < 0 || index > cw.Bases.Count)
throw new ArgumentOutOfRangeException(nameof(index));
var toFinish = cw.Bases[index];
if (toFinish.BaseDestroyed != false) throw new InvalidOperationException("That base is already destroyed.");
if (toFinish.CallUser == null) throw new InvalidOperationException("That base is unclaimed.");
toFinish.BaseDestroyed = true;
toFinish.Stars = stars;
}
}
}

View File

@ -24,8 +24,8 @@ namespace NadekoBot.Modules.CustomReactions
using (var uow = DbHandler.UnitOfWork())
{
var items = uow.CustomReactions.GetAll();
GuildReactions = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>(items.Where(g => g.GuildId != null).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => new ConcurrentHashSet<CustomReaction>(g)));
GlobalReactions = new ConcurrentHashSet<CustomReaction>(items.Where(g => g.GuildId == null));
GuildReactions = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => new ConcurrentHashSet<CustomReaction>(g)));
GlobalReactions = new ConcurrentHashSet<CustomReaction>(items.Where(g => g.GuildId == null || g.GuildId == 0));
}
}
public CustomReactions(ILocalization loc, CommandService cmds, ShardedDiscordClient client) : base(loc, cmds, client)
@ -33,7 +33,7 @@ namespace NadekoBot.Modules.CustomReactions
client.MessageReceived += (imsg) =>
{
var umsg = imsg as IUserMessage;
if (umsg == null)
if (umsg == null || imsg.Author.IsBot)
return Task.CompletedTask;
var channel = umsg.Channel as ITextChannel;
@ -42,19 +42,29 @@ namespace NadekoBot.Modules.CustomReactions
var t = Task.Run(async () =>
{
var content = umsg.Content.ToLowerInvariant();
var content = umsg.Content.Trim().ToLowerInvariant();
ConcurrentHashSet<CustomReaction> reactions;
GuildReactions.TryGetValue(channel.Guild.Id, out reactions);
if (reactions != null && reactions.Any())
{
var reaction = reactions.Where(cr => cr.TriggerWithContext(umsg) == content).Shuffle().FirstOrDefault();
var reaction = reactions.Where(cr => {
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).Shuffle().FirstOrDefault();
if (reaction != null)
{
try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
return;
}
}
var greaction = GlobalReactions.Where(cr => cr.TriggerWithContext(umsg) == content).Shuffle().FirstOrDefault();
var greaction = GlobalReactions.Where(cr =>
{
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).Shuffle().FirstOrDefault();
if (greaction != null)
{
try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
@ -124,10 +134,32 @@ namespace NadekoBot.Modules.CustomReactions
if (customReactions == null || !customReactions.Any())
await imsg.Channel.SendMessageAsync("`No custom reactions found`").ConfigureAwait(false);
else
await imsg.Channel.SendMessageAsync(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger).Skip((page - 1) * 10).Take(10)))
await imsg.Channel.SendMessageAsync($"`Page {page} of custom reactions:`\n" + string.Join("\n", customReactions.OrderBy(cr => cr.Trigger).Skip((page - 1) * 15).Take(15).Select(cr => $"`#{cr.Id}` `Trigger:` {cr.Trigger}")))
.ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
public async Task ShowCustReact(IUserMessage imsg, int id)
{
var channel = imsg.Channel as ITextChannel;
ConcurrentHashSet<CustomReaction> customReactions;
if (channel == null)
customReactions = GlobalReactions;
else
customReactions = GuildReactions.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CustomReaction>());
var found = customReactions.FirstOrDefault(cr => cr.Id == id);
if (found == null)
await imsg.Channel.SendMessageAsync("`No custom reaction found with that id.`").ConfigureAwait(false);
else
{
await imsg.Channel.SendMessageAsync($"`Custom reaction #{id}`\n`Trigger:` {found.Trigger}\n`Response:` {found.Response}")
.ConfigureAwait(false);
}
}
[NadekoCommand, Usage, Description, Aliases]
public async Task DelCustReact(IUserMessage imsg, int id)
{
@ -147,16 +179,16 @@ namespace NadekoBot.Modules.CustomReactions
if (toDelete == null) //not found
return;
if (toDelete.GuildId == null && channel == null)
if ((toDelete.GuildId == null || toDelete.GuildId == 0) && channel == null)
{
uow.CustomReactions.Remove(toDelete);
GlobalReactions.RemoveWhere(cr => cr.Id == toDelete.Id);
success = true;
}
else if (toDelete.GuildId != null && channel?.Guild.Id == toDelete.GuildId)
else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && channel?.Guild.Id == toDelete.GuildId)
{
uow.CustomReactions.Remove(toDelete);
GuildReactions.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CustomReaction>()).RemoveWhere(cr=>cr.Id == toDelete.Id);
GuildReactions.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CustomReaction>()).RemoveWhere(cr => cr.Id == toDelete.Id);
success = true;
}
if(success)

View File

@ -12,27 +12,45 @@ namespace NadekoBot.Modules.CustomReactions
{
public static class Extensions
{
public static Dictionary<string, Func<IUserMessage, string, string>> responsePlaceholders = new Dictionary<string, Func<IUserMessage, string, string>>()
{
{"%target%", (ctx, trigger) => { return ctx.Content.ToLowerInvariant().Substring(trigger.Length); } }
};
public static Dictionary<string, Func<IUserMessage, string>> placeholders = new Dictionary<string, Func<IUserMessage, string>>()
{
{"%mention%", (ctx) => { return $"<@{NadekoBot.Client.GetCurrentUser().Id}>"; } },
{"%user%", (ctx) => { return ctx.Author.Mention; } },
{"%target%", (ctx) => { return ctx.MentionedUsers.Shuffle().FirstOrDefault()?.Mention ?? "Nobody"; } },
{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } }
};
private static string ResolveCRString(this string str, IUserMessage ctx)
private static string ResolveTriggerString(this string str, IUserMessage ctx)
{
foreach (var ph in placeholders)
{
str = str.Replace(ph.Key, ph.Value(ctx));
str = str.ToLowerInvariant().Replace(ph.Key, ph.Value(ctx));
}
return str;
}
private static string ResolveResponseString(this string str, IUserMessage ctx, string resolvedTrigger)
{
foreach (var ph in placeholders)
{
str = str.ToLowerInvariant().Replace(ph.Key.ToLowerInvariant(), ph.Value(ctx));
}
foreach (var ph in responsePlaceholders)
{
str = str.ToLowerInvariant().Replace(ph.Key.ToLowerInvariant(), ph.Value(ctx, resolvedTrigger));
}
return str;
}
public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx)
=> cr.Trigger.ResolveCRString(ctx);
=> cr.Trigger.ResolveTriggerString(ctx);
public static string ResponseWithContext(this CustomReaction cr, IUserMessage ctx)
=> cr.Response.ResolveCRString(ctx);
=> cr.Response.ResolveResponseString(ctx, cr.Trigger.ResolveTriggerString(ctx));
}
}

View File

@ -87,7 +87,7 @@ namespace NadekoBot.Modules.Gambling
public async Task Give(IUserMessage umsg, long amount, [Remainder] IGuildUser receiver)
{
var channel = (ITextChannel)umsg.Channel;
if (amount <= 0)
if (amount <= 0 || umsg.Author.Id == receiver.Id)
return;
var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)umsg.Author, $"Gift to {receiver.Username} ({receiver.Id}).", amount, true).ConfigureAwait(false);
if (!success)
@ -96,7 +96,7 @@ namespace NadekoBot.Modules.Gambling
return;
}
await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {umsg.Author.Username} ({umsg.Author.Id}).", amount, true).ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully sent {amount} {Gambling.CurrencyPluralName}s to {receiver.Mention}!").ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully sent {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to {receiver.Mention}!").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
@ -117,7 +117,7 @@ namespace NadekoBot.Modules.Gambling
await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({umsg.Author.Username}/{umsg.Author.Id})", (int)amount).ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully awarded {amount} {Gambling.CurrencyName}s to <@{usrId}>!").ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully awarded {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
@ -130,9 +130,9 @@ namespace NadekoBot.Modules.Gambling
return;
if(await CurrencyHandler.RemoveCurrencyAsync(user, $"Taken by bot owner.({umsg.Author.Username}/{umsg.Author.Id})", amount, true).ConfigureAwait(false))
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully took {amount} {Gambling.CurrencyPluralName} from {user}!").ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully took {amount} {(amount == 1? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from {user}!").ConfigureAwait(false);
else
await channel.SendMessageAsync($"{umsg.Author.Mention} was unable to take {amount} {Gambling.CurrencyPluralName} from {user} because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} was unable to take {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from {user} because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false);
}
@ -146,9 +146,9 @@ namespace NadekoBot.Modules.Gambling
return;
if(await CurrencyHandler.RemoveCurrencyAsync(usrId, $"Taken by bot owner.({umsg.Author.Username}/{umsg.Author.Id})", amount).ConfigureAwait(false))
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully took {amount} {Gambling.CurrencyName}s from <@{usrId}>!").ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} successfully took {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from <@{usrId}>!").ConfigureAwait(false);
else
await channel.SendMessageAsync($"{umsg.Author.Mention} was unable to take {amount} {Gambling.CurrencyPluralName} from `{usrId}` because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false);
await channel.SendMessageAsync($"{umsg.Author.Mention} was unable to take {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]

View File

@ -128,7 +128,7 @@ namespace NadekoBot.Modules.Games
return;
if (participants.TryAdd(msg.Author, vote))
{
try { await (ch as ITextChannel).SendMessageAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false); } catch { }
try { await ((IMessageChannel)ch).SendMessageAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false); } catch { }
}
});
return Task.CompletedTask;

View File

@ -124,6 +124,7 @@ namespace NadekoBot.Modules.Music.Classes
AddSong(CurrentSong, 0);
}
catch (OperationCanceledException) { }
finally
{
if (!cancelToken.IsCancellationRequested)
@ -250,9 +251,10 @@ namespace NadekoBot.Modules.Music.Classes
RepeatSong = false;
Destroyed = true;
playlist.Clear();
try { await audioClient.DisconnectAsync(); } catch { }
if (!SongCancelSource.IsCancellationRequested)
SongCancelSource.Cancel();
await audioClient.DisconnectAsync();
});
}

View File

@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Music.Classes
private Logger _log;
public int SkipTo {
get { return SkipTo; }
get { return skipTo; }
set {
skipTo = value;
bytesSent = (ulong)skipTo * 3840 * 50;

View File

@ -72,8 +72,9 @@ namespace NadekoBot.Modules.Music
var channel = (ITextChannel)umsg.Channel;
MusicPlayer musicPlayer;
if (!MusicPlayers.TryRemove(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask;
if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask;
if (((IGuildUser)umsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel)
if(MusicPlayers.TryRemove(channel.Guild.Id, out musicPlayer))
musicPlayer.Destroy();
return Task.CompletedTask;
}

View File

@ -136,7 +136,10 @@ namespace NadekoBot.Modules.Permissions
com += $"<#{perm.PrimaryTargetId}>";
break;
case PrimaryPermissionType.Role:
if(guild == null)
com += $"<@&{perm.PrimaryTargetId}>";
else
com += guild.GetRole(perm.PrimaryTargetId).ToString() ?? $"<@{perm.PrimaryTargetId}>";
break;
case PrimaryPermissionType.Server:
break;

View File

@ -11,12 +11,39 @@ using Discord;
using NadekoBot.Services.Database;
using NadekoBot.Services.Database.Models;
using Discord.API;
using System.Collections.Concurrent;
namespace NadekoBot.Modules.Permissions
{
[NadekoModule("Permissions", ";")]
public partial class Permissions : DiscordModule
{
public class PermissionCache
{
public string PermRole { get; set; }
public bool Verbose { get; set; } = true;
public Permission RootPermission { get; set; }
}
//guildid, root permission
public static ConcurrentDictionary<ulong, PermissionCache> Cache;
static Permissions()
{
using (var uow = DbHandler.UnitOfWork())
{
Cache = new ConcurrentDictionary<ulong, PermissionCache>(uow.GuildConfigs
.PermissionsForAll()
.ToDictionary(k => k.GuildId,
v => new PermissionCache()
{
RootPermission = v.RootPermission,
Verbose = v.VerbosePermissions,
PermRole = v.PermissionRole
}));
}
}
public Permissions(ILocalization loc, CommandService cmds, ShardedDiscordClient client) : base(loc, cmds, client)
{
}
@ -31,6 +58,12 @@ namespace NadekoBot.Modules.Permissions
{
var config = uow.GuildConfigs.For(channel.Guild.Id);
config.VerbosePermissions = action.Value;
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = Permission.GetDefaultRoot(),
Verbose = config.VerbosePermissions
}, (id, old) => { old.Verbose = config.VerbosePermissions; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
@ -52,6 +85,12 @@ namespace NadekoBot.Modules.Permissions
}
else {
config.PermissionRole = role.Name.Trim();
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = Permission.GetDefaultRoot(),
Verbose = config.VerbosePermissions
}, (id, old) => { old.PermRole = role.Name.Trim(); return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
}
@ -107,6 +146,12 @@ namespace NadekoBot.Modules.Permissions
{
p = perms.RemoveAt(index);
}
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
@ -216,6 +261,12 @@ namespace NadekoBot.Modules.Permissions
}
config.RootPermission = fromPerm.GetRoot();
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"`Moved permission:` \"{fromPerm.GetCommand(channel.Guild)}\" `from #{++from} to #{++to}.`").ConfigureAwait(false);
@ -244,7 +295,14 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = command.Text.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{command.Text}` command on this server.").ConfigureAwait(false);
@ -266,7 +324,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = module.Name.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{module.Name}` module on this server.").ConfigureAwait(false);
@ -288,7 +352,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = command.Text.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{command.Text}` command for `{user}` user.").ConfigureAwait(false);
@ -310,7 +380,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = module.Name.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{module.Name}` module for `{user}` user.").ConfigureAwait(false);
@ -332,7 +408,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = command.Text.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{command.Text}` command for `{role}` role.").ConfigureAwait(false);
@ -354,7 +436,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = module.Name.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{module.Name}` module for `{role}` role.").ConfigureAwait(false);
@ -377,7 +465,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = command.Text.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
}
@ -403,7 +497,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = module.Name.ToLowerInvariant(),
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{module.Name}` module for `{chnl}` channel.").ConfigureAwait(false);
@ -425,7 +525,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = "*",
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `ALL MODULES` for `{chnl}` channel.").ConfigureAwait(false);
@ -447,7 +553,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = "*",
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `ALL MODULES` for `{role}` role.").ConfigureAwait(false);
@ -469,7 +581,13 @@ namespace NadekoBot.Modules.Permissions
SecondaryTargetName = "*",
State = action.Value,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, newPerm);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `ALL MODULES` for `{user}` user.").ConfigureAwait(false);
@ -502,7 +620,13 @@ namespace NadekoBot.Modules.Permissions
State = true,
};
uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, allowUser);
var config = uow.GuildConfigs.SetNewRootPermission(channel.Guild.Id, allowUser);
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{
PermRole = config.PermissionRole,
RootPermission = config.RootPermission,
Verbose = config.VerbosePermissions
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `ALL MODULES` on this server.").ConfigureAwait(false);

View File

@ -1,175 +0,0 @@
using NadekoBot.Extensions;
using NadekoBot.Modules.Searches.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
/*******************************************************************************
* Free ASP.net IMDb Scraper API for the new IMDb Template.
* Author: Abhinay Rathore
* Website: http://www.AbhinayRathore.com
* Blog: http://web3o.blogspot.com
* More Info: http://web3o.blogspot.com/2010/11/aspnetc-imdb-scraping-api.html
* Updated By: Gergo Torcsvari
* Last Updated: Feb, 2016
*******************************************************************************/
namespace NadekoBot.Modules.Searches.IMDB
{
public static class ImdbScraper
{
//Search Engine URLs
private static string GoogleSearch = "https://www.google.com/search?q=imdb+";
//Constructor
public static async Task<ImdbMovie> ImdbScrape(string MovieName, bool GetExtraInfo = true)
{
ImdbMovie mov = new ImdbMovie();
string imdbUrl = await GetIMDbUrlAsync(System.Uri.EscapeUriString(MovieName));
mov.Status = false;
if (!string.IsNullOrWhiteSpace(imdbUrl))
{
await ParseIMDbPage(imdbUrl, GetExtraInfo, mov);
}
return mov;
}
public static async Task<ImdbMovie> ImdbScrapeFromId(string imdbId, bool GetExtraInfo = true)
{
ImdbMovie mov = new ImdbMovie();
string imdbUrl = "http://www.imdb.com/title/" + imdbId + "/";
mov.Status = false;
await ParseIMDbPage(imdbUrl, GetExtraInfo, mov);
return mov;
}
public static async Task<string> GetIMDBId(string MovieName)
{
string imdbUrl = await GetIMDbUrlAsync(System.Uri.EscapeUriString(MovieName));
return Match(@"http://www.imdb.com/title/(tt\d{7})", imdbUrl);
}
//Get IMDb URL from search results
private static async Task<string> GetIMDbUrlAsync(string MovieName)
{
string url = GoogleSearch + MovieName;
string html = await GetUrlDataAsync(url);
List<string> imdbUrls = MatchAll(@"<a href=""(http://www.imdb.com/title/tt\d{7}/)"".*?>.*?</a>", html);
if (imdbUrls.Count > 0)
return (string)imdbUrls[0];
else return String.Empty;
}
//Parse IMDb page data
private static async Task ParseIMDbPage(string imdbUrl, bool GetExtraInfo, ImdbMovie mov)
{
string html = await GetUrlDataAsync(imdbUrl + "combined");
mov.Id = Match(@"<link rel=""canonical"" href=""http://www.imdb.com/title/(tt\d{7})/combined"" />", html);
if (!string.IsNullOrEmpty(mov.Id))
{
mov.Status = true;
mov.Title = Match(@"<title>(IMDb \- )*(.*?) \(.*?</title>", html, 2);
mov.OriginalTitle = Match(@"title-extra"">(.*?)<", html);
mov.Year = Match(@"<title>.*?\(.*?(\d{4}).*?\).*?</title>", Match(@"(<title>.*?</title>)", html));
mov.Rating = Match(@"<b>(\d.\d)/10</b>", html);
mov.Genres = MatchAll(@"<a.*?>(.*?)</a>", Match(@"Genre.?:(.*?)(</div>|See more)", html)).Cast<string>().ToList();
mov.Plot = Match(@"Plot:</h5>.*?<div class=""info-content"">(.*?)(<a|</div)", html);
mov.Poster = Match(@"<div class=""photo"">.*?<a name=""poster"".*?><img.*?src=""(.*?)"".*?</div>", html);
if (!string.IsNullOrEmpty(mov.Poster) && mov.Poster.IndexOf("media-imdb.com") > 0)
{
mov.Poster = Regex.Replace(mov.Poster, @"_V1.*?.jpg", "_V1._SY200.jpg");
}
else
{
mov.Poster = string.Empty;
}
mov.ImdbURL = "http://www.imdb.com/title/" + mov.Id + "/";
if (GetExtraInfo)
{
string plotHtml = await GetUrlDataAsync(imdbUrl + "plotsummary");
await GetReleaseDatesAndAka(mov);
}
}
}
//Get all release dates and aka-s
private static async Task GetReleaseDatesAndAka(ImdbMovie mov)
{
Dictionary<string, string> release = new Dictionary<string, string>();
string releasehtml = await GetUrlDataAsync("http://www.imdb.com/title/" + mov.Id + "/releaseinfo");
foreach (string r in MatchAll(@"<tr class="".*?"">(.*?)</tr>", Match(@"<table id=""release_dates"" class=""subpage_data spFirst"">\n*?(.*?)</table>", releasehtml)))
{
Match rd = new Regex(@"<td>(.*?)</td>\n*?.*?<td class=.*?>(.*?)</td>", RegexOptions.Multiline).Match(r);
release[StripHTML(rd.Groups[1].Value.Trim())] = StripHTML(rd.Groups[2].Value.Trim());
}
//mov.ReleaseDates = release;
Dictionary<string, string> aka = new Dictionary<string, string>();
List<string> list = MatchAll(@".*?<tr class="".*?"">(.*?)</tr>", Match(@"<table id=""akas"" class=.*?>\n*?(.*?)</table>", releasehtml));
foreach (string r in list)
{
Match rd = new Regex(@"\n*?.*?<td>(.*?)</td>\n*?.*?<td>(.*?)</td>", RegexOptions.Multiline).Match(r);
aka[StripHTML(rd.Groups[1].Value.Trim())] = StripHTML(rd.Groups[2].Value.Trim());
}
mov.Aka = aka;
}
//Get all media images
private static async Task<List<string>> GetMediaImages(ImdbMovie mov)
{
List<string> list = new List<string>();
string mediaurl = "http://www.imdb.com/title/" + mov.Id + "/mediaindex";
string mediahtml = await GetUrlDataAsync(mediaurl);
int pagecount = MatchAll(@"<a href=""\?page=(.*?)"">", Match(@"<span style=""padding: 0 1em;"">(.*?)</span>", mediahtml)).Count;
for (int p = 1; p <= pagecount + 1; p++)
{
mediahtml = await GetUrlDataAsync(mediaurl + "?page=" + p);
foreach (Match m in new Regex(@"src=""(.*?)""", RegexOptions.Multiline).Matches(Match(@"<div class=""thumb_list"" style=""font-size: 0px;"">(.*?)</div>", mediahtml)))
{
String image = m.Groups[1].Value;
list.Add(Regex.Replace(image, @"_V1\..*?.jpg", "_V1._SY0.jpg"));
}
}
return list;
}
//Get Recommended Titles
private static async Task<List<string>> GetRecommendedTitlesAsync(ImdbMovie mov)
{
List<string> list = new List<string>();
string recUrl = "http://www.imdb.com/widget/recommendations/_ajax/get_more_recs?specs=p13nsims%3A" + mov.Id;
string json = await GetUrlDataAsync(recUrl);
return MatchAll(@"title=\\""(.*?)\\""", json);
}
/*******************************[ Helper Methods ]********************************/
//Match single instance
private static string Match(string regex, string html, int i = 1)
{
return new Regex(regex, RegexOptions.Multiline | RegexOptions.IgnoreCase).Match(html).Groups[i].ToString().Trim();
}
//Match all instances and return as List<string>
private static List<string> MatchAll(string regex, string html, int i = 1)
{
List<string> list = new List<string>();
foreach (Match m in new Regex(regex, RegexOptions.Multiline).Matches(html))
list.Add(m.Groups[i].Value.Trim());
return list;
}
//Strip HTML Tags
private static string StripHTML(string inputString)
{
return Regex.Replace(inputString, @"<.*?>", string.Empty);
}
//Get URL Data
private static async Task<string> GetUrlDataAsync(string url)
{
using (var http = new HttpClient())
{
http.AddFakeHeaders();
return await http.GetStringAsync(url);
}
}
}
}

View File

@ -26,7 +26,7 @@ $@"`Title:` {WebUtility.HtmlDecode(Title)} {(string.IsNullOrEmpty(OriginalTitle)
`Genre:` {GenresAsString}
`Link:` <{ImdbURL}>
`Plot:` {System.Net.WebUtility.HtmlDecode(Plot.TrimTo(500))}
`img:` " + Poster;
`Poster:` " + NadekoBot.Google.ShortenUrl(Poster).GetAwaiter().GetResult();
public string GenresAsString =>
string.Join(", ", Genres);
}

View File

@ -0,0 +1,46 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Searches.Commands.OMDB
{
public static class OmdbProvider
{
private const string queryUrl = "http://www.omdbapi.com/?t={0}&y=&plot=full&r=json";
public static async Task<OmdbMovie> FindMovie(string name)
{
using (var http = new HttpClient())
{
var res = await http.GetStringAsync(String.Format(queryUrl,name.Trim().Replace(' ','+'))).ConfigureAwait(false);
var movie = JsonConvert.DeserializeObject<OmdbMovie>(res);
movie.Poster = await NadekoBot.Google.ShortenUrl(movie.Poster);
return movie;
}
}
}
public class OmdbMovie
{
public string Title { get; set; }
public string Year { get; set; }
public string ImdbRating { get; set; }
public string ImdbId { get; set; }
public string Genre { get; set; }
public string Plot { get; set; }
public string Poster { get; set; }
public override string ToString() =>
$@"`Title:` {Title}
`Year:` {Year}
`Rating:` {ImdbRating}
`Genre:` {Genre}
`Link:` http://www.imdb.com/title/{ImdbId}/
`Plot:` {Plot}";
}
}

View File

@ -12,11 +12,11 @@ using System.Text.RegularExpressions;
using System.Net;
using Discord.WebSocket;
using NadekoBot.Modules.Searches.Models;
using NadekoBot.Modules.Searches.IMDB;
using System.Collections.Generic;
using ImageProcessorCore;
using NadekoBot.Extensions;
using System.IO;
using NadekoBot.Modules.Searches.Commands.OMDB;
namespace NadekoBot.Modules.Searches
{
@ -74,21 +74,14 @@ $@"🌍 **Weather for** 【{obj["target"]}】
if (!(await ValidateQuery(channel, query).ConfigureAwait(false))) return;
await umsg.Channel.TriggerTypingAsync().ConfigureAwait(false);
string result;
try
{
var movie = await ImdbScraper.ImdbScrape(query, true);
if (movie.Status) result = movie.ToString();
else result = "Failed to find that movie.";
}
catch (Exception ex)
var movie = await OmdbProvider.FindMovie(query);
if (movie == null)
{
await channel.SendMessageAsync("Failed to find that movie.").ConfigureAwait(false);
_log.Warn(ex);
return;
}
await channel.SendMessageAsync(result.ToString()).ConfigureAwait(false);
await channel.SendMessageAsync(movie.ToString()).ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]

View File

@ -66,6 +66,7 @@ namespace NadekoBot.Modules.Utility
}
public async Task UpdateCurrency()
{try
{
var currencyRates = await UpdateCurrencyRates();
var unitTypeString = "currency";
@ -96,6 +97,10 @@ namespace NadekoBot.Modules.Utility
Units.AddRange(range);
_log.Info("Updated Currency");
}
catch {
_log.Warn("Failed updating currency.");
}
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task ConvertList(IUserMessage msg)
@ -143,10 +148,10 @@ namespace NadekoBot.Modules.Utility
break;
}
//from Kelvin to target
switch (targetUnit.Triggers.First())
switch (targetUnit.Triggers.First().ToUpperInvariant())
{
case "C":
res = value - 273.15m; //celcius!
res = res - 273.15m; //celcius!
break;
case "F":
res = res * (9m / 5m) - 459.67m;

View File

@ -366,7 +366,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Adds a role, or list of roles separated by whitespace(use quotations for multiword roles) to the list of self-assignable roles..
/// Looks up a localized string similar to Adds a role to the list of self-assignable roles..
/// </summary>
public static string asar_desc {
get {
@ -1338,7 +1338,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument finishes for someone else..
/// Looks up a localized string similar to Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else..
/// </summary>
public static string claimfinish_desc {
get {
@ -1347,7 +1347,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to `,cf 1 Someone`.
/// Looks up a localized string similar to `,cf 1` or `,cf 1 5`.
/// </summary>
public static string claimfinish_usage {
get {
@ -1365,7 +1365,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument finishes for someone else..
/// Looks up a localized string similar to Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else..
/// </summary>
public static string claimfinish1_desc {
get {
@ -1374,7 +1374,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to `,cf1 2 SomeGirl`.
/// Looks up a localized string similar to `,cf1 1` or `,cf1 1 5`.
/// </summary>
public static string claimfinish1_usage {
get {
@ -1392,7 +1392,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument finishes for someone else..
/// Looks up a localized string similar to Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else..
/// </summary>
public static string claimfinish2_desc {
get {
@ -1401,7 +1401,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to `,cf2 1 SomeGuy`.
/// Looks up a localized string similar to `,cf2 1` or `,cf2 1 5`.
/// </summary>
public static string claimfinish2_usage {
get {
@ -2067,7 +2067,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Add a donator to the database. **Kwoth Only**.
/// Looks up a localized string similar to Add a donator to the database..
/// </summary>
public static string donadd_desc {
get {
@ -3111,7 +3111,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to imdb.
/// Looks up a localized string similar to imdb omdb.
/// </summary>
public static string imdb_cmd {
get {
@ -3120,7 +3120,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Queries imdb for movies or series, show first result..
/// Looks up a localized string similar to Queries omdb for movies or series, show first result..
/// </summary>
public static string imdb_desc {
get {
@ -4641,7 +4641,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to `~pokeab &quot;water gun&quot;`.
/// Looks up a localized string similar to `~pokeab overgrow`.
/// </summary>
public static string pokemonability_usage {
get {
@ -5550,7 +5550,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to List all roles on this server or a single user if specified..
/// Looks up a localized string similar to List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page..
/// </summary>
public static string roles_desc {
get {
@ -5559,7 +5559,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to `.roles`.
/// Looks up a localized string similar to `.roles 2` or `.roles @Someone`.
/// </summary>
public static string roles_usage {
get {
@ -6171,7 +6171,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Shows all possible responses from a single custom reaction..
/// Looks up a localized string similar to Shows a custom reaction&apos;s response on a given ID..
/// </summary>
public static string showcustreact_desc {
get {
@ -6180,7 +6180,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to `.scr %mention% bb`.
/// Looks up a localized string similar to `.scr 1`.
/// </summary>
public static string showcustreact_usage {
get {

View File

@ -382,7 +382,7 @@
<value>asar</value>
</data>
<data name="asar_desc" xml:space="preserve">
<value>Adds a role, or list of roles separated by whitespace(use quotations for multiword roles) to the list of self-assignable roles.</value>
<value>Adds a role to the list of self-assignable roles.</value>
</data>
<data name="asar_usage" xml:space="preserve">
<value>`.asar Gamer`</value>
@ -454,10 +454,10 @@
<value>showcustreact scr</value>
</data>
<data name="showcustreact_desc" xml:space="preserve">
<value>Shows all possible responses from a single custom reaction.</value>
<value>Shows a custom reaction's response on a given ID.</value>
</data>
<data name="showcustreact_usage" xml:space="preserve">
<value>`.scr %mention% bb`</value>
<value>`.scr 1`</value>
</data>
<data name="editcustreact_cmd" xml:space="preserve">
<value>editcustreact ecr</value>
@ -796,7 +796,7 @@
<value>donadd</value>
</data>
<data name="donadd_desc" xml:space="preserve">
<value>Add a donator to the database. **Kwoth Only**</value>
<value>Add a donator to the database.</value>
</data>
<data name="donadd_usage" xml:space="preserve">
<value>`.donadd Donate Amount`</value>
@ -940,10 +940,10 @@
<value>roles</value>
</data>
<data name="roles_desc" xml:space="preserve">
<value>List all roles on this server or a single user if specified.</value>
<value>List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page.</value>
</data>
<data name="roles_usage" xml:space="preserve">
<value>`.roles`</value>
<value>`.roles 2` or `.roles @Someone`</value>
</data>
<data name="channeltopic_cmd" xml:space="preserve">
<value>channeltopic ct</value>
@ -1996,7 +1996,7 @@
<value>Searches for a pokemon ability.</value>
</data>
<data name="pokemonability_usage" xml:space="preserve">
<value>`~pokeab "water gun"`</value>
<value>`~pokeab overgrow`</value>
</data>
<data name="memelist_cmd" xml:space="preserve">
<value>memelist</value>
@ -2044,10 +2044,10 @@
<value>`~ani aquarion evol`</value>
</data>
<data name="imdb_cmd" xml:space="preserve">
<value>imdb</value>
<value>imdb omdb</value>
</data>
<data name="imdb_desc" xml:space="preserve">
<value>Queries imdb for movies or series, show first result.</value>
<value>Queries omdb for movies or series, show first result.</value>
</data>
<data name="imdb_usage" xml:space="preserve">
<value>`~imdb Batman vs Superman`</value>
@ -2362,28 +2362,28 @@
<value>claimfinish cf</value>
</data>
<data name="claimfinish_desc" xml:space="preserve">
<value>Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument finishes for someone else.</value>
<value>Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else.</value>
</data>
<data name="claimfinish_usage" xml:space="preserve">
<value>`,cf 1 Someone`</value>
<value>`,cf 1` or `,cf 1 5`</value>
</data>
<data name="claimfinish2_cmd" xml:space="preserve">
<value>claimfinish2 cf2</value>
</data>
<data name="claimfinish2_desc" xml:space="preserve">
<value>Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument finishes for someone else.</value>
<value>Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else.</value>
</data>
<data name="claimfinish2_usage" xml:space="preserve">
<value>`,cf2 1 SomeGuy`</value>
<value>`,cf2 1` or `,cf2 1 5`</value>
</data>
<data name="claimfinish1_cmd" xml:space="preserve">
<value>claimfinish1 cf1</value>
</data>
<data name="claimfinish1_desc" xml:space="preserve">
<value>Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument finishes for someone else.</value>
<value>Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else.</value>
</data>
<data name="claimfinish1_usage" xml:space="preserve">
<value>`,cf1 2 SomeGirl`</value>
<value>`,cf1 1` or `,cf1 1 5`</value>
</data>
<data name="unclaim_cmd" xml:space="preserve">
<value>unclaim ucall uc</value>

View File

@ -129,7 +129,7 @@ namespace NadekoBot.Services
{
var t = await ExecuteCommand(usrMsg, usrMsg.Content, guild, usrMsg.Author, MultiMatchHandling.Best);
var command = t.Item1;
var verbose = t.Item2;
var permCache = t.Item2;
var result = t.Item3;
sw.Stop();
var channel = (usrMsg.Channel as ITextChannel);
@ -165,7 +165,7 @@ namespace NadekoBot.Services
);
if (guild != null && command != null && result.Error == CommandError.Exception)
{
if (verbose)
if (permCache != null && permCache.Verbose)
try { await msg.Channel.SendMessageAsync(":warning: " + result.ErrorReason).ConfigureAwait(false); } catch { }
}
}
@ -189,10 +189,10 @@ namespace NadekoBot.Services
return;
}
public async Task<Tuple<Command,bool, IResult>> ExecuteCommand(IUserMessage message, string input, IGuild guild, IUser user, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Best) {
public async Task<Tuple<Command, PermissionCache, IResult>> ExecuteCommand(IUserMessage message, string input, IGuild guild, IUser user, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Best) {
var searchResult = _commandService.Search(message, input);
if (!searchResult.IsSuccess)
return new Tuple<Command, bool, IResult>(null, false, searchResult);
return new Tuple<Command, PermissionCache, IResult>(null, null, searchResult);
var commands = searchResult.Commands;
for (int i = commands.Count - 1; i >= 0; i--)
@ -201,7 +201,7 @@ namespace NadekoBot.Services
if (!preconditionResult.IsSuccess)
{
if (commands.Count == 1)
return new Tuple<Command, bool, IResult>(null, false, searchResult);
return new Tuple<Command, PermissionCache, IResult>(null, null, searchResult);
else
continue;
}
@ -225,55 +225,55 @@ namespace NadekoBot.Services
if (!parseResult.IsSuccess)
{
if (commands.Count == 1)
return new Tuple<Command, bool, IResult>(null, false, parseResult);
return new Tuple<Command, PermissionCache, IResult>(null, null, parseResult);
else
continue;
}
}
bool verbose = false;
Permission rootPerm = null;
string permRole = "";
var cmd = commands[i];
bool resetCommand = cmd.Name == "ResetPermissions";
PermissionCache pc;
if (guild != null)
{
pc = Permissions.Cache.GetOrAdd(guild.Id, (id) =>
{
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.GuildConfigs.PermissionsFor(guild.Id);
verbose = config.VerbosePermissions;
rootPerm = config.RootPermission;
permRole = config.PermissionRole.Trim().ToLowerInvariant();
}
}
_log.Info("Permissions retrieved");
var cmd = commands[i];
bool resetCommand = cmd.Name == "ResetPermissions";
//check permissions
if (guild != null)
return new PermissionCache()
{
Verbose = config.VerbosePermissions,
RootPermission = config.RootPermission,
PermRole = config.PermissionRole.Trim().ToLowerInvariant(),
};
}
});
int index;
if (!resetCommand && !rootPerm.AsEnumerable().CheckPermissions(message, cmd.Text, cmd.Module.Name, out index))
if (!resetCommand && !pc.RootPermission.AsEnumerable().CheckPermissions(message, cmd.Text, cmd.Module.Name, out index))
{
var returnMsg = $"Permission number #{index + 1} **{rootPerm.GetAt(index).GetCommand()}** is preventing this action.";
return new Tuple<Command, bool, IResult>(cmd, verbose, SearchResult.FromError(CommandError.Exception, returnMsg));
var returnMsg = $"Permission number #{index + 1} **{pc.RootPermission.GetAt(index).GetCommand()}** is preventing this action.";
return new Tuple<Command, PermissionCache, IResult>(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
}
if (cmd.Module.Source.Name == typeof(Permissions).Name) //permissions, you must have special role
{
if (!((IGuildUser)user).Roles.Any(r => r.Name.Trim().ToLowerInvariant() == permRole))
if (!((IGuildUser)user).Roles.Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()))
{
return new Tuple<Command, bool, IResult>(cmd, false, SearchResult.FromError(CommandError.Exception, $"You need the **{permRole}** role in order to use permission commands."));
return new Tuple<Command, PermissionCache, IResult>(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
}
}
}
if (CmdCdsCommands.HasCooldown(cmd, guild, user))
return new Tuple<Command, bool, IResult>(cmd, false, SearchResult.FromError(CommandError.Exception, $"That command is on cooldown for you."));
return new Tuple<Command, PermissionCache, IResult>(cmd, null, SearchResult.FromError(CommandError.Exception, $"That command is on cooldown for you."));
return new Tuple<Command, bool, IResult>(commands[i], false, await commands[i].Execute(message, parseResult));
return new Tuple<Command, PermissionCache, IResult>(commands[i], null, await commands[i].Execute(message, parseResult));
}
return new Tuple<Command, bool, IResult>(null, false, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
return new Tuple<Command, PermissionCache, IResult>(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
}
}

View File

@ -7,6 +7,7 @@ using Discord;
using NadekoBot.Services.Database;
using NadekoBot.Extensions;
using NadekoBot.Modules.Gambling;
using NadekoBot.Services.Database.Models;
namespace NadekoBot.Services
{
@ -33,6 +34,12 @@ namespace NadekoBot.Services
var success = uow.Currency.TryUpdateState(authorId, -amount);
if (!success)
return false;
uow.CurrencyTransactions.Add(new CurrencyTransaction()
{
UserId = authorId,
Reason = reason,
Amount = amount,
});
await uow.CompleteAsync().ConfigureAwait(false);
}
@ -56,6 +63,12 @@ namespace NadekoBot.Services
using (var uow = DbHandler.UnitOfWork())
{
uow.Currency.TryUpdateState(receiverId, amount);
uow.CurrencyTransactions.Add(new CurrencyTransaction()
{
UserId = receiverId,
Reason = reason,
Amount = amount,
});
await uow.CompleteAsync();
}
}

View File

@ -22,6 +22,7 @@ namespace NadekoBot.Services.Database
IUnitConverterRepository ConverterUnits { get; }
ICustomReactionRepository CustomReactions { get; }
ICurrencyRepository Currency { get; }
ICurrencyTransactionsRepository CurrencyTransactions { get; }
IMusicPlaylistRepository MusicPlaylists { get; }
int Complete();

View File

@ -9,6 +9,7 @@ namespace NadekoBot.Services.Database.Models
{
public class ClashCaller : DbEntity
{
public int? SequenceNumber { get; set; } = null;
public string CallUser { get; set; }
public DateTime TimeAdded { get; set; }

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Services.Database.Models
{
public class CurrencyTransaction : DbEntity
{
public long Amount { get; set; }
public string Reason { get; set; }
public ulong UserId { get; set; }
}
}

View File

@ -24,6 +24,7 @@ namespace NadekoBot.Services.Database
public DbSet<ConvertUnit> ConversionUnits { get; set; }
public DbSet<MusicPlaylist> MusicPlaylists { get; set; }
public DbSet<CustomReaction> CustomReactions { get; set; }
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
//logging
public DbSet<LogSetting> LogSettings { get; set; }

View File

@ -0,0 +1,13 @@
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Services.Database.Repositories
{
public interface ICurrencyTransactionsRepository : IRepository<CurrencyTransaction>
{
}
}

View File

@ -12,7 +12,8 @@ namespace NadekoBot.Services.Database.Repositories
{
GuildConfig For(ulong guildId);
GuildConfig PermissionsFor(ulong guildId);
void SetNewRootPermission(ulong guildId, Permission p);
IEnumerable<GuildConfig> PermissionsForAll();
GuildConfig SetNewRootPermission(ulong guildId, Permission p);
IEnumerable<FollowedStream> GetAllFollowedStreams();
}
}

View File

@ -16,8 +16,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
public IEnumerable<ClashWar> GetAllWars()
{
return _set.Include(cw => cw.Bases)
var toReturn = _set.Include(cw => cw.Bases)
.ToList();
toReturn.ForEach(cw => cw.Bases = cw.Bases.Where(w => w.SequenceNumber != null).OrderBy(w => w.SequenceNumber).ToList());
return toReturn;
}
}
}

View File

@ -0,0 +1,17 @@
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace NadekoBot.Services.Database.Repositories.Impl
{
public class CurrencyTransactionsRepository : Repository<CurrencyTransaction>, ICurrencyTransactionsRepository
{
public CurrencyTransactionsRepository(DbContext context) : base(context)
{
}
}
}

View File

@ -90,12 +90,28 @@ namespace NadekoBot.Services.Database.Repositories.Impl
return config;
}
public IEnumerable<GuildConfig> PermissionsForAll()
{
var query = _set.Include(gc => gc.RootPermission);
//todo this is possibly a disaster for performance
//What i could do instead is count the number of permissions in the permission table for this guild
// and make a for loop with those.
// or just select permissions for this guild and manually chain them
for (int i = 0; i < 60; i++)
{
query = query.ThenInclude(gc => gc.Next);
}
return query.ToList();
}
public IEnumerable<FollowedStream> GetAllFollowedStreams() =>
_set.Include(gc => gc.FollowedStreams)
.SelectMany(gc => gc.FollowedStreams)
.ToList();
public void SetNewRootPermission(ulong guildId, Permission p)
public GuildConfig SetNewRootPermission(ulong guildId, Permission p)
{
var data = _set
.Include(gc => gc.RootPermission)
@ -103,6 +119,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl
data.RootPermission.Prepend(p);
data.RootPermission = p;
return data;
}
}
}

View File

@ -39,6 +39,9 @@ namespace NadekoBot.Services.Database
private ICurrencyRepository _currency;
public ICurrencyRepository Currency => _currency ?? (_currency = new CurrencyRepository(_context));
private ICurrencyTransactionsRepository _currencyTransactions;
public ICurrencyTransactionsRepository CurrencyTransactions => _currencyTransactions ?? (_currencyTransactions = new CurrencyTransactionsRepository(_context));
private IUnitConverterRepository _conUnits;
public IUnitConverterRepository ConverterUnits => _conUnits ?? (_conUnits = new UnitConverterRepository(_context));

View File

@ -33,6 +33,8 @@ namespace NadekoBot.Services.Impl
public BotCredentials()
{
_log = LogManager.GetCurrentClassLogger();
try { File.WriteAllText("./credentials_example.json", JsonConvert.SerializeObject(new CredentialsModel(), Formatting.Indented)); } catch { }
if (File.Exists("./credentials.json"))
{
var cm = JsonConvert.DeserializeObject<CredentialsModel>(File.ReadAllText("./credentials.json"));
@ -52,23 +54,23 @@ namespace NadekoBot.Services.Impl
}
else
{
File.WriteAllText("./credentials_example.json", JsonConvert.SerializeObject(new CredentialsModel(), Formatting.Indented));
_log.Fatal($"credentials.json is missing. Failed to start. Example written to {Path.GetFullPath("./credentials_example.json")}");
_log.Fatal($"credentials.json is missing. Failed to start. Example is in {Path.GetFullPath("./credentials_example.json")}");
throw new FileNotFoundException();
}
}
private class CredentialsModel
{
public ulong ClientId { get; set; }
public ulong ClientId { get; set; } = 123123123;
public ulong? BotId { get; set; }
public string Token { get; set; }
public ulong[] OwnerIds { get; set; }
public string LoLApiKey { get; set; }
public string GoogleApiKey { get; set; }
public string MashapeKey { get; set; }
public string OsuApiKey { get; set; }
public string SoundCloudClientId { get; set; }
public string Token { get; set; } = "";
public ulong[] OwnerIds { get; set; } = new ulong[1];
public string LoLApiKey { get; set; } = "";
public string GoogleApiKey { get; set; } = "";
public string MashapeKey { get; set; } = "";
public string OsuApiKey { get; set; } = "";
public string SoundCloudClientId { get; set; } = "";
public DB Db { get; set; }
public int TotalShards { get; set; } = 1;
}

View File

@ -7,6 +7,7 @@ using Google.Apis.Services;
using System.Text.RegularExpressions;
using Google.Apis.Urlshortener.v1;
using Google.Apis.Urlshortener.v1.Data;
using NLog;
namespace NadekoBot.Services.Impl
{
@ -14,6 +15,7 @@ namespace NadekoBot.Services.Impl
{
private YouTubeService yt;
private UrlshortenerService sh;
private Logger _log { get; }
public GoogleApiService()
{
@ -23,6 +25,8 @@ namespace NadekoBot.Services.Impl
ApiKey = NadekoBot.Credentials.GoogleApiKey
};
_log = LogManager.GetCurrentClassLogger();
yt = new YouTubeService(bcs);
sh = new UrlshortenerService(bcs);
}
@ -85,10 +89,17 @@ namespace NadekoBot.Services.Impl
{
if (string.IsNullOrWhiteSpace(url))
throw new ArgumentNullException(nameof(url));
try
{
var response = await sh.Url.Insert(new Url { LongUrl = url }).ExecuteAsync();
return response.Id;
}
catch (Exception ex)
{
_log.Warn(ex);
return url;
}
}
public async Task<IEnumerable<string>> GetPlaylistTracksAsync(string playlistId, int count = 50)
{
@ -108,7 +119,7 @@ namespace NadekoBot.Services.Impl
count -= toGet;
var query = yt.PlaylistItems.List("contentDetails");
query.MaxResults = count;
query.MaxResults = toGet;
query.PlaylistId = playlistId;
query.PageToken = nextPageToken;

View File

@ -33,17 +33,17 @@ namespace NadekoBot.Services.Impl
this.client.Disconnected += _ => Reset();
}
public Task<string> Print()
public async Task<string> Print()
{
var curUser = client.GetCurrentUser();
return Task.FromResult($@"`Author: Kwoth` `Library: Discord.Net`
var curUser = await client.GetCurrentUserAsync();
return $@"`Author: Kwoth` `Library: Discord.Net`
`Bot Version: {BotVersion}`
`Bot id: {curUser.Id}`
`Owners' Ids: {string.Join(", ", NadekoBot.Credentials.OwnerIds)}`
`Uptime: {GetUptimeString()}`
`Servers: {client.GetGuilds().Count} | TextChannels: {client.GetGuilds().SelectMany(g => g.GetChannels().Where(c => c is ITextChannel)).Count()} | VoiceChannels: {client.GetGuilds().SelectMany(g => g.GetChannels().Where(c => c is IVoiceChannel)).Count()}`
`Commands Ran this session: {commandsRan}`
`Messages: {messageCounter} ({messageCounter / (double)GetUptime().TotalSeconds:F2}/sec)` `Heap: {Heap} MB`");
`Messages: {messageCounter} ({messageCounter / (double)GetUptime().TotalSeconds:F2}/sec)` `Heap: {Heap} MB`";
}
public Task Reset()

View File

@ -65,7 +65,10 @@ namespace NadekoBot
}
public ISelfUser GetCurrentUser() =>
Clients.Select(c => c.GetCurrentUser()).FirstOrDefault(u => u != null);
Clients[0].GetCurrentUser();
public Task<ISelfUser> GetCurrentUserAsync() =>
Clients[0].GetCurrentUserAsync();
public IReadOnlyCollection<IGuild> GetGuilds() =>
Clients.SelectMany(c => c.GetGuilds()).ToArray();
@ -74,7 +77,7 @@ namespace NadekoBot
Clients.Select(c => c.GetGuild(id)).FirstOrDefault(g => g != null);
public Task<IDMChannel> GetDMChannelAsync(ulong channelId) =>
Clients.Select(async c => await c.GetDMChannelAsync(channelId).ConfigureAwait(false)).FirstOrDefault(c => c != null);
Clients[0].GetDMChannelAsync(channelId);
internal Task LoginAsync(TokenType tokenType, string token) =>
Task.WhenAll(Clients.Select(async c => { await c.LoginAsync(tokenType, token); _log.Info($"Shard #{c.ShardId} logged in."); }));

View File

@ -24,6 +24,15 @@ namespace NadekoBot.Extensions
http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
}
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> elems, Action<T> exec)
{
foreach (var elem in elems)
{
exec(elem);
}
return elems;
}
public static void AddRange<T>(this HashSet<T> target, IEnumerable<T> elements) where T : class
{
foreach (var item in elements)

View File

@ -0,0 +1,15 @@
{
"ClientId": 123123123,
"BotId": null,
"Token": "",
"OwnerIds": [
0
],
"LoLApiKey": "",
"GoogleApiKey": "",
"MashapeKey": "",
"OsuApiKey": "",
"SoundCloudClientId": "",
"Db": null,
"TotalShards": 1
}