forked from EllieBotDevs/elliebot
140 lines
4.3 KiB
C#
140 lines
4.3 KiB
C#
using LinqToDB;
|
|
using LinqToDB.EntityFrameworkCore;
|
|
using EllieBot.Common.ModuleBehaviors;
|
|
using EllieBot.Db.Models;
|
|
|
|
namespace EllieBot.Modules.Administration;
|
|
|
|
public class TempRoleService : IReadyExecutor, IEService
|
|
{
|
|
private readonly DbService _db;
|
|
private readonly DiscordSocketClient _client;
|
|
private readonly IBotCreds _creds;
|
|
|
|
private TaskCompletionSource<bool> _tcs = new();
|
|
|
|
public TempRoleService(
|
|
DbService db,
|
|
DiscordSocketClient client,
|
|
IBotCreds creds)
|
|
{
|
|
_db = db;
|
|
_client = client;
|
|
_creds = creds;
|
|
}
|
|
|
|
public async Task AddTempRoleAsync(
|
|
ulong guildId,
|
|
ulong roleId,
|
|
ulong userId,
|
|
TimeSpan duration)
|
|
{
|
|
if (duration == TimeSpan.Zero)
|
|
{
|
|
await using var uow = _db.GetDbContext();
|
|
await uow.GetTable<TempRole>()
|
|
.Where(x => x.GuildId == guildId && x.UserId == userId)
|
|
.DeleteAsync();
|
|
return;
|
|
}
|
|
|
|
var until = DateTime.UtcNow.Add(duration);
|
|
await using var ctx = _db.GetDbContext();
|
|
await ctx.GetTable<TempRole>()
|
|
.InsertOrUpdateAsync(() => new()
|
|
{
|
|
GuildId = guildId,
|
|
RoleId = roleId,
|
|
UserId = userId,
|
|
Remove = false,
|
|
ExpiresAt = until
|
|
},
|
|
(old) => new()
|
|
{
|
|
ExpiresAt = until,
|
|
},
|
|
() => new()
|
|
{
|
|
GuildId = guildId,
|
|
UserId = userId,
|
|
RoleId = roleId
|
|
});
|
|
|
|
_tcs.TrySetResult(true);
|
|
}
|
|
|
|
public async Task OnReadyAsync()
|
|
{
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
_tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
var latest = await _db.GetDbContext()
|
|
.GetTable<TempRole>()
|
|
.Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId,
|
|
_creds.TotalShards,
|
|
_client.ShardId))
|
|
.OrderBy(x => x.ExpiresAt)
|
|
.FirstOrDefaultAsyncLinqToDB();
|
|
|
|
if (latest == default)
|
|
{
|
|
await _tcs.Task;
|
|
continue;
|
|
}
|
|
|
|
var now = DateTime.UtcNow;
|
|
if (latest.ExpiresAt > now)
|
|
{
|
|
await Task.WhenAny(Task.Delay(latest.ExpiresAt - now), _tcs.Task);
|
|
continue;
|
|
}
|
|
|
|
var deleted = await _db.GetDbContext()
|
|
.GetTable<TempRole>()
|
|
.Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId,
|
|
_creds.TotalShards,
|
|
_client.ShardId)
|
|
&& x.ExpiresAt <= now)
|
|
.DeleteWithOutputAsync();
|
|
|
|
foreach (var d in deleted)
|
|
{
|
|
try
|
|
{
|
|
await RemoveRole(d);
|
|
}
|
|
catch
|
|
{
|
|
Log.Warning("Unable to remove temp role {RoleId} from user {UserId}",
|
|
d.RoleId,
|
|
d.UserId);
|
|
}
|
|
|
|
await Task.Delay(1000);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Unexpected error occurred in temprole loop");
|
|
await Task.Delay(1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task RemoveRole(TempRole tempRole)
|
|
{
|
|
var guild = _client.GetGuild(tempRole.GuildId);
|
|
|
|
var role = guild?.GetRole(tempRole.RoleId);
|
|
if (role is null)
|
|
return;
|
|
|
|
var user = guild?.GetUser(tempRole.UserId);
|
|
if (user is null)
|
|
return;
|
|
|
|
await user.RemoveRoleAsync(role);
|
|
}
|
|
}
|