From 1a2d1398a7c0004da01ab1b9ea11d39b2d340f7b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Sep 2016 20:53:49 +0200 Subject: [PATCH] More work on permission system, fixes --- .../20160910180231_first.Designer.cs | 556 ------------------ .../Migrations/20160920004320_second.cs | 47 -- ...er.cs => 20160922170157_perms.Designer.cs} | 18 +- ...80231_first.cs => 20160922170157_perms.cs} | 34 +- .../NadekoSqliteContextModelSnapshot.cs | 14 +- .../Modules/Gambling/Commands/AnimalRacing.cs | 2 +- .../Games/Commands/PlantAndPickCommands.cs | 4 +- src/NadekoBot/Modules/Music/Music.cs | 2 +- .../Permissions/PermissionExtensions.cs | 121 ++++ .../Modules/Permissions/Permissions.cs | 43 +- .../Resources/CommandStrings.Designer.cs | 27 + src/NadekoBot/Resources/CommandStrings.resx | 9 + src/NadekoBot/Services/CommandHandler.cs | 70 ++- .../Services/Database/Models/Permission.cs | 18 +- .../Impl/GuildConfigRepository.cs | 1 + 15 files changed, 326 insertions(+), 640 deletions(-) delete mode 100644 src/NadekoBot/Migrations/20160910180231_first.Designer.cs delete mode 100644 src/NadekoBot/Migrations/20160920004320_second.cs rename src/NadekoBot/Migrations/{20160920004320_second.Designer.cs => 20160922170157_perms.Designer.cs} (98%) rename src/NadekoBot/Migrations/{20160910180231_first.cs => 20160922170157_perms.cs} (94%) create mode 100644 src/NadekoBot/Modules/Permissions/PermissionExtensions.cs diff --git a/src/NadekoBot/Migrations/20160910180231_first.Designer.cs b/src/NadekoBot/Migrations/20160910180231_first.Designer.cs deleted file mode 100644 index 1097f981..00000000 --- a/src/NadekoBot/Migrations/20160910180231_first.Designer.cs +++ /dev/null @@ -1,556 +0,0 @@ -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("20160910180231_first")] - partial class first - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("ProductVersion", "1.0.0-rtm-21431"); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("BotConfigId"); - - b.Property("ItemId"); - - b.HasKey("Id"); - - b.HasIndex("BotConfigId"); - - b.ToTable("BlacklistItem"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("BufferSize"); - - b.Property("CurrencyGenerationChance"); - - b.Property("CurrencyGenerationCooldown"); - - b.Property("CurrencyName"); - - b.Property("CurrencyPluralName"); - - b.Property("CurrencySign"); - - b.Property("DontJoinServers"); - - b.Property("ForwardMessages"); - - b.Property("ForwardToAllOwners"); - - b.Property("RemindMessageFormat"); - - b.Property("RotatingStatuses"); - - b.HasKey("Id"); - - b.ToTable("BotConfig"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("BaseDestroyed"); - - b.Property("CallUser"); - - b.Property("ClashWarId"); - - b.Property("Stars"); - - b.Property("TimeAdded"); - - b.HasKey("Id"); - - b.HasIndex("ClashWarId"); - - b.ToTable("ClashCallers"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("EnemyClan"); - - b.Property("GuildId"); - - b.Property("Size"); - - b.Property("StartedAt"); - - b.Property("WarState"); - - b.HasKey("Id"); - - b.ToTable("ClashOfClans"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("InternalTrigger"); - - b.Property("Modifier"); - - b.Property("UnitType"); - - b.HasKey("Id"); - - b.ToTable("ConversionUnits"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Amount"); - - b.Property("UserId"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("Currency"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Amount"); - - b.Property("Name"); - - b.Property("UserId"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("Donators"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("BotConfigId"); - - b.Property("Text"); - - b.HasKey("Id"); - - b.HasIndex("BotConfigId"); - - b.ToTable("EightBallResponses"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("GuildConfigId"); - - b.Property("GuildId"); - - b.Property("LastStatus"); - - b.Property("Type"); - - b.Property("Username"); - - b.HasKey("Id"); - - b.HasIndex("GuildConfigId"); - - b.ToTable("FollowedStream"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AutoAssignRoleId"); - - b.Property("AutoDeleteByeMessages"); - - b.Property("AutoDeleteGreetMessages"); - - b.Property("AutoDeleteGreetMessagesTimer"); - - b.Property("AutoDeleteSelfAssignedRoleMessages"); - - b.Property("ByeMessageChannelId"); - - b.Property("ChannelByeMessageText"); - - b.Property("ChannelGreetMessageText"); - - b.Property("DefaultMusicVolume"); - - b.Property("DeleteMessageOnCommand"); - - b.Property("DmGreetMessageText"); - - b.Property("ExclusiveSelfAssignedRoles"); - - b.Property("GenerateCurrencyChannelId"); - - b.Property("GreetMessageChannelId"); - - b.Property("GuildId"); - - b.Property("LogSettingId"); - - b.Property("SendChannelByeMessage"); - - b.Property("SendChannelGreetMessage"); - - b.Property("SendDmGreetMessage"); - - b.Property("VoicePlusTextEnabled"); - - b.HasKey("Id"); - - b.HasIndex("GuildId") - .IsUnique(); - - b.HasIndex("LogSettingId"); - - b.ToTable("GuildConfigs"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("LogSettingId"); - - b.HasKey("Id"); - - b.HasIndex("LogSettingId"); - - b.ToTable("IgnoredLogChannels"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("LogSettingId"); - - b.HasKey("Id"); - - b.HasIndex("LogSettingId"); - - b.ToTable("IgnoredVoicePresenceCHannels"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelCreated"); - - b.Property("ChannelDestroyed"); - - b.Property("ChannelId"); - - b.Property("ChannelUpdated"); - - b.Property("IsLogging"); - - b.Property("LogUserPresence"); - - b.Property("LogVoicePresence"); - - b.Property("MessageDeleted"); - - b.Property("MessageReceived"); - - b.Property("MessageUpdated"); - - b.Property("UserBanned"); - - b.Property("UserJoined"); - - b.Property("UserLeft"); - - b.Property("UserPresenceChannelId"); - - b.Property("UserUnbanned"); - - b.Property("UserUpdated"); - - b.Property("VoicePresenceChannelId"); - - b.HasKey("Id"); - - b.ToTable("LogSettings"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("BotConfigId"); - - b.Property("ModuleName"); - - b.Property("Prefix"); - - b.HasKey("Id"); - - b.HasIndex("BotConfigId"); - - b.ToTable("ModulePrefixes"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("BotConfigId"); - - b.Property("Status"); - - b.HasKey("Id"); - - b.HasIndex("BotConfigId"); - - b.ToTable("PlayingStatus"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AuthorId"); - - b.Property("AuthorName") - .IsRequired(); - - b.Property("GuildId"); - - b.Property("Keyword") - .IsRequired(); - - b.Property("Text") - .IsRequired(); - - b.HasKey("Id"); - - b.ToTable("Quotes"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("BotConfigId"); - - b.Property("Icon"); - - b.Property("Name"); - - b.HasKey("Id"); - - b.HasIndex("BotConfigId"); - - b.ToTable("RaceAnimals"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("IsPrivate"); - - b.Property("Message"); - - b.Property("ServerId"); - - b.Property("UserId"); - - b.Property("When"); - - b.HasKey("Id"); - - b.ToTable("Reminders"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("GuildId"); - - b.Property("Interval"); - - b.Property("Message"); - - b.HasKey("Id"); - - b.HasIndex("ChannelId") - .IsUnique(); - - b.ToTable("Repeaters"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("GuildId"); - - b.Property("RoleId"); - - b.HasKey("Id"); - - b.HasIndex("GuildId", "RoleId") - .IsUnique(); - - b.ToTable("SelfAssignableRoles"); - }); - - modelBuilder.Entity("NadekoBot.Services.Database.Models.TypingArticle", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Author"); - - b.Property("Text"); - - b.HasKey("Id"); - - b.ToTable("TypingArticles"); - }); - - 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.EightBallResponse", b => - { - b.HasOne("NadekoBot.Services.Database.Models.BotConfig") - .WithMany("EightBallResponses") - .HasForeignKey("BotConfigId"); - }); - - 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.GuildConfig", b => - { - b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") - .WithMany() - .HasForeignKey("LogSettingId"); - }); - - 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", "BotConfig") - .WithMany("ModulePrefixes") - .HasForeignKey("BotConfigId") - .OnDelete(DeleteBehavior.Cascade); - }); - - 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.RaceAnimal", b => - { - b.HasOne("NadekoBot.Services.Database.Models.BotConfig") - .WithMany("RaceAnimals") - .HasForeignKey("BotConfigId"); - }); - } - } -} diff --git a/src/NadekoBot/Migrations/20160920004320_second.cs b/src/NadekoBot/Migrations/20160920004320_second.cs deleted file mode 100644 index 7b417d43..00000000 --- a/src/NadekoBot/Migrations/20160920004320_second.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace NadekoBot.Migrations -{ - public partial class second : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Permission", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Autoincrement", true), - Command = table.Column(nullable: true), - GuildConfigId = table.Column(nullable: true), - Module = table.Column(nullable: true), - State = table.Column(nullable: false), - Target = table.Column(nullable: true), - TargetType = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Permission", x => x.Id); - table.ForeignKey( - name: "FK_Permission_GuildConfigs_GuildConfigId", - column: x => x.GuildConfigId, - principalTable: "GuildConfigs", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_Permission_GuildConfigId", - table: "Permission", - column: "GuildConfigId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Permission"); - } - } -} diff --git a/src/NadekoBot/Migrations/20160920004320_second.Designer.cs b/src/NadekoBot/Migrations/20160922170157_perms.Designer.cs similarity index 98% rename from src/NadekoBot/Migrations/20160920004320_second.Designer.cs rename to src/NadekoBot/Migrations/20160922170157_perms.Designer.cs index c39b6fd1..737b3c23 100644 --- a/src/NadekoBot/Migrations/20160920004320_second.Designer.cs +++ b/src/NadekoBot/Migrations/20160922170157_perms.Designer.cs @@ -8,8 +8,8 @@ using NadekoBot.Services.Database.Impl; namespace NadekoBot.Migrations { [DbContext(typeof(NadekoSqliteContext))] - [Migration("20160920004320_second")] - partial class second + [Migration("20160922170157_perms")] + partial class perms { protected override void BuildTargetModel(ModelBuilder modelBuilder) { @@ -354,18 +354,18 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); - b.Property("Command"); - b.Property("GuildConfigId"); - b.Property("Module"); + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); b.Property("State"); - b.Property("Target"); - - b.Property("TargetType"); - b.HasKey("Id"); b.HasIndex("GuildConfigId"); diff --git a/src/NadekoBot/Migrations/20160910180231_first.cs b/src/NadekoBot/Migrations/20160922170157_perms.cs similarity index 94% rename from src/NadekoBot/Migrations/20160910180231_first.cs rename to src/NadekoBot/Migrations/20160922170157_perms.cs index c24604f5..e892e494 100644 --- a/src/NadekoBot/Migrations/20160910180231_first.cs +++ b/src/NadekoBot/Migrations/20160922170157_perms.cs @@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace NadekoBot.Migrations { - public partial class first : Migration + public partial class perms : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -428,6 +428,30 @@ namespace NadekoBot.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateTable( + name: "Permission", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Autoincrement", true), + GuildConfigId = table.Column(nullable: true), + PrimaryTarget = table.Column(nullable: false), + PrimaryTargetId = table.Column(nullable: false), + SecondaryTarget = table.Column(nullable: false), + SecondaryTargetName = table.Column(nullable: true), + State = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Permission", x => x.Id); + table.ForeignKey( + name: "FK_Permission_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + migrationBuilder.CreateIndex( name: "IX_BlacklistItem_BotConfigId", table: "BlacklistItem", @@ -486,6 +510,11 @@ namespace NadekoBot.Migrations table: "ModulePrefixes", column: "BotConfigId"); + migrationBuilder.CreateIndex( + name: "IX_Permission_GuildConfigId", + table: "Permission", + column: "GuildConfigId"); + migrationBuilder.CreateIndex( name: "IX_PlayingStatus_BotConfigId", table: "PlayingStatus", @@ -541,6 +570,9 @@ namespace NadekoBot.Migrations migrationBuilder.DropTable( name: "ModulePrefixes"); + migrationBuilder.DropTable( + name: "Permission"); + migrationBuilder.DropTable( name: "PlayingStatus"); diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 06546b13..232314b2 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -353,18 +353,18 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); - b.Property("Command"); - b.Property("GuildConfigId"); - b.Property("Module"); + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); b.Property("State"); - b.Property("Target"); - - b.Property("TargetType"); - b.HasKey("Id"); b.HasIndex("GuildConfigId"); diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index 7870fa6a..15ea002d 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -96,7 +96,7 @@ namespace NadekoBot.Modules.Gambling { try { - await raceChannel.SendMessageAsync($"🏁`Race is starting in 20 seconds or when the room is full. Type {NadekoBot.ModulePrefixes["Gambling"]}jr to join the race.`"); + await raceChannel.SendMessageAsync($"🏁`Race is starting in 20 seconds or when the room is full. Type {NadekoBot.ModulePrefixes[typeof(Gambling).Name]}jr to join the race.`"); var t = await Task.WhenAny(Task.Delay(20000, token), fullgame); Started = true; cancelSource.Cancel(); diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index a6976739..689aea42 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -86,7 +86,7 @@ namespace NadekoBot.Modules.Games { var sent = await channel.SendFileAsync( GetRandomCurrencyImagePath(), - $"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes["Gambling"]}pick`") + $"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") .ConfigureAwait(false); plantedFlowers.AddOrUpdate(channel.Id, new List() { sent }, (id, old) => { old.Add(sent); return old; }); } @@ -148,7 +148,7 @@ namespace NadekoBot.Modules.Games IUserMessage msg; var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(Gambling.Gambling.CurrencyName[0]); - var msgToSend = $"Oh how Nice! **{imsg.Author.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.Gambling.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes["Games"]}pick"; + var msgToSend = $"Oh how Nice! **{imsg.Author.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.Gambling.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Gambling.Gambling).Name]}pick"; if (file == null) { msg = await channel.SendMessageAsync(Gambling.Gambling.CurrencySign).ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 5675eff1..b2709a72 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -17,7 +17,7 @@ using NadekoBot.Services.Database; namespace NadekoBot.Modules.Music { - [NadekoModule("ClashOfClans", "!!")] + [NadekoModule("Music", "!!")] public partial class Music : DiscordModule { public static ConcurrentDictionary MusicPlayers = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs b/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs new file mode 100644 index 00000000..f1c668c7 --- /dev/null +++ b/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs @@ -0,0 +1,121 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Permissions +{ + public static class PermissionExtensions + { + public static bool CheckPermissions(this IEnumerable permsEnumerable, IUserMessage message, Command command) + { + var perms = permsEnumerable as List ?? permsEnumerable.ToList(); + int throwaway; + return perms.CheckPermissions(message, command, out throwaway); + } + + public static bool CheckPermissions(this IEnumerable permsEnumerable, IUserMessage message, Command command, out int permIndex) + { + var perms = permsEnumerable as List ?? permsEnumerable.ToList(); + + for (int i = 0; i < perms.Count; i++) + { + var perm = perms[i]; + + var result = perm.CheckPermission(message, command); + + if (result == null) + { + continue; + } + else + { + permIndex = i + 1; + return result.Value; + } + } + permIndex = -1; //defaut behaviour + return true; + } + + //null = not applicable + //true = applicable, allowed + //false = applicable, not allowed + public static bool? CheckPermission(this Permission perm, IUserMessage message, Command command) + { + if (!((perm.SecondaryTarget == SecondaryPermissionType.Command && + perm.SecondaryTargetName == command.Text.ToLowerInvariant()) || + (perm.SecondaryTarget == SecondaryPermissionType.Module && + perm.SecondaryTargetName == command.Module.Name.ToLowerInvariant()))) + return null; + + switch (perm.PrimaryTarget) + { + case PrimaryPermissionType.User: + if (perm.PrimaryTargetId == message.Author.Id) + return perm.State; + break; + case PrimaryPermissionType.Channel: + if (perm.PrimaryTargetId == message.Channel.Id) + return perm.State; + break; + case PrimaryPermissionType.Role: + var guildUser = message.Author as IGuildUser; + if (guildUser == null) + break; + if (guildUser.Roles.Any(r => r.Id == perm.PrimaryTargetId)) + return perm.State; + break; + } + return null; + } + + public static string GetCommand(this Permission perm) + { + var com = NadekoBot.ModulePrefixes[typeof(Permissions).Name]; + switch (perm.PrimaryTarget) + { + case PrimaryPermissionType.User: + com += "u"; + break; + case PrimaryPermissionType.Channel: + com += "c"; + break; + case PrimaryPermissionType.Role: + com += "r"; + break; + } + + switch (perm.SecondaryTarget) + { + case SecondaryPermissionType.Module: + com += "m"; + break; + case SecondaryPermissionType.Command: + com += "c"; + break; + } + com += " " + perm.SecondaryTargetName + " " + (perm.State ? "enable" : "disable") + " "; + + switch (perm.PrimaryTarget) + { + case PrimaryPermissionType.User: + com += $"<@{perm.PrimaryTargetId}>"; + break; + case PrimaryPermissionType.Channel: + com += $"<#{perm.PrimaryTargetId}>"; + break; + case PrimaryPermissionType.Role: + com += $"<@&{perm.PrimaryTargetId}>"; + break; + } + + return com; + } + + } +} diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index 743f5a26..8a9357d3 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -20,6 +20,27 @@ namespace NadekoBot.Modules.Permissions { } + [LocalizedCommand, LocalizedDescription, LocalizedSummary, LocalizedAlias] + [RequireContext(ContextType.Guild)] + public async Task ListPerms(IUserMessage msg) + { + var channel = (ITextChannel)msg.Channel; + + string toSend = ""; + using (var uow = DbHandler.UnitOfWork()) + { + var perms = uow.GuildConfigs.For(channel.Guild.Id).Permissions; + + var i = 1; + toSend = String.Join("\n", perms.Select(p => $"`{(i++)}.` {p.GetCommand()}")); + } + + if (string.IsNullOrWhiteSpace(toSend)) + await channel.SendMessageAsync("`No permissions set.`").ConfigureAwait(false); + else + await channel.SendMessageAsync(toSend).ConfigureAwait(false); + } + [LocalizedCommand, LocalizedDescription, LocalizedSummary, LocalizedAlias] [RequireContext(ContextType.Guild)] public async Task UsrCmd(IUserMessage imsg, Command command, PermissionAction action, IGuildUser user) @@ -30,14 +51,15 @@ namespace NadekoBot.Modules.Permissions { uow.GuildConfigs.For(channel.Guild.Id).Permissions.Add(new Permission { - TargetType = PermissionType.User, - Target = user.Id.ToString(), - Command = command.Text.ToLowerInvariant(), + PrimaryTarget = PrimaryPermissionType.User, + PrimaryTargetId = user.Id, + SecondaryTarget = SecondaryPermissionType.Command, + SecondaryTargetName = command.Text.ToLowerInvariant(), State = action.Value, }); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } - await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{command.Text}` command for `{user}` user."); + await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{command.Text}` command for `{user}` user.").ConfigureAwait(false); } [LocalizedCommand, LocalizedDescription, LocalizedSummary, LocalizedAlias] @@ -50,14 +72,15 @@ namespace NadekoBot.Modules.Permissions { uow.GuildConfigs.For(channel.Guild.Id).Permissions.Add(new Permission { - TargetType = PermissionType.User, - Target = user.Id.ToString(), - Module = module.Name.ToLowerInvariant(), + PrimaryTarget = PrimaryPermissionType.User, + PrimaryTargetId = user.Id, + SecondaryTarget = SecondaryPermissionType.Module, + SecondaryTargetName = module.Name.ToLowerInvariant(), State = action.Value, }); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } - await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{module.Name}` module for `{user}` user."); + await channel.SendMessageAsync($"{(action.Value ? "Allowed" : "Denied")} usage of `{module.Name}` module for `{user}` user.").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 25136f16..b727a16e 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -3596,6 +3596,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Lists whole permission chain with their indexes.. + /// + public static string listperms_desc { + get { + return ResourceManager.GetString("listperms_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `;lp`. + /// + public static string listperms_summary { + get { + return ResourceManager.GetString("listperms_summary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to listperms lp. + /// + public static string listperms_text { + get { + return ResourceManager.GetString("listperms_text", resourceCulture); + } + } + /// /// Looks up a localized string similar to Lists all playing statuses with their corresponding number. **Bot Owner Only!**. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index e43b132f..5425ea2f 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2637,4 +2637,13 @@ cash $$ + + Lists whole permission chain with their indexes. + + + `;lp` + + + listperms lp + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 493571ce..03863b8a 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -8,6 +8,9 @@ using Discord; using NLog; using System.Diagnostics; using Discord.Commands; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Permissions; namespace NadekoBot.Services { @@ -33,11 +36,15 @@ namespace NadekoBot.Services var usrMsg = msg as IUserMessage; if (usrMsg == null) return Task.CompletedTask; + + var guild = (msg.Channel as ITextChannel)?.Guild; + var throwaway = Task.Run(async () => { var sw = new Stopwatch(); sw.Start(); - var t = await _commandService.Execute(usrMsg, usrMsg.Content, MultiMatchHandling.Best); + + var t = await ExecuteCommand(usrMsg, usrMsg.Content, guild, usrMsg.Author, MultiMatchHandling.Best); var command = t.Item1; var result = t.Item2; sw.Stop(); @@ -77,6 +84,67 @@ namespace NadekoBot.Services return Task.CompletedTask; } + + public async Task> 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(null, searchResult); + + var commands = searchResult.Commands; + for (int i = commands.Count - 1; i >= 0; i--) + { + var preconditionResult = await commands[i].CheckPreconditions(message); + if (!preconditionResult.IsSuccess) + { + if (commands.Count == 1) + return new Tuple(null, searchResult); + else + continue; + } + + var parseResult = await commands[i].Parse(message, searchResult, preconditionResult); + if (!parseResult.IsSuccess) + { + if (parseResult.Error == CommandError.MultipleMatches) + { + TypeReaderValue[] argList, paramList; + switch (multiMatchHandling) + { + case MultiMatchHandling.Best: + argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToArray(); + paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToArray(); + parseResult = ParseResult.FromSuccess(argList, paramList); + break; + } + } + + if (!parseResult.IsSuccess) + { + if (commands.Count == 1) + return new Tuple(null, parseResult); + else + continue; + } + } + var cmd = commands[i]; + List perms; + //check permissions + if (guild != null) + { + using (var uow = DbHandler.UnitOfWork()) + { + perms = uow.GuildConfigs.For(guild.Id).Permissions; + } + int index; + if (!perms.CheckPermissions(message, cmd, out index)) + return new Tuple(null, SearchResult.FromError(CommandError.Exception, $"Permission error. Permission number {index} (`{(index != -1 ? perms[index - 1].GetCommand() : "default")}`)")); + } + + return new Tuple(commands[i], await commands[i].Execute(message, parseResult)); + } + + return new Tuple(null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload.")); + } } public class CommandExecutedEventArgs diff --git a/src/NadekoBot/Services/Database/Models/Permission.cs b/src/NadekoBot/Services/Database/Models/Permission.cs index 9b1831a5..de342b6b 100644 --- a/src/NadekoBot/Services/Database/Models/Permission.cs +++ b/src/NadekoBot/Services/Database/Models/Permission.cs @@ -8,17 +8,25 @@ namespace NadekoBot.Services.Database.Models { public class Permission : DbEntity { - public PermissionType TargetType { get; set; } - public string Command { get; set; } = null; - public string Module { get; set; } = null; + public PrimaryPermissionType PrimaryTarget { get; set; } + public ulong PrimaryTargetId { get; set; } + + public SecondaryPermissionType SecondaryTarget { get; set; } + public string SecondaryTargetName { get; set; } + public bool State { get; set; } - public string Target { get; set; } } - public enum PermissionType + public enum PrimaryPermissionType { User, Channel, Role } + + public enum SecondaryPermissionType + { + Module, + Command + } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 3ff0b7e6..be741701 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -29,6 +29,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl public GuildConfig For(ulong guildId) { var config = _set.Include(gc => gc.FollowedStreams) + .Include(gc => gc.Permissions) .Include(gc => gc.LogSetting) .ThenInclude(ls=>ls.IgnoredChannels) .FirstOrDefault(c => c.GuildId == guildId);