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

Add responders for scheduled event cancellation and completion

Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
Octol1ttle 2023-05-31 18:11:24 +05:00
parent b89e557e48
commit 4b8c3fd11c
Signed by: Octol1ttle
GPG key ID: B77C34313AEE1FFF
7 changed files with 842 additions and 1147 deletions

View file

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

View file

@ -44,7 +44,7 @@ public class GuildCreateResponder : IResponder<IGuildCreate> {
var guildConfig = await _dataService.GetConfiguration(guild.ID, ct); var guildConfig = await _dataService.GetConfiguration(guild.ID, ct);
if (!guildConfig.ReceiveStartupMessages) if (!guildConfig.ReceiveStartupMessages)
return Result.FromSuccess(); return Result.FromSuccess();
if (guildConfig.PrivateFeedbackChannel is null) if (guildConfig.PrivateFeedbackChannel is 0)
return Result.FromSuccess(); return Result.FromSuccess();
var currentUserResult = await _userApi.GetCurrentUserAsync(ct); var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
@ -86,7 +86,7 @@ public class MessageDeletedResponder : IResponder<IMessageDelete> {
if (!gatewayEvent.GuildID.IsDefined(out var guildId)) return Result.FromSuccess(); if (!gatewayEvent.GuildID.IsDefined(out var guildId)) return Result.FromSuccess();
var guildConfiguration = await _dataService.GetConfiguration(guildId, ct); var guildConfiguration = await _dataService.GetConfiguration(guildId, ct);
if (guildConfiguration.PrivateFeedbackChannel is null) return Result.FromSuccess(); if (guildConfiguration.PrivateFeedbackChannel is 0) return Result.FromSuccess();
var messageResult = await _channelApi.GetChannelMessageAsync(gatewayEvent.ChannelID, gatewayEvent.ID, ct); var messageResult = await _channelApi.GetChannelMessageAsync(gatewayEvent.ChannelID, gatewayEvent.ID, ct);
if (!messageResult.IsDefined(out var message)) return Result.FromError(messageResult); if (!messageResult.IsDefined(out var message)) return Result.FromError(messageResult);
@ -111,10 +111,9 @@ public class MessageDeletedResponder : IResponder<IMessageDelete> {
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithSmallTitle( .WithSmallTitle(
message.Author,
string.Format( string.Format(
Messages.CachedMessageDeleted, Messages.CachedMessageDeleted,
message.Author.GetTag())) message.Author.GetTag()), message.Author)
.WithDescription( .WithDescription(
$"{Mention.Channel(gatewayEvent.ChannelID)}\n{Markdown.BlockCode(message.Content.SanitizeForBlockCode())}") $"{Mention.Channel(gatewayEvent.ChannelID)}\n{Markdown.BlockCode(message.Content.SanitizeForBlockCode())}")
.WithActionFooter(user) .WithActionFooter(user)
@ -148,7 +147,7 @@ public class MessageEditedResponder : IResponder<IMessageUpdate> {
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); var guildConfiguration = await _dataService.GetConfiguration(guildId, ct);
if (guildConfiguration.PrivateFeedbackChannel is null) if (guildConfiguration.PrivateFeedbackChannel is 0)
return Result.FromSuccess(); return Result.FromSuccess();
if (!gatewayEvent.Content.IsDefined(out var newContent)) if (!gatewayEvent.Content.IsDefined(out var newContent))
return Result.FromSuccess(); return Result.FromSuccess();
@ -185,9 +184,7 @@ public class MessageEditedResponder : IResponder<IMessageUpdate> {
Messages.Culture = guildConfiguration.Culture; Messages.Culture = guildConfiguration.Culture;
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithSmallTitle( .WithSmallTitle(string.Format(Messages.CachedMessageEdited, message.Author.GetTag()), message.Author)
message.Author,
string.Format(Messages.CachedMessageEdited, message.Author.GetTag()))
.WithDescription($"https://discord.com/channels/{guildId}/{channelId}/{messageId}\n{diff.AsMarkdown()}") .WithDescription($"https://discord.com/channels/{guildId}/{channelId}/{messageId}\n{diff.AsMarkdown()}")
.WithUserFooter(currentUser) .WithUserFooter(currentUser)
.WithTimestamp(timestamp.Value) .WithTimestamp(timestamp.Value)
@ -215,9 +212,9 @@ public class GuildMemberAddResponder : IResponder<IGuildMemberAdd> {
public async Task<Result> RespondAsync(IGuildMemberAdd gatewayEvent, CancellationToken ct = default) { public async Task<Result> RespondAsync(IGuildMemberAdd gatewayEvent, CancellationToken ct = default) {
var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct); var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct);
if (guildConfiguration.PublicFeedbackChannel is null) if (guildConfiguration.PublicFeedbackChannel is 0)
return Result.FromSuccess(); return Result.FromSuccess();
if (guildConfiguration.WelcomeMessage is null or "off" or "disable" or "disabled") if (guildConfiguration.WelcomeMessage is "off" or "disable" or "disabled")
return Result.FromSuccess(); return Result.FromSuccess();
Messages.Culture = guildConfiguration.Culture; Messages.Culture = guildConfiguration.Culture;
@ -232,7 +229,7 @@ public class GuildMemberAddResponder : IResponder<IGuildMemberAdd> {
if (!guildResult.IsDefined(out var guild)) return Result.FromError(guildResult); if (!guildResult.IsDefined(out var guild)) return Result.FromError(guildResult);
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithSmallTitle(user, string.Format(welcomeMessage, user.GetTag(), guild.Name)) .WithSmallTitle(string.Format(welcomeMessage, user.GetTag(), guild.Name), user)
.WithGuildFooter(guild) .WithGuildFooter(guild)
.WithTimestamp(gatewayEvent.JoinedAt) .WithTimestamp(gatewayEvent.JoinedAt)
.WithColour(Color.LawnGreen) .WithColour(Color.LawnGreen)
@ -260,7 +257,7 @@ public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEven
public async Task<Result> RespondAsync(IGuildScheduledEventCreate gatewayEvent, CancellationToken ct = default) { public async Task<Result> RespondAsync(IGuildScheduledEventCreate gatewayEvent, CancellationToken ct = default) {
var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct); var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct);
if (guildConfiguration.EventNotificationChannel is null) if (guildConfiguration.EventNotificationChannel is 0)
return Result.FromSuccess(); return Result.FromSuccess();
var currentUserResult = await _userApi.GetCurrentUserAsync(ct); var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
@ -310,7 +307,7 @@ public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEven
} }
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithSmallTitle(creator, string.Format(Messages.EventCreatedTitle, creator.GetTag())) .WithSmallTitle(string.Format(Messages.EventCreatedTitle, creator.GetTag()), creator)
.WithTitle(gatewayEvent.Name) .WithTitle(gatewayEvent.Name)
.WithDescription(embedDescription) .WithDescription(embedDescription)
.WithEventCover(gatewayEvent.ID, gatewayEvent.Image) .WithEventCover(gatewayEvent.ID, gatewayEvent.Image)
@ -337,3 +334,63 @@ public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEven
components: new[] { new ActionRowComponent(new[] { button }) }, ct: ct); components: new[] { new ActionRowComponent(new[] { button }) }, ct: ct);
} }
} }
public class GuildScheduledEventUpdateResponder : IResponder<IGuildScheduledEventUpdate> {
private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
public GuildScheduledEventUpdateResponder(IDiscordRestChannelAPI channelApi, GuildDataService dataService) {
_channelApi = channelApi;
_dataService = dataService;
}
public async Task<Result> RespondAsync(IGuildScheduledEventUpdate gatewayEvent, CancellationToken ct = default) {
if (gatewayEvent.Status is not GuildScheduledEventStatus.Completed) return Result.FromSuccess();
var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct);
if (guildConfiguration.EventNotificationChannel is 0)
return Result.FromSuccess();
var embed = new EmbedBuilder().WithTitle(string.Format(Messages.EventCompleted, gatewayEvent.Name))
.WithDescription(
string.Format(
Messages.EventDuration,
DateTimeOffset.UtcNow.Subtract(gatewayEvent.ScheduledStartTime)))
.WithColour(Color.Black)
.WithCurrentTimestamp()
.Build();
if (!embed.IsDefined(out var built)) return Result.FromError(embed);
return (Result)await _channelApi.CreateMessageAsync(
guildConfiguration.EventNotificationChannel.ToDiscordSnowflake(), embeds: new[] { built }, ct: ct);
}
}
public class GuildScheduledEventResponder : IResponder<IGuildScheduledEventDelete> {
private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
public GuildScheduledEventResponder(IDiscordRestChannelAPI channelApi, GuildDataService dataService) {
_channelApi = channelApi;
_dataService = dataService;
}
public async Task<Result> RespondAsync(IGuildScheduledEventDelete gatewayEvent, CancellationToken ct = default) {
var guildConfiguration = await _dataService.GetConfiguration(gatewayEvent.GuildID, ct);
if (guildConfiguration.EventNotificationChannel is 0)
return Result.FromSuccess();
var embed = new EmbedBuilder()
.WithSmallTitle(string.Format(Messages.EventCancelled, gatewayEvent.Name))
.WithDescription(":(")
.WithColour(Color.DarkRed)
.WithCurrentTimestamp()
.Build();
if (!embed.IsDefined(out var built)) return Result.FromError(embed);
return (Result)await _channelApi.CreateMessageAsync(
guildConfiguration.EventNotificationChannel.ToDiscordSnowflake(), embeds: new[] { built }, ct: ct);
}
}

