Initial split of the modules
This commit is contained in:
370
NadekoBot.Core/Modules/Administration/Administration.cs
Normal file
370
NadekoBot.Core/Modules/Administration/Administration.cs
Normal file
@ -0,0 +1,370 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration : NadekoTopLevelModule<AdministrationService>
|
||||
{
|
||||
private IGuild _nadekoSupportServer;
|
||||
private readonly DbService _db;
|
||||
|
||||
public Administration(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Delmsgoncmd()
|
||||
{
|
||||
bool enabled;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
enabled = conf.DeleteMessageOnCommand = !conf.DeleteMessageOnCommand;
|
||||
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
if (enabled)
|
||||
{
|
||||
_service.DeleteMessagesOnCommand.Add(Context.Guild.Id);
|
||||
await ReplyConfirmLocalized("delmsg_on").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_service.DeleteMessagesOnCommand.TryRemove(Context.Guild.Id);
|
||||
await ReplyConfirmLocalized("delmsg_off").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Setrole(IGuildUser usr, [Remainder] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)Context.User;
|
||||
var maxRole = guser.GetRoles().Max(x => x.Position);
|
||||
if ((Context.User.Id != Context.Guild.OwnerId) && (maxRole <= role.Position || maxRole <= usr.GetRoles().Max(x => x.Position)))
|
||||
return;
|
||||
try
|
||||
{
|
||||
await usr.AddRoleAsync(role).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("setrole", Format.Bold(role.Name), Format.Bold(usr.ToString()))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyErrorLocalized("setrole_err").ConfigureAwait(false);
|
||||
_log.Info(ex);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Removerole(IGuildUser usr, [Remainder] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)Context.User;
|
||||
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= usr.GetRoles().Max(x => x.Position))
|
||||
return;
|
||||
try
|
||||
{
|
||||
await usr.RemoveRoleAsync(role).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("remrole", Format.Bold(role.Name), Format.Bold(usr.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalized("remrole_err").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task RenameRole(IRole roleToEdit, string newname)
|
||||
{
|
||||
var guser = (IGuildUser)Context.User;
|
||||
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= roleToEdit.Position)
|
||||
return;
|
||||
try
|
||||
{
|
||||
if (roleToEdit.Position > (await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).GetRoles().Max(r => r.Position))
|
||||
{
|
||||
await ReplyErrorLocalized("renrole_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await roleToEdit.ModifyAsync(g => g.Name = newname).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("renrole").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("renrole_err").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task RemoveAllRoles([Remainder] IGuildUser user)
|
||||
{
|
||||
var guser = (IGuildUser)Context.User;
|
||||
|
||||
var userRoles = user.GetRoles().Except(new[] { guser.Guild.EveryoneRole });
|
||||
if (user.Id == Context.Guild.OwnerId || (Context.User.Id != Context.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position)))
|
||||
return;
|
||||
try
|
||||
{
|
||||
await user.RemoveRolesAsync(userRoles).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("rar_err").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task CreateRole([Remainder] string roleName = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
return;
|
||||
|
||||
var r = await Context.Guild.CreateRoleAsync(roleName).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("cr", Format.Bold(r.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task RoleHoist(IRole role)
|
||||
{
|
||||
await role.ModifyAsync(r => r.Hoist = !role.IsHoisted).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("rh", Format.Bold(role.Name), Format.Bold(role.IsHoisted.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task RoleColor(params string[] args)
|
||||
{
|
||||
if (args.Length != 2 && args.Length != 4)
|
||||
{
|
||||
await ReplyErrorLocalized("rc_params").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var roleName = args[0].ToUpperInvariant();
|
||||
var role = Context.Guild.Roles.FirstOrDefault(r => r.Name.ToUpperInvariant() == roleName);
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
await ReplyErrorLocalized("rc_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var rgb = args.Length == 4;
|
||||
var arg1 = args[1].Replace("#", "");
|
||||
|
||||
var red = Convert.ToByte(rgb ? int.Parse(arg1) : Convert.ToInt32(arg1.Substring(0, 2), 16));
|
||||
var green = Convert.ToByte(rgb ? int.Parse(args[2]) : Convert.ToInt32(arg1.Substring(2, 2), 16));
|
||||
var blue = Convert.ToByte(rgb ? int.Parse(args[3]) : Convert.ToInt32(arg1.Substring(4, 2), 16));
|
||||
|
||||
await role.ModifyAsync(r => r.Color = new Color(red, green, blue)).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("rc", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("rc_perms").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.DeafenMembers)]
|
||||
[RequireBotPermission(GuildPermission.DeafenMembers)]
|
||||
public async Task Deafen(params IGuildUser[] users)
|
||||
{
|
||||
if (!users.Any())
|
||||
return;
|
||||
foreach (var u in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
await u.ModifyAsync(usr => usr.Deaf = true).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
await ReplyConfirmLocalized("deafen").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.DeafenMembers)]
|
||||
[RequireBotPermission(GuildPermission.DeafenMembers)]
|
||||
public async Task UnDeafen(params IGuildUser[] users)
|
||||
{
|
||||
if (!users.Any())
|
||||
return;
|
||||
|
||||
foreach (var u in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
await u.ModifyAsync(usr => usr.Deaf = false).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
await ReplyConfirmLocalized("undeafen").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task DelVoiChanl([Remainder] IVoiceChannel voiceChannel)
|
||||
{
|
||||
await voiceChannel.DeleteAsync().ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("delvoich", Format.Bold(voiceChannel.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task CreatVoiChanl([Remainder] string channelName)
|
||||
{
|
||||
var ch = await Context.Guild.CreateVoiceChannelAsync(channelName).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("createvoich",Format.Bold(ch.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task DelTxtChanl([Remainder] ITextChannel toDelete)
|
||||
{
|
||||
await toDelete.DeleteAsync().ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("deltextchan", Format.Bold(toDelete.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task CreaTxtChanl([Remainder] string channelName)
|
||||
{
|
||||
var txtCh = await Context.Guild.CreateTextChannelAsync(channelName).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("createtextchan", Format.Bold(txtCh.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task SetTopic([Remainder] string topic = null)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
topic = topic ?? "";
|
||||
await channel.ModifyAsync(c => c.Topic = topic);
|
||||
await ReplyConfirmLocalized("set_topic").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task SetChanlName([Remainder] string name)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
await channel.ModifyAsync(c => c.Name = name).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("set_channel_name").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.MentionEveryone)]
|
||||
public async Task MentionRole(params IRole[] roles)
|
||||
{
|
||||
string send = "❕" +GetText("menrole",Context.User.Mention);
|
||||
foreach (var role in roles)
|
||||
{
|
||||
send += $"\n**{role.Name}**\n";
|
||||
send += string.Join(", ", (await Context.Guild.GetUsersAsync())
|
||||
.Where(u => u.GetRoles().Contains(role))
|
||||
.Take(50).Select(u => u.Mention));
|
||||
}
|
||||
|
||||
while (send.Length > 2000)
|
||||
{
|
||||
var curstr = send.Substring(0, 2000);
|
||||
await Context.Channel.SendMessageAsync(curstr.Substring(0,
|
||||
curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false);
|
||||
send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) +
|
||||
send.Substring(2000);
|
||||
}
|
||||
await Context.Channel.SendMessageAsync(send).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Donators()
|
||||
{
|
||||
IEnumerable<Donator> donatorsOrdered;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
donatorsOrdered = uow.Donators.GetDonatorsOrdered();
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync(GetText("donators"), string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false);
|
||||
|
||||
_nadekoSupportServer = _nadekoSupportServer ?? (await Context.Client.GetGuildAsync(117523346618318850));
|
||||
|
||||
var patreonRole = _nadekoSupportServer?.GetRole(236667642088259585);
|
||||
if (patreonRole == null)
|
||||
return;
|
||||
|
||||
var usrs = (await _nadekoSupportServer.GetUsersAsync()).Where(u => u.RoleIds.Contains(236667642088259585u));
|
||||
await Context.Channel.SendConfirmAsync("Patreon supporters", string.Join("⭐", usrs.Select(d => d.Username))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Donadd(IUser donator, int amount)
|
||||
{
|
||||
Donator don;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
don = uow.Donators.AddOrUpdateDonator(donator.Id, donator.Username, amount);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
await ReplyConfirmLocalized("donadd", don.Amount).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class AutoAssignRoleCommands : NadekoSubmodule<AutoAssignRoleService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public AutoAssignRoleCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task AutoAssignRole([Remainder] IRole role = null)
|
||||
{
|
||||
var guser = (IGuildUser)Context.User;
|
||||
if (role != null)
|
||||
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
return;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
if (role == null)
|
||||
{
|
||||
conf.AutoAssignRoleId = 0;
|
||||
_service.AutoAssignedRoles.TryRemove(Context.Guild.Id, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
conf.AutoAssignRoleId = role.Id;
|
||||
_service.AutoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id);
|
||||
}
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
await ReplyConfirmLocalized("aar_disabled").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("aar_enabled").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
195
NadekoBot.Core/Modules/Administration/Common/Migration/0_9..cs
Normal file
195
NadekoBot.Core/Modules/Administration/Common/Migration/0_9..cs
Normal file
@ -0,0 +1,195 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Common.Migration
|
||||
{
|
||||
public class CommandPrefixes0_9
|
||||
{
|
||||
public string Administration { get; set; }
|
||||
public string Searches { get; set; }
|
||||
public string NSFW { get; set; }
|
||||
public string Conversations { get; set; }
|
||||
public string ClashOfClans { get; set; }
|
||||
public string Help { get; set; }
|
||||
public string Music { get; set; }
|
||||
public string Trello { get; set; }
|
||||
public string Games { get; set; }
|
||||
public string Gambling { get; set; }
|
||||
public string Permissions { get; set; }
|
||||
public string Programming { get; set; }
|
||||
public string Pokemon { get; set; }
|
||||
public string Utility { get; set; }
|
||||
}
|
||||
|
||||
public class Config0_9
|
||||
{
|
||||
public bool DontJoinServers { get; set; }
|
||||
public bool ForwardMessages { get; set; }
|
||||
public bool ForwardToAllOwners { get; set; }
|
||||
public bool IsRotatingStatus { get; set; }
|
||||
public int BufferSize { get; set; }
|
||||
public List<string> RaceAnimals { get; set; }
|
||||
public string RemindMessageFormat { get; set; }
|
||||
public Dictionary<string, List<string>> CustomReactions { get; set; }
|
||||
public List<string> RotatingStatuses { get; set; }
|
||||
public CommandPrefixes0_9 CommandPrefixes { get; set; }
|
||||
public List<ulong> ServerBlacklist { get; set; }
|
||||
public List<ulong> ChannelBlacklist { get; set; }
|
||||
public List<ulong> UserBlacklist { get; set; }
|
||||
public List<string> _8BallResponses { get; set; }
|
||||
public string CurrencySign { get; set; }
|
||||
public string CurrencyName { get; set; }
|
||||
public string DMHelpString { get; set; }
|
||||
public string HelpString { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds a permission list
|
||||
/// </summary>
|
||||
public class Permissions
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the parent object whose permissions these are
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Module name with allowed/disallowed
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, bool> Modules { get; set; }
|
||||
/// <summary>
|
||||
/// Command name with allowed/disallowed
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, bool> Commands { get; set; }
|
||||
/// <summary>
|
||||
/// Should the bot filter invites to other discord servers (and ref links in the future)
|
||||
/// </summary>
|
||||
public bool FilterInvites { get; set; }
|
||||
/// <summary>
|
||||
/// Should the bot filter words which are specified in the Words hashset
|
||||
/// </summary>
|
||||
public bool FilterWords { get; set; }
|
||||
|
||||
public Permissions(string name)
|
||||
{
|
||||
Name = name;
|
||||
Modules = new ConcurrentDictionary<string, bool>();
|
||||
Commands = new ConcurrentDictionary<string, bool>();
|
||||
FilterInvites = false;
|
||||
FilterWords = false;
|
||||
}
|
||||
|
||||
public void CopyFrom(Permissions other)
|
||||
{
|
||||
Modules.Clear();
|
||||
foreach (var mp in other.Modules)
|
||||
Modules.AddOrUpdate(mp.Key, mp.Value, (s, b) => mp.Value);
|
||||
Commands.Clear();
|
||||
foreach (var cp in other.Commands)
|
||||
Commands.AddOrUpdate(cp.Key, cp.Value, (s, b) => cp.Value);
|
||||
FilterInvites = other.FilterInvites;
|
||||
FilterWords = other.FilterWords;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var toReturn = "";
|
||||
var bannedModules = Modules.Where(kvp => kvp.Value == false);
|
||||
var bannedModulesArray = bannedModules as KeyValuePair<string, bool>[] ?? bannedModules.ToArray();
|
||||
if (bannedModulesArray.Any())
|
||||
{
|
||||
toReturn += "`Banned Modules:`\n";
|
||||
toReturn = bannedModulesArray.Aggregate(toReturn, (current, m) => current + $"\t`[x] {m.Key}`\n");
|
||||
}
|
||||
var bannedCommands = Commands.Where(kvp => kvp.Value == false);
|
||||
var bannedCommandsArr = bannedCommands as KeyValuePair<string, bool>[] ?? bannedCommands.ToArray();
|
||||
if (bannedCommandsArr.Any())
|
||||
{
|
||||
toReturn += "`Banned Commands:`\n";
|
||||
toReturn = bannedCommandsArr.Aggregate(toReturn, (current, c) => current + $"\t`[x] {c.Key}`\n");
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerPermissions0_9
|
||||
{
|
||||
/// <summary>
|
||||
/// The guy who can edit the permissions
|
||||
/// </summary>
|
||||
public string PermissionsControllerRole { get; set; }
|
||||
/// <summary>
|
||||
/// Does it print the error when a restriction occurs
|
||||
/// </summary>
|
||||
public bool Verbose { get; set; }
|
||||
/// <summary>
|
||||
/// The id of the thing (user/server/channel)
|
||||
/// </summary>
|
||||
public ulong Id { get; set; } //a string because of the role name.
|
||||
/// <summary>
|
||||
/// Permission object bound to the id of something/role name
|
||||
/// </summary>
|
||||
public Permissions Permissions { get; set; }
|
||||
/// <summary>
|
||||
/// Banned words, usually profanities, like word "java"
|
||||
/// </summary>
|
||||
public HashSet<string> Words { get; set; }
|
||||
|
||||
public Dictionary<ulong, Permissions> UserPermissions { get; set; }
|
||||
public Dictionary<ulong, Permissions> ChannelPermissions { get; set; }
|
||||
public Dictionary<ulong, Permissions> RolePermissions { get; set; }
|
||||
/// <summary>
|
||||
/// Dictionary of command names with their respective cooldowns
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, int> CommandCooldowns { get; set; }
|
||||
|
||||
public ServerPermissions0_9(ulong id, string name)
|
||||
{
|
||||
Id = id;
|
||||
PermissionsControllerRole = "Nadeko";
|
||||
Verbose = true;
|
||||
|
||||
Permissions = new Permissions(name);
|
||||
Permissions.Modules.TryAdd("NSFW", false);
|
||||
UserPermissions = new Dictionary<ulong, Permissions>();
|
||||
ChannelPermissions = new Dictionary<ulong, Permissions>();
|
||||
RolePermissions = new Dictionary<ulong, Permissions>();
|
||||
CommandCooldowns = new ConcurrentDictionary<string, int>();
|
||||
Words = new HashSet<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerSpecificConfig
|
||||
{
|
||||
public bool VoicePlusTextEnabled { get; set; }
|
||||
public bool SendPrivateMessageOnMention { get; set; }
|
||||
public ulong? LogChannel { get; set; } = null;
|
||||
public ulong? LogPresenceChannel { get; set; } = null;
|
||||
public HashSet<ulong> LogserverIgnoreChannels { get; set; }
|
||||
public ConcurrentDictionary<ulong, ulong> VoiceChannelLog { get; set; }
|
||||
public HashSet<ulong> ListOfSelfAssignableRoles { get; set; }
|
||||
public ulong AutoAssignedRole { get; set; }
|
||||
public ConcurrentDictionary<ulong, int> GenerateCurrencyChannels { get; set; }
|
||||
public bool AutoDeleteMessagesOnCommand { get; set; }
|
||||
public bool ExclusiveSelfAssignedRoles { get; set; }
|
||||
public float DefaultMusicVolume { get; set; }
|
||||
public HashSet<StreamNotificationConfig0_9> ObservingStreams { get; set; }
|
||||
}
|
||||
|
||||
public class StreamNotificationConfig0_9
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public StreamType Type { get; set; }
|
||||
public ulong ServerId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public bool LastStatus { get; set; }
|
||||
|
||||
public enum StreamType
|
||||
{
|
||||
Twitch,
|
||||
Beam,
|
||||
Hitbox,
|
||||
YoutubeGaming
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Common.Migration
|
||||
{
|
||||
public class MigrationException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Discord;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Common
|
||||
{
|
||||
public enum ProtectionType
|
||||
{
|
||||
Raiding,
|
||||
Spamming,
|
||||
}
|
||||
|
||||
public class AntiRaidStats
|
||||
{
|
||||
public AntiRaidSetting AntiRaidSettings { get; set; }
|
||||
public int UsersCount { get; set; }
|
||||
public ConcurrentHashSet<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
|
||||
}
|
||||
|
||||
public class AntiSpamStats
|
||||
{
|
||||
public AntiSpamSetting AntiSpamSettings { get; set; }
|
||||
public ConcurrentDictionary<ulong, UserSpamStats> UserStats { get; set; }
|
||||
= new ConcurrentDictionary<ulong, UserSpamStats>();
|
||||
}
|
||||
}
|
59
NadekoBot.Core/Modules/Administration/Common/Ratelimiter.cs
Normal file
59
NadekoBot.Core/Modules/Administration/Common/Ratelimiter.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Common
|
||||
{
|
||||
public class Ratelimiter
|
||||
{
|
||||
private readonly SlowmodeService _svc;
|
||||
|
||||
public class RatelimitedUser
|
||||
{
|
||||
public ulong UserId { get; set; }
|
||||
public int MessageCount { get; set; } = 0;
|
||||
}
|
||||
|
||||
public ulong ChannelId { get; set; }
|
||||
public int MaxMessages { get; set; }
|
||||
public int PerSeconds { get; set; }
|
||||
|
||||
public Ratelimiter(SlowmodeService svc)
|
||||
{
|
||||
_svc = svc;
|
||||
}
|
||||
|
||||
public CancellationTokenSource CancelSource { get; set; } = new CancellationTokenSource();
|
||||
|
||||
public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; } = new ConcurrentDictionary<ulong, RatelimitedUser>();
|
||||
|
||||
public bool CheckUserRatelimit(ulong id, ulong guildId, SocketGuildUser optUser)
|
||||
{
|
||||
if ((_svc.IgnoredUsers.TryGetValue(guildId, out HashSet<ulong> ignoreUsers) && ignoreUsers.Contains(id)) ||
|
||||
(optUser != null && _svc.IgnoredRoles.TryGetValue(guildId, out HashSet<ulong> ignoreRoles) && optUser.Roles.Any(x => ignoreRoles.Contains(x.Id))))
|
||||
return false;
|
||||
|
||||
var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
|
||||
if (usr.MessageCount >= MaxMessages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
usr.MessageCount++;
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(PerSeconds * 1000, CancelSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
usr.MessageCount--;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Discord;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Common
|
||||
{
|
||||
public class UserSpamStats : IDisposable
|
||||
{
|
||||
public int Count => timers.Count;
|
||||
public string LastMessage { get; set; }
|
||||
|
||||
private ConcurrentQueue<Timer> timers { get; }
|
||||
|
||||
public UserSpamStats(IUserMessage msg)
|
||||
{
|
||||
LastMessage = msg.Content.ToUpperInvariant();
|
||||
timers = new ConcurrentQueue<Timer>();
|
||||
|
||||
ApplyNextMessage(msg);
|
||||
}
|
||||
|
||||
private readonly object applyLock = new object();
|
||||
public void ApplyNextMessage(IUserMessage message)
|
||||
{
|
||||
lock (applyLock)
|
||||
{
|
||||
var upperMsg = message.Content.ToUpperInvariant();
|
||||
if (upperMsg != LastMessage || (string.IsNullOrWhiteSpace(upperMsg) && message.Attachments.Any()))
|
||||
{
|
||||
LastMessage = upperMsg;
|
||||
while (timers.TryDequeue(out var old))
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
var t = new Timer((_) => {
|
||||
if (timers.TryDequeue(out var old))
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(30));
|
||||
timers.Enqueue(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
while (timers.TryDequeue(out var old))
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
}
|
68
NadekoBot.Core/Modules/Administration/GameChannelCommands.cs
Normal file
68
NadekoBot.Core/Modules/Administration/GameChannelCommands.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class GameChannelCommands : NadekoSubmodule<GameVoiceChannelService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public GameChannelCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[RequireBotPermission(GuildPermission.MoveMembers)]
|
||||
public async Task GameVoiceChannel()
|
||||
{
|
||||
var vch = ((IGuildUser)Context.User).VoiceChannel;
|
||||
|
||||
if (vch == null)
|
||||
{
|
||||
await ReplyErrorLocalized("not_in_voice").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
ulong? id;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
|
||||
if (gc.GameVoiceChannel == vch.Id)
|
||||
{
|
||||
_service.GameVoiceChannels.TryRemove(vch.Id);
|
||||
id = gc.GameVoiceChannel = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(gc.GameVoiceChannel != null)
|
||||
_service.GameVoiceChannels.TryRemove(gc.GameVoiceChannel.Value);
|
||||
_service.GameVoiceChannels.Add(vch.Id);
|
||||
id = gc.GameVoiceChannel = vch.Id;
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
if (id == null)
|
||||
{
|
||||
await ReplyConfirmLocalized("gvc_disabled").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_service.GameVoiceChannels.Add(vch.Id);
|
||||
await ReplyConfirmLocalized("gvc_enabled", Format.Bold(vch.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
255
NadekoBot.Core/Modules/Administration/LocalizationCommands.cs
Normal file
255
NadekoBot.Core/Modules/Administration/LocalizationCommands.cs
Normal file
@ -0,0 +1,255 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class LocalizationCommands : NadekoSubmodule
|
||||
{
|
||||
private static ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
||||
{
|
||||
{"ar", "العربية" },
|
||||
{"zh-TW", "繁體中文, 台灣" },
|
||||
{"zh-CN", "简体中文, 中华人民共和国"},
|
||||
{"nl-NL", "Nederlands, Nederland"},
|
||||
{"en-US", "English, United States"},
|
||||
{"fr-FR", "Français, France"},
|
||||
{"cs-CZ", "Čeština, Česká republika" },
|
||||
{"da-DK", "Dansk, Danmark" },
|
||||
{"de-DE", "Deutsch, Deutschland"},
|
||||
{"he-IL", "עברית, ישראל"},
|
||||
{"id-ID", "Bahasa Indonesia, Indonesia" },
|
||||
{"it-IT", "Italiano, Italia" },
|
||||
{"ja-JP", "日本語, 日本"},
|
||||
{"ko-KR", "한국어, 대한민국" },
|
||||
{"nb-NO", "Norsk, Norge"},
|
||||
{"pl-PL", "Polski, Polska" },
|
||||
{"pt-BR", "Português Brasileiro, Brasil"},
|
||||
{"ro-RO", "Română, România" },
|
||||
{"ru-RU", "Русский, Россия"},
|
||||
{"sr-Cyrl-RS", "Српски, Србија"},
|
||||
{"es-ES", "Español, España"},
|
||||
{"sv-SE", "Svenska, Sverige"},
|
||||
{"tr-TR", "Türkçe, Türkiye"}
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task LanguageSet()
|
||||
{
|
||||
var cul = _localization.GetCultureInfo(Context.Guild);
|
||||
await ReplyConfirmLocalized("lang_set_show", Format.Bold(cul.ToString()), Format.Bold(cul.NativeName))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task LanguageSet(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
CultureInfo ci;
|
||||
if (name.Trim().ToLowerInvariant() == "default")
|
||||
{
|
||||
_localization.RemoveGuildCulture(Context.Guild);
|
||||
ci = _localization.DefaultCultureInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = new CultureInfo(name);
|
||||
_localization.SetGuildCulture(Context.Guild, ci);
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("lang_set", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("lang_set_fail").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task LanguageSetDefault()
|
||||
{
|
||||
var cul = _localization.DefaultCultureInfo;
|
||||
await ReplyConfirmLocalized("lang_set_bot_show", cul, cul.NativeName).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task LanguageSetDefault(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
CultureInfo ci;
|
||||
if (name.Trim().ToLowerInvariant() == "default")
|
||||
{
|
||||
_localization.ResetDefaultCulture();
|
||||
ci = _localization.DefaultCultureInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = new CultureInfo(name);
|
||||
_localization.SetDefaultCulture(ci);
|
||||
}
|
||||
await ReplyConfirmLocalized("lang_set_bot", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("lang_set_fail").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task LanguagesList()
|
||||
{
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("lang_list"))
|
||||
.WithDescription(string.Join("\n",
|
||||
supportedLocales.Select(x => $"{Format.Code(x.Key), -10} => {x.Value}"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* list of language codes for reference.
|
||||
* taken from https://github.com/dotnet/coreclr/blob/ee5862c6a257e60e263537d975ab6c513179d47f/src/mscorlib/src/System/Globalization/CultureData.cs#L192
|
||||
{ "029", "en-029" },
|
||||
{ "AE", "ar-AE" },
|
||||
{ "AF", "prs-AF" },
|
||||
{ "AL", "sq-AL" },
|
||||
{ "AM", "hy-AM" },
|
||||
{ "AR", "es-AR" },
|
||||
{ "AT", "de-AT" },
|
||||
{ "AU", "en-AU" },
|
||||
{ "AZ", "az-Cyrl-AZ" },
|
||||
{ "BA", "bs-Latn-BA" },
|
||||
{ "BD", "bn-BD" },
|
||||
{ "BE", "nl-BE" },
|
||||
{ "BG", "bg-BG" },
|
||||
{ "BH", "ar-BH" },
|
||||
{ "BN", "ms-BN" },
|
||||
{ "BO", "es-BO" },
|
||||
{ "BR", "pt-BR" },
|
||||
{ "BY", "be-BY" },
|
||||
{ "BZ", "en-BZ" },
|
||||
{ "CA", "en-CA" },
|
||||
{ "CH", "it-CH" },
|
||||
{ "CL", "es-CL" },
|
||||
{ "CN", "zh-CN" },
|
||||
{ "CO", "es-CO" },
|
||||
{ "CR", "es-CR" },
|
||||
{ "CS", "sr-Cyrl-CS" },
|
||||
{ "CZ", "cs-CZ" },
|
||||
{ "DE", "de-DE" },
|
||||
{ "DK", "da-DK" },
|
||||
{ "DO", "es-DO" },
|
||||
{ "DZ", "ar-DZ" },
|
||||
{ "EC", "es-EC" },
|
||||
{ "EE", "et-EE" },
|
||||
{ "EG", "ar-EG" },
|
||||
{ "ES", "es-ES" },
|
||||
{ "ET", "am-ET" },
|
||||
{ "FI", "fi-FI" },
|
||||
{ "FO", "fo-FO" },
|
||||
{ "FR", "fr-FR" },
|
||||
{ "GB", "en-GB" },
|
||||
{ "GE", "ka-GE" },
|
||||
{ "GL", "kl-GL" },
|
||||
{ "GR", "el-GR" },
|
||||
{ "GT", "es-GT" },
|
||||
{ "HK", "zh-HK" },
|
||||
{ "HN", "es-HN" },
|
||||
{ "HR", "hr-HR" },
|
||||
{ "HU", "hu-HU" },
|
||||
{ "ID", "id-ID" },
|
||||
{ "IE", "en-IE" },
|
||||
{ "IL", "he-IL" },
|
||||
{ "IN", "hi-IN" },
|
||||
{ "IQ", "ar-IQ" },
|
||||
{ "IR", "fa-IR" },
|
||||
{ "IS", "is-IS" },
|
||||
{ "IT", "it-IT" },
|
||||
{ "IV", "" },
|
||||
{ "JM", "en-JM" },
|
||||
{ "JO", "ar-JO" },
|
||||
{ "JP", "ja-JP" },
|
||||
{ "KE", "sw-KE" },
|
||||
{ "KG", "ky-KG" },
|
||||
{ "KH", "km-KH" },
|
||||
{ "KR", "ko-KR" },
|
||||
{ "KW", "ar-KW" },
|
||||
{ "KZ", "kk-KZ" },
|
||||
{ "LA", "lo-LA" },
|
||||
{ "LB", "ar-LB" },
|
||||
{ "LI", "de-LI" },
|
||||
{ "LK", "si-LK" },
|
||||
{ "LT", "lt-LT" },
|
||||
{ "LU", "lb-LU" },
|
||||
{ "LV", "lv-LV" },
|
||||
{ "LY", "ar-LY" },
|
||||
{ "MA", "ar-MA" },
|
||||
{ "MC", "fr-MC" },
|
||||
{ "ME", "sr-Latn-ME" },
|
||||
{ "MK", "mk-MK" },
|
||||
{ "MN", "mn-MN" },
|
||||
{ "MO", "zh-MO" },
|
||||
{ "MT", "mt-MT" },
|
||||
{ "MV", "dv-MV" },
|
||||
{ "MX", "es-MX" },
|
||||
{ "MY", "ms-MY" },
|
||||
{ "NG", "ig-NG" },
|
||||
{ "NI", "es-NI" },
|
||||
{ "NL", "nl-NL" },
|
||||
{ "NO", "nn-NO" },
|
||||
{ "NP", "ne-NP" },
|
||||
{ "NZ", "en-NZ" },
|
||||
{ "OM", "ar-OM" },
|
||||
{ "PA", "es-PA" },
|
||||
{ "PE", "es-PE" },
|
||||
{ "PH", "en-PH" },
|
||||
{ "PK", "ur-PK" },
|
||||
{ "PL", "pl-PL" },
|
||||
{ "PR", "es-PR" },
|
||||
{ "PT", "pt-PT" },
|
||||
{ "PY", "es-PY" },
|
||||
{ "QA", "ar-QA" },
|
||||
{ "RO", "ro-RO" },
|
||||
{ "RS", "sr-Latn-RS" },
|
||||
{ "RU", "ru-RU" },
|
||||
{ "RW", "rw-RW" },
|
||||
{ "SA", "ar-SA" },
|
||||
{ "SE", "sv-SE" },
|
||||
{ "SG", "zh-SG" },
|
||||
{ "SI", "sl-SI" },
|
||||
{ "SK", "sk-SK" },
|
||||
{ "SN", "wo-SN" },
|
||||
{ "SV", "es-SV" },
|
||||
{ "SY", "ar-SY" },
|
||||
{ "TH", "th-TH" },
|
||||
{ "TJ", "tg-Cyrl-TJ" },
|
||||
{ "TM", "tk-TM" },
|
||||
{ "TN", "ar-TN" },
|
||||
{ "TR", "tr-TR" },
|
||||
{ "TT", "en-TT" },
|
||||
{ "TW", "zh-TW" },
|
||||
{ "UA", "uk-UA" },
|
||||
{ "US", "en-US" },
|
||||
{ "UY", "es-UY" },
|
||||
{ "UZ", "uz-Cyrl-UZ" },
|
||||
{ "VE", "es-VE" },
|
||||
{ "VN", "vi-VN" },
|
||||
{ "YE", "ar-YE" },
|
||||
{ "ZA", "af-ZA" },
|
||||
{ "ZW", "en-ZW" }
|
||||
*/
|
183
NadekoBot.Core/Modules/Administration/LogCommands.cs
Normal file
183
NadekoBot.Core/Modules/Administration/LogCommands.cs
Normal file
@ -0,0 +1,183 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using static NadekoBot.Modules.Administration.Services.LogCommandService;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
[NoPublicBot]
|
||||
public class LogCommands : NadekoSubmodule<LogCommandService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public LogCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public enum EnableDisable
|
||||
{
|
||||
Enable,
|
||||
Disable
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[OwnerOnly]
|
||||
public async Task LogServer(PermissionAction action)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
LogSetting logSetting;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
|
||||
_service.GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
|
||||
logSetting.LogOtherId =
|
||||
logSetting.MessageUpdatedId =
|
||||
logSetting.MessageDeletedId =
|
||||
logSetting.UserJoinedId =
|
||||
logSetting.UserLeftId =
|
||||
logSetting.UserBannedId =
|
||||
logSetting.UserUnbannedId =
|
||||
logSetting.UserUpdatedId =
|
||||
logSetting.ChannelCreatedId =
|
||||
logSetting.ChannelDestroyedId =
|
||||
logSetting.ChannelUpdatedId =
|
||||
logSetting.LogUserPresenceId =
|
||||
logSetting.LogVoicePresenceId =
|
||||
logSetting.UserMutedId =
|
||||
logSetting.LogVoicePresenceTTSId = (action.Value ? channel.Id : (ulong?)null);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (action.Value)
|
||||
await ReplyConfirmLocalized("log_all").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("log_disabled").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[OwnerOnly]
|
||||
public async Task LogIgnore()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
int removed;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id);
|
||||
LogSetting logSetting = _service.GuildLogSettings.GetOrAdd(channel.Guild.Id, (id) => config.LogSetting);
|
||||
removed = logSetting.IgnoredChannels.RemoveWhere(ilc => ilc.ChannelId == channel.Id);
|
||||
config.LogSetting.IgnoredChannels.RemoveWhere(ilc => ilc.ChannelId == channel.Id);
|
||||
if (removed == 0)
|
||||
{
|
||||
var toAdd = new IgnoredLogChannel { ChannelId = channel.Id };
|
||||
logSetting.IgnoredChannels.Add(toAdd);
|
||||
config.LogSetting.IgnoredChannels.Add(toAdd);
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (removed == 0)
|
||||
await ReplyConfirmLocalized("log_ignore", Format.Bold(channel.Mention + "(" + channel.Id + ")")).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("log_not_ignore", Format.Bold(channel.Mention + "(" + channel.Id + ")")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[OwnerOnly]
|
||||
public async Task LogEvents()
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync(Format.Bold(GetText("log_events")) + "\n" +
|
||||
$"```fix\n{string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>())}```")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[OwnerOnly]
|
||||
public async Task Log(LogType type)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
ulong? channelId = null;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
|
||||
_service.GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
|
||||
switch (type)
|
||||
{
|
||||
case LogType.Other:
|
||||
channelId = logSetting.LogOtherId = (logSetting.LogOtherId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.MessageUpdated:
|
||||
channelId = logSetting.MessageUpdatedId = (logSetting.MessageUpdatedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.MessageDeleted:
|
||||
channelId = logSetting.MessageDeletedId = (logSetting.MessageDeletedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.UserJoined:
|
||||
channelId = logSetting.UserJoinedId = (logSetting.UserJoinedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.UserLeft:
|
||||
channelId = logSetting.UserLeftId = (logSetting.UserLeftId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.UserBanned:
|
||||
channelId = logSetting.UserBannedId = (logSetting.UserBannedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.UserUnbanned:
|
||||
channelId = logSetting.UserUnbannedId = (logSetting.UserUnbannedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.UserUpdated:
|
||||
channelId = logSetting.UserUpdatedId = (logSetting.UserUpdatedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.UserMuted:
|
||||
channelId = logSetting.UserMutedId = (logSetting.UserMutedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.ChannelCreated:
|
||||
channelId = logSetting.ChannelCreatedId = (logSetting.ChannelCreatedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.ChannelDestroyed:
|
||||
channelId = logSetting.ChannelDestroyedId = (logSetting.ChannelDestroyedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.ChannelUpdated:
|
||||
channelId = logSetting.ChannelUpdatedId = (logSetting.ChannelUpdatedId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.UserPresence:
|
||||
channelId = logSetting.LogUserPresenceId = (logSetting.LogUserPresenceId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.VoicePresence:
|
||||
channelId = logSetting.LogVoicePresenceId = (logSetting.LogVoicePresenceId == null ? channel.Id : default);
|
||||
break;
|
||||
case LogType.VoicePresenceTTS:
|
||||
channelId = logSetting.LogVoicePresenceTTSId = (logSetting.LogVoicePresenceTTSId == null ? channel.Id : default);
|
||||
break;
|
||||
}
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (channelId != null)
|
||||
await ReplyConfirmLocalized("log", Format.Bold(type.ToString())).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("log_stop", Format.Bold(type.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
381
NadekoBot.Core/Modules/Administration/MigrationCommands.cs
Normal file
381
NadekoBot.Core/Modules/Administration/MigrationCommands.cs
Normal file
@ -0,0 +1,381 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Concurrent;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services.Database;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Modules.Administration.Common.Migration;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class MigrationCommands : NadekoSubmodule
|
||||
{
|
||||
private const int CURRENT_VERSION = 1;
|
||||
private readonly DbService _db;
|
||||
|
||||
public MigrationCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task MigrateData()
|
||||
{
|
||||
var version = 0;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
version = uow.BotConfig.GetOrCreate().MigrationVersion;
|
||||
}
|
||||
try
|
||||
{
|
||||
for (var i = version; i < CURRENT_VERSION; i++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
Migrate0_9To1_0();
|
||||
break;
|
||||
}
|
||||
}
|
||||
await ReplyConfirmLocalized("migration_done").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(ex);
|
||||
await ReplyErrorLocalized("migration_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void Migrate0_9To1_0()
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var botConfig = uow.BotConfig.GetOrCreate();
|
||||
MigrateConfig0_9(uow, botConfig);
|
||||
MigratePermissions0_9(uow);
|
||||
MigrateServerSpecificConfigs0_9(uow);
|
||||
MigrateDb0_9(uow);
|
||||
|
||||
//NOW save it
|
||||
_log.Warn("Writing to disc");
|
||||
uow.Complete();
|
||||
botConfig.MigrationVersion = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateDb0_9(IUnitOfWork uow)
|
||||
{
|
||||
var db = new SqliteConnection("Data Source=data/nadekobot.sqlite");
|
||||
|
||||
if (!File.Exists("data/nadekobot.sqlite"))
|
||||
{
|
||||
_log.Warn("No data from the old database will be migrated.");
|
||||
return;
|
||||
}
|
||||
db.Open();
|
||||
|
||||
var com = db.CreateCommand();
|
||||
var i = 0;
|
||||
try
|
||||
{
|
||||
com.CommandText = "SELECT * FROM Announcement";
|
||||
|
||||
var reader = com.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
var gid = (ulong)(long)reader["ServerId"];
|
||||
var greet = (long)reader["Greet"] == 1;
|
||||
var greetDM = (long)reader["GreetPM"] == 1;
|
||||
var greetChannel = (ulong)(long)reader["GreetChannelId"];
|
||||
var greetMsg = (string)reader["GreetText"];
|
||||
var bye = (long)reader["Bye"] == 1;
|
||||
var byeChannel = (ulong)(long)reader["ByeChannelId"];
|
||||
var byeMsg = (string)reader["ByeText"];
|
||||
var gc = uow.GuildConfigs.For(gid, set => set);
|
||||
|
||||
if (greetDM)
|
||||
gc.SendDmGreetMessage = greet;
|
||||
else
|
||||
gc.SendChannelGreetMessage = greet;
|
||||
gc.GreetMessageChannelId = greetChannel;
|
||||
gc.ChannelGreetMessageText = greetMsg;
|
||||
|
||||
gc.SendChannelByeMessage = bye;
|
||||
gc.ByeMessageChannelId = byeChannel;
|
||||
gc.ChannelByeMessageText = byeMsg;
|
||||
|
||||
_log.Info(++i);
|
||||
}
|
||||
}
|
||||
catch {
|
||||
_log.Warn("Greet/bye messages won't be migrated");
|
||||
}
|
||||
var com2 = db.CreateCommand();
|
||||
com2.CommandText = "SELECT * FROM CurrencyState GROUP BY UserId";
|
||||
|
||||
i = 0;
|
||||
try
|
||||
{
|
||||
var reader2 = com2.ExecuteReader();
|
||||
while (reader2.Read())
|
||||
{
|
||||
_log.Info(++i);
|
||||
var curr = new Currency()
|
||||
{
|
||||
Amount = (long)reader2["Value"],
|
||||
UserId = (ulong)(long)reader2["UserId"]
|
||||
};
|
||||
uow.Currency.Add(curr);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn("Currency won't be migrated");
|
||||
}
|
||||
db.Close();
|
||||
try { File.Move("data/nadekobot.sqlite", "data/DELETE_ME_nadekobot.sqlite"); } catch { }
|
||||
}
|
||||
|
||||
private void MigrateServerSpecificConfigs0_9(IUnitOfWork uow)
|
||||
{
|
||||
const string specificConfigsPath = "data/ServerSpecificConfigs.json";
|
||||
|
||||
if (!File.Exists(specificConfigsPath))
|
||||
{
|
||||
_log.Warn($"No data from {specificConfigsPath} will be migrated.");
|
||||
return;
|
||||
}
|
||||
|
||||
var configs = new ConcurrentDictionary<ulong, ServerSpecificConfig>();
|
||||
try
|
||||
{
|
||||
configs = JsonConvert
|
||||
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
|
||||
File.ReadAllText(specificConfigsPath), new JsonSerializerSettings()
|
||||
{
|
||||
Error = (s, e) =>
|
||||
{
|
||||
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels")
|
||||
{
|
||||
e.ErrorContext.Handled = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex, "ServerSpecificConfig deserialization failed");
|
||||
return;
|
||||
}
|
||||
var i = 0;
|
||||
var selfAssRoles = new ConcurrentHashSet<SelfAssignedRole>();
|
||||
configs
|
||||
.Select(p => new { data = p.Value, gconfig = uow.GuildConfigs.For(p.Key) })
|
||||
.AsParallel()
|
||||
.ForAll(config =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var guildConfig = config.gconfig;
|
||||
var data = config.data;
|
||||
|
||||
guildConfig.AutoAssignRoleId = data.AutoAssignedRole;
|
||||
guildConfig.DeleteMessageOnCommand = data.AutoDeleteMessagesOnCommand;
|
||||
guildConfig.DefaultMusicVolume = data.DefaultMusicVolume;
|
||||
guildConfig.ExclusiveSelfAssignedRoles = data.ExclusiveSelfAssignedRoles;
|
||||
guildConfig.GenerateCurrencyChannelIds = new HashSet<GCChannelId>(data.GenerateCurrencyChannels.Select(gc => new GCChannelId() { ChannelId = gc.Key }));
|
||||
selfAssRoles.AddRange(data.ListOfSelfAssignableRoles.Select(r => new SelfAssignedRole() { GuildId = guildConfig.GuildId, RoleId = r }).ToArray());
|
||||
guildConfig.LogSetting.IgnoredChannels = new HashSet<IgnoredLogChannel>(data.LogserverIgnoreChannels.Select(id => new IgnoredLogChannel() { ChannelId = id }));
|
||||
|
||||
guildConfig.LogSetting.LogUserPresenceId = data.LogPresenceChannel;
|
||||
|
||||
|
||||
guildConfig.FollowedStreams = new HashSet<FollowedStream>(data.ObservingStreams.Select(x =>
|
||||
{
|
||||
FollowedStream.FollowedStreamType type = FollowedStream.FollowedStreamType.Twitch;
|
||||
switch (x.Type)
|
||||
{
|
||||
case StreamNotificationConfig0_9.StreamType.Twitch:
|
||||
type = FollowedStream.FollowedStreamType.Twitch;
|
||||
break;
|
||||
case StreamNotificationConfig0_9.StreamType.Beam:
|
||||
type = FollowedStream.FollowedStreamType.Mixer;
|
||||
break;
|
||||
case StreamNotificationConfig0_9.StreamType.Hitbox:
|
||||
type = FollowedStream.FollowedStreamType.Smashcast;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return new FollowedStream()
|
||||
{
|
||||
ChannelId = x.ChannelId,
|
||||
GuildId = guildConfig.GuildId,
|
||||
Username = x.Username.ToLowerInvariant(),
|
||||
Type = type
|
||||
};
|
||||
}));
|
||||
guildConfig.VoicePlusTextEnabled = data.VoicePlusTextEnabled;
|
||||
_log.Info("Migrating SpecificConfig for {0} done ({1})", guildConfig.GuildId, ++i);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(ex);
|
||||
}
|
||||
});
|
||||
uow.SelfAssignedRoles.AddRange(selfAssRoles.ToArray());
|
||||
try { File.Move("data/ServerSpecificConfigs.json", "data/DELETE_ME_ServerSpecificCOnfigs.json"); } catch { }
|
||||
}
|
||||
|
||||
private void MigratePermissions0_9(IUnitOfWork uow)
|
||||
{
|
||||
var permissionsDict = new ConcurrentDictionary<ulong, ServerPermissions0_9>();
|
||||
if (!Directory.Exists("data/permissions/"))
|
||||
{
|
||||
_log.Warn("No data from permissions will be migrated.");
|
||||
return;
|
||||
}
|
||||
foreach (var file in Directory.EnumerateFiles("data/permissions/"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var strippedFileName = Path.GetFileNameWithoutExtension(file);
|
||||
if (string.IsNullOrWhiteSpace(strippedFileName)) continue;
|
||||
var id = ulong.Parse(strippedFileName);
|
||||
var data = JsonConvert.DeserializeObject<ServerPermissions0_9>(File.ReadAllText(file));
|
||||
permissionsDict.TryAdd(id, data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
var i = 0;
|
||||
permissionsDict
|
||||
.Select(p => new { data = p.Value, gconfig = uow.GuildConfigs.For(p.Key) })
|
||||
.AsParallel()
|
||||
.ForAll(perms =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = perms.data;
|
||||
var gconfig = perms.gconfig;
|
||||
|
||||
gconfig.PermissionRole = data.PermissionsControllerRole;
|
||||
gconfig.VerbosePermissions = data.Verbose;
|
||||
gconfig.FilteredWords = new HashSet<FilteredWord>(data.Words.Select(w => w.ToLowerInvariant())
|
||||
.Distinct()
|
||||
.Select(w => new FilteredWord() { Word = w }));
|
||||
gconfig.FilterWords = data.Permissions.FilterWords;
|
||||
gconfig.FilterInvites = data.Permissions.FilterInvites;
|
||||
|
||||
gconfig.FilterInvitesChannelIds = new HashSet<FilterChannelId>();
|
||||
gconfig.FilterInvitesChannelIds.AddRange(data.ChannelPermissions.Where(kvp => kvp.Value.FilterInvites)
|
||||
.Select(cp => new FilterChannelId()
|
||||
{
|
||||
ChannelId = cp.Key
|
||||
}));
|
||||
|
||||
gconfig.FilterWordsChannelIds = new HashSet<FilterChannelId>();
|
||||
gconfig.FilterWordsChannelIds.AddRange(data.ChannelPermissions.Where(kvp => kvp.Value.FilterWords)
|
||||
.Select(cp => new FilterChannelId()
|
||||
{
|
||||
ChannelId = cp.Key
|
||||
}));
|
||||
|
||||
gconfig.CommandCooldowns = new HashSet<CommandCooldown>(data.CommandCooldowns
|
||||
.Where(cc => !string.IsNullOrWhiteSpace(cc.Key) && cc.Value > 0)
|
||||
.Select(cc => new CommandCooldown()
|
||||
{
|
||||
CommandName = cc.Key,
|
||||
Seconds = cc.Value
|
||||
}));
|
||||
_log.Info("Migrating data from permissions folder for {0} done ({1})", gconfig.GuildId, ++i);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(ex);
|
||||
}
|
||||
});
|
||||
|
||||
try { Directory.Move("data/permissions", "data/DELETE_ME_permissions"); } catch { }
|
||||
|
||||
}
|
||||
|
||||
private void MigrateConfig0_9(IUnitOfWork uow, BotConfig botConfig)
|
||||
{
|
||||
Config0_9 oldConfig;
|
||||
const string configPath = "data/config.json";
|
||||
try
|
||||
{
|
||||
oldConfig = JsonConvert.DeserializeObject<Config0_9>(File.ReadAllText(configPath));
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
_log.Warn("config.json not found");
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_log.Error("Unknown error while deserializing file config.json, pls check its integrity, aborting migration");
|
||||
throw new MigrationException();
|
||||
}
|
||||
|
||||
//Basic
|
||||
botConfig.ForwardMessages = oldConfig.ForwardMessages;
|
||||
botConfig.ForwardToAllOwners = oldConfig.ForwardToAllOwners;
|
||||
botConfig.BufferSize = (ulong)oldConfig.BufferSize;
|
||||
botConfig.RemindMessageFormat = oldConfig.RemindMessageFormat;
|
||||
botConfig.CurrencySign = oldConfig.CurrencySign;
|
||||
botConfig.CurrencyName = oldConfig.CurrencyName;
|
||||
botConfig.DMHelpString = oldConfig.DMHelpString;
|
||||
botConfig.HelpString = oldConfig.HelpString;
|
||||
|
||||
//messages
|
||||
botConfig.RotatingStatuses = oldConfig.IsRotatingStatus;
|
||||
var messages = new List<PlayingStatus>();
|
||||
|
||||
oldConfig.RotatingStatuses.ForEach(i => messages.Add(new PlayingStatus { Status = i }));
|
||||
botConfig.RotatingStatusMessages = messages;
|
||||
|
||||
//Blacklist
|
||||
var blacklist = new HashSet<BlacklistItem>(oldConfig.ServerBlacklist.Select(server => new BlacklistItem() { ItemId = server, Type = BlacklistType.Server }));
|
||||
blacklist.AddRange(oldConfig.ChannelBlacklist.Select(channel => new BlacklistItem() { ItemId = channel, Type = BlacklistType.Channel }));
|
||||
blacklist.AddRange(oldConfig.UserBlacklist.Select(user => new BlacklistItem() { ItemId = user, Type = BlacklistType.User }));
|
||||
botConfig.Blacklist = blacklist;
|
||||
|
||||
//Eightball
|
||||
botConfig.EightBallResponses = new HashSet<EightBallResponse>(oldConfig._8BallResponses.Select(response => new EightBallResponse() { Text = response }));
|
||||
|
||||
//customreactions
|
||||
uow.CustomReactions.AddRange(oldConfig.CustomReactions.SelectMany(cr =>
|
||||
{
|
||||
return cr.Value.Select(res => new CustomReaction()
|
||||
{
|
||||
GuildId = null,
|
||||
IsRegex = false,
|
||||
OwnerOnly = false,
|
||||
Response = res,
|
||||
Trigger = cr.Key.ToLowerInvariant(),
|
||||
});
|
||||
}).ToArray());
|
||||
|
||||
try { File.Move(configPath, "./data/DELETE_ME_config.json"); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
171
NadekoBot.Core/Modules/Administration/MuteCommands.cs
Normal file
171
NadekoBot.Core/Modules/Administration/MuteCommands.cs
Normal file
@ -0,0 +1,171 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class MuteCommands : NadekoSubmodule<MuteService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public MuteCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public async Task SetMuteRole([Remainder] string name)
|
||||
{
|
||||
name = name.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
config.MuteRoleName = name;
|
||||
_service.GuildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalized("mute_role_set").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[Priority(1)]
|
||||
public Task SetMuteRole([Remainder] IRole role)
|
||||
=> SetMuteRole(role.Name);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||
[Priority(0)]
|
||||
public async Task Mute(IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.MuteUser(user).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_muted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||
[Priority(1)]
|
||||
public async Task Mute(int minutes, IGuildUser user)
|
||||
{
|
||||
if (minutes < 1 || minutes > 1440)
|
||||
return;
|
||||
try
|
||||
{
|
||||
await _service.TimedMute(user, TimeSpan.FromMinutes(minutes)).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_muted_time", Format.Bold(user.ToString()), minutes).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||
public async Task Unmute(IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.UnmuteUser(user).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_unmuted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task ChatMute(IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.MuteUser(user, MuteType.Chat).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_chat_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task ChatUnmute(IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.UnmuteUser(user, MuteType.Chat).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_chat_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||
public async Task VoiceMute([Remainder] IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.MuteUser(user, MuteType.Voice).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_voice_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||
public async Task VoiceUnmute([Remainder] IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.UnmuteUser(user, MuteType.Voice).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_voice_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class PlayingRotateCommands : NadekoSubmodule<PlayingRotateService>
|
||||
{
|
||||
private static readonly object _locker = new object();
|
||||
private readonly DbService _db;
|
||||
|
||||
public PlayingRotateCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task RotatePlaying()
|
||||
{
|
||||
bool enabled;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
|
||||
enabled = config.RotatingStatuses = !config.RotatingStatuses;
|
||||
uow.Complete();
|
||||
}
|
||||
if (enabled)
|
||||
await ReplyConfirmLocalized("ropl_enabled").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("ropl_disabled").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task AddPlaying([Remainder] string status)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
var toAdd = new PlayingStatus { Status = status };
|
||||
config.RotatingStatusMessages.Add(toAdd);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("ropl_added").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ListPlaying()
|
||||
{
|
||||
if (!_service.BotConfig.RotatingStatusMessages.Any())
|
||||
await ReplyErrorLocalized("ropl_not_set").ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
var i = 1;
|
||||
await ReplyConfirmLocalized("ropl_list",
|
||||
string.Join("\n\t", _service.BotConfig.RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task RemovePlaying(int index)
|
||||
{
|
||||
index -= 1;
|
||||
|
||||
string msg;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
|
||||
if (index >= config.RotatingStatusMessages.Count)
|
||||
return;
|
||||
msg = config.RotatingStatusMessages[index].Status;
|
||||
config.RotatingStatusMessages.RemoveAt(index);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
await ReplyConfirmLocalized("reprm", msg).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
NadekoBot.Core/Modules/Administration/PrefixCommands.cs
Normal file
53
NadekoBot.Core/Modules/Administration/PrefixCommands.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class PrefixCommands : NadekoSubmodule
|
||||
{
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[Priority(1)]
|
||||
public new async Task Prefix()
|
||||
{
|
||||
await ReplyConfirmLocalized("prefix_current", Format.Code(_cmdHandler.GetPrefix(Context.Guild))).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[Priority(0)]
|
||||
public new async Task Prefix([Remainder]string prefix)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(prefix))
|
||||
return;
|
||||
|
||||
var oldPrefix = base.Prefix;
|
||||
var newPrefix = _cmdHandler.SetPrefix(Context.Guild, prefix);
|
||||
|
||||
await ReplyConfirmLocalized("prefix_new", Format.Code(oldPrefix), Format.Code(newPrefix)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task DefPrefix([Remainder]string prefix)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(prefix))
|
||||
{
|
||||
await ReplyConfirmLocalized("defprefix_current", _cmdHandler.DefaultPrefix).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var oldPrefix = _cmdHandler.DefaultPrefix;
|
||||
var newPrefix = _cmdHandler.SetDefaultPrefix(prefix);
|
||||
|
||||
await ReplyConfirmLocalized("defprefix_new", Format.Code(oldPrefix), Format.Code(newPrefix)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
274
NadekoBot.Core/Modules/Administration/ProtectionCommands.cs
Normal file
274
NadekoBot.Core/Modules/Administration/ProtectionCommands.cs
Normal file
@ -0,0 +1,274 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class ProtectionCommands : NadekoSubmodule<ProtectionService>
|
||||
{
|
||||
private readonly MuteService _mute;
|
||||
private readonly DbService _db;
|
||||
|
||||
public ProtectionCommands(MuteService mute, DbService db)
|
||||
{
|
||||
_mute = mute;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
private string GetAntiSpamString(AntiSpamStats stats)
|
||||
{
|
||||
var settings = stats.AntiSpamSettings;
|
||||
var ignoredString = string.Join(", ", settings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>"));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ignoredString))
|
||||
ignoredString = "none";
|
||||
|
||||
string add = "";
|
||||
if (settings.Action == PunishmentAction.Mute
|
||||
&& settings.MuteTime > 0)
|
||||
{
|
||||
add = " (" + settings.MuteTime + "s)";
|
||||
}
|
||||
|
||||
return GetText("spam_stats",
|
||||
Format.Bold(settings.MessageThreshold.ToString()),
|
||||
Format.Bold(settings.Action.ToString() + add),
|
||||
ignoredString);
|
||||
}
|
||||
|
||||
private string GetAntiRaidString(AntiRaidStats stats) => GetText("raid_stats",
|
||||
Format.Bold(stats.AntiRaidSettings.UserThreshold.ToString()),
|
||||
Format.Bold(stats.AntiRaidSettings.Seconds.ToString()),
|
||||
Format.Bold(stats.AntiRaidSettings.Action.ToString()));
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task AntiRaid(int userThreshold = 5, int seconds = 10, PunishmentAction action = PunishmentAction.Mute)
|
||||
{
|
||||
if (userThreshold < 2 || userThreshold > 30)
|
||||
{
|
||||
await ReplyErrorLocalized("raid_cnt", 2, 30).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (seconds < 2 || seconds > 300)
|
||||
{
|
||||
await ReplyErrorLocalized("raid_time", 2, 300).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_service.AntiRaidGuilds.TryRemove(Context.Guild.Id, out _))
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
||||
|
||||
gc.AntiRaidSetting = null;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalized("prot_disable", "Anti-Raid").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _mute.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
await ReplyErrorLocalized("prot_error").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var stats = new AntiRaidStats()
|
||||
{
|
||||
AntiRaidSettings = new AntiRaidSetting()
|
||||
{
|
||||
Action = action,
|
||||
Seconds = seconds,
|
||||
UserThreshold = userThreshold,
|
||||
}
|
||||
};
|
||||
|
||||
_service.AntiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
||||
|
||||
gc.AntiRaidSetting = stats.AntiRaidSettings;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync(GetText("prot_enable", "Anti-Raid"), $"{Context.User.Mention} {GetAntiRaidString(stats)}")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[Priority(1)]
|
||||
public async Task AntiSpam()
|
||||
{
|
||||
if (_service.AntiSpamGuilds.TryRemove(Context.Guild.Id, out var removed))
|
||||
{
|
||||
removed.UserStats.ForEach(x => x.Value.Dispose());
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels));
|
||||
|
||||
gc.AntiSpamSetting = null;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalized("prot_disable", "Anti-Spam").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await AntiSpam(3).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[Priority(0)]
|
||||
public async Task AntiSpam(int messageCount, PunishmentAction action = PunishmentAction.Mute, int time = 0)
|
||||
{
|
||||
if (messageCount < 2 || messageCount > 10)
|
||||
return;
|
||||
|
||||
if (time < 0 || time > 60 * 12)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
await _mute.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
await ReplyErrorLocalized("prot_error").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var stats = new AntiSpamStats
|
||||
{
|
||||
AntiSpamSettings = new AntiSpamSetting()
|
||||
{
|
||||
Action = action,
|
||||
MessageThreshold = messageCount,
|
||||
MuteTime = time,
|
||||
}
|
||||
};
|
||||
|
||||
stats = _service.AntiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) =>
|
||||
{
|
||||
stats.AntiSpamSettings.IgnoredChannels = old.AntiSpamSettings.IgnoredChannels;
|
||||
return stats;
|
||||
});
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting));
|
||||
|
||||
gc.AntiSpamSetting = stats.AntiSpamSettings;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync(GetText("prot_enable", "Anti-Spam"), $"{Context.User.Mention} {GetAntiSpamString(stats)}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task AntispamIgnore()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
var obj = new AntiSpamIgnore()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
};
|
||||
bool added;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels));
|
||||
var spam = gc.AntiSpamSetting;
|
||||
if (spam == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (spam.IgnoredChannels.Add(obj))
|
||||
{
|
||||
AntiSpamStats temp;
|
||||
if (_service.AntiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
temp.AntiSpamSettings.IgnoredChannels.Add(obj);
|
||||
added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
spam.IgnoredChannels.Remove(obj);
|
||||
AntiSpamStats temp;
|
||||
if (_service.AntiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
temp.AntiSpamSettings.IgnoredChannels.Remove(obj);
|
||||
added = false;
|
||||
}
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (added)
|
||||
await ReplyConfirmLocalized("spam_ignore", "Anti-Spam").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("spam_not_ignore", "Anti-Spam").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AntiList()
|
||||
{
|
||||
AntiSpamStats spam;
|
||||
_service.AntiSpamGuilds.TryGetValue(Context.Guild.Id, out spam);
|
||||
|
||||
AntiRaidStats raid;
|
||||
_service.AntiRaidGuilds.TryGetValue(Context.Guild.Id, out raid);
|
||||
|
||||
if (spam == null && raid == null)
|
||||
{
|
||||
await ReplyConfirmLocalized("prot_none").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("prot_active"));
|
||||
|
||||
if (spam != null)
|
||||
embed.AddField(efb => efb.WithName("Anti-Spam")
|
||||
.WithValue(GetAntiSpamString(spam))
|
||||
.WithIsInline(true));
|
||||
|
||||
if (raid != null)
|
||||
embed.AddField(efb => efb.WithName("Anti-Raid")
|
||||
.WithValue(GetAntiRaidString(raid))
|
||||
.WithIsInline(true));
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
NadekoBot.Core/Modules/Administration/PruneCommands.cs
Normal file
64
NadekoBot.Core/Modules/Administration/PruneCommands.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class PruneCommands : NadekoSubmodule<PruneService>
|
||||
{
|
||||
private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
|
||||
|
||||
//delets her own messages, no perm required
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Prune()
|
||||
{
|
||||
var user = await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||
|
||||
await _service.PruneWhere((ITextChannel)Context.Channel, 100, (x) => x.Author.Id == user.Id).ConfigureAwait(false);
|
||||
Context.Message.DeleteAfter(3);
|
||||
}
|
||||
// prune x
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||
[Priority(1)]
|
||||
public async Task Prune(int count)
|
||||
{
|
||||
count++;
|
||||
if (count < 1)
|
||||
return;
|
||||
if (count > 1000)
|
||||
count = 1000;
|
||||
await _service.PruneWhere((ITextChannel)Context.Channel, count, x => true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//prune @user [x]
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public async Task Prune(IGuildUser user, int count = 100)
|
||||
{
|
||||
if (user.Id == Context.User.Id)
|
||||
count++;
|
||||
|
||||
if (count < 1)
|
||||
return;
|
||||
|
||||
if (count > 1000)
|
||||
count = 1000;
|
||||
await _service.PruneWhere((ITextChannel)Context.Channel, count, m => m.Author.Id == user.Id && DateTime.UtcNow - m.CreatedAt < twoWeeks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
NadekoBot.Core/Modules/Administration/RatelimitCommands.cs
Normal file
131
NadekoBot.Core/Modules/Administration/RatelimitCommands.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class SlowModeCommands : NadekoSubmodule<SlowmodeService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public SlowModeCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Slowmode()
|
||||
{
|
||||
if (_service.RatelimitingChannels.TryRemove(Context.Channel.Id, out Ratelimiter removed))
|
||||
{
|
||||
removed.CancelSource.Cancel();
|
||||
await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Slowmode(int msg, int perSec)
|
||||
{
|
||||
await Slowmode().ConfigureAwait(false); // disable if exists
|
||||
|
||||
if (msg < 1 || perSec < 1 || msg > 100 || perSec > 3600)
|
||||
{
|
||||
await ReplyErrorLocalized("invalid_params").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var toAdd = new Ratelimiter(_service)
|
||||
{
|
||||
ChannelId = Context.Channel.Id,
|
||||
MaxMessages = msg,
|
||||
PerSeconds = perSec,
|
||||
};
|
||||
if(_service.RatelimitingChannels.TryAdd(Context.Channel.Id, toAdd))
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync(GetText("slowmode_init"),
|
||||
GetText("slowmode_desc", Format.Bold(toAdd.MaxMessages.ToString()), Format.Bold(toAdd.PerSeconds.ToString())))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public async Task SlowmodeWhitelist(IGuildUser user)
|
||||
{
|
||||
var siu = new SlowmodeIgnoredUser
|
||||
{
|
||||
UserId = user.Id
|
||||
};
|
||||
|
||||
HashSet<SlowmodeIgnoredUser> usrs;
|
||||
bool removed;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
usrs = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredUsers))
|
||||
.SlowmodeIgnoredUsers;
|
||||
|
||||
if (!(removed = usrs.Remove(siu)))
|
||||
usrs.Add(siu);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_service.IgnoredUsers.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(usrs.Select(x => x.UserId)), (key, old) => new HashSet<ulong>(usrs.Select(x => x.UserId)));
|
||||
|
||||
if(removed)
|
||||
await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("slowmodewl_user_start", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[Priority(1)]
|
||||
public async Task SlowmodeWhitelist(IRole role)
|
||||
{
|
||||
var sir = new SlowmodeIgnoredRole
|
||||
{
|
||||
RoleId = role.Id
|
||||
};
|
||||
|
||||
HashSet<SlowmodeIgnoredRole> roles;
|
||||
bool removed;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
roles = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredRoles))
|
||||
.SlowmodeIgnoredRoles;
|
||||
|
||||
if (!(removed = roles.Remove(sir)))
|
||||
roles.Add(sir);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_service.IgnoredRoles.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(roles.Select(x => x.RoleId)), (key, old) => new HashSet<ulong>(roles.Select(x => x.RoleId)));
|
||||
|
||||
if (removed)
|
||||
await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("slowmodewl_role_start", Format.Bold(role.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.Collections;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class SelfAssignedRolesCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public SelfAssignedRolesCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task AdSarm()
|
||||
{
|
||||
bool newval;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ Automatic deleting of `iam` and `iamn` confirmations has been {(newval ? "**enabled**" : "**disabled**")}.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Asar([Remainder] IRole role)
|
||||
{
|
||||
IEnumerable<SelfAssignedRole> roles;
|
||||
|
||||
var guser = (IGuildUser)Context.User;
|
||||
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
return;
|
||||
|
||||
string msg;
|
||||
var error = false;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
||||
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id))
|
||||
{
|
||||
msg = GetText("role_in_list", Format.Bold(role.Name));
|
||||
error = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uow.SelfAssignedRoles.Add(new SelfAssignedRole
|
||||
{
|
||||
RoleId = role.Id,
|
||||
GuildId = role.Guild.Id
|
||||
});
|
||||
await uow.CompleteAsync();
|
||||
msg = GetText("role_added", Format.Bold(role.Name));
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
await Context.Channel.SendErrorAsync(msg).ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Rsar([Remainder] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)Context.User;
|
||||
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
return;
|
||||
|
||||
bool success;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
success = uow.SelfAssignedRoles.DeleteByGuildAndRoleId(role.Guild.Id, role.Id);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await ReplyConfirmLocalized("self_assign_rem", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Lsar(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
|
||||
var toRemove = new ConcurrentHashSet<SelfAssignedRole>();
|
||||
var removeMsg = new StringBuilder();
|
||||
var roles = new List<string>();
|
||||
var roleCnt = 0;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var roleModels = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToList();
|
||||
|
||||
foreach (var roleModel in roleModels)
|
||||
{
|
||||
var role = Context.Guild.Roles.FirstOrDefault(r => r.Id == roleModel.RoleId);
|
||||
if (role == null)
|
||||
{
|
||||
toRemove.Add(roleModel);
|
||||
uow.SelfAssignedRoles.Remove(roleModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
roles.Add(Format.Bold(role.Name));
|
||||
roleCnt++;
|
||||
}
|
||||
}
|
||||
foreach (var role in toRemove)
|
||||
{
|
||||
roles.Add(GetText("role_clean", role.RoleId));
|
||||
}
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
|
||||
await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, (curPage) =>
|
||||
{
|
||||
return new EmbedBuilder()
|
||||
.WithTitle(GetText("self_assign_list", roleCnt))
|
||||
.WithDescription(string.Join("\n", roles.Skip(curPage * 10).Take(10)))
|
||||
.WithOkColor();
|
||||
}, roles.Count / 10);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Tesar()
|
||||
{
|
||||
bool areExclusive;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
|
||||
areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
if(areExclusive)
|
||||
await ReplyConfirmLocalized("self_assign_excl").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("self_assign_no_excl").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iam([Remainder] IRole role)
|
||||
{
|
||||
var guildUser = (IGuildUser)Context.User;
|
||||
|
||||
GuildConfig conf;
|
||||
SelfAssignedRole[] roles;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToArray();
|
||||
}
|
||||
if (roles.FirstOrDefault(r=>r.RoleId == role.Id) == null)
|
||||
{
|
||||
await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await ReplyErrorLocalized("self_assign_already", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var roleIds = roles.Select(x => x.RoleId).ToArray();
|
||||
if (conf.ExclusiveSelfAssignedRoles)
|
||||
{
|
||||
var sameRoles = guildUser.RoleIds.Where(r => roleIds.Contains(r));
|
||||
|
||||
foreach (var roleId in sameRoles)
|
||||
{
|
||||
var sameRole = Context.Guild.GetRole(roleId);
|
||||
if (sameRole != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(sameRole).ConfigureAwait(false);
|
||||
await Task.Delay(300).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
await guildUser.AddRoleAsync(role).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyErrorLocalized("self_assign_perms").ConfigureAwait(false);
|
||||
_log.Info(ex);
|
||||
return;
|
||||
}
|
||||
var msg = await ReplyConfirmLocalized("self_assign_success",Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
|
||||
if (conf.AutoDeleteSelfAssignedRoleMessages)
|
||||
{
|
||||
msg.DeleteAfter(3);
|
||||
Context.Message.DeleteAfter(3);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iamnot([Remainder] IRole role)
|
||||
{
|
||||
var guildUser = (IGuildUser)Context.User;
|
||||
|
||||
bool autoDeleteSelfAssignedRoleMessages;
|
||||
IEnumerable<SelfAssignedRole> roles;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
autoDeleteSelfAssignedRoleMessages = uow.GuildConfigs.For(Context.Guild.Id, set => set).AutoDeleteSelfAssignedRoleMessages;
|
||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
||||
}
|
||||
if (roles.FirstOrDefault(r => r.RoleId == role.Id) == null)
|
||||
{
|
||||
await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await ReplyErrorLocalized("self_assign_not_have",Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(role).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("self_assign_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var msg = await ReplyConfirmLocalized("self_assign_remove", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
|
||||
if (autoDeleteSelfAssignedRoleMessages)
|
||||
{
|
||||
msg.DeleteAfter(3);
|
||||
Context.Message.DeleteAfter(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
465
NadekoBot.Core/Modules/Administration/SelfCommands.cs
Normal file
465
NadekoBot.Core/Modules/Administration/SelfCommands.cs
Normal file
@ -0,0 +1,465 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Diagnostics;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class SelfCommands : NadekoSubmodule<SelfService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
private static readonly object _locker = new object();
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IImagesService _images;
|
||||
private readonly IBotConfigProvider _bc;
|
||||
private readonly NadekoBot _bot;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
public SelfCommands(DbService db, NadekoBot bot, DiscordSocketClient client,
|
||||
IImagesService images, IBotConfigProvider bc,
|
||||
IBotCredentials creds)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
_images = images;
|
||||
_bc = bc;
|
||||
_bot = bot;
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartupCommandAdd([Remainder] string cmdText)
|
||||
{
|
||||
var guser = ((IGuildUser)Context.User);
|
||||
var cmd = new StartupCommand()
|
||||
{
|
||||
CommandText = cmdText,
|
||||
ChannelId = Context.Channel.Id,
|
||||
ChannelName = Context.Channel.Name,
|
||||
GuildId = Context.Guild?.Id,
|
||||
GuildName = Context.Guild?.Name,
|
||||
VoiceChannelId = guser.VoiceChannel?.Id,
|
||||
VoiceChannelName = guser.VoiceChannel?.Name,
|
||||
};
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.BotConfig
|
||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||
.StartupCommands.Add(cmd);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("scadd"))
|
||||
.AddField(efb => efb.WithName(GetText("server"))
|
||||
.WithValue(cmd.GuildId == null ? $"-" : $"{cmd.GuildName}/{cmd.GuildId}").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("channel"))
|
||||
.WithValue($"{cmd.ChannelName}/{cmd.ChannelId}").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("command_text"))
|
||||
.WithValue(cmdText).WithIsInline(false)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartupCommands(int page = 1)
|
||||
{
|
||||
if (page < 1)
|
||||
return;
|
||||
page -= 1;
|
||||
IEnumerable<StartupCommand> scmds;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
scmds = uow.BotConfig
|
||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||
.StartupCommands
|
||||
.OrderBy(x => x.Id)
|
||||
.ToArray();
|
||||
}
|
||||
scmds = scmds.Skip(page * 5).Take(5);
|
||||
if (!scmds.Any())
|
||||
{
|
||||
await ReplyErrorLocalized("startcmdlist_none").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("", string.Join("\n", scmds.Select(x =>
|
||||
{
|
||||
string str = $"```css\n[{GetText("server") + "]: " + (x.GuildId == null ? "-" : x.GuildName + " #" + x.GuildId)}";
|
||||
|
||||
str += $@"
|
||||
[{GetText("channel")}]: {x.ChannelName} #{x.ChannelId}
|
||||
[{GetText("command_text")}]: {x.CommandText}```";
|
||||
return str;
|
||||
})), footer: GetText("page", page + 1))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Wait(int miliseconds)
|
||||
{
|
||||
if (miliseconds <= 0)
|
||||
return;
|
||||
Context.Message.DeleteAfter(0);
|
||||
try
|
||||
{
|
||||
var msg = await Context.Channel.SendConfirmAsync($"⏲ {miliseconds}ms")
|
||||
.ConfigureAwait(false);
|
||||
msg.DeleteAfter(miliseconds / 1000);
|
||||
}
|
||||
catch { }
|
||||
|
||||
await Task.Delay(miliseconds);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartupCommandRemove([Remainder] string cmdText)
|
||||
{
|
||||
StartupCommand cmd;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var cmds = uow.BotConfig
|
||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||
.StartupCommands;
|
||||
cmd = cmds
|
||||
.FirstOrDefault(x => x.CommandText.ToLowerInvariant() == cmdText.ToLowerInvariant());
|
||||
|
||||
if (cmd != null)
|
||||
{
|
||||
cmds.Remove(cmd);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == null)
|
||||
await ReplyErrorLocalized("scrm_fail").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("scrm").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartupCommandsClear()
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.BotConfig
|
||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||
.StartupCommands
|
||||
.Clear();
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("startcmds_cleared").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardMessages()
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
config.ForwardMessages = !config.ForwardMessages;
|
||||
uow.Complete();
|
||||
}
|
||||
_bc.Reload();
|
||||
|
||||
if (_service.ForwardDMs)
|
||||
await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("fwdm_stop").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardToAll()
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
lock (_locker)
|
||||
config.ForwardToAllOwners = !config.ForwardToAllOwners;
|
||||
uow.Complete();
|
||||
}
|
||||
_bc.Reload();
|
||||
|
||||
if (_service.ForwardDMsToAllOwners)
|
||||
await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("fwall_stop").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
//todo 2 shard commands
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
//[Shard0Precondition]
|
||||
//[OwnerOnly]
|
||||
//public async Task RestartShard(int shardid)
|
||||
//{
|
||||
// if (shardid == 0 || shardid > b)
|
||||
// {
|
||||
// await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false);
|
||||
// return;
|
||||
// }
|
||||
// try
|
||||
// {
|
||||
// await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
||||
// await shard.StartAsync().ConfigureAwait(false);
|
||||
// await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _log.Warn(ex);
|
||||
// }
|
||||
//}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Leave([Remainder] string guildStr)
|
||||
{
|
||||
guildStr = guildStr.Trim().ToUpperInvariant();
|
||||
var server = _client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr) ??
|
||||
_client.Guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr);
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
await ReplyErrorLocalized("no_server").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (server.OwnerId != _client.CurrentUser.Id)
|
||||
{
|
||||
await server.LeaveAsync().ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("left_server", Format.Bold(server.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await server.DeleteAsync().ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("deleted_server", Format.Bold(server.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Die()
|
||||
{
|
||||
try
|
||||
{
|
||||
await ReplyConfirmLocalized("shutting_down").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Restart()
|
||||
{
|
||||
var cmd = _creds.RestartCommand;
|
||||
if (cmd == null || string.IsNullOrWhiteSpace(cmd.Cmd))
|
||||
{
|
||||
await ReplyErrorLocalized("restart_fail").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("restarting").ConfigureAwait(false);
|
||||
Process.Start(cmd.Cmd, cmd.Args);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetName([Remainder] string newName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newName))
|
||||
return;
|
||||
|
||||
await _client.CurrentUser.ModifyAsync(u => u.Username = newName).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("bot_name", Format.Bold(newName)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(GuildPermission.ManageNicknames)]
|
||||
[Priority(0)]
|
||||
public async Task SetNick([Remainder] string newNick = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newNick))
|
||||
return;
|
||||
var curUser = await Context.Guild.GetCurrentUserAsync();
|
||||
await curUser.ModifyAsync(u => u.Nickname = newNick).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("bot_nick", Format.Bold(newNick) ?? "-").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireBotPermission(GuildPermission.ManageNicknames)]
|
||||
[RequireUserPermission(GuildPermission.ManageNicknames)]
|
||||
[Priority(1)]
|
||||
public async Task SetNick(IGuildUser gu, [Remainder] string newNick = null)
|
||||
{
|
||||
await gu.ModifyAsync(u => u.Nickname = newNick).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("user_nick", Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetStatus([Remainder] SettableUserStatus status)
|
||||
{
|
||||
await _client.SetStatusAsync(SettableUserStatusToUserStatus(status)).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("bot_status", Format.Bold(status.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetAvatar([Remainder] string img = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(img))
|
||||
return;
|
||||
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
using (var sr = await http.GetStreamAsync(img))
|
||||
{
|
||||
var imgStream = new MemoryStream();
|
||||
await sr.CopyToAsync(imgStream);
|
||||
imgStream.Position = 0;
|
||||
|
||||
await _client.CurrentUser.ModifyAsync(u => u.Avatar = new Image(imgStream)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("set_avatar").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetGame([Remainder] string game = null)
|
||||
{
|
||||
await _bot.SetGameAsync(game).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("set_game").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetStream(string url, [Remainder] string name = null)
|
||||
{
|
||||
name = name ?? "";
|
||||
|
||||
await _client.SetGameAsync(name, url, StreamType.Twitch).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("set_stream").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Send(string where, [Remainder] string msg = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
return;
|
||||
|
||||
var ids = where.Split('|');
|
||||
if (ids.Length != 2)
|
||||
return;
|
||||
var sid = ulong.Parse(ids[0]);
|
||||
var server = _client.Guilds.FirstOrDefault(s => s.Id == sid);
|
||||
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
if (ids[1].ToUpperInvariant().StartsWith("C:"))
|
||||
{
|
||||
var cid = ulong.Parse(ids[1].Substring(2));
|
||||
var ch = server.TextChannels.FirstOrDefault(c => c.Id == cid);
|
||||
if (ch == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await ch.SendMessageAsync(msg).ConfigureAwait(false);
|
||||
}
|
||||
else if (ids[1].ToUpperInvariant().StartsWith("U:"))
|
||||
{
|
||||
var uid = ulong.Parse(ids[1].Substring(2));
|
||||
var user = server.Users.FirstOrDefault(u => u.Id == uid);
|
||||
if (user == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await user.SendMessageAsync(msg).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalized("invalid_format").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await ReplyConfirmLocalized("message_sent").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ReloadImages()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
_images.Reload();
|
||||
sw.Stop();
|
||||
await ReplyConfirmLocalized("images_loaded", sw.Elapsed.TotalSeconds.ToString("F3")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
|
||||
{
|
||||
switch (sus)
|
||||
{
|
||||
case SettableUserStatus.Online:
|
||||
return UserStatus.Online;
|
||||
case SettableUserStatus.Invisible:
|
||||
return UserStatus.Invisible;
|
||||
case SettableUserStatus.Idle:
|
||||
return UserStatus.AFK;
|
||||
case SettableUserStatus.Dnd:
|
||||
return UserStatus.DoNotDisturb;
|
||||
}
|
||||
|
||||
return UserStatus.Online;
|
||||
}
|
||||
|
||||
public enum SettableUserStatus
|
||||
{
|
||||
Online,
|
||||
Invisible,
|
||||
Idle,
|
||||
Dnd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
162
NadekoBot.Core/Modules/Administration/ServerGreetCommands.cs
Normal file
162
NadekoBot.Core/Modules/Administration/ServerGreetCommands.cs
Normal file
@ -0,0 +1,162 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class ServerGreetCommands : NadekoSubmodule<GreetSettingsService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public ServerGreetCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task GreetDel(int timer = 30)
|
||||
{
|
||||
if (timer < 0 || timer > 600)
|
||||
return;
|
||||
|
||||
await _service.SetGreetDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
||||
|
||||
if (timer > 0)
|
||||
await ReplyConfirmLocalized("greetdel_on", timer).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("greetdel_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task Greet()
|
||||
{
|
||||
var enabled = await _service.SetGreet(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
||||
|
||||
if (enabled)
|
||||
await ReplyConfirmLocalized("greet_on").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("greet_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task GreetMsg([Remainder] string text = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
string channelGreetMessageText;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
channelGreetMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelGreetMessageText;
|
||||
}
|
||||
await ReplyConfirmLocalized("greetmsg_cur", channelGreetMessageText?.SanitizeMentions()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sendGreetEnabled = _service.SetGreetMessage(Context.Guild.Id, ref text);
|
||||
|
||||
await ReplyConfirmLocalized("greetmsg_new").ConfigureAwait(false);
|
||||
if (!sendGreetEnabled)
|
||||
await ReplyConfirmLocalized("greetmsg_enable", $"`{Prefix}greet`").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task GreetDm()
|
||||
{
|
||||
var enabled = await _service.SetGreetDm(Context.Guild.Id).ConfigureAwait(false);
|
||||
|
||||
if (enabled)
|
||||
await ReplyConfirmLocalized("greetdm_on").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("greetdm_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task GreetDmMsg([Remainder] string text = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
GuildConfig config;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
config = uow.GuildConfigs.For(Context.Guild.Id);
|
||||
}
|
||||
await ReplyConfirmLocalized("greetdmmsg_cur", config.DmGreetMessageText?.SanitizeMentions()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sendGreetEnabled = _service.SetGreetDmMessage(Context.Guild.Id, ref text);
|
||||
|
||||
await ReplyConfirmLocalized("greetdmmsg_new").ConfigureAwait(false);
|
||||
if (!sendGreetEnabled)
|
||||
await ReplyConfirmLocalized("greetdmmsg_enable", $"`{Prefix}greetdm`").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task Bye()
|
||||
{
|
||||
var enabled = await _service.SetBye(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
||||
|
||||
if (enabled)
|
||||
await ReplyConfirmLocalized("bye_on").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("bye_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task ByeMsg([Remainder] string text = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
string byeMessageText;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
byeMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelByeMessageText;
|
||||
}
|
||||
await ReplyConfirmLocalized("byemsg_cur", byeMessageText?.SanitizeMentions()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sendByeEnabled = _service.SetByeMessage(Context.Guild.Id, ref text);
|
||||
|
||||
await ReplyConfirmLocalized("byemsg_new").ConfigureAwait(false);
|
||||
if (!sendByeEnabled)
|
||||
await ReplyConfirmLocalized("byemsg_enable", $"`{Prefix}bye`").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task ByeDel(int timer = 30)
|
||||
{
|
||||
await _service.SetByeDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
||||
|
||||
if (timer > 0)
|
||||
await ReplyConfirmLocalized("byedel_on", timer).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("byedel_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class AdministrationService : INService
|
||||
{
|
||||
public readonly ConcurrentHashSet<ulong> DeleteMessagesOnCommand;
|
||||
private readonly Logger _log;
|
||||
|
||||
public AdministrationService(IEnumerable<GuildConfig> gcs, CommandHandler cmdHandler)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
DeleteMessagesOnCommand = new ConcurrentHashSet<ulong>(gcs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
||||
cmdHandler.CommandExecuted += DelMsgOnCmd_Handler;
|
||||
}
|
||||
|
||||
private Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var channel = msg.Channel as SocketTextChannel;
|
||||
if (channel == null)
|
||||
return;
|
||||
if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick")
|
||||
await msg.DeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Delmsgoncmd errored...");
|
||||
_log.Warn(ex);
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class AutoAssignRoleService : INService
|
||||
{
|
||||
private readonly Logger _log;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
//guildid/roleid
|
||||
public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
|
||||
|
||||
public AutoAssignRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
|
||||
AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(
|
||||
gcs.Where(x => x.AutoAssignRoleId != 0)
|
||||
.ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
|
||||
|
||||
_client.UserJoined += (user) =>
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
AutoAssignedRoles.TryGetValue(user.Guild.Id, out ulong roleId);
|
||||
|
||||
if (roleId == 0)
|
||||
return;
|
||||
|
||||
var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
|
||||
|
||||
if (role != null)
|
||||
await user.AddRoleAsync(role).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class GameVoiceChannelService : INService
|
||||
{
|
||||
public readonly ConcurrentHashSet<ulong> GameVoiceChannels = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private readonly Logger _log;
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public GameVoiceChannelService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
_client = client;
|
||||
|
||||
GameVoiceChannels = new ConcurrentHashSet<ulong>(
|
||||
gcs.Where(gc => gc.GameVoiceChannel != null)
|
||||
.Select(gc => gc.GameVoiceChannel.Value));
|
||||
|
||||
_client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
||||
|
||||
}
|
||||
|
||||
private Task Client_UserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var gUser = usr as SocketGuildUser;
|
||||
if (gUser == null)
|
||||
return;
|
||||
|
||||
var game = gUser.Game?.Name?.TrimTo(50).ToLowerInvariant();
|
||||
|
||||
if (oldState.VoiceChannel == newState.VoiceChannel ||
|
||||
newState.VoiceChannel == null)
|
||||
return;
|
||||
|
||||
if (!GameVoiceChannels.Contains(newState.VoiceChannel.Id) ||
|
||||
string.IsNullOrWhiteSpace(game))
|
||||
return;
|
||||
|
||||
var vch = gUser.Guild.VoiceChannels
|
||||
.FirstOrDefault(x => x.Name.ToLowerInvariant() == game);
|
||||
|
||||
if (vch == null)
|
||||
return;
|
||||
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
await gUser.ModifyAsync(gu => gu.Channel = vch).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class GuildTimezoneService : INService
|
||||
{
|
||||
// todo 70 this is a hack >.<
|
||||
public static ConcurrentDictionary<ulong, GuildTimezoneService> AllServices { get; } = new ConcurrentDictionary<ulong, GuildTimezoneService>();
|
||||
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
|
||||
private readonly DbService _db;
|
||||
|
||||
public GuildTimezoneService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
||||
{
|
||||
_timezones = gcs
|
||||
.Select(x =>
|
||||
{
|
||||
TimeZoneInfo tz;
|
||||
try
|
||||
{
|
||||
if (x.TimeZoneId == null)
|
||||
tz = null;
|
||||
else
|
||||
tz = TimeZoneInfo.FindSystemTimeZoneById(x.TimeZoneId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
tz = null;
|
||||
}
|
||||
return (x.GuildId, tz);
|
||||
})
|
||||
.Where(x => x.Item2 != null)
|
||||
.ToDictionary(x => x.Item1, x => x.Item2)
|
||||
.ToConcurrent();
|
||||
|
||||
var curUser = client.CurrentUser;
|
||||
if (curUser != null)
|
||||
AllServices.TryAdd(curUser.Id, this);
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public TimeZoneInfo GetTimeZoneOrDefault(ulong guildId)
|
||||
{
|
||||
if (_timezones.TryGetValue(guildId, out var tz))
|
||||
return tz;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SetTimeZone(ulong guildId, TimeZoneInfo tz)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||
|
||||
gc.TimeZoneId = tz?.Id;
|
||||
uow.Complete();
|
||||
|
||||
if (tz == null)
|
||||
_timezones.TryRemove(guildId, out tz);
|
||||
else
|
||||
_timezones.AddOrUpdate(guildId, tz, (key, old) => tz);
|
||||
}
|
||||
}
|
||||
|
||||
public TimeZoneInfo GetTimeZoneOrUtc(ulong guildId)
|
||||
=> GetTimeZoneOrDefault(guildId) ?? TimeZoneInfo.Utc;
|
||||
}
|
||||
}
|
1027
NadekoBot.Core/Modules/Administration/Services/LogCommandService.cs
Normal file
1027
NadekoBot.Core/Modules/Administration/Services/LogCommandService.cs
Normal file
File diff suppressed because it is too large
Load Diff
280
NadekoBot.Core/Modules/Administration/Services/MuteService.cs
Normal file
280
NadekoBot.Core/Modules/Administration/Services/MuteService.cs
Normal file
@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public enum MuteType
|
||||
{
|
||||
Voice,
|
||||
Chat,
|
||||
All
|
||||
}
|
||||
|
||||
public class MuteService : INService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
|
||||
public ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
|
||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>> UnmuteTimers { get; }
|
||||
= new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>>();
|
||||
|
||||
public event Action<IGuildUser, MuteType> UserMuted = delegate { };
|
||||
public event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
|
||||
|
||||
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(addReactions: PermValue.Deny, sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
|
||||
|
||||
private readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly DbService _db;
|
||||
|
||||
public MuteService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
||||
{
|
||||
_client = client;
|
||||
_db = db;
|
||||
|
||||
GuildMuteRoles = gcs
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
|
||||
.ToDictionary(c => c.GuildId, c => c.MuteRoleName)
|
||||
.ToConcurrent();
|
||||
|
||||
MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(gcs.ToDictionary(
|
||||
k => k.GuildId,
|
||||
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
|
||||
));
|
||||
|
||||
foreach (var conf in gcs)
|
||||
{
|
||||
foreach (var x in conf.UnmuteTimers)
|
||||
{
|
||||
TimeSpan after;
|
||||
if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
|
||||
{
|
||||
after = TimeSpan.FromMinutes(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
after = x.UnmuteAt - DateTime.UtcNow;
|
||||
}
|
||||
StartUnmuteTimer(conf.GuildId, x.UserId, after);
|
||||
}
|
||||
}
|
||||
|
||||
_client.UserJoined += Client_UserJoined;
|
||||
}
|
||||
|
||||
private Task Client_UserJoined(IGuildUser usr)
|
||||
{
|
||||
try
|
||||
{
|
||||
MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted);
|
||||
|
||||
if (muted == null || !muted.Contains(usr.Id))
|
||||
return Task.CompletedTask;
|
||||
var _ = Task.Run(() => MuteUser(usr).ConfigureAwait(false));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task MuteUser(IGuildUser usr, MuteType type = MuteType.All)
|
||||
{
|
||||
if (type == MuteType.All)
|
||||
{
|
||||
await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
|
||||
var muteRole = await GetMuteRole(usr.Guild);
|
||||
if (!usr.RoleIds.Contains(muteRole.Id))
|
||||
await usr.AddRoleAsync(muteRole).ConfigureAwait(false);
|
||||
StopUnmuteTimer(usr.GuildId, usr.Id);
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(usr.Guild.Id,
|
||||
set => set.Include(gc => gc.MutedUsers)
|
||||
.Include(gc => gc.UnmuteTimers));
|
||||
config.MutedUsers.Add(new MutedUserId()
|
||||
{
|
||||
UserId = usr.Id
|
||||
});
|
||||
if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
|
||||
muted.Add(usr.Id);
|
||||
|
||||
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
UserMuted(usr, MuteType.All);
|
||||
}
|
||||
else if (type == MuteType.Voice)
|
||||
{
|
||||
await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
|
||||
UserMuted(usr, MuteType.Voice);
|
||||
}
|
||||
else if (type == MuteType.Chat)
|
||||
{
|
||||
await usr.AddRoleAsync(await GetMuteRole(usr.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
UserMuted(usr, MuteType.Chat);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UnmuteUser(IGuildUser usr, MuteType type = MuteType.All)
|
||||
{
|
||||
if (type == MuteType.All)
|
||||
{
|
||||
StopUnmuteTimer(usr.GuildId, usr.Id);
|
||||
try { await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false); } catch { }
|
||||
try { await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false); } catch { /*ignore*/ }
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(usr.Guild.Id, set => set.Include(gc => gc.MutedUsers)
|
||||
.Include(gc => gc.UnmuteTimers));
|
||||
config.MutedUsers.Remove(new MutedUserId()
|
||||
{
|
||||
UserId = usr.Id
|
||||
});
|
||||
if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
|
||||
muted.TryRemove(usr.Id);
|
||||
|
||||
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
UserUnmuted(usr, MuteType.All);
|
||||
}
|
||||
else if (type == MuteType.Voice)
|
||||
{
|
||||
await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false);
|
||||
UserUnmuted(usr, MuteType.Voice);
|
||||
}
|
||||
else if (type == MuteType.Chat)
|
||||
{
|
||||
await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
UserUnmuted(usr, MuteType.Chat);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IRole> GetMuteRole(IGuild guild)
|
||||
{
|
||||
const string defaultMuteRoleName = "nadeko-mute";
|
||||
|
||||
var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName);
|
||||
|
||||
var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
|
||||
if (muteRole == null)
|
||||
{
|
||||
|
||||
//if it doesn't exist, create it
|
||||
try { muteRole = await guild.CreateRoleAsync(muteRoleName, GuildPermissions.None).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
//if creations fails, maybe the name is not correct, find default one, if doesn't work, create default one
|
||||
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) ??
|
||||
await guild.CreateRoleAsync(defaultMuteRoleName, GuildPermissions.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var toOverwrite in (await guild.GetTextChannelsAsync()))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!toOverwrite.PermissionOverwrites.Select(x => x.Permissions).Contains(denyOverwrite))
|
||||
{
|
||||
await toOverwrite.AddPermissionOverwriteAsync(muteRole, denyOverwrite)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(200).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
return muteRole;
|
||||
}
|
||||
|
||||
public async Task TimedMute(IGuildUser user, TimeSpan after)
|
||||
{
|
||||
await MuteUser(user).ConfigureAwait(false); // mute the user. This will also remove any previous unmute timers
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(user.GuildId, set => set.Include(x => x.UnmuteTimers));
|
||||
config.UnmuteTimers.Add(new UnmuteTimer()
|
||||
{
|
||||
UserId = user.Id,
|
||||
UnmuteAt = DateTime.UtcNow + after,
|
||||
}); // add teh unmute timer to the database
|
||||
uow.Complete();
|
||||
}
|
||||
StartUnmuteTimer(user.GuildId, user.Id, after); // start the timer
|
||||
}
|
||||
|
||||
public void StartUnmuteTimer(ulong guildId, ulong userId, TimeSpan after)
|
||||
{
|
||||
//load the unmute timers for this guild
|
||||
var userUnmuteTimers = UnmuteTimers.GetOrAdd(guildId, new ConcurrentDictionary<ulong, Timer>());
|
||||
|
||||
//unmute timer to be added
|
||||
var toAdd = new Timer(async _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _client.GetGuild(guildId); // load the guild
|
||||
if (guild == null)
|
||||
{
|
||||
RemoveUnmuteTimerFromDb(guildId, userId);
|
||||
return; // if guild can't be found, just remove the timer from db
|
||||
}
|
||||
// unmute the user, this will also remove the timer from the db
|
||||
await UnmuteUser(guild.GetUser(userId)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RemoveUnmuteTimerFromDb(guildId, userId); // if unmute errored, just remove unmute from db
|
||||
_log.Warn("Couldn't unmute user {0} in guild {1}", userId, guildId);
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}, null, after, Timeout.InfiniteTimeSpan);
|
||||
|
||||
//add it, or stop the old one and add this one
|
||||
userUnmuteTimers.AddOrUpdate(userId, (key) => toAdd, (key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return toAdd;
|
||||
});
|
||||
}
|
||||
|
||||
public void StopUnmuteTimer(ulong guildId, ulong userId)
|
||||
{
|
||||
if (!UnmuteTimers.TryGetValue(guildId, out ConcurrentDictionary<ulong, Timer> userUnmuteTimers)) return;
|
||||
|
||||
if (userUnmuteTimers.TryRemove(userId, out Timer removed))
|
||||
{
|
||||
removed.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveUnmuteTimerFromDb(ulong guildId, ulong userId)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(guildId, set => set.Include(x => x.UnmuteTimers));
|
||||
config.UnmuteTimers.RemoveWhere(x => x.UserId == userId);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Replacements;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class PlayingRotateService : INService
|
||||
{
|
||||
private readonly Timer _t;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly Logger _log;
|
||||
private readonly IDataCache _cache;
|
||||
private readonly Replacer _rep;
|
||||
private readonly DbService _db;
|
||||
private readonly IBotConfigProvider _bcp;
|
||||
|
||||
public BotConfig BotConfig => _bcp.BotConfig;
|
||||
|
||||
private class TimerState
|
||||
{
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
public PlayingRotateService(DiscordSocketClient client, IBotConfigProvider bcp,
|
||||
DbService db, IDataCache cache, NadekoBot bot)
|
||||
{
|
||||
_client = client;
|
||||
_bcp = bcp;
|
||||
_db = db;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_cache = cache;
|
||||
|
||||
if (client.ShardId == 0)
|
||||
{
|
||||
|
||||
_rep = new ReplacementBuilder()
|
||||
.WithClient(client)
|
||||
.WithStats(client)
|
||||
//todo type readers
|
||||
//.WithMusic(music)
|
||||
.Build();
|
||||
|
||||
_t = new Timer(async (objState) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
bcp.Reload();
|
||||
|
||||
var state = (TimerState)objState;
|
||||
if (!BotConfig.RotatingStatuses)
|
||||
return;
|
||||
if (state.Index >= BotConfig.RotatingStatusMessages.Count)
|
||||
state.Index = 0;
|
||||
|
||||
if (!BotConfig.RotatingStatusMessages.Any())
|
||||
return;
|
||||
var status = BotConfig.RotatingStatusMessages[state.Index++].Status;
|
||||
if (string.IsNullOrWhiteSpace(status))
|
||||
return;
|
||||
|
||||
status = _rep.Replace(status);
|
||||
|
||||
try
|
||||
{
|
||||
await bot.SetGameAsync(status).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Rotating playing status errored.\n" + ex);
|
||||
}
|
||||
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class ProtectionService : INService
|
||||
{
|
||||
public readonly ConcurrentDictionary<ulong, AntiRaidStats> AntiRaidGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiRaidStats>();
|
||||
// guildId | (userId|messages)
|
||||
public readonly ConcurrentDictionary<ulong, AntiSpamStats> AntiSpamGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiSpamStats>();
|
||||
|
||||
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate { return Task.CompletedTask; };
|
||||
|
||||
private readonly Logger _log;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly MuteService _mute;
|
||||
|
||||
public ProtectionService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, MuteService mute)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
_mute = mute;
|
||||
|
||||
foreach (var gc in gcs)
|
||||
{
|
||||
var raid = gc.AntiRaidSetting;
|
||||
var spam = gc.AntiSpamSetting;
|
||||
|
||||
if (raid != null)
|
||||
{
|
||||
var raidStats = new AntiRaidStats() { AntiRaidSettings = raid };
|
||||
AntiRaidGuilds.TryAdd(gc.GuildId, raidStats);
|
||||
}
|
||||
|
||||
if (spam != null)
|
||||
AntiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
||||
}
|
||||
|
||||
_client.MessageReceived += (imsg) =>
|
||||
{
|
||||
var msg = imsg as IUserMessage;
|
||||
if (msg == null || msg.Author.IsBot)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var channel = msg.Channel as ITextChannel;
|
||||
if (channel == null)
|
||||
return Task.CompletedTask;
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!AntiSpamGuilds.TryGetValue(channel.Guild.Id, out var spamSettings) ||
|
||||
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
}))
|
||||
return;
|
||||
|
||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, (id) => new UserSpamStats(msg),
|
||||
(id, old) =>
|
||||
{
|
||||
old.ApplyNextMessage(msg); return old;
|
||||
});
|
||||
|
||||
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
||||
{
|
||||
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
|
||||
{
|
||||
stats.Dispose();
|
||||
await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, spamSettings.AntiSpamSettings.MuteTime, (IGuildUser)msg.Author)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
_client.UserJoined += (usr) =>
|
||||
{
|
||||
if (usr.IsBot)
|
||||
return Task.CompletedTask;
|
||||
if (!AntiRaidGuilds.TryGetValue(usr.Guild.Id, out var settings))
|
||||
return Task.CompletedTask;
|
||||
if (!settings.RaidUsers.Add(usr))
|
||||
return Task.CompletedTask;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
++settings.UsersCount;
|
||||
|
||||
if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold)
|
||||
{
|
||||
var users = settings.RaidUsers.ToArray();
|
||||
settings.RaidUsers.Clear();
|
||||
|
||||
await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, 0, users).ConfigureAwait(false);
|
||||
}
|
||||
await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false);
|
||||
|
||||
settings.RaidUsers.TryRemove(usr);
|
||||
--settings.UsersCount;
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private async Task PunishUsers(PunishmentAction action, ProtectionType pt, int muteTime, params IGuildUser[] gus)
|
||||
{
|
||||
_log.Info($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild");
|
||||
foreach (var gu in gus)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case PunishmentAction.Mute:
|
||||
try
|
||||
{
|
||||
if (muteTime <= 0)
|
||||
await _mute.MuteUser(gu).ConfigureAwait(false);
|
||||
else
|
||||
await _mute.TimedMute(gu, TimeSpan.FromSeconds(muteTime)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||
break;
|
||||
case PunishmentAction.Kick:
|
||||
try
|
||||
{
|
||||
await gu.KickAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||
break;
|
||||
case PunishmentAction.Softban:
|
||||
try
|
||||
{
|
||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||
// try it twice, really don't want to ban user if
|
||||
// only kick has been specified as the punishement
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||
break;
|
||||
case PunishmentAction.Ban:
|
||||
try
|
||||
{
|
||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
await OnAntiProtectionTriggered(action, pt, gus).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class PruneService : INService
|
||||
{
|
||||
//channelids where prunes are currently occuring
|
||||
private ConcurrentHashSet<ulong> _pruningGuilds = new ConcurrentHashSet<ulong>();
|
||||
private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
|
||||
|
||||
public async Task PruneWhere(ITextChannel channel, int amount, Func<IMessage, bool> predicate)
|
||||
{
|
||||
channel.ThrowIfNull(nameof(channel));
|
||||
if (amount <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(amount));
|
||||
|
||||
if (!_pruningGuilds.Add(channel.GuildId))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
IMessage[] msgs;
|
||||
IMessage lastMessage = null;
|
||||
msgs = (await channel.GetMessagesAsync(50).Flatten()).Where(predicate).Take(amount).ToArray();
|
||||
while (amount > 0 && msgs.Any())
|
||||
{
|
||||
lastMessage = msgs[msgs.Length - 1];
|
||||
|
||||
var bulkDeletable = new List<IMessage>();
|
||||
var singleDeletable = new List<IMessage>();
|
||||
foreach (var x in msgs)
|
||||
{
|
||||
if (DateTime.UtcNow - x.CreatedAt < twoWeeks)
|
||||
bulkDeletable.Add(x);
|
||||
else
|
||||
singleDeletable.Add(x);
|
||||
}
|
||||
|
||||
if (bulkDeletable.Count > 0)
|
||||
await Task.WhenAll(Task.Delay(1000), channel.DeleteMessagesAsync(bulkDeletable)).ConfigureAwait(false);
|
||||
|
||||
var i = 0;
|
||||
foreach (var group in singleDeletable.GroupBy(x => ++i / (singleDeletable.Count / 5)))
|
||||
await Task.WhenAll(Task.Delay(1000), Task.WhenAll(group.Select(x => x.DeleteAsync()))).ConfigureAwait(false);
|
||||
|
||||
//this isn't good, because this still work as if i want to remove only specific user's messages from the last
|
||||
//100 messages, Maybe this needs to be reduced by msgs.Length instead of 100
|
||||
amount -= 50;
|
||||
if(amount > 0)
|
||||
msgs = (await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).Flatten()).Where(predicate).Take(amount).ToArray();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
finally
|
||||
{
|
||||
_pruningGuilds.TryRemove(channel.GuildId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class SlowmodeService : IEarlyBlocker, INService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>();
|
||||
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||
|
||||
private readonly Logger _log;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public SlowmodeService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
|
||||
IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
||||
gcs.ToDictionary(x => x.GuildId,
|
||||
x => new HashSet<ulong>(x.SlowmodeIgnoredRoles.Select(y => y.RoleId))));
|
||||
|
||||
IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
||||
gcs.ToDictionary(x => x.GuildId,
|
||||
x => new HashSet<ulong>(x.SlowmodeIgnoredUsers.Select(y => y.UserId))));
|
||||
}
|
||||
|
||||
public async Task<bool> TryBlockEarly(IGuild guild, IUserMessage usrMsg)
|
||||
{
|
||||
if (guild == null)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
var channel = usrMsg?.Channel as SocketTextChannel;
|
||||
|
||||
if (channel == null || usrMsg == null || usrMsg.IsAuthor(_client))
|
||||
return false;
|
||||
if (!RatelimitingChannels.TryGetValue(channel.Id, out Ratelimiter limiter))
|
||||
return false;
|
||||
|
||||
if (limiter.CheckUserRatelimit(usrMsg.Author.Id, channel.Guild.Id, usrMsg.Author as SocketGuildUser))
|
||||
{
|
||||
await usrMsg.DeleteAsync();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
161
NadekoBot.Core/Modules/Administration/Services/SelfService.cs
Normal file
161
NadekoBot.Core/Modules/Administration/Services/SelfService.cs
Normal file
@ -0,0 +1,161 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Impl;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class SelfService : ILateExecutor, INService
|
||||
{
|
||||
public bool ForwardDMs => _bc.BotConfig.ForwardMessages;
|
||||
public bool ForwardDMsToAllOwners => _bc.BotConfig.ForwardToAllOwners;
|
||||
|
||||
private readonly NadekoBot _bot;
|
||||
private readonly CommandHandler _cmdHandler;
|
||||
private readonly DbService _db;
|
||||
private readonly Logger _log;
|
||||
private readonly ILocalization _localization;
|
||||
private readonly NadekoStrings _strings;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotCredentials _creds;
|
||||
private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels = new ImmutableArray<AsyncLazy<IDMChannel>>();
|
||||
private readonly IBotConfigProvider _bc;
|
||||
|
||||
public SelfService(DiscordSocketClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db,
|
||||
IBotConfigProvider bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds)
|
||||
{
|
||||
_bot = bot;
|
||||
_cmdHandler = cmdHandler;
|
||||
_db = db;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_localization = localization;
|
||||
_strings = strings;
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
_bc = bc;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
await bot.Ready.Task.ConfigureAwait(false);
|
||||
|
||||
foreach (var cmd in bc.BotConfig.StartupCommands)
|
||||
{
|
||||
await cmdHandler.ExecuteExternal(cmd.GuildId, cmd.ChannelId, cmd.CommandText);
|
||||
await Task.Delay(400).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
var ___ = Task.Run(async () =>
|
||||
{
|
||||
await bot.Ready.Task.ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(5000);
|
||||
|
||||
_client.Guilds.SelectMany(g => g.Users);
|
||||
|
||||
if(client.ShardId == 0)
|
||||
LoadOwnerChannels();
|
||||
});
|
||||
}
|
||||
|
||||
private void LoadOwnerChannels()
|
||||
{
|
||||
var hs = new HashSet<ulong>(_creds.OwnerIds);
|
||||
var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
|
||||
|
||||
if (hs.Count > 0)
|
||||
{
|
||||
foreach (var g in _client.Guilds)
|
||||
{
|
||||
if (hs.Count == 0)
|
||||
break;
|
||||
|
||||
foreach (var u in g.Users)
|
||||
{
|
||||
if (hs.Remove(u.Id))
|
||||
{
|
||||
channels.Add(u.Id, new AsyncLazy<IDMChannel>(async () => await u.GetOrCreateDMChannelAsync()));
|
||||
if (hs.Count == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key))
|
||||
.Select(x => x.Value)
|
||||
.ToImmutableArray();
|
||||
|
||||
if (!ownerChannels.Any())
|
||||
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
||||
else
|
||||
_log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels.");
|
||||
}
|
||||
|
||||
// forwards dms
|
||||
public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg)
|
||||
{
|
||||
if (msg.Channel is IDMChannel && ForwardDMs && ownerChannels.Length > 0)
|
||||
{
|
||||
var title = _strings.GetText("dm_from",
|
||||
_localization.DefaultCultureInfo,
|
||||
"Administration".ToLowerInvariant()) +
|
||||
$" [{msg.Author}]({msg.Author.Id})";
|
||||
|
||||
var attachamentsTxt = _strings.GetText("attachments",
|
||||
_localization.DefaultCultureInfo,
|
||||
"Administration".ToLowerInvariant());
|
||||
|
||||
var toSend = msg.Content;
|
||||
|
||||
if (msg.Attachments.Count > 0)
|
||||
{
|
||||
toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n" +
|
||||
string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl));
|
||||
}
|
||||
|
||||
if (ForwardDMsToAllOwners)
|
||||
{
|
||||
var allOwnerChannels = await Task.WhenAll(ownerChannels
|
||||
.Select(x => x.Value))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (var ownerCh in allOwnerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id))
|
||||
{
|
||||
try
|
||||
{
|
||||
await ownerCh.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn("Can't contact owner with id {0}", ownerCh.Recipient.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstOwnerChannel = await ownerChannels[0];
|
||||
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class UserPunishService : INService
|
||||
{
|
||||
private readonly MuteService _mute;
|
||||
private readonly DbService _db;
|
||||
|
||||
public UserPunishService(MuteService mute, DbService db)
|
||||
{
|
||||
_mute = mute;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<PunishmentAction?> Warn(IGuild guild, ulong userId, string modName, string reason)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(reason))
|
||||
reason = "-";
|
||||
|
||||
var guildId = guild.Id;
|
||||
|
||||
var warn = new Warning()
|
||||
{
|
||||
UserId = userId,
|
||||
GuildId = guildId,
|
||||
Forgiven = false,
|
||||
Reason = reason,
|
||||
Moderator = modName,
|
||||
};
|
||||
|
||||
int warnings = 1;
|
||||
List<WarningPunishment> ps;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments))
|
||||
.WarnPunishments;
|
||||
|
||||
warnings += uow.Warnings
|
||||
.For(guildId, userId)
|
||||
.Where(w => !w.Forgiven && w.UserId == userId)
|
||||
.Count();
|
||||
|
||||
uow.Warnings.Add(warn);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
var p = ps.FirstOrDefault(x => x.Count == warnings);
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
var user = await guild.GetUserAsync(userId);
|
||||
if (user == null)
|
||||
return null;
|
||||
switch (p.Punishment)
|
||||
{
|
||||
case PunishmentAction.Mute:
|
||||
if (p.Time == 0)
|
||||
await _mute.MuteUser(user).ConfigureAwait(false);
|
||||
else
|
||||
await _mute.TimedMute(user, TimeSpan.FromMinutes(p.Time)).ConfigureAwait(false);
|
||||
break;
|
||||
case PunishmentAction.Kick:
|
||||
await user.KickAsync().ConfigureAwait(false);
|
||||
break;
|
||||
case PunishmentAction.Ban:
|
||||
await guild.AddBanAsync(user).ConfigureAwait(false);
|
||||
break;
|
||||
case PunishmentAction.Softban:
|
||||
await guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await guild.RemoveBanAsync(user).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await guild.RemoveBanAsync(user).ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return p.Punishment;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
119
NadekoBot.Core/Modules/Administration/Services/VcRoleService.cs
Normal file
119
NadekoBot.Core/Modules/Administration/Services/VcRoleService.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class VcRoleService : INService
|
||||
{
|
||||
private readonly Logger _log;
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
|
||||
|
||||
public VcRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
_client = client;
|
||||
|
||||
_client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated;
|
||||
VcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>();
|
||||
var missingRoles = new List<VcRoleInfo>();
|
||||
foreach (var gconf in gcs)
|
||||
{
|
||||
var g = _client.GetGuild(gconf.GuildId);
|
||||
if (g == null)
|
||||
continue;
|
||||
|
||||
var infos = new ConcurrentDictionary<ulong, IRole>();
|
||||
VcRoles.TryAdd(gconf.GuildId, infos);
|
||||
foreach (var ri in gconf.VcRoleInfos)
|
||||
{
|
||||
var role = g.GetRole(ri.RoleId);
|
||||
if (role == null)
|
||||
{
|
||||
missingRoles.Add(ri);
|
||||
continue;
|
||||
}
|
||||
|
||||
infos.TryAdd(ri.VoiceChannelId, role);
|
||||
}
|
||||
}
|
||||
if(missingRoles.Any())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
_log.Warn($"Removing {missingRoles.Count} missing roles from {nameof(VcRoleService)}");
|
||||
uow._context.RemoveRange(missingRoles);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState,
|
||||
SocketVoiceState newState)
|
||||
{
|
||||
|
||||
var gusr = usr as SocketGuildUser;
|
||||
if (gusr == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var oldVc = oldState.VoiceChannel;
|
||||
var newVc = newState.VoiceChannel;
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (oldVc != newVc)
|
||||
{
|
||||
ulong guildId;
|
||||
guildId = newVc?.Guild.Id ?? oldVc.Guild.Id;
|
||||
|
||||
if (VcRoles.TryGetValue(guildId, out ConcurrentDictionary<ulong, IRole> guildVcRoles))
|
||||
{
|
||||
//remove old
|
||||
if (oldVc != null && guildVcRoles.TryGetValue(oldVc.Id, out IRole role))
|
||||
{
|
||||
try
|
||||
{
|
||||
await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
//add new
|
||||
if (newVc != null && guildVcRoles.TryGetValue(newVc.Id, out role))
|
||||
{
|
||||
if (!gusr.Roles.Contains(role))
|
||||
{
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
await gusr.AddRoleAsync(role).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
154
NadekoBot.Core/Modules/Administration/Services/VplusTService.cs
Normal file
154
NadekoBot.Core/Modules/Administration/Services/VplusTService.cs
Normal file
@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Services.Impl;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
public class VplusTService : INService
|
||||
{
|
||||
private readonly Regex _channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
||||
|
||||
public readonly ConcurrentHashSet<ulong> VoicePlusTextCache;
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly NadekoStrings _strings;
|
||||
private readonly DbService _db;
|
||||
private readonly Logger _log;
|
||||
|
||||
public VplusTService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings,
|
||||
DbService db)
|
||||
{
|
||||
_client = client;
|
||||
_strings = strings;
|
||||
_db = db;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
VoicePlusTextCache = new ConcurrentHashSet<ulong>(gcs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId));
|
||||
_client.UserVoiceStateUpdated += UserUpdatedEventHandler;
|
||||
}
|
||||
|
||||
private Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after)
|
||||
{
|
||||
var user = (iuser as SocketGuildUser);
|
||||
var guild = user?.Guild;
|
||||
|
||||
if (guild == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var botUserPerms = guild.CurrentUser.GuildPermissions;
|
||||
|
||||
if (before.VoiceChannel == after.VoiceChannel)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (!VoicePlusTextCache.Contains(guild.Id))
|
||||
return Task.CompletedTask;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles)
|
||||
{
|
||||
try
|
||||
{
|
||||
await guild.Owner.SendErrorAsync(
|
||||
_strings.GetText("vt_exit",
|
||||
guild.Id,
|
||||
"Administration".ToLowerInvariant(),
|
||||
Format.Bold(guild.Name))).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false;
|
||||
VoicePlusTextCache.TryRemove(guild.Id);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var semaphore = _guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1));
|
||||
|
||||
try
|
||||
{
|
||||
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
var beforeVch = before.VoiceChannel;
|
||||
if (beforeVch != null)
|
||||
{
|
||||
var beforeRoleName = GetRoleName(beforeVch);
|
||||
var beforeRole = guild.Roles.FirstOrDefault(x => x.Name == beforeRoleName);
|
||||
if (beforeRole != null)
|
||||
{
|
||||
_log.Info("Removing role " + beforeRoleName + " from user " + user.Username);
|
||||
await user.RemoveRoleAsync(beforeRole).ConfigureAwait(false);
|
||||
await Task.Delay(200).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
var afterVch = after.VoiceChannel;
|
||||
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
|
||||
{
|
||||
var roleName = GetRoleName(afterVch);
|
||||
var roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName) ??
|
||||
(IRole)await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false);
|
||||
|
||||
ITextChannel textChannel = guild.TextChannels
|
||||
.FirstOrDefault(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant());
|
||||
if (textChannel == null)
|
||||
{
|
||||
var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
|
||||
|
||||
try { await guild.CurrentUser.AddRoleAsync(roleToAdd).ConfigureAwait(false); } catch {/*ignored*/}
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions(
|
||||
readMessages: PermValue.Allow,
|
||||
sendMessages: PermValue.Allow))
|
||||
.ConfigureAwait(false);
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
await created.AddPermissionOverwriteAsync(guild.EveryoneRole, new OverwritePermissions(
|
||||
readMessages: PermValue.Deny,
|
||||
sendMessages: PermValue.Deny))
|
||||
.ConfigureAwait(false);
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
}
|
||||
_log.Info("Adding role " + roleToAdd.Name + " to user " + user.Username);
|
||||
await user.AddRoleAsync(roleToAdd).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string GetChannelName(string voiceName) =>
|
||||
_channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
||||
|
||||
public string GetRoleName(IVoiceChannel ch) =>
|
||||
"nvoice-" + ch.Id;
|
||||
}
|
||||
}
|
65
NadekoBot.Core/Modules/Administration/TimeZoneCommands.cs
Normal file
65
NadekoBot.Core/Modules/Administration/TimeZoneCommands.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class TimeZoneCommands : NadekoSubmodule<GuildTimezoneService>
|
||||
{
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Timezones(int page = 1)
|
||||
{
|
||||
page--;
|
||||
|
||||
if (page < 0 || page > 20)
|
||||
return;
|
||||
|
||||
var timezones = TimeZoneInfo.GetSystemTimeZones()
|
||||
.OrderBy(x => x.BaseUtcOffset)
|
||||
.ToArray();
|
||||
var timezonesPerPage = 20;
|
||||
|
||||
await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page,
|
||||
(curPage) => new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText("timezones_available"))
|
||||
.WithDescription(string.Join("\n", timezones.Skip(curPage * timezonesPerPage).Take(timezonesPerPage).Select(x => $"`{x.Id,-25}` {(x.BaseUtcOffset < TimeSpan.Zero? "-" : "+")}{x.BaseUtcOffset:hhmm}"))),
|
||||
timezones.Length / timezonesPerPage);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Timezone([Remainder] string id = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
await ReplyConfirmLocalized("timezone_guild", _service.GetTimeZoneOrUtc(Context.Guild.Id)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
TimeZoneInfo tz;
|
||||
try { tz = TimeZoneInfo.FindSystemTimeZoneById(id); } catch { tz = null; }
|
||||
|
||||
_service.SetTimeZone(Context.Guild.Id, tz);
|
||||
|
||||
if (tz == null)
|
||||
{
|
||||
await ReplyErrorLocalized("timezone_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync(tz.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
397
NadekoBot.Core/Modules/Administration/UserPunishCommands.cs
Normal file
397
NadekoBot.Core/Modules/Administration/UserPunishCommands.cs
Normal file
@ -0,0 +1,397 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class UserPunishCommands : NadekoSubmodule<UserPunishService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public UserPunishCommands(DbService db, MuteService muteService)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
public async Task Warn(IGuildUser user, [Remainder] string reason = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await (await user.GetOrCreateDMChannelAsync()).EmbedAsync(new EmbedBuilder().WithErrorColor()
|
||||
.WithDescription(GetText("warned_on", Context.Guild.ToString()))
|
||||
.AddField(efb => efb.WithName(GetText("moderator")).WithValue(Context.User.ToString()))
|
||||
.AddField(efb => efb.WithName(GetText("reason")).WithValue(reason ?? "-")))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
var punishment = await _service.Warn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false);
|
||||
|
||||
if (punishment == null)
|
||||
{
|
||||
await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalized("user_warned_and_punished", Format.Bold(user.ToString()), Format.Bold(punishment.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
[Priority(2)]
|
||||
public Task Warnlog(int page, IGuildUser user)
|
||||
=> Warnlog(page, user.Id);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[Priority(3)]
|
||||
public Task Warnlog(IGuildUser user)
|
||||
=> Context.User.Id == user.Id || ((IGuildUser)Context.User).GuildPermissions.BanMembers ? Warnlog(user.Id) : Task.CompletedTask;
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
[Priority(0)]
|
||||
public Task Warnlog(int page, ulong userId)
|
||||
=> InternalWarnlog(userId, page - 1);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
[Priority(1)]
|
||||
public Task Warnlog(ulong userId)
|
||||
=> InternalWarnlog(userId, 0);
|
||||
|
||||
private async Task InternalWarnlog(ulong userId, int page)
|
||||
{
|
||||
if (page < 0)
|
||||
return;
|
||||
Warning[] warnings;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
warnings = uow.Warnings.For(Context.Guild.Id, userId);
|
||||
}
|
||||
|
||||
warnings = warnings.Skip(page * 9)
|
||||
.Take(9)
|
||||
.ToArray();
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("warnlog_for", (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()))
|
||||
.WithFooter(efb => efb.WithText(GetText("page", page + 1)));
|
||||
|
||||
if (!warnings.Any())
|
||||
{
|
||||
embed.WithDescription(GetText("warnings_none"));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var w in warnings)
|
||||
{
|
||||
var name = GetText("warned_on_by", w.DateAdded.Value.ToString("dd.MM.yyy"), w.DateAdded.Value.ToString("HH:mm"), w.Moderator);
|
||||
if (w.Forgiven)
|
||||
name = Format.Strikethrough(name) + " " + GetText("warn_cleared_by", w.ForgivenBy);
|
||||
|
||||
embed.AddField(x => x
|
||||
.WithName(name)
|
||||
.WithValue(w.Reason));
|
||||
}
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
public async Task WarnlogAll(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
IGrouping<ulong, Warning>[] warnings;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
warnings = uow.Warnings.GetForGuild(Context.Guild.Id).GroupBy(x => x.UserId).ToArray();
|
||||
}
|
||||
|
||||
await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, async (curPage) =>
|
||||
{
|
||||
var ws = await Task.WhenAll(warnings.Skip(curPage * 15)
|
||||
.Take(15)
|
||||
.ToArray()
|
||||
.Select(async x =>
|
||||
{
|
||||
var all = x.Count();
|
||||
var forgiven = x.Count(y => y.Forgiven);
|
||||
var total = all - forgiven;
|
||||
return ((await Context.Guild.GetUserAsync(x.Key))?.ToString() ?? x.Key.ToString()) + $" | {total} ({all} - {forgiven})";
|
||||
}));
|
||||
|
||||
return new EmbedBuilder()
|
||||
.WithTitle(GetText("warnings_list"))
|
||||
.WithDescription(string.Join("\n", ws));
|
||||
|
||||
}, warnings.Length / 15);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
public Task Warnclear(IGuildUser user)
|
||||
=> Warnclear(user.Id);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
public async Task Warnclear(ulong userId)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
await uow.Warnings.ForgiveAll(Context.Guild.Id, userId, Context.User.ToString()).ConfigureAwait(false);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("warnings_cleared",
|
||||
Format.Bold((Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
public async Task WarnPunish(int number, PunishmentAction punish, int time = 0)
|
||||
{
|
||||
if (punish != PunishmentAction.Mute && time != 0)
|
||||
return;
|
||||
if (number <= 0)
|
||||
return;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||
ps.RemoveAll(x => x.Count == number);
|
||||
|
||||
ps.Add(new WarningPunishment()
|
||||
{
|
||||
Count = number,
|
||||
Punishment = punish,
|
||||
Time = time,
|
||||
});
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("warn_punish_set",
|
||||
Format.Bold(punish.ToString()),
|
||||
Format.Bold(number.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
public async Task WarnPunish(int number)
|
||||
{
|
||||
if (number <= 0)
|
||||
return;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||
var p = ps.FirstOrDefault(x => x.Count == number);
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
uow._context.Remove(p);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("warn_punish_rem",
|
||||
Format.Bold(number.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task WarnPunishList()
|
||||
{
|
||||
WarningPunishment[] ps;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
ps = uow.GuildConfigs.For(Context.Guild.Id, gc => gc.Include(x => x.WarnPunishments))
|
||||
.WarnPunishments
|
||||
.OrderBy(x => x.Count)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
string list;
|
||||
if (ps.Any())
|
||||
{
|
||||
list = string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
list = GetText("warnpl_none");
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync(
|
||||
GetText("warn_punish_list"),
|
||||
list).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||
public async Task Ban(IGuildUser user, [Remainder] string msg = null)
|
||||
{
|
||||
if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()))
|
||||
{
|
||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
try
|
||||
{
|
||||
await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText("banned_user"))
|
||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||
public async Task Unban([Remainder]string user)
|
||||
{
|
||||
var bans = await Context.Guild.GetBansAsync();
|
||||
|
||||
var bun = bans.FirstOrDefault(x => x.User.ToString().ToLowerInvariant() == user.ToLowerInvariant());
|
||||
|
||||
if (bun == null)
|
||||
{
|
||||
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await UnbanInternal(bun.User).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||
public async Task Unban(ulong userId)
|
||||
{
|
||||
var bans = await Context.Guild.GetBansAsync();
|
||||
|
||||
var bun = bans.FirstOrDefault(x => x.User.Id == userId);
|
||||
|
||||
if (bun == null)
|
||||
{
|
||||
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await UnbanInternal(bun.User).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task UnbanInternal(IUser user)
|
||||
{
|
||||
await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("unbanned_user", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||
public async Task Softban(IGuildUser user, [Remainder] string msg = null)
|
||||
{
|
||||
if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
||||
{
|
||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
try
|
||||
{
|
||||
await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
||||
catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("☣ " + GetText("sb_user"))
|
||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireBotPermission(GuildPermission.KickMembers)]
|
||||
public async Task Kick(IGuildUser user, [Remainder] string msg = null)
|
||||
{
|
||||
if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
||||
{
|
||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
try
|
||||
{
|
||||
await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
await user.KickAsync().ConfigureAwait(false);
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("kicked_user"))
|
||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
NadekoBot.Core/Modules/Administration/VcRoleCommands.cs
Normal file
108
NadekoBot.Core/Modules/Administration/VcRoleCommands.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class VcRoleCommands : NadekoSubmodule<VcRoleService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public VcRoleCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
//todo 999 discord.net [RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task VcRole([Remainder]IRole role = null)
|
||||
{
|
||||
var user = (IGuildUser) Context.User;
|
||||
|
||||
var vc = user.VoiceChannel;
|
||||
|
||||
if (vc == null || vc.GuildId != user.GuildId)
|
||||
{
|
||||
await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var guildVcRoles = _service.VcRoles.GetOrAdd(user.GuildId, new ConcurrentDictionary<ulong, IRole>());
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
if (guildVcRoles.TryRemove(vc.Id, out role))
|
||||
{
|
||||
await ReplyConfirmLocalized("vcrole_removed", Format.Bold(vc.Name)).ConfigureAwait(false);
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
||||
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
guildVcRoles.AddOrUpdate(vc.Id, role, (key, old) => role);
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
||||
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id); // remove old one
|
||||
conf.VcRoleInfos.Add(new VcRoleInfo()
|
||||
{
|
||||
VoiceChannelId = vc.Id,
|
||||
RoleId = role.Id,
|
||||
}); // add new one
|
||||
uow.Complete();
|
||||
}
|
||||
await ReplyConfirmLocalized("vcrole_added", Format.Bold(vc.Name), Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task VcRoleList()
|
||||
{
|
||||
var guild = (SocketGuild) Context.Guild;
|
||||
string text;
|
||||
if (_service.VcRoles.TryGetValue(Context.Guild.Id, out ConcurrentDictionary<ulong, IRole> roles))
|
||||
{
|
||||
if (!roles.Any())
|
||||
{
|
||||
text = GetText("no_vcroles");
|
||||
}
|
||||
else
|
||||
{
|
||||
text = string.Join("\n", roles.Select(x =>
|
||||
$"{Format.Bold(guild.GetVoiceChannel(x.Key)?.Name ?? x.Key.ToString())} => {x.Value}"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text = GetText("no_vcroles");
|
||||
}
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("vc_role_list"))
|
||||
.WithDescription(text))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
NadekoBot.Core/Modules/Administration/VoicePlusTextCommands.cs
Normal file
131
NadekoBot.Core/Modules/Administration/VoicePlusTextCommands.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class VoicePlusTextCommands : NadekoSubmodule<VplusTService>
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public VoicePlusTextCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
public async Task VoicePlusText()
|
||||
{
|
||||
var guild = Context.Guild;
|
||||
|
||||
var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||
if (!botUser.GuildPermissions.ManageRoles || !botUser.GuildPermissions.ManageChannels)
|
||||
{
|
||||
await ReplyErrorLocalized("vt_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!botUser.GuildPermissions.Administrator)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ReplyErrorLocalized("vt_no_admin").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
bool isEnabled;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guild.Id, set => set);
|
||||
isEnabled = conf.VoicePlusTextEnabled = !conf.VoicePlusTextEnabled;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (!isEnabled)
|
||||
{
|
||||
_service.VoicePlusTextCache.TryRemove(guild.Id);
|
||||
foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice")))
|
||||
{
|
||||
try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
foreach (var role in guild.Roles.Where(c => c.Name.StartsWith("nvoice-")))
|
||||
{
|
||||
try { await role.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalized("vt_disabled").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
_service.VoicePlusTextCache.Add(guild.Id);
|
||||
await ReplyConfirmLocalized("vt_enabled").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync(ex.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
//[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task CleanVPlusT()
|
||||
{
|
||||
var guild = Context.Guild;
|
||||
var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||
if (!botUser.GuildPermissions.Administrator)
|
||||
{
|
||||
await ReplyErrorLocalized("need_admin").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var textChannels = await guild.GetTextChannelsAsync().ConfigureAwait(false);
|
||||
var voiceChannels = await guild.GetVoiceChannelsAsync().ConfigureAwait(false);
|
||||
|
||||
var boundTextChannels = textChannels.Where(c => c.Name.EndsWith("-voice"));
|
||||
var validTxtChannelNames = new HashSet<string>(voiceChannels.Select(c => _service.GetChannelName(c.Name).ToLowerInvariant()));
|
||||
var invalidTxtChannels = boundTextChannels.Where(c => !validTxtChannelNames.Contains(c.Name));
|
||||
|
||||
foreach (var c in invalidTxtChannels)
|
||||
{
|
||||
try { await c.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var boundRoles = guild.Roles.Where(r => r.Name.StartsWith("nvoice-"));
|
||||
var validRoleNames = new HashSet<string>(voiceChannels.Select(c => _service.GetRoleName(c).ToLowerInvariant()));
|
||||
var invalidRoles = boundRoles.Where(r => !validRoleNames.Contains(r.Name));
|
||||
|
||||
foreach (var r in invalidRoles)
|
||||
{
|
||||
try { await r.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("cleaned_up").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
173
NadekoBot.Core/Modules/Help/Help.cs
Normal file
173
NadekoBot.Core/Modules/Help/Help.cs
Normal file
@ -0,0 +1,173 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using System.Linq;
|
||||
using Discord;
|
||||
using NadekoBot.Services;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Modules.Help.Services;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Help
|
||||
{
|
||||
public class Help : NadekoTopLevelModule<HelpService>
|
||||
{
|
||||
public const string PatreonUrl = "https://patreon.com/nadekobot";
|
||||
public const string PaypalUrl = "https://paypal.me/Kwoth";
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IBotConfigProvider _config;
|
||||
private readonly CommandService _cmds;
|
||||
private readonly GlobalPermissionService _perms;
|
||||
|
||||
public string HelpString => String.Format(_config.BotConfig.HelpString, _creds.ClientId, Prefix);
|
||||
public string DMHelpString => _config.BotConfig.DMHelpString;
|
||||
|
||||
public Help(IBotCredentials creds, GlobalPermissionService perms, IBotConfigProvider config, CommandService cmds)
|
||||
{
|
||||
_creds = creds;
|
||||
_config = config;
|
||||
_cmds = cmds;
|
||||
_perms = perms;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Modules()
|
||||
{
|
||||
var embed = new EmbedBuilder().WithOkColor()
|
||||
.WithFooter(efb => efb.WithText("ℹ️" + GetText("modules_footer", Prefix)))
|
||||
.WithTitle(GetText("list_of_modules"))
|
||||
.WithDescription(string.Join("\n",
|
||||
_cmds.Modules.GroupBy(m => m.GetTopLevelModule())
|
||||
.Where(m => !_perms.BlockedModules.Contains(m.Key.Name.ToLowerInvariant()))
|
||||
.Select(m => "• " + m.Key.Name)
|
||||
.OrderBy(s => s)));
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Commands([Remainder] string module = null)
|
||||
{
|
||||
var channel = Context.Channel;
|
||||
|
||||
module = module?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(module))
|
||||
return;
|
||||
var cmds = _cmds.Commands.Where(c => c.Module.GetTopLevelModule().Name.ToUpperInvariant().StartsWith(module))
|
||||
.Where(c => !_perms.BlockedCommands.Contains(c.Aliases.First().ToLowerInvariant()))
|
||||
.OrderBy(c => c.Aliases.First())
|
||||
.Distinct(new CommandTextEqualityComparer())
|
||||
.AsEnumerable();
|
||||
|
||||
var cmdsArray = cmds as CommandInfo[] ?? cmds.ToArray();
|
||||
if (!cmdsArray.Any())
|
||||
{
|
||||
await ReplyErrorLocalized("module_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var j = 0;
|
||||
var groups = cmdsArray.GroupBy(x => j++ / 48).ToArray();
|
||||
|
||||
for (int i = 0; i < groups.Count(); i++)
|
||||
{
|
||||
await channel.SendTableAsync(i == 0 ? $"📃 **{GetText("list_of_commands")}**\n" : "", groups.ElementAt(i), el => $"{Prefix + el.Aliases.First(),-15} {"[" + el.Aliases.Skip(1).FirstOrDefault() + "]",-8}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await ConfirmLocalized("commands_instr", Prefix).ConfigureAwait(false);
|
||||
}
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[Priority(0)]
|
||||
public async Task H([Remainder] string fail)
|
||||
{
|
||||
await ReplyErrorLocalized("command_not_found").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[Priority(1)]
|
||||
public async Task H([Remainder] CommandInfo com = null)
|
||||
{
|
||||
var channel = Context.Channel;
|
||||
|
||||
if (com == null)
|
||||
{
|
||||
IMessageChannel ch = channel is ITextChannel ? await ((IGuildUser)Context.User).GetOrCreateDMChannelAsync() : channel;
|
||||
await ch.SendMessageAsync(HelpString).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (com == null)
|
||||
//{
|
||||
// await ReplyErrorLocalized("command_not_found").ConfigureAwait(false);
|
||||
// return;
|
||||
//}
|
||||
|
||||
var embed = _service.GetCommandHelp(com, Context.Guild);
|
||||
await channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task Hgit()
|
||||
{
|
||||
var helpstr = new StringBuilder();
|
||||
helpstr.AppendLine(GetText("cmdlist_donate", PatreonUrl, PaypalUrl) + "\n");
|
||||
helpstr.AppendLine("##"+ GetText("table_of_contents"));
|
||||
helpstr.AppendLine(string.Join("\n", _cmds.Modules.Where(m => m.GetTopLevelModule().Name.ToLowerInvariant() != "help")
|
||||
.Select(m => m.GetTopLevelModule().Name)
|
||||
.Distinct()
|
||||
.OrderBy(m => m)
|
||||
.Prepend("Help")
|
||||
.Select(m => string.Format("- [{0}](#{1})", m, m.ToLowerInvariant()))));
|
||||
helpstr.AppendLine();
|
||||
string lastModule = null;
|
||||
foreach (var com in _cmds.Commands.OrderBy(com => com.Module.GetTopLevelModule().Name).GroupBy(c => c.Aliases.First()).Select(g => g.First()))
|
||||
{
|
||||
var module = com.Module.GetTopLevelModule();
|
||||
if (module.Name != lastModule)
|
||||
{
|
||||
if (lastModule != null)
|
||||
{
|
||||
helpstr.AppendLine();
|
||||
helpstr.AppendLine($"###### [{GetText("back_to_toc")}](#{GetText("table_of_contents").ToLowerInvariant().Replace(' ', '-')})");
|
||||
}
|
||||
helpstr.AppendLine();
|
||||
helpstr.AppendLine("### " + module.Name + " ");
|
||||
helpstr.AppendLine($"{GetText("cmd_and_alias")} | {GetText("desc")} | {GetText("usage")}");
|
||||
helpstr.AppendLine("----------------|--------------|-------");
|
||||
lastModule = module.Name;
|
||||
}
|
||||
helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + Prefix + a + "`"))} |" +
|
||||
$" {string.Format(com.Summary, Prefix)} {_service.GetCommandRequirements(com, Context.Guild)} |" +
|
||||
$" {string.Format(com.Remarks, Prefix)}");
|
||||
}
|
||||
File.WriteAllText("../../docs/Commands List.md", helpstr.ToString());
|
||||
await ReplyConfirmLocalized("commandlist_regen").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Guide()
|
||||
{
|
||||
await ConfirmLocalized("guide",
|
||||
"http://nadekobot.readthedocs.io/en/latest/Commands%20List/",
|
||||
"http://nadekobot.readthedocs.io/en/latest/").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Donate()
|
||||
{
|
||||
await ReplyConfirmLocalized("donate", PatreonUrl, PaypalUrl).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandTextEqualityComparer : IEqualityComparer<CommandInfo>
|
||||
{
|
||||
public bool Equals(CommandInfo x, CommandInfo y) => x.Aliases.First() == y.Aliases.First();
|
||||
|
||||
public int GetHashCode(CommandInfo obj) => obj.Aliases.First().GetHashCode();
|
||||
|
||||
}
|
||||
}
|
74
NadekoBot.Core/Modules/Help/Services/HelpService.cs
Normal file
74
NadekoBot.Core/Modules/Help/Services/HelpService.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using System;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using System.Linq;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Impl;
|
||||
|
||||
namespace NadekoBot.Modules.Help.Services
|
||||
{
|
||||
public class HelpService : ILateExecutor, INService
|
||||
{
|
||||
private readonly IBotConfigProvider _bc;
|
||||
private readonly CommandHandler _ch;
|
||||
private readonly NadekoStrings _strings;
|
||||
|
||||
public HelpService(IBotConfigProvider bc, CommandHandler ch, NadekoStrings strings)
|
||||
{
|
||||
_bc = bc;
|
||||
_ch = ch;
|
||||
_strings = strings;
|
||||
}
|
||||
|
||||
public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(guild == null)
|
||||
await msg.Channel.SendMessageAsync(_bc.BotConfig.DMHelpString).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
public EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild)
|
||||
{
|
||||
var prefix = _ch.GetPrefix(guild);
|
||||
|
||||
var str = string.Format("**`{0}`**", prefix + com.Aliases.First());
|
||||
var alias = com.Aliases.Skip(1).FirstOrDefault();
|
||||
if (alias != null)
|
||||
str += string.Format(" **/ `{0}`**", prefix + alias);
|
||||
return new EmbedBuilder()
|
||||
.AddField(fb => fb.WithName(str).WithValue($"{com.RealSummary(prefix)} {GetCommandRequirements(com, guild)}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName(GetText("usage", guild)).WithValue(com.RealRemarks(prefix)).WithIsInline(false))
|
||||
.WithFooter(efb => efb.WithText(GetText("module", guild, com.Module.GetTopLevelModule().Name)))
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
}
|
||||
|
||||
public string GetCommandRequirements(CommandInfo cmd, IGuild guild) =>
|
||||
string.Join(" ", cmd.Preconditions
|
||||
.Where(ca => ca is OwnerOnlyAttribute || ca is RequireUserPermissionAttribute)
|
||||
.Select(ca =>
|
||||
{
|
||||
if (ca is OwnerOnlyAttribute)
|
||||
return Format.Bold(GetText("bot_owner_only", guild));
|
||||
var cau = (RequireUserPermissionAttribute)ca;
|
||||
if (cau.GuildPermission != null)
|
||||
return Format.Bold(GetText("server_permission", guild, cau.GuildPermission))
|
||||
.Replace("Guild", "Server");
|
||||
return Format.Bold(GetText("channel_permission", guild, cau.ChannelPermission))
|
||||
.Replace("Guild", "Server");
|
||||
}));
|
||||
|
||||
private string GetText(string text, IGuild guild, params object[] replacements) =>
|
||||
_strings.GetText(text, guild?.Id, "Help".ToLowerInvariant(), replacements);
|
||||
}
|
||||
}
|
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