494 lines
21 KiB
C#
494 lines
21 KiB
C#
using Discord;
|
|
using Discord.Commands;
|
|
using Discord.WebSocket;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NadekoBot.Extensions;
|
|
using NadekoBot.Core.Services;
|
|
using NadekoBot.Core.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;
|
|
private readonly CurrencyService _cs;
|
|
private readonly IBotConfigProvider _bc;
|
|
|
|
public UserPunishCommands(DbService db, MuteService muteService,
|
|
CurrencyService cs, IBotConfigProvider bc)
|
|
{
|
|
_db = db;
|
|
_cs = cs;
|
|
_bc = bc;
|
|
}
|
|
|
|
[NadekoCommand, Usage, Description, Aliases]
|
|
[RequireContext(ContextType.Guild)]
|
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
|
public async Task Warn(IGuildUser user, [Remainder] string reason = 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;
|
|
}
|
|
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);
|
|
}
|
|
|
|
[NadekoCommand, Usage, Description, Aliases]
|
|
[RequireContext(ContextType.Guild)]
|
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
|
[RequireBotPermission(GuildPermission.BanMembers)]
|
|
[OwnerOnly]
|
|
public async Task MassKill([Remainder] string people)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(people))
|
|
return;
|
|
|
|
var gusers = ((SocketGuild)Context.Guild).Users;
|
|
//get user objects and reasons
|
|
var bans = people.Split("\n")
|
|
.Select(x =>
|
|
{
|
|
var split = x.Trim().Split(" ");
|
|
|
|
var reason = string.Join(" ", split.Skip(1));
|
|
|
|
if (ulong.TryParse(split[0], out var id))
|
|
return (Original: split[0], Id: id, Reason: reason);
|
|
|
|
return (Original: split[0],
|
|
Id: gusers
|
|
.FirstOrDefault(u => u.ToString().ToLowerInvariant() == x)
|
|
?.Id,
|
|
Reason: reason);
|
|
})
|
|
.ToArray();
|
|
|
|
//if user is null, means that person couldn't be found
|
|
var missing = bans
|
|
.Where(x => !x.Id.HasValue)
|
|
.ToArray();
|
|
|
|
//get only data for found users
|
|
var found = bans
|
|
.Where(x => x.Id.HasValue)
|
|
.Select(x => x.Id.Value)
|
|
.ToArray();
|
|
|
|
var missStr = string.Join("\n", missing);
|
|
if (string.IsNullOrWhiteSpace(missStr))
|
|
missStr = "-";
|
|
|
|
//send a message but don't wait for it
|
|
var banningMessageTask = Context.Channel.EmbedAsync(new EmbedBuilder()
|
|
.WithDescription(GetText("mass_kill_in_progress", bans.Length))
|
|
.AddField(GetText("invalid", missing.Length), missStr)
|
|
.WithOkColor());
|
|
|
|
using (var uow = _db.UnitOfWork)
|
|
{
|
|
var bc = uow.BotConfig.GetOrCreate(set => set.Include(x => x.Blacklist));
|
|
//blacklist the users
|
|
bc.Blacklist.AddRange(found.Select(x =>
|
|
new BlacklistItem
|
|
{
|
|
ItemId = x,
|
|
Type = BlacklistType.User,
|
|
}));
|
|
//clear their currencies
|
|
uow.Currency.RemoveFromMany(found.Select(x => (long)x).ToList());
|
|
uow.Complete();
|
|
}
|
|
|
|
_bc.Reload();
|
|
|
|
//do the banning
|
|
await Task.WhenAll(bans
|
|
.Where(x => x.Id.HasValue)
|
|
.Select(x => Context.Guild.AddBanAsync(x.Id.Value, 7, x.Reason, new RequestOptions() {
|
|
RetryMode = RetryMode.AlwaysRetry,
|
|
})))
|
|
.ConfigureAwait(false);
|
|
|
|
//wait for the message and edit it
|
|
var banningMessage = await banningMessageTask.ConfigureAwait(false);
|
|
|
|
await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder()
|
|
.WithDescription(GetText("mass_kill_completed", bans.Length))
|
|
.AddField(GetText("invalid", missing.Length), missStr)
|
|
.WithOkColor()
|
|
.Build()).ConfigureAwait(false);
|
|
}
|
|
}
|
|
}
|
|
}
|