1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-04-20 00:43:36 +03:00

Fix issues reported by ReSharper, implement GuildData (only GuildConfiguration)

Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
Octol1ttle 2023-05-30 18:42:57 +05:00
parent 3e9940f0ca
commit cca2965205
Signed by: Octol1ttle
GPG key ID: B77C34313AEE1FFF
10 changed files with 201 additions and 116 deletions

View file

@ -18,9 +18,6 @@ jobs:
contents: read contents: read
security-events: write security-events: write
strategy:
fail-fast: false
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v3

View file

@ -1,3 +1,4 @@
using Boyfriend.Data.Services;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -17,20 +18,11 @@ using Remora.Rest.Core;
namespace Boyfriend; namespace Boyfriend;
public class Boyfriend { public class Boyfriend {
public static ILogger<Boyfriend> Logger = null!;
public static IConfiguration GuildConfiguration = null!;
public static readonly AllowedMentions NoMentions = new( public static readonly AllowedMentions NoMentions = new(
Array.Empty<MentionType>(), Array.Empty<Snowflake>(), Array.Empty<Snowflake>()); Array.Empty<MentionType>(), Array.Empty<Snowflake>(), Array.Empty<Snowflake>());
public static async Task Main(string[] args) { public static async Task Main(string[] args) {
var host = CreateHostBuilder(args).UseConsoleLifetime().Build(); var host = CreateHostBuilder(args).UseConsoleLifetime().Build();
var services = host.Services;
Logger = services.GetRequiredService<ILogger<Boyfriend>>();
GuildConfiguration = services.GetRequiredService<IConfigurationBuilder>().AddJsonFile("guild_configs.json")
.Build();
await host.RunAsync(); await host.RunAsync();
} }
@ -47,12 +39,10 @@ public class Boyfriend {
} }
).ConfigureServices( ).ConfigureServices(
(_, services) => { (_, services) => {
var responderTypes = typeof(Boyfriend).Assembly services.Configure<DiscordGatewayClientOptions>(
.GetExportedTypes() options => options.Intents |= GatewayIntents.MessageContents
.Where(t => t.IsResponder()); | GatewayIntents.GuildMembers
foreach (var responderType in responderTypes) services.AddResponder(responderType); | GatewayIntents.GuildScheduledEvents);
services.AddDiscordCaching();
services.Configure<CacheSettings>( services.Configure<CacheSettings>(
settings => { settings => {
settings.SetDefaultAbsoluteExpiration(TimeSpan.FromHours(1)); settings.SetDefaultAbsoluteExpiration(TimeSpan.FromHours(1));
@ -61,16 +51,16 @@ public class Boyfriend {
settings.SetSlidingExpiration<IMessage>(TimeSpan.FromDays(7)); settings.SetSlidingExpiration<IMessage>(TimeSpan.FromDays(7));
}); });
services.AddTransient<IConfigurationBuilder, ConfigurationBuilder>(); services.AddTransient<IConfigurationBuilder, ConfigurationBuilder>()
.AddDiscordCaching()
services.Configure<DiscordGatewayClientOptions>( .AddDiscordCommands()
options => options.Intents |= GatewayIntents.MessageContents .AddInteractivity()
| GatewayIntents.GuildMembers .AddInteractionGroup<InteractionResponders>()
| GatewayIntents.GuildScheduledEvents); .AddSingleton<GuildDataService>();
var responderTypes = typeof(Boyfriend).Assembly
services.AddDiscordCommands(); .GetExportedTypes()
services.AddInteractivity(); .Where(t => t.IsResponder());
services.AddInteractionGroup<InteractionResponders>(); foreach (var responderType in responderTypes) services.AddResponder(responderType);
} }
).ConfigureLogging( ).ConfigureLogging(
c => c.AddConsole() c => c.AddConsole()

View file

@ -5,7 +5,7 @@
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>1.0.0</Version> <Version>2.0.0</Version>
<Title>Boyfriend</Title> <Title>Boyfriend</Title>
<Authors>Octol1ttle, mctaylors</Authors> <Authors>Octol1ttle, mctaylors</Authors>
<Copyright>AGPLv3</Copyright> <Copyright>AGPLv3</Copyright>
@ -21,7 +21,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DiffPlex" Version="1.7.1"/> <PackageReference Include="DiffPlex" Version="1.7.1"/>
<PackageReference Include="Humanizer.Core.ru" Version="2.14.1"/> <PackageReference Include="Humanizer.Core.ru" Version="2.14.1"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0-preview.3.23174.8"/> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1"/>
<PackageReference Include="Remora.Discord" Version="2023.3.0"/> <PackageReference Include="Remora.Discord" Version="2023.3.0"/>
</ItemGroup> </ItemGroup>

View file

@ -0,0 +1,32 @@
using System.Globalization;
namespace Boyfriend.Data;
public class GuildConfiguration {
private static readonly Dictionary<string, CultureInfo> CultureInfoCache = new() {
{ "en", new CultureInfo("en-US") },
{ "ru", new CultureInfo("ru-RU") },
{ "mctaylors-ru", new CultureInfo("tt-RU") }
};
public string Prefix { get; set; } = "!";
public string Language { get; set; } = "en";
public string? WelcomeMessage { get; set; }
public bool ReceiveStartupMessages { get; set; }
public bool RemoveRolesOnMute { get; set; }
public bool ReturnRolesOnRejoin { get; set; }
public bool AutoStartEvents { get; set; }
public ulong? PublicFeedbackChannel { get; set; }
public ulong? PrivateFeedbackChannel { get; set; }
public ulong? EventNotificationChannel { get; set; }
public ulong? StarterRole { get; set; }
public ulong? MuteRole { get; set; }
public ulong? EventNotificationRole { get; set; }
public List<NotificationReceiver> EventStartedReceivers { get; set; }
= new() { NotificationReceiver.Interested, NotificationReceiver.Role };
public TimeSpan EventEarlyNotificationOffset { get; set; } = TimeSpan.Zero;
public CultureInfo Culture => CultureInfoCache[Language];
}

11
Data/GuildData.cs Normal file
View file

@ -0,0 +1,11 @@
namespace Boyfriend.Data;
public class GuildData {
public readonly GuildConfiguration Configuration;
public readonly string ConfigurationPath;
public GuildData(GuildConfiguration configuration, string configurationPath) {
Configuration = configuration;
ConfigurationPath = configurationPath;
}
}

View file

@ -0,0 +1,6 @@
namespace Boyfriend.Data;
public enum NotificationReceiver {
Interested,
Role
}

View file

@ -0,0 +1,49 @@
using System.Text.Json;
using Microsoft.Extensions.Hosting;
using Remora.Rest.Core;
namespace Boyfriend.Data.Services;
public class GuildDataService : IHostedService {
private readonly Dictionary<Snowflake, GuildData> _datas = new();
public Task StartAsync(CancellationToken ct) {
return Task.CompletedTask;
}
public async Task StopAsync(CancellationToken ct) {
var tasks = new List<Task>();
foreach (var data in _datas.Values) {
await using var stream = File.OpenWrite(data.ConfigurationPath);
tasks.Add(JsonSerializer.SerializeAsync(stream, data.Configuration, cancellationToken: ct));
}
await Task.WhenAll(tasks);
}
private async Task<GuildData> GetData(Snowflake guildId, CancellationToken ct = default) {
return _datas.TryGetValue(guildId, out var data) ? data : await InitializeData(guildId, ct);
}
private async Task<GuildData> InitializeData(Snowflake guildId, CancellationToken ct = default) {
var idString = $"{guildId}";
var memberDataDir = $"{guildId}/MemberData";
var configurationPath = $"{guildId}/Configuration.json";
if (!Directory.Exists(idString)) Directory.CreateDirectory(idString);
if (!Directory.Exists(memberDataDir)) Directory.CreateDirectory(memberDataDir);
if (!File.Exists(configurationPath)) await File.WriteAllTextAsync(configurationPath, "{}", ct);
await using var stream = File.OpenRead(configurationPath);
var configuration
= JsonSerializer.DeserializeAsync<GuildConfiguration>(
stream, cancellationToken: ct);
var data = new GuildData(await configuration ?? new GuildConfiguration(), configurationPath);
_datas.Add(guildId, data);
return data;
}
public async Task<GuildConfiguration> GetConfiguration(Snowflake guildId, CancellationToken ct = default) {
return (await GetData(guildId, ct)).Configuration;
}
}

View file

@ -1,4 +1,5 @@
using System.Drawing; using System.Drawing;
using Boyfriend.Data.Services;
using DiffPlex; using DiffPlex;
using DiffPlex.DiffBuilder; using DiffPlex.DiffBuilder;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -21,29 +22,35 @@ namespace Boyfriend;
public class GuildCreateResponder : IResponder<IGuildCreate> { public class GuildCreateResponder : IResponder<IGuildCreate> {
private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
private readonly ILogger<GuildCreateResponder> _logger;
private readonly IDiscordRestUserAPI _userApi; private readonly IDiscordRestUserAPI _userApi;
public GuildCreateResponder(IDiscordRestChannelAPI channelApi, IDiscordRestUserAPI userApi) { public GuildCreateResponder(
IDiscordRestChannelAPI channelApi, GuildDataService dataService, IDiscordRestUserAPI userApi,
ILogger<GuildCreateResponder> logger) {
_channelApi = channelApi; _channelApi = channelApi;
_dataService = dataService;
_userApi = userApi; _userApi = userApi;
_logger = logger;
} }
public async Task<Result> RespondAsync(IGuildCreate gatewayEvent, CancellationToken ct = default) { public async Task<Result> RespondAsync(IGuildCreate gatewayEvent, CancellationToken ct = default) {
if (!gatewayEvent.Guild.IsT0) return Result.FromSuccess(); // is IAvailableGuild if (!gatewayEvent.Guild.IsT0) return Result.FromSuccess(); // is IAvailableGuild
var guild = gatewayEvent.Guild.AsT0; var guild = gatewayEvent.Guild.AsT0;
Boyfriend.Logger.LogInformation("Joined guild \"{Name}\"", guild.Name); _logger.LogInformation("Joined guild \"{Name}\"", guild.Name);
var channelResult = guild.ID.GetConfigChannel("PrivateFeedbackChannel"); var guildConfig = await _dataService.GetConfiguration(guild.ID, ct);
if (!channelResult.IsDefined(out var channel)) return Result.FromSuccess(); if (!guildConfig.ReceiveStartupMessages)
return Result.FromSuccess();
if (guildConfig.PrivateFeedbackChannel is null)
return Result.FromSuccess();
var currentUserResult = await _userApi.GetCurrentUserAsync(ct); var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
if (!currentUserResult.IsDefined(out var currentUser)) return Result.FromError(currentUserResult); if (!currentUserResult.IsDefined(out var currentUser)) return Result.FromError(currentUserResult);
if (!guild.GetConfigBool("ReceiveStartupMessages").IsDefined(out var shouldSendStartupMessage) Messages.Culture = guildConfig.Culture;
|| !shouldSendStartupMessage) return Result.FromSuccess();
Messages.Culture = guild.ID.GetGuildCulture();
var i = Random.Shared.Next(1, 4); var i = Random.Shared.Next(1, 4);
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
@ -56,7 +63,7 @@ public class GuildCreateResponder : IResponder<IGuildCreate> {
if (!embed.IsDefined(out var built)) return Result.FromError(embed); if (!embed.IsDefined(out var built)) return Result.FromError(embed);
return (Result)await _channelApi.CreateMessageAsync( return (Result)await _channelApi.CreateMessageAsync(
channel, embeds: new[] { built }, ct: ct); guildConfig.PrivateFeedbackChannel.ToDiscordSnowflake(), embeds: new[] { built }, ct: ct);
} }
} }
@ -64,22 +71,24 @@ public class MessageDeletedResponder : IResponder<IMessageDelete> {
private readonly IDiscordRestAuditLogAPI _auditLogApi; private readonly IDiscordRestAuditLogAPI _auditLogApi;
private readonly CacheService _cacheService; private readonly CacheService _cacheService;
private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
private readonly IDiscordRestUserAPI _userApi; private readonly IDiscordRestUserAPI _userApi;
public MessageDeletedResponder( public MessageDeletedResponder(
IDiscordRestAuditLogAPI auditLogApi, CacheService cacheService, IDiscordRestChannelAPI channelApi, IDiscordRestAuditLogAPI auditLogApi, CacheService cacheService, IDiscordRestChannelAPI channelApi,
IDiscordRestUserAPI userApi) { GuildDataService dataService, IDiscordRestUserAPI userApi) {
_auditLogApi = auditLogApi; _auditLogApi = auditLogApi;
_cacheService = cacheService; _cacheService = cacheService;
_channelApi = channelApi; _channelApi = channelApi;
_dataService = dataService;
_userApi = userApi; _userApi = userApi;
} }
public async Task<Result> RespondAsync(IMessageDelete gatewayEvent, CancellationToken ct = default) { public async Task<Result> RespondAsync(IMessageDelete gatewayEvent, CancellationToken ct = default) {
if (!gatewayEvent.GuildID.IsDefined(out var guildId)) return Result.FromSuccess(); if (!gatewayEvent.GuildID.IsDefined(out var guildId)) return Result.FromSuccess();
var channelResult = guildId.GetConfigChannel("PrivateFeedbackChannel"); var guildConfiguration = await _dataService.GetConfiguration(guildId, ct);
if (!channelResult.IsDefined(out var logChannel)) return Result.FromSuccess(); if (guildConfiguration.PrivateFeedbackChannel is null) return Result.FromSuccess();
var messageResult = await _cacheService.TryGetValueAsync<IMessage>( var messageResult = await _cacheService.TryGetValueAsync<IMessage>(
new KeyHelpers.MessageCacheKey(gatewayEvent.ChannelID, gatewayEvent.ID), ct); new KeyHelpers.MessageCacheKey(gatewayEvent.ChannelID, gatewayEvent.ID), ct);
@ -101,7 +110,7 @@ public class MessageDeletedResponder : IResponder<IMessageDelete> {
if (!userResult.IsDefined(out user)) return Result.FromError(userResult); if (!userResult.IsDefined(out user)) return Result.FromError(userResult);
} }
Messages.Culture = guildId.GetGuildCulture(); Messages.Culture = guildConfiguration.Culture;
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithSmallTitle( .WithSmallTitle(
@ -118,22 +127,29 @@ public class MessageDeletedResponder : IResponder<IMessageDelete> {
if (!embed.IsDefined(out var built)) return Result.FromError(embed); if (!embed.IsDefined(out var built)) return Result.FromError(embed);
return (Result)await _channelApi.CreateMessageAsync( return (Result)await _channelApi.CreateMessageAsync(
logChannel, embeds: new[] { built }, allowedMentions: Boyfriend.NoMentions, ct: ct); guildConfiguration.PrivateFeedbackChannel.ToDiscordSnowflake(), embeds: new[] { built },
allowedMentions: Boyfriend.NoMentions, ct: ct);
} }
} }
public class MessageEditedResponder : IResponder<IMessageUpdate> { public class MessageEditedResponder : IResponder<IMessageUpdate> {
private readonly CacheService _cacheService; private readonly CacheService _cacheService;
private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
public MessageEditedResponder(CacheService cacheService, IDiscordRestChannelAPI channelApi) { public MessageEditedResponder(
CacheService cacheService, IDiscordRestChannelAPI channelApi, GuildDataService dataService) {
_cacheService = cacheService; _cacheService = cacheService;
_channelApi = channelApi; _channelApi = channelApi;
_dataService = dataService;
} }
public async Task<Result> RespondAsync(IMessageUpdate gatewayEvent, CancellationToken ct = default) { public async Task<Result> RespondAsync(IMessageUpdate gatewayEvent, CancellationToken ct = default) {
if (!gatewayEvent.GuildID.IsDefined(out var guildId)) if (!gatewayEvent.GuildID.IsDefined(out var guildId))
return Result.FromSuccess(); return Result.FromSuccess();
var guildConfiguration = await _dataService.GetConfiguration(guildId, ct);
if (guildConfiguration.PrivateFeedbackChannel is null)
return Result.FromSuccess();
if (!gatewayEvent.Content.IsDefined(out var newContent)) if (!gatewayEvent.Content.IsDefined(out var newContent))
return Result.FromSuccess(); return Result.FromSuccess();
@ -148,18 +164,12 @@ public class MessageEditedResponder : IResponder<IMessageUpdate> {
var messageResult = await _cacheService.TryGetValueAsync<IMessage>( var messageResult = await _cacheService.TryGetValueAsync<IMessage>(
cacheKey, ct); cacheKey, ct);
if (!messageResult.IsDefined(out var message)) return Result.FromError(messageResult); if (!messageResult.IsDefined(out var message)) return Result.FromError(messageResult);
if (string.IsNullOrWhiteSpace(message.Content) if (message.Content == newContent) return Result.FromSuccess();
|| string.IsNullOrWhiteSpace(newContent)
|| message.Content == newContent) return Result.FromSuccess();
await _cacheService.EvictAsync<IMessage>(cacheKey, ct); await _cacheService.EvictAsync<IMessage>(cacheKey, ct);
var newMessageResult = await _channelApi.GetChannelMessageAsync(channelId, messageId, ct); var newMessageResult = await _channelApi.GetChannelMessageAsync(channelId, messageId, ct);
if (!newMessageResult.IsDefined(out var newMessage)) return Result.FromError(newMessageResult); if (!newMessageResult.IsDefined(out var newMessage)) return Result.FromError(newMessageResult);
// No need to await the recache since we don't depend on it await _cacheService.CacheAsync(cacheKey, newMessage, ct);
_ = _cacheService.CacheAsync(cacheKey, newMessage, ct);
var logChannelResult = guildId.GetConfigChannel("PrivateFeedbackChannel");
if (!logChannelResult.IsDefined(out var logChannel)) return Result.FromSuccess();
var currentUserResult = await _cacheService.TryGetValueAsync<IUser>( var currentUserResult = await _cacheService.TryGetValueAsync<IUser>(
new KeyHelpers.CurrentUserCacheKey(), ct); new KeyHelpers.CurrentUserCacheKey(), ct);
@ -167,7 +177,7 @@ public class MessageEditedResponder : IResponder<IMessageUpdate> {
var diff = new SideBySideDiffBuilder(Differ.Instance).BuildDiffModel(message.Content, newContent, true, true); var diff = new SideBySideDiffBuilder(Differ.Instance).BuildDiffModel(message.Content, newContent, true, true);
Messages.Culture = guildId.GetGuildCulture(); Messages.Culture = guildConfiguration.Culture;
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithSmallTitle( .WithSmallTitle(
@ -181,30 +191,35 @@ public class MessageEditedResponder : IResponder<IMessageUpdate> {
if (!embed.IsDefined(out var built)) return Result.FromError(embed); if (!embed.IsDefined(out var built)) return Result.FromError(embed);
return (Result)await _channelApi.CreateMessageAsync( return (Result)await _channelApi.CreateMessageAsync(
logChannel, embeds: new[] { built }, allowedMentions: Boyfriend.NoMentions, ct: ct); guildConfiguration.PrivateFeedbackChannel.ToDiscordSnowflake(), embeds: new[] { built },
allowedMentions: Boyfriend.NoMentions, ct: ct);
} }
} }
public class GuildMemberAddResponder : IResponder<IGuildMemberAdd> { public class GuildMemberAddResponder : IResponder<IGuildMemberAdd> {
private readonly CacheService _cacheService; private readonly CacheService _cacheService;
private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
public GuildMemberAddResponder(CacheService cacheService, IDiscordRestChannelAPI channelApi) { public GuildMemberAddResponder(
CacheService cacheService, IDiscordRestChannelAPI channelApi, GuildDataService dataService) {
_cacheService = cacheService; _cacheService = cacheService;
_channelApi = channelApi; _channelApi = channelApi;
_dataService = dataService;
} }
public async Task<Result> RespondAsync(IGuildMemberAdd gatewayEvent, CancellationToken ct = default) { public async Task<Result> RespondAsync(IGuildMemberAdd gatewayEvent, CancellationToken ct = default) {
if (!gatewayEvent.GuildID.GetConfigString("WelcomeMessage").IsDefined(out var welcomeMessage) var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct);
|| welcomeMessage is "off" or "disable" or "disabled") if (guildConfiguration.PublicFeedbackChannel is null)
return Result.FromSuccess();
if (guildConfiguration.WelcomeMessage is null or "off" or "disable" or "disabled")
return Result.FromSuccess(); return Result.FromSuccess();
if (welcomeMessage is "default" or "reset") {
Messages.Culture = gatewayEvent.GuildID.GetGuildCulture();
welcomeMessage = Messages.DefaultWelcomeMessage;
}
if (!gatewayEvent.GuildID.GetConfigChannel("PublicFeedbackChannel").IsDefined(out var channel)) Messages.Culture = guildConfiguration.Culture;
return Result.FromSuccess(); var welcomeMessage = guildConfiguration.WelcomeMessage is "default" or "reset"
? Messages.DefaultWelcomeMessage
: guildConfiguration.WelcomeMessage;
if (!gatewayEvent.User.IsDefined(out var user)) if (!gatewayEvent.User.IsDefined(out var user))
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.User))); return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.User)));
@ -221,25 +236,30 @@ public class GuildMemberAddResponder : IResponder<IGuildMemberAdd> {
if (!embed.IsDefined(out var built)) return Result.FromError(embed); if (!embed.IsDefined(out var built)) return Result.FromError(embed);
return (Result)await _channelApi.CreateMessageAsync( return (Result)await _channelApi.CreateMessageAsync(
channel, embeds: new[] { built }, allowedMentions: Boyfriend.NoMentions, ct: ct); guildConfiguration.PublicFeedbackChannel.ToDiscordSnowflake(), embeds: new[] { built },
allowedMentions: Boyfriend.NoMentions, ct: ct);
} }
} }
public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEventCreate> { public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEventCreate> {
private readonly CacheService _cacheService; private readonly CacheService _cacheService;
private readonly IDiscordRestChannelAPI _channelApi; private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
private readonly IDiscordRestUserAPI _userApi; private readonly IDiscordRestUserAPI _userApi;
public GuildScheduledEventCreateResponder( public GuildScheduledEventCreateResponder(
CacheService cacheService, IDiscordRestChannelAPI channelApi, IDiscordRestUserAPI userApi) { CacheService cacheService, IDiscordRestChannelAPI channelApi, GuildDataService dataService,
IDiscordRestUserAPI userApi) {
_cacheService = cacheService; _cacheService = cacheService;
_channelApi = channelApi; _channelApi = channelApi;
_dataService = dataService;
_userApi = userApi; _userApi = userApi;
} }
public async Task<Result> RespondAsync(IGuildScheduledEventCreate gatewayEvent, CancellationToken ct = default) { public async Task<Result> RespondAsync(IGuildScheduledEventCreate gatewayEvent, CancellationToken ct = default) {
var channelResult = gatewayEvent.GuildID.GetConfigChannel("EventNotificationChannel"); var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct);
if (!channelResult.IsDefined(out var channel)) return Result.FromSuccess(); if (guildConfiguration.EventNotificationChannel is null)
return Result.FromSuccess();
var currentUserResult = await _cacheService.TryGetValueAsync<IUser>( var currentUserResult = await _cacheService.TryGetValueAsync<IUser>(
new KeyHelpers.CurrentUserCacheKey(), ct); new KeyHelpers.CurrentUserCacheKey(), ct);
@ -250,7 +270,7 @@ public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEven
var creatorResult = await creatorId.Value.TryGetUserAsync(_cacheService, _userApi, ct); var creatorResult = await creatorId.Value.TryGetUserAsync(_cacheService, _userApi, ct);
if (!creatorResult.IsDefined(out var creator)) return Result.FromError(creatorResult); if (!creatorResult.IsDefined(out var creator)) return Result.FromError(creatorResult);
Messages.Culture = gatewayEvent.GuildID.GetGuildCulture(); Messages.Culture = guildConfiguration.Culture;
string embedDescription; string embedDescription;
var eventDescription = gatewayEvent.Description is { HasValue: true, Value: not null } var eventDescription = gatewayEvent.Description is { HasValue: true, Value: not null }
@ -308,6 +328,7 @@ public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEven
); );
return (Result)await _channelApi.CreateMessageAsync( return (Result)await _channelApi.CreateMessageAsync(
channel, embeds: new[] { built }, components: new[] { new ActionRowComponent(new[] { button }) }, ct: ct); guildConfiguration.EventNotificationChannel.ToDiscordSnowflake(), embeds: new[] { built },
components: new[] { new ActionRowComponent(new[] { button }) }, ct: ct);
} }
} }

