mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
- Removed NadekoCommand and Aliases attribute from all commands
- All commands must be marked as partial - Added [Cmd] Attribute to all commands - Cmd Attribute comes from the source generator which adds [NadekoCommand] and [Aliases] Attribute to each command - Should be updated in the future probably to be more performant and maybe add extra data to the commands - Started reorganizing modules and submodules
This commit is contained in:
332
src/NadekoBot/Modules/Administration/Role/RoleCommands.cs
Normal file
332
src/NadekoBot/Modules/Administration/Role/RoleCommands.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System.Net;
|
||||
using Color = SixLabors.ImageSharp.Color;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration
|
||||
{
|
||||
public partial class RoleCommands : NadekoSubmodule<RoleCommandsService>
|
||||
{
|
||||
public enum Exclude { Excl }
|
||||
|
||||
private IServiceProvider _services;
|
||||
|
||||
public RoleCommands(IServiceProvider services)
|
||||
=> _services = services;
|
||||
|
||||
public async Task InternalReactionRoles(bool exclusive, ulong? messageId, params string[] input)
|
||||
{
|
||||
var target = messageId is { } msgId
|
||||
? await ctx.Channel.GetMessageAsync(msgId)
|
||||
: (await ctx.Channel.GetMessagesAsync(2).FlattenAsync()).Skip(1).FirstOrDefault();
|
||||
|
||||
if (input.Length % 2 != 0)
|
||||
return;
|
||||
|
||||
var all = await input.Chunk(input.Length / 2)
|
||||
.Select(async x =>
|
||||
{
|
||||
var inputRoleStr = x.First();
|
||||
var roleReader = new RoleTypeReader<SocketRole>();
|
||||
var roleResult = await roleReader.ReadAsync(ctx, inputRoleStr, _services);
|
||||
if (!roleResult.IsSuccess)
|
||||
{
|
||||
Log.Warning("Role {0} not found.", inputRoleStr);
|
||||
return null;
|
||||
}
|
||||
|
||||
var role = (IRole)roleResult.BestMatch;
|
||||
if (role.Position > ((IGuildUser)ctx.User).GetRoles().Select(r => r.Position).Max()
|
||||
&& ctx.User.Id != ctx.Guild.OwnerId)
|
||||
return null;
|
||||
var emote = x.Last().ToIEmote();
|
||||
return new { role, emote };
|
||||
})
|
||||
.Where(x => x != null)
|
||||
.WhenAll();
|
||||
|
||||
if (!all.Any())
|
||||
return;
|
||||
|
||||
foreach (var x in all)
|
||||
{
|
||||
try
|
||||
{
|
||||
await target.AddReactionAsync(x.emote,
|
||||
new() { RetryMode = RetryMode.Retry502 | RetryMode.RetryRatelimit });
|
||||
}
|
||||
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.reaction_cant_access(Format.Code(x.emote.ToString())));
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(500);
|
||||
}
|
||||
|
||||
if (_service.Add(ctx.Guild.Id,
|
||||
new()
|
||||
{
|
||||
Exclusive = exclusive,
|
||||
MessageId = target.Id,
|
||||
ChannelId = target.Channel.Id,
|
||||
ReactionRoles = all.Select(x =>
|
||||
{
|
||||
return new ReactionRole
|
||||
{
|
||||
EmoteName = x.emote.ToString(), RoleId = x.role.Id
|
||||
};
|
||||
})
|
||||
.ToList()
|
||||
}))
|
||||
await ctx.OkAsync();
|
||||
else
|
||||
await ReplyErrorLocalizedAsync(strs.reaction_roles_full);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public partial Task ReactionRoles(ulong messageId, params string[] input)
|
||||
=> InternalReactionRoles(false, messageId, input);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(1)]
|
||||
public partial Task ReactionRoles(ulong messageId, Exclude _, params string[] input)
|
||||
=> InternalReactionRoles(true, messageId, input);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public partial Task ReactionRoles(params string[] input)
|
||||
=> InternalReactionRoles(false, null, input);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(1)]
|
||||
public partial Task ReactionRoles(Exclude _, params string[] input)
|
||||
=> InternalReactionRoles(true, null, input);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task ReactionRolesList()
|
||||
{
|
||||
var embed = _eb.Create().WithOkColor();
|
||||
if (!_service.Get(ctx.Guild.Id, out var rrs) || !rrs.Any())
|
||||
{
|
||||
embed.WithDescription(GetText(strs.no_reaction_roles));
|
||||
}
|
||||
else
|
||||
{
|
||||
var g = (SocketGuild)ctx.Guild;
|
||||
foreach (var rr in rrs)
|
||||
{
|
||||
var ch = g.GetTextChannel(rr.ChannelId);
|
||||
IUserMessage msg = null;
|
||||
if (ch is not null) msg = await ch.GetMessageAsync(rr.MessageId) as IUserMessage;
|
||||
var content = msg?.Content.TrimTo(30) ?? "DELETED!";
|
||||
embed.AddField($"**{rr.Index + 1}.** {ch?.Name ?? "DELETED!"}",
|
||||
GetText(strs.reaction_roles_message(rr.ReactionRoles?.Count ?? 0, content)));
|
||||
}
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task ReactionRolesRemove(int index)
|
||||
{
|
||||
if (index < 1 || !_service.Get(ctx.Guild.Id, out var rrs) || !rrs.Any() || rrs.Count < index)
|
||||
return;
|
||||
index--;
|
||||
var rr = rrs[index];
|
||||
_service.Remove(ctx.Guild.Id, index);
|
||||
await ReplyConfirmLocalizedAsync(strs.reaction_role_removed(index + 1));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task SetRole(IGuildUser targetUser, [Leftover] IRole roleToAdd)
|
||||
{
|
||||
var runnerUser = (IGuildUser)ctx.User;
|
||||
var runnerMaxRolePosition = runnerUser.GetRoles().Max(x => x.Position);
|
||||
if (ctx.User.Id != ctx.Guild.OwnerId && runnerMaxRolePosition <= roleToAdd.Position)
|
||||
return;
|
||||
try
|
||||
{
|
||||
await targetUser.AddRoleAsync(roleToAdd);
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.setrole(Format.Bold(roleToAdd.Name),
|
||||
Format.Bold(targetUser.ToString())));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Error in setrole command");
|
||||
await ReplyErrorLocalizedAsync(strs.setrole_err);
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task RemoveRole(IGuildUser targetUser, [Leftover] IRole roleToRemove)
|
||||
{
|
||||
var runnerUser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != runnerUser.Guild.OwnerId
|
||||
&& runnerUser.GetRoles().Max(x => x.Position) <= roleToRemove.Position)
|
||||
return;
|
||||
try
|
||||
{
|
||||
await targetUser.RemoveRoleAsync(roleToRemove);
|
||||
await ReplyConfirmLocalizedAsync(strs.remrole(Format.Bold(roleToRemove.Name),
|
||||
Format.Bold(targetUser.ToString())));
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.remrole_err);
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task RenameRole(IRole roleToEdit, [Leftover] string newname)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= roleToEdit.Position)
|
||||
return;
|
||||
try
|
||||
{
|
||||
if (roleToEdit.Position > (await ctx.Guild.GetCurrentUserAsync()).GetRoles().Max(r => r.Position))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.renrole_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
await roleToEdit.ModifyAsync(g => g.Name = newname);
|
||||
await ReplyConfirmLocalizedAsync(strs.renrole);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.renrole_err);
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task RemoveAllRoles([Leftover] IGuildUser user)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
|
||||
var userRoles = user.GetRoles().Where(x => !x.IsManaged && x != x.Guild.EveryoneRole).ToList();
|
||||
|
||||
if (user.Id == ctx.Guild.OwnerId
|
||||
|| (ctx.User.Id != ctx.Guild.OwnerId
|
||||
&& guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position)))
|
||||
return;
|
||||
try
|
||||
{
|
||||
await user.RemoveRolesAsync(userRoles);
|
||||
await ReplyConfirmLocalizedAsync(strs.rar(Format.Bold(user.ToString())));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.rar_err);
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task CreateRole([Leftover] string roleName = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
return;
|
||||
|
||||
var r = await ctx.Guild.CreateRoleAsync(roleName, isMentionable: false);
|
||||
await ReplyConfirmLocalizedAsync(strs.cr(Format.Bold(r.Name)));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task DeleteRole([Leftover] IRole role)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||
return;
|
||||
|
||||
await role.DeleteAsync();
|
||||
await ReplyConfirmLocalizedAsync(strs.dr(Format.Bold(role.Name)));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task RoleHoist(IRole role)
|
||||
{
|
||||
var newHoisted = !role.IsHoisted;
|
||||
await role.ModifyAsync(r => r.Hoist = newHoisted);
|
||||
if (newHoisted)
|
||||
await ReplyConfirmLocalizedAsync(strs.rolehoist_enabled(Format.Bold(role.Name)));
|
||||
else
|
||||
await ReplyConfirmLocalizedAsync(strs.rolehoist_disabled(Format.Bold(role.Name)));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[Priority(1)]
|
||||
public async partial Task RoleColor([Leftover] IRole role)
|
||||
=> await SendConfirmAsync("Role Color", role.Color.RawValue.ToString("x6"));
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Priority(0)]
|
||||
public async partial Task RoleColor(Color color, [Leftover] IRole role)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rgba32 = color.ToPixel<Rgba32>();
|
||||
await role.ModifyAsync(r => r.Color = new Discord.Color(rgba32.R, rgba32.G, rgba32.B));
|
||||
await ReplyConfirmLocalizedAsync(strs.rc(Format.Bold(role.Name)));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.rc_perms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
250
src/NadekoBot/Modules/Administration/Role/RoleCommandsService.cs
Normal file
250
src/NadekoBot/Modules/Administration/Role/RoleCommandsService.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
#nullable disable
|
||||
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;
|
||||
|
||||
public class RoleCommandsService : INService
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly ConcurrentDictionary<ulong, IndexedCollection<ReactionRoleMessage>> _models;
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
#if !GLOBAL_NADEKO
|
||||
_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,
|
||||
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))
|
||||
return;
|
||||
|
||||
var conf = confs.FirstOrDefault(x => x.MessageId == msg.Id);
|
||||
|
||||
if (conf is null)
|
||||
return;
|
||||
|
||||
// compare emote names for backwards compatibility :facepalm:
|
||||
var reactionRole = conf.ReactionRoles.FirstOrDefault(x
|
||||
=> x.EmoteName == reaction.Emote.Name || x.EmoteName == reaction.Emote.ToString());
|
||||
|
||||
if (reactionRole != null)
|
||||
{
|
||||
if (!conf.Exclusive)
|
||||
{
|
||||
await AddReactionRoleAsync(gusr, reactionRole);
|
||||
return;
|
||||
}
|
||||
|
||||
// If same (message, user) are being processed in an exclusive rero, quit
|
||||
if (!_reacting.Add((msg.Id, reaction.UserId)))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var removeExclusiveTask = RemoveExclusiveReactionRoleAsync(msg,
|
||||
gusr,
|
||||
reaction,
|
||||
conf,
|
||||
reactionRole,
|
||||
CancellationToken.None);
|
||||
var addRoleTask = AddReactionRoleAsync(gusr, reactionRole);
|
||||
|
||||
await Task.WhenAll(removeExclusiveTask, addRoleTask);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Free (message/user) for another exclusive rero
|
||||
_reacting.TryRemove((msg.Id, reaction.UserId));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dl = await msg.GetOrDownloadAsync();
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task _client_ReactionRemoved(
|
||||
Cacheable<IUserMessage, ulong> msg,
|
||||
Cacheable<IMessageChannel, ulong> chan,
|
||||
SocketReaction reaction)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!reaction.User.IsSpecified
|
||||
|| reaction.User.Value.IsBot
|
||||
|| reaction.User.Value is not SocketGuildUser gusr)
|
||||
return;
|
||||
|
||||
if (chan.Value is not SocketGuildChannel gch)
|
||||
return;
|
||||
|
||||
if (!_models.TryGetValue(gch.Guild.Id, out var confs))
|
||||
return;
|
||||
|
||||
var conf = confs.FirstOrDefault(x => x.MessageId == msg.Id);
|
||||
|
||||
if (conf is null)
|
||||
return;
|
||||
|
||||
var reactionRole = conf.ReactionRoles.FirstOrDefault(x
|
||||
=> x.EmoteName == reaction.Emote.Name || x.EmoteName == reaction.Emote.ToString());
|
||||
|
||||
if (reactionRole != null)
|
||||
{
|
||||
var role = gusr.Guild.GetRole(reactionRole.RoleId);
|
||||
if (role is null)
|
||||
return;
|
||||
await gusr.RemoveRoleAsync(role);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public bool Get(ulong id, out IndexedCollection<ReactionRoleMessage> rrs)
|
||||
=> _models.TryGetValue(id, out rrs);
|
||||
|
||||
public bool Add(ulong id, ReactionRoleMessage rrm)
|
||||
{
|
||||
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));
|
||||
|
||||
if (gc.ReactionRoleMessages.Count >= 10)
|
||||
return false;
|
||||
|
||||
gc.ReactionRoleMessages.Add(rrm);
|
||||
uow.SaveChanges();
|
||||
|
||||
_models.AddOrUpdate(id, gc.ReactionRoleMessages, delegate { return gc.ReactionRoleMessages; });
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Remove(ulong id, int index)
|
||||
{
|
||||
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);
|
||||
gc.ReactionRoleMessages.RemoveAt(index);
|
||||
_models.AddOrUpdate(id, gc.ReactionRoleMessages, delegate { return gc.ReactionRoleMessages; });
|
||||
uow.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
private Task AddReactionRoleAsync(SocketGuildUser user, ReactionRole dbRero)
|
||||
{
|
||||
var toAdd = user.Guild.GetRole(dbRero.RoleId);
|
||||
|
||||
return toAdd != null && !user.Roles.Contains(toAdd) ? user.AddRoleAsync(toAdd) : Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
/// <param name="reaction">The Discord reaction of the user.</param>
|
||||
/// <param name="dbReroMsg">The database entry of the reaction role message.</param>
|
||||
/// <param name="dbRero">The database settings of this reaction role.</param>
|
||||
/// <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)
|
||||
{
|
||||
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);
|
||||
|
||||
var removeReactionsTask = RemoveOldReactionsAsync(reactionMessage, user, reaction, cToken);
|
||||
|
||||
var removeRolesTask = user.RemoveRolesAsync(roleIds);
|
||||
|
||||
return Task.WhenAll(removeReactionsTask, removeRolesTask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
/// <param name="reaction">The Discord reaction of the user.</param>
|
||||
/// <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)
|
||||
{
|
||||
cToken.ThrowIfCancellationRequested();
|
||||
|
||||
//if the role is exclusive,
|
||||
// remove all other reactions user added to the message
|
||||
var dl = await reactionMessage.GetOrDownloadAsync();
|
||||
foreach (var r in dl.Reactions)
|
||||
{
|
||||
if (r.Key.Name == reaction.Emote.Name)
|
||||
continue;
|
||||
try { await dl.RemoveReactionAsync(r.Key, user); }
|
||||
catch { }
|
||||
|
||||
await Task.Delay(100, cToken);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user