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
}
}