NadekoBot Patronage system, Search commands improvements + fixes

This commit is contained in:
Kwoth
2022-06-14 07:24:33 +00:00
parent 18b10b8c6f
commit 7b5145f116
165 changed files with 14920 additions and 1457 deletions

View File

@@ -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();

View File

@@ -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

View File

@@ -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,

View File

@@ -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)]

View File

@@ -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>()

View File

@@ -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);