mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-12 10:18:27 -04:00
Applied codestyle to all .cs files
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user