Initial split of the modules
This commit is contained in:
108
NadekoBot.Core/Modules/Permissions/BlacklistCommands.cs
Normal file
108
NadekoBot.Core/Modules/Permissions/BlacklistCommands.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Common.TypeReaders;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
public partial class Permissions
|
||||
{
|
||||
[Group]
|
||||
public class BlacklistCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly BlacklistService _bs;
|
||||
private readonly DbService _db;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
private ConcurrentHashSet<ulong> BlacklistedUsers => _bs.BlacklistedUsers;
|
||||
private ConcurrentHashSet<ulong> BlacklistedGuilds => _bs.BlacklistedGuilds;
|
||||
private ConcurrentHashSet<ulong> BlacklistedChannels => _bs.BlacklistedChannels;
|
||||
|
||||
public BlacklistCommands(BlacklistService bs, DbService db, IBotCredentials creds)
|
||||
{
|
||||
_bs = bs;
|
||||
_db = db;
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public Task UserBlacklist(AddRemove action, ulong id)
|
||||
=> Blacklist(action, id, BlacklistType.User);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public Task UserBlacklist(AddRemove action, IUser usr)
|
||||
=> Blacklist(action, usr.Id, BlacklistType.User);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public Task ChannelBlacklist(AddRemove action, ulong id)
|
||||
=> Blacklist(action, id, BlacklistType.Channel);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public Task ServerBlacklist(AddRemove action, ulong id)
|
||||
=> Blacklist(action, id, BlacklistType.Server);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public Task ServerBlacklist(AddRemove action, IGuild guild)
|
||||
=> Blacklist(action, guild.Id, BlacklistType.Server);
|
||||
|
||||
private async Task Blacklist(AddRemove action, ulong id, BlacklistType type)
|
||||
{
|
||||
if(action == AddRemove.Add && _creds.OwnerIds.Contains(id))
|
||||
return;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
if (action == AddRemove.Add)
|
||||
{
|
||||
var item = new BlacklistItem { ItemId = id, Type = type };
|
||||
uow.BotConfig.GetOrCreate().Blacklist.Add(item);
|
||||
if (type == BlacklistType.Server)
|
||||
{
|
||||
BlacklistedGuilds.Add(id);
|
||||
}
|
||||
else if (type == BlacklistType.Channel)
|
||||
{
|
||||
BlacklistedChannels.Add(id);
|
||||
}
|
||||
else if (type == BlacklistType.User)
|
||||
{
|
||||
BlacklistedUsers.Add(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uow.BotConfig.GetOrCreate().Blacklist.RemoveWhere(bi => bi.ItemId == id && bi.Type == type);
|
||||
if (type == BlacklistType.Server)
|
||||
{
|
||||
BlacklistedGuilds.TryRemove(id);
|
||||
}
|
||||
else if (type == BlacklistType.Channel)
|
||||
{
|
||||
BlacklistedChannels.TryRemove(id);
|
||||
}
|
||||
else if (type == BlacklistType.User)
|
||||
{
|
||||
BlacklistedUsers.TryRemove(id);
|
||||
}
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if(action == AddRemove.Add)
|
||||
await ReplyConfirmLocalized("blacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("unblacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
94
NadekoBot.Core/Modules/Permissions/CmdCdsCommands.cs
Normal file
94
NadekoBot.Core/Modules/Permissions/CmdCdsCommands.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
public partial class Permissions
|
||||
{
|
||||
[Group]
|
||||
public class CmdCdsCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly CmdCdService _service;
|
||||
|
||||
private ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> CommandCooldowns
|
||||
=> _service.CommandCooldowns;
|
||||
private ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> ActiveCooldowns
|
||||
=> _service.ActiveCooldowns;
|
||||
|
||||
public CmdCdsCommands(CmdCdService service, DbService db)
|
||||
{
|
||||
_service = service;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task CmdCooldown(CommandInfo command, int secs)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
if (secs < 0 || secs > 3600)
|
||||
{
|
||||
await ReplyErrorLocalized("invalid_second_param_between", 0, 3600).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns));
|
||||
var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||
|
||||
config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
||||
localSet.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
||||
if (secs != 0)
|
||||
{
|
||||
var cc = new CommandCooldown()
|
||||
{
|
||||
CommandName = command.Aliases.First().ToLowerInvariant(),
|
||||
Seconds = secs,
|
||||
};
|
||||
config.CommandCooldowns.Add(cc);
|
||||
localSet.Add(cc);
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (secs == 0)
|
||||
{
|
||||
var activeCds = ActiveCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<ActiveCooldown>());
|
||||
activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant());
|
||||
await ReplyConfirmLocalized("cmdcd_cleared",
|
||||
Format.Bold(command.Aliases.First())).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("cmdcd_add",
|
||||
Format.Bold(command.Aliases.First()),
|
||||
Format.Bold(secs.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AllCmdCooldowns()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||
|
||||
if (!localSet.Any())
|
||||
await ReplyConfirmLocalized("cmdcd_none").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + GetText("sec")), s => $"{s,-30}", 2).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
NadekoBot.Core/Modules/Permissions/CommandCostCommands.cs
Normal file
90
NadekoBot.Core/Modules/Permissions/CommandCostCommands.cs
Normal file
@ -0,0 +1,90 @@
|
||||
using Discord.Commands;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
public partial class Permissions
|
||||
{
|
||||
[Group]
|
||||
public class CommandCostCommands : NadekoSubmodule
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, int> _commandCosts = new ConcurrentDictionary<string, int>();
|
||||
public static IReadOnlyDictionary<string, int> CommandCosts => _commandCosts;
|
||||
|
||||
static CommandCostCommands()
|
||||
{
|
||||
//_commandCosts = new ConcurrentDictionary<string, int>(NadekoBot.BotConfig.CommandCosts.ToDictionary(
|
||||
// x => x.CommandName.Trim().ToUpperInvariant(),
|
||||
// x => x.Cost));
|
||||
}
|
||||
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
//public async Task CmdCosts(int page = 1)
|
||||
//{
|
||||
// var prices = _commandCosts.ToList();
|
||||
|
||||
// if (!prices.Any())
|
||||
// {
|
||||
// await Context.Channel.SendConfirmAsync(GetText("no_costs")).ConfigureAwait(false);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => {
|
||||
// var embed = new EmbedBuilder().WithOkColor()
|
||||
// .WithTitle(GetText("command_costs"));
|
||||
// var current = prices.Skip((curPage - 1) * 9)
|
||||
// .Take(9);
|
||||
// foreach (var price in current)
|
||||
// {
|
||||
// embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true));
|
||||
// }
|
||||
// return embed;
|
||||
// }, prices.Count / 9).ConfigureAwait(false);
|
||||
//}
|
||||
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
//public async Task CommandCost(int cost, CommandInfo cmd)
|
||||
//{
|
||||
// if (cost < 0)
|
||||
// return;
|
||||
|
||||
// var cmdName = cmd.Aliases.First().ToLowerInvariant();
|
||||
|
||||
// var cmdPrice = new CommandCost()
|
||||
// {
|
||||
// CommandName = cmdName,
|
||||
// Cost = cost
|
||||
// };
|
||||
|
||||
// using (var uow = _db.UnitOfWork)
|
||||
// {
|
||||
// var bc = uow.BotConfig.GetOrCreate();
|
||||
|
||||
// if (cost != 0)
|
||||
// {
|
||||
// var elem = bc.CommandCosts.Where(cc => cc.CommandName == cmdPrice.CommandName).FirstOrDefault();
|
||||
// if (elem == null)
|
||||
// bc.CommandCosts.Add(cmdPrice);
|
||||
// else
|
||||
// elem.Cost = cost;
|
||||
|
||||
// _commandCosts.AddOrUpdate(cmdName, cost, (key, old) => cost);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// bc.CommandCosts.RemoveAt(bc.CommandCosts.IndexOf(cmdPrice));
|
||||
// _commandCosts.TryRemove(cmdName, out _);
|
||||
// }
|
||||
|
||||
// await uow.CompleteAsync().ConfigureAwait(false);
|
||||
// }
|
||||
|
||||
// if (cost == 0)
|
||||
// await Context.Channel.SendConfirmAsync($"Removed the cost from the {Format.Bold(cmd.Name)} command.").ConfigureAwait(false);
|
||||
// else
|
||||
// await Context.Channel.SendConfirmAsync($"{Format.Bold(cmd.Name)} now costs {cost}{NadekoBot.BotConfig.CurrencySign} to run.").ConfigureAwait(false);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
18
NadekoBot.Core/Modules/Permissions/Common/PermissionCache.cs
Normal file
18
NadekoBot.Core/Modules/Permissions/Common/PermissionCache.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Common
|
||||
{
|
||||
public class OldPermissionCache
|
||||
{
|
||||
public string PermRole { get; set; }
|
||||
public bool Verbose { get; set; } = true;
|
||||
public Permission RootPermission { get; set; }
|
||||
}
|
||||
|
||||
public class PermissionCache
|
||||
{
|
||||
public string PermRole { get; set; }
|
||||
public bool Verbose { get; set; } = true;
|
||||
public PermissionsCollection<Permissionv2> Permissions { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Common
|
||||
{
|
||||
public static class PermissionExtensions
|
||||
{
|
||||
public static bool CheckPermissions(this IEnumerable<Permissionv2> permsEnumerable, IUserMessage message,
|
||||
string commandName, string moduleName, out int permIndex)
|
||||
{
|
||||
var perms = permsEnumerable as List<Permissionv2> ?? permsEnumerable.ToList();
|
||||
|
||||
for (int i = perms.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var perm = perms[i];
|
||||
|
||||
var result = perm.CheckPermission(message, commandName, moduleName);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
permIndex = i;
|
||||
return result.Value;
|
||||
}
|
||||
permIndex = -1; //defaut behaviour
|
||||
return true;
|
||||
}
|
||||
|
||||
//null = not applicable
|
||||
//true = applicable, allowed
|
||||
//false = applicable, not allowed
|
||||
public static bool? CheckPermission(this Permissionv2 perm, IUserMessage message, string commandName, string moduleName)
|
||||
{
|
||||
if (!((perm.SecondaryTarget == SecondaryPermissionType.Command &&
|
||||
perm.SecondaryTargetName.ToLowerInvariant() == commandName.ToLowerInvariant()) ||
|
||||
(perm.SecondaryTarget == SecondaryPermissionType.Module &&
|
||||
perm.SecondaryTargetName.ToLowerInvariant() == moduleName.ToLowerInvariant()) ||
|
||||
perm.SecondaryTarget == SecondaryPermissionType.AllModules))
|
||||
return null;
|
||||
|
||||
var guildUser = message.Author as IGuildUser;
|
||||
|
||||
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:
|
||||
if (guildUser == null)
|
||||
break;
|
||||
if (guildUser.RoleIds.Contains(perm.PrimaryTargetId))
|
||||
return perm.State;
|
||||
break;
|
||||
case PrimaryPermissionType.Server:
|
||||
if (guildUser == null)
|
||||
break;
|
||||
return perm.State;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetCommand(this Permissionv2 perm, string prefix, SocketGuild guild = null)
|
||||
{
|
||||
var com = "";
|
||||
switch (perm.PrimaryTarget)
|
||||
{
|
||||
case PrimaryPermissionType.User:
|
||||
com += "u";
|
||||
break;
|
||||
case PrimaryPermissionType.Channel:
|
||||
com += "c";
|
||||
break;
|
||||
case PrimaryPermissionType.Role:
|
||||
com += "r";
|
||||
break;
|
||||
case PrimaryPermissionType.Server:
|
||||
com += "s";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (perm.SecondaryTarget)
|
||||
{
|
||||
case SecondaryPermissionType.Module:
|
||||
com += "m";
|
||||
break;
|
||||
case SecondaryPermissionType.Command:
|
||||
com += "c";
|
||||
break;
|
||||
case SecondaryPermissionType.AllModules:
|
||||
com = "a" + com + "m";
|
||||
break;
|
||||
}
|
||||
|
||||
var secName = perm.SecondaryTarget == SecondaryPermissionType.Command ?
|
||||
prefix + perm.SecondaryTargetName : perm.SecondaryTargetName;
|
||||
com += " " + (perm.SecondaryTargetName != "*" ? secName + " " : "") + (perm.State ? "enable" : "disable") + " ";
|
||||
|
||||
switch (perm.PrimaryTarget)
|
||||
{
|
||||
case PrimaryPermissionType.User:
|
||||
com += guild?.GetUser(perm.PrimaryTargetId)?.ToString() ?? $"<@{perm.PrimaryTargetId}>";
|
||||
break;
|
||||
case PrimaryPermissionType.Channel:
|
||||
com += $"<#{perm.PrimaryTargetId}>";
|
||||
break;
|
||||
case PrimaryPermissionType.Role:
|
||||
com += guild?.GetRole(perm.PrimaryTargetId)?.ToString() ?? $"<@&{perm.PrimaryTargetId}>";
|
||||
break;
|
||||
case PrimaryPermissionType.Server:
|
||||
break;
|
||||
}
|
||||
|
||||
return prefix + com;
|
||||
}
|
||||
|
||||
public static IEnumerable<Permission> AsEnumerable(this Permission perm)
|
||||
{
|
||||
do yield return perm;
|
||||
while ((perm = perm.Next) != null);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Common
|
||||
{
|
||||
public class PermissionsCollection<T> : IndexedCollection<T> where T : class, IIndexed
|
||||
{
|
||||
private readonly object _localLocker = new object();
|
||||
public PermissionsCollection(IEnumerable<T> source) : base(source)
|
||||
{
|
||||
}
|
||||
|
||||
public static implicit operator List<T>(PermissionsCollection<T> x) =>
|
||||
x.Source;
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
lock (_localLocker)
|
||||
{
|
||||
var first = Source[0];
|
||||
base.Clear();
|
||||
Source[0] = first;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Remove(T item)
|
||||
{
|
||||
bool removed;
|
||||
lock (_localLocker)
|
||||
{
|
||||
if(Source.IndexOf(item) == 0)
|
||||
throw new ArgumentException("You can't remove first permsission (allow all)");
|
||||
removed = base.Remove(item);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public override void Insert(int index, T item)
|
||||
{
|
||||
lock (_localLocker)
|
||||
{
|
||||
if(index == 0) // can't insert on first place. Last item is always allow all.
|
||||
throw new IndexOutOfRangeException(nameof(index));
|
||||
base.Insert(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveAt(int index)
|
||||
{
|
||||
lock (_localLocker)
|
||||
{
|
||||
if(index == 0) // you can't remove first permission (allow all)
|
||||
throw new IndexOutOfRangeException(nameof(index));
|
||||
|
||||
base.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public override T this[int index] {
|
||||
get => Source[index];
|
||||
set {
|
||||
lock (_localLocker)
|
||||
{
|
||||
if(index == 0) // can't set first element. It's always allow all
|
||||
throw new IndexOutOfRangeException(nameof(index));
|
||||
base[index] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
209
NadekoBot.Core/Modules/Permissions/FilterCommands.cs
Normal file
209
NadekoBot.Core/Modules/Permissions/FilterCommands.cs
Normal file
@ -0,0 +1,209 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
public partial class Permissions
|
||||
{
|
||||
[Group]
|
||||
public class FilterCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly FilterService _service;
|
||||
|
||||
public FilterCommands(FilterService service, DbService db)
|
||||
{
|
||||
_service = service;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task SrvrFilterInv()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
bool enabled;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
|
||||
enabled = config.FilterInvites = !config.FilterInvites;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
_service.InviteFilteringServers.Add(channel.Guild.Id);
|
||||
await ReplyConfirmLocalized("invite_filter_server_on").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_service.InviteFilteringServers.TryRemove(channel.Guild.Id);
|
||||
await ReplyConfirmLocalized("invite_filter_server_off").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ChnlFilterInv()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
int removed;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilterInvitesChannelIds));
|
||||
removed = config.FilterInvitesChannelIds.RemoveWhere(fc => fc.ChannelId == channel.Id);
|
||||
if (removed == 0)
|
||||
{
|
||||
config.FilterInvitesChannelIds.Add(new FilterChannelId()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
});
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (removed == 0)
|
||||
{
|
||||
_service.InviteFilteringChannels.Add(channel.Id);
|
||||
await ReplyConfirmLocalized("invite_filter_channel_on").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("invite_filter_channel_off").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task SrvrFilterWords()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
bool enabled;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
|
||||
enabled = config.FilterWords = !config.FilterWords;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
_service.WordFilteringServers.Add(channel.Guild.Id);
|
||||
await ReplyConfirmLocalized("word_filter_server_on").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_service.WordFilteringServers.TryRemove(channel.Guild.Id);
|
||||
await ReplyConfirmLocalized("word_filter_server_off").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ChnlFilterWords()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
int removed;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilterWordsChannelIds));
|
||||
removed = config.FilterWordsChannelIds.RemoveWhere(fc => fc.ChannelId == channel.Id);
|
||||
if (removed == 0)
|
||||
{
|
||||
config.FilterWordsChannelIds.Add(new FilterChannelId()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
});
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (removed == 0)
|
||||
{
|
||||
_service.WordFilteringChannels.Add(channel.Id);
|
||||
await ReplyConfirmLocalized("word_filter_channel_on").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_service.WordFilteringChannels.TryRemove(channel.Id);
|
||||
await ReplyConfirmLocalized("word_filter_channel_off").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task FilterWord([Remainder] string word)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
word = word?.Trim().ToLowerInvariant();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(word))
|
||||
return;
|
||||
|
||||
int removed;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilteredWords));
|
||||
|
||||
removed = config.FilteredWords.RemoveWhere(fw => fw.Word.Trim().ToLowerInvariant() == word);
|
||||
|
||||
if (removed == 0)
|
||||
config.FilteredWords.Add(new FilteredWord() { Word = word });
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var filteredWords = _service.ServerFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<string>());
|
||||
|
||||
if (removed == 0)
|
||||
{
|
||||
filteredWords.Add(word);
|
||||
await ReplyConfirmLocalized("filter_word_add", Format.Code(word)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
filteredWords.TryRemove(word);
|
||||
await ReplyConfirmLocalized("filter_word_remove", Format.Code(word)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task LstFilterWords(int page = 1)
|
||||
{
|
||||
page--;
|
||||
if (page < 0)
|
||||
return;
|
||||
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
_service.ServerFilteredWords.TryGetValue(channel.Guild.Id, out var fwHash);
|
||||
|
||||
var fws = fwHash.ToArray();
|
||||
|
||||
await channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client,
|
||||
page,
|
||||
(curPage) =>
|
||||
new EmbedBuilder()
|
||||
.WithTitle(GetText("filter_word_list"))
|
||||
.WithDescription(string.Join("\n", fws.Skip(curPage * 10).Take(10)))
|
||||
, fws.Length / 10).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
NadekoBot.Core/Modules/Permissions/GlobalPermissionCommands.cs
Normal file
114
NadekoBot.Core/Modules/Permissions/GlobalPermissionCommands.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.TypeReaders;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
public partial class Permissions
|
||||
{
|
||||
[Group]
|
||||
public class GlobalPermissionCommands : NadekoSubmodule
|
||||
{
|
||||
private GlobalPermissionService _service;
|
||||
private readonly DbService _db;
|
||||
|
||||
public GlobalPermissionCommands(GlobalPermissionService service, DbService db)
|
||||
{
|
||||
_service = service;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Lgp()
|
||||
{
|
||||
if (!_service.BlockedModules.Any() && !_service.BlockedCommands.Any())
|
||||
{
|
||||
await ReplyErrorLocalized("lgp_none").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor();
|
||||
|
||||
if (_service.BlockedModules.Any())
|
||||
embed.AddField(efb => efb.WithName(GetText("blocked_modules")).WithValue(string.Join("\n", _service.BlockedModules)).WithIsInline(false));
|
||||
|
||||
if (_service.BlockedCommands.Any())
|
||||
embed.AddField(efb => efb.WithName(GetText("blocked_commands")).WithValue(string.Join("\n", _service.BlockedCommands)).WithIsInline(false));
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Gmod(ModuleOrCrInfo module)
|
||||
{
|
||||
var moduleName = module.Name.ToLowerInvariant();
|
||||
if (_service.BlockedModules.Add(moduleName))
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var bc = uow.BotConfig.GetOrCreate();
|
||||
bc.BlockedModules.Add(new BlockedCmdOrMdl
|
||||
{
|
||||
Name = moduleName,
|
||||
});
|
||||
uow.Complete();
|
||||
}
|
||||
await ReplyConfirmLocalized("gmod_add", Format.Bold(module.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else if (_service.BlockedModules.TryRemove(moduleName))
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var bc = uow.BotConfig.GetOrCreate();
|
||||
bc.BlockedModules.RemoveWhere(x => x.Name == moduleName);
|
||||
uow.Complete();
|
||||
}
|
||||
await ReplyConfirmLocalized("gmod_remove", Format.Bold(module.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Gcmd(CommandOrCrInfo cmd)
|
||||
{
|
||||
var commandName = cmd.Name.ToLowerInvariant();
|
||||
if (_service.BlockedCommands.Add(commandName))
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var bc = uow.BotConfig.GetOrCreate();
|
||||
bc.BlockedCommands.Add(new BlockedCmdOrMdl
|
||||
{
|
||||
Name = commandName,
|
||||
});
|
||||
uow.Complete();
|
||||
}
|
||||
await ReplyConfirmLocalized("gcmd_add", Format.Bold(cmd.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else if (_service.BlockedCommands.TryRemove(commandName))
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var bc = uow.BotConfig.GetOrCreate();
|
||||
bc.BlockedCommands.RemoveWhere(x => x.Name == commandName);
|
||||
uow.Complete();
|
||||
}
|
||||
await ReplyConfirmLocalized("gcmd_remove", Format.Bold(cmd.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
536
NadekoBot.Core/Modules/Permissions/Permissions.cs
Normal file
536
NadekoBot.Core/Modules/Permissions/Permissions.cs
Normal file
@ -0,0 +1,536 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using Discord;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections.Generic;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.TypeReaders;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Modules.Permissions.Common;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
public partial class Permissions : NadekoTopLevelModule<PermissionService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public Permissions(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Verbose(PermissionAction action)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||
config.VerbosePermissions = action.Value;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
_service.UpdateCache(config);
|
||||
}
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("verbose_true").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("verbose_false").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task PermRole([Remainder] IRole role = null)
|
||||
{
|
||||
if (role != null && role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||
if (role == null)
|
||||
{
|
||||
await ReplyConfirmLocalized("permrole", Format.Bold(config.PermissionRole)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
config.PermissionRole = role.Name.Trim();
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
_service.UpdateCache(config);
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("permrole_changed", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ListPerms(int page = 1)
|
||||
{
|
||||
if (page < 1)
|
||||
return;
|
||||
|
||||
IList<Permissionv2> perms;
|
||||
|
||||
if (_service.Cache.TryGetValue(Context.Guild.Id, out var permCache))
|
||||
{
|
||||
perms = permCache.Permissions.Source.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
perms = Permissionv2.GetDefaultPermlist;
|
||||
}
|
||||
|
||||
var startPos = 20 * (page - 1);
|
||||
var toSend = Format.Bold(GetText("page", page)) + "\n\n" + string.Join("\n",
|
||||
perms.Reverse()
|
||||
.Skip(startPos)
|
||||
.Take(20)
|
||||
.Select(p =>
|
||||
{
|
||||
var str =
|
||||
$"`{p.Index + 1}.` {Format.Bold(p.GetCommand(Prefix, (SocketGuild) Context.Guild))}";
|
||||
if (p.Index == 0)
|
||||
str += $" [{GetText("uneditable")}]";
|
||||
return str;
|
||||
}));
|
||||
|
||||
await Context.Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task RemovePerm(int index)
|
||||
{
|
||||
index -= 1;
|
||||
if (index < 0)
|
||||
return;
|
||||
try
|
||||
{
|
||||
Permissionv2 p;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||
var permsCol = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||
p = permsCol[index];
|
||||
permsCol.RemoveAt(index);
|
||||
uow._context.Remove(p);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
_service.UpdateCache(config);
|
||||
}
|
||||
await ReplyConfirmLocalized("removed",
|
||||
index + 1,
|
||||
Format.Code(p.GetCommand(Prefix, (SocketGuild) Context.Guild))).ConfigureAwait(false);
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task MovePerm(int from, int to)
|
||||
{
|
||||
from -= 1;
|
||||
to -= 1;
|
||||
if (!(from == to || from < 0 || to < 0))
|
||||
{
|
||||
try
|
||||
{
|
||||
Permissionv2 fromPerm;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||
var permsCol = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||
|
||||
var fromFound = from < permsCol.Count;
|
||||
var toFound = to < permsCol.Count;
|
||||
|
||||
if (!fromFound)
|
||||
{
|
||||
await ReplyErrorLocalized("not_found", ++from).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!toFound)
|
||||
{
|
||||
await ReplyErrorLocalized("not_found", ++to).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
fromPerm = permsCol[from];
|
||||
|
||||
permsCol.RemoveAt(from);
|
||||
permsCol.Insert(to, fromPerm);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
_service.UpdateCache(config);
|
||||
}
|
||||
await ReplyConfirmLocalized("moved_permission",
|
||||
Format.Code(fromPerm.GetCommand(Prefix, (SocketGuild) Context.Guild)),
|
||||
++from,
|
||||
++to)
|
||||
.ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
catch (Exception e) when (e is ArgumentOutOfRangeException || e is IndexOutOfRangeException)
|
||||
{
|
||||
}
|
||||
}
|
||||
await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task SrvrCmd(CommandOrCrInfo command, PermissionAction action)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Server,
|
||||
PrimaryTargetId = 0,
|
||||
SecondaryTarget = SecondaryPermissionType.Command,
|
||||
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("sx_enable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command")).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("sx_disable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command")).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task SrvrMdl(ModuleOrCrInfo module, PermissionAction action)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Server,
|
||||
PrimaryTargetId = 0,
|
||||
SecondaryTarget = SecondaryPermissionType.Module,
|
||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("sx_enable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module")).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("sx_disable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module")).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task UsrCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IGuildUser user)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.User,
|
||||
PrimaryTargetId = user.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.Command,
|
||||
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("ux_enable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command"),
|
||||
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("ux_disable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command"),
|
||||
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task UsrMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] IGuildUser user)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.User,
|
||||
PrimaryTargetId = user.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.Module,
|
||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("ux_enable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module"),
|
||||
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("ux_disable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module"),
|
||||
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task RoleCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IRole role)
|
||||
{
|
||||
if (role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Role,
|
||||
PrimaryTargetId = role.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.Command,
|
||||
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("rx_enable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command"),
|
||||
Format.Code(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("rx_disable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command"),
|
||||
Format.Code(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task RoleMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] IRole role)
|
||||
{
|
||||
if (role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Role,
|
||||
PrimaryTargetId = role.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.Module,
|
||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("rx_enable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module"),
|
||||
Format.Code(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("rx_disable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module"),
|
||||
Format.Code(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ChnlCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] ITextChannel chnl)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Channel,
|
||||
PrimaryTargetId = chnl.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.Command,
|
||||
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("cx_enable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command"),
|
||||
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("cx_disable",
|
||||
Format.Code(command.Name),
|
||||
GetText("of_command"),
|
||||
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ChnlMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] ITextChannel chnl)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Channel,
|
||||
PrimaryTargetId = chnl.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.Module,
|
||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("cx_enable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module"),
|
||||
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("cx_disable",
|
||||
Format.Code(module.Name),
|
||||
GetText("of_module"),
|
||||
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AllChnlMdls(PermissionAction action, [Remainder] ITextChannel chnl)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Channel,
|
||||
PrimaryTargetId = chnl.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||
SecondaryTargetName = "*",
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("acm_enable",
|
||||
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("acm_disable",
|
||||
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AllRoleMdls(PermissionAction action, [Remainder] IRole role)
|
||||
{
|
||||
if (role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Role,
|
||||
PrimaryTargetId = role.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||
SecondaryTargetName = "*",
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("arm_enable",
|
||||
Format.Code(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("arm_disable",
|
||||
Format.Code(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AllUsrMdls(PermissionAction action, [Remainder] IUser user)
|
||||
{
|
||||
await _service.AddPermissions(Context.Guild.Id, new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.User,
|
||||
PrimaryTargetId = user.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||
SecondaryTargetName = "*",
|
||||
State = action.Value,
|
||||
});
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("aum_enable",
|
||||
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("aum_disable",
|
||||
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AllSrvrMdls(PermissionAction action)
|
||||
{
|
||||
var newPerm = new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.Server,
|
||||
PrimaryTargetId = 0,
|
||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||
SecondaryTargetName = "*",
|
||||
State = action.Value,
|
||||
};
|
||||
|
||||
var allowUser = new Permissionv2
|
||||
{
|
||||
PrimaryTarget = PrimaryPermissionType.User,
|
||||
PrimaryTargetId = Context.User.Id,
|
||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||
SecondaryTargetName = "*",
|
||||
State = true,
|
||||
};
|
||||
|
||||
await _service.AddPermissions(Context.Guild.Id,
|
||||
newPerm,
|
||||
allowUser);
|
||||
|
||||
if (action.Value)
|
||||
{
|
||||
await ReplyConfirmLocalized("asm_enable").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("asm_disable").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
public partial class Permissions
|
||||
{
|
||||
[Group]
|
||||
public class ResetPermissionsCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly ResetPermissionsService _service;
|
||||
|
||||
public ResetPermissionsCommands(ResetPermissionsService service)
|
||||
{
|
||||
_service = service;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task ResetPermissions()
|
||||
{
|
||||
await _service.ResetPermissions(Context.Guild.Id).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ResetGlobalPermissions()
|
||||
{
|
||||
await _service.ResetGlobalPermissions().ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services
|
||||
{
|
||||
public class BlacklistService : IEarlyBlocker, INService
|
||||
{
|
||||
public ConcurrentHashSet<ulong> BlacklistedUsers { get; }
|
||||
public ConcurrentHashSet<ulong> BlacklistedGuilds { get; }
|
||||
public ConcurrentHashSet<ulong> BlacklistedChannels { get; }
|
||||
|
||||
public BlacklistService(IBotConfigProvider bc)
|
||||
{
|
||||
var blacklist = bc.BotConfig.Blacklist;
|
||||
BlacklistedUsers = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.User).Select(c => c.ItemId));
|
||||
BlacklistedGuilds = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.Server).Select(c => c.ItemId));
|
||||
BlacklistedChannels = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.Channel).Select(c => c.ItemId));
|
||||
}
|
||||
|
||||
public Task<bool> TryBlockEarly(IGuild guild, IUserMessage usrMsg)
|
||||
=> Task.FromResult((guild != null && BlacklistedGuilds.Contains(guild.Id)) ||
|
||||
BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
||||
BlacklistedUsers.Contains(usrMsg.Author.Id));
|
||||
}
|
||||
}
|
67
NadekoBot.Core/Modules/Permissions/Services/CmdCdService.cs
Normal file
67
NadekoBot.Core/Modules/Permissions/Services/CmdCdService.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services
|
||||
{
|
||||
public class CmdCdService : ILateBlocker, INService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> CommandCooldowns { get; }
|
||||
public ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> ActiveCooldowns { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>>();
|
||||
|
||||
public CmdCdService(IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
CommandCooldowns = new ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>>(
|
||||
gcs.ToDictionary(k => k.GuildId,
|
||||
v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns)));
|
||||
}
|
||||
|
||||
public Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild,
|
||||
IMessageChannel channel, IUser user, string moduleName, string commandName)
|
||||
{
|
||||
if (guild == null)
|
||||
return Task.FromResult(false);
|
||||
var cmdcds = CommandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||
CommandCooldown cdRule;
|
||||
if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == commandName.ToLowerInvariant())) != null)
|
||||
{
|
||||
var activeCdsForGuild = ActiveCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<ActiveCooldown>());
|
||||
if (activeCdsForGuild.FirstOrDefault(ac => ac.UserId == user.Id && ac.Command == commandName.ToLowerInvariant()) != null)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
activeCdsForGuild.Add(new ActiveCooldown()
|
||||
{
|
||||
UserId = user.Id,
|
||||
Command = commandName.ToLowerInvariant(),
|
||||
});
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(cdRule.Seconds * 1000);
|
||||
activeCdsForGuild.RemoveWhere(ac => ac.Command == commandName.ToLowerInvariant() && ac.UserId == user.Id);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
}
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public class ActiveCooldown
|
||||
{
|
||||
public string Command { get; set; }
|
||||
public ulong UserId { get; set; }
|
||||
}
|
||||
}
|
140
NadekoBot.Core/Modules/Permissions/Services/FilterService.cs
Normal file
140
NadekoBot.Core/Modules/Permissions/Services/FilterService.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Net;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services
|
||||
{
|
||||
public class FilterService : IEarlyBlocker, INService
|
||||
{
|
||||
private readonly Logger _log;
|
||||
|
||||
public ConcurrentHashSet<ulong> InviteFilteringChannels { get; }
|
||||
public ConcurrentHashSet<ulong> InviteFilteringServers { get; }
|
||||
|
||||
//serverid, filteredwords
|
||||
public ConcurrentDictionary<ulong, ConcurrentHashSet<string>> ServerFilteredWords { get; }
|
||||
|
||||
public ConcurrentHashSet<ulong> WordFilteringChannels { get; }
|
||||
public ConcurrentHashSet<ulong> WordFilteringServers { get; }
|
||||
|
||||
public ConcurrentHashSet<string> FilteredWordsForChannel(ulong channelId, ulong guildId)
|
||||
{
|
||||
ConcurrentHashSet<string> words = new ConcurrentHashSet<string>();
|
||||
if (WordFilteringChannels.Contains(channelId))
|
||||
ServerFilteredWords.TryGetValue(guildId, out words);
|
||||
return words;
|
||||
}
|
||||
|
||||
public ConcurrentHashSet<string> FilteredWordsForServer(ulong guildId)
|
||||
{
|
||||
var words = new ConcurrentHashSet<string>();
|
||||
if (WordFilteringServers.Contains(guildId))
|
||||
ServerFilteredWords.TryGetValue(guildId, out words);
|
||||
return words;
|
||||
}
|
||||
|
||||
public FilterService(DiscordSocketClient _client, IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
InviteFilteringServers = new ConcurrentHashSet<ulong>(gcs.Where(gc => gc.FilterInvites).Select(gc => gc.GuildId));
|
||||
InviteFilteringChannels = new ConcurrentHashSet<ulong>(gcs.SelectMany(gc => gc.FilterInvitesChannelIds.Select(fci => fci.ChannelId)));
|
||||
|
||||
var dict = gcs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet<string>(gc.FilteredWords.Select(fw => fw.Word)));
|
||||
|
||||
ServerFilteredWords = new ConcurrentDictionary<ulong, ConcurrentHashSet<string>>(dict);
|
||||
|
||||
var serverFiltering = gcs.Where(gc => gc.FilterWords);
|
||||
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
|
||||
|
||||
WordFilteringChannels = new ConcurrentHashSet<ulong>(gcs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId)));
|
||||
|
||||
_client.MessageUpdated += (oldData, newMsg, channel) =>
|
||||
{
|
||||
var _ = Task.Run(() =>
|
||||
{
|
||||
var guild = (channel as ITextChannel)?.Guild;
|
||||
var usrMsg = newMsg as IUserMessage;
|
||||
|
||||
if (guild == null || usrMsg == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
return TryBlockEarly(guild, usrMsg);
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<bool> TryBlockEarly(IGuild guild, IUserMessage msg)
|
||||
=> !(msg.Author is IGuildUser gu) //it's never filtered outside of guilds, and never block administrators
|
||||
? false
|
||||
: !gu.GuildPermissions.Administrator && (await FilterInvites(guild, msg) || await FilterWords(guild, msg));
|
||||
|
||||
public async Task<bool> FilterWords(IGuild guild, IUserMessage usrMsg)
|
||||
{
|
||||
if (guild is null)
|
||||
return false;
|
||||
if (usrMsg is null)
|
||||
return false;
|
||||
|
||||
var filteredChannelWords = FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
var filteredServerWords = FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
|
||||
{
|
||||
foreach (var word in wordsInMessage)
|
||||
{
|
||||
if (filteredChannelWords.Contains(word) ||
|
||||
filteredServerWords.Contains(word))
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> FilterInvites(IGuild guild, IUserMessage usrMsg)
|
||||
{
|
||||
if (guild is null)
|
||||
return false;
|
||||
if (usrMsg is null)
|
||||
return false;
|
||||
|
||||
if ((InviteFilteringChannels.Contains(usrMsg.Channel.Id)
|
||||
|| InviteFilteringServers.Contains(guild.Id))
|
||||
&& usrMsg.Content.IsDiscordInvite())
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services
|
||||
{
|
||||
public class GlobalPermissionService : ILateBlocker, INService
|
||||
{
|
||||
public readonly ConcurrentHashSet<string> BlockedModules;
|
||||
public readonly ConcurrentHashSet<string> BlockedCommands;
|
||||
|
||||
public GlobalPermissionService(IBotConfigProvider bc)
|
||||
{
|
||||
BlockedModules = new ConcurrentHashSet<string>(bc.BotConfig.BlockedModules.Select(x => x.Name));
|
||||
BlockedCommands = new ConcurrentHashSet<string>(bc.BotConfig.BlockedCommands.Select(x => x.Name));
|
||||
}
|
||||
|
||||
public async Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName)
|
||||
{
|
||||
await Task.Yield();
|
||||
commandName = commandName.ToLowerInvariant();
|
||||
|
||||
if (commandName != "resetglobalperms" &&
|
||||
(BlockedCommands.Contains(commandName) ||
|
||||
BlockedModules.Contains(moduleName.ToLowerInvariant())))
|
||||
{
|
||||
return true;
|
||||
//return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"Command or module is blocked globally by the bot owner."));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Common;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Services.Impl;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services
|
||||
{
|
||||
public class PermissionService : ILateBlocker, INService
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly CommandHandler _cmd;
|
||||
private readonly NadekoStrings _strings;
|
||||
|
||||
//guildid, root permission
|
||||
public ConcurrentDictionary<ulong, PermissionCache> Cache { get; } =
|
||||
new ConcurrentDictionary<ulong, PermissionCache>();
|
||||
|
||||
public PermissionService(DiscordSocketClient client, DbService db, CommandHandler cmd, NadekoStrings strings)
|
||||
{
|
||||
_db = db;
|
||||
_cmd = cmd;
|
||||
_strings = strings;
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
if (client.ShardId == 0)
|
||||
TryMigratePermissions();
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
foreach (var x in uow.GuildConfigs.Permissionsv2ForAll(client.Guilds.ToArray().Select(x => (long)x.Id).ToList()))
|
||||
{
|
||||
Cache.TryAdd(x.GuildId, new PermissionCache()
|
||||
{
|
||||
Verbose = x.VerbosePermissions,
|
||||
PermRole = x.PermissionRole,
|
||||
Permissions = new PermissionsCollection<Permissionv2>(x.Permissions)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PermissionCache GetCache(ulong guildId)
|
||||
{
|
||||
if (!Cache.TryGetValue(guildId, out var pc))
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(guildId,
|
||||
set => set.Include(x => x.Permissions));
|
||||
UpdateCache(config);
|
||||
}
|
||||
Cache.TryGetValue(guildId, out pc);
|
||||
if (pc == null)
|
||||
throw new Exception("Cache is null.");
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
private void TryMigratePermissions()
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var bc = uow.BotConfig.GetOrCreate();
|
||||
var log = LogManager.GetCurrentClassLogger();
|
||||
if (bc.PermissionVersion <= 1)
|
||||
{
|
||||
log.Info("Permission version is 1, upgrading to 2.");
|
||||
var oldCache = new ConcurrentDictionary<ulong, OldPermissionCache>(uow.GuildConfigs
|
||||
.OldPermissionsForAll()
|
||||
.Where(x => x.RootPermission != null) // there is a check inside already, but just in case
|
||||
.ToDictionary(k => k.GuildId,
|
||||
v => new OldPermissionCache()
|
||||
{
|
||||
RootPermission = v.RootPermission,
|
||||
Verbose = v.VerbosePermissions,
|
||||
PermRole = v.PermissionRole
|
||||
}));
|
||||
|
||||
if (oldCache.Any())
|
||||
{
|
||||
log.Info("Old permissions found. Performing one-time migration to v2.");
|
||||
var i = 0;
|
||||
foreach (var oc in oldCache)
|
||||
{
|
||||
if (i % 3 == 0)
|
||||
log.Info("Migrating Permissions #" + i + " - GuildId: " + oc.Key);
|
||||
i++;
|
||||
var gc = uow.GuildConfigs.GcWithPermissionsv2For(oc.Key);
|
||||
|
||||
var oldPerms = oc.Value.RootPermission.AsEnumerable().Reverse().ToList();
|
||||
uow._context.Set<Permission>().RemoveRange(oldPerms);
|
||||
gc.RootPermission = null;
|
||||
if (oldPerms.Count > 2)
|
||||
{
|
||||
|
||||
var newPerms = oldPerms.Take(oldPerms.Count - 1)
|
||||
.Select(x => x.Tov2())
|
||||
.ToList();
|
||||
|
||||
var allowPerm = Permissionv2.AllowAllPerm;
|
||||
var firstPerm = newPerms[0];
|
||||
if (allowPerm.State != firstPerm.State ||
|
||||
allowPerm.PrimaryTarget != firstPerm.PrimaryTarget ||
|
||||
allowPerm.SecondaryTarget != firstPerm.SecondaryTarget ||
|
||||
allowPerm.PrimaryTargetId != firstPerm.PrimaryTargetId ||
|
||||
allowPerm.SecondaryTargetName != firstPerm.SecondaryTargetName)
|
||||
newPerms.Insert(0, Permissionv2.AllowAllPerm);
|
||||
Cache.TryAdd(oc.Key, new PermissionCache
|
||||
{
|
||||
Permissions = new PermissionsCollection<Permissionv2>(newPerms),
|
||||
Verbose = gc.VerbosePermissions,
|
||||
PermRole = gc.PermissionRole,
|
||||
});
|
||||
gc.Permissions = newPerms;
|
||||
}
|
||||
}
|
||||
log.Info("Permission migration to v2 is done.");
|
||||
}
|
||||
|
||||
bc.PermissionVersion = 2;
|
||||
uow.Complete();
|
||||
}
|
||||
if (bc.PermissionVersion <= 2)
|
||||
{
|
||||
var oldPrefixes = new[] { ".", ";", "!!", "!m", "!", "+", "-", "$", ">" };
|
||||
uow._context.Database.ExecuteSqlCommand(
|
||||
@"UPDATE Permissionv2
|
||||
SET secondaryTargetName=trim(substr(secondaryTargetName, 3))
|
||||
WHERE secondaryTargetName LIKE '!!%' OR secondaryTargetName LIKE '!m%';
|
||||
|
||||
UPDATE Permissionv2
|
||||
SET secondaryTargetName=substr(secondaryTargetName, 2)
|
||||
WHERE secondaryTargetName LIKE '.%' OR
|
||||
secondaryTargetName LIKE '~%' OR
|
||||
secondaryTargetName LIKE ';%' OR
|
||||
secondaryTargetName LIKE '>%' OR
|
||||
secondaryTargetName LIKE '-%' OR
|
||||
secondaryTargetName LIKE '!%';");
|
||||
bc.PermissionVersion = 3;
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddPermissions(ulong guildId, params Permissionv2[] perms)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(guildId);
|
||||
//var orderedPerms = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||
var max = config.Permissions.Max(x => x.Index); //have to set its index to be the highest
|
||||
foreach (var perm in perms)
|
||||
{
|
||||
perm.Index = ++max;
|
||||
config.Permissions.Add(perm);
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
UpdateCache(config);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCache(GuildConfig config)
|
||||
{
|
||||
Cache.AddOrUpdate(config.GuildId, new PermissionCache()
|
||||
{
|
||||
Permissions = new PermissionsCollection<Permissionv2>(config.Permissions),
|
||||
PermRole = config.PermissionRole,
|
||||
Verbose = config.VerbosePermissions
|
||||
}, (id, old) =>
|
||||
{
|
||||
old.Permissions = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||
old.PermRole = config.PermissionRole;
|
||||
old.Verbose = config.VerbosePermissions;
|
||||
return old;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName)
|
||||
{
|
||||
await Task.Yield();
|
||||
if (guild == null)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var resetCommand = commandName == "resetperms";
|
||||
|
||||
PermissionCache pc = GetCache(guild.Id);
|
||||
if (!resetCommand && !pc.Permissions.CheckPermissions(msg, commandName, moduleName, out int index))
|
||||
{
|
||||
if (pc.Verbose)
|
||||
try { await channel.SendErrorAsync(_strings.GetText("trigger", guild.Id, "Permissions".ToLowerInvariant(), index + 1, Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild)))).ConfigureAwait(false); } catch { }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (moduleName == "Permissions")
|
||||
{
|
||||
var roles = (user as SocketGuildUser)?.Roles ?? ((IGuildUser)user).RoleIds.Select(x => guild.GetRole(x)).Where(x => x != null);
|
||||
if (!roles.Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && user.Id != ((IGuildUser)user).Guild.OwnerId)
|
||||
{
|
||||
var returnMsg = $"You need the **{pc.PermRole}** role in order to use permission commands.";
|
||||
if (pc.Verbose)
|
||||
try { await channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services
|
||||
{
|
||||
public class ResetPermissionsService : INService
|
||||
{
|
||||
private readonly PermissionService _perms;
|
||||
private readonly GlobalPermissionService _globalPerms;
|
||||
private readonly DbService _db;
|
||||
|
||||
public ResetPermissionsService(PermissionService perms, GlobalPermissionService globalPerms, DbService db)
|
||||
{
|
||||
_perms = perms;
|
||||
_globalPerms = globalPerms;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task ResetPermissions(ulong guildId)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(guildId);
|
||||
config.Permissions = Permissionv2.GetDefaultPermlist;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
_perms.UpdateCache(config);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ResetGlobalPermissions()
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.BotConfig.GetOrCreate();
|
||||
gc.BlockedCommands.Clear();
|
||||
gc.BlockedModules.Clear();
|
||||
|
||||
_globalPerms.BlockedCommands.Clear();
|
||||
_globalPerms.BlockedModules.Clear();
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user