mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
Applied codestyle to all .cs files
This commit is contained in:
@@ -6,10 +6,13 @@ namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration : NadekoModule<AdministrationService>
|
||||
{
|
||||
private readonly ImageOnlyChannelService _imageOnly;
|
||||
|
||||
public Administration(ImageOnlyChannelService imageOnly)
|
||||
=> _imageOnly = imageOnly;
|
||||
public enum Channel
|
||||
{
|
||||
Channel,
|
||||
Ch,
|
||||
Chnl,
|
||||
Chan
|
||||
}
|
||||
|
||||
public enum List
|
||||
{
|
||||
@@ -17,7 +20,25 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
Ls = 0
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public enum Server
|
||||
{
|
||||
Server
|
||||
}
|
||||
|
||||
public enum State
|
||||
{
|
||||
Enable,
|
||||
Disable,
|
||||
Inherit
|
||||
}
|
||||
|
||||
private readonly ImageOnlyChannelService _imageOnly;
|
||||
|
||||
public Administration(ImageOnlyChannelService imageOnly)
|
||||
=> _imageOnly = imageOnly;
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[BotPerm(GuildPerm.Administrator)]
|
||||
@@ -30,7 +51,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyPendingLocalizedAsync(strs.imageonly_disable);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(ChannelPerm.ManageChannels)]
|
||||
[BotPerm(ChannelPerm.ManageChannels)]
|
||||
@@ -39,9 +61,9 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
var seconds = (int?)time?.Time.TotalSeconds ?? 0;
|
||||
if (time is not null && (time.Time < TimeSpan.FromSeconds(0) || time.Time > TimeSpan.FromHours(6)))
|
||||
return;
|
||||
|
||||
|
||||
await ((ITextChannel) ctx.Channel).ModifyAsync(tcp =>
|
||||
|
||||
await ((ITextChannel)ctx.Channel).ModifyAsync(tcp =>
|
||||
{
|
||||
tcp.SlowModeInterval = seconds;
|
||||
});
|
||||
@@ -49,26 +71,26 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[BotPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(2)]
|
||||
public async Task Delmsgoncmd(List _)
|
||||
{
|
||||
var guild = (SocketGuild) ctx.Guild;
|
||||
var guild = (SocketGuild)ctx.Guild;
|
||||
var (enabled, channels) = _service.GetDelMsgOnCmdData(ctx.Guild.Id);
|
||||
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.server_delmsgoncmd))
|
||||
.WithDescription(enabled ? "✅" : "❌");
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.server_delmsgoncmd))
|
||||
.WithDescription(enabled ? "✅" : "❌");
|
||||
|
||||
var str = string.Join("\n", channels
|
||||
.Select(x =>
|
||||
var str = string.Join("\n",
|
||||
channels.Select(x =>
|
||||
{
|
||||
var ch = guild.GetChannel(x.ChannelId)?.ToString()
|
||||
?? x.ChannelId.ToString();
|
||||
var ch = guild.GetChannel(x.ChannelId)?.ToString() ?? x.ChannelId.ToString();
|
||||
var prefix = x.State ? "✅ " : "❌ ";
|
||||
return prefix + ch;
|
||||
}));
|
||||
@@ -81,12 +103,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
}
|
||||
|
||||
public enum Server
|
||||
{
|
||||
Server
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[BotPerm(GuildPerm.ManageMessages)]
|
||||
@@ -105,22 +123,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
}
|
||||
}
|
||||
|
||||
public enum Channel
|
||||
{
|
||||
Channel,
|
||||
Ch,
|
||||
Chnl,
|
||||
Chan
|
||||
}
|
||||
|
||||
public enum State
|
||||
{
|
||||
Enable,
|
||||
Disable,
|
||||
Inherit
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[BotPerm(GuildPerm.ManageMessages)]
|
||||
@@ -128,7 +132,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
public Task Delmsgoncmd(Channel _, State s, ITextChannel ch)
|
||||
=> Delmsgoncmd(_, s, ch.Id);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[BotPerm(GuildPerm.ManageMessages)]
|
||||
@@ -139,20 +144,15 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await _service.SetDelMsgOnCmdState(ctx.Guild.Id, actualChId, s);
|
||||
|
||||
if (s == State.Disable)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.delmsg_channel_off);
|
||||
}
|
||||
else if (s == State.Enable)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.delmsg_channel_on);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.delmsg_channel_inherit);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.DeafenMembers)]
|
||||
[BotPerm(GuildPerm.DeafenMembers)]
|
||||
@@ -162,7 +162,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyConfirmLocalizedAsync(strs.deafen);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.DeafenMembers)]
|
||||
[BotPerm(GuildPerm.DeafenMembers)]
|
||||
@@ -172,7 +173,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyConfirmLocalizedAsync(strs.undeafen);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[BotPerm(GuildPerm.ManageChannels)]
|
||||
@@ -182,7 +184,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyConfirmLocalizedAsync(strs.delvoich(Format.Bold(voiceChannel.Name)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[BotPerm(GuildPerm.ManageChannels)]
|
||||
@@ -192,7 +195,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyConfirmLocalizedAsync(strs.createvoich(Format.Bold(ch.Name)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[BotPerm(GuildPerm.ManageChannels)]
|
||||
@@ -202,7 +206,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyConfirmLocalizedAsync(strs.deltextchan(Format.Bold(toDelete.Name)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[BotPerm(GuildPerm.ManageChannels)]
|
||||
@@ -212,36 +217,39 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyConfirmLocalizedAsync(strs.createtextchan(Format.Bold(txtCh.Name)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[BotPerm(GuildPerm.ManageChannels)]
|
||||
public async Task SetTopic([Leftover] string topic = null)
|
||||
{
|
||||
var channel = (ITextChannel) ctx.Channel;
|
||||
var channel = (ITextChannel)ctx.Channel;
|
||||
topic ??= "";
|
||||
await channel.ModifyAsync(c => c.Topic = topic);
|
||||
await ReplyConfirmLocalizedAsync(strs.set_topic);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[BotPerm(GuildPerm.ManageChannels)]
|
||||
public async Task SetChanlName([Leftover] string name)
|
||||
{
|
||||
var channel = (ITextChannel) ctx.Channel;
|
||||
var channel = (ITextChannel)ctx.Channel;
|
||||
await channel.ModifyAsync(c => c.Name = name);
|
||||
await ReplyConfirmLocalizedAsync(strs.set_channel_name);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[BotPerm(GuildPerm.ManageChannels)]
|
||||
public async Task NsfwToggle()
|
||||
{
|
||||
var channel = (ITextChannel) ctx.Channel;
|
||||
var channel = (ITextChannel)ctx.Channel;
|
||||
var isEnabled = channel.IsNsfw;
|
||||
|
||||
await channel.ModifyAsync(c => c.IsNsfw = !isEnabled);
|
||||
@@ -252,20 +260,22 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await ReplyConfirmLocalizedAsync(strs.nsfw_set_true);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(ChannelPerm.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public Task Edit(ulong messageId, [Leftover] string text)
|
||||
=> Edit((ITextChannel) ctx.Channel, messageId, text);
|
||||
=> Edit((ITextChannel)ctx.Channel, messageId, text);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[Priority(1)]
|
||||
public async Task Edit(ITextChannel channel, ulong messageId, [Leftover] string text)
|
||||
{
|
||||
var userPerms = ((SocketGuildUser) ctx.User).GetPermissions(channel);
|
||||
var botPerms = ((SocketGuild) ctx.Guild).CurrentUser.GetPermissions(channel);
|
||||
var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel);
|
||||
var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel);
|
||||
if (!userPerms.Has(ChannelPermission.ManageMessages))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
|
||||
@@ -281,23 +291,28 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
await _service.EditMessage(ctx, channel, messageId, text);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(ChannelPerm.ManageMessages)]
|
||||
[BotPerm(ChannelPerm.ManageMessages)]
|
||||
public Task Delete(ulong messageId, StoopidTime time = null)
|
||||
=> Delete((ITextChannel) ctx.Channel, messageId, time);
|
||||
=> Delete((ITextChannel)ctx.Channel, messageId, time);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Delete(ITextChannel channel, ulong messageId, StoopidTime time = null)
|
||||
=> await InternalMessageAction(channel, messageId, time, msg => msg.DeleteAsync());
|
||||
|
||||
private async Task InternalMessageAction(ITextChannel channel, ulong messageId, StoopidTime time,
|
||||
private async Task InternalMessageAction(
|
||||
ITextChannel channel,
|
||||
ulong messageId,
|
||||
StoopidTime time,
|
||||
Func<IMessage, Task> func)
|
||||
{
|
||||
var userPerms = ((SocketGuildUser) ctx.User).GetPermissions(channel);
|
||||
var botPerms = ((SocketGuild) ctx.Guild).CurrentUser.GetPermissions(channel);
|
||||
var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel);
|
||||
var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel);
|
||||
if (!userPerms.Has(ChannelPermission.ManageMessages))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
|
||||
@@ -338,4 +353,4 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,13 +8,14 @@ public partial class Administration
|
||||
[Group]
|
||||
public class AutoAssignRoleCommands : NadekoSubmodule<AutoAssignRoleService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task AutoAssignRole([Leftover] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser) ctx.User;
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (role.Id == ctx.Guild.EveryoneRole.Id)
|
||||
return;
|
||||
|
||||
@@ -27,20 +28,15 @@ public partial class Administration
|
||||
|
||||
var roles = await _service.ToggleAarAsync(ctx.Guild.Id, role.Id);
|
||||
if (roles.Count == 0)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_disabled);
|
||||
}
|
||||
else if (roles.Contains(role.Id))
|
||||
{
|
||||
await AutoAssignRole();
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_role_removed(Format.Bold(role.ToString())));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -51,18 +47,14 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_none);
|
||||
return;
|
||||
}
|
||||
|
||||
var existing = roles.Select(rid => ctx.Guild.GetRole(rid)).Where(r => r is not null)
|
||||
.ToList();
|
||||
|
||||
var existing = roles.Select(rid => ctx.Guild.GetRole(rid)).Where(r => r is not null).ToList();
|
||||
|
||||
if (existing.Count != roles.Count)
|
||||
{
|
||||
await _service.SetAarRolesAsync(ctx.Guild.Id, existing.Select(x => x.Id));
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_roles(
|
||||
'\n' + existing.Select(x => Format.Bold(x.ToString()))
|
||||
.Join(",\n")));
|
||||
'\n' + existing.Select(x => Format.Bold(x.ToString())).Join(",\n")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,4 +18,4 @@ public enum LogType
|
||||
VoicePresence,
|
||||
VoicePresenceTTS,
|
||||
UserMuted
|
||||
}
|
||||
}
|
@@ -25,18 +25,28 @@ public class AntiSpamStats
|
||||
|
||||
public class AntiAltStats
|
||||
{
|
||||
public PunishmentAction Action
|
||||
=> _setting.Action;
|
||||
|
||||
public int ActionDurationMinutes
|
||||
=> _setting.ActionDurationMinutes;
|
||||
|
||||
public ulong? RoleId
|
||||
=> _setting.RoleId;
|
||||
|
||||
public TimeSpan MinAge
|
||||
=> _setting.MinAge;
|
||||
|
||||
public int Counter
|
||||
=> _counter;
|
||||
|
||||
private readonly AntiAltSetting _setting;
|
||||
public PunishmentAction Action => _setting.Action;
|
||||
public int ActionDurationMinutes => _setting.ActionDurationMinutes;
|
||||
public ulong? RoleId => _setting.RoleId;
|
||||
public TimeSpan MinAge => _setting.MinAge;
|
||||
|
||||
private int _counter = 0;
|
||||
public int Counter => _counter;
|
||||
|
||||
private int _counter;
|
||||
|
||||
public AntiAltStats(AntiAltSetting setting)
|
||||
=> _setting = setting;
|
||||
|
||||
public void Increment() => Interlocked.Increment(ref _counter);
|
||||
|
||||
}
|
||||
public void Increment()
|
||||
=> Interlocked.Increment(ref _counter);
|
||||
}
|
@@ -10,4 +10,4 @@ public class PunishQueueItem
|
||||
public int MuteTime { get; set; }
|
||||
public ulong? RoleId { get; set; }
|
||||
public IGuildUser User { get; set; }
|
||||
}
|
||||
}
|
@@ -3,11 +3,15 @@ namespace NadekoBot.Modules.Administration.Common;
|
||||
|
||||
public sealed class UserSpamStats : IDisposable
|
||||
{
|
||||
public int Count => timers.Count;
|
||||
public int Count
|
||||
=> timers.Count;
|
||||
|
||||
public string LastMessage { get; set; }
|
||||
|
||||
private ConcurrentQueue<Timer> timers { get; }
|
||||
|
||||
private readonly object applyLock = new();
|
||||
|
||||
public UserSpamStats(IUserMessage msg)
|
||||
{
|
||||
LastMessage = msg.Content.ToUpperInvariant();
|
||||
@@ -16,7 +20,6 @@ public sealed class UserSpamStats : IDisposable
|
||||
ApplyNextMessage(msg);
|
||||
}
|
||||
|
||||
private readonly object applyLock = new();
|
||||
public void ApplyNextMessage(IUserMessage message)
|
||||
{
|
||||
lock (applyLock)
|
||||
@@ -28,10 +31,15 @@ public sealed class UserSpamStats : IDisposable
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -41,4 +49,4 @@ public sealed class UserSpamStats : IDisposable
|
||||
while (timers.TryDequeue(out var old))
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,20 +10,17 @@ namespace NadekoBot.Modules.Administration
|
||||
[OwnerOnly]
|
||||
public class DangerousCommands : NadekoSubmodule<DangerousCommandsService>
|
||||
{
|
||||
|
||||
private async Task InternalExecSql(string sql, params object[] reps)
|
||||
{
|
||||
sql = string.Format(sql, reps);
|
||||
try
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithTitle(GetText(strs.sql_confirm_exec))
|
||||
.WithDescription(Format.Code(sql));
|
||||
.WithTitle(GetText(strs.sql_confirm_exec))
|
||||
.WithDescription(Format.Code(sql));
|
||||
|
||||
if (!await PromptUserConfirmAsync(embed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var res = await _service.ExecuteSql(sql);
|
||||
await SendConfirmAsync(res.ToString());
|
||||
@@ -34,87 +31,91 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task SqlSelect([Leftover]string sql)
|
||||
public Task SqlSelect([Leftover] string sql)
|
||||
{
|
||||
var result = _service.SelectSql(sql);
|
||||
|
||||
return ctx.SendPaginatedConfirmAsync(0, cur =>
|
||||
{
|
||||
var items = result.Results.Skip(cur * 20).Take(20);
|
||||
|
||||
if (!items.Any())
|
||||
return ctx.SendPaginatedConfirmAsync(0,
|
||||
cur =>
|
||||
{
|
||||
var items = result.Results.Skip(cur * 20).Take(20).ToList();
|
||||
|
||||
if (!items.Any())
|
||||
return _eb.Create().WithErrorColor().WithFooter(sql).WithDescription("-");
|
||||
|
||||
return _eb.Create()
|
||||
.WithErrorColor()
|
||||
.WithFooter(sql)
|
||||
.WithDescription("-");
|
||||
}
|
||||
|
||||
return _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithFooter(sql)
|
||||
.WithTitle(string.Join(" ║ ", result.ColumnNames))
|
||||
.WithDescription(string.Join('\n', items.Select(x => string.Join(" ║ ", x))));
|
||||
|
||||
}, result.Results.Count, 20);
|
||||
.WithOkColor()
|
||||
.WithFooter(sql)
|
||||
.WithTitle(string.Join(" ║ ", result.ColumnNames))
|
||||
.WithDescription(string.Join('\n', items.Select(x => string.Join(" ║ ", x))));
|
||||
},
|
||||
result.Results.Count,
|
||||
20);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task SqlExec([Leftover]string sql) =>
|
||||
InternalExecSql(sql);
|
||||
public Task SqlExec([Leftover] string sql)
|
||||
=> InternalExecSql(sql);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifus() =>
|
||||
SqlExec(DangerousCommandsService.WaifusDeleteSql);
|
||||
public Task DeleteWaifus()
|
||||
=> SqlExec(DangerousCommandsService.WaifusDeleteSql);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifu(IUser user) =>
|
||||
DeleteWaifu(user.Id);
|
||||
public Task DeleteWaifu(IUser user)
|
||||
=> DeleteWaifu(user.Id);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifu(ulong userId) =>
|
||||
InternalExecSql(DangerousCommandsService.WaifuDeleteSql, userId);
|
||||
public Task DeleteWaifu(ulong userId)
|
||||
=> InternalExecSql(DangerousCommandsService.WaifuDeleteSql, userId);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task DeleteCurrency() =>
|
||||
SqlExec(DangerousCommandsService.CurrencyDeleteSql);
|
||||
public Task DeleteCurrency()
|
||||
=> SqlExec(DangerousCommandsService.CurrencyDeleteSql);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task DeletePlaylists() =>
|
||||
SqlExec(DangerousCommandsService.MusicPlaylistDeleteSql);
|
||||
public Task DeletePlaylists()
|
||||
=> SqlExec(DangerousCommandsService.MusicPlaylistDeleteSql);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task DeleteXp() =>
|
||||
SqlExec(DangerousCommandsService.XpDeleteSql);
|
||||
public Task DeleteXp()
|
||||
=> SqlExec(DangerousCommandsService.XpDeleteSql);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task PurgeUser(ulong userId)
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
|
||||
.WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
|
||||
|
||||
if (!await PromptUserConfirmAsync(embed)) return;
|
||||
|
||||
if (!await PromptUserConfirmAsync(embed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _service.PurgeUserAsync(userId);
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task PurgeUser([Leftover]IUser user)
|
||||
public Task PurgeUser([Leftover] IUser user)
|
||||
=> PurgeUser(user.Id);
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
//[OwnerOnly]
|
||||
@@ -123,4 +124,4 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
@@ -11,7 +11,8 @@ public partial class Administration
|
||||
{
|
||||
// override stats, it should require that the user has managessages guild permission
|
||||
// .po 'stats' add user guild managemessages
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task DiscordPermOverride(CommandOrCrInfo cmd, params GuildPerm[] perms)
|
||||
@@ -26,20 +27,20 @@ public partial class Administration
|
||||
var aggregatePerms = perms.Aggregate((acc, seed) => seed | acc);
|
||||
await _service.AddOverride(ctx.Guild.Id, cmd.Name, aggregatePerms);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.perm_override(
|
||||
Format.Bold(aggregatePerms.ToString()),
|
||||
await ReplyConfirmLocalizedAsync(strs.perm_override(Format.Bold(aggregatePerms.ToString()),
|
||||
Format.Code(cmd.Name)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task DiscordPermOverrideReset()
|
||||
{
|
||||
var result = await PromptUserConfirmAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithDescription(GetText(strs.perm_override_all_confirm)));
|
||||
|
||||
.WithOkColor()
|
||||
.WithDescription(GetText(strs.perm_override_all_confirm)));
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
await _service.ClearAllOverrides(ctx.Guild.Id);
|
||||
@@ -47,35 +48,34 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.perm_override_all);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task DiscordPermOverrideList(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
|
||||
|
||||
var overrides = await _service.GetAllOverrides(ctx.Guild.Id);
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page, curPage =>
|
||||
{
|
||||
var eb = _eb.Create()
|
||||
.WithTitle(GetText(strs.perm_overrides))
|
||||
.WithOkColor();
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
curPage =>
|
||||
{
|
||||
var eb = _eb.Create().WithTitle(GetText(strs.perm_overrides)).WithOkColor();
|
||||
|
||||
var thisPageOverrides = overrides
|
||||
.Skip(9 * curPage)
|
||||
.Take(9)
|
||||
.ToList();
|
||||
var thisPageOverrides = overrides.Skip(9 * curPage).Take(9).ToList();
|
||||
|
||||
if (thisPageOverrides.Count == 0)
|
||||
eb.WithDescription(GetText(strs.perm_override_page_none));
|
||||
else
|
||||
eb.WithDescription(string.Join("\n",
|
||||
thisPageOverrides.Select(ov => $"{ov.Command} => {ov.Perm.ToString()}")));
|
||||
if (thisPageOverrides.Count == 0)
|
||||
eb.WithDescription(GetText(strs.perm_override_page_none));
|
||||
else
|
||||
eb.WithDescription(string.Join("\n",
|
||||
thisPageOverrides.Select(ov => $"{ov.Command} => {ov.Perm.ToString()}")));
|
||||
|
||||
return eb;
|
||||
}, overrides.Count, 9, true);
|
||||
return eb;
|
||||
},
|
||||
overrides.Count,
|
||||
9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,7 +8,8 @@ public partial class Administration
|
||||
[Group]
|
||||
public class GameChannelCommands : NadekoSubmodule<GameVoiceChannelService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[BotPerm(GuildPerm.MoveMembers)]
|
||||
@@ -21,6 +22,7 @@ public partial class Administration
|
||||
await ReplyErrorLocalizedAsync(strs.not_in_voice);
|
||||
return;
|
||||
}
|
||||
|
||||
var id = _service.ToggleGameVoiceChannel(ctx.Guild.Id, vch.Id);
|
||||
|
||||
if (id is null)
|
||||
@@ -34,4 +36,4 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,7 +10,7 @@ public class GreetGrouper<T>
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a group, if group already exists, adds the specified user
|
||||
/// Creates a group, if group already exists, adds the specified user
|
||||
/// </summary>
|
||||
/// <param name="guildId">Id of the server for which to create group for</param>
|
||||
/// <param name="toAddIfExists">User to add if group already exists</param>
|
||||
@@ -31,7 +31,7 @@ public class GreetGrouper<T>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the specified amount of items from the group. If all items are removed, group will be removed.
|
||||
/// Remove the specified amount of items from the group. If all items are removed, group will be removed.
|
||||
/// </summary>
|
||||
/// <param name="guildId">Id of the group</param>
|
||||
/// <param name="count">Maximum number of items to retrieve</param>
|
||||
@@ -54,8 +54,7 @@ public class GreetGrouper<T>
|
||||
// if there are more in the group than what's needed
|
||||
// take the requested number, remove them from the set
|
||||
// and return them
|
||||
var toReturn = set.TakeWhile(_ => count-- != 0)
|
||||
.ToList();
|
||||
var toReturn = set.TakeWhile(_ => count-- != 0).ToList();
|
||||
foreach (var item in toReturn)
|
||||
set.Remove(item);
|
||||
|
||||
@@ -69,4 +68,4 @@ public class GreetGrouper<T>
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,3 @@
|
||||
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
@@ -43,4 +42,4 @@ public class GreetSettings
|
||||
BoostMessageDeleteAfter = g.BoostMessageDeleteAfter,
|
||||
BoostMessageChannelId = g.BoostMessageChannelId
|
||||
};
|
||||
}
|
||||
}
|
@@ -1,10 +1,13 @@
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
|
||||
public class GreetSettingsService : INService
|
||||
{
|
||||
public bool GroupGreets
|
||||
=> _bss.Data.GroupGreets;
|
||||
|
||||
private readonly DbService _db;
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, GreetSettings> _guildConfigsCache;
|
||||
@@ -14,9 +17,6 @@ public class GreetSettingsService : INService
|
||||
private readonly GreetGrouper<IUser> _byes = new();
|
||||
private readonly BotConfigService _bss;
|
||||
|
||||
public bool GroupGreets
|
||||
=> _bss.Data.GroupGreets;
|
||||
|
||||
public GreetSettingsService(
|
||||
DiscordSocketClient client,
|
||||
Bot bot,
|
||||
@@ -42,8 +42,10 @@ public class GreetSettingsService : INService
|
||||
{
|
||||
// if user is a new booster
|
||||
// or boosted again the same server
|
||||
if ((optOldUser.Value is { PremiumSince: null } && newUser is { PremiumSince: not null }) ||
|
||||
(optOldUser.Value?.PremiumSince is { } oldDate && newUser.PremiumSince is { } newDate && newDate > oldDate))
|
||||
if ((optOldUser.Value is { PremiumSince: null } && newUser is { PremiumSince: not null })
|
||||
|| (optOldUser.Value?.PremiumSince is { } oldDate
|
||||
&& newUser.PremiumSince is { } newDate
|
||||
&& newDate > oldDate))
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(newUser.Guild.Id);
|
||||
if (!conf.SendBoostMessage) return Task.CompletedTask;
|
||||
@@ -65,20 +67,12 @@ public class GreetSettingsService : INService
|
||||
return;
|
||||
|
||||
var toSend = SmartText.CreateFrom(conf.BoostMessage);
|
||||
var rep = new ReplacementBuilder().WithDefault(user,
|
||||
channel,
|
||||
user.Guild,
|
||||
_client
|
||||
)
|
||||
.Build();
|
||||
var rep = new ReplacementBuilder().WithDefault(user, channel, user.Guild, _client).Build();
|
||||
|
||||
try
|
||||
{
|
||||
var toDelete = await channel.SendAsync(rep.Replace(toSend));
|
||||
if (conf.BoostMessageDeleteAfter > 0)
|
||||
{
|
||||
toDelete.DeleteAfter(conf.BoostMessageDeleteAfter);
|
||||
}
|
||||
if (conf.BoostMessageDeleteAfter > 0) toDelete.DeleteAfter(conf.BoostMessageDeleteAfter);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -96,76 +90,71 @@ public class GreetSettingsService : INService
|
||||
{
|
||||
_guildConfigsCache.AddOrUpdate(gc.GuildId,
|
||||
GreetSettings.Create(gc),
|
||||
delegate { return GreetSettings.Create(gc); }
|
||||
);
|
||||
delegate { return GreetSettings.Create(gc); });
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task UserLeft(SocketGuild guild, SocketUser user)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
var conf = GetOrAddSettingsForGuild(guild.Id);
|
||||
|
||||
if (!conf.SendChannelByeMessage) return;
|
||||
var channel = guild.TextChannels.FirstOrDefault(c => c.Id == conf.ByeMessageChannelId);
|
||||
|
||||
if (channel is null) //maybe warn the server owner that the channel is missing
|
||||
return;
|
||||
|
||||
if (GroupGreets)
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(guild.Id);
|
||||
|
||||
if (!conf.SendChannelByeMessage) return;
|
||||
var channel = guild.TextChannels.FirstOrDefault(c => c.Id == conf.ByeMessageChannelId);
|
||||
|
||||
if (channel is null) //maybe warn the server owner that the channel is missing
|
||||
return;
|
||||
|
||||
if (GroupGreets)
|
||||
// if group is newly created, greet that user right away,
|
||||
// but any user which joins in the next 5 seconds will
|
||||
// be greeted in a group greet
|
||||
if (_byes.CreateOrAdd(guild.Id, user))
|
||||
{
|
||||
// if group is newly created, greet that user right away,
|
||||
// but any user which joins in the next 5 seconds will
|
||||
// be greeted in a group greet
|
||||
if (_byes.CreateOrAdd(guild.Id, user))
|
||||
// greet single user
|
||||
await ByeUsers(conf, channel, new[] { user });
|
||||
var groupClear = false;
|
||||
while (!groupClear)
|
||||
{
|
||||
// greet single user
|
||||
await ByeUsers(conf, channel, new[] { user });
|
||||
var groupClear = false;
|
||||
while (!groupClear)
|
||||
{
|
||||
await Task.Delay(5000);
|
||||
groupClear = _byes.ClearGroup(guild.Id, 5, out var toBye);
|
||||
await ByeUsers(conf, channel, toBye);
|
||||
}
|
||||
await Task.Delay(5000);
|
||||
groupClear = _byes.ClearGroup(guild.Id, 5, out var toBye);
|
||||
await ByeUsers(conf, channel, toBye);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ByeUsers(conf, channel, new[] { user });
|
||||
}
|
||||
}
|
||||
catch
|
||||
else
|
||||
{
|
||||
// ignored
|
||||
await ByeUsers(conf, channel, new[] { user });
|
||||
}
|
||||
}
|
||||
);
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string? GetDmGreetMsg(ulong id)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.GuildConfigsForId(id, set => set)
|
||||
?.DmGreetMessageText;
|
||||
return uow.GuildConfigsForId(id, set => set)?.DmGreetMessageText;
|
||||
}
|
||||
|
||||
public string? GetGreetMsg(ulong gid)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.GuildConfigsForId(gid, set => set)
|
||||
.ChannelGreetMessageText;
|
||||
return uow.GuildConfigsForId(gid, set => set).ChannelGreetMessageText;
|
||||
}
|
||||
|
||||
public string? GetBoostMessage(ulong gid)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.GuildConfigsForId(gid, set => set)
|
||||
.BoostMessage;
|
||||
return uow.GuildConfigsForId(gid, set => set).BoostMessage;
|
||||
}
|
||||
|
||||
private Task ByeUsers(GreetSettings conf, ITextChannel channel, IUser user)
|
||||
@@ -177,20 +166,17 @@ public class GreetSettingsService : INService
|
||||
return;
|
||||
|
||||
var rep = new ReplacementBuilder().WithChannel(channel)
|
||||
.WithClient(_client)
|
||||
.WithServer(_client, (SocketGuild)channel.Guild)
|
||||
.WithManyUsers(users)
|
||||
.Build();
|
||||
.WithClient(_client)
|
||||
.WithServer(_client, (SocketGuild)channel.Guild)
|
||||
.WithManyUsers(users)
|
||||
.Build();
|
||||
|
||||
var text = SmartText.CreateFrom(conf.ChannelByeMessageText);
|
||||
text = rep.Replace(text);
|
||||
try
|
||||
{
|
||||
var toDelete = await channel.SendAsync(text);
|
||||
if (conf.AutoDeleteByeMessagesTimer > 0)
|
||||
{
|
||||
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
||||
}
|
||||
if (conf.AutoDeleteByeMessagesTimer > 0) toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -207,20 +193,17 @@ public class GreetSettingsService : INService
|
||||
return;
|
||||
|
||||
var rep = new ReplacementBuilder().WithChannel(channel)
|
||||
.WithClient(_client)
|
||||
.WithServer(_client, (SocketGuild)channel.Guild)
|
||||
.WithManyUsers(users)
|
||||
.Build();
|
||||
.WithClient(_client)
|
||||
.WithServer(_client, (SocketGuild)channel.Guild)
|
||||
.WithManyUsers(users)
|
||||
.Build();
|
||||
|
||||
var text = SmartText.CreateFrom(conf.ChannelGreetMessageText);
|
||||
text = rep.Replace(text);
|
||||
try
|
||||
{
|
||||
var toDelete = await channel.SendAsync(text);
|
||||
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
||||
{
|
||||
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
||||
}
|
||||
if (conf.AutoDeleteGreetMessagesTimer > 0) toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -230,12 +213,7 @@ public class GreetSettingsService : INService
|
||||
|
||||
private async Task<bool> GreetDmUser(GreetSettings conf, IDMChannel channel, IGuildUser user)
|
||||
{
|
||||
var rep = new ReplacementBuilder().WithDefault(user,
|
||||
channel,
|
||||
(SocketGuild)user.Guild,
|
||||
_client
|
||||
)
|
||||
.Build();
|
||||
var rep = new ReplacementBuilder().WithDefault(user, channel, (SocketGuild)user.Guild, _client).Build();
|
||||
|
||||
var text = SmartText.CreateFrom(conf.DmGreetMessageText);
|
||||
rep.Replace(text);
|
||||
@@ -254,65 +232,60 @@ public class GreetSettingsService : INService
|
||||
private Task UserJoined(IGuildUser user)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
|
||||
if (conf.SendChannelGreetMessage)
|
||||
if (conf.SendChannelGreetMessage)
|
||||
{
|
||||
var channel = await user.Guild.GetTextChannelAsync(conf.GreetMessageChannelId);
|
||||
if (channel != null)
|
||||
{
|
||||
var channel = await user.Guild.GetTextChannelAsync(conf.GreetMessageChannelId);
|
||||
if (channel != null)
|
||||
if (GroupGreets)
|
||||
{
|
||||
if (GroupGreets)
|
||||
// if group is newly created, greet that user right away,
|
||||
// but any user which joins in the next 5 seconds will
|
||||
// be greeted in a group greet
|
||||
if (_greets.CreateOrAdd(user.GuildId, user))
|
||||
{
|
||||
// if group is newly created, greet that user right away,
|
||||
// but any user which joins in the next 5 seconds will
|
||||
// be greeted in a group greet
|
||||
if (_greets.CreateOrAdd(user.GuildId, user))
|
||||
// greet single user
|
||||
await GreetUsers(conf, channel, new[] { user });
|
||||
var groupClear = false;
|
||||
while (!groupClear)
|
||||
{
|
||||
// greet single user
|
||||
await GreetUsers(conf, channel, new[] { user });
|
||||
var groupClear = false;
|
||||
while (!groupClear)
|
||||
{
|
||||
await Task.Delay(5000);
|
||||
groupClear = _greets.ClearGroup(user.GuildId, 5, out var toGreet);
|
||||
await GreetUsers(conf, channel, toGreet);
|
||||
}
|
||||
await Task.Delay(5000);
|
||||
groupClear = _greets.ClearGroup(user.GuildId, 5, out var toGreet);
|
||||
await GreetUsers(conf, channel, toGreet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await GreetUsers(conf, channel, new[] { user });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.SendDmGreetMessage)
|
||||
{
|
||||
var channel = await user.CreateDMChannelAsync();
|
||||
|
||||
if (channel is not null)
|
||||
else
|
||||
{
|
||||
await GreetDmUser(conf, channel, user);
|
||||
await GreetUsers(conf, channel, new[] { user });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
||||
if (conf.SendDmGreetMessage)
|
||||
{
|
||||
// ignored
|
||||
var channel = await user.CreateDMChannelAsync();
|
||||
|
||||
if (channel is not null) await GreetDmUser(conf, channel, user);
|
||||
}
|
||||
}
|
||||
);
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string? GetByeMessage(ulong gid)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.GuildConfigsForId(gid, set => set)
|
||||
.ChannelByeMessageText;
|
||||
return uow.GuildConfigsForId(gid, set => set).ChannelByeMessageText;
|
||||
}
|
||||
|
||||
public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
||||
@@ -332,11 +305,9 @@ public class GreetSettingsService : INService
|
||||
|
||||
public async Task<bool> SetSettings(ulong guildId, GreetSettings settings)
|
||||
{
|
||||
if (settings.AutoDeleteByeMessagesTimer is > 600 or < 0 ||
|
||||
settings.AutoDeleteGreetMessagesTimer is > 600 or < 0)
|
||||
{
|
||||
if (settings.AutoDeleteByeMessagesTimer is > 600 or < 0
|
||||
|| settings.AutoDeleteGreetMessagesTimer is > 600 or < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
||||
@@ -411,53 +382,6 @@ public class GreetSettingsService : INService
|
||||
return enabled;
|
||||
}
|
||||
|
||||
#region Get Enabled Status
|
||||
|
||||
public bool GetGreetDmEnabled(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
||||
return conf.SendDmGreetMessage;
|
||||
}
|
||||
|
||||
public bool GetGreetEnabled(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
||||
return conf.SendChannelGreetMessage;
|
||||
}
|
||||
|
||||
public bool GetByeEnabled(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
||||
return conf.SendChannelByeMessage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Test Messages
|
||||
|
||||
public Task ByeTest(ITextChannel channel, IGuildUser user)
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
return ByeUsers(conf, channel, user);
|
||||
}
|
||||
|
||||
public Task GreetTest(ITextChannel channel, IGuildUser user)
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
return GreetUsers(conf, channel, user);
|
||||
}
|
||||
|
||||
public Task<bool> GreetDmTest(IDMChannel channel, IGuildUser user)
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
return GreetDmUser(conf, channel, user);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool SetGreetDmMessage(ulong guildId, ref string? message)
|
||||
{
|
||||
message = message?.SanitizeMentions();
|
||||
@@ -580,4 +504,51 @@ public class GreetSettingsService : INService
|
||||
_guildConfigsCache.AddOrUpdate(guildId, toAdd, (_, _) => toAdd);
|
||||
return conf.SendBoostMessage;
|
||||
}
|
||||
|
||||
#region Get Enabled Status
|
||||
|
||||
public bool GetGreetDmEnabled(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
||||
return conf.SendDmGreetMessage;
|
||||
}
|
||||
|
||||
public bool GetGreetEnabled(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
||||
return conf.SendChannelGreetMessage;
|
||||
}
|
||||
|
||||
public bool GetByeEnabled(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set);
|
||||
return conf.SendChannelByeMessage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Test Messages
|
||||
|
||||
public Task ByeTest(ITextChannel channel, IGuildUser user)
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
return ByeUsers(conf, channel, user);
|
||||
}
|
||||
|
||||
public Task GreetTest(ITextChannel channel, IGuildUser user)
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
return GreetUsers(conf, channel, user);
|
||||
}
|
||||
|
||||
public Task<bool> GreetDmTest(IDMChannel channel, IGuildUser user)
|
||||
{
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
return GreetDmUser(conf, channel, user);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
@@ -5,7 +5,8 @@ public partial class Administration
|
||||
[Group]
|
||||
public class ServerGreetCommands : NadekoSubmodule<GreetSettingsService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task Boost()
|
||||
@@ -18,7 +19,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.boost_off);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task BoostDel(int timer = 30)
|
||||
@@ -34,7 +36,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.boostdel_off);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task BoostMsg([Leftover] string? text = null)
|
||||
@@ -53,7 +56,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.boostmsg_enable($"`{Prefix}boost`"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task GreetDel(int timer = 30)
|
||||
@@ -69,7 +73,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.greetdel_off);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task Greet()
|
||||
@@ -82,7 +87,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.greet_off);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task GreetMsg([Leftover] string? text = null)
|
||||
@@ -97,12 +103,13 @@ public partial class Administration
|
||||
var sendGreetEnabled = _service.SetGreetMessage(ctx.Guild.Id, ref text);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.greetmsg_new);
|
||||
|
||||
|
||||
if (!sendGreetEnabled)
|
||||
await ReplyPendingLocalizedAsync(strs.greetmsg_enable($"`{Prefix}greet`"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task GreetDm()
|
||||
@@ -115,7 +122,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.greetdm_off);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task GreetDmMsg([Leftover] string? text = null)
|
||||
@@ -134,7 +142,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.greetdmmsg_enable($"`{Prefix}greetdm`"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task Bye()
|
||||
@@ -147,7 +156,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.bye_off);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task ByeMsg([Leftover] string? text = null)
|
||||
@@ -166,7 +176,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.byemsg_enable($"`{Prefix}bye`"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
public async Task ByeDel(int timer = 30)
|
||||
@@ -180,7 +191,8 @@ public partial class Administration
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
[Ratelimit(5)]
|
||||
@@ -190,13 +202,11 @@ public partial class Administration
|
||||
|
||||
await _service.ByeTest((ITextChannel)ctx.Channel, user);
|
||||
var enabled = _service.GetByeEnabled(ctx.Guild.Id);
|
||||
if (!enabled)
|
||||
{
|
||||
await ReplyPendingLocalizedAsync(strs.byemsg_enable($"`{Prefix}bye`"));
|
||||
}
|
||||
if (!enabled) await ReplyPendingLocalizedAsync(strs.byemsg_enable($"`{Prefix}bye`"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
[Ratelimit(5)]
|
||||
@@ -206,13 +216,11 @@ public partial class Administration
|
||||
|
||||
await _service.GreetTest((ITextChannel)ctx.Channel, user);
|
||||
var enabled = _service.GetGreetEnabled(ctx.Guild.Id);
|
||||
if (!enabled)
|
||||
{
|
||||
await ReplyPendingLocalizedAsync(strs.greetmsg_enable($"`{Prefix}greet`"));
|
||||
}
|
||||
if (!enabled) await ReplyPendingLocalizedAsync(strs.greetmsg_enable($"`{Prefix}greet`"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageGuild)]
|
||||
[Ratelimit(5)]
|
||||
@@ -231,4 +239,4 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.greetdmmsg_enable($"`{Prefix}greetdm`"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,46 +8,46 @@ public partial class Administration
|
||||
[Group]
|
||||
public class LocalizationCommands : NadekoSubmodule
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<string, string> supportedLocales =
|
||||
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", "עברית, ישראל"},
|
||||
{"hu-HU", "Magyar, Magyarország"},
|
||||
{"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"},
|
||||
{"ts-TS", "Tsundere, You Baka"},
|
||||
{"uk-UA", "Українська, Україна"}
|
||||
};
|
||||
private static readonly IReadOnlyDictionary<string, string> supportedLocales = 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", "עברית, ישראל" },
|
||||
{ "hu-HU", "Magyar, Magyarország" },
|
||||
{ "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" },
|
||||
{ "ts-TS", "Tsundere, You Baka" },
|
||||
{ "uk-UA", "Українська, Україна" }
|
||||
};
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[Priority(0)]
|
||||
public async Task LanguageSet()
|
||||
=> await ReplyConfirmLocalizedAsync(strs.lang_set_show(
|
||||
Format.Bold(Culture.ToString()),
|
||||
=> await ReplyConfirmLocalizedAsync(strs.lang_set_show(Format.Bold(Culture.ToString()),
|
||||
Format.Bold(Culture.NativeName)));
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(1)]
|
||||
@@ -67,8 +67,7 @@ public partial class Administration
|
||||
Localization.SetGuildCulture(ctx.Guild, ci);
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.lang_set(Format.Bold(ci.ToString()),
|
||||
Format.Bold(ci.NativeName)));
|
||||
await ReplyConfirmLocalizedAsync(strs.lang_set(Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -76,14 +75,16 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
public async Task LanguageSetDefault()
|
||||
{
|
||||
var cul = Localization.DefaultCultureInfo;
|
||||
await ReplyErrorLocalizedAsync(strs.lang_set_bot_show(cul, cul.NativeName));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task LanguageSetDefault(string name)
|
||||
{
|
||||
@@ -110,12 +111,15 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
public async Task LanguagesList()
|
||||
=> await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.lang_list))
|
||||
.WithDescription(string.Join("\n",
|
||||
supportedLocales.Select(x => $"{Format.Code(x.Key),-10} => {x.Value}"))));
|
||||
=> await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.lang_list))
|
||||
.WithDescription(string.Join("\n",
|
||||
supportedLocales.Select(
|
||||
x => $"{Format.Code(x.Key),-10} => {x.Value}"))));
|
||||
}
|
||||
}
|
||||
/* list of language codes for reference.
|
||||
@@ -248,4 +252,4 @@ public partial class Administration
|
||||
{ "YE", "ar-YE" },
|
||||
{ "ZA", "af-ZA" },
|
||||
{ "ZW", "en-ZW" }
|
||||
*/
|
||||
*/
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -11,7 +11,8 @@ public partial class Administration
|
||||
[NoPublicBot]
|
||||
public class LogCommands : NadekoSubmodule<ILogCommandService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
@@ -24,7 +25,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.log_disabled);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
@@ -38,63 +40,74 @@ public partial class Administration
|
||||
?? new List<IgnoredLogItem>();
|
||||
|
||||
var eb = _eb.Create(ctx)
|
||||
.WithOkColor()
|
||||
.AddField(GetText(strs.log_ignored_channels),
|
||||
chs.Count == 0 ? "-" : string.Join('\n', chs.Select(x => $"{x.LogItemId} | <#{x.LogItemId}>")))
|
||||
.AddField(GetText(strs.log_ignored_users),
|
||||
usrs.Count == 0 ? "-" : string.Join('\n', usrs.Select(x => $"{x.LogItemId} | <@{x.LogItemId}>")));
|
||||
.WithOkColor()
|
||||
.AddField(GetText(strs.log_ignored_channels),
|
||||
chs.Count == 0
|
||||
? "-"
|
||||
: string.Join('\n', chs.Select(x => $"{x.LogItemId} | <#{x.LogItemId}>")))
|
||||
.AddField(GetText(strs.log_ignored_users),
|
||||
usrs.Count == 0
|
||||
? "-"
|
||||
: string.Join('\n', usrs.Select(x => $"{x.LogItemId} | <@{x.LogItemId}>")));
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
public async Task LogIgnore([Leftover]ITextChannel target)
|
||||
public async Task LogIgnore([Leftover] ITextChannel target)
|
||||
{
|
||||
target ??= (ITextChannel)ctx.Channel;
|
||||
|
||||
var removed = _service.LogIgnore(ctx.Guild.Id, target.Id, IgnoredItemType.Channel);
|
||||
|
||||
if (!removed)
|
||||
await ReplyConfirmLocalizedAsync(strs.log_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
await ReplyConfirmLocalizedAsync(
|
||||
strs.log_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
else
|
||||
await ReplyConfirmLocalizedAsync(strs.log_not_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
await ReplyConfirmLocalizedAsync(
|
||||
strs.log_not_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
public async Task LogIgnore([Leftover]IUser target)
|
||||
public async Task LogIgnore([Leftover] IUser target)
|
||||
{
|
||||
var removed = _service.LogIgnore(ctx.Guild.Id, target.Id, IgnoredItemType.User);
|
||||
|
||||
if (!removed)
|
||||
await ReplyConfirmLocalizedAsync(strs.log_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
await ReplyConfirmLocalizedAsync(
|
||||
strs.log_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
else
|
||||
await ReplyConfirmLocalizedAsync(strs.log_not_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
await ReplyConfirmLocalizedAsync(
|
||||
strs.log_not_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
public async Task LogEvents()
|
||||
{
|
||||
var logSetting = _service.GetGuildLogSettings(ctx.Guild.Id);
|
||||
var str = string.Join("\n", Enum.GetNames(typeof(LogType))
|
||||
.Select(x =>
|
||||
{
|
||||
var val = logSetting is null ? null : GetLogProperty(logSetting, Enum.Parse<LogType>(x));
|
||||
if (val != null)
|
||||
return $"{Format.Bold(x)} <#{val}>";
|
||||
return Format.Bold(x);
|
||||
}));
|
||||
var str = string.Join("\n",
|
||||
Enum.GetNames(typeof(LogType))
|
||||
.Select(x =>
|
||||
{
|
||||
var val = logSetting is null ? null : GetLogProperty(logSetting, Enum.Parse<LogType>(x));
|
||||
if (val != null)
|
||||
return $"{Format.Bold(x)} <#{val}>";
|
||||
return Format.Bold(x);
|
||||
}));
|
||||
|
||||
await SendConfirmAsync(Format.Bold(GetText(strs.log_events)) + "\n" +
|
||||
str);
|
||||
await SendConfirmAsync(Format.Bold(GetText(strs.log_events)) + "\n" + str);
|
||||
}
|
||||
|
||||
private static ulong? GetLogProperty(LogSetting l, LogType type)
|
||||
@@ -136,7 +149,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
@@ -150,4 +164,4 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.log_stop(Format.Bold(type.ToString())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,8 +13,8 @@ public partial class Administration
|
||||
{
|
||||
var runnerUserRoles = runnerUser.GetRoles();
|
||||
var targetUserRoles = targetUser.GetRoles();
|
||||
if (runnerUser.Id != ctx.Guild.OwnerId &&
|
||||
runnerUserRoles.Max(x => x.Position) <= targetUserRoles.Max(x => x.Position))
|
||||
if (runnerUser.Id != ctx.Guild.OwnerId
|
||||
&& runnerUserRoles.Max(x => x.Position) <= targetUserRoles.Max(x => x.Position))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.mute_perms);
|
||||
return false;
|
||||
@@ -23,7 +23,8 @@ public partial class Administration
|
||||
return true;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async Task MuteRole([Leftover] IRole role = null)
|
||||
@@ -34,20 +35,21 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.mute_role(Format.Code(muteRole.Name)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.User.Id != ctx.Guild.OwnerId &&
|
||||
role.Position >= ((SocketGuildUser) ctx.User).Roles.Max(x => x.Position))
|
||||
|
||||
if (ctx.User.Id != ctx.Guild.OwnerId
|
||||
&& role.Position >= ((SocketGuildUser)ctx.User).Roles.Max(x => x.Position))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await _service.SetMuteRoleAsync(ctx.Guild.Id, role.Name);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.mute_role_set);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||
[Priority(0)]
|
||||
@@ -68,7 +70,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||
[Priority(1)]
|
||||
@@ -82,7 +85,8 @@ public partial class Administration
|
||||
return;
|
||||
|
||||
await _service.TimedMute(user, ctx.User, time.Time, reason: reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_muted_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
|
||||
await ReplyConfirmLocalizedAsync(strs.user_muted_time(Format.Bold(user.ToString()),
|
||||
(int)time.Time.TotalMinutes));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -91,7 +95,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||
public async Task Unmute(IGuildUser user, [Leftover] string reason = "")
|
||||
@@ -107,7 +112,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
@@ -118,7 +124,7 @@ public partial class Administration
|
||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||
return;
|
||||
|
||||
await _service.MuteUser(user, ctx.User, MuteType.Chat, reason: reason);
|
||||
await _service.MuteUser(user, ctx.User, MuteType.Chat, reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_chat_mute(Format.Bold(user.ToString())));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -128,7 +134,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(1)]
|
||||
@@ -141,8 +148,9 @@ public partial class Administration
|
||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||
return;
|
||||
|
||||
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Chat, reason: reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_chat_mute_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
|
||||
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Chat, reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_chat_mute_time(Format.Bold(user.ToString()),
|
||||
(int)time.Time.TotalMinutes));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -151,14 +159,15 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ChatUnmute(IGuildUser user, [Leftover] string reason = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.UnmuteUser(user.Guild.Id, user.Id, ctx.User, MuteType.Chat, reason: reason);
|
||||
await _service.UnmuteUser(user.Guild.Id, user.Id, ctx.User, MuteType.Chat, reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_chat_unmute(Format.Bold(user.ToString())));
|
||||
}
|
||||
catch
|
||||
@@ -167,7 +176,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.MuteMembers)]
|
||||
[Priority(0)]
|
||||
@@ -178,7 +188,7 @@ public partial class Administration
|
||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||
return;
|
||||
|
||||
await _service.MuteUser(user, ctx.User, MuteType.Voice, reason: reason);
|
||||
await _service.MuteUser(user, ctx.User, MuteType.Voice, reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_voice_mute(Format.Bold(user.ToString())));
|
||||
}
|
||||
catch
|
||||
@@ -187,11 +197,12 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.MuteMembers)]
|
||||
[Priority(1)]
|
||||
public async Task VoiceMute(StoopidTime time,IGuildUser user, [Leftover] string reason = "")
|
||||
public async Task VoiceMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
||||
{
|
||||
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
||||
return;
|
||||
@@ -200,8 +211,9 @@ public partial class Administration
|
||||
if (!await VerifyMutePermissions((IGuildUser)ctx.User, user))
|
||||
return;
|
||||
|
||||
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Voice, reason: reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_voice_mute_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
|
||||
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Voice, reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_voice_mute_time(Format.Bold(user.ToString()),
|
||||
(int)time.Time.TotalMinutes));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -209,14 +221,15 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.MuteMembers)]
|
||||
public async Task VoiceUnmute(IGuildUser user, [Leftover] string reason = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
await _service.UnmuteUser(user.GuildId, user.Id, ctx.User, MuteType.Voice, reason: reason);
|
||||
await _service.UnmuteUser(user.GuildId, user.Id, ctx.User, MuteType.Voice, reason);
|
||||
await ReplyConfirmLocalizedAsync(strs.user_voice_unmute(Format.Bold(user.ToString())));
|
||||
}
|
||||
catch
|
||||
@@ -225,4 +238,4 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,7 +8,8 @@ public partial class Administration
|
||||
[Group]
|
||||
public class PlayingRotateCommands : NadekoSubmodule<PlayingRotateService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task RotatePlaying()
|
||||
{
|
||||
@@ -18,7 +19,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.ropl_disabled);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task AddPlaying(ActivityType t, [Leftover] string status)
|
||||
{
|
||||
@@ -27,7 +29,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.ropl_added);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ListPlaying()
|
||||
{
|
||||
@@ -40,13 +43,13 @@ public partial class Administration
|
||||
else
|
||||
{
|
||||
var i = 1;
|
||||
await ReplyConfirmLocalizedAsync(strs.ropl_list(
|
||||
string.Join("\n\t", statuses.Select(rs => $"`{i++}.` *{rs.Type}* {rs.Status}"))));
|
||||
await ReplyConfirmLocalizedAsync(strs.ropl_list(string.Join("\n\t",
|
||||
statuses.Select(rs => $"`{i++}.` *{rs.Type}* {rs.Status}"))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task RemovePlaying(int index)
|
||||
{
|
||||
@@ -60,4 +63,4 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.reprm(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,41 +6,45 @@ public partial class Administration
|
||||
[Group]
|
||||
public class PrefixCommands : NadekoSubmodule
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[Priority(1)]
|
||||
public async Task PrefixCommand()
|
||||
=> await ReplyConfirmLocalizedAsync(strs.prefix_current(Format.Code(CmdHandler.GetPrefix(ctx.Guild))));
|
||||
|
||||
public enum Set
|
||||
{
|
||||
Set
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[Priority(1)]
|
||||
public async Task PrefixCommand()
|
||||
=> await ReplyConfirmLocalizedAsync(strs.prefix_current(Format.Code(CmdHandler.GetPrefix(ctx.Guild))));
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(0)]
|
||||
public Task PrefixCommand(Set _, [Leftover] string prefix)
|
||||
=> PrefixCommand(prefix);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(0)]
|
||||
public async Task PrefixCommand([Leftover]string prefix)
|
||||
public async Task PrefixCommand([Leftover] string prefix)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(prefix))
|
||||
return;
|
||||
|
||||
var oldPrefix = base.Prefix;
|
||||
var oldPrefix = Prefix;
|
||||
var newPrefix = CmdHandler.SetPrefix(ctx.Guild, prefix);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.prefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task DefPrefix([Leftover]string prefix = null)
|
||||
public async Task DefPrefix([Leftover] string prefix = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(prefix))
|
||||
{
|
||||
@@ -54,4 +58,4 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.defprefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -11,7 +11,8 @@ public partial class Administration
|
||||
[Group]
|
||||
public class ProtectionCommands : NadekoSubmodule<ProtectionService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task AntiAlt()
|
||||
@@ -25,26 +26,31 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.protection_not_running("Anti-Alt"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task AntiAlt(StoopidTime minAge, PunishmentAction action, [Leftover] StoopidTime punishTime = null)
|
||||
{
|
||||
var minAgeMinutes = (int)minAge.Time.TotalMinutes;
|
||||
var punishTimeMinutes = (int?) punishTime?.Time.TotalMinutes ?? 0;
|
||||
var punishTimeMinutes = (int?)punishTime?.Time.TotalMinutes ?? 0;
|
||||
|
||||
if (minAgeMinutes < 1 || punishTimeMinutes < 0)
|
||||
return;
|
||||
|
||||
await _service.StartAntiAltAsync(ctx.Guild.Id, minAgeMinutes, action, (int?)punishTime?.Time.TotalMinutes ?? 0);
|
||||
await _service.StartAntiAltAsync(ctx.Guild.Id,
|
||||
minAgeMinutes,
|
||||
action,
|
||||
(int?)punishTime?.Time.TotalMinutes ?? 0);
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task AntiAlt(StoopidTime minAge, PunishmentAction action, [Leftover]IRole role)
|
||||
public async Task AntiAlt(StoopidTime minAge, PunishmentAction action, [Leftover] IRole role)
|
||||
{
|
||||
var minAgeMinutes = (int)minAge.Time.TotalMinutes;
|
||||
|
||||
@@ -55,46 +61,50 @@ public partial class Administration
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public Task AntiRaid()
|
||||
{
|
||||
if (_service.TryStopAntiRaid(ctx.Guild.Id))
|
||||
{
|
||||
return ReplyConfirmLocalizedAsync(strs.prot_disable("Anti-Raid"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Raid"));
|
||||
}
|
||||
return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Raid"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(1)]
|
||||
public Task AntiRaid(int userThreshold, int seconds,
|
||||
PunishmentAction action, [Leftover] StoopidTime punishTime)
|
||||
=> InternalAntiRaid(userThreshold, seconds, action, punishTime: punishTime);
|
||||
public Task AntiRaid(
|
||||
int userThreshold,
|
||||
int seconds,
|
||||
PunishmentAction action,
|
||||
[Leftover] StoopidTime punishTime)
|
||||
=> InternalAntiRaid(userThreshold, seconds, action, punishTime);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(2)]
|
||||
public Task AntiRaid(int userThreshold, int seconds, PunishmentAction action)
|
||||
=> InternalAntiRaid(userThreshold, seconds, action);
|
||||
|
||||
private async Task InternalAntiRaid(int userThreshold, int seconds = 10,
|
||||
PunishmentAction action = PunishmentAction.Mute, StoopidTime punishTime = null)
|
||||
|
||||
private async Task InternalAntiRaid(
|
||||
int userThreshold,
|
||||
int seconds = 10,
|
||||
PunishmentAction action = PunishmentAction.Mute,
|
||||
StoopidTime punishTime = null)
|
||||
{
|
||||
if (action == PunishmentAction.AddRole)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.punishment_unsupported(action));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (userThreshold is < 2 or > 30)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.raid_cnt(2, 30));
|
||||
@@ -106,47 +116,36 @@ public partial class Administration
|
||||
await ReplyErrorLocalizedAsync(strs.raid_time(2, 300));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (punishTime is not null)
|
||||
{
|
||||
if (!_service.IsDurationAllowed(action))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.prot_cant_use_time);
|
||||
}
|
||||
}
|
||||
|
||||
var time = (int?) punishTime?.Time.TotalMinutes ?? 0;
|
||||
|
||||
var time = (int?)punishTime?.Time.TotalMinutes ?? 0;
|
||||
if (time is < 0 or > 60 * 24)
|
||||
return;
|
||||
|
||||
var stats = await _service.StartAntiRaidAsync(ctx.Guild.Id, userThreshold, seconds,
|
||||
action, time);
|
||||
var stats = await _service.StartAntiRaidAsync(ctx.Guild.Id, userThreshold, seconds, action, time);
|
||||
|
||||
if (stats is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (stats is null) return;
|
||||
|
||||
await SendConfirmAsync(GetText(strs.prot_enable("Anti-Raid")),
|
||||
$"{ctx.User.Mention} {GetAntiRaidString(stats)}");
|
||||
$"{ctx.User.Mention} {GetAntiRaidString(stats)}");
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public Task AntiSpam()
|
||||
{
|
||||
if (_service.TryStopAntiSpam(ctx.Guild.Id))
|
||||
{
|
||||
return ReplyConfirmLocalizedAsync(strs.prot_disable("Anti-Spam"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Spam"));
|
||||
}
|
||||
return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Spam"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(0)]
|
||||
@@ -158,35 +157,36 @@ public partial class Administration
|
||||
return InternalAntiSpam(messageCount, action, null, role);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(1)]
|
||||
public Task AntiSpam(int messageCount, PunishmentAction action, [Leftover] StoopidTime punishTime)
|
||||
=> InternalAntiSpam(messageCount, action, punishTime, null);
|
||||
=> InternalAntiSpam(messageCount, action, punishTime);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[Priority(2)]
|
||||
public Task AntiSpam(int messageCount, PunishmentAction action)
|
||||
=> InternalAntiSpam(messageCount, action);
|
||||
|
||||
public async Task InternalAntiSpam(int messageCount, PunishmentAction action,
|
||||
StoopidTime timeData = null, IRole role = null)
|
||||
public async Task InternalAntiSpam(
|
||||
int messageCount,
|
||||
PunishmentAction action,
|
||||
StoopidTime timeData = null,
|
||||
IRole role = null)
|
||||
{
|
||||
if (messageCount is < 2 or > 10)
|
||||
return;
|
||||
|
||||
if (timeData is not null)
|
||||
{
|
||||
if (!_service.IsDurationAllowed(action))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.prot_cant_use_time);
|
||||
}
|
||||
}
|
||||
|
||||
var time = (int?) timeData?.Time.TotalMinutes ?? 0;
|
||||
var time = (int?)timeData?.Time.TotalMinutes ?? 0;
|
||||
if (time is < 0 or > 60 * 24)
|
||||
return;
|
||||
|
||||
@@ -196,14 +196,15 @@ public partial class Administration
|
||||
$"{ctx.User.Mention} {GetAntiSpamString(stats)}");
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task AntispamIgnore()
|
||||
{
|
||||
var added = await _service.AntiSpamIgnoreAsync(ctx.Guild.Id, ctx.Channel.Id);
|
||||
|
||||
if(added is null)
|
||||
if (added is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.protection_not_running("Anti-Spam"));
|
||||
return;
|
||||
@@ -215,7 +216,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.spam_not_ignore("Anti-Spam"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AntiList()
|
||||
{
|
||||
@@ -227,8 +229,7 @@ public partial class Administration
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = _eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.prot_active));
|
||||
var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.prot_active));
|
||||
|
||||
if (spam != null)
|
||||
embed.AddField("Anti-Spam", GetAntiSpamString(spam).TrimTo(1024), true);
|
||||
@@ -242,9 +243,8 @@ public partial class Administration
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private string GetAntiAltString(AntiAltStats alt)
|
||||
=> GetText(strs.anti_alt_status(
|
||||
Format.Bold(alt.MinAge.ToString(@"dd\d\ hh\h\ mm\m\ ")),
|
||||
private string GetAntiAltString(AntiAltStats alt)
|
||||
=> GetText(strs.anti_alt_status(Format.Bold(alt.MinAge.ToString(@"dd\d\ hh\h\ mm\m\ ")),
|
||||
Format.Bold(alt.Action.ToString()),
|
||||
Format.Bold(alt.Counter.ToString())));
|
||||
|
||||
@@ -257,13 +257,9 @@ public partial class Administration
|
||||
ignoredString = "none";
|
||||
|
||||
var add = string.Empty;
|
||||
if (settings.MuteTime > 0)
|
||||
{
|
||||
add = $" ({TimeSpan.FromMinutes(settings.MuteTime):hh\\hmm\\m})";
|
||||
}
|
||||
if (settings.MuteTime > 0) add = $" ({TimeSpan.FromMinutes(settings.MuteTime):hh\\hmm\\m})";
|
||||
|
||||
return GetText(strs.spam_stats(
|
||||
Format.Bold(settings.MessageThreshold.ToString()),
|
||||
return GetText(strs.spam_stats(Format.Bold(settings.MessageThreshold.ToString()),
|
||||
Format.Bold(settings.Action + add),
|
||||
ignoredString));
|
||||
}
|
||||
@@ -273,14 +269,11 @@ public partial class Administration
|
||||
var actionString = Format.Bold(stats.AntiRaidSettings.Action.ToString());
|
||||
|
||||
if (stats.AntiRaidSettings.PunishDuration > 0)
|
||||
{
|
||||
actionString += $" **({TimeSpan.FromMinutes(stats.AntiRaidSettings.PunishDuration):hh\\hmm\\m})**";
|
||||
}
|
||||
|
||||
return GetText(strs.raid_stats(
|
||||
Format.Bold(stats.AntiRaidSettings.UserThreshold.ToString()),
|
||||
return GetText(strs.raid_stats(Format.Bold(stats.AntiRaidSettings.UserThreshold.ToString()),
|
||||
Format.Bold(stats.AntiRaidSettings.Seconds.ToString()),
|
||||
actionString));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using ITextChannel = Discord.ITextChannel;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -12,7 +11,8 @@ public partial class Administration
|
||||
private static readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
|
||||
|
||||
//delets her own messages, no perm required
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Prune(string parameter = null)
|
||||
{
|
||||
@@ -24,8 +24,10 @@ public partial class Administration
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id);
|
||||
ctx.Message.DeleteAfter(3);
|
||||
}
|
||||
|
||||
// prune x
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(ChannelPerm.ManageMessages)]
|
||||
[BotPerm(ChannelPerm.ManageMessages)]
|
||||
@@ -45,7 +47,8 @@ public partial class Administration
|
||||
}
|
||||
|
||||
//prune @user [x]
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(ChannelPerm.ManageMessages)]
|
||||
[BotPerm(ChannelPerm.ManageMessages)]
|
||||
@@ -54,7 +57,8 @@ public partial class Administration
|
||||
=> Prune(user.Id, count, parameter);
|
||||
|
||||
//prune userid [x]
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(ChannelPerm.ManageMessages)]
|
||||
[BotPerm(ChannelPerm.ManageMessages)]
|
||||
@@ -71,9 +75,13 @@ public partial class Administration
|
||||
count = 1000;
|
||||
|
||||
if (parameter is "-s" or "--safe")
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel, count, m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < twoWeeks && !m.IsPinned);
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
count,
|
||||
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < twoWeeks && !m.IsPinned);
|
||||
else
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel, count, m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < twoWeeks);
|
||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||
count,
|
||||
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < twoWeeks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,9 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System.Net;
|
||||
using Color = SixLabors.ImageSharp.Color;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -10,9 +11,10 @@ public partial class Administration
|
||||
{
|
||||
public class RoleCommands : NadekoSubmodule<RoleCommandsService>
|
||||
{
|
||||
private IServiceProvider _services;
|
||||
public enum Exclude { Excl }
|
||||
|
||||
private IServiceProvider _services;
|
||||
|
||||
public RoleCommands(IServiceProvider services)
|
||||
=> _services = services;
|
||||
|
||||
@@ -20,34 +22,32 @@ public partial class Administration
|
||||
{
|
||||
var target = messageId is { } msgId
|
||||
? await ctx.Channel.GetMessageAsync(msgId)
|
||||
: (await ctx.Channel.GetMessagesAsync(2).FlattenAsync())
|
||||
.Skip(1)
|
||||
.FirstOrDefault();
|
||||
: (await ctx.Channel.GetMessagesAsync(2).FlattenAsync()).Skip(1).FirstOrDefault();
|
||||
|
||||
if (input.Length % 2 != 0)
|
||||
return;
|
||||
|
||||
var all = await input
|
||||
.Chunk(input.Length / 2)
|
||||
.Select(async x =>
|
||||
{
|
||||
var inputRoleStr = x.First();
|
||||
var roleReader = new RoleTypeReader<SocketRole>();
|
||||
var roleResult = await roleReader.ReadAsync(ctx, inputRoleStr, _services);
|
||||
if (!roleResult.IsSuccess)
|
||||
{
|
||||
Log.Warning("Role {0} not found.", inputRoleStr);
|
||||
return null;
|
||||
}
|
||||
var role = (IRole)roleResult.BestMatch;
|
||||
if (role.Position > ((IGuildUser)ctx.User).GetRoles().Select(r => r.Position).Max()
|
||||
&& ctx.User.Id != ctx.Guild.OwnerId)
|
||||
return null;
|
||||
var emote = x.Last().ToIEmote();
|
||||
return new { role, emote };
|
||||
})
|
||||
.Where(x => x != null)
|
||||
.WhenAll();
|
||||
var all = await input.Chunk(input.Length / 2)
|
||||
.Select(async x =>
|
||||
{
|
||||
var inputRoleStr = x.First();
|
||||
var roleReader = new RoleTypeReader<SocketRole>();
|
||||
var roleResult = await roleReader.ReadAsync(ctx, inputRoleStr, _services);
|
||||
if (!roleResult.IsSuccess)
|
||||
{
|
||||
Log.Warning("Role {0} not found.", inputRoleStr);
|
||||
return null;
|
||||
}
|
||||
|
||||
var role = (IRole)roleResult.BestMatch;
|
||||
if (role.Position > ((IGuildUser)ctx.User).GetRoles().Select(r => r.Position).Max()
|
||||
&& ctx.User.Id != ctx.Guild.OwnerId)
|
||||
return null;
|
||||
var emote = x.Last().ToIEmote();
|
||||
return new { role, emote };
|
||||
})
|
||||
.Where(x => x != null)
|
||||
.WhenAll();
|
||||
|
||||
if (!all.Any())
|
||||
return;
|
||||
@@ -56,12 +56,10 @@ public partial class Administration
|
||||
{
|
||||
try
|
||||
{
|
||||
await target.AddReactionAsync(x.emote, new()
|
||||
{
|
||||
RetryMode = RetryMode.Retry502 | RetryMode.RetryRatelimit
|
||||
});
|
||||
await target.AddReactionAsync(x.emote,
|
||||
new() { RetryMode = RetryMode.Retry502 | RetryMode.RetryRatelimit });
|
||||
}
|
||||
catch (Discord.Net.HttpException ex) when(ex.HttpCode == HttpStatusCode.BadRequest)
|
||||
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.reaction_cant_access(Format.Code(x.emote.ToString())));
|
||||
return;
|
||||
@@ -70,75 +68,75 @@ public partial class Administration
|
||||
await Task.Delay(500);
|
||||
}
|
||||
|
||||
if (_service.Add(ctx.Guild.Id, new()
|
||||
{
|
||||
Exclusive = exclusive,
|
||||
MessageId = target.Id,
|
||||
ChannelId = target.Channel.Id,
|
||||
ReactionRoles = all.Select(x =>
|
||||
if (_service.Add(ctx.Guild.Id,
|
||||
new()
|
||||
{
|
||||
return new ReactionRole()
|
||||
{
|
||||
EmoteName = x.emote.ToString(),
|
||||
RoleId = x.role.Id,
|
||||
};
|
||||
}).ToList(),
|
||||
}))
|
||||
{
|
||||
Exclusive = exclusive,
|
||||
MessageId = target.Id,
|
||||
ChannelId = target.Channel.Id,
|
||||
ReactionRoles = all.Select(x =>
|
||||
{
|
||||
return new ReactionRole
|
||||
{
|
||||
EmoteName = x.emote.ToString(), RoleId = x.role.Id
|
||||
};
|
||||
})
|
||||
.ToList()
|
||||
}))
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.reaction_roles_full);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public Task ReactionRoles(ulong messageId, params string[] input) =>
|
||||
InternalReactionRoles(false, messageId, input);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task ReactionRoles(ulong messageId, params string[] input)
|
||||
=> InternalReactionRoles(false, messageId, input);
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(1)]
|
||||
public Task ReactionRoles(ulong messageId, Exclude _, params string[] input) =>
|
||||
InternalReactionRoles(true, messageId, input);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task ReactionRoles(ulong messageId, Exclude _, params string[] input)
|
||||
=> InternalReactionRoles(true, messageId, input);
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public Task ReactionRoles(params string[] input) =>
|
||||
InternalReactionRoles(false, null, input);
|
||||
public Task ReactionRoles(params string[] input)
|
||||
=> InternalReactionRoles(false, null, input);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(1)]
|
||||
public Task ReactionRoles(Exclude _, params string[] input) =>
|
||||
InternalReactionRoles(true, null, input);
|
||||
public Task ReactionRoles(Exclude _, params string[] input)
|
||||
=> InternalReactionRoles(true, null, input);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ReactionRolesList()
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor();
|
||||
if (!_service.Get(ctx.Guild.Id, out var rrs) ||
|
||||
!rrs.Any())
|
||||
var embed = _eb.Create().WithOkColor();
|
||||
if (!_service.Get(ctx.Guild.Id, out var rrs) || !rrs.Any())
|
||||
{
|
||||
embed.WithDescription(GetText(strs.no_reaction_roles));
|
||||
}
|
||||
@@ -149,37 +147,33 @@ public partial class Administration
|
||||
{
|
||||
var ch = g.GetTextChannel(rr.ChannelId);
|
||||
IUserMessage msg = null;
|
||||
if (ch is not null)
|
||||
{
|
||||
msg = await ch.GetMessageAsync(rr.MessageId) as IUserMessage;
|
||||
}
|
||||
if (ch is not null) msg = await ch.GetMessageAsync(rr.MessageId) as IUserMessage;
|
||||
var content = msg?.Content.TrimTo(30) ?? "DELETED!";
|
||||
embed.AddField($"**{rr.Index + 1}.** {ch?.Name ?? "DELETED!"}",
|
||||
GetText(strs.reaction_roles_message(rr.ReactionRoles?.Count ?? 0, content)));
|
||||
}
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ReactionRolesRemove(int index)
|
||||
{
|
||||
if (index < 1 ||
|
||||
!_service.Get(ctx.Guild.Id, out var rrs) ||
|
||||
!rrs.Any() || rrs.Count < index)
|
||||
{
|
||||
if (index < 1 || !_service.Get(ctx.Guild.Id, out var rrs) || !rrs.Any() || rrs.Count < index)
|
||||
return;
|
||||
}
|
||||
index--;
|
||||
var rr = rrs[index];
|
||||
_service.Remove(ctx.Guild.Id, index);
|
||||
await ReplyConfirmLocalizedAsync(strs.reaction_role_removed(index + 1));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -193,9 +187,8 @@ public partial class Administration
|
||||
{
|
||||
await targetUser.AddRoleAsync(roleToAdd);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(
|
||||
strs.setrole(Format.Bold(roleToAdd.Name), Format.Bold(targetUser.ToString()))
|
||||
);
|
||||
await ReplyConfirmLocalizedAsync(strs.setrole(Format.Bold(roleToAdd.Name),
|
||||
Format.Bold(targetUser.ToString())));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -204,19 +197,22 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task RemoveRole(IGuildUser targetUser, [Leftover] IRole roleToRemove)
|
||||
{
|
||||
var runnerUser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != runnerUser.Guild.OwnerId && runnerUser.GetRoles().Max(x => x.Position) <= roleToRemove.Position)
|
||||
if (ctx.User.Id != runnerUser.Guild.OwnerId
|
||||
&& runnerUser.GetRoles().Max(x => x.Position) <= roleToRemove.Position)
|
||||
return;
|
||||
try
|
||||
{
|
||||
await targetUser.RemoveRoleAsync(roleToRemove);
|
||||
await ReplyConfirmLocalizedAsync(strs.remrole(Format.Bold(roleToRemove.Name), Format.Bold(targetUser.ToString())));
|
||||
await ReplyConfirmLocalizedAsync(strs.remrole(Format.Bold(roleToRemove.Name),
|
||||
Format.Bold(targetUser.ToString())));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -224,11 +220,12 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task RenameRole(IRole roleToEdit, [Leftover]string newname)
|
||||
public async Task RenameRole(IRole roleToEdit, [Leftover] string newname)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= roleToEdit.Position)
|
||||
@@ -240,6 +237,7 @@ public partial class Administration
|
||||
await ReplyErrorLocalizedAsync(strs.renrole_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
await roleToEdit.ModifyAsync(g => g.Name = newname);
|
||||
await ReplyConfirmLocalizedAsync(strs.renrole);
|
||||
}
|
||||
@@ -249,7 +247,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -257,11 +256,11 @@ public partial class Administration
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
|
||||
var userRoles = user.GetRoles()
|
||||
.Where(x => !x.IsManaged && x != x.Guild.EveryoneRole)
|
||||
.ToList();
|
||||
|
||||
if (user.Id == ctx.Guild.OwnerId || (ctx.User.Id != ctx.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position)))
|
||||
var userRoles = user.GetRoles().Where(x => !x.IsManaged && x != x.Guild.EveryoneRole).ToList();
|
||||
|
||||
if (user.Id == ctx.Guild.OwnerId
|
||||
|| (ctx.User.Id != ctx.Guild.OwnerId
|
||||
&& guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position)))
|
||||
return;
|
||||
try
|
||||
{
|
||||
@@ -274,7 +273,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -287,22 +287,23 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.cr(Format.Bold(r.Name)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task DeleteRole([Leftover] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != guser.Guild.OwnerId
|
||||
&& guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
return;
|
||||
|
||||
await role.DeleteAsync();
|
||||
await ReplyConfirmLocalizedAsync(strs.dr(Format.Bold(role.Name)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -311,32 +312,30 @@ public partial class Administration
|
||||
var newHoisted = !role.IsHoisted;
|
||||
await role.ModifyAsync(r => r.Hoist = newHoisted);
|
||||
if (newHoisted)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.rolehoist_enabled(Format.Bold(role.Name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.rolehoist_disabled(Format.Bold(role.Name)));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[Priority(1)]
|
||||
public async Task RoleColor([Leftover] IRole role)
|
||||
=> await SendConfirmAsync("Role Color", role.Color.RawValue.ToString("x6"));
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public async Task RoleColor(SixLabors.ImageSharp.Color color, [Leftover]IRole role)
|
||||
public async Task RoleColor(Color color, [Leftover] IRole role)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rgba32 = color.ToPixel<Rgba32>();
|
||||
await role.ModifyAsync(r => r.Color = new Color(rgba32.R, rgba32.G, rgba32.B));
|
||||
await role.ModifyAsync(r => r.Color = new Discord.Color(rgba32.R, rgba32.G, rgba32.B));
|
||||
await ReplyConfirmLocalizedAsync(strs.rc(Format.Bold(role.Name)));
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -345,4 +344,4 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using System.Text;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using System.Text;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -9,7 +9,8 @@ public partial class Administration
|
||||
[Group]
|
||||
public class SelfAssignedRolesCommands : NadekoSubmodule<SelfAssignedRolesService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[BotPerm(GuildPerm.ManageMessages)]
|
||||
@@ -18,24 +19,22 @@ public partial class Administration
|
||||
var newVal = _service.ToggleAdSarm(ctx.Guild.Id);
|
||||
|
||||
if (newVal)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.adsarm_enable(Prefix));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.adsarm_disable(Prefix));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(1)]
|
||||
public Task Asar([Leftover] IRole role) =>
|
||||
Asar(0, role);
|
||||
public Task Asar([Leftover] IRole role)
|
||||
=> Asar(0, role);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -49,16 +48,14 @@ public partial class Administration
|
||||
var succ = _service.AddNew(ctx.Guild.Id, role, group);
|
||||
|
||||
if (succ)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.role_added(Format.Bold(role.Name), Format.Bold(group.ToString())));
|
||||
}
|
||||
await ReplyConfirmLocalizedAsync(strs.role_added(Format.Bold(role.Name),
|
||||
Format.Bold(group.ToString())));
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.role_in_list(Format.Bold(role.Name)));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -70,16 +67,14 @@ public partial class Administration
|
||||
var set = await _service.SetNameAsync(ctx.Guild.Id, group, name);
|
||||
|
||||
if (set)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.group_name_added(Format.Bold(group.ToString()), Format.Bold(name.ToString())));
|
||||
}
|
||||
await ReplyConfirmLocalizedAsync(
|
||||
strs.group_name_added(Format.Bold(group.ToString()), Format.Bold(name)));
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.group_name_removed(Format.Bold(group.ToString())));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async Task Rsar([Leftover] IRole role)
|
||||
@@ -90,16 +85,13 @@ public partial class Administration
|
||||
|
||||
var success = _service.RemoveSar(role.Guild.Id, role.Id);
|
||||
if (!success)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.self_assign_not);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.self_assign_rem(Format.Bold(role.Name)));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Lsar(int page = 1)
|
||||
{
|
||||
@@ -108,57 +100,55 @@ public partial class Administration
|
||||
|
||||
var (exclusive, roles, groups) = _service.GetRoles(ctx.Guild);
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page, cur =>
|
||||
{
|
||||
var rolesStr = new StringBuilder();
|
||||
var roleGroups = roles
|
||||
.OrderBy(x => x.Model.Group)
|
||||
.Skip(cur * 20)
|
||||
.Take(20)
|
||||
.GroupBy(x => x.Model.Group)
|
||||
.OrderBy(x => x.Key);
|
||||
|
||||
foreach (var kvp in roleGroups)
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
cur =>
|
||||
{
|
||||
var groupNameText = string.Empty;
|
||||
if (!groups.TryGetValue(kvp.Key, out var name))
|
||||
{
|
||||
groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key)));
|
||||
}
|
||||
else
|
||||
{
|
||||
groupNameText = Format.Bold($"{kvp.Key} - {name.TrimTo(25, true)}");
|
||||
}
|
||||
var rolesStr = new StringBuilder();
|
||||
var roleGroups = roles.OrderBy(x => x.Model.Group)
|
||||
.Skip(cur * 20)
|
||||
.Take(20)
|
||||
.GroupBy(x => x.Model.Group)
|
||||
.OrderBy(x => x.Key);
|
||||
|
||||
rolesStr.AppendLine("\t\t\t\t ⟪" + groupNameText + "⟫");
|
||||
foreach (var (model, role) in kvp.AsEnumerable())
|
||||
foreach (var kvp in roleGroups)
|
||||
{
|
||||
if (role is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var groupNameText = string.Empty;
|
||||
if (!groups.TryGetValue(kvp.Key, out var name))
|
||||
groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key)));
|
||||
else
|
||||
{
|
||||
// first character is invisible space
|
||||
if (model.LevelRequirement == 0)
|
||||
rolesStr.AppendLine(" " + role.Name);
|
||||
else
|
||||
rolesStr.AppendLine(" " + role.Name + $" (lvl {model.LevelRequirement}+)");
|
||||
}
|
||||
}
|
||||
rolesStr.AppendLine();
|
||||
}
|
||||
groupNameText = Format.Bold($"{kvp.Key} - {name.TrimTo(25, true)}");
|
||||
|
||||
return _eb.Create().WithOkColor()
|
||||
.WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count()))))
|
||||
.WithDescription(rolesStr.ToString())
|
||||
.WithFooter(exclusive
|
||||
? GetText(strs.self_assign_are_exclusive)
|
||||
: GetText(strs.self_assign_are_not_exclusive));
|
||||
}, roles.Count(), 20);
|
||||
rolesStr.AppendLine("\t\t\t\t ⟪" + groupNameText + "⟫");
|
||||
foreach (var (model, role) in kvp.AsEnumerable())
|
||||
if (role is null)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
// first character is invisible space
|
||||
if (model.LevelRequirement == 0)
|
||||
rolesStr.AppendLine(" " + role.Name);
|
||||
else
|
||||
rolesStr.AppendLine(" " + role.Name + $" (lvl {model.LevelRequirement}+)");
|
||||
}
|
||||
|
||||
rolesStr.AppendLine();
|
||||
}
|
||||
|
||||
return _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count()))))
|
||||
.WithDescription(rolesStr.ToString())
|
||||
.WithFooter(exclusive
|
||||
? GetText(strs.self_assign_are_exclusive)
|
||||
: GetText(strs.self_assign_are_not_exclusive));
|
||||
},
|
||||
roles.Count(),
|
||||
20);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -171,7 +161,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.self_assign_no_excl);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
@@ -188,12 +179,12 @@ public partial class Administration
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.self_assign_level_req(
|
||||
Format.Bold(role.Name),
|
||||
await ReplyConfirmLocalizedAsync(strs.self_assign_level_req(Format.Bold(role.Name),
|
||||
Format.Bold(level.ToString())));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iam([Leftover] IRole role)
|
||||
{
|
||||
@@ -203,25 +194,15 @@ public partial class Administration
|
||||
|
||||
IUserMessage msg;
|
||||
if (result == SelfAssignedRolesService.AssignResult.Err_Not_Assignable)
|
||||
{
|
||||
msg = await ReplyErrorLocalizedAsync(strs.self_assign_not);
|
||||
}
|
||||
else if (result == SelfAssignedRolesService.AssignResult.Err_Lvl_Req)
|
||||
{
|
||||
msg = await ReplyErrorLocalizedAsync(strs.self_assign_not_level(Format.Bold(extra.ToString())));
|
||||
}
|
||||
else if (result == SelfAssignedRolesService.AssignResult.Err_Already_Have)
|
||||
{
|
||||
msg = await ReplyErrorLocalizedAsync(strs.self_assign_already(Format.Bold(role.Name)));
|
||||
}
|
||||
else if (result == SelfAssignedRolesService.AssignResult.Err_Not_Perms)
|
||||
{
|
||||
msg = await ReplyErrorLocalizedAsync(strs.self_assign_perms);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = await ReplyConfirmLocalizedAsync(strs.self_assign_success(Format.Bold(role.Name)));
|
||||
}
|
||||
|
||||
if (autoDelete)
|
||||
{
|
||||
@@ -230,7 +211,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iamnot([Leftover] IRole role)
|
||||
{
|
||||
@@ -240,21 +222,13 @@ public partial class Administration
|
||||
|
||||
IUserMessage msg;
|
||||
if (result == SelfAssignedRolesService.RemoveResult.Err_Not_Assignable)
|
||||
{
|
||||
msg = await ReplyErrorLocalizedAsync(strs.self_assign_not);
|
||||
}
|
||||
else if (result == SelfAssignedRolesService.RemoveResult.Err_Not_Have)
|
||||
{
|
||||
msg = await ReplyErrorLocalizedAsync(strs.self_assign_not_have(Format.Bold(role.Name)));
|
||||
}
|
||||
else if (result == SelfAssignedRolesService.RemoveResult.Err_Not_Perms)
|
||||
{
|
||||
msg = await ReplyErrorLocalizedAsync(strs.self_assign_perms);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = await ReplyConfirmLocalizedAsync(strs.self_assign_remove(Format.Bold(role.Name)));
|
||||
}
|
||||
|
||||
if (autoDelete)
|
||||
{
|
||||
@@ -263,4 +237,4 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -9,6 +9,14 @@ public partial class Administration
|
||||
[Group]
|
||||
public class SelfCommands : NadekoSubmodule<SelfService>
|
||||
{
|
||||
public enum SettableUserStatus
|
||||
{
|
||||
Online,
|
||||
Invisible,
|
||||
Idle,
|
||||
Dnd
|
||||
}
|
||||
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotStrings _strings;
|
||||
private readonly ICoordinator _coord;
|
||||
@@ -20,7 +28,8 @@ public partial class Administration
|
||||
_coord = coord;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
@@ -30,7 +39,7 @@ public partial class Administration
|
||||
return;
|
||||
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
var cmd = new AutoCommand()
|
||||
var cmd = new AutoCommand
|
||||
{
|
||||
CommandText = cmdText,
|
||||
ChannelId = ctx.Channel.Id,
|
||||
@@ -39,18 +48,22 @@ public partial class Administration
|
||||
GuildName = ctx.Guild?.Name,
|
||||
VoiceChannelId = guser.VoiceChannel?.Id,
|
||||
VoiceChannelName = guser.VoiceChannel?.Name,
|
||||
Interval = 0,
|
||||
Interval = 0
|
||||
};
|
||||
_service.AddNewAutoCommand(cmd);
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.scadd))
|
||||
.AddField(GetText(strs.server), cmd.GuildId is null ? $"-" : $"{cmd.GuildName}/{cmd.GuildId}", true)
|
||||
.AddField(GetText(strs.channel), $"{cmd.ChannelName}/{cmd.ChannelId}", true)
|
||||
.AddField(GetText(strs.command_text), cmdText, false));
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.scadd))
|
||||
.AddField(GetText(strs.server),
|
||||
cmd.GuildId is null ? "-" : $"{cmd.GuildName}/{cmd.GuildId}",
|
||||
true)
|
||||
.AddField(GetText(strs.channel), $"{cmd.ChannelName}/{cmd.ChannelId}", true)
|
||||
.AddField(GetText(strs.command_text), cmdText));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
@@ -63,7 +76,7 @@ public partial class Administration
|
||||
return;
|
||||
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
var cmd = new AutoCommand()
|
||||
var cmd = new AutoCommand
|
||||
{
|
||||
CommandText = cmdText,
|
||||
ChannelId = ctx.Channel.Id,
|
||||
@@ -72,14 +85,15 @@ public partial class Administration
|
||||
GuildName = ctx.Guild?.Name,
|
||||
VoiceChannelId = guser.VoiceChannel?.Id,
|
||||
VoiceChannelName = guser.VoiceChannel?.Name,
|
||||
Interval = interval,
|
||||
Interval = interval
|
||||
};
|
||||
_service.AddNewAutoCommand(cmd);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.autocmd_add(Format.Code(Format.Sanitize(cmdText)), cmd.Interval));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartupCommandsList(int page = 1)
|
||||
@@ -87,11 +101,8 @@ public partial class Administration
|
||||
if (page-- < 1)
|
||||
return;
|
||||
|
||||
var scmds = _service.GetStartupCommands()
|
||||
.Skip(page * 5)
|
||||
.Take(5)
|
||||
.ToList();
|
||||
|
||||
var scmds = _service.GetStartupCommands().Skip(page * 5).Take(5).ToList();
|
||||
|
||||
if (scmds.Count == 0)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.startcmdlist_none);
|
||||
@@ -99,19 +110,19 @@ public partial class Administration
|
||||
else
|
||||
{
|
||||
var i = 0;
|
||||
await SendConfirmAsync(
|
||||
text: string.Join("\n", scmds
|
||||
.Select(x => $@"```css
|
||||
await SendConfirmAsync(text: string.Join("\n",
|
||||
scmds.Select(x => $@"```css
|
||||
#{++i + (page * 5)}
|
||||
[{GetText(strs.server)}]: {(x.GuildId.HasValue ? $"{x.GuildName} #{x.GuildId}" : "-")}
|
||||
[{GetText(strs.channel)}]: {x.ChannelName} #{x.ChannelId}
|
||||
[{GetText(strs.command_text)}]: {x.CommandText}```")),
|
||||
title: string.Empty,
|
||||
footer: GetText(strs.page(page + 1)));
|
||||
title: string.Empty,
|
||||
footer: GetText(strs.page(page + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task AutoCommandsList(int page = 1)
|
||||
@@ -119,10 +130,7 @@ public partial class Administration
|
||||
if (page-- < 1)
|
||||
return;
|
||||
|
||||
var scmds = _service.GetAutoCommands()
|
||||
.Skip(page * 5)
|
||||
.Take(5)
|
||||
.ToList();
|
||||
var scmds = _service.GetAutoCommands().Skip(page * 5).Take(5).ToList();
|
||||
if (!scmds.Any())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.autocmdlist_none);
|
||||
@@ -130,23 +138,23 @@ public partial class Administration
|
||||
else
|
||||
{
|
||||
var i = 0;
|
||||
await SendConfirmAsync(
|
||||
text: string.Join("\n", scmds
|
||||
.Select(x => $@"```css
|
||||
await SendConfirmAsync(text: string.Join("\n",
|
||||
scmds.Select(x => $@"```css
|
||||
#{++i + (page * 5)}
|
||||
[{GetText(strs.server)}]: {(x.GuildId.HasValue ? $"{x.GuildName} #{x.GuildId}" : "-")}
|
||||
[{GetText(strs.channel)}]: {x.ChannelName} #{x.ChannelId}
|
||||
{GetIntervalText(x.Interval)}
|
||||
[{GetText(strs.command_text)}]: {x.CommandText}```")),
|
||||
title: string.Empty,
|
||||
footer: GetText(strs.page(page + 1)));
|
||||
title: string.Empty,
|
||||
footer: GetText(strs.page(page + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
private string GetIntervalText(int interval)
|
||||
=> $"[{GetText(strs.interval)}]: {interval}";
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Wait(int miliseconds)
|
||||
{
|
||||
@@ -162,8 +170,9 @@ public partial class Administration
|
||||
|
||||
await Task.Delay(miliseconds);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
@@ -174,11 +183,12 @@ public partial class Administration
|
||||
await ReplyErrorLocalizedAsync(strs.acrm_fail);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartupCommandRemove([Leftover] int index)
|
||||
@@ -189,7 +199,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.scrm);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[OwnerOnly]
|
||||
@@ -200,7 +211,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.startcmds_cleared);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardMessages()
|
||||
{
|
||||
@@ -212,7 +224,8 @@ public partial class Administration
|
||||
await ReplyPendingLocalizedAsync(strs.fwdm_stop);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardToAll()
|
||||
{
|
||||
@@ -222,10 +235,10 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.fwall_start);
|
||||
else
|
||||
await ReplyPendingLocalizedAsync(strs.fwall_stop);
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
public async Task ShardStats(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
@@ -233,35 +246,36 @@ public partial class Administration
|
||||
|
||||
var statuses = _coord.GetAllShardStatuses();
|
||||
|
||||
var status = string.Join(" : ", statuses
|
||||
.Select(x => (ConnectionStateToEmoji(x), x))
|
||||
.GroupBy(x => x.Item1)
|
||||
.Select(x => $"`{x.Count()} {x.Key}`")
|
||||
.ToArray());
|
||||
var status = string.Join(" : ",
|
||||
statuses.Select(x => (ConnectionStateToEmoji(x), x))
|
||||
.GroupBy(x => x.Item1)
|
||||
.Select(x => $"`{x.Count()} {x.Key}`")
|
||||
.ToArray());
|
||||
|
||||
var allShardStrings = statuses
|
||||
.Select(st =>
|
||||
var allShardStrings = statuses.Select(st =>
|
||||
{
|
||||
var stateStr = ConnectionStateToEmoji(st);
|
||||
var timeDiff = DateTime.UtcNow - st.LastUpdate;
|
||||
var maxGuildCountLength =
|
||||
statuses.Max(x => x.GuildCount).ToString().Length;
|
||||
return $"`{stateStr} "
|
||||
+ $"| #{st.ShardId.ToString().PadBoth(3)} "
|
||||
+ $"| {timeDiff:mm\\:ss} "
|
||||
+ $"| {st.GuildCount.ToString().PadBoth(maxGuildCountLength)} `";
|
||||
})
|
||||
.ToArray();
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
curPage =>
|
||||
{
|
||||
var stateStr = ConnectionStateToEmoji(st);
|
||||
var timeDiff = DateTime.UtcNow - st.LastUpdate;
|
||||
var maxGuildCountLength = statuses.Max(x => x.GuildCount).ToString().Length;
|
||||
return $"`{stateStr} " +
|
||||
$"| #{st.ShardId.ToString().PadBoth(3)} " +
|
||||
$"| {timeDiff:mm\\:ss} " +
|
||||
$"| {st.GuildCount.ToString().PadBoth(maxGuildCountLength)} `";
|
||||
})
|
||||
.ToArray();
|
||||
await ctx.SendPaginatedConfirmAsync(page, curPage =>
|
||||
{
|
||||
var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25));
|
||||
var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
str = GetText(strs.no_shards_on_page);
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
str = GetText(strs.no_shards_on_page);
|
||||
|
||||
return _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithDescription($"{status}\n\n{str}");
|
||||
}, allShardStrings.Length, 25);
|
||||
return _eb.Create().WithOkColor().WithDescription($"{status}\n\n{str}");
|
||||
},
|
||||
allShardStrings.Length,
|
||||
25);
|
||||
}
|
||||
|
||||
private static string ConnectionStateToEmoji(ShardStatus status)
|
||||
@@ -276,28 +290,27 @@ public partial class Administration
|
||||
};
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task RestartShard(int shardId)
|
||||
{
|
||||
var success = _coord.RestartShard(shardId);
|
||||
if (success)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.shard_reconnecting(Format.Bold("#" + shardId)));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_shard_id);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public Task Leave([Leftover] string guildStr)
|
||||
=> _service.LeaveGuild(guildStr);
|
||||
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Die(bool graceful = false)
|
||||
{
|
||||
@@ -309,11 +322,13 @@ public partial class Administration
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
await Task.Delay(2000);
|
||||
_coord.Die(graceful);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Restart()
|
||||
{
|
||||
@@ -324,10 +339,12 @@ public partial class Administration
|
||||
return;
|
||||
}
|
||||
|
||||
try { await ReplyConfirmLocalizedAsync(strs.restarting); } catch { }
|
||||
try { await ReplyConfirmLocalizedAsync(strs.restarting); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetName([Leftover] string newName)
|
||||
{
|
||||
@@ -346,7 +363,8 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.bot_name(Format.Bold(newName)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[UserPerm(GuildPerm.ManageNicknames)]
|
||||
[BotPerm(GuildPerm.ChangeNickname)]
|
||||
[Priority(0)]
|
||||
@@ -360,26 +378,28 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.bot_nick(Format.Bold(newNick) ?? "-"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[BotPerm(GuildPerm.ManageNicknames)]
|
||||
[UserPerm(GuildPerm.ManageNicknames)]
|
||||
[Priority(1)]
|
||||
public async Task SetNick(IGuildUser gu, [Leftover] string newNick = null)
|
||||
{
|
||||
var sg = (SocketGuild) ctx.Guild;
|
||||
if (sg.OwnerId == gu.Id ||
|
||||
gu.GetRoles().Max(r => r.Position) >= sg.CurrentUser.GetRoles().Max(r => r.Position))
|
||||
var sg = (SocketGuild)ctx.Guild;
|
||||
if (sg.OwnerId == gu.Id
|
||||
|| gu.GetRoles().Max(r => r.Position) >= sg.CurrentUser.GetRoles().Max(r => r.Position))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuf_perms_i);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await gu.ModifyAsync(u => u.Nickname = newNick);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-"));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetStatus([Leftover] SettableUserStatus status)
|
||||
{
|
||||
@@ -388,32 +408,30 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.bot_status(Format.Bold(status.ToString())));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetAvatar([Leftover] string img = null)
|
||||
{
|
||||
var success = await _service.SetAvatar(img);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.set_avatar);
|
||||
}
|
||||
if (success) await ReplyConfirmLocalizedAsync(strs.set_avatar);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetGame(ActivityType type, [Leftover] string game = null)
|
||||
{
|
||||
var rep = new ReplacementBuilder()
|
||||
.WithDefault(Context)
|
||||
.Build();
|
||||
var rep = new ReplacementBuilder().WithDefault(Context).Build();
|
||||
|
||||
await _service.SetGameAsync(game is null ? game : rep.Replace(game), type);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.set_game);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetStream(string url, [Leftover] string name = null)
|
||||
{
|
||||
@@ -424,23 +442,22 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.set_stream);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task Send(string where, [Leftover] SmartText text = null)
|
||||
{
|
||||
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 is null)
|
||||
return;
|
||||
|
||||
var rep = new ReplacementBuilder()
|
||||
.WithDefault(Context)
|
||||
.Build();
|
||||
var rep = new ReplacementBuilder().WithDefault(Context).Build();
|
||||
|
||||
if (ids[1].ToUpperInvariant().StartsWith("C:", StringComparison.InvariantCulture))
|
||||
{
|
||||
@@ -450,7 +467,7 @@ public partial class Administration
|
||||
return;
|
||||
|
||||
text = rep.Replace(text);
|
||||
await ch.SendAsync(text, sanitizeAll: false);
|
||||
await ch.SendAsync(text);
|
||||
}
|
||||
else if (ids[1].ToUpperInvariant().StartsWith("U:", StringComparison.InvariantCulture))
|
||||
{
|
||||
@@ -468,27 +485,30 @@ public partial class Administration
|
||||
await ReplyErrorLocalizedAsync(strs.invalid_format);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.message_sent);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ImagesReload()
|
||||
{
|
||||
await _service.ReloadImagesAsync();
|
||||
await ReplyConfirmLocalizedAsync(strs.images_loading);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task StringsReload()
|
||||
{
|
||||
_strings.Reload();
|
||||
await ReplyConfirmLocalizedAsync(strs.bot_strings_reloaded);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task CoordReload()
|
||||
{
|
||||
@@ -512,13 +532,5 @@ public partial class Administration
|
||||
|
||||
return UserStatus.Online;
|
||||
}
|
||||
|
||||
public enum SettableUserStatus
|
||||
{
|
||||
Online,
|
||||
Invisible,
|
||||
Idle,
|
||||
Dnd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -13,19 +13,20 @@ public class AdministrationService : INService
|
||||
private readonly DbService _db;
|
||||
private readonly ILogCommandService _logService;
|
||||
|
||||
public AdministrationService(Bot bot, CommandHandler cmdHandler, DbService db, ILogCommandService logService)
|
||||
public AdministrationService(
|
||||
Bot bot,
|
||||
CommandHandler cmdHandler,
|
||||
DbService db,
|
||||
ILogCommandService logService)
|
||||
{
|
||||
_db = db;
|
||||
_logService = logService;
|
||||
|
||||
DeleteMessagesOnCommand = new(bot.AllGuildConfigs
|
||||
.Where(g => g.DeleteMessageOnCommand)
|
||||
.Select(g => g.GuildId));
|
||||
DeleteMessagesOnCommand = new(bot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
||||
|
||||
DeleteMessagesOnCommandChannels = new(bot.AllGuildConfigs
|
||||
.SelectMany(x => x.DelMsgOnCmdChannels)
|
||||
.ToDictionary(x => x.ChannelId, x => x.State)
|
||||
.ToConcurrent());
|
||||
DeleteMessagesOnCommandChannels = new(bot.AllGuildConfigs.SelectMany(x => x.DelMsgOnCmdChannels)
|
||||
.ToDictionary(x => x.ChannelId, x => x.State)
|
||||
.ToConcurrent());
|
||||
|
||||
cmdHandler.CommandExecuted += DelMsgOnCmd_Handler;
|
||||
}
|
||||
@@ -33,8 +34,7 @@ public class AdministrationService : INService
|
||||
public (bool DelMsgOnCmd, IEnumerable<DelMsgOnCmdChannel> channels) GetDelMsgOnCmdData(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId,
|
||||
set => set.Include(x => x.DelMsgOnCmdChannels));
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.DelMsgOnCmdChannels));
|
||||
|
||||
return (conf.DeleteMessageOnCommand, conf.DelMsgOnCmdChannels);
|
||||
}
|
||||
@@ -52,14 +52,16 @@ public class AdministrationService : INService
|
||||
if (state && cmd.Name != "prune" && cmd.Name != "pick")
|
||||
{
|
||||
_logService.AddDeleteIgnore(msg.Id);
|
||||
try { await msg.DeleteAsync(); } catch { }
|
||||
try { await msg.DeleteAsync(); }
|
||||
catch { }
|
||||
}
|
||||
//if state is false, that means do not do it
|
||||
}
|
||||
else if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick")
|
||||
{
|
||||
_logService.AddDeleteIgnore(msg.Id);
|
||||
try { await msg.DeleteAsync(); } catch { }
|
||||
try { await msg.DeleteAsync(); }
|
||||
catch { }
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
@@ -80,8 +82,7 @@ public class AdministrationService : INService
|
||||
{
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var conf = uow.GuildConfigsForId(guildId,
|
||||
set => set.Include(x => x.DelMsgOnCmdChannels));
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.DelMsgOnCmdChannels));
|
||||
|
||||
var old = conf.DelMsgOnCmdChannels.FirstOrDefault(x => x.ChannelId == chId);
|
||||
if (newState == Administration.State.Inherit)
|
||||
@@ -125,7 +126,6 @@ public class AdministrationService : INService
|
||||
if (!users.Any())
|
||||
return;
|
||||
foreach (var u in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
await u.ModifyAsync(usr => usr.Deaf = value);
|
||||
@@ -134,23 +134,24 @@ public class AdministrationService : INService
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task EditMessage(ICommandContext context, ITextChannel chanl, ulong messageId, string input)
|
||||
public async Task EditMessage(
|
||||
ICommandContext context,
|
||||
ITextChannel chanl,
|
||||
ulong messageId,
|
||||
string input)
|
||||
{
|
||||
var msg = await chanl.GetMessageAsync(messageId);
|
||||
|
||||
if (msg is not IUserMessage umsg || msg.Author.Id != context.Client.CurrentUser.Id)
|
||||
return;
|
||||
|
||||
var rep = new ReplacementBuilder()
|
||||
.WithDefault(context)
|
||||
.Build();
|
||||
var rep = new ReplacementBuilder().WithDefault(context).Build();
|
||||
|
||||
var text = SmartText.CreateFrom(input);
|
||||
text = rep.Replace(text);
|
||||
|
||||
await umsg.EditAsync(text);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,10 @@
|
||||
#nullable disable
|
||||
using System.Threading.Channels;
|
||||
using LinqToDB;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Net;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -18,9 +19,7 @@ public sealed class AutoAssignRoleService : INService
|
||||
private readonly Channel<SocketGuildUser> _assignQueue = Channel.CreateBounded<SocketGuildUser>(
|
||||
new BoundedChannelOptions(100)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.DropOldest,
|
||||
SingleReader = true,
|
||||
SingleWriter = false,
|
||||
FullMode = BoundedChannelFullMode.DropOldest, SingleReader = true, SingleWriter = false
|
||||
});
|
||||
|
||||
public AutoAssignRoleService(DiscordSocketClient client, Bot bot, DbService db)
|
||||
@@ -28,10 +27,10 @@ public sealed class AutoAssignRoleService : INService
|
||||
_client = client;
|
||||
_db = db;
|
||||
|
||||
_autoAssignableRoles = bot.AllGuildConfigs
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.AutoAssignRoleIds))
|
||||
.ToDictionary<GuildConfig, ulong, IReadOnlyList<ulong>>(k => k.GuildId, v => v.GetAutoAssignableRoles())
|
||||
.ToConcurrent();
|
||||
_autoAssignableRoles = bot.AllGuildConfigs.Where(x => !string.IsNullOrWhiteSpace(x.AutoAssignRoleIds))
|
||||
.ToDictionary<GuildConfig, ulong, IReadOnlyList<ulong>>(k => k.GuildId,
|
||||
v => v.GetAutoAssignableRoles())
|
||||
.ToConcurrent();
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@@ -40,14 +39,13 @@ public sealed class AutoAssignRoleService : INService
|
||||
var user = await _assignQueue.Reader.ReadAsync();
|
||||
if (!_autoAssignableRoles.TryGetValue(user.Guild.Id, out var savedRoleIds))
|
||||
continue;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var roleIds = savedRoleIds
|
||||
.Select(roleId => user.Guild.GetRole(roleId))
|
||||
.Where(x => x is not null)
|
||||
.ToList();
|
||||
|
||||
var roleIds = savedRoleIds.Select(roleId => user.Guild.GetRole(roleId))
|
||||
.Where(x => x is not null)
|
||||
.ToList();
|
||||
|
||||
if (roleIds.Any())
|
||||
{
|
||||
await user.AddRolesAsync(roleIds);
|
||||
@@ -59,16 +57,17 @@ public sealed class AutoAssignRoleService : INService
|
||||
"Disabled 'Auto assign role' feature on {GuildName} [{GuildId}] server the roles dont exist",
|
||||
user.Guild.Name,
|
||||
user.Guild.Id);
|
||||
|
||||
|
||||
await DisableAarAsync(user.Guild.Id);
|
||||
}
|
||||
}
|
||||
catch (Discord.Net.HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
|
||||
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden)
|
||||
{
|
||||
Log.Warning("Disabled 'Auto assign role' feature on {GuildName} [{GuildId}] server because I don't have role management permissions",
|
||||
Log.Warning(
|
||||
"Disabled 'Auto assign role' feature on {GuildName} [{GuildId}] server because I don't have role management permissions",
|
||||
user.Guild.Name,
|
||||
user.Guild.Id);
|
||||
|
||||
|
||||
await DisableAarAsync(user.Guild.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -84,16 +83,13 @@ public sealed class AutoAssignRoleService : INService
|
||||
|
||||
private async Task OnClientRoleDeleted(SocketRole role)
|
||||
{
|
||||
if (_autoAssignableRoles.TryGetValue(role.Guild.Id, out var roles)
|
||||
&& roles.Contains(role.Id))
|
||||
{
|
||||
if (_autoAssignableRoles.TryGetValue(role.Guild.Id, out var roles) && roles.Contains(role.Id))
|
||||
await ToggleAarAsync(role.Guild.Id, role.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnClientOnUserJoined(SocketGuildUser user)
|
||||
{
|
||||
if (_autoAssignableRoles.TryGetValue(user.Guild.Id, out _))
|
||||
if (_autoAssignableRoles.TryGetValue(user.Guild.Id, out _))
|
||||
await _assignQueue.Writer.WriteAsync(user);
|
||||
}
|
||||
|
||||
@@ -102,42 +98,40 @@ public sealed class AutoAssignRoleService : INService
|
||||
await using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set);
|
||||
var roles = gc.GetAutoAssignableRoles();
|
||||
if(!roles.Remove(roleId) && roles.Count < 3)
|
||||
if (!roles.Remove(roleId) && roles.Count < 3)
|
||||
roles.Add(roleId);
|
||||
|
||||
|
||||
gc.SetAutoAssignableRoles(roles);
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
|
||||
if (roles.Count > 0)
|
||||
_autoAssignableRoles[guildId] = roles;
|
||||
else
|
||||
_autoAssignableRoles.TryRemove(guildId, out _);
|
||||
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
public async Task DisableAarAsync(ulong guildId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
await uow
|
||||
.GuildConfigs
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.UpdateAsync(_ => new(){ AutoAssignRoleIds = null});
|
||||
|
||||
|
||||
await uow.GuildConfigs.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.UpdateAsync(_ => new() { AutoAssignRoleIds = null });
|
||||
|
||||
_autoAssignableRoles.TryRemove(guildId, out _);
|
||||
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task SetAarRolesAsync(ulong guildId, IEnumerable<ulong> newRoles)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set);
|
||||
gc.SetAutoAssignableRoles(newRoles);
|
||||
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -157,4 +151,4 @@ public static class GuildConfigExtensions
|
||||
|
||||
public static void SetAutoAssignableRoles(this GuildConfig gc, IEnumerable<ulong> roles)
|
||||
=> gc.AutoAssignRoleIds = roles.Join(',');
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
@@ -11,12 +11,18 @@ public class DangerousCommandsService : INService
|
||||
public const string WaifusDeleteSql = @"DELETE FROM WaifuUpdates;
|
||||
DELETE FROM WaifuItem;
|
||||
DELETE FROM WaifuInfo;";
|
||||
public const string WaifuDeleteSql = @"DELETE FROM WaifuUpdates WHERE UserId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
||||
|
||||
public const string WaifuDeleteSql =
|
||||
@"DELETE FROM WaifuUpdates WHERE UserId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
||||
DELETE FROM WaifuItem WHERE WaifuInfoId=(SELECT Id FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0}));
|
||||
UPDATE WaifuInfo SET ClaimerId=NULL WHERE ClaimerId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
||||
DELETE FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0});";
|
||||
public const string CurrencyDeleteSql = "UPDATE DiscordUser SET CurrencyAmount=0; DELETE FROM CurrencyTransactions; DELETE FROM PlantedCurrency;";
|
||||
|
||||
public const string CurrencyDeleteSql =
|
||||
"UPDATE DiscordUser SET CurrencyAmount=0; DELETE FROM CurrencyTransactions; DELETE FROM PlantedCurrency;";
|
||||
|
||||
public const string MusicPlaylistDeleteSql = "DELETE FROM MusicPlaylists;";
|
||||
|
||||
public const string XpDeleteSql = @"DELETE FROM UserXpStats;
|
||||
UPDATE DiscordUser
|
||||
SET ClubId=NULL,
|
||||
@@ -44,19 +50,9 @@ DELETE FROM Clubs;";
|
||||
return res;
|
||||
}
|
||||
|
||||
public class SelectResult
|
||||
{
|
||||
public List<string> ColumnNames { get; set; }
|
||||
public List<string[]> Results { get; set; }
|
||||
}
|
||||
|
||||
public SelectResult SelectSql(string sql)
|
||||
{
|
||||
var result = new SelectResult()
|
||||
{
|
||||
ColumnNames = new(),
|
||||
Results = new(),
|
||||
};
|
||||
var result = new SelectResult { ColumnNames = new(), Results = new() };
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
var conn = uow.Database.GetDbConnection();
|
||||
@@ -65,10 +61,7 @@ DELETE FROM Clubs;";
|
||||
using var reader = cmd.ExecuteReader();
|
||||
if (reader.HasRows)
|
||||
{
|
||||
for (var i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
result.ColumnNames.Add(reader.GetName(i));
|
||||
}
|
||||
for (var i = 0; i < reader.FieldCount; i++) result.ColumnNames.Add(reader.GetName(i));
|
||||
while (reader.Read())
|
||||
{
|
||||
var obj = new object[reader.FieldCount];
|
||||
@@ -83,50 +76,45 @@ DELETE FROM Clubs;";
|
||||
public async Task PurgeUserAsync(ulong userId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
|
||||
// get waifu info
|
||||
var wi = await uow.Set<WaifuInfo>()
|
||||
.FirstOrDefaultAsyncEF(x => x.Waifu.UserId == userId);
|
||||
var wi = await uow.Set<WaifuInfo>().FirstOrDefaultAsyncEF(x => x.Waifu.UserId == userId);
|
||||
|
||||
// if it exists, delete waifu related things
|
||||
if (wi is not null)
|
||||
{
|
||||
// remove updates which have new or old as this waifu
|
||||
await uow
|
||||
.WaifuUpdates
|
||||
.DeleteAsync(wu => wu.New.UserId == userId || wu.Old.UserId == userId);
|
||||
await uow.WaifuUpdates.DeleteAsync(wu => wu.New.UserId == userId || wu.Old.UserId == userId);
|
||||
|
||||
// delete all items this waifu owns
|
||||
await uow
|
||||
.Set<WaifuItem>()
|
||||
.DeleteAsync(x => x.WaifuInfoId == wi.Id);
|
||||
await uow.Set<WaifuItem>().DeleteAsync(x => x.WaifuInfoId == wi.Id);
|
||||
|
||||
// all waifus this waifu claims are released
|
||||
await uow
|
||||
.Set<WaifuInfo>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.Claimer.UserId == userId)
|
||||
.UpdateAsync(x => new() {ClaimerId = null});
|
||||
|
||||
await uow.Set<WaifuInfo>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.Claimer.UserId == userId)
|
||||
.UpdateAsync(x => new() { ClaimerId = null });
|
||||
|
||||
// all affinities set to this waifu are reset
|
||||
await uow
|
||||
.Set<WaifuInfo>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.Affinity.UserId == userId)
|
||||
.UpdateAsync(x => new() {AffinityId = null});
|
||||
await uow.Set<WaifuInfo>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.Affinity.UserId == userId)
|
||||
.UpdateAsync(x => new() { AffinityId = null });
|
||||
}
|
||||
|
||||
// delete guild xp
|
||||
await uow
|
||||
.UserXpStats
|
||||
.DeleteAsync(x => x.UserId == userId);
|
||||
|
||||
await uow.UserXpStats.DeleteAsync(x => x.UserId == userId);
|
||||
|
||||
// delete currency transactions
|
||||
await uow.Set<CurrencyTransaction>()
|
||||
.DeleteAsync(x => x.UserId == userId);
|
||||
|
||||
await uow.Set<CurrencyTransaction>().DeleteAsync(x => x.UserId == userId);
|
||||
|
||||
// delete user, currency, and clubs go away with it
|
||||
await uow.DiscordUser
|
||||
.DeleteAsync(u => u.UserId == userId);
|
||||
await uow.DiscordUser.DeleteAsync(u => u.UserId == userId);
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectResult
|
||||
{
|
||||
public List<string> ColumnNames { get; set; }
|
||||
public List<string[]> Results { get; set; }
|
||||
}
|
||||
}
|
@@ -7,11 +7,10 @@ namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public class DiscordPermOverrideService : INService, ILateBlocker
|
||||
{
|
||||
public int Priority { get; } = int.MaxValue;
|
||||
private readonly DbService _db;
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public int Priority { get; } = int.MaxValue;
|
||||
|
||||
private readonly ConcurrentDictionary<(ulong, string), DiscordPermOverride> _overrides;
|
||||
|
||||
public DiscordPermOverrideService(DbService db, IServiceProvider services)
|
||||
@@ -19,11 +18,10 @@ public class DiscordPermOverrideService : INService, ILateBlocker
|
||||
_db = db;
|
||||
_services = services;
|
||||
using var uow = _db.GetDbContext();
|
||||
_overrides = uow.DiscordPermOverrides
|
||||
.AsNoTracking()
|
||||
.AsEnumerable()
|
||||
.ToDictionary(o => (o.GuildId ?? 0, o.Command), o => o)
|
||||
.ToConcurrent();
|
||||
_overrides = uow.DiscordPermOverrides.AsNoTracking()
|
||||
.AsEnumerable()
|
||||
.ToDictionary(o => (o.GuildId ?? 0, o.Command), o => o)
|
||||
.ToConcurrent();
|
||||
}
|
||||
|
||||
public bool TryGetOverrides(ulong guildId, string commandName, out GuildPerm? perm)
|
||||
@@ -39,8 +37,11 @@ public class DiscordPermOverrideService : INService, ILateBlocker
|
||||
return false;
|
||||
}
|
||||
|
||||
public Task<PreconditionResult> ExecuteOverrides(ICommandContext ctx, CommandInfo command,
|
||||
GuildPerm perms, IServiceProvider services)
|
||||
public Task<PreconditionResult> ExecuteOverrides(
|
||||
ICommandContext ctx,
|
||||
CommandInfo command,
|
||||
GuildPerm perms,
|
||||
IServiceProvider services)
|
||||
{
|
||||
var rupa = new RequireUserPermissionAttribute(perms);
|
||||
return rupa.CheckPermissionsAsync(ctx, command, services);
|
||||
@@ -50,20 +51,14 @@ public class DiscordPermOverrideService : INService, ILateBlocker
|
||||
{
|
||||
commandName = commandName.ToLowerInvariant();
|
||||
await using var uow = _db.GetDbContext();
|
||||
var over = await uow
|
||||
.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command);
|
||||
var over = await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command);
|
||||
|
||||
if (over is null)
|
||||
{
|
||||
uow.Set<DiscordPermOverride>()
|
||||
.Add(over = new() { Command = commandName, Perm = perm, GuildId = guildId, });
|
||||
}
|
||||
uow.Set<DiscordPermOverride>().Add(over = new() { Command = commandName, Perm = perm, GuildId = guildId });
|
||||
else
|
||||
{
|
||||
over.Perm = perm;
|
||||
}
|
||||
|
||||
_overrides[(guildId, commandName)] = over;
|
||||
|
||||
@@ -73,20 +68,16 @@ public class DiscordPermOverrideService : INService, ILateBlocker
|
||||
public async Task ClearAllOverrides(ulong guildId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var overrides = await uow
|
||||
.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
var overrides = await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
|
||||
uow.RemoveRange(overrides);
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
foreach (var over in overrides)
|
||||
{
|
||||
_overrides.TryRemove((guildId, over.Command), out _);
|
||||
}
|
||||
foreach (var over in overrides) _overrides.TryRemove((guildId, over.Command), out _);
|
||||
}
|
||||
|
||||
public async Task RemoveOverride(ulong guildId, string commandName)
|
||||
@@ -94,11 +85,10 @@ public class DiscordPermOverrideService : INService, ILateBlocker
|
||||
commandName = commandName.ToLowerInvariant();
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var over = await uow
|
||||
.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && x.Command == commandName);
|
||||
var over = await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.GuildId == guildId && x.Command == commandName);
|
||||
|
||||
if (over is null)
|
||||
return;
|
||||
@@ -112,24 +102,25 @@ public class DiscordPermOverrideService : INService, ILateBlocker
|
||||
public async Task<List<DiscordPermOverride>> GetAllOverrides(ulong guildId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow
|
||||
.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
return await uow.Set<DiscordPermOverride>()
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> TryBlockLate(ICommandContext context, string moduleName, CommandInfo command)
|
||||
{
|
||||
if (TryGetOverrides(context.Guild?.Id ?? 0, command.Name, out var perm) && perm is not null)
|
||||
{
|
||||
var result = await new RequireUserPermissionAttribute((GuildPermission)perm)
|
||||
.CheckPermissionsAsync(context, command, _services);
|
||||
var result =
|
||||
await new RequireUserPermissionAttribute((GuildPermission)perm).CheckPermissionsAsync(context,
|
||||
command,
|
||||
_services);
|
||||
|
||||
return !result.IsSuccess;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,9 +16,8 @@ public class GameVoiceChannelService : INService
|
||||
_db = db;
|
||||
_client = client;
|
||||
|
||||
GameVoiceChannels = new(
|
||||
bot.AllGuildConfigs.Where(gc => gc.GameVoiceChannel != null)
|
||||
.Select(gc => gc.GameVoiceChannel.Value));
|
||||
GameVoiceChannels = new(bot.AllGuildConfigs.Where(gc => gc.GameVoiceChannel != null)
|
||||
.Select(gc => gc.GameVoiceChannel.Value));
|
||||
|
||||
_client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
||||
_client.GuildMemberUpdated += _client_GuildMemberUpdated;
|
||||
@@ -39,11 +38,8 @@ public class GameVoiceChannelService : INService
|
||||
var oldActivity = before.Value.Activities.FirstOrDefault();
|
||||
var newActivity = after.Activities.FirstOrDefault();
|
||||
if (oldActivity != newActivity && newActivity is { Type: ActivityType.Playing })
|
||||
{
|
||||
//trigger gvc
|
||||
await TriggerGvc(after, newActivity.Name);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -87,12 +83,10 @@ public class GameVoiceChannelService : INService
|
||||
|
||||
var game = gUser.Activities.FirstOrDefault()?.Name;
|
||||
|
||||
if (oldState.VoiceChannel == newState.VoiceChannel ||
|
||||
newState.VoiceChannel is null)
|
||||
if (oldState.VoiceChannel == newState.VoiceChannel || newState.VoiceChannel is null)
|
||||
return;
|
||||
|
||||
if (!GameVoiceChannels.Contains(newState.VoiceChannel.Id) ||
|
||||
string.IsNullOrWhiteSpace(game))
|
||||
if (!GameVoiceChannels.Contains(newState.VoiceChannel.Id) || string.IsNullOrWhiteSpace(game))
|
||||
return;
|
||||
|
||||
await TriggerGvc(gUser, game);
|
||||
@@ -112,8 +106,7 @@ public class GameVoiceChannelService : INService
|
||||
return;
|
||||
|
||||
game = game.TrimTo(50).ToLowerInvariant();
|
||||
var vch = gUser.Guild.VoiceChannels
|
||||
.FirstOrDefault(x => x.Name.ToLowerInvariant() == game);
|
||||
var vch = gUser.Guild.VoiceChannels.FirstOrDefault(x => x.Name.ToLowerInvariant() == game);
|
||||
|
||||
if (vch is null)
|
||||
return;
|
||||
@@ -121,4 +114,4 @@ public class GameVoiceChannelService : INService
|
||||
await Task.Delay(1000);
|
||||
await gUser.ModifyAsync(gu => gu.Channel = vch);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -12,11 +12,10 @@ public class GuildTimezoneService : INService
|
||||
|
||||
public GuildTimezoneService(DiscordSocketClient client, Bot bot, DbService db)
|
||||
{
|
||||
_timezones = bot.AllGuildConfigs
|
||||
.Select(GetTimzezoneTuple)
|
||||
.Where(x => x.Timezone != null)
|
||||
.ToDictionary(x => x.GuildId, x => x.Timezone)
|
||||
.ToConcurrent();
|
||||
_timezones = bot.AllGuildConfigs.Select(GetTimzezoneTuple)
|
||||
.Where(x => x.Timezone != null)
|
||||
.ToDictionary(x => x.GuildId, x => x.Timezone)
|
||||
.ToConcurrent();
|
||||
|
||||
var curUser = client.CurrentUser;
|
||||
if (curUser != null)
|
||||
@@ -48,6 +47,7 @@ public class GuildTimezoneService : INService
|
||||
{
|
||||
tz = null;
|
||||
}
|
||||
|
||||
return (x.GuildId, Timezone: tz);
|
||||
}
|
||||
|
||||
@@ -74,4 +74,4 @@ public class GuildTimezoneService : INService
|
||||
|
||||
public TimeZoneInfo GetTimeZoneOrUtc(ulong guildId)
|
||||
=> GetTimeZoneOrDefault(guildId) ?? TimeZoneInfo.Utc;
|
||||
}
|
||||
}
|
@@ -1,25 +1,25 @@
|
||||
#nullable disable
|
||||
using System.Net;
|
||||
using System.Threading.Channels;
|
||||
using LinqToDB;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using System.Net;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public sealed class ImageOnlyChannelService : IEarlyBehavior
|
||||
{
|
||||
public int Priority { get; } = 0;
|
||||
private readonly IMemoryCache _ticketCache;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly DbService _db;
|
||||
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _enabledOn;
|
||||
|
||||
private readonly Channel<IUserMessage> _deleteQueue = Channel.CreateBounded<IUserMessage>(new BoundedChannelOptions(100)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.DropOldest,
|
||||
SingleReader = true,
|
||||
SingleWriter = false,
|
||||
});
|
||||
private readonly Channel<IUserMessage> _deleteQueue = Channel.CreateBounded<IUserMessage>(
|
||||
new BoundedChannelOptions(100)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.DropOldest, SingleReader = true, SingleWriter = false
|
||||
});
|
||||
|
||||
|
||||
public ImageOnlyChannelService(IMemoryCache ticketCache, DiscordSocketClient client, DbService db)
|
||||
@@ -29,14 +29,13 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
||||
_db = db;
|
||||
|
||||
var uow = _db.GetDbContext();
|
||||
_enabledOn = uow.ImageOnlyChannels
|
||||
.ToList()
|
||||
.GroupBy(x => x.GuildId)
|
||||
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(x => x.ChannelId)))
|
||||
.ToConcurrent();
|
||||
|
||||
_enabledOn = uow.ImageOnlyChannels.ToList()
|
||||
.GroupBy(x => x.GuildId)
|
||||
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(x => x.ChannelId)))
|
||||
.ToConcurrent();
|
||||
|
||||
_ = Task.Run(DeleteQueueRunner);
|
||||
|
||||
|
||||
_client.ChannelDestroyed += ClientOnChannelDestroyed;
|
||||
}
|
||||
|
||||
@@ -73,25 +72,19 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
||||
{
|
||||
var newState = false;
|
||||
using var uow = _db.GetDbContext();
|
||||
if (forceDisable
|
||||
|| (_enabledOn.TryGetValue(guildId, out var channels)
|
||||
&& channels.TryRemove(channelId)))
|
||||
if (forceDisable || (_enabledOn.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
|
||||
{
|
||||
uow.ImageOnlyChannels.Delete(x => x.ChannelId == channelId);
|
||||
}
|
||||
else
|
||||
{
|
||||
uow.ImageOnlyChannels.Add(new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ChannelId = channelId
|
||||
});
|
||||
uow.ImageOnlyChannels.Add(new() { GuildId = guildId, ChannelId = channelId });
|
||||
|
||||
channels = _enabledOn.GetOrAdd(guildId, new ConcurrentHashSet<ulong>());
|
||||
channels.Add(channelId);
|
||||
newState = true;
|
||||
}
|
||||
|
||||
|
||||
uow.SaveChanges();
|
||||
return newState;
|
||||
}
|
||||
@@ -100,20 +93,19 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
||||
{
|
||||
if (msg.Channel is not ITextChannel tch)
|
||||
return false;
|
||||
|
||||
|
||||
if (msg.Attachments.Any(x => x is { Height: > 0, Width: > 0 }))
|
||||
return false;
|
||||
|
||||
if (!_enabledOn.TryGetValue(tch.GuildId, out var chs)
|
||||
|| !chs.Contains(msg.Channel.Id))
|
||||
if (!_enabledOn.TryGetValue(tch.GuildId, out var chs) || !chs.Contains(msg.Channel.Id))
|
||||
return false;
|
||||
|
||||
var user = await tch.Guild.GetUserAsync(msg.Author.Id)
|
||||
?? await _client.Rest.GetGuildUserAsync(tch.GuildId, msg.Author.Id);
|
||||
|
||||
|
||||
if (user is null)
|
||||
return false;
|
||||
|
||||
|
||||
// ignore owner and admin
|
||||
if (user.Id == tch.Guild.OwnerId || user.GuildPermissions.Administrator)
|
||||
{
|
||||
@@ -129,7 +121,8 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
||||
// can't modify channel perms if not admin apparently
|
||||
if (!botUser.GuildPermissions.ManageGuild)
|
||||
{
|
||||
ToggleImageOnlyChannel( tch.GuildId, tch.Id, true);;
|
||||
ToggleImageOnlyChannel(tch.GuildId, tch.Id, true);
|
||||
;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -142,16 +135,14 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
||||
msg.Author.Id,
|
||||
msg.Channel.Id);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
await _deleteQueue.Writer.WriteAsync(msg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error deleting message {MessageId} in image-only channel {ChannelId}.",
|
||||
msg.Id,
|
||||
tch.Id);
|
||||
Log.Error(ex, "Error deleting message {MessageId} in image-only channel {ChannelId}.", msg.Id, tch.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -159,18 +150,17 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
||||
|
||||
private bool AddUserTicket(ulong guildId, ulong userId)
|
||||
{
|
||||
var old = _ticketCache.GetOrCreate($"{guildId}_{userId}", entry =>
|
||||
{
|
||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1);
|
||||
return 0;
|
||||
});
|
||||
var old = _ticketCache.GetOrCreate($"{guildId}_{userId}",
|
||||
entry =>
|
||||
{
|
||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1);
|
||||
return 0;
|
||||
});
|
||||
|
||||
_ticketCache.Set($"{guildId}_{userId}", ++old);
|
||||
|
||||
|
||||
// if this is the third time that the user posts a
|
||||
// non image in an image-only channel on this server
|
||||
return old > 2;
|
||||
}
|
||||
|
||||
public int Priority { get; } = 0;
|
||||
}
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -15,7 +15,7 @@ public interface ILogCommandService
|
||||
LogSetting GetGuildLogSettings(ulong guildId);
|
||||
bool Log(ulong guildId, ulong? channelId, LogType type);
|
||||
}
|
||||
|
||||
|
||||
public sealed class DummyLogCommandService : ILogCommandService
|
||||
{
|
||||
public void AddDeleteIgnore(ulong xId)
|
||||
@@ -34,14 +34,13 @@ public sealed class DummyLogCommandService : ILogCommandService
|
||||
public bool Log(ulong guildId, ulong? channelId, LogType type)
|
||||
=> false;
|
||||
}
|
||||
|
||||
|
||||
public sealed class LogCommandService : ILogCommandService
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }
|
||||
|
||||
private ConcurrentDictionary<ITextChannel, List<string>> PresenceUpdates { get; } = new();
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
private readonly Timer _timerReference;
|
||||
private readonly IBotStrings _strings;
|
||||
@@ -51,13 +50,19 @@ public sealed class LogCommandService : ILogCommandService
|
||||
private readonly GuildTimezoneService _tz;
|
||||
private readonly IEmbedBuilderService _eb;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
|
||||
private readonly Timer _clearTimer;
|
||||
private readonly ConcurrentHashSet<ulong> _ignoreMessageIds = new();
|
||||
|
||||
public LogCommandService(DiscordSocketClient client, IBotStrings strings,
|
||||
DbService db, MuteService mute, ProtectionService prot, GuildTimezoneService tz,
|
||||
IMemoryCache memoryCache, IEmbedBuilderService eb)
|
||||
public LogCommandService(
|
||||
DiscordSocketClient client,
|
||||
IBotStrings strings,
|
||||
DbService db,
|
||||
MuteService mute,
|
||||
ProtectionService prot,
|
||||
GuildTimezoneService tz,
|
||||
IMemoryCache memoryCache,
|
||||
IEmbedBuilderService eb)
|
||||
{
|
||||
_client = client;
|
||||
_memoryCache = memoryCache;
|
||||
@@ -69,41 +74,41 @@ public sealed class LogCommandService : ILogCommandService
|
||||
_tz = tz;
|
||||
|
||||
#if !GLOBAL_NADEKO
|
||||
|
||||
|
||||
using (var uow = db.GetDbContext())
|
||||
{
|
||||
var guildIds = client.Guilds.Select(x => x.Id).ToList();
|
||||
var configs = uow
|
||||
.LogSettings
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => guildIds.Contains(x.GuildId))
|
||||
.Include(ls => ls.LogIgnores)
|
||||
.ToList();
|
||||
var configs = uow.LogSettings.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Where(x => guildIds.Contains(x.GuildId))
|
||||
.Include(ls => ls.LogIgnores)
|
||||
.ToList();
|
||||
|
||||
GuildLogSettings = configs
|
||||
.ToDictionary(ls => ls.GuildId)
|
||||
.ToConcurrent();
|
||||
GuildLogSettings = configs.ToDictionary(ls => ls.GuildId).ToConcurrent();
|
||||
}
|
||||
|
||||
_timerReference = new(async state =>
|
||||
{
|
||||
var keys = PresenceUpdates.Keys.ToList();
|
||||
|
||||
await keys.Select(key =>
|
||||
{
|
||||
if (!((SocketGuild) key.Guild).CurrentUser.GetPermissions(key).SendMessages)
|
||||
return Task.CompletedTask;
|
||||
if (PresenceUpdates.TryRemove(key, out var msgs))
|
||||
{
|
||||
var title = GetText(key.Guild, strs.presence_updates);
|
||||
var desc = string.Join(Environment.NewLine, msgs);
|
||||
return key.SendConfirmAsync(_eb, title, desc.TrimTo(2048));
|
||||
}
|
||||
var keys = PresenceUpdates.Keys.ToList();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}).WhenAll();
|
||||
}, null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
|
||||
await keys.Select(key =>
|
||||
{
|
||||
if (!((SocketGuild)key.Guild).CurrentUser.GetPermissions(key).SendMessages)
|
||||
return Task.CompletedTask;
|
||||
if (PresenceUpdates.TryRemove(key, out var msgs))
|
||||
{
|
||||
var title = GetText(key.Guild, strs.presence_updates);
|
||||
var desc = string.Join(Environment.NewLine, msgs);
|
||||
return key.SendConfirmAsync(_eb, title, desc.TrimTo(2048));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
})
|
||||
.WhenAll();
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromSeconds(15),
|
||||
TimeSpan.FromSeconds(15));
|
||||
|
||||
//_client.MessageReceived += _client_MessageReceived;
|
||||
_client.MessageUpdated += _client_MessageUpdated;
|
||||
@@ -128,10 +133,13 @@ public sealed class LogCommandService : ILogCommandService
|
||||
_prot.OnAntiProtectionTriggered += TriggeredAntiProtection;
|
||||
|
||||
_clearTimer = new(_ =>
|
||||
{
|
||||
_ignoreMessageIds.Clear();
|
||||
}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1));
|
||||
|
||||
{
|
||||
_ignoreMessageIds.Clear();
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromHours(1),
|
||||
TimeSpan.FromHours(1));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -150,12 +158,11 @@ public sealed class LogCommandService : ILogCommandService
|
||||
using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var logSetting = uow.LogSettingsFor(gid);
|
||||
removed = logSetting.LogIgnores
|
||||
.RemoveAll(x => x.ItemType == itemType && itemId == x.LogItemId);
|
||||
|
||||
removed = logSetting.LogIgnores.RemoveAll(x => x.ItemType == itemType && itemId == x.LogItemId);
|
||||
|
||||
if (removed == 0)
|
||||
{
|
||||
var toAdd = new IgnoredLogItem { LogItemId = itemId, ItemType = itemType};
|
||||
var toAdd = new IgnoredLogItem { LogItemId = itemId, ItemType = itemType };
|
||||
logSetting.LogIgnores.Add(toAdd);
|
||||
}
|
||||
|
||||
@@ -165,9 +172,9 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
return removed > 0;
|
||||
}
|
||||
|
||||
private string GetText(IGuild guild, LocStr str) =>
|
||||
_strings.GetText(str, guild.Id);
|
||||
|
||||
private string GetText(IGuild guild, LocStr str)
|
||||
=> _strings.GetText(str, guild.Id);
|
||||
|
||||
private string PrettyCurrentTime(IGuild g)
|
||||
{
|
||||
@@ -190,23 +197,12 @@ public sealed class LogCommandService : ILogCommandService
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var logSetting = uow.LogSettingsFor(guildId);
|
||||
|
||||
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 =
|
||||
value ? channelId : null;
|
||||
|
||||
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 = value ? channelId : null;
|
||||
;
|
||||
await uow.SaveChangesAsync();
|
||||
GuildLogSettings.AddOrUpdate(guildId, id => logSetting, (id, old) => logSetting);
|
||||
@@ -223,13 +219,11 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
var g = after.Guild;
|
||||
|
||||
if (!GuildLogSettings.TryGetValue(g.Id, out var logSetting)
|
||||
|| logSetting.UserUpdatedId is null)
|
||||
if (!GuildLogSettings.TryGetValue(g.Id, out var logSetting) || logSetting.UserUpdatedId is null)
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel =
|
||||
await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) is null)
|
||||
if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) is null)
|
||||
return;
|
||||
|
||||
var embed = _eb.Create();
|
||||
@@ -237,18 +231,18 @@ public sealed class LogCommandService : ILogCommandService
|
||||
if (before.Username != after.Username)
|
||||
{
|
||||
embed.WithTitle("👥 " + GetText(g, strs.username_changed))
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.AddField("Old Name", $"{before.Username}", true)
|
||||
.AddField("New Name", $"{after.Username}", true)
|
||||
.WithFooter(CurrentTime(g))
|
||||
.WithOkColor();
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.AddField("Old Name", $"{before.Username}", true)
|
||||
.AddField("New Name", $"{after.Username}", true)
|
||||
.WithFooter(CurrentTime(g))
|
||||
.WithOkColor();
|
||||
}
|
||||
else if (before.AvatarId != after.AvatarId)
|
||||
{
|
||||
embed.WithTitle("👥" + GetText(g, strs.avatar_changed))
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.WithFooter(CurrentTime(g))
|
||||
.WithOkColor();
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.WithFooter(CurrentTime(g))
|
||||
.WithOkColor();
|
||||
|
||||
var bav = before.RealAvatarUrl();
|
||||
if (bav != null && bav.IsAbsoluteUri)
|
||||
@@ -273,7 +267,7 @@ public sealed class LogCommandService : ILogCommandService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public bool Log(ulong gid, ulong? cid, LogType type/*, string options*/)
|
||||
public bool Log(ulong gid, ulong? cid, LogType type /*, string options*/)
|
||||
{
|
||||
ulong? channelId = null;
|
||||
using (var uow = _db.GetDbContext())
|
||||
@@ -314,19 +308,16 @@ public sealed class LogCommandService : ILogCommandService
|
||||
channelId = logSetting.ChannelCreatedId = logSetting.ChannelCreatedId is null ? cid : default;
|
||||
break;
|
||||
case LogType.ChannelDestroyed:
|
||||
channelId = logSetting.ChannelDestroyedId =
|
||||
logSetting.ChannelDestroyedId is null ? cid : default;
|
||||
channelId = logSetting.ChannelDestroyedId = logSetting.ChannelDestroyedId is null ? cid : default;
|
||||
break;
|
||||
case LogType.ChannelUpdated:
|
||||
channelId = logSetting.ChannelUpdatedId = logSetting.ChannelUpdatedId is null ? cid : default;
|
||||
break;
|
||||
case LogType.UserPresence:
|
||||
channelId = logSetting.LogUserPresenceId =
|
||||
logSetting.LogUserPresenceId is null ? cid : default;
|
||||
channelId = logSetting.LogUserPresenceId = logSetting.LogUserPresenceId is null ? cid : default;
|
||||
break;
|
||||
case LogType.VoicePresence:
|
||||
channelId = logSetting.LogVoicePresenceId =
|
||||
logSetting.LogVoicePresenceId is null ? cid : default;
|
||||
channelId = logSetting.LogVoicePresenceId = logSetting.LogVoicePresenceId is null ? cid : default;
|
||||
break;
|
||||
case LogType.VoicePresenceTTS:
|
||||
channelId = logSetting.LogVoicePresenceTTSId =
|
||||
@@ -365,17 +356,11 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
var str = string.Empty;
|
||||
if (beforeVch?.Guild == afterVch?.Guild)
|
||||
{
|
||||
str = GetText(logChannel.Guild, strs.log_vc_moved(usr.Username, beforeVch?.Name, afterVch?.Name));
|
||||
}
|
||||
else if (beforeVch is null)
|
||||
{
|
||||
str = GetText(logChannel.Guild, strs.log_vc_joined(usr.Username, afterVch.Name));
|
||||
}
|
||||
else if (afterVch is null)
|
||||
{
|
||||
str = GetText(logChannel.Guild, strs.log_vc_left(usr.Username, beforeVch.Name));
|
||||
}
|
||||
|
||||
var toDelete = await logChannel.SendMessageAsync(str, true);
|
||||
toDelete.DeleteAfter(5);
|
||||
@@ -388,14 +373,17 @@ public sealed class LogCommandService : ILogCommandService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void MuteCommands_UserMuted(IGuildUser usr, IUser mod, MuteType muteType, string reason)
|
||||
private void MuteCommands_UserMuted(
|
||||
IGuildUser usr,
|
||||
IUser mod,
|
||||
MuteType muteType,
|
||||
string reason)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting)
|
||||
|| logSetting.UserMutedId is null)
|
||||
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting) || logSetting.UserMutedId is null)
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
@@ -412,15 +400,16 @@ public sealed class LogCommandService : ILogCommandService
|
||||
mutes = "🔇 " + GetText(logChannel.Guild, strs.xmuted_text(mutedLocalized, mod.ToString()));
|
||||
break;
|
||||
case MuteType.All:
|
||||
mutes = "🔇 " + GetText(logChannel.Guild, strs.xmuted_text_and_voice(mutedLocalized,
|
||||
mod.ToString()));
|
||||
mutes = "🔇 "
|
||||
+ GetText(logChannel.Guild, strs.xmuted_text_and_voice(mutedLocalized, mod.ToString()));
|
||||
break;
|
||||
}
|
||||
|
||||
var embed = _eb.Create().WithAuthor(mutes)
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter(CurrentTime(usr.Guild))
|
||||
.WithOkColor();
|
||||
var embed = _eb.Create()
|
||||
.WithAuthor(mutes)
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter(CurrentTime(usr.Guild))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed);
|
||||
}
|
||||
@@ -431,14 +420,17 @@ public sealed class LogCommandService : ILogCommandService
|
||||
});
|
||||
}
|
||||
|
||||
private void MuteCommands_UserUnmuted(IGuildUser usr, IUser mod, MuteType muteType, string reason)
|
||||
private void MuteCommands_UserUnmuted(
|
||||
IGuildUser usr,
|
||||
IUser mod,
|
||||
MuteType muteType,
|
||||
string reason)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting)
|
||||
|| logSetting.UserMutedId is null)
|
||||
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting) || logSetting.UserMutedId is null)
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
@@ -456,15 +448,17 @@ public sealed class LogCommandService : ILogCommandService
|
||||
mutes = "🔊 " + GetText(logChannel.Guild, strs.xmuted_text(unmutedLocalized, mod.ToString()));
|
||||
break;
|
||||
case MuteType.All:
|
||||
mutes = "🔊 " + GetText(logChannel.Guild, strs.xmuted_text_and_voice(unmutedLocalized,
|
||||
mod.ToString()));
|
||||
mutes = "🔊 "
|
||||
+ GetText(logChannel.Guild,
|
||||
strs.xmuted_text_and_voice(unmutedLocalized, mod.ToString()));
|
||||
break;
|
||||
}
|
||||
|
||||
var embed = _eb.Create().WithAuthor(mutes)
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter($"{CurrentTime(usr.Guild)}")
|
||||
.WithOkColor();
|
||||
var embed = _eb.Create()
|
||||
.WithAuthor(mutes)
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter($"{CurrentTime(usr.Guild)}")
|
||||
.WithOkColor();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(reason))
|
||||
embed.WithDescription(reason);
|
||||
@@ -478,8 +472,7 @@ public sealed class LogCommandService : ILogCommandService
|
||||
});
|
||||
}
|
||||
|
||||
public Task TriggeredAntiProtection(PunishmentAction action, ProtectionType protection,
|
||||
params IGuildUser[] users)
|
||||
public Task TriggeredAntiProtection(PunishmentAction action, ProtectionType protection, params IGuildUser[] users)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
@@ -515,11 +508,12 @@ public sealed class LogCommandService : ILogCommandService
|
||||
break;
|
||||
}
|
||||
|
||||
var embed = _eb.Create().WithAuthor($"🛡 Anti-{protection}")
|
||||
.WithTitle(GetText(logChannel.Guild, strs.users) + " " + punishment)
|
||||
.WithDescription(string.Join("\n", users.Select(u => u.ToString())))
|
||||
.WithFooter(CurrentTime(logChannel.Guild))
|
||||
.WithOkColor();
|
||||
var embed = _eb.Create()
|
||||
.WithAuthor($"🛡 Anti-{protection}")
|
||||
.WithTitle(GetText(logChannel.Guild, strs.users) + " " + punishment)
|
||||
.WithDescription(string.Join("\n", users.Select(u => u.ToString())))
|
||||
.WithFooter(CurrentTime(logChannel.Guild))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed);
|
||||
}
|
||||
@@ -533,13 +527,11 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
private string GetRoleDeletedKey(ulong roleId)
|
||||
=> $"role_deleted_{roleId}";
|
||||
|
||||
|
||||
private Task _client_RoleDeleted(SocketRole socketRole)
|
||||
{
|
||||
Serilog.Log.Information("Role deleted {RoleId}", socketRole.Id);
|
||||
_memoryCache.Set(GetRoleDeletedKey(socketRole.Id),
|
||||
true,
|
||||
TimeSpan.FromMinutes(5));
|
||||
_memoryCache.Set(GetRoleDeletedKey(socketRole.Id), true, TimeSpan.FromMinutes(5));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -559,25 +551,27 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
if (before is null)
|
||||
return;
|
||||
|
||||
|
||||
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out var logSetting)
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if (logSetting.UserUpdatedId != null &&
|
||||
(logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) != null)
|
||||
if (logSetting.UserUpdatedId != null
|
||||
&& (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) != null)
|
||||
{
|
||||
var embed = _eb.Create().WithOkColor()
|
||||
.WithFooter(CurrentTime(before.Guild))
|
||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithFooter(CurrentTime(before.Guild))
|
||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
|
||||
if (before.Nickname != after.Nickname)
|
||||
{
|
||||
embed.WithAuthor("👥 " + GetText(logChannel.Guild, strs.nick_change))
|
||||
.AddField(GetText(logChannel.Guild, strs.old_nick)
|
||||
, $"{before.Nickname}#{before.Discriminator}")
|
||||
.AddField(GetText(logChannel.Guild, strs.new_nick)
|
||||
, $"{after.Nickname}#{after.Discriminator}");
|
||||
.AddField(GetText(logChannel.Guild, strs.old_nick),
|
||||
$"{before.Nickname}#{before.Discriminator}")
|
||||
.AddField(GetText(logChannel.Guild, strs.new_nick),
|
||||
$"{after.Nickname}#{after.Discriminator}");
|
||||
|
||||
await logChannel.EmbedAsync(embed);
|
||||
}
|
||||
@@ -587,22 +581,21 @@ public sealed class LogCommandService : ILogCommandService
|
||||
{
|
||||
var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => r.Name);
|
||||
embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_add))
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
|
||||
await logChannel.EmbedAsync(embed);
|
||||
}
|
||||
else if (before.Roles.Count > after.Roles.Count)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
var diffRoles = before.Roles
|
||||
.Where(r => !after.Roles.Contains(r) && !IsRoleDeleted(r.Id))
|
||||
.Select(r => r.Name)
|
||||
.ToList();
|
||||
var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r) && !IsRoleDeleted(r.Id))
|
||||
.Select(r => r.Name)
|
||||
.ToList();
|
||||
|
||||
if (diffRoles.Any())
|
||||
{
|
||||
embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_rem))
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
|
||||
await logChannel.EmbedAsync(embed);
|
||||
}
|
||||
@@ -611,17 +604,20 @@ public sealed class LogCommandService : ILogCommandService
|
||||
}
|
||||
|
||||
logChannel = null;
|
||||
if (!before.IsBot && logSetting.LogUserPresenceId != null && (logChannel =
|
||||
await TryGetLogChannel(before.Guild, logSetting, LogType.UserPresence)) != null)
|
||||
if (!before.IsBot
|
||||
&& logSetting.LogUserPresenceId != null
|
||||
&& (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserPresence)) != null)
|
||||
{
|
||||
if (before.Status != after.Status)
|
||||
{
|
||||
var str = "🎭" + Format.Code(PrettyCurrentTime(after.Guild)) +
|
||||
GetText(logChannel.Guild, strs.user_status_change(
|
||||
"👤" + Format.Bold(after.Username),
|
||||
Format.Bold(after.Status.ToString())));
|
||||
var str = "🎭"
|
||||
+ Format.Code(PrettyCurrentTime(after.Guild))
|
||||
+ GetText(logChannel.Guild,
|
||||
strs.user_status_change("👤" + Format.Bold(after.Username),
|
||||
Format.Bold(after.Status.ToString())));
|
||||
PresenceUpdates.AddOrUpdate(logChannel,
|
||||
new List<string>() {str}, (id, list) =>
|
||||
new List<string> { str },
|
||||
(id, list) =>
|
||||
{
|
||||
list.Add(str);
|
||||
return list;
|
||||
@@ -632,7 +628,8 @@ public sealed class LogCommandService : ILogCommandService
|
||||
var str =
|
||||
$"👾`{PrettyCurrentTime(after.Guild)}`👤__**{after.Username}**__ is now playing **{after.Activities.FirstOrDefault()?.Name ?? "-"}**.";
|
||||
PresenceUpdates.AddOrUpdate(logChannel,
|
||||
new List<string>() {str}, (id, list) =>
|
||||
new List<string> { str },
|
||||
(id, list) =>
|
||||
{
|
||||
list.Add(str);
|
||||
return list;
|
||||
@@ -657,36 +654,32 @@ public sealed class LogCommandService : ILogCommandService
|
||||
if (cbefore is not IGuildChannel before)
|
||||
return;
|
||||
|
||||
var after = (IGuildChannel) cafter;
|
||||
var after = (IGuildChannel)cafter;
|
||||
|
||||
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out var logSetting)
|
||||
|| logSetting.ChannelUpdatedId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) is null)
|
||||
return;
|
||||
|
||||
var embed = _eb.Create().WithOkColor()
|
||||
.WithFooter(CurrentTime(before.Guild));
|
||||
var embed = _eb.Create().WithOkColor().WithFooter(CurrentTime(before.Guild));
|
||||
|
||||
var beforeTextChannel = cbefore as ITextChannel;
|
||||
var afterTextChannel = cafter as ITextChannel;
|
||||
|
||||
if (before.Name != after.Name)
|
||||
{
|
||||
embed.WithTitle("ℹ️ " + GetText(logChannel.Guild, strs.ch_name_change))
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(GetText(logChannel.Guild, strs.ch_old_name), before.Name);
|
||||
}
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(GetText(logChannel.Guild, strs.ch_old_name), before.Name);
|
||||
else if (beforeTextChannel?.Topic != afterTextChannel?.Topic)
|
||||
{
|
||||
embed.WithTitle("ℹ️ " + GetText(logChannel.Guild, strs.ch_topic_change))
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(GetText(logChannel.Guild, strs.old_topic) , beforeTextChannel?.Topic ?? "-")
|
||||
.AddField(GetText(logChannel.Guild, strs.new_topic), afterTextChannel?.Topic ?? "-");
|
||||
}
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(GetText(logChannel.Guild, strs.old_topic), beforeTextChannel?.Topic ?? "-")
|
||||
.AddField(GetText(logChannel.Guild, strs.new_topic), afterTextChannel?.Topic ?? "-");
|
||||
else
|
||||
return;
|
||||
|
||||
@@ -711,7 +704,8 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out var logSetting)
|
||||
|| logSetting.ChannelDestroyedId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == ch.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == ch.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
@@ -719,17 +713,15 @@ public sealed class LogCommandService : ILogCommandService
|
||||
return;
|
||||
string title;
|
||||
if (ch is IVoiceChannel)
|
||||
{
|
||||
title = GetText(logChannel.Guild, strs.voice_chan_destroyed);
|
||||
}
|
||||
else
|
||||
title = GetText(logChannel.Guild, strs.text_chan_destroyed);
|
||||
|
||||
await logChannel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + title)
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(CurrentTime(ch.Guild)));
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + title)
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(CurrentTime(ch.Guild)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -757,17 +749,15 @@ public sealed class LogCommandService : ILogCommandService
|
||||
return;
|
||||
string title;
|
||||
if (ch is IVoiceChannel)
|
||||
{
|
||||
title = GetText(logChannel.Guild, strs.voice_chan_created);
|
||||
}
|
||||
else
|
||||
title = GetText(logChannel.Guild, strs.text_chan_created);
|
||||
|
||||
await logChannel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + title)
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(CurrentTime(ch.Guild)));
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + title)
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(CurrentTime(ch.Guild)));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -794,7 +784,8 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting)
|
||||
|| logSetting.LogVoicePresenceId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == iusr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
|| logSetting.LogIgnores.Any(
|
||||
ilc => ilc.LogItemId == iusr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
@@ -803,32 +794,33 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
string str = null;
|
||||
if (beforeVch?.Guild == afterVch?.Guild)
|
||||
{
|
||||
str = "🎙" + Format.Code(PrettyCurrentTime(usr.Guild)) + GetText(logChannel.Guild,
|
||||
strs.user_vmoved(
|
||||
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(beforeVch?.Name ?? ""), Format.Bold(afterVch?.Name ?? "")));
|
||||
}
|
||||
str = "🎙"
|
||||
+ Format.Code(PrettyCurrentTime(usr.Guild))
|
||||
+ GetText(logChannel.Guild,
|
||||
strs.user_vmoved("👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(beforeVch?.Name ?? ""),
|
||||
Format.Bold(afterVch?.Name ?? "")));
|
||||
else if (beforeVch is null)
|
||||
{
|
||||
str = "🎙" + Format.Code(PrettyCurrentTime(usr.Guild)) + GetText(logChannel.Guild,
|
||||
strs.user_vjoined(
|
||||
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(afterVch.Name ?? "")));
|
||||
}
|
||||
str = "🎙"
|
||||
+ Format.Code(PrettyCurrentTime(usr.Guild))
|
||||
+ GetText(logChannel.Guild,
|
||||
strs.user_vjoined("👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(afterVch.Name ?? "")));
|
||||
else if (afterVch is null)
|
||||
{
|
||||
str = "🎙" + Format.Code(PrettyCurrentTime(usr.Guild)) + GetText(logChannel.Guild,
|
||||
strs.user_vleft("👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(beforeVch.Name ?? "")));
|
||||
}
|
||||
str = "🎙"
|
||||
+ Format.Code(PrettyCurrentTime(usr.Guild))
|
||||
+ GetText(logChannel.Guild,
|
||||
strs.user_vleft("👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(beforeVch.Name ?? "")));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(str))
|
||||
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() {str}, (id, list) =>
|
||||
{
|
||||
list.Add(str);
|
||||
return list;
|
||||
});
|
||||
PresenceUpdates.AddOrUpdate(logChannel,
|
||||
new List<string> { str },
|
||||
(id, list) =>
|
||||
{
|
||||
list.Add(str);
|
||||
return list;
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -846,18 +838,19 @@ public sealed class LogCommandService : ILogCommandService
|
||||
{
|
||||
if (!GuildLogSettings.TryGetValue(guild.Id, out var logSetting)
|
||||
|| logSetting.UserLeftId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserLeft)) is null)
|
||||
return;
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("❌ " + GetText(logChannel.Guild, strs.user_left))
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.WithFooter(CurrentTime(guild));
|
||||
.WithOkColor()
|
||||
.WithTitle("❌ " + GetText(logChannel.Guild, strs.user_left))
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.WithFooter(CurrentTime(guild));
|
||||
|
||||
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
|
||||
embed.WithThumbnailUrl(usr.GetAvatarUrl());
|
||||
@@ -878,8 +871,7 @@ public sealed class LogCommandService : ILogCommandService
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting)
|
||||
|| logSetting.UserJoinedId is null)
|
||||
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting) || logSetting.UserJoinedId is null)
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
@@ -887,17 +879,17 @@ public sealed class LogCommandService : ILogCommandService
|
||||
return;
|
||||
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("✅ " + GetText(logChannel.Guild, strs.user_joined))
|
||||
.WithDescription($"{usr.Mention} `{usr}`")
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.AddField(GetText(logChannel.Guild, strs.joined_server),
|
||||
$"{usr.JoinedAt?.ToString("dd.MM.yyyy HH:mm" ?? "?")}",
|
||||
true)
|
||||
.AddField(GetText(logChannel.Guild, strs.joined_discord),
|
||||
$"{usr.CreatedAt:dd.MM.yyyy HH:mm}",
|
||||
true)
|
||||
.WithFooter(CurrentTime(usr.Guild));
|
||||
.WithOkColor()
|
||||
.WithTitle("✅ " + GetText(logChannel.Guild, strs.user_joined))
|
||||
.WithDescription($"{usr.Mention} `{usr}`")
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.AddField(GetText(logChannel.Guild, strs.joined_server),
|
||||
$"{usr.JoinedAt?.ToString("dd.MM.yyyy HH:mm" ?? "?")}",
|
||||
true)
|
||||
.AddField(GetText(logChannel.Guild, strs.joined_discord),
|
||||
$"{usr.CreatedAt:dd.MM.yyyy HH:mm}",
|
||||
true)
|
||||
.WithFooter(CurrentTime(usr.Guild));
|
||||
|
||||
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
|
||||
embed.WithThumbnailUrl(usr.GetAvatarUrl());
|
||||
@@ -920,18 +912,19 @@ public sealed class LogCommandService : ILogCommandService
|
||||
{
|
||||
if (!GuildLogSettings.TryGetValue(guild.Id, out var logSetting)
|
||||
|| logSetting.UserUnbannedId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) is null)
|
||||
return;
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("♻️ " + GetText(logChannel.Guild, strs.user_unbanned))
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.WithFooter(CurrentTime(guild));
|
||||
.WithOkColor()
|
||||
.WithTitle("♻️ " + GetText(logChannel.Guild, strs.user_unbanned))
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.WithFooter(CurrentTime(guild));
|
||||
|
||||
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
|
||||
embed.WithThumbnailUrl(usr.GetAvatarUrl());
|
||||
@@ -954,20 +947,19 @@ public sealed class LogCommandService : ILogCommandService
|
||||
{
|
||||
if (!GuildLogSettings.TryGetValue(guild.Id, out var logSetting)
|
||||
|| logSetting.UserBannedId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel =
|
||||
await TryGetLogChannel(guild, logSetting, LogType.UserBanned)) ==
|
||||
null)
|
||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null)
|
||||
return;
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("🚫 " + GetText(logChannel.Guild, strs.user_banned))
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.WithFooter(CurrentTime(guild));
|
||||
.WithOkColor()
|
||||
.WithTitle("🚫 " + GetText(logChannel.Guild, strs.user_banned))
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField("Id", usr.Id.ToString())
|
||||
.WithFooter(CurrentTime(guild));
|
||||
|
||||
var avatarUrl = usr.GetAvatarUrl();
|
||||
|
||||
@@ -1002,27 +994,28 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out var logSetting)
|
||||
|| logSetting.MessageDeletedId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == channel.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == channel.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageDeleted)) is null || logChannel.Id == msg.Id)
|
||||
if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageDeleted)) is null
|
||||
|| logChannel.Id == msg.Id)
|
||||
return;
|
||||
|
||||
var resolvedMessage = msg.Resolve(userHandling: TagHandling.FullName);
|
||||
var resolvedMessage = msg.Resolve(TagHandling.FullName);
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("🗑 " + GetText(logChannel.Guild, strs.msg_del(((ITextChannel) msg.Channel).Name)))
|
||||
.WithDescription(msg.Author.ToString())
|
||||
.AddField(GetText(logChannel.Guild, strs.content),
|
||||
string.IsNullOrWhiteSpace(resolvedMessage) ? "-" : resolvedMessage,
|
||||
false)
|
||||
.AddField("Id", msg.Id.ToString(), false)
|
||||
.WithFooter(CurrentTime(channel.Guild));
|
||||
.WithOkColor()
|
||||
.WithTitle("🗑 "
|
||||
+ GetText(logChannel.Guild, strs.msg_del(((ITextChannel)msg.Channel).Name)))
|
||||
.WithDescription(msg.Author.ToString())
|
||||
.AddField(GetText(logChannel.Guild, strs.content),
|
||||
string.IsNullOrWhiteSpace(resolvedMessage) ? "-" : resolvedMessage)
|
||||
.AddField("Id", msg.Id.ToString())
|
||||
.WithFooter(CurrentTime(channel.Guild));
|
||||
if (msg.Attachments.Any())
|
||||
embed.AddField(GetText(logChannel.Guild, strs.attachments),
|
||||
string.Join(", ", msg.Attachments.Select(a => a.Url)),
|
||||
false);
|
||||
string.Join(", ", msg.Attachments.Select(a => a.Url)));
|
||||
|
||||
await logChannel.EmbedAsync(embed);
|
||||
}
|
||||
@@ -1034,7 +1027,9 @@ public sealed class LogCommandService : ILogCommandService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task _client_MessageUpdated(Cacheable<IMessage, ulong> optmsg, SocketMessage imsg2,
|
||||
private Task _client_MessageUpdated(
|
||||
Cacheable<IMessage, ulong> optmsg,
|
||||
SocketMessage imsg2,
|
||||
ISocketMessageChannel ch)
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
@@ -1058,30 +1053,29 @@ public sealed class LogCommandService : ILogCommandService
|
||||
|
||||
if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out var logSetting)
|
||||
|| logSetting.MessageUpdatedId is null
|
||||
|| logSetting.LogIgnores.Any(ilc => ilc.LogItemId == channel.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
|| logSetting.LogIgnores.Any(ilc
|
||||
=> ilc.LogItemId == channel.Id && ilc.ItemType == IgnoredItemType.Channel))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageUpdated)) is null || logChannel.Id == after.Channel.Id)
|
||||
if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageUpdated)) is null
|
||||
|| logChannel.Id == after.Channel.Id)
|
||||
return;
|
||||
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("📝 " + GetText(logChannel.Guild, strs.msg_update(((ITextChannel)after.Channel).Name)))
|
||||
.WithDescription(after.Author.ToString())
|
||||
.AddField(GetText(logChannel.Guild, strs.old_msg),
|
||||
string.IsNullOrWhiteSpace(before.Content)
|
||||
? "-"
|
||||
: before.Resolve(userHandling: TagHandling.FullName),
|
||||
false)
|
||||
.AddField(
|
||||
GetText(logChannel.Guild, strs.new_msg),
|
||||
string.IsNullOrWhiteSpace(after.Content)
|
||||
? "-"
|
||||
: after.Resolve(userHandling: TagHandling.FullName),
|
||||
false)
|
||||
.AddField("Id", after.Id.ToString(), false)
|
||||
.WithFooter(CurrentTime(channel.Guild));
|
||||
.WithOkColor()
|
||||
.WithTitle("📝 "
|
||||
+ GetText(logChannel.Guild,
|
||||
strs.msg_update(((ITextChannel)after.Channel).Name)))
|
||||
.WithDescription(after.Author.ToString())
|
||||
.AddField(GetText(logChannel.Guild, strs.old_msg),
|
||||
string.IsNullOrWhiteSpace(before.Content)
|
||||
? "-"
|
||||
: before.Resolve(TagHandling.FullName))
|
||||
.AddField(GetText(logChannel.Guild, strs.new_msg),
|
||||
string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(TagHandling.FullName))
|
||||
.AddField("Id", after.Id.ToString())
|
||||
.WithFooter(CurrentTime(channel.Guild));
|
||||
|
||||
await logChannel.EmbedAsync(embed);
|
||||
}
|
||||
@@ -1158,8 +1152,8 @@ public sealed class LogCommandService : ILogCommandService
|
||||
UnsetLogSetting(guild.Id, logChannelType);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
return channel;
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
private void UnsetLogSetting(ulong guildId, LogType logChannelType)
|
||||
@@ -1218,4 +1212,4 @@ public sealed class LogCommandService : ILogCommandService
|
||||
GuildLogSettings.AddOrUpdate(guildId, newLogSetting, (gid, old) => newLogSetting);
|
||||
uow.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -14,17 +14,19 @@ public enum MuteType
|
||||
|
||||
public class MuteService : INService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
|
||||
public ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
|
||||
public enum TimerType { Mute, Ban, AddRole }
|
||||
|
||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<(ulong, TimerType), Timer>> Un_Timers { get; } = new();
|
||||
private static readonly OverwritePermissions denyOverwrite = new(addReactions: PermValue.Deny,
|
||||
sendMessages: PermValue.Deny,
|
||||
attachFiles: PermValue.Deny);
|
||||
|
||||
public event Action<IGuildUser, IUser, MuteType, string> UserMuted = delegate { };
|
||||
public event Action<IGuildUser, IUser, MuteType, string> UserUnmuted = delegate { };
|
||||
|
||||
private static readonly OverwritePermissions denyOverwrite =
|
||||
new(addReactions: PermValue.Deny, sendMessages: PermValue.Deny,
|
||||
attachFiles: PermValue.Deny);
|
||||
public ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
|
||||
public ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
|
||||
|
||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<(ulong, TimerType), Timer>> Un_Timers { get; } = new();
|
||||
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly DbService _db;
|
||||
@@ -39,24 +41,21 @@ public class MuteService : INService
|
||||
using (var uow = db.GetDbContext())
|
||||
{
|
||||
var guildIds = client.Guilds.Select(x => x.Id).ToList();
|
||||
var configs = uow.Set<GuildConfig>().AsQueryable()
|
||||
.Include(x => x.MutedUsers)
|
||||
.Include(x => x.UnbanTimer)
|
||||
.Include(x => x.UnmuteTimers)
|
||||
.Include(x => x.UnroleTimer)
|
||||
.Where(x => guildIds.Contains(x.GuildId))
|
||||
.ToList();
|
||||
var configs = uow.Set<GuildConfig>()
|
||||
.AsQueryable()
|
||||
.Include(x => x.MutedUsers)
|
||||
.Include(x => x.UnbanTimer)
|
||||
.Include(x => x.UnmuteTimers)
|
||||
.Include(x => x.UnroleTimer)
|
||||
.Where(x => guildIds.Contains(x.GuildId))
|
||||
.ToList();
|
||||
|
||||
GuildMuteRoles = configs
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
|
||||
.ToDictionary(c => c.GuildId, c => c.MuteRoleName)
|
||||
.ToConcurrent();
|
||||
GuildMuteRoles = configs.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
|
||||
.ToDictionary(c => c.GuildId, c => c.MuteRoleName)
|
||||
.ToConcurrent();
|
||||
|
||||
MutedUsers = new(configs
|
||||
.ToDictionary(
|
||||
k => k.GuildId,
|
||||
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
|
||||
));
|
||||
MutedUsers = new(configs.ToDictionary(k => k.GuildId,
|
||||
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))));
|
||||
|
||||
var max = TimeSpan.FromDays(49);
|
||||
|
||||
@@ -118,30 +117,40 @@ public class MuteService : INService
|
||||
UserUnmuted += OnUserUnmuted;
|
||||
}
|
||||
|
||||
private void OnUserMuted(IGuildUser user, IUser mod, MuteType type, string reason)
|
||||
private void OnUserMuted(
|
||||
IGuildUser user,
|
||||
IUser mod,
|
||||
MuteType type,
|
||||
string reason)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(reason))
|
||||
return;
|
||||
|
||||
|
||||
var _ = Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
|
||||
.WithDescription($"You've been muted in {user.Guild} server")
|
||||
.AddField("Mute Type", type.ToString())
|
||||
.AddField("Moderator", mod.ToString())
|
||||
.AddField("Reason", reason)
|
||||
.Build()));
|
||||
.WithDescription(
|
||||
$"You've been muted in {user.Guild} server")
|
||||
.AddField("Mute Type", type.ToString())
|
||||
.AddField("Moderator", mod.ToString())
|
||||
.AddField("Reason", reason)
|
||||
.Build()));
|
||||
}
|
||||
|
||||
private void OnUserUnmuted(IGuildUser user, IUser mod, MuteType type, string reason)
|
||||
private void OnUserUnmuted(
|
||||
IGuildUser user,
|
||||
IUser mod,
|
||||
MuteType type,
|
||||
string reason)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(reason))
|
||||
return;
|
||||
|
||||
|
||||
var _ = Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
|
||||
.WithDescription($"You've been unmuted in {user.Guild} server")
|
||||
.AddField("Unmute Type", type.ToString())
|
||||
.AddField("Moderator", mod.ToString())
|
||||
.AddField("Reason", reason)
|
||||
.Build()));
|
||||
.WithDescription(
|
||||
$"You've been unmuted in {user.Guild} server")
|
||||
.AddField("Unmute Type", type.ToString())
|
||||
.AddField("Moderator", mod.ToString())
|
||||
.AddField("Reason", reason)
|
||||
.Build()));
|
||||
}
|
||||
|
||||
private Task Client_UserJoined(IGuildUser usr)
|
||||
@@ -158,6 +167,7 @@ public class MuteService : INService
|
||||
{
|
||||
Log.Warning(ex, "Error in MuteService UserJoined event");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -170,11 +180,17 @@ public class MuteService : INService
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task MuteUser(IGuildUser usr, IUser mod, MuteType type = MuteType.All, string reason = "")
|
||||
public async Task MuteUser(
|
||||
IGuildUser usr,
|
||||
IUser mod,
|
||||
MuteType type = MuteType.All,
|
||||
string reason = "")
|
||||
{
|
||||
if (type == MuteType.All)
|
||||
{
|
||||
try { await usr.ModifyAsync(x => x.Mute = true); } catch { }
|
||||
try { await usr.ModifyAsync(x => x.Mute = true); }
|
||||
catch { }
|
||||
|
||||
var muteRole = await GetMuteRole(usr.Guild);
|
||||
if (!usr.RoleIds.Contains(muteRole.Id))
|
||||
await usr.AddRoleAsync(muteRole);
|
||||
@@ -182,12 +198,8 @@ public class MuteService : INService
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var config = uow.GuildConfigsForId(usr.Guild.Id,
|
||||
set => set.Include(gc => gc.MutedUsers)
|
||||
.Include(gc => gc.UnmuteTimers));
|
||||
config.MutedUsers.Add(new()
|
||||
{
|
||||
UserId = usr.Id
|
||||
});
|
||||
set => set.Include(gc => gc.MutedUsers).Include(gc => gc.UnmuteTimers));
|
||||
config.MutedUsers.Add(new() { UserId = usr.Id });
|
||||
if (MutedUsers.TryGetValue(usr.Guild.Id, out var muted))
|
||||
muted.Add(usr.Id);
|
||||
|
||||
@@ -195,6 +207,7 @@ public class MuteService : INService
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
UserMuted(usr, mod, MuteType.All, reason);
|
||||
}
|
||||
else if (type == MuteType.Voice)
|
||||
@@ -213,7 +226,12 @@ public class MuteService : INService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UnmuteUser(ulong guildId, ulong usrId, IUser mod, MuteType type = MuteType.All, string reason = "")
|
||||
public async Task UnmuteUser(
|
||||
ulong guildId,
|
||||
ulong usrId,
|
||||
IUser mod,
|
||||
MuteType type = MuteType.All,
|
||||
string reason = "")
|
||||
{
|
||||
var usr = _client.GetGuild(guildId)?.GetUser(usrId);
|
||||
if (type == MuteType.All)
|
||||
@@ -221,17 +239,11 @@ public class MuteService : INService
|
||||
StopTimer(guildId, usrId, TimerType.Mute);
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var config = uow.GuildConfigsForId(guildId, set => set.Include(gc => gc.MutedUsers)
|
||||
.Include(gc => gc.UnmuteTimers));
|
||||
var match = new MutedUserId()
|
||||
{
|
||||
UserId = usrId
|
||||
};
|
||||
var config = uow.GuildConfigsForId(guildId,
|
||||
set => set.Include(gc => gc.MutedUsers).Include(gc => gc.UnmuteTimers));
|
||||
var match = new MutedUserId { UserId = usrId };
|
||||
var toRemove = config.MutedUsers.FirstOrDefault(x => x.Equals(match));
|
||||
if (toRemove != null)
|
||||
{
|
||||
uow.Remove(toRemove);
|
||||
}
|
||||
if (toRemove != null) uow.Remove(toRemove);
|
||||
if (MutedUsers.TryGetValue(guildId, out var muted))
|
||||
muted.TryRemove(usrId);
|
||||
|
||||
@@ -239,10 +251,18 @@ public class MuteService : INService
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
if (usr != null)
|
||||
{
|
||||
try { await usr.ModifyAsync(x => x.Mute = false); } catch { }
|
||||
try { await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)); } catch { /*ignore*/ }
|
||||
try { await usr.ModifyAsync(x => x.Mute = false); }
|
||||
catch { }
|
||||
|
||||
try { await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)); }
|
||||
catch
|
||||
{
|
||||
/*ignore*/
|
||||
}
|
||||
|
||||
UserUnmuted(usr, mod, MuteType.All, reason);
|
||||
}
|
||||
}
|
||||
@@ -277,20 +297,16 @@ public class MuteService : INService
|
||||
|
||||
var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
|
||||
if (muteRole is null)
|
||||
{
|
||||
|
||||
//if it doesn't exist, create it
|
||||
try { muteRole = await guild.CreateRoleAsync(muteRoleName, isMentionable: 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, isMentionable: false);
|
||||
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName)
|
||||
?? await guild.CreateRoleAsync(defaultMuteRoleName, isMentionable: false);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var toOverwrite in await guild.GetTextChannelsAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!toOverwrite.PermissionOverwrites.Any(x => x.TargetId == muteRole.Id
|
||||
@@ -305,12 +321,16 @@ public class MuteService : INService
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
return muteRole;
|
||||
}
|
||||
|
||||
public async Task TimedMute(IGuildUser user, IUser mod, TimeSpan after, MuteType muteType = MuteType.All, string reason = "")
|
||||
public async Task TimedMute(
|
||||
IGuildUser user,
|
||||
IUser mod,
|
||||
TimeSpan after,
|
||||
MuteType muteType = MuteType.All,
|
||||
string reason = "")
|
||||
{
|
||||
await MuteUser(user, mod, muteType, reason); // mute the user. This will also remove any previous unmute timers
|
||||
await using (var uow = _db.GetDbContext())
|
||||
@@ -318,8 +338,7 @@ public class MuteService : INService
|
||||
var config = uow.GuildConfigsForId(user.GuildId, set => set.Include(x => x.UnmuteTimers));
|
||||
config.UnmuteTimers.Add(new()
|
||||
{
|
||||
UserId = user.Id,
|
||||
UnmuteAt = DateTime.UtcNow + after,
|
||||
UserId = user.Id, UnmuteAt = DateTime.UtcNow + after
|
||||
}); // add teh unmute timer to the database
|
||||
uow.SaveChanges();
|
||||
}
|
||||
@@ -327,7 +346,11 @@ public class MuteService : INService
|
||||
StartUn_Timer(user.GuildId, user.Id, after, TimerType.Mute); // start the timer
|
||||
}
|
||||
|
||||
public async Task TimedBan(IGuild guild, IUser user, TimeSpan after, string reason)
|
||||
public async Task TimedBan(
|
||||
IGuild guild,
|
||||
IUser user,
|
||||
TimeSpan after,
|
||||
string reason)
|
||||
{
|
||||
await guild.AddBanAsync(user.Id, 0, reason);
|
||||
await using (var uow = _db.GetDbContext())
|
||||
@@ -335,8 +358,7 @@ public class MuteService : INService
|
||||
var config = uow.GuildConfigsForId(guild.Id, set => set.Include(x => x.UnbanTimer));
|
||||
config.UnbanTimer.Add(new()
|
||||
{
|
||||
UserId = user.Id,
|
||||
UnbanAt = DateTime.UtcNow + after,
|
||||
UserId = user.Id, UnbanAt = DateTime.UtcNow + after
|
||||
}); // add teh unmute timer to the database
|
||||
uow.SaveChanges();
|
||||
}
|
||||
@@ -344,7 +366,11 @@ public class MuteService : INService
|
||||
StartUn_Timer(guild.Id, user.Id, after, TimerType.Ban); // start the timer
|
||||
}
|
||||
|
||||
public async Task TimedRole(IGuildUser user, TimeSpan after, string reason, IRole role)
|
||||
public async Task TimedRole(
|
||||
IGuildUser user,
|
||||
TimeSpan after,
|
||||
string reason,
|
||||
IRole role)
|
||||
{
|
||||
await user.AddRoleAsync(role);
|
||||
await using (var uow = _db.GetDbContext())
|
||||
@@ -352,81 +378,78 @@ public class MuteService : INService
|
||||
var config = uow.GuildConfigsForId(user.GuildId, set => set.Include(x => x.UnroleTimer));
|
||||
config.UnroleTimer.Add(new()
|
||||
{
|
||||
UserId = user.Id,
|
||||
UnbanAt = DateTime.UtcNow + after,
|
||||
RoleId = role.Id
|
||||
UserId = user.Id, UnbanAt = DateTime.UtcNow + after, RoleId = role.Id
|
||||
}); // add teh unmute timer to the database
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
StartUn_Timer(user.GuildId, user.Id, after, TimerType.AddRole, role.Id); // start the timer
|
||||
}
|
||||
|
||||
public enum TimerType { Mute, Ban, AddRole }
|
||||
public void StartUn_Timer(ulong guildId, ulong userId, TimeSpan after, TimerType type, ulong? roleId = null)
|
||||
public void StartUn_Timer(
|
||||
ulong guildId,
|
||||
ulong userId,
|
||||
TimeSpan after,
|
||||
TimerType type,
|
||||
ulong? roleId = null)
|
||||
{
|
||||
//load the unmute timers for this guild
|
||||
var userUnTimers = Un_Timers.GetOrAdd(guildId, new ConcurrentDictionary<(ulong, TimerType), Timer>());
|
||||
|
||||
//unmute timer to be added
|
||||
var toAdd = new Timer(async _ =>
|
||||
{
|
||||
if (type == TimerType.Ban)
|
||||
{
|
||||
try
|
||||
{
|
||||
RemoveTimerFromDb(guildId, userId, type);
|
||||
StopTimer(guildId, userId, type);
|
||||
var guild = _client.GetGuild(guildId); // load the guild
|
||||
if (guild != null)
|
||||
if (type == TimerType.Ban)
|
||||
try
|
||||
{
|
||||
await guild.RemoveBanAsync(userId);
|
||||
RemoveTimerFromDb(guildId, userId, type);
|
||||
StopTimer(guildId, userId, type);
|
||||
var guild = _client.GetGuild(guildId); // load the guild
|
||||
if (guild != null) await guild.RemoveBanAsync(userId);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Couldn't unban user {0} in guild {1}", userId, guildId);
|
||||
}
|
||||
}
|
||||
else if (type == TimerType.AddRole)
|
||||
{
|
||||
try
|
||||
{
|
||||
RemoveTimerFromDb(guildId, userId, type);
|
||||
StopTimer(guildId, userId, type);
|
||||
var guild = _client.GetGuild(guildId);
|
||||
var user = guild?.GetUser(userId);
|
||||
var role = guild.GetRole(roleId.Value);
|
||||
if (guild != null && user != null && user.Roles.Contains(role))
|
||||
catch (Exception ex)
|
||||
{
|
||||
await user.RemoveRoleAsync(role);
|
||||
Log.Warning(ex, "Couldn't unban user {0} in guild {1}", userId, guildId);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Couldn't remove role from user {0} in guild {1}", userId, guildId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
// unmute the user, this will also remove the timer from the db
|
||||
await UnmuteUser(guildId, userId, _client.CurrentUser, reason: "Timed mute expired");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RemoveTimerFromDb(guildId, userId, type); // if unmute errored, just remove unmute from db
|
||||
Log.Warning(ex, "Couldn't unmute user {0} in guild {1}", userId, guildId);
|
||||
}
|
||||
}
|
||||
}, null, after, Timeout.InfiniteTimeSpan);
|
||||
else if (type == TimerType.AddRole)
|
||||
try
|
||||
{
|
||||
RemoveTimerFromDb(guildId, userId, type);
|
||||
StopTimer(guildId, userId, type);
|
||||
var guild = _client.GetGuild(guildId);
|
||||
var user = guild?.GetUser(userId);
|
||||
var role = guild.GetRole(roleId.Value);
|
||||
if (guild != null && user != null && user.Roles.Contains(role))
|
||||
await user.RemoveRoleAsync(role);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Couldn't remove role from user {0} in guild {1}", userId, guildId);
|
||||
}
|
||||
else
|
||||
try
|
||||
{
|
||||
// unmute the user, this will also remove the timer from the db
|
||||
await UnmuteUser(guildId, userId, _client.CurrentUser, reason: "Timed mute expired");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RemoveTimerFromDb(guildId, userId, type); // if unmute errored, just remove unmute from db
|
||||
Log.Warning(ex, "Couldn't unmute user {0} in guild {1}", userId, guildId);
|
||||
}
|
||||
},
|
||||
null,
|
||||
after,
|
||||
Timeout.InfiniteTimeSpan);
|
||||
|
||||
//add it, or stop the old one and add this one
|
||||
userUnTimers.AddOrUpdate((userId, type), key => toAdd, (key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return toAdd;
|
||||
});
|
||||
userUnTimers.AddOrUpdate((userId, type),
|
||||
key => toAdd,
|
||||
(key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return toAdd;
|
||||
});
|
||||
}
|
||||
|
||||
public void StopTimer(ulong guildId, ulong userId, TimerType type)
|
||||
@@ -434,10 +457,7 @@ public class MuteService : INService
|
||||
if (!Un_Timers.TryGetValue(guildId, out var userTimer))
|
||||
return;
|
||||
|
||||
if (userTimer.TryRemove((userId, type), out var removed))
|
||||
{
|
||||
removed.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
if (userTimer.TryRemove((userId, type), out var removed)) removed.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
|
||||
private void RemoveTimerFromDb(ulong guildId, ulong userId, TimerType type)
|
||||
@@ -454,10 +474,8 @@ public class MuteService : INService
|
||||
var config = uow.GuildConfigsForId(guildId, set => set.Include(x => x.UnbanTimer));
|
||||
toDelete = config.UnbanTimer.FirstOrDefault(x => x.UserId == userId);
|
||||
}
|
||||
if (toDelete != null)
|
||||
{
|
||||
uow.Remove(toDelete);
|
||||
}
|
||||
|
||||
if (toDelete != null) uow.Remove(toDelete);
|
||||
uow.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -13,13 +13,13 @@ public sealed class PlayingRotateService : INService
|
||||
private readonly DbService _db;
|
||||
private readonly Bot _bot;
|
||||
|
||||
private class TimerState
|
||||
{
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
public PlayingRotateService(DiscordSocketClient client, DbService db, Bot bot,
|
||||
BotConfigService bss, IEnumerable<IPlaceholderProvider> phProviders, SelfService selfService)
|
||||
public PlayingRotateService(
|
||||
DiscordSocketClient client,
|
||||
DbService db,
|
||||
Bot bot,
|
||||
BotConfigService bss,
|
||||
IEnumerable<IPlaceholderProvider> phProviders,
|
||||
SelfService selfService)
|
||||
{
|
||||
_db = db;
|
||||
_bot = bot;
|
||||
@@ -28,10 +28,7 @@ public sealed class PlayingRotateService : INService
|
||||
|
||||
if (client.ShardId == 0)
|
||||
{
|
||||
_rep = new ReplacementBuilder()
|
||||
.WithClient(client)
|
||||
.WithProviders(phProviders)
|
||||
.Build();
|
||||
_rep = new ReplacementBuilder().WithClient(client).WithProviders(phProviders).Build();
|
||||
|
||||
_t = new(RotatingStatuses, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||
}
|
||||
@@ -41,17 +38,14 @@ public sealed class PlayingRotateService : INService
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = (TimerState) objState;
|
||||
var state = (TimerState)objState;
|
||||
|
||||
if (!_bss.Data.RotateStatuses) return;
|
||||
|
||||
IReadOnlyList<RotatingPlayingStatus> rotatingStatuses;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
rotatingStatuses = uow.RotatingStatus
|
||||
.AsNoTracking()
|
||||
.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
rotatingStatuses = uow.RotatingStatus.AsNoTracking().OrderBy(x => x.Id).ToList();
|
||||
}
|
||||
|
||||
if (rotatingStatuses.Count == 0)
|
||||
@@ -76,11 +70,7 @@ public sealed class PlayingRotateService : INService
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var toRemove = await uow.RotatingStatus
|
||||
.AsQueryable()
|
||||
.AsNoTracking()
|
||||
.Skip(index)
|
||||
.FirstOrDefaultAsync();
|
||||
var toRemove = await uow.RotatingStatus.AsQueryable().AsNoTracking().Skip(index).FirstOrDefaultAsync();
|
||||
|
||||
if (toRemove is null)
|
||||
return null;
|
||||
@@ -93,7 +83,7 @@ public sealed class PlayingRotateService : INService
|
||||
public async Task AddPlaying(ActivityType t, string status)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var toAdd = new RotatingPlayingStatus {Status = status, Type = t};
|
||||
var toAdd = new RotatingPlayingStatus { Status = status, Type = t };
|
||||
uow.Add(toAdd);
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
@@ -110,4 +100,9 @@ public sealed class PlayingRotateService : INService
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.RotatingStatus.AsNoTracking().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private class TimerState
|
||||
{
|
||||
public int Index { get; set; }
|
||||
}
|
||||
}
|
@@ -1,38 +1,40 @@
|
||||
#nullable disable
|
||||
using System.Threading.Channels;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Administration.Common;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public class ProtectionService : INService
|
||||
{
|
||||
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, AntiRaidStats> _antiRaidGuilds = new();
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, AntiSpamStats> _antiSpamGuilds = new();
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, AntiAltStats> _antiAltGuilds = new();
|
||||
|
||||
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered
|
||||
= delegate { return Task.CompletedTask; };
|
||||
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly MuteService _mute;
|
||||
private readonly DbService _db;
|
||||
private readonly UserPunishService _punishService;
|
||||
|
||||
private readonly Channel<PunishQueueItem> PunishUserQueue =
|
||||
System.Threading.Channels.Channel.CreateUnbounded<PunishQueueItem>(new()
|
||||
{
|
||||
SingleReader = true,
|
||||
SingleWriter = false
|
||||
});
|
||||
|
||||
public ProtectionService(DiscordSocketClient client, Bot bot,
|
||||
MuteService mute, DbService db, UserPunishService punishService)
|
||||
{
|
||||
private readonly Channel<PunishQueueItem> PunishUserQueue =
|
||||
Channel.CreateUnbounded<PunishQueueItem>(new() { SingleReader = true, SingleWriter = false });
|
||||
|
||||
public ProtectionService(
|
||||
DiscordSocketClient client,
|
||||
Bot bot,
|
||||
MuteService mute,
|
||||
DbService db,
|
||||
UserPunishService punishService)
|
||||
{
|
||||
_client = client;
|
||||
_mute = mute;
|
||||
_db = db;
|
||||
@@ -42,18 +44,15 @@ public class ProtectionService : INService
|
||||
using (var uow = db.GetDbContext())
|
||||
{
|
||||
var configs = uow.Set<GuildConfig>()
|
||||
.AsQueryable()
|
||||
.Include(x => x.AntiRaidSetting)
|
||||
.Include(x => x.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels)
|
||||
.Include(x => x.AntiAltSetting)
|
||||
.Where(x => ids.Contains(x.GuildId))
|
||||
.ToList();
|
||||
.AsQueryable()
|
||||
.Include(x => x.AntiRaidSetting)
|
||||
.Include(x => x.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels)
|
||||
.Include(x => x.AntiAltSetting)
|
||||
.Where(x => ids.Contains(x.GuildId))
|
||||
.ToList();
|
||||
|
||||
foreach (var gc in configs)
|
||||
{
|
||||
Initialize(gc);
|
||||
}
|
||||
foreach (var gc in configs) Initialize(gc);
|
||||
}
|
||||
|
||||
_client.MessageReceived += HandleAntiSpam;
|
||||
@@ -61,7 +60,7 @@ public class ProtectionService : INService
|
||||
|
||||
bot.JoinedGuild += _bot_JoinedGuild;
|
||||
_client.LeftGuild += _client_LeftGuild;
|
||||
|
||||
|
||||
_ = Task.Run(RunQueue);
|
||||
}
|
||||
|
||||
@@ -75,8 +74,13 @@ public class ProtectionService : INService
|
||||
var gu = item.User;
|
||||
try
|
||||
{
|
||||
await _punishService.ApplyPunishment(gu.Guild, gu, _client.CurrentUser,
|
||||
item.Action, muteTime, item.RoleId, $"{item.Type} Protection");
|
||||
await _punishService.ApplyPunishment(gu.Guild,
|
||||
gu,
|
||||
_client.CurrentUser,
|
||||
item.Action,
|
||||
muteTime,
|
||||
item.RoleId,
|
||||
$"{item.Type} Protection");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -104,11 +108,10 @@ public class ProtectionService : INService
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var gcWithData = uow.GuildConfigsForId(gc.GuildId,
|
||||
set => set
|
||||
.Include(x => x.AntiRaidSetting)
|
||||
.Include(x => x.AntiAltSetting)
|
||||
.Include(x => x.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels));
|
||||
set => set.Include(x => x.AntiRaidSetting)
|
||||
.Include(x => x.AntiAltSetting)
|
||||
.Include(x => x.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels));
|
||||
|
||||
Initialize(gcWithData);
|
||||
return Task.CompletedTask;
|
||||
@@ -121,7 +124,7 @@ public class ProtectionService : INService
|
||||
|
||||
if (raid != null)
|
||||
{
|
||||
var raidStats = new AntiRaidStats() { AntiRaidSettings = raid };
|
||||
var raidStats = new AntiRaidStats { AntiRaidSettings = raid };
|
||||
_antiRaidGuilds[gc.GuildId] = raidStats;
|
||||
}
|
||||
|
||||
@@ -137,41 +140,38 @@ public class ProtectionService : INService
|
||||
{
|
||||
if (user.IsBot)
|
||||
return Task.CompletedTask;
|
||||
|
||||
|
||||
_antiRaidGuilds.TryGetValue(user.Guild.Id, out var maybeStats);
|
||||
_antiAltGuilds.TryGetValue(user.Guild.Id, out var maybeAlts);
|
||||
|
||||
|
||||
if (maybeStats is null && maybeAlts is null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (maybeAlts is { } alts)
|
||||
{
|
||||
if (user.CreatedAt != default)
|
||||
{
|
||||
var diff = DateTime.UtcNow - user.CreatedAt.UtcDateTime;
|
||||
if (diff < alts.MinAge)
|
||||
{
|
||||
alts.Increment();
|
||||
|
||||
await PunishUsers(
|
||||
alts.Action,
|
||||
|
||||
await PunishUsers(alts.Action,
|
||||
ProtectionType.Alting,
|
||||
alts.ActionDurationMinutes,
|
||||
alts.ActionDurationMinutes,
|
||||
alts.RoleId,
|
||||
user);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (maybeStats is not { } stats || !stats.RaidUsers.Add(user))
|
||||
return;
|
||||
|
||||
|
||||
++stats.UsersCount;
|
||||
|
||||
if (stats.UsersCount >= stats.AntiRaidSettings.UserThreshold)
|
||||
@@ -180,14 +180,13 @@ public class ProtectionService : INService
|
||||
stats.RaidUsers.Clear();
|
||||
var settings = stats.AntiRaidSettings;
|
||||
|
||||
await PunishUsers(settings.Action, ProtectionType.Raiding,
|
||||
settings.PunishDuration, null, users);
|
||||
await PunishUsers(settings.Action, ProtectionType.Raiding, settings.PunishDuration, null, users);
|
||||
}
|
||||
|
||||
await Task.Delay(1000 * stats.AntiRaidSettings.Seconds);
|
||||
|
||||
stats.RaidUsers.TryRemove(user);
|
||||
--stats.UsersCount;
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -208,29 +207,29 @@ public class ProtectionService : INService
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_antiSpamGuilds.TryGetValue(channel.Guild.Id, out var spamSettings) ||
|
||||
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
}))
|
||||
if (!_antiSpamGuilds.TryGetValue(channel.Guild.Id, out var spamSettings)
|
||||
|| spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new() { ChannelId = channel.Id }))
|
||||
return;
|
||||
|
||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, id => new(msg),
|
||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id,
|
||||
id => new(msg),
|
||||
(id, old) =>
|
||||
{
|
||||
old.ApplyNextMessage(msg); return old;
|
||||
old.ApplyNextMessage(msg);
|
||||
return old;
|
||||
});
|
||||
|
||||
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
||||
{
|
||||
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
|
||||
{
|
||||
stats.Dispose();
|
||||
var settings = spamSettings.AntiSpamSettings;
|
||||
await PunishUsers(settings.Action, ProtectionType.Spamming, settings.MuteTime,
|
||||
settings.RoleId, (IGuildUser)msg.Author);
|
||||
await PunishUsers(settings.Action,
|
||||
ProtectionType.Spamming,
|
||||
settings.MuteTime,
|
||||
settings.RoleId,
|
||||
(IGuildUser)msg.Author);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -240,18 +239,20 @@ public class ProtectionService : INService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task PunishUsers(PunishmentAction action, ProtectionType pt, int muteTime, ulong? roleId,
|
||||
private async Task PunishUsers(
|
||||
PunishmentAction action,
|
||||
ProtectionType pt,
|
||||
int muteTime,
|
||||
ulong? roleId,
|
||||
params IGuildUser[] gus)
|
||||
{
|
||||
Log.Information(
|
||||
"[{PunishType}] - Punishing [{Count}] users with [{PunishAction}] in {GuildName} guild",
|
||||
Log.Information("[{PunishType}] - Punishing [{Count}] users with [{PunishAction}] in {GuildName} guild",
|
||||
pt,
|
||||
gus.Length,
|
||||
action,
|
||||
gus[0].Guild.Name);
|
||||
|
||||
|
||||
foreach (var gu in gus)
|
||||
{
|
||||
await PunishUserQueue.Writer.WriteAsync(new()
|
||||
{
|
||||
Action = action,
|
||||
@@ -260,24 +261,27 @@ public class ProtectionService : INService
|
||||
MuteTime = muteTime,
|
||||
RoleId = roleId
|
||||
});
|
||||
}
|
||||
|
||||
_ = OnAntiProtectionTriggered(action, pt, gus);
|
||||
}
|
||||
|
||||
public async Task<AntiRaidStats> StartAntiRaidAsync(ulong guildId, int userThreshold, int seconds,
|
||||
PunishmentAction action, int minutesDuration)
|
||||
public async Task<AntiRaidStats> StartAntiRaidAsync(
|
||||
ulong guildId,
|
||||
int userThreshold,
|
||||
int seconds,
|
||||
PunishmentAction action,
|
||||
int minutesDuration)
|
||||
{
|
||||
var g = _client.GetGuild(guildId);
|
||||
await _mute.GetMuteRole(g);
|
||||
|
||||
if (action == PunishmentAction.AddRole)
|
||||
return null;
|
||||
|
||||
|
||||
if (!IsDurationAllowed(action))
|
||||
minutesDuration = 0;
|
||||
|
||||
var stats = new AntiRaidStats()
|
||||
var stats = new AntiRaidStats
|
||||
{
|
||||
AntiRaidSettings = new()
|
||||
{
|
||||
@@ -310,6 +314,7 @@ public class ProtectionService : INService
|
||||
uow.SaveChanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -317,24 +322,26 @@ public class ProtectionService : INService
|
||||
{
|
||||
if (_antiSpamGuilds.TryRemove(guildId, out var removed))
|
||||
{
|
||||
foreach (var (_, val) in removed.UserStats)
|
||||
{
|
||||
val.Dispose();
|
||||
}
|
||||
|
||||
foreach (var (_, val) in removed.UserStats) val.Dispose();
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels));
|
||||
var gc = uow.GuildConfigsForId(guildId,
|
||||
set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels));
|
||||
|
||||
gc.AntiSpamSetting = null;
|
||||
uow.SaveChanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<AntiSpamStats> StartAntiSpamAsync(ulong guildId, int messageCount, PunishmentAction action,
|
||||
int punishDurationMinutes, ulong? roleId)
|
||||
public async Task<AntiSpamStats> StartAntiSpamAsync(
|
||||
ulong guildId,
|
||||
int messageCount,
|
||||
PunishmentAction action,
|
||||
int punishDurationMinutes,
|
||||
ulong? roleId)
|
||||
{
|
||||
var g = _client.GetGuild(guildId);
|
||||
await _mute.GetMuteRole(g);
|
||||
@@ -349,15 +356,17 @@ public class ProtectionService : INService
|
||||
Action = action,
|
||||
MessageThreshold = messageCount,
|
||||
MuteTime = punishDurationMinutes,
|
||||
RoleId = roleId,
|
||||
RoleId = roleId
|
||||
}
|
||||
};
|
||||
|
||||
stats = _antiSpamGuilds.AddOrUpdate(guildId, stats, (key, old) =>
|
||||
{
|
||||
stats.AntiSpamSettings.IgnoredChannels = old.AntiSpamSettings.IgnoredChannels;
|
||||
return stats;
|
||||
});
|
||||
stats = _antiSpamGuilds.AddOrUpdate(guildId,
|
||||
stats,
|
||||
(key, old) =>
|
||||
{
|
||||
stats.AntiSpamSettings.IgnoredChannels = old.AntiSpamSettings.IgnoredChannels;
|
||||
return stats;
|
||||
});
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiSpamSetting));
|
||||
@@ -373,24 +382,20 @@ public class ProtectionService : INService
|
||||
{
|
||||
gc.AntiSpamSetting = stats.AntiSpamSettings;
|
||||
}
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
return stats;
|
||||
}
|
||||
|
||||
public async Task<bool?> AntiSpamIgnoreAsync(ulong guildId, ulong channelId)
|
||||
{
|
||||
var obj = new AntiSpamIgnore()
|
||||
{
|
||||
ChannelId = channelId
|
||||
};
|
||||
var obj = new AntiSpamIgnore { ChannelId = channelId };
|
||||
bool added;
|
||||
await using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels));
|
||||
var gc = uow.GuildConfigsForId(guildId,
|
||||
set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels));
|
||||
var spam = gc.AntiSpamSetting;
|
||||
if (spam is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (spam is null) return null;
|
||||
|
||||
if (spam.IgnoredChannels.Add(obj)) // if adding to db is successful
|
||||
{
|
||||
@@ -403,9 +408,7 @@ public class ProtectionService : INService
|
||||
var toRemove = spam.IgnoredChannels.First(x => x.ChannelId == channelId);
|
||||
uow.Set<AntiSpamIgnore>().Remove(toRemove); // remove from db
|
||||
if (_antiSpamGuilds.TryGetValue(guildId, out var temp))
|
||||
{
|
||||
temp.AntiSpamSettings.IgnoredChannels.Remove(toRemove); // remove from local cache
|
||||
}
|
||||
added = false;
|
||||
}
|
||||
|
||||
@@ -437,8 +440,12 @@ public class ProtectionService : INService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartAntiAltAsync(ulong guildId, int minAgeMinutes, PunishmentAction action,
|
||||
int actionDurationMinutes = 0, ulong? roleId = null)
|
||||
public async Task StartAntiAltAsync(
|
||||
ulong guildId,
|
||||
int minAgeMinutes,
|
||||
PunishmentAction action,
|
||||
int actionDurationMinutes = 0,
|
||||
ulong? roleId = null)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiAltSetting));
|
||||
@@ -447,7 +454,7 @@ public class ProtectionService : INService
|
||||
Action = action,
|
||||
ActionDurationMinutes = actionDurationMinutes,
|
||||
MinAge = TimeSpan.FromMinutes(minAgeMinutes),
|
||||
RoleId = roleId,
|
||||
RoleId = roleId
|
||||
};
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
@@ -465,4 +472,4 @@ public class ProtectionService : INService
|
||||
await uow.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,12 +9,12 @@ public class PruneService : INService
|
||||
private readonly ILogCommandService _logService;
|
||||
|
||||
public PruneService(ILogCommandService logService)
|
||||
=> this._logService = logService;
|
||||
=> _logService = logService;
|
||||
|
||||
public async Task PruneWhere(ITextChannel channel, int amount, Func<IMessage, bool> predicate)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(channel, nameof(channel));
|
||||
|
||||
|
||||
if (amount <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(amount));
|
||||
|
||||
@@ -46,17 +46,16 @@ public class PruneService : INService
|
||||
await Task.WhenAll(Task.Delay(1000), channel.DeleteMessagesAsync(bulkDeletable));
|
||||
|
||||
foreach (var group in singleDeletable.Chunk(5))
|
||||
await Task.WhenAll(
|
||||
Task.Delay(1000),
|
||||
group.Select(x => x.DeleteAsync())
|
||||
.WhenAll()
|
||||
);
|
||||
await Task.WhenAll(Task.Delay(1000), group.Select(x => x.DeleteAsync()).WhenAll());
|
||||
|
||||
//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).FlattenAsync()).Where(predicate).Take(amount).ToArray();
|
||||
if (amount > 0)
|
||||
msgs = (await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).FlattenAsync())
|
||||
.Where(predicate)
|
||||
.Take(amount)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -68,4 +67,4 @@ public class PruneService : INService
|
||||
_pruningGuilds.TryRemove(channel.GuildId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,10 +1,10 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -15,36 +15,34 @@ public class RoleCommandsService : INService
|
||||
private readonly ConcurrentDictionary<ulong, IndexedCollection<ReactionRoleMessage>> _models;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the (Message ID, User ID) of reaction roles that are currently being processed.
|
||||
/// Contains the (Message ID, User ID) of reaction roles that are currently being processed.
|
||||
/// </summary>
|
||||
private readonly ConcurrentHashSet<(ulong, ulong)> _reacting = new();
|
||||
|
||||
public RoleCommandsService(DiscordSocketClient client, DbService db,
|
||||
Bot bot)
|
||||
public RoleCommandsService(DiscordSocketClient client, DbService db, Bot bot)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
#if !GLOBAL_NADEKO
|
||||
_models = bot.AllGuildConfigs.ToDictionary(x => x.GuildId,
|
||||
x => x.ReactionRoleMessages)
|
||||
.ToConcurrent();
|
||||
_models = bot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.ReactionRoleMessages).ToConcurrent();
|
||||
|
||||
_client.ReactionAdded += _client_ReactionAdded;
|
||||
_client.ReactionRemoved += _client_ReactionRemoved;
|
||||
#endif
|
||||
}
|
||||
|
||||
private Task _client_ReactionAdded(Cacheable<IUserMessage, ulong> msg,
|
||||
private Task _client_ReactionAdded(
|
||||
Cacheable<IUserMessage, ulong> msg,
|
||||
Cacheable<IMessageChannel, ulong> chan,
|
||||
SocketReaction reaction)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (!reaction.User.IsSpecified ||
|
||||
reaction.User.Value.IsBot ||
|
||||
reaction.User.Value is not SocketGuildUser gusr ||
|
||||
chan.Value is not SocketGuildChannel gch ||
|
||||
!_models.TryGetValue(gch.Guild.Id, out var confs))
|
||||
if (!reaction.User.IsSpecified
|
||||
|| reaction.User.Value.IsBot
|
||||
|| reaction.User.Value is not SocketGuildUser gusr
|
||||
|| chan.Value is not SocketGuildChannel gch
|
||||
|| !_models.TryGetValue(gch.Guild.Id, out var confs))
|
||||
return;
|
||||
|
||||
var conf = confs.FirstOrDefault(x => x.MessageId == msg.Id);
|
||||
@@ -53,7 +51,8 @@ public class RoleCommandsService : INService
|
||||
return;
|
||||
|
||||
// compare emote names for backwards compatibility :facepalm:
|
||||
var reactionRole = conf.ReactionRoles.FirstOrDefault(x => x.EmoteName == reaction.Emote.Name || x.EmoteName == reaction.Emote.ToString());
|
||||
var reactionRole = conf.ReactionRoles.FirstOrDefault(x
|
||||
=> x.EmoteName == reaction.Emote.Name || x.EmoteName == reaction.Emote.ToString());
|
||||
|
||||
if (reactionRole != null)
|
||||
{
|
||||
@@ -69,7 +68,12 @@ public class RoleCommandsService : INService
|
||||
|
||||
try
|
||||
{
|
||||
var removeExclusiveTask = RemoveExclusiveReactionRoleAsync(msg, gusr, reaction, conf, reactionRole, CancellationToken.None);
|
||||
var removeExclusiveTask = RemoveExclusiveReactionRoleAsync(msg,
|
||||
gusr,
|
||||
reaction,
|
||||
conf,
|
||||
reactionRole,
|
||||
CancellationToken.None);
|
||||
var addRoleTask = AddReactionRoleAsync(gusr, reactionRole);
|
||||
|
||||
await Task.WhenAll(removeExclusiveTask, addRoleTask);
|
||||
@@ -83,11 +87,9 @@ public class RoleCommandsService : INService
|
||||
else
|
||||
{
|
||||
var dl = await msg.GetOrDownloadAsync();
|
||||
await dl.RemoveReactionAsync(reaction.Emote, dl.Author,
|
||||
new()
|
||||
{
|
||||
RetryMode = RetryMode.RetryRatelimit | RetryMode.Retry502
|
||||
});
|
||||
await dl.RemoveReactionAsync(reaction.Emote,
|
||||
dl.Author,
|
||||
new() { RetryMode = RetryMode.RetryRatelimit | RetryMode.Retry502 });
|
||||
Log.Warning("User {0} is adding unrelated reactions to the reaction roles message.", dl.Author);
|
||||
}
|
||||
});
|
||||
@@ -95,7 +97,8 @@ public class RoleCommandsService : INService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task _client_ReactionRemoved(Cacheable<IUserMessage, ulong> msg,
|
||||
private Task _client_ReactionRemoved(
|
||||
Cacheable<IUserMessage, ulong> msg,
|
||||
Cacheable<IMessageChannel, ulong> chan,
|
||||
SocketReaction reaction)
|
||||
{
|
||||
@@ -103,9 +106,9 @@ public class RoleCommandsService : INService
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!reaction.User.IsSpecified ||
|
||||
reaction.User.Value.IsBot ||
|
||||
reaction.User.Value is not SocketGuildUser gusr)
|
||||
if (!reaction.User.IsSpecified
|
||||
|| reaction.User.Value.IsBot
|
||||
|| reaction.User.Value is not SocketGuildUser gusr)
|
||||
return;
|
||||
|
||||
if (chan.Value is not SocketGuildChannel gch)
|
||||
@@ -119,7 +122,8 @@ public class RoleCommandsService : INService
|
||||
if (conf is null)
|
||||
return;
|
||||
|
||||
var reactionRole = conf.ReactionRoles.FirstOrDefault(x => x.EmoteName == reaction.Emote.Name || x.EmoteName == reaction.Emote.ToString());
|
||||
var reactionRole = conf.ReactionRoles.FirstOrDefault(x
|
||||
=> x.EmoteName == reaction.Emote.Name || x.EmoteName == reaction.Emote.ToString());
|
||||
|
||||
if (reactionRole != null)
|
||||
{
|
||||
@@ -143,20 +147,17 @@ public class RoleCommandsService : INService
|
||||
using var uow = _db.GetDbContext();
|
||||
var table = uow.GetTable<ReactionRoleMessage>();
|
||||
table.Delete(x => x.MessageId == rrm.MessageId);
|
||||
|
||||
var gc = uow.GuildConfigsForId(id, set => set
|
||||
.Include(x => x.ReactionRoleMessages)
|
||||
.ThenInclude(x => x.ReactionRoles));
|
||||
|
||||
|
||||
var gc = uow.GuildConfigsForId(id,
|
||||
set => set.Include(x => x.ReactionRoleMessages).ThenInclude(x => x.ReactionRoles));
|
||||
|
||||
if (gc.ReactionRoleMessages.Count >= 10)
|
||||
return false;
|
||||
|
||||
|
||||
gc.ReactionRoleMessages.Add(rrm);
|
||||
uow.SaveChanges();
|
||||
|
||||
_models.AddOrUpdate(id,
|
||||
gc.ReactionRoleMessages,
|
||||
delegate { return gc.ReactionRoleMessages; });
|
||||
|
||||
_models.AddOrUpdate(id, gc.ReactionRoleMessages, delegate { return gc.ReactionRoleMessages; });
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -164,19 +165,15 @@ public class RoleCommandsService : INService
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(id,
|
||||
set => set.Include(x => x.ReactionRoleMessages)
|
||||
.ThenInclude(x => x.ReactionRoles));
|
||||
uow.Set<ReactionRole>()
|
||||
.RemoveRange(gc.ReactionRoleMessages[index].ReactionRoles);
|
||||
set => set.Include(x => x.ReactionRoleMessages).ThenInclude(x => x.ReactionRoles));
|
||||
uow.Set<ReactionRole>().RemoveRange(gc.ReactionRoleMessages[index].ReactionRoles);
|
||||
gc.ReactionRoleMessages.RemoveAt(index);
|
||||
_models.AddOrUpdate(id,
|
||||
gc.ReactionRoleMessages,
|
||||
delegate { return gc.ReactionRoleMessages; });
|
||||
_models.AddOrUpdate(id, gc.ReactionRoleMessages, delegate { return gc.ReactionRoleMessages; });
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a reaction role to the specified user.
|
||||
/// Adds a reaction role to the specified user.
|
||||
/// </summary>
|
||||
/// <param name="user">A Discord guild user.</param>
|
||||
/// <param name="dbRero">The database settings of this reaction role.</param>
|
||||
@@ -184,13 +181,11 @@ public class RoleCommandsService : INService
|
||||
{
|
||||
var toAdd = user.Guild.GetRole(dbRero.RoleId);
|
||||
|
||||
return toAdd != null && !user.Roles.Contains(toAdd)
|
||||
? user.AddRoleAsync(toAdd)
|
||||
: Task.CompletedTask;
|
||||
return toAdd != null && !user.Roles.Contains(toAdd) ? user.AddRoleAsync(toAdd) : Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the exclusive reaction roles and reactions from the specified user.
|
||||
/// Removes the exclusive reaction roles and reactions from the specified user.
|
||||
/// </summary>
|
||||
/// <param name="reactionMessage">The Discord message that contains the reaction roles.</param>
|
||||
/// <param name="user">A Discord guild user.</param>
|
||||
@@ -200,14 +195,20 @@ public class RoleCommandsService : INService
|
||||
/// <param name="cToken">A cancellation token to cancel the operation.</param>
|
||||
/// <exception cref="OperationCanceledException">Occurs when the operation is cancelled before it began.</exception>
|
||||
/// <exception cref="TaskCanceledException">Occurs when the operation is cancelled while it's still executing.</exception>
|
||||
private Task RemoveExclusiveReactionRoleAsync(Cacheable<IUserMessage, ulong> reactionMessage, SocketGuildUser user, SocketReaction reaction, ReactionRoleMessage dbReroMsg, ReactionRole dbRero, CancellationToken cToken = default)
|
||||
private Task RemoveExclusiveReactionRoleAsync(
|
||||
Cacheable<IUserMessage, ulong> reactionMessage,
|
||||
SocketGuildUser user,
|
||||
SocketReaction reaction,
|
||||
ReactionRoleMessage dbReroMsg,
|
||||
ReactionRole dbRero,
|
||||
CancellationToken cToken = default)
|
||||
{
|
||||
cToken.ThrowIfCancellationRequested();
|
||||
|
||||
var roleIds = dbReroMsg.ReactionRoles.Select(x => x.RoleId)
|
||||
.Where(x => x != dbRero.RoleId)
|
||||
.Select(x => user.Guild.GetRole(x))
|
||||
.Where(x => x != null);
|
||||
.Where(x => x != dbRero.RoleId)
|
||||
.Select(x => user.Guild.GetRole(x))
|
||||
.Where(x => x != null);
|
||||
|
||||
var removeReactionsTask = RemoveOldReactionsAsync(reactionMessage, user, reaction, cToken);
|
||||
|
||||
@@ -217,7 +218,7 @@ public class RoleCommandsService : INService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes old reactions from an exclusive reaction role.
|
||||
/// Removes old reactions from an exclusive reaction role.
|
||||
/// </summary>
|
||||
/// <param name="reactionMessage">The Discord message that contains the reaction roles.</param>
|
||||
/// <param name="user">A Discord guild user.</param>
|
||||
@@ -225,7 +226,11 @@ public class RoleCommandsService : INService
|
||||
/// <param name="cToken">A cancellation token to cancel the operation.</param>
|
||||
/// <exception cref="OperationCanceledException">Occurs when the operation is cancelled before it began.</exception>
|
||||
/// <exception cref="TaskCanceledException">Occurs when the operation is cancelled while it's still executing.</exception>
|
||||
private async Task RemoveOldReactionsAsync(Cacheable<IUserMessage, ulong> reactionMessage, SocketGuildUser user, SocketReaction reaction, CancellationToken cToken = default)
|
||||
private async Task RemoveOldReactionsAsync(
|
||||
Cacheable<IUserMessage, ulong> reactionMessage,
|
||||
SocketGuildUser user,
|
||||
SocketReaction reaction,
|
||||
CancellationToken cToken = default)
|
||||
{
|
||||
cToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -236,8 +241,10 @@ public class RoleCommandsService : INService
|
||||
{
|
||||
if (r.Key.Name == reaction.Emote.Name)
|
||||
continue;
|
||||
try { await dl.RemoveReactionAsync(r.Key, user); } catch { }
|
||||
try { await dl.RemoveReactionAsync(r.Key, user); }
|
||||
catch { }
|
||||
|
||||
await Task.Delay(100, cToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,32 +1,32 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Xp;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public class SelfAssignedRolesService : INService
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public enum RemoveResult
|
||||
{
|
||||
Removed, // successfully removed
|
||||
Err_Not_Assignable, // not assignable (error)
|
||||
Err_Not_Have, // you don't have a role you want to remove (error)
|
||||
Err_Not_Perms, // bot doesn't have perms (error)
|
||||
}
|
||||
|
||||
public enum AssignResult
|
||||
{
|
||||
Assigned, // successfully removed
|
||||
Err_Not_Assignable, // not assignable (error)
|
||||
Err_Already_Have, // you already have that role (error)
|
||||
Err_Not_Perms, // bot doesn't have perms (error)
|
||||
Err_Lvl_Req, // you are not required level (error)
|
||||
Err_Lvl_Req // you are not required level (error)
|
||||
}
|
||||
|
||||
public enum RemoveResult
|
||||
{
|
||||
Removed, // successfully removed
|
||||
Err_Not_Assignable, // not assignable (error)
|
||||
Err_Not_Have, // you don't have a role you want to remove (error)
|
||||
Err_Not_Perms // bot doesn't have perms (error)
|
||||
}
|
||||
|
||||
private readonly DbService _db;
|
||||
|
||||
public SelfAssignedRolesService(DbService db)
|
||||
=> _db = db;
|
||||
|
||||
@@ -34,17 +34,9 @@ public class SelfAssignedRolesService : INService
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var roles = uow.SelfAssignableRoles.GetFromGuild(guildId);
|
||||
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id)) return false;
|
||||
|
||||
uow.SelfAssignableRoles.Add(new()
|
||||
{
|
||||
Group = @group,
|
||||
RoleId = role.Id,
|
||||
GuildId = role.Guild.Id
|
||||
});
|
||||
uow.SelfAssignableRoles.Add(new() { Group = group, RoleId = role.Id, GuildId = role.Guild.Id });
|
||||
uow.SaveChanges();
|
||||
return true;
|
||||
}
|
||||
@@ -72,31 +64,20 @@ public class SelfAssignedRolesService : INService
|
||||
|
||||
var theRoleYouWant = roles.FirstOrDefault(r => r.RoleId == role.Id);
|
||||
if (theRoleYouWant is null)
|
||||
{
|
||||
return (AssignResult.Err_Not_Assignable, autoDelete, null);
|
||||
}
|
||||
else if (theRoleYouWant.LevelRequirement > userLevelData.Level)
|
||||
{
|
||||
if (theRoleYouWant.LevelRequirement > userLevelData.Level)
|
||||
return (AssignResult.Err_Lvl_Req, autoDelete, theRoleYouWant.LevelRequirement);
|
||||
}
|
||||
else if (guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
return (AssignResult.Err_Already_Have, autoDelete, null);
|
||||
}
|
||||
if (guildUser.RoleIds.Contains(role.Id)) return (AssignResult.Err_Already_Have, autoDelete, null);
|
||||
|
||||
var roleIds = roles
|
||||
.Where(x => x.Group == theRoleYouWant.Group)
|
||||
.Select(x => x.RoleId).ToArray();
|
||||
var roleIds = roles.Where(x => x.Group == theRoleYouWant.Group).Select(x => x.RoleId).ToArray();
|
||||
if (exclusive)
|
||||
{
|
||||
var sameRoles = guildUser.RoleIds
|
||||
.Where(r => roleIds.Contains(r));
|
||||
var sameRoles = guildUser.RoleIds.Where(r => roleIds.Contains(r));
|
||||
|
||||
foreach (var roleId in sameRoles)
|
||||
{
|
||||
var sameRole = guildUser.Guild.GetRole(roleId);
|
||||
if (sameRole != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(sameRole);
|
||||
@@ -106,9 +87,9 @@ public class SelfAssignedRolesService : INService
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await guildUser.AddRoleAsync(role);
|
||||
@@ -126,7 +107,7 @@ public class SelfAssignedRolesService : INService
|
||||
var set = false;
|
||||
await using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, y => y.Include(x => x.SelfAssignableRoleGroupNames));
|
||||
var toUpdate = gc.SelfAssignableRoleGroupNames.FirstOrDefault(x => x.Number == @group);
|
||||
var toUpdate = gc.SelfAssignableRoleGroupNames.FirstOrDefault(x => x.Number == group);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
@@ -135,11 +116,7 @@ public class SelfAssignedRolesService : INService
|
||||
}
|
||||
else if (toUpdate is null)
|
||||
{
|
||||
gc.SelfAssignableRoleGroupNames.Add(new()
|
||||
{
|
||||
Name = name,
|
||||
Number = @group,
|
||||
});
|
||||
gc.SelfAssignableRoleGroupNames.Add(new() { Name = name, Number = group });
|
||||
set = true;
|
||||
}
|
||||
else
|
||||
@@ -158,13 +135,8 @@ public class SelfAssignedRolesService : INService
|
||||
var (autoDelete, _, roles) = GetAdAndRoles(guildUser.Guild.Id);
|
||||
|
||||
if (roles.FirstOrDefault(r => r.RoleId == role.Id) is null)
|
||||
{
|
||||
return (RemoveResult.Err_Not_Assignable, autoDelete);
|
||||
}
|
||||
if (!guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
return (RemoveResult.Err_Not_Have, autoDelete);
|
||||
}
|
||||
if (!guildUser.RoleIds.Contains(role.Id)) return (RemoveResult.Err_Not_Have, autoDelete);
|
||||
try
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(role);
|
||||
@@ -226,7 +198,8 @@ public class SelfAssignedRolesService : INService
|
||||
return areExclusive;
|
||||
}
|
||||
|
||||
public (bool Exclusive, IEnumerable<(SelfAssignedRole Model, IRole Role)> Roles, IDictionary<int, string> GroupNames) GetRoles(IGuild guild)
|
||||
public (bool Exclusive, IEnumerable<(SelfAssignedRole Model, IRole Role)> Roles, IDictionary<int, string> GroupNames
|
||||
) GetRoles(IGuild guild)
|
||||
{
|
||||
var exclusive = false;
|
||||
|
||||
@@ -238,12 +211,11 @@ public class SelfAssignedRolesService : INService
|
||||
exclusive = gc.ExclusiveSelfAssignedRoles;
|
||||
groupNames = gc.SelfAssignableRoleGroupNames.ToDictionary(x => x.Number, x => x.Name);
|
||||
var roleModels = uow.SelfAssignableRoles.GetFromGuild(guild.Id);
|
||||
roles = roleModels
|
||||
.Select(x => (Model: x, Role: guild.GetRole(x.RoleId)));
|
||||
roles = roleModels.Select(x => (Model: x, Role: guild.GetRole(x.RoleId)));
|
||||
uow.SelfAssignableRoles.RemoveRange(roles.Where(x => x.Role is null).Select(x => x.Model).ToArray());
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
return (exclusive, roles.Where(x => x.Role != null), groupNames);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
#nullable disable
|
||||
using System.Collections.Immutable;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -56,58 +56,49 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
_activitySetKey = new("activity.set");
|
||||
_imagesReloadKey = new("images.reload");
|
||||
_guildLeaveKey = new("guild.leave");
|
||||
|
||||
|
||||
HandleStatusChanges();
|
||||
|
||||
if (_client.ShardId == 0)
|
||||
{
|
||||
_pubSub.Sub(_imagesReloadKey, async _ => await _imgs.Reload());
|
||||
}
|
||||
|
||||
_pubSub.Sub(_guildLeaveKey, async input =>
|
||||
{
|
||||
var guildStr = input.ToString().Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(guildStr))
|
||||
return;
|
||||
if (_client.ShardId == 0) _pubSub.Sub(_imagesReloadKey, async _ => await _imgs.Reload());
|
||||
|
||||
var server = _client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr
|
||||
|| g.Name.Trim().ToUpperInvariant() == guildStr);
|
||||
if (server is null)
|
||||
_pubSub.Sub(_guildLeaveKey,
|
||||
async input =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
var guildStr = input.ToString().Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(guildStr))
|
||||
return;
|
||||
|
||||
if (server.OwnerId != _client.CurrentUser.Id)
|
||||
{
|
||||
await server.LeaveAsync();
|
||||
Log.Information($"Left server {server.Name} [{server.Id}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
await server.DeleteAsync();
|
||||
Log.Information($"Deleted server {server.Name} [{server.Id}]");
|
||||
}
|
||||
});
|
||||
var server = _client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr
|
||||
|| g.Name.Trim().ToUpperInvariant() == guildStr);
|
||||
if (server is null) return;
|
||||
|
||||
if (server.OwnerId != _client.CurrentUser.Id)
|
||||
{
|
||||
await server.LeaveAsync();
|
||||
Log.Information($"Left server {server.Name} [{server.Id}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
await server.DeleteAsync();
|
||||
Log.Information($"Deleted server {server.Name} [{server.Id}]");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
_autoCommands = uow
|
||||
.AutoCommands
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Interval >= 5)
|
||||
.AsEnumerable()
|
||||
.GroupBy(x => x.GuildId)
|
||||
.ToDictionary(x => x.Key,
|
||||
y => y.ToDictionary(x => x.Id, TimerFromAutoCommand)
|
||||
.ToConcurrent())
|
||||
.ToConcurrent();
|
||||
_autoCommands = uow.AutoCommands.AsNoTracking()
|
||||
.Where(x => x.Interval >= 5)
|
||||
.AsEnumerable()
|
||||
.GroupBy(x => x.GuildId)
|
||||
.ToDictionary(x => x.Key,
|
||||
y => y.ToDictionary(x => x.Id, TimerFromAutoCommand).ToConcurrent())
|
||||
.ToConcurrent();
|
||||
|
||||
var startupCommands = uow.AutoCommands.AsNoTracking().Where(x => x.Interval == 0);
|
||||
foreach (var cmd in startupCommands)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ExecuteCommand(cmd);
|
||||
@@ -115,19 +106,12 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (_client.ShardId == 0)
|
||||
{
|
||||
await LoadOwnerChannels();
|
||||
}
|
||||
if (_client.ShardId == 0) await LoadOwnerChannels();
|
||||
}
|
||||
|
||||
private Timer TimerFromAutoCommand(AutoCommand x)
|
||||
=> new(async obj => await ExecuteCommand((AutoCommand) obj),
|
||||
x,
|
||||
x.Interval * 1000,
|
||||
x.Interval * 1000);
|
||||
=> new(async obj => await ExecuteCommand((AutoCommand)obj), x, x.Interval * 1000, x.Interval * 1000);
|
||||
|
||||
private async Task ExecuteCommand(AutoCommand cmd)
|
||||
{
|
||||
@@ -136,7 +120,7 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
if (cmd.GuildId is null)
|
||||
return;
|
||||
|
||||
var guildShard = (int) ((cmd.GuildId.Value >> 22) % (ulong) _creds.TotalShards);
|
||||
var guildShard = (int)((cmd.GuildId.Value >> 22) % (ulong)_creds.TotalShards);
|
||||
if (guildShard != _client.ShardId)
|
||||
return;
|
||||
var prefix = _cmdHandler.GetPrefix(cmd.GuildId);
|
||||
@@ -162,34 +146,26 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
if (cmd.Interval >= 5)
|
||||
{
|
||||
var autos = _autoCommands.GetOrAdd(cmd.GuildId, new ConcurrentDictionary<int, Timer>());
|
||||
autos.AddOrUpdate(cmd.Id, key => TimerFromAutoCommand(cmd), (key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return TimerFromAutoCommand(cmd);
|
||||
});
|
||||
autos.AddOrUpdate(cmd.Id,
|
||||
key => TimerFromAutoCommand(cmd),
|
||||
(key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return TimerFromAutoCommand(cmd);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AutoCommand> GetStartupCommands()
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow
|
||||
.AutoCommands
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Interval == 0)
|
||||
.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
return uow.AutoCommands.AsNoTracking().Where(x => x.Interval == 0).OrderBy(x => x.Id).ToList();
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<AutoCommand> GetAutoCommands()
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow
|
||||
.AutoCommands
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Interval >= 5)
|
||||
.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
return uow.AutoCommands.AsNoTracking().Where(x => x.Interval >= 5).OrderBy(x => x.Id).ToList();
|
||||
}
|
||||
|
||||
private async Task LoadOwnerChannels()
|
||||
@@ -204,8 +180,8 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
}));
|
||||
|
||||
ownerChannels = channels.Where(x => x != null)
|
||||
.ToDictionary(x => x.Recipient.Id, x => x)
|
||||
.ToImmutableDictionary();
|
||||
.ToDictionary(x => x.Recipient.Id, x => x)
|
||||
.ToImmutableDictionary();
|
||||
|
||||
if (!ownerChannels.Any())
|
||||
Log.Warning(
|
||||
@@ -214,7 +190,7 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
Log.Information($"Created {ownerChannels.Count} out of {_creds.OwnerIds.Count} owner message channels.");
|
||||
}
|
||||
|
||||
public Task LeaveGuild(string guildStr)
|
||||
public Task LeaveGuild(string guildStr)
|
||||
=> _pubSub.Pub(_guildLeaveKey, guildStr);
|
||||
|
||||
// forwards dms
|
||||
@@ -223,25 +199,21 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
var bs = _bss.Data;
|
||||
if (msg.Channel is IDMChannel && bs.ForwardMessages && ownerChannels.Any())
|
||||
{
|
||||
var title = _strings.GetText(strs.dm_from) +
|
||||
$" [{msg.Author}]({msg.Author.Id})";
|
||||
var title = _strings.GetText(strs.dm_from) + $" [{msg.Author}]({msg.Author.Id})";
|
||||
|
||||
var attachamentsTxt = _strings.GetText(strs.attachments);
|
||||
|
||||
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));
|
||||
}
|
||||
toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n"
|
||||
+ string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl));
|
||||
|
||||
if (bs.ForwardToAllOwners)
|
||||
{
|
||||
var allOwnerChannels = ownerChannels.Values;
|
||||
|
||||
foreach (var ownerCh in allOwnerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id))
|
||||
{
|
||||
try
|
||||
{
|
||||
await ownerCh.SendConfirmAsync(_eb, title, toSend);
|
||||
@@ -250,13 +222,11 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
{
|
||||
Log.Warning("Can't contact owner with id {0}", ownerCh.Recipient.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstOwnerChannel = ownerChannels.Values.First();
|
||||
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await firstOwnerChannel.SendConfirmAsync(_eb, title, toSend);
|
||||
@@ -265,7 +235,6 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,11 +242,7 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
public bool RemoveStartupCommand(int index, out AutoCommand cmd)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
cmd = uow.AutoCommands
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Interval == 0)
|
||||
.Skip(index)
|
||||
.FirstOrDefault();
|
||||
cmd = uow.AutoCommands.AsNoTracking().Where(x => x.Interval == 0).Skip(index).FirstOrDefault();
|
||||
|
||||
if (cmd != null)
|
||||
{
|
||||
@@ -288,15 +253,11 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public bool RemoveAutoCommand(int index, out AutoCommand cmd)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
cmd = uow.AutoCommands
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Interval >= 5)
|
||||
.Skip(index)
|
||||
.FirstOrDefault();
|
||||
cmd = uow.AutoCommands.AsNoTracking().Where(x => x.Interval >= 5).Skip(index).FirstOrDefault();
|
||||
|
||||
if (cmd != null)
|
||||
{
|
||||
@@ -337,16 +298,13 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
public void ClearStartupCommands()
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var toRemove = uow
|
||||
.AutoCommands
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Interval == 0);
|
||||
var toRemove = uow.AutoCommands.AsNoTracking().Where(x => x.Interval == 0);
|
||||
|
||||
uow.AutoCommands.RemoveRange(toRemove);
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
public Task ReloadImagesAsync()
|
||||
public Task ReloadImagesAsync()
|
||||
=> _pubSub.Pub(_imagesReloadKey, true);
|
||||
|
||||
public bool ForwardMessages()
|
||||
@@ -363,22 +321,23 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
_bss.ModifyConfig(config => { isToAll = config.ForwardToAllOwners = !config.ForwardToAllOwners; });
|
||||
return isToAll;
|
||||
}
|
||||
|
||||
private void HandleStatusChanges()
|
||||
=> _pubSub.Sub(_activitySetKey, async data =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await _client.SetGameAsync(data.Name, data.Link, type: data.Type);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Error setting activity");
|
||||
}
|
||||
});
|
||||
|
||||
public Task SetGameAsync(string game, ActivityType type)
|
||||
=> _pubSub.Pub(_activitySetKey, new() {Name = game, Link = null, Type = type});
|
||||
private void HandleStatusChanges()
|
||||
=> _pubSub.Sub(_activitySetKey,
|
||||
async data =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await _client.SetGameAsync(data.Name, data.Link, data.Type);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Error setting activity");
|
||||
}
|
||||
});
|
||||
|
||||
public Task SetGameAsync(string game, ActivityType type)
|
||||
=> _pubSub.Pub(_activitySetKey, new() { Name = game, Link = null, Type = type });
|
||||
|
||||
public Task SetStreamAsync(string name, string link)
|
||||
=> _pubSub.Pub(_activitySetKey, new() { Name = name, Link = link, Type = ActivityType.Streaming });
|
||||
@@ -389,4 +348,4 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
|
||||
public string Link { get; init; }
|
||||
public ActivityType Type { get; init; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
@@ -16,7 +16,11 @@ public class UserPunishService : INService
|
||||
private readonly BotConfigService _bcs;
|
||||
private readonly Timer _warnExpiryTimer;
|
||||
|
||||
public UserPunishService(MuteService mute, DbService db, BlacklistService blacklistService, BotConfigService bcs)
|
||||
public UserPunishService(
|
||||
MuteService mute,
|
||||
DbService db,
|
||||
BlacklistService blacklistService,
|
||||
BotConfigService bcs)
|
||||
{
|
||||
_mute = mute;
|
||||
_db = db;
|
||||
@@ -24,16 +28,24 @@ public class UserPunishService : INService
|
||||
_bcs = bcs;
|
||||
|
||||
_warnExpiryTimer = new(async _ =>
|
||||
{
|
||||
await CheckAllWarnExpiresAsync();
|
||||
}, null, TimeSpan.FromSeconds(0), TimeSpan.FromHours(12));
|
||||
{
|
||||
await CheckAllWarnExpiresAsync();
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromSeconds(0),
|
||||
TimeSpan.FromHours(12));
|
||||
}
|
||||
|
||||
public async Task<WarningPunishment> Warn(IGuild guild, ulong userId, IUser mod, int weight, string reason)
|
||||
public async Task<WarningPunishment> Warn(
|
||||
IGuild guild,
|
||||
ulong userId,
|
||||
IUser mod,
|
||||
int weight,
|
||||
string reason)
|
||||
{
|
||||
if (weight <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(weight));
|
||||
|
||||
|
||||
var modName = mod.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(reason))
|
||||
@@ -41,28 +53,25 @@ public class UserPunishService : INService
|
||||
|
||||
var guildId = guild.Id;
|
||||
|
||||
var warn = new Warning()
|
||||
var warn = new Warning
|
||||
{
|
||||
UserId = userId,
|
||||
GuildId = guildId,
|
||||
Forgiven = false,
|
||||
Reason = reason,
|
||||
Moderator = modName,
|
||||
Weight = weight,
|
||||
Weight = weight
|
||||
};
|
||||
|
||||
var warnings = 1;
|
||||
List<WarningPunishment> ps;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments))
|
||||
.WarnPunishments;
|
||||
ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||
|
||||
warnings += uow
|
||||
.Warnings
|
||||
.ForId(guildId, userId)
|
||||
.Where(w => !w.Forgiven && w.UserId == userId)
|
||||
.Sum(x => x.Weight);
|
||||
warnings += uow.Warnings.ForId(guildId, userId)
|
||||
.Where(w => !w.Forgiven && w.UserId == userId)
|
||||
.Sum(x => x.Weight);
|
||||
|
||||
uow.Warnings.Add(warn);
|
||||
|
||||
@@ -84,13 +93,18 @@ public class UserPunishService : INService
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task ApplyPunishment(IGuild guild, IGuildUser user, IUser mod, PunishmentAction p, int minutes,
|
||||
ulong? roleId, string reason)
|
||||
public async Task ApplyPunishment(
|
||||
IGuild guild,
|
||||
IGuildUser user,
|
||||
IUser mod,
|
||||
PunishmentAction p,
|
||||
int minutes,
|
||||
ulong? roleId,
|
||||
string reason)
|
||||
{
|
||||
|
||||
if (!await CheckPermission(guild, p))
|
||||
return;
|
||||
|
||||
|
||||
switch (p)
|
||||
{
|
||||
case PunishmentAction.Mute:
|
||||
@@ -121,7 +135,7 @@ public class UserPunishService : INService
|
||||
await _mute.TimedBan(user.Guild, user, TimeSpan.FromMinutes(minutes), reason);
|
||||
break;
|
||||
case PunishmentAction.Softban:
|
||||
await guild.AddBanAsync(user, 7, reason: $"Softban | {reason}");
|
||||
await guild.AddBanAsync(user, 7, $"Softban | {reason}");
|
||||
try
|
||||
{
|
||||
await guild.RemoveBanAsync(user);
|
||||
@@ -151,22 +165,19 @@ public class UserPunishService : INService
|
||||
Log.Warning($"Can't find role {roleId.Value} on server {guild.Id} to apply punishment.");
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to prevent the bot from hitting 403's when it needs to
|
||||
/// apply punishments with insufficient permissions
|
||||
/// Used to prevent the bot from hitting 403's when it needs to
|
||||
/// apply punishments with insufficient permissions
|
||||
/// </summary>
|
||||
/// <param name="guild">Guild the punishment is applied in</param>
|
||||
/// <param name="punish">Punishment to apply</param>
|
||||
/// <returns>Whether the bot has sufficient permissions</returns>
|
||||
private async Task<bool> CheckPermission(IGuild guild, PunishmentAction punish)
|
||||
{
|
||||
|
||||
var botUser = await guild.GetCurrentUserAsync();
|
||||
switch (punish)
|
||||
{
|
||||
@@ -194,21 +205,19 @@ public class UserPunishService : INService
|
||||
public async Task CheckAllWarnExpiresAsync()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var cleared = await uow.Database.ExecuteSqlRawAsync($@"UPDATE Warnings
|
||||
var cleared = await uow.Database.ExecuteSqlRawAsync(@"UPDATE Warnings
|
||||
SET Forgiven = 1,
|
||||
ForgivenBy = 'Expiry'
|
||||
WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND WarnExpireAction = 0)
|
||||
AND Forgiven = 0
|
||||
AND DateAdded < datetime('now', (SELECT '-' || WarnExpireHours || ' hours' FROM GuildConfigs as gc WHERE gc.GuildId = Warnings.GuildId));");
|
||||
|
||||
var deleted = await uow.Database.ExecuteSqlRawAsync($@"DELETE FROM Warnings
|
||||
var deleted = await uow.Database.ExecuteSqlRawAsync(@"DELETE FROM Warnings
|
||||
WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND WarnExpireAction = 1)
|
||||
AND DateAdded < datetime('now', (SELECT '-' || WarnExpireHours || ' hours' FROM GuildConfigs as gc WHERE gc.GuildId = Warnings.GuildId));");
|
||||
|
||||
if(cleared > 0 || deleted > 0)
|
||||
{
|
||||
if (cleared > 0 || deleted > 0)
|
||||
Log.Information($"Cleared {cleared} warnings and deleted {deleted} warnings due to expiry.");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CheckWarnExpiresAsync(ulong guildId)
|
||||
@@ -221,20 +230,16 @@ WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND
|
||||
|
||||
var hours = $"{-config.WarnExpireHours} hours";
|
||||
if (config.WarnExpireAction == WarnExpireAction.Clear)
|
||||
{
|
||||
await uow.Database.ExecuteSqlInterpolatedAsync($@"UPDATE warnings
|
||||
SET Forgiven = 1,
|
||||
ForgivenBy = 'Expiry'
|
||||
WHERE GuildId={guildId}
|
||||
AND Forgiven = 0
|
||||
AND DateAdded < datetime('now', {hours})");
|
||||
}
|
||||
else if (config.WarnExpireAction == WarnExpireAction.Delete)
|
||||
{
|
||||
await uow.Database.ExecuteSqlInterpolatedAsync($@"DELETE FROM warnings
|
||||
WHERE GuildId={guildId}
|
||||
AND DateAdded < datetime('now', {hours})");
|
||||
}
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
@@ -245,7 +250,7 @@ WHERE GuildId={guildId}
|
||||
var config = uow.GuildConfigsForId(guildId, set => set);
|
||||
return Task.FromResult(config.WarnExpireHours / 24);
|
||||
}
|
||||
|
||||
|
||||
public async Task WarnExpireAsync(ulong guildId, int days, bool delete)
|
||||
{
|
||||
await using (var uow = _db.GetDbContext())
|
||||
@@ -276,23 +281,28 @@ WHERE GuildId={guildId}
|
||||
return uow.Warnings.ForId(gid, userId);
|
||||
}
|
||||
|
||||
public async Task<bool> WarnClearAsync(ulong guildId, ulong userId, int index, string moderator)
|
||||
public async Task<bool> WarnClearAsync(
|
||||
ulong guildId,
|
||||
ulong userId,
|
||||
int index,
|
||||
string moderator)
|
||||
{
|
||||
var toReturn = true;
|
||||
await using var uow = _db.GetDbContext();
|
||||
if (index == 0)
|
||||
{
|
||||
await uow.Warnings.ForgiveAll(guildId, userId, moderator);
|
||||
}
|
||||
else
|
||||
{
|
||||
toReturn = uow.Warnings.Forgive(guildId, userId, moderator, index - 1);
|
||||
}
|
||||
uow.SaveChanges();
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public bool WarnPunish(ulong guildId, int number, PunishmentAction punish, StoopidTime time, IRole role = null)
|
||||
public bool WarnPunish(
|
||||
ulong guildId,
|
||||
int number,
|
||||
PunishmentAction punish,
|
||||
StoopidTime time,
|
||||
IRole role = null)
|
||||
{
|
||||
// these 3 don't make sense with time
|
||||
if (punish is PunishmentAction.Softban or PunishmentAction.Kick or PunishmentAction.RemoveRoles && time != null)
|
||||
@@ -311,7 +321,7 @@ WHERE GuildId={guildId}
|
||||
Count = number,
|
||||
Punishment = punish,
|
||||
Time = (int?)time?.Time.TotalMinutes ?? 0,
|
||||
RoleId = punish == PunishmentAction.AddRole ? role.Id : default(ulong?),
|
||||
RoleId = punish == PunishmentAction.AddRole ? role.Id : default(ulong?)
|
||||
});
|
||||
uow.SaveChanges();
|
||||
return true;
|
||||
@@ -339,42 +349,37 @@ WHERE GuildId={guildId}
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.GuildConfigsForId(guildId, gc => gc.Include(x => x.WarnPunishments))
|
||||
.WarnPunishments
|
||||
.OrderBy(x => x.Count)
|
||||
.ToArray();
|
||||
.WarnPunishments.OrderBy(x => x.Count)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public (IEnumerable<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill(SocketGuild guild, string people)
|
||||
public (IEnumerable<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill(
|
||||
SocketGuild guild,
|
||||
string people)
|
||||
{
|
||||
var gusers = guild.Users;
|
||||
//get user objects and reasons
|
||||
var bans = people.Split("\n")
|
||||
.Select(x =>
|
||||
{
|
||||
var split = x.Trim().Split(" ");
|
||||
.Select(x =>
|
||||
{
|
||||
var split = x.Trim().Split(" ");
|
||||
|
||||
var reason = string.Join(" ", split.Skip(1));
|
||||
var reason = string.Join(" ", split.Skip(1));
|
||||
|
||||
if (ulong.TryParse(split[0], out var id))
|
||||
return (Original: split[0], Id: id, Reason: reason);
|
||||
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();
|
||||
return (Original: split[0],
|
||||
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
|
||||
.Count(x => !x.Id.HasValue);
|
||||
var missing = bans.Count(x => !x.Id.HasValue);
|
||||
|
||||
//get only data for found users
|
||||
var found = bans
|
||||
.Where(x => x.Id.HasValue)
|
||||
.Select(x => x.Id.Value)
|
||||
.ToList();
|
||||
var found = bans.Where(x => x.Id.HasValue).Select(x => x.Id.Value).ToList();
|
||||
|
||||
_blacklistService.BlacklistUsers(found);
|
||||
|
||||
@@ -384,33 +389,25 @@ WHERE GuildId={guildId}
|
||||
public string GetBanTemplate(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var template = uow.BanTemplates
|
||||
.AsQueryable()
|
||||
.FirstOrDefault(x => x.GuildId == guildId);
|
||||
var template = uow.BanTemplates.AsQueryable().FirstOrDefault(x => x.GuildId == guildId);
|
||||
return template?.Text;
|
||||
}
|
||||
|
||||
public void SetBanTemplate(ulong guildId, string text)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var template = uow.BanTemplates
|
||||
.AsQueryable()
|
||||
.FirstOrDefault(x => x.GuildId == guildId);
|
||||
var template = uow.BanTemplates.AsQueryable().FirstOrDefault(x => x.GuildId == guildId);
|
||||
|
||||
if (text is null)
|
||||
{
|
||||
if (template is null)
|
||||
return;
|
||||
|
||||
|
||||
uow.Remove(template);
|
||||
}
|
||||
else if (template is null)
|
||||
{
|
||||
uow.BanTemplates.Add(new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
Text = text,
|
||||
});
|
||||
uow.BanTemplates.Add(new() { GuildId = guildId, Text = text });
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -420,67 +417,66 @@ WHERE GuildId={guildId}
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
public SmartText GetBanUserDmEmbed(ICommandContext context, IGuildUser target, string defaultMessage,
|
||||
string banReason, TimeSpan? duration)
|
||||
=> GetBanUserDmEmbed(
|
||||
(DiscordSocketClient) context.Client,
|
||||
(SocketGuild) context.Guild,
|
||||
(IGuildUser) context.User,
|
||||
public SmartText GetBanUserDmEmbed(
|
||||
ICommandContext context,
|
||||
IGuildUser target,
|
||||
string defaultMessage,
|
||||
string banReason,
|
||||
TimeSpan? duration)
|
||||
=> GetBanUserDmEmbed((DiscordSocketClient)context.Client,
|
||||
(SocketGuild)context.Guild,
|
||||
(IGuildUser)context.User,
|
||||
target,
|
||||
defaultMessage,
|
||||
banReason,
|
||||
duration);
|
||||
|
||||
public SmartText GetBanUserDmEmbed(DiscordSocketClient client, SocketGuild guild,
|
||||
IGuildUser moderator, IGuildUser target, string defaultMessage, string banReason, TimeSpan? duration)
|
||||
public SmartText GetBanUserDmEmbed(
|
||||
DiscordSocketClient client,
|
||||
SocketGuild guild,
|
||||
IGuildUser moderator,
|
||||
IGuildUser target,
|
||||
string defaultMessage,
|
||||
string banReason,
|
||||
TimeSpan? duration)
|
||||
{
|
||||
var template = GetBanTemplate(guild.Id);
|
||||
|
||||
banReason = string.IsNullOrWhiteSpace(banReason)
|
||||
? "-"
|
||||
: banReason;
|
||||
banReason = string.IsNullOrWhiteSpace(banReason) ? "-" : banReason;
|
||||
|
||||
var replacer = new ReplacementBuilder()
|
||||
.WithServer(client, guild)
|
||||
.WithOverride("%ban.mod%", () => moderator.ToString())
|
||||
.WithOverride("%ban.mod.fullname%", () => moderator.ToString())
|
||||
.WithOverride("%ban.mod.name%", () => moderator.Username)
|
||||
.WithOverride("%ban.mod.discrim%", () => moderator.Discriminator)
|
||||
.WithOverride("%ban.user%", () => target.ToString())
|
||||
.WithOverride("%ban.user.fullname%", () => target.ToString())
|
||||
.WithOverride("%ban.user.name%", () => target.Username)
|
||||
.WithOverride("%ban.user.discrim%", () => target.Discriminator)
|
||||
.WithOverride("%reason%", () => banReason)
|
||||
.WithOverride("%ban.reason%", () => banReason)
|
||||
.WithOverride("%ban.duration%", () => duration?.ToString(@"d\.hh\:mm")?? "perma")
|
||||
.Build();
|
||||
var replacer = new ReplacementBuilder().WithServer(client, guild)
|
||||
.WithOverride("%ban.mod%", () => moderator.ToString())
|
||||
.WithOverride("%ban.mod.fullname%", () => moderator.ToString())
|
||||
.WithOverride("%ban.mod.name%", () => moderator.Username)
|
||||
.WithOverride("%ban.mod.discrim%", () => moderator.Discriminator)
|
||||
.WithOverride("%ban.user%", () => target.ToString())
|
||||
.WithOverride("%ban.user.fullname%", () => target.ToString())
|
||||
.WithOverride("%ban.user.name%", () => target.Username)
|
||||
.WithOverride("%ban.user.discrim%", () => target.Discriminator)
|
||||
.WithOverride("%reason%", () => banReason)
|
||||
.WithOverride("%ban.reason%", () => banReason)
|
||||
.WithOverride("%ban.duration%",
|
||||
() => duration?.ToString(@"d\.hh\:mm") ?? "perma")
|
||||
.Build();
|
||||
|
||||
// if template isn't set, use the old message style
|
||||
if (string.IsNullOrWhiteSpace(template))
|
||||
{
|
||||
template = JsonConvert.SerializeObject(new
|
||||
{
|
||||
color = _bcs.Data.Color.Error.PackedValue >> 8,
|
||||
description = defaultMessage
|
||||
color = _bcs.Data.Color.Error.PackedValue >> 8, description = defaultMessage
|
||||
});
|
||||
}
|
||||
// if template is set to "-" do not dm the user
|
||||
else if (template == "-")
|
||||
{
|
||||
return default;
|
||||
}
|
||||
// if template is an embed, send that embed with replacements
|
||||
// otherwise, treat template as a regular string with replacements
|
||||
else if (!SmartText.CreateFrom(template).IsEmbed)
|
||||
{
|
||||
template = JsonConvert.SerializeObject(new
|
||||
{
|
||||
color = _bcs.Data.Color.Error.PackedValue >> 8,
|
||||
description = template
|
||||
color = _bcs.Data.Color.Error.PackedValue >> 8, description = template
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var output = SmartText.CreateFrom(template);
|
||||
return replacer.Replace(output);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,17 +1,16 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public class VcRoleService : INService
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
|
||||
public ConcurrentDictionary<ulong, ConcurrentQueue<(bool, IGuildUser, IRole)>> ToAssign { get; }
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
public VcRoleService(DiscordSocketClient client, Bot bot, DbService db)
|
||||
{
|
||||
@@ -26,12 +25,12 @@ public class VcRoleService : INService
|
||||
{
|
||||
var guildIds = client.Guilds.Select(x => x.Id).ToList();
|
||||
uow.Set<GuildConfig>()
|
||||
.AsQueryable()
|
||||
.Include(x => x.VcRoleInfos)
|
||||
.Where(x => guildIds.Contains(x.GuildId))
|
||||
.AsEnumerable()
|
||||
.Select(InitializeVcRole)
|
||||
.WhenAll();
|
||||
.AsQueryable()
|
||||
.Include(x => x.VcRoleInfos)
|
||||
.Where(x => guildIds.Contains(x.GuildId))
|
||||
.AsEnumerable()
|
||||
.Select(InitializeVcRole)
|
||||
.WhenAll();
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
@@ -39,42 +38,34 @@ public class VcRoleService : INService
|
||||
while (true)
|
||||
{
|
||||
Task Selector(ConcurrentQueue<(bool, IGuildUser, IRole)> queue)
|
||||
=> Task.Run(async () =>
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
while (queue.TryDequeue(out var item))
|
||||
{
|
||||
while (queue.TryDequeue(out var item))
|
||||
var (add, user, role) = item;
|
||||
|
||||
try
|
||||
{
|
||||
var (add, user, role) = item;
|
||||
|
||||
try
|
||||
if (add)
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
if (!user.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await user.AddRoleAsync(role);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (user.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await user.RemoveRoleAsync(role);
|
||||
|
||||
}
|
||||
}
|
||||
if (!user.RoleIds.Contains(role.Id)) await user.AddRoleAsync(role);
|
||||
}
|
||||
catch
|
||||
else
|
||||
{
|
||||
if (user.RoleIds.Contains(role.Id)) await user.RemoveRoleAsync(role);
|
||||
}
|
||||
|
||||
await Task.Delay(250);
|
||||
}
|
||||
}
|
||||
);
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
await ToAssign.Values.Select(Selector)
|
||||
.Append(Task.Delay(1000))
|
||||
.WhenAll();
|
||||
await Task.Delay(250);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await ToAssign.Values.Select(Selector).Append(Task.Delay(1000)).WhenAll();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -88,10 +79,7 @@ public class VcRoleService : INService
|
||||
// need to load new guildconfig with vc role included
|
||||
using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var configWithVcRole = uow.GuildConfigsForId(
|
||||
arg.GuildId,
|
||||
set => set.Include(x => x.VcRoleInfos)
|
||||
);
|
||||
var configWithVcRole = uow.GuildConfigsForId(arg.GuildId, set => set.Include(x => x.VcRoleInfos));
|
||||
var _ = InitializeVcRole(configWithVcRole);
|
||||
}
|
||||
|
||||
@@ -132,8 +120,7 @@ public class VcRoleService : INService
|
||||
await using var uow = _db.GetDbContext();
|
||||
Log.Warning("Removing {MissingRoleCount} missing roles from {ServiceName}",
|
||||
missingRoles.Count,
|
||||
nameof(VcRoleService)
|
||||
);
|
||||
nameof(VcRoleService));
|
||||
uow.RemoveRange(missingRoles);
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
@@ -150,15 +137,8 @@ public class VcRoleService : INService
|
||||
using var uow = _db.GetDbContext();
|
||||
var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.VcRoleInfos));
|
||||
var toDelete = conf.VcRoleInfos.FirstOrDefault(x => x.VoiceChannelId == vcId); // remove old one
|
||||
if(toDelete != null)
|
||||
{
|
||||
uow.Remove(toDelete);
|
||||
}
|
||||
conf.VcRoleInfos.Add(new()
|
||||
{
|
||||
VoiceChannelId = vcId,
|
||||
RoleId = role.Id,
|
||||
}); // add new one
|
||||
if (toDelete != null) uow.Remove(toDelete);
|
||||
conf.VcRoleInfos.Add(new() { VoiceChannelId = vcId, RoleId = role.Id }); // add new one
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
@@ -179,8 +159,7 @@ public class VcRoleService : INService
|
||||
return true;
|
||||
}
|
||||
|
||||
private Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState,
|
||||
SocketVoiceState newState)
|
||||
private Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
|
||||
{
|
||||
if (usr is not SocketGuildUser gusr)
|
||||
return Task.CompletedTask;
|
||||
@@ -200,15 +179,9 @@ public class VcRoleService : INService
|
||||
{
|
||||
//remove old
|
||||
if (oldVc != null && guildVcRoles.TryGetValue(oldVc.Id, out var role))
|
||||
{
|
||||
Assign(false, gusr, role);
|
||||
}
|
||||
//add new
|
||||
if (newVc != null && guildVcRoles.TryGetValue(newVc.Id, out role))
|
||||
{
|
||||
Assign(true, gusr, role);
|
||||
}
|
||||
|
||||
if (newVc != null && guildVcRoles.TryGetValue(newVc.Id, out role)) Assign(true, gusr, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,4 +198,4 @@ public class VcRoleService : INService
|
||||
var queue = ToAssign.GetOrAdd(gusr.Guild.Id, new ConcurrentQueue<(bool, IGuildUser, IRole)>());
|
||||
queue.Enqueue((v, gusr, role));
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,7 +8,8 @@ public partial class Administration
|
||||
[Group]
|
||||
public class TimeZoneCommands : NadekoSubmodule<GuildTimezoneService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Timezones(int page = 1)
|
||||
{
|
||||
@@ -17,55 +18,50 @@ public partial class Administration
|
||||
if (page is < 0 or > 20)
|
||||
return;
|
||||
|
||||
var timezones = TimeZoneInfo.GetSystemTimeZones()
|
||||
.OrderBy(x => x.BaseUtcOffset)
|
||||
.ToArray();
|
||||
var timezones = TimeZoneInfo.GetSystemTimeZones().OrderBy(x => x.BaseUtcOffset).ToArray();
|
||||
var timezonesPerPage = 20;
|
||||
|
||||
var curTime = DateTimeOffset.UtcNow;
|
||||
|
||||
var i = 0;
|
||||
var timezoneStrings = timezones
|
||||
.Select(x => (x, ++i % 2 == 0))
|
||||
.Select(data =>
|
||||
{
|
||||
var (tzInfo, flip) = data;
|
||||
var nameStr = $"{tzInfo.Id,-30}";
|
||||
var offset = curTime.ToOffset(tzInfo.GetUtcOffset(curTime)).ToString("zzz");
|
||||
if (flip)
|
||||
{
|
||||
return $"{offset} {Format.Code(nameStr)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{Format.Code(offset)} {nameStr}";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var timezoneStrings = timezones.Select(x => (x, ++i % 2 == 0))
|
||||
.Select(data =>
|
||||
{
|
||||
var (tzInfo, flip) = data;
|
||||
var nameStr = $"{tzInfo.Id,-30}";
|
||||
var offset = curTime.ToOffset(tzInfo.GetUtcOffset(curTime))
|
||||
.ToString("zzz");
|
||||
if (flip)
|
||||
return $"{offset} {Format.Code(nameStr)}";
|
||||
return $"{Format.Code(offset)} {nameStr}";
|
||||
});
|
||||
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
curPage => _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.timezones_available))
|
||||
.WithDescription(string.Join("\n", timezoneStrings
|
||||
.Skip(curPage * timezonesPerPage)
|
||||
.Take(timezonesPerPage))),
|
||||
timezones.Length, timezonesPerPage);
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.timezones_available))
|
||||
.WithDescription(string.Join("\n",
|
||||
timezoneStrings.Skip(curPage * timezonesPerPage).Take(timezonesPerPage))),
|
||||
timezones.Length,
|
||||
timezonesPerPage);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Timezone()
|
||||
=> await ReplyConfirmLocalizedAsync(strs.timezone_guild(_service.GetTimeZoneOrUtc(ctx.Guild.Id)));
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task Timezone([Leftover] string id)
|
||||
{
|
||||
TimeZoneInfo tz;
|
||||
try { tz = TimeZoneInfo.FindSystemTimeZoneById(id); } catch { tz = null; }
|
||||
try { tz = TimeZoneInfo.FindSystemTimeZoneById(id); }
|
||||
catch { tz = null; }
|
||||
|
||||
|
||||
if (tz is null)
|
||||
@@ -73,9 +69,10 @@ public partial class Administration
|
||||
await ReplyErrorLocalizedAsync(strs.timezone_not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
_service.SetTimeZone(ctx.Guild.Id, tz);
|
||||
|
||||
await SendConfirmAsync(tz.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,9 +2,9 @@
|
||||
using CommandLine;
|
||||
using Humanizer.Localisation;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -13,6 +13,11 @@ public partial class Administration
|
||||
[Group]
|
||||
public class UserPunishCommands : NadekoSubmodule<UserPunishService>
|
||||
{
|
||||
public enum AddRole
|
||||
{
|
||||
AddRole
|
||||
}
|
||||
|
||||
private readonly MuteService _mute;
|
||||
private readonly BlacklistService _blacklistService;
|
||||
|
||||
@@ -24,47 +29,52 @@ public partial class Administration
|
||||
|
||||
private async Task<bool> CheckRoleHierarchy(IGuildUser target)
|
||||
{
|
||||
var curUser = ((SocketGuild) ctx.Guild).CurrentUser;
|
||||
var curUser = ((SocketGuild)ctx.Guild).CurrentUser;
|
||||
var ownerId = ctx.Guild.OwnerId;
|
||||
var modMaxRole = ((IGuildUser) ctx.User).GetRoles().Max(r => r.Position);
|
||||
var modMaxRole = ((IGuildUser)ctx.User).GetRoles().Max(r => r.Position);
|
||||
var targetMaxRole = target.GetRoles().Max(r => r.Position);
|
||||
var botMaxRole = curUser.GetRoles().Max(r => r.Position);
|
||||
// bot can't punish a user who is higher in the hierarchy. Discord will return 403
|
||||
// moderator can be owner, in which case role hierarchy doesn't matter
|
||||
// otherwise, moderator has to have a higher role
|
||||
if (botMaxRole <= targetMaxRole || (ctx.User.Id != ownerId && targetMaxRole >= modMaxRole) || target.Id == ownerId)
|
||||
if (botMaxRole <= targetMaxRole
|
||||
|| (ctx.User.Id != ownerId && targetMaxRole >= modMaxRole)
|
||||
|| target.Id == ownerId)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.hierarchy);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public Task Warn(IGuildUser user, [Leftover] string reason = null)
|
||||
=> Warn(1, user, reason);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public async Task Warn(int weight, IGuildUser user, [Leftover] string reason = null)
|
||||
{
|
||||
if (weight <= 0)
|
||||
return;
|
||||
|
||||
|
||||
if (!await CheckRoleHierarchy(user))
|
||||
return;
|
||||
|
||||
var dmFailed = false;
|
||||
try
|
||||
{
|
||||
await user.EmbedAsync(_eb.Create().WithErrorColor()
|
||||
.WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
|
||||
.AddField(GetText(strs.moderator), ctx.User.ToString())
|
||||
.AddField(GetText(strs.reason), reason ?? "-"));
|
||||
await user.EmbedAsync(_eb.Create()
|
||||
.WithErrorColor()
|
||||
.WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
|
||||
.AddField(GetText(strs.moderator), ctx.User.ToString())
|
||||
.AddField(GetText(strs.reason), reason ?? "-"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -79,50 +89,28 @@ public partial class Administration
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex.Message);
|
||||
var errorEmbed = _eb.Create()
|
||||
.WithErrorColor()
|
||||
.WithDescription(GetText(strs.cant_apply_punishment));
|
||||
|
||||
if (dmFailed)
|
||||
{
|
||||
errorEmbed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
}
|
||||
|
||||
var errorEmbed = _eb.Create().WithErrorColor().WithDescription(GetText(strs.cant_apply_punishment));
|
||||
|
||||
if (dmFailed) errorEmbed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
|
||||
await ctx.Channel.EmbedAsync(errorEmbed);
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor();
|
||||
var embed = _eb.Create().WithOkColor();
|
||||
if (punishment is null)
|
||||
{
|
||||
embed.WithDescription(GetText(strs.user_warned(Format.Bold(user.ToString()))));
|
||||
}
|
||||
else
|
||||
{
|
||||
embed.WithDescription(GetText(strs.user_warned_and_punished(Format.Bold(user.ToString()),
|
||||
Format.Bold(punishment.Punishment.ToString()))));
|
||||
}
|
||||
|
||||
if (dmFailed)
|
||||
{
|
||||
embed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
}
|
||||
if (dmFailed) embed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
}
|
||||
|
||||
public class WarnExpireOptions : INadekoCommandOptions
|
||||
{
|
||||
[Option('d', "delete", Default = false, HelpText = "Delete warnings instead of clearing them.")]
|
||||
public bool Delete { get; set; } = false;
|
||||
public void NormalizeOptions()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[NadekoOptions(typeof(WarnExpireOptions))]
|
||||
@@ -137,7 +125,8 @@ public partial class Administration
|
||||
await ReplyErrorLocalizedAsync(strs.warns_expire_in(expireDays));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[NadekoOptions(typeof(WarnExpireOptions))]
|
||||
@@ -152,51 +141,53 @@ public partial class Administration
|
||||
await ctx.Channel.TriggerTypingAsync();
|
||||
|
||||
await _service.WarnExpireAsync(ctx.Guild.Id, days, opts.Delete);
|
||||
if(days == 0)
|
||||
if (days == 0)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_expire_reset);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.Delete)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_expire_set_delete(Format.Bold(days.ToString())));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_expire_set_clear(Format.Bold(days.ToString())));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[Priority(2)]
|
||||
public Task Warnlog(int page, [Leftover] IGuildUser user = null)
|
||||
{
|
||||
user ??= (IGuildUser) ctx.User;
|
||||
user ??= (IGuildUser)ctx.User;
|
||||
|
||||
return Warnlog(page, user.Id);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[Priority(3)]
|
||||
public Task Warnlog(IGuildUser user = null)
|
||||
{
|
||||
user ??= (IGuildUser) ctx.User;
|
||||
user ??= (IGuildUser)ctx.User;
|
||||
|
||||
return ctx.User.Id == user.Id || ((IGuildUser)ctx.User).GuildPermissions.BanMembers ? Warnlog(user.Id) : Task.CompletedTask;
|
||||
return ctx.User.Id == user.Id || ((IGuildUser)ctx.User).GuildPermissions.BanMembers
|
||||
? Warnlog(user.Id)
|
||||
: Task.CompletedTask;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[Priority(0)]
|
||||
public Task Warnlog(int page, ulong userId)
|
||||
=> InternalWarnlog(userId, page - 1);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[Priority(1)]
|
||||
@@ -207,58 +198,54 @@ public partial class Administration
|
||||
{
|
||||
if (inputPage < 0)
|
||||
return;
|
||||
|
||||
|
||||
var allWarnings = _service.UserWarnings(ctx.Guild.Id, userId);
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(inputPage, page =>
|
||||
{
|
||||
var warnings = allWarnings
|
||||
.Skip(page * 9)
|
||||
.Take(9)
|
||||
.ToArray();
|
||||
|
||||
var user = (ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString();
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.warnlog_for(user)));
|
||||
|
||||
if (!warnings.Any())
|
||||
await ctx.SendPaginatedConfirmAsync(inputPage,
|
||||
page =>
|
||||
{
|
||||
embed.WithDescription(GetText(strs.warnings_none));
|
||||
}
|
||||
else
|
||||
{
|
||||
var descText = GetText(strs.warn_count(
|
||||
Format.Bold(warnings.Where(x => !x.Forgiven).Sum(x => x.Weight).ToString()),
|
||||
Format.Bold(warnings.Sum(x => x.Weight).ToString())));
|
||||
|
||||
embed.WithDescription(descText);
|
||||
|
||||
var i = page * 9;
|
||||
foreach (var w in warnings)
|
||||
var warnings = allWarnings.Skip(page * 9).Take(9).ToArray();
|
||||
|
||||
var user = (ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString();
|
||||
var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.warnlog_for(user)));
|
||||
|
||||
if (!warnings.Any())
|
||||
{
|
||||
i++;
|
||||
var name = GetText(strs.warned_on_by(
|
||||
w.DateAdded?.ToString("dd.MM.yyy"),
|
||||
w.DateAdded?.ToString("HH:mm"),
|
||||
w.Moderator));
|
||||
|
||||
if (w.Forgiven)
|
||||
name = $"{Format.Strikethrough(name)} {GetText(strs.warn_cleared_by(w.ForgivenBy))}";
|
||||
|
||||
|
||||
embed.AddField($"#`{i}` " + name,
|
||||
Format.Code(GetText(strs.warn_weight(w.Weight))) +
|
||||
'\n' +
|
||||
w.Reason.TrimTo(1000));
|
||||
embed.WithDescription(GetText(strs.warnings_none));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var descText = GetText(strs.warn_count(
|
||||
Format.Bold(warnings.Where(x => !x.Forgiven).Sum(x => x.Weight).ToString()),
|
||||
Format.Bold(warnings.Sum(x => x.Weight).ToString())));
|
||||
|
||||
return embed;
|
||||
}, allWarnings.Length, 9);
|
||||
embed.WithDescription(descText);
|
||||
|
||||
var i = page * 9;
|
||||
foreach (var w in warnings)
|
||||
{
|
||||
i++;
|
||||
var name = GetText(strs.warned_on_by(w.DateAdded?.ToString("dd.MM.yyy"),
|
||||
w.DateAdded?.ToString("HH:mm"),
|
||||
w.Moderator));
|
||||
|
||||
if (w.Forgiven)
|
||||
name = $"{Format.Strikethrough(name)} {GetText(strs.warn_cleared_by(w.ForgivenBy))}";
|
||||
|
||||
|
||||
embed.AddField($"#`{i}` " + name,
|
||||
Format.Code(GetText(strs.warn_weight(w.Weight))) + '\n' + w.Reason.TrimTo(1000));
|
||||
}
|
||||
}
|
||||
|
||||
return embed;
|
||||
},
|
||||
allWarnings.Length,
|
||||
9);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public async Task WarnlogAll(int page = 1)
|
||||
@@ -267,33 +254,40 @@ public partial class Administration
|
||||
return;
|
||||
var warnings = _service.WarnlogAll(ctx.Guild.Id);
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page, curPage =>
|
||||
{
|
||||
var ws = warnings.Skip(curPage * 15)
|
||||
.Take(15)
|
||||
.ToArray()
|
||||
.Select(x =>
|
||||
{
|
||||
var all = x.Count();
|
||||
var forgiven = x.Count(y => y.Forgiven);
|
||||
var total = all - forgiven;
|
||||
var usr = ((SocketGuild)ctx.Guild).GetUser(x.Key);
|
||||
return (usr?.ToString() ?? x.Key.ToString()) + $" | {total} ({all} - {forgiven})";
|
||||
});
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
curPage =>
|
||||
{
|
||||
var ws = warnings.Skip(curPage * 15)
|
||||
.Take(15)
|
||||
.ToArray()
|
||||
.Select(x =>
|
||||
{
|
||||
var all = x.Count();
|
||||
var forgiven = x.Count(y => y.Forgiven);
|
||||
var total = all - forgiven;
|
||||
var usr = ((SocketGuild)ctx.Guild).GetUser(x.Key);
|
||||
return (usr?.ToString() ?? x.Key.ToString())
|
||||
+ $" | {total} ({all} - {forgiven})";
|
||||
});
|
||||
|
||||
return _eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.warnings_list))
|
||||
.WithDescription(string.Join("\n", ws));
|
||||
}, warnings.Length, 15);
|
||||
return _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.warnings_list))
|
||||
.WithDescription(string.Join("\n", ws));
|
||||
},
|
||||
warnings.Length,
|
||||
15);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public Task Warnclear(IGuildUser user, int index = 0)
|
||||
=> Warnclear(user.Id, index);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public async Task Warnclear(ulong userId, int index = 0)
|
||||
@@ -309,57 +303,48 @@ public partial class Administration
|
||||
else
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warning_cleared(Format.Bold(index.ToString()), userStr));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.warning_clear_fail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum AddRole
|
||||
{
|
||||
AddRole
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[Priority(1)]
|
||||
public async Task WarnPunish(int number, AddRole _, IRole role, StoopidTime time = null)
|
||||
public async Task WarnPunish(
|
||||
int number,
|
||||
AddRole _,
|
||||
IRole role,
|
||||
StoopidTime time = null)
|
||||
{
|
||||
var punish = PunishmentAction.AddRole;
|
||||
|
||||
if (ctx.Guild.OwnerId != ctx.User.Id &&
|
||||
role.Position >= ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position))
|
||||
if (ctx.Guild.OwnerId != ctx.User.Id
|
||||
&& role.Position >= ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.role_too_high);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var success = _service.WarnPunish(ctx.Guild.Id, number, punish, time, role);
|
||||
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
if (time is null)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set(
|
||||
Format.Bold(punish.ToString()),
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
||||
Format.Bold(number.ToString())));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(
|
||||
Format.Bold(punish.ToString()),
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
||||
Format.Bold(number.ToString()),
|
||||
Format.Bold(time.Input)));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public async Task WarnPunish(int number, PunishmentAction punish, StoopidTime time = null)
|
||||
@@ -374,35 +359,27 @@ public partial class Administration
|
||||
return;
|
||||
|
||||
if (time is null)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set(
|
||||
Format.Bold(punish.ToString()),
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set(Format.Bold(punish.ToString()),
|
||||
Format.Bold(number.ToString())));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(
|
||||
Format.Bold(punish.ToString()),
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
|
||||
Format.Bold(number.ToString()),
|
||||
Format.Bold(time.Input)));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
public async Task WarnPunish(int number)
|
||||
{
|
||||
if (!_service.WarnPunishRemove(ctx.Guild.Id, number))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!_service.WarnPunishRemove(ctx.Guild.Id, number)) return;
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_rem(
|
||||
Format.Bold(number.ToString())));
|
||||
await ReplyConfirmLocalizedAsync(strs.warn_punish_rem(Format.Bold(number.ToString())));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task WarnPunishList()
|
||||
{
|
||||
@@ -410,20 +387,16 @@ public partial class Administration
|
||||
|
||||
string list;
|
||||
if (ps.Any())
|
||||
{
|
||||
|
||||
list = string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment} {(x.Punishment == PunishmentAction.AddRole ? $"<@&{x.RoleId}>" : "")} {(x.Time <= 0 ? "" : x.Time.ToString() + "m")} "));
|
||||
}
|
||||
list = string.Join("\n",
|
||||
ps.Select(x
|
||||
=> $"{x.Count} -> {x.Punishment} {(x.Punishment == PunishmentAction.AddRole ? $"<@&{x.RoleId}>" : "")} {(x.Time <= 0 ? "" : x.Time + "m")} "));
|
||||
else
|
||||
{
|
||||
list = GetText(strs.warnpl_none);
|
||||
}
|
||||
await SendConfirmAsync(
|
||||
GetText(strs.warn_punish_list),
|
||||
list);
|
||||
await SendConfirmAsync(GetText(strs.warn_punish_list), list);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -441,42 +414,34 @@ public partial class Administration
|
||||
var dmFailed = false;
|
||||
|
||||
if (guildUser != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
|
||||
var embed = _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time);
|
||||
if (embed is not null)
|
||||
{
|
||||
await guildUser.SendAsync(embed);
|
||||
}
|
||||
if (embed is not null) await guildUser.SendAsync(embed);
|
||||
}
|
||||
catch
|
||||
{
|
||||
dmFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
await _mute.TimedBan(ctx.Guild, user, time.Time, (ctx.User.ToString() + " | " + msg).TrimTo(512));
|
||||
var toSend = _eb.Create().WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true)
|
||||
.AddField(GetText(strs.duration),
|
||||
time.Time.Humanize(3,
|
||||
minUnit: TimeUnit.Minute,
|
||||
culture: Culture),
|
||||
true);
|
||||
await _mute.TimedBan(ctx.Guild, user, time.Time, (ctx.User + " | " + msg).TrimTo(512));
|
||||
var toSend = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true)
|
||||
.AddField(GetText(strs.duration),
|
||||
time.Time.Humanize(3, minUnit: TimeUnit.Minute, culture: Culture),
|
||||
true);
|
||||
|
||||
if (dmFailed)
|
||||
{
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
}
|
||||
if (dmFailed) toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
|
||||
await ctx.Channel.EmbedAsync(toSend);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -486,11 +451,12 @@ public partial class Administration
|
||||
var user = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId);
|
||||
if (user is null)
|
||||
{
|
||||
await ctx.Guild.AddBanAsync(userId, 7, (ctx.User.ToString() + " | " + msg).TrimTo(512));
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField("ID", userId.ToString(), true));
|
||||
await ctx.Guild.AddBanAsync(userId, 7, (ctx.User + " | " + msg).TrimTo(512));
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField("ID", userId.ToString(), true));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -498,7 +464,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -514,32 +481,28 @@ public partial class Administration
|
||||
{
|
||||
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
|
||||
var embed = _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null);
|
||||
if (embed is not null)
|
||||
{
|
||||
await ctx.User.SendAsync(embed);
|
||||
}
|
||||
if (embed is not null) await ctx.User.SendAsync(embed);
|
||||
}
|
||||
catch
|
||||
{
|
||||
dmFailed = true;
|
||||
}
|
||||
|
||||
await ctx.Guild.AddBanAsync(user, 7, (ctx.User.ToString() + " | " + msg).TrimTo(512));
|
||||
await ctx.Guild.AddBanAsync(user, 7, (ctx.User + " | " + msg).TrimTo(512));
|
||||
|
||||
var toSend = _eb.Create().WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
var toSend = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText(strs.banned_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed) toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
|
||||
if (dmFailed)
|
||||
{
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(toSend);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -557,12 +520,13 @@ public partial class Administration
|
||||
await SendConfirmAsync(template);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_service.SetBanTemplate(ctx.Guild.Id, message);
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -572,30 +536,28 @@ public partial class Administration
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
[Priority(0)]
|
||||
public Task BanMessageTest([Leftover] string reason = null)
|
||||
=> InternalBanMessageTest(reason, null);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
[Priority(1)]
|
||||
public Task BanMessageTest(StoopidTime duration, [Leftover] string reason = null)
|
||||
=> InternalBanMessageTest(reason, duration.Time);
|
||||
|
||||
|
||||
private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
|
||||
{
|
||||
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), reason));
|
||||
var embed = _service.GetBanUserDmEmbed(Context,
|
||||
(IGuildUser)ctx.User,
|
||||
defaultMessage,
|
||||
reason,
|
||||
duration);
|
||||
var embed = _service.GetBanUserDmEmbed(Context, (IGuildUser)ctx.User, defaultMessage, reason, duration);
|
||||
|
||||
if (embed is null)
|
||||
{
|
||||
@@ -617,7 +579,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -636,7 +599,8 @@ public partial class Administration
|
||||
await UnbanInternal(bun.User);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -662,14 +626,16 @@ public partial class Administration
|
||||
await ReplyConfirmLocalizedAsync(strs.unbanned_user(Format.Bold(user.ToString())));
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.KickMembers | GuildPerm.ManageMessages)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
public Task Softban(IGuildUser user, [Leftover] string msg = null)
|
||||
=> SoftbanInternal(user, msg);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.KickMembers | GuildPerm.ManageMessages)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -681,7 +647,7 @@ public partial class Administration
|
||||
|
||||
await SoftbanInternal(user, msg);
|
||||
}
|
||||
|
||||
|
||||
private async Task SoftbanInternal(IGuildUser user, [Leftover] string msg = null)
|
||||
{
|
||||
if (!await CheckRoleHierarchy(user))
|
||||
@@ -698,24 +664,23 @@ public partial class Administration
|
||||
dmFailed = true;
|
||||
}
|
||||
|
||||
await ctx.Guild.AddBanAsync(user, 7, ("Softban | " + ctx.User.ToString() + " | " + msg).TrimTo(512));
|
||||
await ctx.Guild.AddBanAsync(user, 7, ("Softban | " + ctx.User + " | " + msg).TrimTo(512));
|
||||
try { await ctx.Guild.RemoveBanAsync(user); }
|
||||
catch { await ctx.Guild.RemoveBanAsync(user); }
|
||||
|
||||
var toSend = _eb.Create().WithOkColor()
|
||||
.WithTitle("☣ " + GetText(strs.sb_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed)
|
||||
{
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
}
|
||||
|
||||
var toSend = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle("☣ " + GetText(strs.sb_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed) toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
|
||||
await ctx.Channel.EmbedAsync(toSend);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.KickMembers)]
|
||||
[BotPerm(GuildPerm.KickMembers)]
|
||||
@@ -723,7 +688,8 @@ public partial class Administration
|
||||
public Task Kick(IGuildUser user, [Leftover] string msg = null)
|
||||
=> KickInternal(user, msg);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.KickMembers)]
|
||||
[BotPerm(GuildPerm.KickMembers)]
|
||||
@@ -733,7 +699,7 @@ public partial class Administration
|
||||
var user = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId);
|
||||
if (user is null)
|
||||
return;
|
||||
|
||||
|
||||
await KickInternal(user, msg);
|
||||
}
|
||||
|
||||
@@ -749,26 +715,25 @@ public partial class Administration
|
||||
await user.SendErrorAsync(_eb, GetText(strs.kickdm(Format.Bold(ctx.Guild.Name), msg)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
{
|
||||
dmFailed = true;
|
||||
}
|
||||
|
||||
await user.KickAsync((ctx.User.ToString() + " | " + msg).TrimTo(512));
|
||||
|
||||
var toSend = _eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.kicked_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed)
|
||||
{
|
||||
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
}
|
||||
|
||||
await user.KickAsync((ctx.User + " | " + msg).TrimTo(512));
|
||||
|
||||
var toSend = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.kicked_user))
|
||||
.AddField(GetText(strs.username), user.ToString(), true)
|
||||
.AddField("ID", user.Id.ToString(), true);
|
||||
|
||||
if (dmFailed) toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
|
||||
|
||||
await ctx.Channel.EmbedAsync(toSend);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -783,11 +748,11 @@ public partial class Administration
|
||||
|
||||
await ctx.Channel.TriggerTypingAsync();
|
||||
foreach (var userStr in userStrings)
|
||||
{
|
||||
if (ulong.TryParse(userStr, out var userId))
|
||||
{
|
||||
IUser user = await ctx.Guild.GetUserAsync(userId) ??
|
||||
await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId);
|
||||
IUser user = await ctx.Guild.GetUserAsync(userId)
|
||||
?? await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id,
|
||||
userId);
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -800,14 +765,10 @@ public partial class Administration
|
||||
missing.Add(userStr);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Hierachy checks only if the user is in the guild
|
||||
if (user is IGuildUser gu && !await CheckRoleHierarchy(gu))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (user is IGuildUser gu && !await CheckRoleHierarchy(gu)) return;
|
||||
|
||||
banning.Add(user);
|
||||
}
|
||||
@@ -815,41 +776,38 @@ public partial class Administration
|
||||
{
|
||||
missing.Add(userStr);
|
||||
}
|
||||
}
|
||||
|
||||
var missStr = string.Join("\n", missing);
|
||||
if (string.IsNullOrWhiteSpace(missStr))
|
||||
missStr = "-";
|
||||
|
||||
|
||||
var toSend = _eb.Create(ctx)
|
||||
.WithDescription(GetText(strs.mass_ban_in_progress(banning.Count)))
|
||||
.AddField(GetText(strs.invalid(missing.Count)), missStr)
|
||||
.WithPendingColor();
|
||||
.WithDescription(GetText(strs.mass_ban_in_progress(banning.Count)))
|
||||
.AddField(GetText(strs.invalid(missing.Count)), missStr)
|
||||
.WithPendingColor();
|
||||
|
||||
var banningMessage = await ctx.Channel.EmbedAsync(toSend);
|
||||
|
||||
foreach (var toBan in banning)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ctx.Guild.AddBanAsync(toBan.Id, 7, $"{ctx.User} | Massban");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Error banning {User} user in {GuildId} server",
|
||||
toBan.Id,
|
||||
ctx.Guild.Id);
|
||||
Log.Warning(ex, "Error banning {User} user in {GuildId} server", toBan.Id, ctx.Guild.Id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await banningMessage.ModifyAsync(x => x.Embed = _eb.Create()
|
||||
.WithDescription(GetText(strs.mass_ban_completed(banning.Count())))
|
||||
.AddField(GetText(strs.invalid(missing.Count)), missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
.WithDescription(
|
||||
GetText(strs.mass_ban_completed(banning.Count())))
|
||||
.AddField(GetText(strs.invalid(missing.Count)), missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.BanMembers)]
|
||||
[BotPerm(GuildPerm.BanMembers)]
|
||||
@@ -867,26 +825,37 @@ public partial class Administration
|
||||
|
||||
//send a message but don't wait for it
|
||||
var banningMessageTask = ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithDescription(GetText(strs.mass_kill_in_progress(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithPendingColor());
|
||||
.WithDescription(
|
||||
GetText(strs.mass_kill_in_progress(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithPendingColor());
|
||||
|
||||
//do the banning
|
||||
await Task.WhenAll(bans
|
||||
.Where(x => x.Id.HasValue)
|
||||
.Select(x => ctx.Guild.AddBanAsync(x.Id.Value, 7, x.Reason, new()
|
||||
{
|
||||
RetryMode = RetryMode.AlwaysRetry,
|
||||
})));
|
||||
await Task.WhenAll(bans.Where(x => x.Id.HasValue)
|
||||
.Select(x => ctx.Guild.AddBanAsync(x.Id.Value,
|
||||
7,
|
||||
x.Reason,
|
||||
new() { RetryMode = RetryMode.AlwaysRetry })));
|
||||
|
||||
//wait for the message and edit it
|
||||
var banningMessage = await banningMessageTask;
|
||||
|
||||
await banningMessage.ModifyAsync(x => x.Embed = _eb.Create()
|
||||
.WithDescription(GetText(strs.mass_kill_completed(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
.WithDescription(
|
||||
GetText(strs.mass_kill_completed(bans.Count())))
|
||||
.AddField(GetText(strs.invalid(missing)), missStr)
|
||||
.WithOkColor()
|
||||
.Build());
|
||||
}
|
||||
|
||||
public class WarnExpireOptions : INadekoCommandOptions
|
||||
{
|
||||
[Option('d', "delete", Default = false, HelpText = "Delete warnings instead of clearing them.")]
|
||||
public bool Delete { get; set; } = false;
|
||||
|
||||
public void NormalizeOptions()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,23 +8,21 @@ public partial class Administration
|
||||
[Group]
|
||||
public class VcRoleCommands : NadekoSubmodule<VcRoleService>
|
||||
{
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task VcRoleRm(ulong vcId)
|
||||
{
|
||||
if (_service.RemoveVcRole(ctx.Guild.Id, vcId))
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.vcrole_removed(Format.Bold(vcId.ToString())));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.vcrole_not_found);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
@@ -43,9 +41,7 @@ public partial class Administration
|
||||
if (role is null)
|
||||
{
|
||||
if (_service.RemoveVcRole(ctx.Guild.Id, vc.Id))
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.vcrole_removed(Format.Bold(vc.Name)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -54,7 +50,8 @@ public partial class Administration
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand]
|
||||
[Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task VcRoleList()
|
||||
{
|
||||
@@ -63,22 +60,21 @@ public partial class Administration
|
||||
if (_service.VcRoles.TryGetValue(ctx.Guild.Id, out var roles))
|
||||
{
|
||||
if (!roles.Any())
|
||||
{
|
||||
text = GetText(strs.no_vcroles);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = string.Join("\n", roles.Select(x =>
|
||||
$"{Format.Bold(guild.GetVoiceChannel(x.Key)?.Name ?? x.Key.ToString())} => {x.Value}"));
|
||||
}
|
||||
text = string.Join("\n",
|
||||
roles.Select(x
|
||||
=> $"{Format.Bold(guild.GetVoiceChannel(x.Key)?.Name ?? x.Key.ToString())} => {x.Value}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
text = GetText(strs.no_vcroles);
|
||||
}
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.vc_role_list))
|
||||
.WithDescription(text));
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.vc_role_list))
|
||||
.WithDescription(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user