[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;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Cocotte.Modules.Activities.Models;
|
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("discord.json", false, false);
|
||||||
configuration.AddJsonFile("activity.json", false, false);
|
configuration.AddJsonFile("activity.json", false, false);
|
||||||
|
configuration.AddJsonFile("compositeRoles.json", false, false);
|
||||||
})
|
})
|
||||||
.ConfigureServices((context, services) =>
|
.ConfigureServices((context, services) =>
|
||||||
{
|
{
|
||||||
// Options
|
// Options
|
||||||
services.Configure<DiscordOptions>(context.Configuration.GetSection(DiscordOptions.SectionName));
|
services.Configure<DiscordOptions>(context.Configuration.GetSection(DiscordOptions.SectionName));
|
||||||
services.Configure<ActivityOptions>(context.Configuration.GetSection(ActivityOptions.SectionName));
|
services.Configure<ActivityOptions>(context.Configuration.GetSection(ActivityOptions.SectionName));
|
||||||
|
services.Configure<CompositeRolesOptions>(context.Configuration.GetSection(CompositeRolesOptions.SectionName));
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
services.AddDbContext<CocotteDbContext>(options =>
|
services.AddDbContext<CocotteDbContext>(options =>
|
||||||
@@ -53,6 +55,9 @@ IHost host = Host.CreateDefaultBuilder(args)
|
|||||||
services.AddTransient<InterstellarFormatter>();
|
services.AddTransient<InterstellarFormatter>();
|
||||||
services.AddTransient<ActivityHelper>();
|
services.AddTransient<ActivityHelper>();
|
||||||
|
|
||||||
|
// Composite roles
|
||||||
|
services.AddSingleton<CompositeRolesListener>();
|
||||||
|
|
||||||
// Raids
|
// Raids
|
||||||
services.AddTransient<RaidFormatter>();
|
services.AddTransient<RaidFormatter>();
|
||||||
services.AddSingleton<RaidRegisterManager>();
|
services.AddSingleton<RaidRegisterManager>();
|
||||||
|
|||||||
@@ -65,9 +65,19 @@ public class CocotteService : BackgroundService
|
|||||||
await _client.LoginAsync(TokenType.Bot, _options.Token);
|
await _client.LoginAsync(TokenType.Bot, _options.Token);
|
||||||
await _client.StartAsync();
|
await _client.StartAsync();
|
||||||
|
|
||||||
|
// Register events
|
||||||
|
RegisterEvents();
|
||||||
|
|
||||||
await Task.Delay(Timeout.Infinite, stoppingToken);
|
await Task.Delay(Timeout.Infinite, stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterEvents()
|
||||||
|
{
|
||||||
|
var composteRolesListener = _serviceProvider.GetRequiredService<CompositeRolesListener>();
|
||||||
|
|
||||||
|
_client.GuildMemberUpdated += composteRolesListener.UserUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
private bool ValidateOptions()
|
private bool ValidateOptions()
|
||||||
{
|
{
|
||||||
// Validate group options
|
// 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