From 3a8f76c4b171402dae744939b23635e38b6559b7 Mon Sep 17 00:00:00 2001 From: Misha133 <61027276+Misha-133@users.noreply.github.com> Date: Sat, 15 Apr 2023 02:08:30 +0300 Subject: [PATCH] [Feature] Guild Onboarding support (#2616) * api models * moar models * complete models * modelsss * forgot to push * oh lol forgot this too * api & rest guild method * revert VS being VS & formatting to file scoped namespace * socket entities * yup * fix xml doc * changes --- .../Entities/Guilds/IGuild.cs | 8 +++ .../Onboarding/GuildOnboardingPromptType.cs | 17 +++++ .../Guilds/Onboarding/IGuildOnboarding.cs | 34 ++++++++++ .../Onboarding/IGuildOnboardingPrompt.cs | 40 ++++++++++++ .../IGuildOnboardingPromptOption.cs | 34 ++++++++++ .../API/Common/GuildOnboarding.cs | 18 ++++++ .../API/Common/GuildOnboardingPrompt.cs | 27 ++++++++ .../API/Common/GuildOnboardingPromptOption.cs | 24 +++++++ src/Discord.Net.Rest/DiscordRestApiClient.cs | 13 ++++ .../Entities/Guilds/GuildHelper.cs | 13 +++- .../Guilds/Onboarding/RestGuildOnboarding.cs | 46 +++++++++++++ .../Onboarding/RestGuildOnboardingPrompt.cs | 50 +++++++++++++++ .../RestGuildOnboardingPromptOption.cs | 50 +++++++++++++++ .../Entities/Guilds/RestGuild.cs | 16 +++++ .../Onboarding/SocketGuildOnboarding.cs | 53 +++++++++++++++ .../Onboarding/SocketGuildOnboardingPrompt.cs | 52 +++++++++++++++ .../SocketGuildOnboardingPromptOption.cs | 64 +++++++++++++++++++ .../Entities/Guilds/SocketGuild.cs | 18 ++++++ 18 files changed, 574 insertions(+), 3 deletions(-) create mode 100644 src/Discord.Net.Core/Entities/Guilds/Onboarding/GuildOnboardingPromptType.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboarding.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPrompt.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPromptOption.cs create mode 100644 src/Discord.Net.Rest/API/Common/GuildOnboarding.cs create mode 100644 src/Discord.Net.Rest/API/Common/GuildOnboardingPrompt.cs create mode 100644 src/Discord.Net.Rest/API/Common/GuildOnboardingPromptOption.cs create mode 100644 src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboarding.cs create mode 100644 src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPrompt.cs create mode 100644 src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboarding.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPrompt.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index 66641b8e..97ee481b 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -1307,5 +1307,13 @@ namespace Discord /// A task that represents the asynchronous creation operation. The task result contains the created . /// Task CreateAutoModRuleAsync(Action props, RequestOptions options = null); + + /// + /// Gets the onboarding object configured for the guild. + /// + /// + /// A task that represents the asynchronous creation operation. The task result contains the created . + /// + Task GetOnboardingAsync(RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Guilds/Onboarding/GuildOnboardingPromptType.cs b/src/Discord.Net.Core/Entities/Guilds/Onboarding/GuildOnboardingPromptType.cs new file mode 100644 index 00000000..3b5357b3 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/Onboarding/GuildOnboardingPromptType.cs @@ -0,0 +1,17 @@ +namespace Discord; + +/// +/// Represents the guild onboarding option type. +/// +public enum GuildOnboardingPromptType +{ + /// + /// The prompt accepts multiple choices. + /// + MultipleChoice = 0, + + /// + /// The prompt uses a dropdown menu. + /// + Dropdown = 1, +} diff --git a/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboarding.cs b/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboarding.cs new file mode 100644 index 00000000..96edbba9 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboarding.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace Discord; + +/// +/// Represents the guild onboarding flow. +/// +public interface IGuildOnboarding +{ + /// + /// Gets the ID of the guild this onboarding is part of. + /// + ulong GuildId { get; } + + /// + /// Gets the guild this onboarding is part of. + /// + IGuild Guild { get; } + + /// + /// Gets prompts shown during onboarding and in customize community. + /// + IReadOnlyCollection Prompts { get; } + + /// + /// Gets IDs of channels that members get opted into automatically. + /// + IReadOnlyCollection DefaultChannelIds { get; } + + /// + /// Gets whether onboarding is enabled in the guild. + /// + bool IsEnabled { get; } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPrompt.cs b/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPrompt.cs new file mode 100644 index 00000000..9a9aa01d --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPrompt.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; + +namespace Discord; + +/// +/// Represents the guild onboarding prompt. +/// +public interface IGuildOnboardingPrompt : ISnowflakeEntity +{ + /// + /// Gets options available within the prompt. + /// + IReadOnlyCollection Options { get; } + + /// + /// Gets the title of the prompt. + /// + string Title { get; } + + /// + /// Indicates whether users are limited to selecting one option for the prompt. + /// + bool IsSingleSelect { get; } + + /// + /// Indicates whether the prompt is required before a user completes the onboarding flow. + /// + bool IsRequired { get; } + + /// + /// Indicates whether the prompt is present in the onboarding flow. + /// If , the prompt will only appear in the Channels and Roles tab. + /// + bool IsInOnboarding { get; } + + /// + /// Gets the type of the prompt. + /// + GuildOnboardingPromptType Type { get; } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPromptOption.cs b/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPromptOption.cs new file mode 100644 index 00000000..b7cd01be --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/Onboarding/IGuildOnboardingPromptOption.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace Discord; + +/// +/// Represents the guild onboarding prompt option. +/// +public interface IGuildOnboardingPromptOption : ISnowflakeEntity +{ + /// + /// Gets IDs of channels a member is added to when the option is selected. + /// + IReadOnlyCollection ChannelIds { get; } + + /// + /// Gets IDs of roles assigned to a member when the option is selected. + /// + IReadOnlyCollection RoleIds { get; } + + /// + /// Gets the emoji of the option. if none is set. + /// + IEmote Emoji { get; } + + /// + /// Gets the title of the option. + /// + string Title { get; } + + /// + /// Gets the description of the option. if none is set. + /// + string Description { get; } +} diff --git a/src/Discord.Net.Rest/API/Common/GuildOnboarding.cs b/src/Discord.Net.Rest/API/Common/GuildOnboarding.cs new file mode 100644 index 00000000..898643b6 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/GuildOnboarding.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Discord.API; + +internal class GuildOnboarding +{ + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("prompts")] + public GuildOnboardingPrompt[] Prompts { get; set; } + + [JsonProperty("default_channel_ids")] + public ulong[] DefaultChannelIds { get; set; } + + [JsonProperty("enabled")] + public bool Enabled { get; set; } +} diff --git a/src/Discord.Net.Rest/API/Common/GuildOnboardingPrompt.cs b/src/Discord.Net.Rest/API/Common/GuildOnboardingPrompt.cs new file mode 100644 index 00000000..600ea5d8 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/GuildOnboardingPrompt.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; + +namespace Discord.API; + +internal class GuildOnboardingPrompt +{ + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("options")] + public GuildOnboardingPromptOption[] Options { get; set; } + + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("single_select")] + public bool IsSingleSelect { get; set; } + + [JsonProperty("required")] + public bool IsRequired { get; set; } + + [JsonProperty("in_onboarding")] + public bool IsInOnboarding { get; set; } + + [JsonProperty("type")] + public GuildOnboardingPromptType Type { get; set; } +} diff --git a/src/Discord.Net.Rest/API/Common/GuildOnboardingPromptOption.cs b/src/Discord.Net.Rest/API/Common/GuildOnboardingPromptOption.cs new file mode 100644 index 00000000..bae5dc30 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/GuildOnboardingPromptOption.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; + +namespace Discord.API; + +internal class GuildOnboardingPromptOption +{ + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("channel_ids")] + public ulong[] ChannelIds { get; set; } + + [JsonProperty("role_ids")] + public ulong[] RoleIds { get; set; } + + [JsonProperty("emoji")] + public Emoji Emoji { get; set; } + + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("description")] + public Optional Description { get; set; } +} diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 496d913c..375beb35 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -2239,6 +2239,19 @@ namespace Discord.API #endregion + #region Guild Onboarding + + public async Task GetGuildOnboardingAsync(ulong guildId, RequestOptions options) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendAsync("GET", () => $"guilds/{guildId}/onboarding", new BucketIds(guildId: guildId), options: options); + } + + #endregion + #region Users public async Task GetUserAsync(ulong userId, RequestOptions options = null) { diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 0ee84041..2dc687dc 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -193,7 +193,7 @@ namespace Discord.Rest }, start: fromUserId, count: limit - ); + ); } public static async Task GetBanAsync(IGuild guild, BaseDiscordClient client, ulong userId, RequestOptions options) @@ -427,7 +427,7 @@ namespace Discord.Rest } public static async Task DeleteIntegrationAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) => - await client.ApiClient.DeleteIntegrationAsync(guild.Id, id, options).ConfigureAwait(false); + await client.ApiClient.DeleteIntegrationAsync(guild.Id, id, options).ConfigureAwait(false); #endregion #region Interactions @@ -810,7 +810,7 @@ namespace Discord.Rest } public static IAsyncEnumerable> GetEventUsersAsync(BaseDiscordClient client, IGuildScheduledEvent guildEvent, - ulong? fromUserId, int? limit, RequestOptions options) + ulong? fromUserId, int? limit, RequestOptions options) { return new PagedAsyncEnumerable( DiscordConfig.MaxGuildEventUsersPerBatch, @@ -1254,5 +1254,12 @@ namespace Discord.Rest public static Task DeleteRuleAsync(BaseDiscordClient client, IAutoModRule rule, RequestOptions options) => client.ApiClient.DeleteGuildAutoModRuleAsync(rule.GuildId, rule.Id, options); #endregion + + #region Onboarding + + public static async Task GetGuildOnboardingAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) + => await client.ApiClient.GetGuildOnboardingAsync(guild.Id, options); + + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboarding.cs b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboarding.cs new file mode 100644 index 00000000..d0c4c14b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboarding.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.GuildOnboarding; + +namespace Discord.Rest; + +/// +public class RestGuildOnboarding : IGuildOnboarding +{ + /// + public ulong GuildId { get; private set; } + + /// + public RestGuild Guild { get; private set; } + + /// + public IReadOnlyCollection DefaultChannelIds { get; private set; } + + /// + public bool IsEnabled { get; private set; } + + /// + public IReadOnlyCollection Prompts { get; private set; } + + internal RestGuildOnboarding(BaseDiscordClient discord, Model model, RestGuild guild = null) + { + GuildId = model.GuildId; + DefaultChannelIds = model.DefaultChannelIds.ToImmutableArray(); + IsEnabled = model.Enabled; + + Guild = guild; + Prompts = model.Prompts.Select(prompt => new RestGuildOnboardingPrompt(discord, prompt.Id, prompt)).ToImmutableArray(); + } + + #region IGuildOnboarding + + /// + IReadOnlyCollection IGuildOnboarding.Prompts => Prompts; + + /// + IGuild IGuildOnboarding.Guild => Guild; + + #endregion +} diff --git a/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPrompt.cs b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPrompt.cs new file mode 100644 index 00000000..62308a86 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPrompt.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.GuildOnboardingPrompt; + +namespace Discord.Rest; + +/// +public class RestGuildOnboardingPrompt : RestEntity, IGuildOnboardingPrompt +{ + /// + public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); + + /// + public IReadOnlyCollection Options { get; private set; } + + /// + public string Title { get; private set; } + + /// + public bool IsSingleSelect { get; private set; } + + /// + public bool IsRequired { get; private set; } + + /// + public bool IsInOnboarding { get; private set; } + + /// + public GuildOnboardingPromptType Type { get; private set; } + + internal RestGuildOnboardingPrompt(BaseDiscordClient discord, ulong id, Model model) : base(discord, id) + { + Title = model.Title; + IsSingleSelect = model.IsSingleSelect; + IsInOnboarding = model.IsInOnboarding; + IsRequired = model.IsRequired; + Type = model.Type; + + Options = model.Options.Select(option => new RestGuildOnboardingPromptOption(discord, option.Id, option)).ToImmutableArray(); + } + + #region IGuildOnboardingPrompt + + /// + IReadOnlyCollection IGuildOnboardingPrompt.Options => Options; + + #endregion +} diff --git a/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs new file mode 100644 index 00000000..5323a8ce --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.GuildOnboardingPromptOption; + +namespace Discord.Rest; + +/// +public class RestGuildOnboardingPromptOption : RestEntity, IGuildOnboardingPromptOption +{ + /// + public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); + + /// + public IReadOnlyCollection ChannelIds { get; private set; } + + /// + public IReadOnlyCollection RoleIds { get; private set; } + + /// + public IEmote Emoji { get; private set; } + + /// + public string Title { get; private set; } + + /// + public string Description { get; private set; } + + internal RestGuildOnboardingPromptOption(BaseDiscordClient discord, ulong id, Model model) : base(discord, id) + { + ChannelIds = model.ChannelIds.ToImmutableArray(); + RoleIds = model.RoleIds.ToImmutableArray(); + Title = model.Title; + Description = model.Description.IsSpecified ? model.Description.Value : null; + + if (model.Emoji.Id.HasValue) + { + Emoji = new Emote(model.Emoji.Id.Value, model.Emoji.Name, model.Emoji.Animated ?? false); + } + else if (!string.IsNullOrWhiteSpace(model.Emoji.Name)) + { + Emoji = new Emoji(model.Emoji.Name); + } + else + { + Emoji = null; + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index b1c9dde3..a6c2d2d9 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -1234,6 +1234,18 @@ namespace Discord.Rest } + #endregion + + #region Onboarding + + /// + public async Task GetOnboardingAsync(RequestOptions options = null) + { + var model = await GuildHelper.GetGuildOnboardingAsync(this, Discord, options); + + return new RestGuildOnboarding(Discord, model, this); + } + #endregion #region IGuild @@ -1592,6 +1604,10 @@ namespace Discord.Rest /// async Task IGuild.CreateAutoModRuleAsync(Action props, RequestOptions options) => await CreateAutoModRuleAsync(props, options).ConfigureAwait(false); + + /// + async Task IGuild.GetOnboardingAsync(RequestOptions options) + => await GetOnboardingAsync(options); #endregion } diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboarding.cs b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboarding.cs new file mode 100644 index 00000000..a9d85b7d --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboarding.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.GuildOnboarding; + +namespace Discord.WebSocket; + +/// +public class SocketGuildOnboarding : IGuildOnboarding +{ + /// + public ulong GuildId { get; private set; } + + /// + public SocketGuild Guild { get; private set; } + + /// + public IReadOnlyCollection Prompts { get; private set; } + + /// + public IReadOnlyCollection DefaultChannelIds { get; private set; } + + /// + /// Gets channels members get opted in automatically. + /// + public IReadOnlyCollection DefaultChannels { get; private set; } + + /// + public bool IsEnabled { get; private set; } + + internal SocketGuildOnboarding(DiscordSocketClient discord, Model model, SocketGuild guild) + { + GuildId = model.GuildId; + Guild = guild; + IsEnabled = model.Enabled; + + DefaultChannelIds = model.DefaultChannelIds; + + DefaultChannels = model.DefaultChannelIds.Select(guild.GetChannel).ToImmutableArray(); + Prompts = model.Prompts.Select(x => new SocketGuildOnboardingPrompt(discord, x.Id, x, guild)).ToImmutableArray(); + + } + + #region IGuildOnboarding + + /// + IGuild IGuildOnboarding.Guild => Guild; + + /// + IReadOnlyCollection IGuildOnboarding.Prompts => Prompts; + + #endregion +} diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPrompt.cs b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPrompt.cs new file mode 100644 index 00000000..9bcbfac8 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPrompt.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +using Model = Discord.API.GuildOnboardingPrompt; + +namespace Discord.WebSocket; + + +/// +public class SocketGuildOnboardingPrompt : SocketEntity, IGuildOnboardingPrompt +{ + /// + public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); + + /// + public IReadOnlyCollection Options { get; private set; } + + /// + public string Title { get; private set; } + + /// + public bool IsSingleSelect { get; private set; } + + /// + public bool IsRequired { get; private set; } + + /// + public bool IsInOnboarding { get; private set; } + + /// + public GuildOnboardingPromptType Type { get; private set; } + + internal SocketGuildOnboardingPrompt(DiscordSocketClient discord, ulong id, Model model, SocketGuild guild) : base(discord, id) + { + Title = model.Title; + IsSingleSelect = model.IsSingleSelect; + IsInOnboarding = model.IsInOnboarding; + IsRequired = model.IsRequired; + Type = model.Type; + + Options = model.Options.Select(option => new SocketGuildOnboardingPromptOption(discord, option.Id, option, guild)).ToImmutableArray(); + } + + #region IGuildOnboardingPrompt + + /// + IReadOnlyCollection IGuildOnboardingPrompt.Options => Options; + + #endregion +} diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs new file mode 100644 index 00000000..770f4cc3 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +using Model = Discord.API.GuildOnboardingPromptOption; + +namespace Discord.WebSocket; + +/// +public class SocketGuildOnboardingPromptOption : SocketEntity, IGuildOnboardingPromptOption +{ + /// + public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); + + /// + public IReadOnlyCollection ChannelIds { get; private set; } + + /// + /// Gets channels a member is added to when the option is selected. + /// + public IReadOnlyCollection Channels { get; private set; } + + /// + public IReadOnlyCollection RoleIds { get; private set; } + + /// + /// Gets roles assigned to a member when the option is selected. + /// + public IReadOnlyCollection Roles { get; private set; } + + /// + public IEmote Emoji { get; private set; } + + /// + public string Title { get; private set; } + + /// + public string Description { get; private set; } + + internal SocketGuildOnboardingPromptOption(DiscordSocketClient discord, ulong id, Model model, SocketGuild guild) : base(discord, id) + { + ChannelIds = model.ChannelIds.ToImmutableArray(); + RoleIds = model.RoleIds.ToImmutableArray(); + Title = model.Title; + Description = model.Description.IsSpecified ? model.Description.Value : null; + + if (model.Emoji.Id.HasValue) + { + Emoji = new Emote(model.Emoji.Id.Value, model.Emoji.Name, model.Emoji.Animated ?? false); + } + else if (!string.IsNullOrWhiteSpace(model.Emoji.Name)) + { + Emoji = new Emoji(model.Emoji.Name); + } + else + { + Emoji = null; + } + + Roles = model.RoleIds.Select(guild.GetRole).ToImmutableArray(); + Channels = model.ChannelIds.Select(guild.GetChannel).ToImmutableArray(); + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 74adf5a1..297de2ed 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -1,6 +1,7 @@ using Discord.API.Gateway; using Discord.Audio; using Discord.Rest; + using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -11,6 +12,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; + using AutoModRuleModel = Discord.API.AutoModerationRule; using ChannelModel = Discord.API.Channel; using EmojiUpdateModel = Discord.API.Gateway.GuildEmojiUpdateEvent; @@ -1908,6 +1910,18 @@ namespace Discord.WebSocket #endregion + #region Onboarding + + /// + public async Task GetOnboardingAsync(RequestOptions options = null) + { + var model = await GuildHelper.GetGuildOnboardingAsync(this, Discord, options); + + return new SocketGuildOnboarding(Discord, model, this); + } + + #endregion + #region IGuild /// ulong? IGuild.AFKChannelId => AFKChannelId; @@ -2166,6 +2180,10 @@ namespace Discord.WebSocket async Task IGuild.CreateAutoModRuleAsync(Action props, RequestOptions options) => await CreateAutoModRuleAsync(props, options).ConfigureAwait(false); + /// + async Task IGuild.GetOnboardingAsync(RequestOptions options) + => await GetOnboardingAsync(options); + #endregion } }