View file

@ -1,7 +1,5 @@
using System.Globalization;
using System.Text; using System.Text;
using DiffPlex.DiffBuilder.Model; using DiffPlex.DiffBuilder.Model;
using Microsoft.Extensions.Configuration;
using Remora.Discord.API; using Remora.Discord.API;
using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Objects;
using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.API.Abstractions.Rest;
@ -16,34 +14,6 @@ using Remora.Results;
namespace Boyfriend; namespace Boyfriend;
public static class Extensions { public static class Extensions {
private static readonly Dictionary<string, CultureInfo> CultureInfoCache = new() {
{ "en", new CultureInfo("en-US") },
{ "ru", new CultureInfo("ru-RU") },
{ "mctaylors-ru", new CultureInfo("tt-RU") }
};
public static Result<bool> GetConfigBool(this IGuild guild, string key) {
var value = Boyfriend.GuildConfiguration.GetValue<bool?>($"GuildConfigs:{guild.ID}:{key}");
return value is not null ? Result<bool>.FromSuccess(value.Value) : Result<bool>.FromError(new NotFoundError());
}
public static Result<Snowflake> GetConfigChannel(this Snowflake guildId, string key) {
var value = Boyfriend.GuildConfiguration.GetValue<ulong?>($"GuildConfigs:{guildId}:{key}");
return value is not null
? Result<Snowflake>.FromSuccess(DiscordSnowflake.New(value.Value))
: Result<Snowflake>.FromError(new NotFoundError());
}
public static Result<string> GetConfigString(this Snowflake guildId, string key) {
var value = Boyfriend.GuildConfiguration.GetValue<string?>($"GuildConfigs:{guildId}:{key}");
return value is not null ? Result<string>.FromSuccess(value) : Result<string>.FromError(new NotFoundError());
}
public static CultureInfo GetGuildCulture(this Snowflake guildId) {
var value = Boyfriend.GuildConfiguration.GetValue<string?>($"GuildConfigs:{guildId}:Language");
return value is not null ? CultureInfoCache[value] : CultureInfoCache["en"];
}
public static async Task<Result<IUser>> TryGetUserAsync( public static async Task<Result<IUser>> TryGetUserAsync(
this Snowflake userId, CacheService cacheService, IDiscordRestUserAPI userApi, CancellationToken ct) { this Snowflake userId, CacheService cacheService, IDiscordRestUserAPI userApi, CancellationToken ct) {
var cachedUserResult = await cacheService.TryGetValueAsync<IUser>( var cachedUserResult = await cacheService.TryGetValueAsync<IUser>(
@ -118,4 +88,8 @@ public static class Extensions {
public static string GetTag(this IUser user) { public static string GetTag(this IUser user) {
return $"{user.Username}#{user.Discriminator:0000}"; return $"{user.Username}#{user.Discriminator:0000}";
} }
public static Snowflake ToDiscordSnowflake(this ulong? id) {
return DiscordSnowflake.New(id ?? 0);
}
} }

35
Messages.Designer.cs generated
View file

@ -7,36 +7,41 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Resources;
using System.Runtime.CompilerServices;
namespace Boyfriend { namespace Boyfriend {
using System; [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[DebuggerNonUserCode()]
[CompilerGenerated()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Messages { internal class Messages {
private static System.Resources.ResourceManager resourceMan; private static ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture; private static CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Messages() { internal Messages() {
} }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager { internal static ResourceManager ResourceManager {
get { get {
if (object.Equals(null, resourceMan)) { if (Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Boyfriend.Messages", typeof(Messages).Assembly); ResourceManager temp = new ResourceManager("Boyfriend.Messages", typeof(Messages).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;
} }
} }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture { internal static CultureInfo Culture {
get { get {
return resourceCulture; return resourceCulture;
} }