diff --git a/DisCatSharp/Entities/Channel/DiscordChannel.cs b/DisCatSharp/Entities/Channel/DiscordChannel.cs index 344aa9838f..a62d6f4a36 100644 --- a/DisCatSharp/Entities/Channel/DiscordChannel.cs +++ b/DisCatSharp/Entities/Channel/DiscordChannel.cs @@ -1049,19 +1049,21 @@ public async Task GetStageAsync() /// The scheduled start time. /// The description. /// The cover image. + /// The recurrence rule. /// The reason. /// A scheduled event. + /// Thrown if the user gave an invalid input. /// Thrown when the resource does not exist. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public async Task CreateScheduledEventAsync(string name, DateTimeOffset scheduledStartTime, string description = null, Optional coverImage = default, string reason = null) + public async Task CreateScheduledEventAsync(string name, DateTimeOffset scheduledStartTime, string description = null, Optional coverImage = default, DiscordScheduledEventRecurrenceRule? recurrenceRule = null, string reason = null) { if (!this.IsVoiceJoinable()) throw new NotSupportedException("Cannot create a scheduled event for this type of channel. Channel type must be either voice or stage."); - var type = this.Type == ChannelType.Voice ? ScheduledEventEntityType.Voice : ScheduledEventEntityType.StageInstance; + var type = this.Type is ChannelType.Voice ? ScheduledEventEntityType.Voice : ScheduledEventEntityType.StageInstance; - return await this.Guild.CreateScheduledEventAsync(name, scheduledStartTime, null, this, null, description, type, coverImage, reason).ConfigureAwait(false); + return await this.Guild.CreateScheduledEventAsync(name, scheduledStartTime, null, this, null, description, type, coverImage, recurrenceRule, reason).ConfigureAwait(false); } #endregion diff --git a/DisCatSharp/Entities/Guild/DiscordGuild.cs b/DisCatSharp/Entities/Guild/DiscordGuild.cs index 75bb3fd023..07eda524b9 100644 --- a/DisCatSharp/Entities/Guild/DiscordGuild.cs +++ b/DisCatSharp/Entities/Guild/DiscordGuild.cs @@ -1260,7 +1260,7 @@ public async Task CreateAutomodRuleAsync( ) => await this.Discord.ApiClient.CreateAutomodRuleAsync(this.Id, name, eventType, triggerType, actions, triggerMetadata, enabled, exemptRoles, exemptChannels, reason).ConfigureAwait(false); -#region Scheduled Events + #region Scheduled Events /// /// Creates a scheduled event. @@ -1273,15 +1273,17 @@ public async Task CreateAutomodRuleAsync( /// The description. /// The type. /// The cover image. + /// The recurrence rule. /// The reason. /// A scheduled event. + /// Thrown if the user gave an invalid input. /// Thrown when the guild does not exist. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public async Task CreateScheduledEventAsync(string name, DateTimeOffset scheduledStartTime, DateTimeOffset? scheduledEndTime = null, DiscordChannel channel = null, DiscordScheduledEventEntityMetadata metadata = null, string description = null, ScheduledEventEntityType type = ScheduledEventEntityType.StageInstance, Optional coverImage = default, string reason = null) + public async Task CreateScheduledEventAsync(string name, DateTimeOffset scheduledStartTime, DateTimeOffset? scheduledEndTime = null, DiscordChannel channel = null, DiscordScheduledEventEntityMetadata metadata = null, string description = null, ScheduledEventEntityType type = ScheduledEventEntityType.StageInstance, Optional coverImage = default, DiscordScheduledEventRecurrenceRule? recurrenceRule = null, string reason = null) { var coverb64 = ImageTool.Base64FromStream(coverImage); - return await this.Discord.ApiClient.CreateGuildScheduledEventAsync(this.Id, type == ScheduledEventEntityType.External ? null : channel?.Id, type == ScheduledEventEntityType.External ? metadata : null, name, scheduledStartTime, scheduledEndTime.HasValue && type == ScheduledEventEntityType.External ? scheduledEndTime.Value : null, description, type, coverb64, reason).ConfigureAwait(false); + return await this.Discord.ApiClient.CreateGuildScheduledEventAsync(this.Id, type is ScheduledEventEntityType.External ? null : channel?.Id, type is ScheduledEventEntityType.External ? metadata : null, name, scheduledStartTime, scheduledEndTime.HasValue && type is ScheduledEventEntityType.External ? scheduledEndTime.Value : null, description, type, coverb64, recurrenceRule, reason).ConfigureAwait(false); } /// @@ -1293,15 +1295,17 @@ public async Task CreateScheduledEventAsync(string name, /// The location of the external event. /// The description. /// The cover image. + /// The recurrence rule. /// The reason. /// A scheduled event. + /// Thrown if the user gave an invalid input. /// Thrown when the guild does not exist. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public async Task CreateExternalScheduledEventAsync(string name, DateTimeOffset scheduledStartTime, DateTimeOffset scheduledEndTime, string location, string description = null, Optional coverImage = default, string reason = null) + public async Task CreateExternalScheduledEventAsync(string name, DateTimeOffset scheduledStartTime, DateTimeOffset scheduledEndTime, string location, string description = null, Optional coverImage = default, DiscordScheduledEventRecurrenceRule? recurrenceRule = null, string reason = null) { var coverb64 = ImageTool.Base64FromStream(coverImage); - return await this.Discord.ApiClient.CreateGuildScheduledEventAsync(this.Id, null, new(location), name, scheduledStartTime, scheduledEndTime, description, ScheduledEventEntityType.External, coverb64, reason).ConfigureAwait(false); + return await this.Discord.ApiClient.CreateGuildScheduledEventAsync(this.Id, null, new(location), name, scheduledStartTime, scheduledEndTime, description, ScheduledEventEntityType.External, coverb64, recurrenceRule, reason).ConfigureAwait(false); } /// diff --git a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordRecurrenceRuleNWeekday.cs b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordRecurrenceRuleNWeekday.cs new file mode 100644 index 0000000000..4c924f499d --- /dev/null +++ b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordRecurrenceRuleNWeekday.cs @@ -0,0 +1,23 @@ +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a specific day within a specific week to recur on. +/// +public sealed class DiscordRecurrenceRuleNWeekday +{ + /// + /// Gets or sets the week number (1-5) for recurrence. + /// + [JsonProperty("n")] + public int WeekNumber { get; set; } + + /// + /// Gets or sets the day of the week for recurrence. + /// + [JsonProperty("day")] + public RecurrenceRuleWeekday Day { get; set; } +} diff --git a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs index 07af56a7e1..eae11bbc11 100644 --- a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs +++ b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs @@ -150,6 +150,12 @@ This isn't used. public IReadOnlyList SkuIds { get; internal set; } */ + /// + /// Gets the recurrence rule for this scheduled event, if any. + /// + [JsonProperty("recurrence_rule", NullValueHandling = NullValueHandling.Ignore)] + public DiscordScheduledEventRecurrenceRule? RecurrenceRule { get; internal set; } + /// /// Gets the total number of users subscribed to the scheduled event. /// @@ -169,6 +175,7 @@ internal DiscordScheduledEvent() /// Modifies the current scheduled event. /// /// Action to perform on this thread + /// Thrown if the user gave an invalid input. /// Thrown when the client does not have the permission. /// Thrown when the event does not exist. /// Thrown when an invalid parameter was provided. @@ -190,8 +197,8 @@ public async Task ModifyAsync(Action action) var scheduledEndTime = Optional.None; if (mdl.ScheduledEndTime.HasValue && mdl.EntityType.HasValue ? mdl.EntityType == ScheduledEventEntityType.External : this.EntityType == ScheduledEventEntityType.External) scheduledEndTime = mdl.ScheduledEndTime.Value; - - await this.Discord.ApiClient.ModifyGuildScheduledEventAsync(this.GuildId, this.Id, channelId, this.EntityType == ScheduledEventEntityType.External ? new DiscordScheduledEventEntityMetadata(mdl.Location.Value) : null, mdl.Name, mdl.ScheduledStartTime, scheduledEndTime, mdl.Description, mdl.EntityType, mdl.Status, coverb64, mdl.AuditLogReason).ConfigureAwait(false); + + await this.Discord.ApiClient.ModifyGuildScheduledEventAsync(this.GuildId, this.Id, channelId, this.EntityType == ScheduledEventEntityType.External ? new DiscordScheduledEventEntityMetadata(mdl.Location.Value) : null, mdl.Name, mdl.ScheduledStartTime, scheduledEndTime, mdl.Description, mdl.EntityType, mdl.Status, coverb64, mdl.RecurrenceRule, mdl.AuditLogReason).ConfigureAwait(false); } /// diff --git a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventRecurrenceRule.cs b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventRecurrenceRule.cs new file mode 100644 index 0000000000..d5e817e33c --- /dev/null +++ b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventRecurrenceRule.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents the recurrence rule for a scheduled event. +/// +public sealed class DiscordScheduledEventRecurrenceRule + { + /// + /// Gets or sets the start time of the recurrence interval. + /// + [JsonProperty("start")] + public DateTimeOffset Start { get; set; } + + /// + /// Gets the end time of the recurrence interval. + /// + [JsonProperty("end")] + public DateTimeOffset? End { get; internal set; } + + /// + /// Gets or sets the frequency of the recurrence. + /// + [JsonProperty("frequency")] + public RecurrenceRuleFrequency Frequency { get; set; } + + /// + /// Gets or sets the interval between events. + /// + [JsonProperty("interval")] + public int Interval { get; set; } + + /// + /// Gets or sets specific days within a week for the event to recur on. + /// + [JsonProperty("by_weekday", NullValueHandling = NullValueHandling.Include)] + public List? ByWeekday { get; set; } + + /// + /// Gets or sets specific days within a specific week (1-5) to recur on. + /// + [JsonProperty("by_n_weekday", NullValueHandling = NullValueHandling.Include)] + public List? ByNWeekday { get; set; } + + /// + /// Gets or sets specific months to recur on. + /// + [JsonProperty("by_month", NullValueHandling = NullValueHandling.Include)] + public List? ByMonth { get; set; } + + /// + /// Gets or sets specific dates within a month to recur on. + /// + [JsonProperty("by_month_day", NullValueHandling = NullValueHandling.Include)] + public List? ByMonthDay { get; set; } + + /// + /// Gets specific dates within a year to recur on. + /// + [JsonProperty("by_year_day", NullValueHandling = NullValueHandling.Include)] + public List? ByYearDay { get; internal set; } + + /// + /// Gets the total amount of times that the event is allowed to recur before stopping. + /// + [JsonProperty("count", NullValueHandling = NullValueHandling.Include)] + public int? Count { get; internal set; } + } diff --git a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventRecurrenceRuleValidator.cs b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventRecurrenceRuleValidator.cs new file mode 100644 index 0000000000..c2915c023a --- /dev/null +++ b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventRecurrenceRuleValidator.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Validator for instances. +/// +public static class DiscordScheduledEventRecurrenceRuleValidator +{ + /// + /// A collection of valid weekday sets for events with a daily recurrence frequency. + /// + private static readonly List> s_validDailyWeekdaySets = [CreateWeekdaySet(RecurrenceRuleWeekday.Monday, RecurrenceRuleWeekday.Tuesday, RecurrenceRuleWeekday.Wednesday, RecurrenceRuleWeekday.Thursday, RecurrenceRuleWeekday.Friday), CreateWeekdaySet(RecurrenceRuleWeekday.Tuesday, RecurrenceRuleWeekday.Wednesday, RecurrenceRuleWeekday.Thursday, RecurrenceRuleWeekday.Friday, RecurrenceRuleWeekday.Saturday), CreateWeekdaySet(RecurrenceRuleWeekday.Sunday, RecurrenceRuleWeekday.Monday, RecurrenceRuleWeekday.Tuesday, RecurrenceRuleWeekday.Wednesday, RecurrenceRuleWeekday.Thursday), CreateWeekdaySet(RecurrenceRuleWeekday.Friday, RecurrenceRuleWeekday.Saturday), CreateWeekdaySet(RecurrenceRuleWeekday.Saturday, RecurrenceRuleWeekday.Sunday), CreateWeekdaySet(RecurrenceRuleWeekday.Sunday, RecurrenceRuleWeekday.Monday)]; + + /// + /// Creates a set of weekdays for easier readability. + /// + /// The weekdays to include in the set. + /// A list of objects. + private static List CreateWeekdaySet(params RecurrenceRuleWeekday[] weekdays) + => [..weekdays]; + + /// + /// Validates the recurrence rule. + /// + /// The recurrence rule to validate. + /// A tuple containing a boolean indicating validity and an optional error message. + public static (bool IsValid, string? ErrorMessage) Validate(this DiscordScheduledEventRecurrenceRule rule) + { + return rule.ByWeekday is not null && rule.ByNWeekday is not null + ? ((bool IsValid, string? ErrorMessage))(false, "by_weekday and by_n_weekday cannot both be set.") + : rule.ByMonth is not null && rule.ByMonthDay is not null + ? ((bool IsValid, string? ErrorMessage))(false, "by_month and by_month_day cannot both be set.") + : rule.Frequency switch + { + RecurrenceRuleFrequency.Daily => rule.ValidateDailyFrequency(), + RecurrenceRuleFrequency.Weekly => rule.ValidateWeeklyFrequency(), + RecurrenceRuleFrequency.Monthly => rule.ValidateMonthlyFrequency(), + RecurrenceRuleFrequency.Yearly => rule.ValidateYearlyFrequency(), + _ => (false, "Unknown frequency type.") + }; + } + + /// + /// Validates recurrence rules with a daily frequency. + /// + /// The recurrence rule to validate. + /// A tuple containing a boolean indicating validity and an optional error message. + private static (bool IsValid, string? ErrorMessage) ValidateDailyFrequency(this DiscordScheduledEventRecurrenceRule rule) + => rule.ByWeekday is not null && !rule.ByWeekday.IsValidDailyWeekdaySet() + ? ((bool IsValid, string? ErrorMessage))(false, "Invalid by_weekday set for daily frequency.") + : (true, null); + + /// + /// Validates recurrence rules with a weekly frequency. + /// + /// The recurrence rule to validate. + /// A tuple containing a boolean indicating validity and an optional error message. + private static (bool IsValid, string? ErrorMessage) ValidateWeeklyFrequency(this DiscordScheduledEventRecurrenceRule rule) + => rule.ByWeekday?.Count is not 1 + ? ((bool IsValid, string? ErrorMessage))(false, "Weekly events must have a single day set in by_weekday.") + : rule.Interval is not 1 and not 2 + ? ((bool IsValid, string? ErrorMessage))(false, "Weekly events can only have an interval of 1 or 2.") + : (true, null); + + /// + /// Validates recurrence rules with a monthly frequency. + /// + /// The recurrence rule to validate. + /// A tuple containing a boolean indicating validity and an optional error message. + private static (bool IsValid, string? ErrorMessage) ValidateMonthlyFrequency(this DiscordScheduledEventRecurrenceRule rule) + => rule.ByNWeekday?.Count is not 1 + ? ((bool IsValid, string? ErrorMessage))(false, "Monthly events must have a single day set in by_n_weekday.") + : (true, null); + + /// + /// Validates recurrence rules with a yearly frequency. + /// + /// The recurrence rule to validate. + /// A tuple containing a boolean indicating validity and an optional error message. + private static (bool IsValid, string? ErrorMessage) ValidateYearlyFrequency(this DiscordScheduledEventRecurrenceRule rule) + => rule.ByMonth?.Count is not 1 || rule.ByMonthDay?.Count is not 1 + ? ((bool IsValid, string? ErrorMessage))(false, "Yearly events must have both by_month and by_month_day set to a single value.") + : (true, null); + + /// + /// Validates if the weekday set is valid for a daily frequency. + /// + /// The weekday set to validate. + /// if the set is valid; otherwise, . + private static bool IsValidDailyWeekdaySet(this IReadOnlyCollection byWeekday) + => s_validDailyWeekdaySets.Any(set => set.SequenceEqual(byWeekday)); +} diff --git a/DisCatSharp/Enums/Guild/ScheduledEvent/RecurrenceRuleFrequency.cs b/DisCatSharp/Enums/Guild/ScheduledEvent/RecurrenceRuleFrequency.cs new file mode 100644 index 0000000000..b5b24829e9 --- /dev/null +++ b/DisCatSharp/Enums/Guild/ScheduledEvent/RecurrenceRuleFrequency.cs @@ -0,0 +1,27 @@ +namespace DisCatSharp.Enums; + +/// +/// Represents the frequency of a scheduled event's recurrence. +/// +public enum RecurrenceRuleFrequency +{ + /// + /// The scheduled event repeats yearly. + /// + Yearly = 0, + + /// + /// The scheduled event repeats monthly. + /// + Monthly = 1, + + /// + /// The scheduled event repeats weekly. + /// + Weekly = 2, + + /// + /// The scheduled event repeats daily. + /// + Daily = 3 +} diff --git a/DisCatSharp/Enums/Guild/ScheduledEvent/RecurrenceRuleWeekday.cs b/DisCatSharp/Enums/Guild/ScheduledEvent/RecurrenceRuleWeekday.cs new file mode 100644 index 0000000000..c5e53e404a --- /dev/null +++ b/DisCatSharp/Enums/Guild/ScheduledEvent/RecurrenceRuleWeekday.cs @@ -0,0 +1,42 @@ +namespace DisCatSharp.Enums; + +/// +/// Represents the days of the week for scheduling recurrent events. +/// +public enum RecurrenceRuleWeekday +{ + /// + /// The scheduled event repeats on mondays. + /// + Monday = 0, + + /// + /// The scheduled event repeats tuesdays. + /// + Tuesday = 1, + + /// + /// The scheduled event repeats wednesdays. + /// + Wednesday = 2, + + /// + /// The scheduled event repeats thursdays. + /// + Thursday = 3, + + /// + /// The scheduled event repeats fridays. + /// + Friday = 4, + + /// + /// The scheduled event repeats saturdays. + /// + Saturday = 5, + + /// + /// The scheduled event repeats sundays. + /// + Sunday = 6 +} diff --git a/DisCatSharp/Net/Abstractions/Rest/RestGuildScheduledEventPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestGuildScheduledEventPayloads.cs index 86f313ca7a..f854edeaa3 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestGuildScheduledEventPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestGuildScheduledEventPayloads.cs @@ -40,13 +40,13 @@ internal sealed class RestGuildScheduledEventCreatePayload : ObservableApiObject /// Gets or sets the time to schedule the scheduled event. /// [JsonProperty("scheduled_start_time")] - public DateTimeOffset ScheduledStartTime { get; internal set; } + public DateTimeOffset ScheduledStartTime { get; set; } /// /// Gets or sets the time when the scheduled event is scheduled to end. /// [JsonProperty("scheduled_end_time", NullValueHandling = NullValueHandling.Ignore)] - public DateTimeOffset? ScheduledEndTime { get; internal set; } + public DateTimeOffset? ScheduledEndTime { get; set; } /// /// Gets or sets the entity type of the scheduled event. @@ -60,6 +60,12 @@ internal sealed class RestGuildScheduledEventCreatePayload : ObservableApiObject [JsonProperty("image", NullValueHandling = NullValueHandling.Include)] public Optional CoverBase64 { get; set; } + /// + /// Gets or sets the recurrence rule. + /// + [JsonProperty("recurrence_rule", NullValueHandling = NullValueHandling.Ignore)] + public DiscordScheduledEventRecurrenceRule? RecurrenceRule { get; set; } + /// /// Gets or sets the privacy level of the scheduled event. /// @@ -100,13 +106,13 @@ internal sealed class RestGuildScheduledEventModifyPayload : ObservableApiObject /// Gets or sets the time to schedule the scheduled event. /// [JsonProperty("scheduled_start_time")] - public Optional ScheduledStartTime { get; internal set; } + public Optional ScheduledStartTime { get; set; } /// /// Gets or sets the time when the scheduled event is scheduled to end. /// [JsonProperty("scheduled_end_time")] - public Optional ScheduledEndTime { get; internal set; } + public Optional ScheduledEndTime { get; set; } /// /// Gets or sets the entity type of the scheduled event. @@ -117,8 +123,8 @@ internal sealed class RestGuildScheduledEventModifyPayload : ObservableApiObject /// /// Gets or sets the cover image as base64. /// - [JsonProperty("image")] - public Optional CoverBase64 { get; set; } + [JsonProperty("image", NullValueHandling = NullValueHandling.Include)] + public Optional CoverBase64 { get; set; } /// /// Gets or sets the status of the scheduled event. @@ -126,6 +132,12 @@ internal sealed class RestGuildScheduledEventModifyPayload : ObservableApiObject [JsonProperty("status")] public Optional Status { get; set; } + /// + /// Gets or sets the recurrence rule. + /// + [JsonProperty("recurrence_rule", NullValueHandling = NullValueHandling.Include)] + public Optional RecurrenceRule { get; set; } + /// /// Gets or sets the privacy level of the scheduled event. /// diff --git a/DisCatSharp/Net/Models/ScheduledEventEditModel.cs b/DisCatSharp/Net/Models/ScheduledEventEditModel.cs index 5397ab19c2..44d267c00b 100644 --- a/DisCatSharp/Net/Models/ScheduledEventEditModel.cs +++ b/DisCatSharp/Net/Models/ScheduledEventEditModel.cs @@ -56,6 +56,11 @@ public class ScheduledEventEditModel : BaseEditModel /// public Optional Status { get; set; } + /// + /// Gets or sets the recurrence rule. + /// + public Optional RecurrenceRule { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index dc86c2162e..ed257900e4 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -2079,8 +2079,35 @@ internal async Task DeleteAutomodRuleAsync(ulong guildId, ulong rul /// /// Creates a scheduled event. /// - internal async Task CreateGuildScheduledEventAsync(ulong guildId, ulong? channelId, DiscordScheduledEventEntityMetadata metadata, string name, DateTimeOffset scheduledStartTime, DateTimeOffset? scheduledEndTime, string description, ScheduledEventEntityType type, Optional coverb64, string? reason = null) - { + /// The guild id. + /// The channel id. + /// The metadata. + /// The name. + /// The scheduled start time. + /// The scheduled end time. + /// The description. + /// The type. + /// The cover image. + /// The recurrence rule. + /// The reason. + /// A scheduled event. + /// Thrown if the user gave an invalid input. + /// Thrown when the guild does not exist. + /// Thrown when an invalid parameter was provided. + /// Thrown when Discord is unable to process the request. + internal async Task CreateGuildScheduledEventAsync(ulong guildId, ulong? channelId, DiscordScheduledEventEntityMetadata metadata, string name, DateTimeOffset scheduledStartTime, DateTimeOffset? scheduledEndTime, string description, ScheduledEventEntityType type, Optional coverb64, DiscordScheduledEventRecurrenceRule? recurrenceRule, string? reason = null) + { + if (recurrenceRule is not null) + { + var validationResult = recurrenceRule.Validate(); + if (!validationResult.IsValid) + throw new ValidationException( + typeof(DiscordScheduledEventRecurrenceRule), + "DiscordGuild.CreateScheduledEventAsync or DiscordGuild.CreateExternalScheduledEventAsync", + validationResult.ErrorMessage! + ); + } + var pld = new RestGuildScheduledEventCreatePayload { ChannelId = channelId, @@ -2090,7 +2117,8 @@ internal async Task CreateGuildScheduledEventAsync(ulong ScheduledEndTime = scheduledEndTime, Description = description, EntityType = type, - CoverBase64 = coverb64 + CoverBase64 = coverb64, + RecurrenceRule = recurrenceRule }; var headers = Utilities.GetBaseHeaders(); @@ -2123,6 +2151,24 @@ internal async Task CreateGuildScheduledEventAsync(ulong /// /// Modifies a scheduled event. /// + /// The guild id. + /// The scheduled event id. + /// The channel id. + /// The metadata. + /// The name. + /// The scheduled start time. + /// The scheduled end time. + /// The description. + /// The type. + /// The status. + /// The cover image. + /// The recurrence rule. + /// The reason. + /// A scheduled event. + /// Thrown if the user gave an invalid input. + /// Thrown when the guild does not exist. + /// Thrown when an invalid parameter was provided. + /// Thrown when Discord is unable to process the request. internal async Task ModifyGuildScheduledEventAsync( ulong guildId, ulong scheduledEventId, @@ -2134,10 +2180,22 @@ internal async Task ModifyGuildScheduledEventAsync( Optional description, Optional type, Optional status, - Optional coverb64, + Optional coverb64, + Optional recurrenceRule, string? reason = null ) { + if (recurrenceRule.HasValue && recurrenceRule.Value is not null) + { + var validationResult = recurrenceRule.Value.Validate(); + if (!validationResult.IsValid) + throw new ValidationException( + typeof(DiscordScheduledEventRecurrenceRule), + "DiscordScheduledEvent.ModifyAsync(Action action)", + validationResult.ErrorMessage! + ); + } + var pld = new RestGuildScheduledEventModifyPayload { ChannelId = channelId, @@ -2148,7 +2206,8 @@ internal async Task ModifyGuildScheduledEventAsync( Description = description, EntityType = type, Status = status, - CoverBase64 = coverb64 + CoverBase64 = coverb64, + RecurrenceRule = recurrenceRule }; var headers = Utilities.GetBaseHeaders();