mirror of
https://github.com/TeamOctolings/Octobot.git
synced 2025-05-05 21:46:28 +03:00
Move scheduled events to guild tick loop
Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
parent
59ca76ba6b
commit
3cd2b672a1
5 changed files with 270 additions and 235 deletions
|
@ -1,4 +1,3 @@
|
|||
using System.Text;
|
||||
using Boyfriend.Data;
|
||||
using Boyfriend.Services.Data;
|
||||
using DiffPlex;
|
||||
|
@ -7,14 +6,11 @@ using Microsoft.Extensions.Logging;
|
|||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
using Remora.Discord.API.Objects;
|
||||
using Remora.Discord.Caching;
|
||||
using Remora.Discord.Caching.Services;
|
||||
using Remora.Discord.Extensions.Embeds;
|
||||
using Remora.Discord.Extensions.Formatting;
|
||||
using Remora.Discord.Gateway.Responders;
|
||||
using Remora.Discord.Interactivity;
|
||||
using Remora.Rest.Core;
|
||||
using Remora.Results;
|
||||
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
@ -259,223 +255,6 @@ public class GuildMemberAddResponder : IResponder<IGuildMemberAdd> {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles sending a notification, mentioning the <see cref="GuildConfiguration.EventNotificationRole" /> if one is
|
||||
/// set,
|
||||
/// when a scheduled event is created
|
||||
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
|
||||
/// </summary>
|
||||
public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEventCreate> {
|
||||
private readonly IDiscordRestChannelAPI _channelApi;
|
||||
private readonly GuildDataService _dataService;
|
||||
private readonly IDiscordRestUserAPI _userApi;
|
||||
|
||||
public GuildScheduledEventCreateResponder(
|
||||
IDiscordRestChannelAPI channelApi, GuildDataService dataService,
|
||||
IDiscordRestUserAPI userApi) {
|
||||
_channelApi = channelApi;
|
||||
_dataService = dataService;
|
||||
_userApi = userApi;
|
||||
}
|
||||
|
||||
public async Task<Result> RespondAsync(IGuildScheduledEventCreate gatewayEvent, CancellationToken ct = default) {
|
||||
var guildData = await _dataService.GetData(gatewayEvent.GuildID, ct);
|
||||
guildData.ScheduledEvents.Add(
|
||||
gatewayEvent.ID.Value, new ScheduledEventData(GuildScheduledEventStatus.Scheduled));
|
||||
|
||||
if (guildData.Configuration.EventNotificationChannel is 0)
|
||||
return Result.FromSuccess();
|
||||
|
||||
var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
|
||||
if (!currentUserResult.IsDefined(out var currentUser)) return Result.FromError(currentUserResult);
|
||||
|
||||
if (!gatewayEvent.CreatorID.IsDefined(out var creatorId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.CreatorID)));
|
||||
var creatorResult = await _userApi.GetUserAsync(creatorId.Value, ct);
|
||||
if (!creatorResult.IsDefined(out var creator)) return Result.FromError(creatorResult);
|
||||
|
||||
Messages.Culture = guildData.Culture;
|
||||
|
||||
string embedDescription;
|
||||
var eventDescription = gatewayEvent.Description is { HasValue: true, Value: not null }
|
||||
? gatewayEvent.Description.Value
|
||||
: string.Empty;
|
||||
switch (gatewayEvent.EntityType) {
|
||||
case GuildScheduledEventEntityType.StageInstance or GuildScheduledEventEntityType.Voice:
|
||||
if (!gatewayEvent.ChannelID.AsOptional().IsDefined(out var channelId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ChannelID)));
|
||||
|
||||
embedDescription = $"{eventDescription}\n\n{Markdown.BlockQuote(
|
||||
string.Format(
|
||||
Messages.DescriptionLocalEventCreated,
|
||||
Markdown.Timestamp(gatewayEvent.ScheduledStartTime),
|
||||
Mention.Channel(channelId)
|
||||
))}";
|
||||
break;
|
||||
case GuildScheduledEventEntityType.External:
|
||||
if (!gatewayEvent.EntityMetadata.AsOptional().IsDefined(out var metadata))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.EntityMetadata)));
|
||||
if (!gatewayEvent.ScheduledEndTime.AsOptional().IsDefined(out var endTime))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ScheduledEndTime)));
|
||||
if (!metadata.Location.IsDefined(out var location))
|
||||
return Result.FromError(new ArgumentNullError(nameof(metadata.Location)));
|
||||
|
||||
embedDescription = $"{eventDescription}\n\n{Markdown.BlockQuote(
|
||||
string.Format(
|
||||
Messages.DescriptionExternalEventCreated,
|
||||
Markdown.Timestamp(gatewayEvent.ScheduledStartTime),
|
||||
Markdown.Timestamp(endTime),
|
||||
Markdown.InlineCode(location)
|
||||
))}";
|
||||
break;
|
||||
default:
|
||||
return Result.FromError(new ArgumentOutOfRangeError(nameof(gatewayEvent.EntityType)));
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithSmallTitle(string.Format(Messages.EventCreatedTitle, creator.GetTag()), creator)
|
||||
.WithTitle(gatewayEvent.Name)
|
||||
.WithDescription(embedDescription)
|
||||
.WithEventCover(gatewayEvent.ID, gatewayEvent.Image)
|
||||
.WithUserFooter(currentUser)
|
||||
.WithCurrentTimestamp()
|
||||
.WithColour(ColorsList.Default)
|
||||
.Build();
|
||||
if (!embed.IsDefined(out var built)) return Result.FromError(embed);
|
||||
|
||||
var roleMention = guildData.Configuration.EventNotificationRole is not 0
|
||||
? Mention.Role(guildData.Configuration.EventNotificationRole.ToDiscordSnowflake())
|
||||
: string.Empty;
|
||||
|
||||
var button = new ButtonComponent(
|
||||
ButtonComponentStyle.Primary,
|
||||
Messages.EventDetailsButton,
|
||||
new PartialEmoji(Name: "📋"),
|
||||
CustomIDHelpers.CreateButtonIDWithState(
|
||||
"scheduled-event-details", $"{gatewayEvent.GuildID}:{gatewayEvent.ID}")
|
||||
);
|
||||
|
||||
return (Result)await _channelApi.CreateMessageAsync(
|
||||
guildData.Configuration.EventNotificationChannel.ToDiscordSnowflake(), roleMention, embeds: new[] { built },
|
||||
components: new[] { new ActionRowComponent(new[] { button }) }, ct: ct);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles sending a notification, mentioning the <see cref="GuildConfiguration.EventNotificationRole" /> if one is
|
||||
/// set,
|
||||
/// when a scheduled event has started or completed
|
||||
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
|
||||
/// </summary>
|
||||
public class GuildScheduledEventUpdateResponder : IResponder<IGuildScheduledEventUpdate> {
|
||||
private readonly IDiscordRestChannelAPI _channelApi;
|
||||
private readonly GuildDataService _dataService;
|
||||
private readonly IDiscordRestGuildScheduledEventAPI _eventApi;
|
||||
|
||||
public GuildScheduledEventUpdateResponder(
|
||||
IDiscordRestChannelAPI channelApi, GuildDataService dataService, IDiscordRestGuildScheduledEventAPI eventApi) {
|
||||
_channelApi = channelApi;
|
||||
_dataService = dataService;
|
||||
_eventApi = eventApi;
|
||||
}
|
||||
|
||||
public async Task<Result> RespondAsync(IGuildScheduledEventUpdate gatewayEvent, CancellationToken ct = default) {
|
||||
var guildData = await _dataService.GetData(gatewayEvent.GuildID, ct);
|
||||
if (guildData.Configuration.EventNotificationChannel is 0)
|
||||
return Result.FromSuccess();
|
||||
if (!guildData.ScheduledEvents.TryGetValue(gatewayEvent.ID.Value, out var data)) {
|
||||
guildData.ScheduledEvents.Add(gatewayEvent.ID.Value, new ScheduledEventData(gatewayEvent.Status));
|
||||
} else {
|
||||
if (gatewayEvent.Status == data.Status)
|
||||
return Result.FromSuccess();
|
||||
|
||||
guildData.ScheduledEvents[gatewayEvent.ID.Value].Status = gatewayEvent.Status;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder();
|
||||
StringBuilder? content = null;
|
||||
switch (gatewayEvent.Status) {
|
||||
case GuildScheduledEventStatus.Active:
|
||||
guildData.ScheduledEvents[gatewayEvent.ID.Value].ActualStartTime = DateTimeOffset.UtcNow;
|
||||
|
||||
string embedDescription;
|
||||
switch (gatewayEvent.EntityType) {
|
||||
case GuildScheduledEventEntityType.StageInstance or GuildScheduledEventEntityType.Voice:
|
||||
if (!gatewayEvent.ChannelID.AsOptional().IsDefined(out var channelId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ChannelID)));
|
||||
|
||||
embedDescription = string.Format(
|
||||
Messages.DescriptionLocalEventStarted,
|
||||
Mention.Channel(channelId)
|
||||
);
|
||||
break;
|
||||
case GuildScheduledEventEntityType.External:
|
||||
if (!gatewayEvent.EntityMetadata.AsOptional().IsDefined(out var metadata))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.EntityMetadata)));
|
||||
if (!gatewayEvent.ScheduledEndTime.AsOptional().IsDefined(out var endTime))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ScheduledEndTime)));
|
||||
if (!metadata.Location.IsDefined(out var location))
|
||||
return Result.FromError(new ArgumentNullError(nameof(metadata.Location)));
|
||||
|
||||
embedDescription = string.Format(
|
||||
Messages.DescriptionExternalEventStarted,
|
||||
Markdown.InlineCode(location),
|
||||
Markdown.Timestamp(endTime)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return Result.FromError(new ArgumentOutOfRangeError(nameof(gatewayEvent.EntityType)));
|
||||
}
|
||||
|
||||
content = new StringBuilder();
|
||||
var receivers = guildData.Configuration.EventStartedReceivers;
|
||||
var role = guildData.Configuration.EventNotificationRole.ToDiscordSnowflake();
|
||||
var usersResult = await _eventApi.GetGuildScheduledEventUsersAsync(
|
||||
gatewayEvent.GuildID, gatewayEvent.ID, withMember: true, ct: ct);
|
||||
if (!usersResult.IsDefined(out var users)) return Result.FromError(usersResult);
|
||||
|
||||
if (receivers.Contains(GuildConfiguration.NotificationReceiver.Role) && role.Value is not 0)
|
||||
content.Append($"{Mention.Role(role)} ");
|
||||
if (receivers.Contains(GuildConfiguration.NotificationReceiver.Interested))
|
||||
content = users.Where(
|
||||
user => {
|
||||
if (!user.GuildMember.IsDefined(out var member)) return true;
|
||||
return !member.Roles.Contains(role);
|
||||
})
|
||||
.Aggregate(content, (current, user) => current.Append($"{Mention.User(user.User)} "));
|
||||
|
||||
embed.WithTitle(string.Format(Messages.EventStarted, gatewayEvent.Name))
|
||||
.WithDescription(embedDescription)
|
||||
.WithCurrentTimestamp()
|
||||
.WithColour(ColorsList.Green);
|
||||
break;
|
||||
case GuildScheduledEventStatus.Completed:
|
||||
embed.WithTitle(string.Format(Messages.EventCompleted, gatewayEvent.Name))
|
||||
.WithDescription(
|
||||
string.Format(
|
||||
Messages.EventDuration,
|
||||
DateTimeOffset.UtcNow.Subtract(
|
||||
guildData.ScheduledEvents[gatewayEvent.ID.Value].ActualStartTime
|
||||
?? gatewayEvent.ScheduledStartTime).ToString()))
|
||||
.WithColour(ColorsList.Black);
|
||||
|
||||
guildData.ScheduledEvents.Remove(gatewayEvent.ID.Value);
|
||||
break;
|
||||
case GuildScheduledEventStatus.Canceled:
|
||||
case GuildScheduledEventStatus.Scheduled:
|
||||
default: return Result.FromError(new ArgumentOutOfRangeError(nameof(gatewayEvent.Status)));
|
||||
}
|
||||
|
||||
var result = embed.WithCurrentTimestamp().Build();
|
||||
|
||||
if (!result.IsDefined(out var built)) return Result.FromError(result);
|
||||
|
||||
return (Result)await _channelApi.CreateMessageAsync(
|
||||
guildData.Configuration.EventNotificationChannel.ToDiscordSnowflake(),
|
||||
content?.ToString() ?? default(Optional<string>), embeds: new[] { built }, ct: ct);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles sending a notification when a scheduled event has been cancelled
|
||||
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue