mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
More restructuring
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Utility.Patronage;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using OneOf;
|
||||
using OneOf.Types;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public interface IReactionRoleService
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a single reaction role
|
||||
/// </summary>
|
||||
/// <param name="guild">Guild where to add a reaction role</param>
|
||||
/// <param name="msg">Message to which to add a reaction role</param>
|
||||
/// <param name="emote"></param>
|
||||
/// <param name="role"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="levelReq"></param>
|
||||
/// <returns>The result of the operation</returns>
|
||||
Task<OneOf<Success, FeatureLimit>> AddReactionRole(
|
||||
IGuild guild,
|
||||
IMessage msg,
|
||||
string emote,
|
||||
IRole role,
|
||||
int group = 0,
|
||||
int levelReq = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Get all reaction roles on the specified server
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <returns></returns>
|
||||
Task<IReadOnlyCollection<ReactionRoleV2>> GetReactionRolesAsync(ulong guildId);
|
||||
|
||||
/// <summary>
|
||||
/// Remove reaction roles on the specified message
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> RemoveReactionRoles(ulong guildId, ulong messageId);
|
||||
|
||||
/// <summary>
|
||||
/// Remove all reaction roles in the specified server
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> RemoveAllReactionRoles(ulong guildId);
|
||||
|
||||
Task<IReadOnlyCollection<IEmote>> TransferReactionRolesAsync(ulong guildId, ulong fromMessageId, ulong toMessageId);
|
||||
}
|
@@ -1,171 +0,0 @@
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration
|
||||
{
|
||||
public partial class ReactionRoleCommands : NadekoModule
|
||||
{
|
||||
private readonly IReactionRoleService _rero;
|
||||
|
||||
public ReactionRoleCommands(IReactionRoleService rero)
|
||||
{
|
||||
_rero = rero;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ReactionRoleAdd(
|
||||
ulong messageId,
|
||||
string emoteStr,
|
||||
IRole role,
|
||||
int group = 0,
|
||||
int levelReq = 0)
|
||||
{
|
||||
if (group < 0)
|
||||
return;
|
||||
|
||||
if (levelReq < 0)
|
||||
return;
|
||||
|
||||
var msg = await ctx.Channel.GetMessageAsync(messageId);
|
||||
if (msg is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.User.Id != ctx.Guild.OwnerId && ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position) <= role.Position)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.hierarchy);
|
||||
return;
|
||||
}
|
||||
|
||||
var emote = emoteStr.ToIEmote();
|
||||
await msg.AddReactionAsync(emote);
|
||||
var res = await _rero.AddReactionRole(ctx.Guild,
|
||||
msg,
|
||||
emoteStr,
|
||||
role,
|
||||
group,
|
||||
levelReq);
|
||||
|
||||
await res.Match(
|
||||
_ => ctx.OkAsync(),
|
||||
fl =>
|
||||
{
|
||||
_ = msg.RemoveReactionAsync(emote, ctx.Client.CurrentUser);
|
||||
return !fl.IsPatronLimit
|
||||
? ReplyErrorLocalizedAsync(strs.limit_reached(fl.Quota))
|
||||
: ReplyPendingLocalizedAsync(strs.feature_limit_reached_owner(fl.Quota, fl.Name));
|
||||
});
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ReactionRolesList(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
|
||||
var reros = await _rero.GetReactionRolesAsync(ctx.Guild.Id);
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page, curPage =>
|
||||
{
|
||||
var embed = _eb.Create(ctx)
|
||||
.WithOkColor();
|
||||
|
||||
var content = string.Empty;
|
||||
foreach (var g in reros.OrderBy(x => x.Group)
|
||||
.Skip(curPage * 10)
|
||||
.GroupBy(x => x.MessageId)
|
||||
.OrderBy(x => x.Key))
|
||||
{
|
||||
var messageId = g.Key;
|
||||
content +=
|
||||
$"[{messageId}](https://discord.com/channels/{ctx.Guild.Id}/{g.First().ChannelId}/{g.Key})\n";
|
||||
|
||||
var groupGroups = g.GroupBy(x => x.Group);
|
||||
|
||||
foreach (var ggs in groupGroups)
|
||||
{
|
||||
content += $"`< {(g.Key == 0 ? ("Not Exclusive (Group 0)") : ($"Group {ggs.Key}"))} >`\n";
|
||||
|
||||
foreach (var rero in ggs)
|
||||
{
|
||||
content +=
|
||||
$"\t{rero.Emote} -> {(ctx.Guild.GetRole(rero.RoleId)?.Mention ?? "<missing role>")}";
|
||||
if (rero.LevelReq > 0)
|
||||
content += $" (lvl {rero.LevelReq}+)";
|
||||
content += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
embed.WithDescription(string.IsNullOrWhiteSpace(content)
|
||||
? "There are no reaction roles on this server"
|
||||
: content);
|
||||
|
||||
return embed;
|
||||
}, reros.Count, 10);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ReactionRolesRemove(ulong messageId)
|
||||
{
|
||||
var succ = await _rero.RemoveReactionRoles(ctx.Guild.Id, messageId);
|
||||
if (succ)
|
||||
await ctx.OkAsync();
|
||||
else
|
||||
await ctx.ErrorAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ReactionRolesDeleteAll()
|
||||
{
|
||||
await _rero.RemoveAllReactionRoles(ctx.Guild.Id);
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Ratelimit(60)]
|
||||
public async Task ReactionRolesTransfer(ulong fromMessageId, ulong toMessageId)
|
||||
{
|
||||
var msg = await ctx.Channel.GetMessageAsync(toMessageId);
|
||||
|
||||
if (msg is null)
|
||||
{
|
||||
await ctx.ErrorAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var reactions = await _rero.TransferReactionRolesAsync(ctx.Guild.Id, fromMessageId, toMessageId);
|
||||
|
||||
if (reactions.Count == 0)
|
||||
{
|
||||
await ctx.ErrorAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var r in reactions)
|
||||
{
|
||||
await msg.AddReactionAsync(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,396 +0,0 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Modules.Utility.Patronage;
|
||||
using NadekoBot.Modules.Xp.Extensions;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using OneOf.Types;
|
||||
using OneOf;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionRoleService
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
private ConcurrentDictionary<ulong, List<ReactionRoleV2>> _cache;
|
||||
private readonly object _cacheLock = new();
|
||||
private readonly SemaphoreSlim _assignementLock = new(1, 1);
|
||||
private readonly IPatronageService _ps;
|
||||
|
||||
private static readonly FeatureLimitKey _reroFLKey = new()
|
||||
{
|
||||
Key = "rero:max_count",
|
||||
PrettyName = "Reaction Role"
|
||||
};
|
||||
|
||||
public ReactionRolesService(
|
||||
DiscordSocketClient client,
|
||||
DbService db,
|
||||
IBotCredentials creds,
|
||||
IPatronageService ps)
|
||||
{
|
||||
_db = db;
|
||||
_ps = ps;
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
_cache = new();
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var reros = await uow.GetTable<ReactionRoleV2>()
|
||||
.Where(
|
||||
x => Linq2DbExpressions.GuildOnShard(x.GuildId, _creds.TotalShards, _client.ShardId))
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
foreach (var group in reros.GroupBy(x => x.MessageId))
|
||||
{
|
||||
_cache[group.Key] = group.ToList();
|
||||
}
|
||||
|
||||
_client.ReactionAdded += ClientOnReactionAdded;
|
||||
_client.ReactionRemoved += ClientOnReactionRemoved;
|
||||
}
|
||||
|
||||
private async Task<(IGuildUser, IRole)> GetUserAndRoleAsync(
|
||||
ulong userId,
|
||||
ReactionRoleV2 rero)
|
||||
{
|
||||
var guild = _client.GetGuild(rero.GuildId);
|
||||
var role = guild?.GetRole(rero.RoleId);
|
||||
|
||||
if (role is null)
|
||||
return default;
|
||||
|
||||
var user = guild.GetUser(userId) as IGuildUser
|
||||
?? await _client.Rest.GetGuildUserAsync(guild.Id, userId);
|
||||
|
||||
if (user is null)
|
||||
return default;
|
||||
|
||||
return (user, role);
|
||||
}
|
||||
|
||||
private Task ClientOnReactionRemoved(
|
||||
Cacheable<IUserMessage, ulong> cmsg,
|
||||
Cacheable<IMessageChannel, ulong> ch,
|
||||
SocketReaction r)
|
||||
{
|
||||
if (!_cache.TryGetValue(cmsg.Id, out var reros))
|
||||
return Task.CompletedTask;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var emote = await GetFixedEmoteAsync(cmsg, r.Emote);
|
||||
|
||||
var rero = reros.FirstOrDefault(x => x.Emote == emote.Name
|
||||
|| x.Emote == emote.ToString());
|
||||
if (rero is null)
|
||||
return;
|
||||
|
||||
var (user, role) = await GetUserAndRoleAsync(r.UserId, rero);
|
||||
|
||||
if (user.IsBot)
|
||||
return;
|
||||
|
||||
await _assignementLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
if (user.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await user.RemoveRoleAsync(role.Id);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_assignementLock.Release();
|
||||
}
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
// had to add this because for some reason, reactionremoved event's reaction doesn't have IsAnimated set,
|
||||
// causing the .ToString() to be wrong on animated custom emotes
|
||||
private async Task<IEmote> GetFixedEmoteAsync(
|
||||
Cacheable<IUserMessage, ulong> cmsg,
|
||||
IEmote inputEmote)
|
||||
{
|
||||
// this should only run for emote
|
||||
if (inputEmote is not Emote e)
|
||||
return inputEmote;
|
||||
|
||||
// try to get the message and pull
|
||||
var msg = await cmsg.GetOrDownloadAsync();
|
||||
|
||||
var emote = msg.Reactions.Keys.FirstOrDefault(x => e.Equals(x));
|
||||
return emote ?? inputEmote;
|
||||
}
|
||||
|
||||
private Task ClientOnReactionAdded(
|
||||
Cacheable<IUserMessage, ulong> msg,
|
||||
Cacheable<IMessageChannel, ulong> ch,
|
||||
SocketReaction r)
|
||||
{
|
||||
if (!_cache.TryGetValue(msg.Id, out var reros))
|
||||
return Task.CompletedTask;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var rero = reros.FirstOrDefault(x => x.Emote == r.Emote.Name || x.Emote == r.Emote.ToString());
|
||||
if (rero is null)
|
||||
return;
|
||||
|
||||
var (user, role) = await GetUserAndRoleAsync(r.UserId, rero);
|
||||
|
||||
if (user.IsBot)
|
||||
return;
|
||||
|
||||
await _assignementLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
if (!user.RoleIds.Contains(role.Id))
|
||||
{
|
||||
// first check if there is a level requirement
|
||||
// and if there is, make sure user satisfies it
|
||||
if (rero.LevelReq > 0)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var levelData = await ctx.GetTable<UserXpStats>()
|
||||
.GetLevelDataFor(user.GuildId, user.Id);
|
||||
|
||||
if (levelData.Level < rero.LevelReq)
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all other roles from the same group from the user
|
||||
// execept in group 0, which is a special, non-exclusive group
|
||||
if (rero.Group != 0)
|
||||
{
|
||||
var exclusive = reros
|
||||
.Where(x => x.Group == rero.Group && x.RoleId != role.Id)
|
||||
.Select(x => x.RoleId)
|
||||
.Distinct();
|
||||
|
||||
|
||||
try { await user.RemoveRolesAsync(exclusive); }
|
||||
catch { }
|
||||
|
||||
// remove user's previous reaction
|
||||
try
|
||||
{
|
||||
var m = await msg.GetOrDownloadAsync();
|
||||
if (m is not null)
|
||||
{
|
||||
var reactToRemove = m.Reactions
|
||||
.FirstOrDefault(x => x.Key.ToString() != r.Emote.ToString())
|
||||
.Key;
|
||||
|
||||
if (reactToRemove is not null)
|
||||
{
|
||||
await m.RemoveReactionAsync(reactToRemove, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
await user.AddRoleAsync(role.Id);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_assignementLock.Release();
|
||||
}
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a single reaction role
|
||||
/// </summary>
|
||||
/// <param name="guild">Guild where to add a reaction role</param>
|
||||
/// <param name="msg">Message to which to add a reaction role</param>
|
||||
/// <param name="emote"></param>
|
||||
/// <param name="role"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="levelReq"></param>
|
||||
/// <returns>The result of the operation</returns>
|
||||
public async Task<OneOf<Success, FeatureLimit>> AddReactionRole(
|
||||
IGuild guild,
|
||||
IMessage msg,
|
||||
string emote,
|
||||
IRole role,
|
||||
int group = 0,
|
||||
int levelReq = 0)
|
||||
{
|
||||
if (group < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(group));
|
||||
|
||||
if (levelReq < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(group));
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
await using var tran = await ctx.Database.BeginTransactionAsync();
|
||||
var activeReactionRoles = await ctx.GetTable<ReactionRoleV2>()
|
||||
.Where(x => x.GuildId == guild.Id)
|
||||
.CountAsync();
|
||||
|
||||
var result = await _ps.TryGetFeatureLimitAsync(_reroFLKey, guild.OwnerId, 50);
|
||||
if (result.Quota != -1 && activeReactionRoles >= result.Quota)
|
||||
return result;
|
||||
|
||||
await ctx.GetTable<ReactionRoleV2>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guild.Id,
|
||||
ChannelId = msg.Channel.Id,
|
||||
|
||||
MessageId = msg.Id,
|
||||
Emote = emote,
|
||||
|
||||
RoleId = role.Id,
|
||||
Group = group,
|
||||
LevelReq = levelReq
|
||||
},
|
||||
(old) => new()
|
||||
{
|
||||
RoleId = role.Id,
|
||||
Group = group,
|
||||
LevelReq = levelReq
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
MessageId = msg.Id,
|
||||
Emote = emote,
|
||||
});
|
||||
|
||||
await tran.CommitAsync();
|
||||
|
||||
var obj = new ReactionRoleV2()
|
||||
{
|
||||
GuildId = guild.Id,
|
||||
MessageId = msg.Id,
|
||||
Emote = emote,
|
||||
RoleId = role.Id,
|
||||
Group = group,
|
||||
LevelReq = levelReq
|
||||
};
|
||||
|
||||
lock (_cacheLock)
|
||||
{
|
||||
_cache.AddOrUpdate(msg.Id,
|
||||
_ => new()
|
||||
{
|
||||
obj
|
||||
},
|
||||
(_, list) =>
|
||||
{
|
||||
list.RemoveAll(x => x.Emote == emote);
|
||||
list.Add(obj);
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
return new Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all reaction roles on the specified server
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IReadOnlyCollection<ReactionRoleV2>> GetReactionRolesAsync(ulong guildId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
return await ctx.GetTable<ReactionRoleV2>()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove reaction roles on the specified message
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <param name="messageId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> RemoveReactionRoles(ulong guildId, ulong messageId)
|
||||
{
|
||||
// guildid is used for quick index lookup
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var changed = await ctx.GetTable<ReactionRoleV2>()
|
||||
.Where(x => x.GuildId == guildId && x.MessageId == messageId)
|
||||
.DeleteAsync();
|
||||
|
||||
_cache.TryRemove(messageId, out _);
|
||||
|
||||
if (changed == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all reaction roles in the specified server
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> RemoveAllReactionRoles(ulong guildId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var output = await ctx.GetTable<ReactionRoleV2>()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.DeleteWithOutputAsync(x => x.MessageId);
|
||||
|
||||
lock (_cacheLock)
|
||||
{
|
||||
foreach (var o in output)
|
||||
{
|
||||
_cache.TryRemove(o, out _);
|
||||
}
|
||||
}
|
||||
|
||||
return output.Length;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<IEmote>> TransferReactionRolesAsync(
|
||||
ulong guildId,
|
||||
ulong fromMessageId,
|
||||
ulong toMessageId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var updated = ctx.GetTable<ReactionRoleV2>()
|
||||
.Where(x => x.GuildId == guildId && x.MessageId == fromMessageId)
|
||||
.UpdateWithOutput(old => new()
|
||||
{
|
||||
MessageId = toMessageId
|
||||
},
|
||||
(old, neu) => neu);
|
||||
lock (_cacheLock)
|
||||
{
|
||||
if (_cache.TryRemove(fromMessageId, out var data))
|
||||
{
|
||||
if (_cache.TryGetValue(toMessageId, out var newData))
|
||||
{
|
||||
newData.AddRange(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cache[toMessageId] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return updated.Select(x => x.Emote.ToIEmote()).ToList();
|
||||
}
|
||||
}
|
@@ -1,187 +0,0 @@
|
||||
#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 : NadekoModule
|
||||
{
|
||||
public enum Exclude { Excl }
|
||||
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public RoleCommands(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async 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 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 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 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 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 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 Task RoleHoist([Leftover] 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 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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user