View file

@ -30,14 +30,17 @@ public static class Extensions {
} }
public static EmbedBuilder WithSmallTitle( public static EmbedBuilder WithSmallTitle(
this EmbedBuilder builder, IUser avatarSource, string text, string? url = default) { this EmbedBuilder builder, string text, IUser? avatarSource = null, string? url = default) {
Uri? avatarUrl = null;
if (avatarSource is not null) {
var avatarUrlResult = CDN.GetUserAvatarUrl(avatarSource, imageSize: 256); var avatarUrlResult = CDN.GetUserAvatarUrl(avatarSource, imageSize: 256);
var avatarUrl = avatarUrlResult.IsSuccess avatarUrl = avatarUrlResult.IsSuccess
? avatarUrlResult.Entity ? avatarUrlResult.Entity
: CDN.GetDefaultUserAvatarUrl(avatarSource, imageSize: 256).Entity; : CDN.GetDefaultUserAvatarUrl(avatarSource, imageSize: 256).Entity;
}
builder.Author = new EmbedAuthorBuilder(text, url, avatarUrl.AbsoluteUri); builder.Author = new EmbedAuthorBuilder(text, url, avatarUrl?.AbsoluteUri);
return builder; return builder;
} }
@ -75,7 +78,13 @@ public static class Extensions {
return $"{user.Username}#{user.Discriminator:0000}"; return $"{user.Username}#{user.Discriminator:0000}";
} }
public static Snowflake ToDiscordSnowflake(this ulong? id) { public static Snowflake ToDiscordSnowflake(this ulong id) {
return DiscordSnowflake.New(id ?? 0); return DiscordSnowflake.New(id);
} }
/*public static string AsDuration(this TimeSpan span) {
return span.Humanize(
2, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Month,
culture: Messages.Culture.Name.Contains("RU") ? GuildConfiguration.CultureInfoCache["ru"] : Messages.Culture);
}*/
} }

1796
Messages.Designer.cs generated

File diff suppressed because it is too large Load diff

View file

@ -247,10 +247,10 @@
<value>:(</value> <value>:(</value>
</data> </data>
<data name="EventCancelled" xml:space="preserve"> <data name="EventCancelled" xml:space="preserve">
<value>Event {0} is cancelled!{1}</value> <value>Event "{0}" is cancelled!</value>
</data> </data>
<data name="EventCompleted" xml:space="preserve"> <data name="EventCompleted" xml:space="preserve">
<value>Event {0} has completed! Duration:{1}</value> <value>Event "{0}" has completed!</value>
</data> </data>
<data name="Ever" xml:space="preserve"> <data name="Ever" xml:space="preserve">
<value>ever</value> <value>ever</value>
@ -477,4 +477,7 @@
<data name="EventDetailsButton" xml:space="preserve"> <data name="EventDetailsButton" xml:space="preserve">
<value>Event details</value> <value>Event details</value>
</data> </data>
<data name="EventDuration" xml:space="preserve">
<value>The event has lasted for `{0}`</value>
</data>
</root> </root>

View file

@ -247,10 +247,10 @@
<value>:( </value> <value>:( </value>
</data> </data>
<data name="EventCancelled" xml:space="preserve"> <data name="EventCancelled" xml:space="preserve">
<value>Событие {0} отменено!{1}</value> <value>Событие "{0}" отменено!</value>
</data> </data>
<data name="EventCompleted" xml:space="preserve"> <data name="EventCompleted" xml:space="preserve">
<value>Событие {0} завершено! Продолжительность:{1}</value> <value>Событие "{0}" завершено!</value>
</data> </data>
<data name="Ever" xml:space="preserve"> <data name="Ever" xml:space="preserve">
<value>всегда</value> <value>всегда</value>
@ -477,4 +477,7 @@
<data name="EventDetailsButton" xml:space="preserve"> <data name="EventDetailsButton" xml:space="preserve">
<value>Подробнее о событии</value> <value>Подробнее о событии</value>
</data> </data>
<data name="EventDuration" xml:space="preserve">
<value>Событие длилось `{0}`</value>
</data>
</root> </root>

View file

@ -247,10 +247,10 @@
<value>оъмъомоъемъъео((((</value> <value>оъмъомоъемъъео((((</value>
</data> </data>
<data name="EventCancelled" xml:space="preserve"> <data name="EventCancelled" xml:space="preserve">
<value>движуха {0} отменен!{1}</value> <value>движуха "{0}" отменен!</value>
</data> </data>
<data name="EventCompleted" xml:space="preserve"> <data name="EventCompleted" xml:space="preserve">
<value>движуха {0} завершен! все это длилось{1}</value> <value>движуха "{0}" завершен!</value>
</data> </data>
<data name="Ever" xml:space="preserve"> <data name="Ever" xml:space="preserve">
<value>всегда</value> <value>всегда</value>
@ -477,4 +477,7 @@
<data name="EventDetailsButton" xml:space="preserve"> <data name="EventDetailsButton" xml:space="preserve">
<value>побольше о движухе</value> <value>побольше о движухе</value>
</data> </data>
<data name="EventDuration" xml:space="preserve">
<value>все это длилось `{0}`</value>
</data>
</root> </root>