mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-12 02:08:27 -04:00
Restructured the project structure back to the way it was, there's no reasonable way to split the modules
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public partial class AutoAssignRoleCommands : NadekoModule<AutoAssignRoleService>
|
||||
{
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task AutoAssignRole([Leftover] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (role.Id == ctx.Guild.EveryoneRole.Id)
|
||||
return;
|
||||
|
||||
// the user can't aar the role which is higher or equal to his highest role
|
||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.hierarchy);
|
||||
return;
|
||||
}
|
||||
|
||||
var roles = await _service.ToggleAarAsync(ctx.Guild.Id, role.Id);
|
||||
if (roles.Count == 0)
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_disabled);
|
||||
else if (roles.Contains(role.Id))
|
||||
await AutoAssignRole();
|
||||
else
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_role_removed(Format.Bold(role.ToString())));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task AutoAssignRole()
|
||||
{
|
||||
if (!_service.TryGetRoles(ctx.Guild.Id, out var roles))
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_none);
|
||||
return;
|
||||
}
|
||||
|
||||
var existing = roles.Select(rid => ctx.Guild.GetRole(rid)).Where(r => r is not null).ToList();
|
||||
|
||||
if (existing.Count != roles.Count)
|
||||
await _service.SetAarRolesAsync(ctx.Guild.Id, existing.Select(x => x.Id));
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.aar_roles(
|
||||
'\n' + existing.Select(x => Format.Bold(x.ToString())).Join(",\n")));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,159 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using System.Net;
|
||||
using System.Threading.Channels;
|
||||
using LinqToDB;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public sealed class AutoAssignRoleService : INService
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly DbService _db;
|
||||
|
||||
//guildid/roleid
|
||||
private readonly ConcurrentDictionary<ulong, IReadOnlyList<ulong>> _autoAssignableRoles;
|
||||
|
||||
private readonly Channel<SocketGuildUser> _assignQueue = Channel.CreateBounded<SocketGuildUser>(
|
||||
new BoundedChannelOptions(100)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.DropOldest,
|
||||
SingleReader = true,
|
||||
SingleWriter = false
|
||||
});
|
||||
|
||||
public AutoAssignRoleService(DiscordSocketClient client, IBot bot, DbService db)
|
||||
{
|
||||
_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();
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
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();
|
||||
|
||||
if (roleIds.Any())
|
||||
{
|
||||
await user.AddRolesAsync(roleIds);
|
||||
await Task.Delay(250);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning(
|
||||
"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 (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",
|
||||
user.Guild.Name,
|
||||
user.Guild.Id);
|
||||
|
||||
await DisableAarAsync(user.Guild.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Error in aar. Probably one of the roles doesn't exist");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_client.UserJoined += OnClientOnUserJoined;
|
||||
_client.RoleDeleted += OnClientRoleDeleted;
|
||||
}
|
||||
|
||||
private async Task OnClientRoleDeleted(SocketRole role)
|
||||
{
|
||||
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 _))
|
||||
await _assignQueue.Writer.WriteAsync(user);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<ulong>> ToggleAarAsync(ulong guildId, ulong roleId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var gc = uow.GuildConfigsForId(guildId, set => set);
|
||||
var roles = gc.GetAutoAssignableRoles();
|
||||
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.Set<GuildConfig>().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();
|
||||
}
|
||||
|
||||
public bool TryGetRoles(ulong guildId, out IReadOnlyList<ulong> roles)
|
||||
=> _autoAssignableRoles.TryGetValue(guildId, out roles);
|
||||
}
|
||||
|
||||
public static class GuildConfigExtensions
|
||||
{
|
||||
public static List<ulong> GetAutoAssignableRoles(this GuildConfig gc)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(gc.AutoAssignRoleIds))
|
||||
return new();
|
||||
|
||||
return gc.AutoAssignRoleIds.Split(',').Select(ulong.Parse).ToList();
|
||||
}
|
||||
|
||||
public static void SetAutoAssignableRoles(this GuildConfig gc, IEnumerable<ulong> roles)
|
||||
=> gc.AutoAssignRoleIds = roles.Join(',');
|
||||
}
|
Reference in New Issue
Block a user