mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
NadekoBot Patronage system, Search commands improvements + fixes
This commit is contained in:
@@ -23,6 +23,8 @@ public class DangerousCommandsService : INService
|
||||
// IsClubAdmin = false,
|
||||
TotalXp = 0
|
||||
});
|
||||
|
||||
await ctx.UserXpStats.DeleteAsync();
|
||||
await ctx.ClubApplicants.DeleteAsync();
|
||||
await ctx.ClubBans.DeleteAsync();
|
||||
await ctx.Clubs.DeleteAsync();
|
||||
|
@@ -23,12 +23,13 @@ public class PruneService : INService
|
||||
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
IMessage[] msgs;
|
||||
IMessage lastMessage = null;
|
||||
msgs = (await channel.GetMessagesAsync(50).FlattenAsync()).Where(predicate).Take(amount).ToArray();
|
||||
while (amount > 0 && msgs.Any())
|
||||
{
|
||||
lastMessage = msgs[msgs.Length - 1];
|
||||
lastMessage = msgs[^1];
|
||||
|
||||
var bulkDeletable = new List<IMessage>();
|
||||
var singleDeletable = new List<IMessage>();
|
||||
@@ -36,17 +37,23 @@ public class PruneService : INService
|
||||
{
|
||||
_logService.AddDeleteIgnore(x.Id);
|
||||
|
||||
if (DateTime.UtcNow - x.CreatedAt < _twoWeeks)
|
||||
if (now - x.CreatedAt < _twoWeeks)
|
||||
bulkDeletable.Add(x);
|
||||
else
|
||||
singleDeletable.Add(x);
|
||||
}
|
||||
|
||||
if (bulkDeletable.Count > 0)
|
||||
await Task.WhenAll(Task.Delay(1000), channel.DeleteMessagesAsync(bulkDeletable));
|
||||
{
|
||||
await channel.DeleteMessagesAsync(bulkDeletable);
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
|
||||
foreach (var group in singleDeletable.Chunk(5))
|
||||
await Task.WhenAll(Task.Delay(5000), group.Select(x => x.DeleteAsync()).WhenAll());
|
||||
{
|
||||
await group.Select(x => x.DeleteAsync()).WhenAll();
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
|
||||
//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
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Utility.Patronage;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections;
|
||||
using OneOf;
|
||||
using OneOf.Types;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -9,18 +11,16 @@ public interface IReactionRoleService
|
||||
/// <summary>
|
||||
/// Adds a single reaction role
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="channel"></param>
|
||||
/// <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></returns>
|
||||
Task<bool> AddReactionRole(
|
||||
ulong guildId,
|
||||
/// <returns>The result of the operation</returns>
|
||||
Task<OneOf<Success, FeatureLimit>> AddReactionRole(
|
||||
IGuild guild,
|
||||
IMessage msg,
|
||||
ITextChannel channel,
|
||||
string emote,
|
||||
IRole role,
|
||||
int group = 0,
|
||||
|
@@ -15,7 +15,6 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task ReactionRoleAdd(
|
||||
@@ -46,27 +45,26 @@ public partial class Administration
|
||||
|
||||
var emote = emoteStr.ToIEmote();
|
||||
await msg.AddReactionAsync(emote);
|
||||
var succ = await _rero.AddReactionRole(ctx.Guild.Id,
|
||||
var res = await _rero.AddReactionRole(ctx.Guild,
|
||||
msg,
|
||||
(ITextChannel)ctx.Channel,
|
||||
emoteStr,
|
||||
role,
|
||||
group,
|
||||
levelReq);
|
||||
|
||||
if (succ)
|
||||
{
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await ctx.ErrorAsync();
|
||||
}
|
||||
|
||||
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)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task ReactionRolesList()
|
||||
@@ -109,7 +107,6 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task ReactionRolesRemove(ulong messageId)
|
||||
@@ -123,7 +120,6 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task ReactionRolesDeleteAll()
|
||||
@@ -134,7 +130,6 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[NoPublicBot]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
[Ratelimit(60)]
|
||||
|
@@ -2,8 +2,11 @@
|
||||
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;
|
||||
|
||||
@@ -16,20 +19,33 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
private ConcurrentDictionary<ulong, List<ReactionRoleV2>> _cache;
|
||||
private readonly object _cacheLock = new();
|
||||
private readonly SemaphoreSlim _assignementLock = new(1, 1);
|
||||
private readonly IPatronageService _ps;
|
||||
|
||||
public ReactionRolesService(DiscordSocketClient client, DbService db, IBotCredentials creds)
|
||||
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))
|
||||
.Where(
|
||||
x => Linq2DbExpressions.GuildOnShard(x.GuildId, _creds.TotalShards, _client.ShardId))
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
foreach (var group in reros.GroupBy(x => x.MessageId))
|
||||
@@ -126,12 +142,12 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var levelData = await ctx.GetTable<UserXpStats>()
|
||||
.GetLevelDataFor(user.GuildId, user.Id);
|
||||
.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)
|
||||
@@ -141,7 +157,7 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
.Select(x => x.RoleId)
|
||||
.Distinct();
|
||||
|
||||
|
||||
|
||||
try { await user.RemoveRolesAsync(exclusive); }
|
||||
catch { }
|
||||
|
||||
@@ -181,18 +197,16 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
/// <summary>
|
||||
/// Adds a single reaction role
|
||||
/// </summary>
|
||||
/// <param name="guildId"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="channel"></param>
|
||||
/// <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></returns>
|
||||
public async Task<bool> AddReactionRole(
|
||||
ulong guildId,
|
||||
/// <returns>The result of the operation</returns>
|
||||
public async Task<OneOf<Success, FeatureLimit>> AddReactionRole(
|
||||
IGuild guild,
|
||||
IMessage msg,
|
||||
ITextChannel channel,
|
||||
string emote,
|
||||
IRole role,
|
||||
int group = 0,
|
||||
@@ -205,44 +219,46 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
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 == guildId)
|
||||
.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;
|
||||
|
||||
if (activeReactionRoles >= 50)
|
||||
return false;
|
||||
await ctx.GetTable<ReactionRoleV2>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guild.Id,
|
||||
ChannelId = msg.Channel.Id,
|
||||
|
||||
var changed = await ctx.GetTable<ReactionRoleV2>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ChannelId = channel.Id,
|
||||
MessageId = msg.Id,
|
||||
Emote = emote,
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
RoleId = role.Id,
|
||||
Group = group,
|
||||
LevelReq = levelReq
|
||||
},
|
||||
(old) => new()
|
||||
{
|
||||
RoleId = role.Id,
|
||||
Group = group,
|
||||
LevelReq = levelReq
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
MessageId = msg.Id,
|
||||
Emote = emote,
|
||||
});
|
||||
|
||||
if (changed == 0)
|
||||
return false;
|
||||
await tran.CommitAsync();
|
||||
|
||||
var obj = new ReactionRoleV2()
|
||||
{
|
||||
GuildId = guildId,
|
||||
GuildId = guild.Id,
|
||||
MessageId = msg.Id,
|
||||
Emote = emote,
|
||||
RoleId = role.Id,
|
||||
@@ -265,7 +281,7 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
return new Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -326,7 +342,10 @@ public sealed class ReactionRolesService : IReadyExecutor, INService, IReactionR
|
||||
return output.Length;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<IEmote>> TransferReactionRolesAsync(ulong guildId, ulong fromMessageId, ulong toMessageId)
|
||||
public async Task<IReadOnlyCollection<IEmote>> TransferReactionRolesAsync(
|
||||
ulong guildId,
|
||||
ulong fromMessageId,
|
||||
ulong toMessageId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var updated = ctx.GetTable<ReactionRoleV2>()
|
||||
|
@@ -149,7 +149,7 @@ public partial class Administration
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async partial Task RoleHoist(IRole role)
|
||||
public async partial Task RoleHoist([Leftover] IRole role)
|
||||
{
|
||||
var newHoisted = !role.IsHoisted;
|
||||
await role.ModifyAsync(r => r.Hoist = newHoisted);
|
||||
|
Reference in New Issue
Block a user