diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index 17fca275e..d779f7327 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -1241,11 +1241,19 @@ namespace Discord RequestOptions options = null); /// - /// Gets the welcome screen of the guild. + /// Gets the welcome screen of the guild. Returns is the welcome channel is not set. /// /// /// A task that represents the asynchronous creation operation. The task result contains a . /// Task GetWelcomeScreenAsync(RequestOptions options = null); + + /// + /// Modifies the welcome screen of the guild. Returns if welcome screen is removed. + /// + /// + /// A task that represents the asynchronous creation operation. The task result contains a . + /// + Task ModifyWelcomeScreenAsync(bool enabled, WelcomeScreenChannelProperties[] channels, string description = null, RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannel.cs b/src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannel.cs index 69aeba514..0f4c9b060 100644 --- a/src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannel.cs +++ b/src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannel.cs @@ -40,17 +40,4 @@ public class WelcomeScreenChannel : ISnowflakeEntity Emoji = null; } - - /// - /// Initializes a new instance of to be used to modify one. - /// - /// - /// - /// - public WelcomeScreenChannel(ulong id, string description, IEmote emoji) - { - Id = id; - Description = description; - Emoji = emoji; - } } diff --git a/src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannelProperties.cs b/src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannelProperties.cs new file mode 100644 index 000000000..dfab6fe91 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannelProperties.cs @@ -0,0 +1,50 @@ +using System; +using System.Xml.Linq; + +namespace Discord; + +public class WelcomeScreenChannelProperties : ISnowflakeEntity +{ + /// + /// Gets or sets the channel's id. + /// + public ulong Id { get; set; } + + /// + /// Gets or sets the description shown for the channel. + /// + public string Description { get; set; } + + /// + /// Gets or sets the emoji for this channel. if it is unicode emoji, if it is a custom one and if none is set. + /// + /// + /// If the emoji is only the will be populated. + /// Use to get the emoji. + /// + public IEmote Emoji { get; set; } + + /// + public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); + + /// + /// Initializes a new instance of . + /// + /// Id if a channel. + /// Description for the channel in the welcome screen. + /// The emoji for the channel in the welcome screen. + public WelcomeScreenChannelProperties(ulong id, string description, IEmote emoji = null) + { + Id = id; + Description = description; + Emoji = emoji; + } + + /// + /// Initializes a new instance of . + /// + /// A welcome screen channel to modify. + /// A new instance of . + public static WelcomeScreenChannelProperties FromWelcomeScreenChannel(WelcomeScreenChannel channel) + => new (channel.Id, channel.Description, channel.Emoji); +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildWelcomeScreenParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildWelcomeScreenParams.cs index 7deb7209e..8e8ddb63e 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildWelcomeScreenParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildWelcomeScreenParams.cs @@ -10,7 +10,7 @@ internal class ModifyGuildWelcomeScreenParams public Optional Enabled { get; set; } [JsonProperty("welcome_channels")] - public Optional Channels { get; set; } + public Optional WelcomeChannels { get; set; } [JsonProperty("description")] public Optional Description { get; set; } diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 18b82344f..36f52d955 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -2,6 +2,7 @@ using Discord.API.Rest; using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Data; using System.Linq; using System.Threading.Tasks; using WidgetModel = Discord.API.GuildWidget; @@ -19,7 +20,8 @@ namespace Discord.Rest public static async Task ModifyAsync(IGuild guild, BaseDiscordClient client, Action func, RequestOptions options) { - if (func == null) throw new ArgumentNullException(nameof(func)); + if (func == null) + throw new ArgumentNullException(nameof(func)); var args = new GuildProperties(); func(args); @@ -140,7 +142,7 @@ namespace Discord.Rest }; var mebibyte = Math.Pow(2, 20); - return (ulong) (tierFactor * mebibyte); + return (ulong)(tierFactor * mebibyte); } #endregion @@ -231,7 +233,8 @@ namespace Discord.Rest public static async Task CreateTextChannelAsync(IGuild guild, BaseDiscordClient client, string name, RequestOptions options, Action func = null) { - if (name == null) throw new ArgumentNullException(paramName: nameof(name)); + if (name == null) + throw new ArgumentNullException(paramName: nameof(name)); var props = new TextChannelProperties(); func?.Invoke(props); @@ -260,7 +263,8 @@ namespace Discord.Rest public static async Task CreateVoiceChannelAsync(IGuild guild, BaseDiscordClient client, string name, RequestOptions options, Action func = null) { - if (name == null) throw new ArgumentNullException(paramName: nameof(name)); + if (name == null) + throw new ArgumentNullException(paramName: nameof(name)); var props = new VoiceChannelProperties(); func?.Invoke(props); @@ -316,7 +320,8 @@ namespace Discord.Rest public static async Task CreateCategoryChannelAsync(IGuild guild, BaseDiscordClient client, string name, RequestOptions options, Action func = null) { - if (name == null) throw new ArgumentNullException(paramName: nameof(name)); + if (name == null) + throw new ArgumentNullException(paramName: nameof(name)); var props = new GuildChannelProperties(); func?.Invoke(props); @@ -387,7 +392,8 @@ namespace Discord.Rest RequestOptions options) { var vanityModel = await client.ApiClient.GetVanityInviteAsync(guild.Id, options).ConfigureAwait(false); - if (vanityModel == null) throw new InvalidOperationException("This guild does not have a vanity URL."); + if (vanityModel == null) + throw new InvalidOperationException("This guild does not have a vanity URL."); var inviteModel = await client.ApiClient.GetInviteAsync(vanityModel.Code, options).ConfigureAwait(false); inviteModel.Uses = vanityModel.Uses; return RestInviteMetadata.Create(client, guild, null, inviteModel); @@ -400,7 +406,8 @@ namespace Discord.Rest public static async Task CreateRoleAsync(IGuild guild, BaseDiscordClient client, string name, GuildPermissions? permissions, Color? color, bool isHoisted, bool isMentionable, RequestOptions options) { - if (name == null) throw new ArgumentNullException(paramName: nameof(name)); + if (name == null) + throw new ArgumentNullException(paramName: nameof(name)); var createGuildRoleParams = new API.Rest.ModifyGuildRoleParams { @@ -616,7 +623,8 @@ namespace Discord.Rest public static async Task ModifyEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, Action func, RequestOptions options) { - if (func == null) throw new ArgumentNullException(paramName: nameof(func)); + if (func == null) + throw new ArgumentNullException(paramName: nameof(func)); var props = new EmoteProperties(); func(props); @@ -807,7 +815,7 @@ namespace Discord.Rest { switch (args.Status.Value) { - case GuildScheduledEventStatus.Active when guildEvent.Status != GuildScheduledEventStatus.Scheduled: + case GuildScheduledEventStatus.Active when guildEvent.Status != GuildScheduledEventStatus.Scheduled: case GuildScheduledEventStatus.Completed when guildEvent.Status != GuildScheduledEventStatus.Active: case GuildScheduledEventStatus.Cancelled when guildEvent.Status != GuildScheduledEventStatus.Scheduled: throw new ArgumentException($"Cannot set event to {args.Status.Value} when events status is {guildEvent.Status}"); @@ -849,7 +857,7 @@ namespace Discord.Rest : Optional.Unspecified }; - if(args.Location.IsSpecified) + if (args.Location.IsSpecified) { apiArgs.EntityMetadata = new API.GuildScheduledEventEntityMetadata() { @@ -889,7 +897,7 @@ namespace Discord.Rest Image? bannerImage = null, RequestOptions options = null) { - if(location != null) + if (location != null) { Preconditions.AtMost(location.Length, 100, nameof(location)); } @@ -925,7 +933,7 @@ namespace Discord.Rest Image = bannerImage.HasValue ? bannerImage.Value.ToModel() : Optional.Unspecified }; - if(location != null) + if (location != null) { apiArgs.EntityMetadata = new API.GuildScheduledEventEntityMetadata() { @@ -951,6 +959,9 @@ namespace Discord.Rest { var model = await client.ApiClient.GetGuildWelcomeScreenAsync(guild.Id, options); + if (model.WelcomeChannels.Length == 0) + return null; + return new WelcomeScreen(model.Description.GetValueOrDefault(null), model.WelcomeChannels.Select( x => new WelcomeScreenChannel( x.ChannelId, x.Description, @@ -958,9 +969,28 @@ namespace Discord.Rest x.EmojiId.GetValueOrDefault(0))).ToList()); } - public static async Task ModifyWelcomeScreenAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) + public static async Task ModifyWelcomeScreenAsync(bool enabled, string description, WelcomeScreenChannelProperties[] channels, IGuild guild, BaseDiscordClient client, RequestOptions options) { - var model = await client.ApiClient.ModifyGuildWelcomeScreenAsync(null, guild.Id, options); + if (!guild.Features.HasFeature(GuildFeature.Community)) + throw new InvalidOperationException("Cannot update welcome screed in a non-community guild."); + + var args = new ModifyGuildWelcomeScreenParams + { + Enabled = enabled, + Description = description, + WelcomeChannels = channels?.Select(ch => new API.WelcomeScreenChannel + { + ChannelId = ch.Id, + Description = ch.Description, + EmojiName = ch.Emoji is Emoji emoj ? emoj.Name : Optional.Unspecified, + EmojiId = ch.Emoji is Emote emote ? emote.Id : Optional.Unspecified + }).ToArray() + }; + + var model = await client.ApiClient.ModifyGuildWelcomeScreenAsync(args, guild.Id, options); + + if(model.WelcomeChannels.Length == 0) + return null; return new WelcomeScreen(model.Description.GetValueOrDefault(null), model.WelcomeChannels.Select( x => new WelcomeScreenChannel( diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 1fbfa95de..e0e96a104 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -1523,6 +1523,10 @@ namespace Discord.Rest public Task GetWelcomeScreenAsync(RequestOptions options = null) => GuildHelper.GetWelcomeScreenAsync(this, Discord, options); + /// + public Task ModifyWelcomeScreenAsync(bool enabled, WelcomeScreenChannelProperties[] channels, string description = null, RequestOptions options = null) + => GuildHelper.ModifyWelcomeScreenAsync(enabled, description, channels, this, Discord, options); + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index e8c3184ff..7d53619f1 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -2015,6 +2015,10 @@ namespace Discord.WebSocket public Task GetWelcomeScreenAsync(RequestOptions options = null) => GuildHelper.GetWelcomeScreenAsync(this, Discord, options); + /// + public Task ModifyWelcomeScreenAsync(bool enabled, WelcomeScreenChannelProperties[] channels, string description = null, RequestOptions options = null) + => GuildHelper.ModifyWelcomeScreenAsync(enabled, description, channels, this, Discord, options); + void IDisposable.Dispose() { DisconnectAudioAsync().GetAwaiter().GetResult();