[CompositeRoles] Add listener and options
This commit is contained in:
60
Cocotte/Modules/Activities/CompositeRolesListener.cs
Normal file
60
Cocotte/Modules/Activities/CompositeRolesListener.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Cocotte.Options;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Cocotte.Modules.Activities;
|
||||
|
||||
public class CompositeRolesListener
|
||||
{
|
||||
private readonly ILogger<CompositeRolesListener> _logger;
|
||||
private readonly IDictionary<ulong, GuildCompositeRoles[]> _compositeRoles;
|
||||
|
||||
public CompositeRolesListener(ILogger<CompositeRolesListener> logger,
|
||||
IOptions<CompositeRolesOptions> compositeRolesOptions)
|
||||
{
|
||||
_logger = logger;
|
||||
// Initialize dictionary: transform string guildIds to ulong
|
||||
_compositeRoles = compositeRolesOptions.Value.CompositeRoles.ToDictionary(kp => ulong.Parse(kp.Key), kp => kp.Value);
|
||||
}
|
||||
|
||||
public async Task UserUpdated(Cacheable<SocketGuildUser, ulong> cacheable, SocketGuildUser guildUser)
|
||||
{
|
||||
// Fetch composite roles for this guild
|
||||
if (!_compositeRoles.TryGetValue(guildUser.Guild.Id, out var guildCompositeRoles))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogTrace("Guild {Guild} has at least one composite role, checking for user {User}", guildUser.Guild.Name, guildUser.DisplayName);
|
||||
|
||||
// Check roles for each composite roles
|
||||
var roles = guildUser.Roles;
|
||||
foreach (var compositeRole in guildCompositeRoles)
|
||||
{
|
||||
// If the user has the target role, check if we need to remove it
|
||||
if (roles.FirstOrDefault(r => r.Id == compositeRole.TargetRoleId) is { } presentTargetRole)
|
||||
{
|
||||
// Check that the user no associated role
|
||||
if (!roles.Any(r => compositeRole.CompositeRolesIds.Contains(r.Id)))
|
||||
{
|
||||
await guildUser.RemoveRoleAsync(presentTargetRole);
|
||||
|
||||
_logger.LogInformation("CompositeRoles removed role {Role} from {User}", presentTargetRole.Name, guildUser.DisplayName);
|
||||
}
|
||||
}
|
||||
// It the user doesn't have the target role, check if we need to add it
|
||||
else
|
||||
{
|
||||
// Check that the user has at least one of the desired roles
|
||||
if (roles.Any(r => compositeRole.CompositeRolesIds.Contains(r.Id)))
|
||||
{
|
||||
var missingTargetRole = guildUser.Guild.GetRole(compositeRole.TargetRoleId);
|
||||
await guildUser.AddRoleAsync(missingTargetRole);
|
||||
|
||||
_logger.LogInformation("CompositeRoles added role {Role} from {User}", missingTargetRole.Name, guildUser.DisplayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cocotte.Modules.Activities.Models;
|
||||
|
||||
14
Cocotte/Options/CompositeRolesOptions.cs
Normal file
14
Cocotte/Options/CompositeRolesOptions.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Cocotte.Options;
|
||||
|
||||
public class CompositeRolesOptions
|
||||
{
|
||||
public const string SectionName = "CompositeRolesOptions";
|
||||
|
||||
public required IReadOnlyDictionary<string, GuildCompositeRoles[]> CompositeRoles { get; init; }
|
||||
}
|
||||
|
||||
public class GuildCompositeRoles
|
||||
{
|
||||
public required ulong TargetRoleId { get; init; }
|
||||
public required ulong[] CompositeRolesIds { get; init; }
|
||||
}
|
||||
@@ -21,12 +21,14 @@ IHost host = Host.CreateDefaultBuilder(args)
|
||||
{
|
||||
configuration.AddJsonFile("discord.json", false, false);
|
||||
configuration.AddJsonFile("activity.json", false, false);
|
||||
configuration.AddJsonFile("compositeRoles.json", false, false);
|
||||
})
|
||||
.ConfigureServices((context, services) =>
|
||||
{
|
||||
// Options
|
||||
services.Configure<DiscordOptions>(context.Configuration.GetSection(DiscordOptions.SectionName));
|
||||
services.Configure<ActivityOptions>(context.Configuration.GetSection(ActivityOptions.SectionName));
|
||||
services.Configure<CompositeRolesOptions>(context.Configuration.GetSection(CompositeRolesOptions.SectionName));
|
||||
|
||||
// Database
|
||||
services.AddDbContext<CocotteDbContext>(options =>
|
||||
@@ -53,6 +55,9 @@ IHost host = Host.CreateDefaultBuilder(args)
|
||||
services.AddTransient<InterstellarFormatter>();
|
||||
services.AddTransient<ActivityHelper>();
|
||||
|
||||
// Composite roles
|
||||
services.AddSingleton<CompositeRolesListener>();
|
||||
|
||||
// Raids
|
||||
services.AddTransient<RaidFormatter>();
|
||||
services.AddSingleton<RaidRegisterManager>();
|
||||
|
||||
@@ -65,9 +65,19 @@ public class CocotteService : BackgroundService
|
||||
await _client.LoginAsync(TokenType.Bot, _options.Token);
|
||||
await _client.StartAsync();
|
||||
|
||||
// Register events
|
||||
RegisterEvents();
|
||||
|
||||
await Task.Delay(Timeout.Infinite, stoppingToken);
|
||||
}
|
||||
|
||||
private void RegisterEvents()
|
||||
{
|
||||
var composteRolesListener = _serviceProvider.GetRequiredService<CompositeRolesListener>();
|
||||
|
||||
_client.GuildMemberUpdated += composteRolesListener.UserUpdated;
|
||||
}
|
||||
|
||||
private bool ValidateOptions()
|
||||
{
|
||||
// Validate group options
|
||||
|
||||
26
Cocotte/compositeRoles.json
Normal file
26
Cocotte/compositeRoles.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"CompositeRolesOptions": {
|
||||
"CompositeRoles": {
|
||||
"someGuildId (ulong)": [
|
||||
{
|
||||
"TargetRoleId": 1,
|
||||
"CompositeRolesIds": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
]
|
||||
}
|
||||
],
|
||||
"anotherGuildId (ulong)": [
|
||||
{
|
||||
"TargetRoleId": 45,
|
||||
"CompositeRolesIds": [
|
||||
98,
|
||||
1,
|
||||
2
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user