* add `AppliedTags` property * convert collections into immutable arrays * remove "not supported" remark * implement `ThreadChannelProperties` * Add `DefaultSlowModeInterval` and `DefaultSlowModeInterval` properties to forum channels * add `Moderated` property to `ForumTag`` * `ForumTag` inherits `ISnowflakeEntity` * Fix `DiscordRestClient.GetChannelAsync` not getting forum channel * a lot of changes added: - channel flags - `ForumTagBuilder` - imroved channel modification * fixed a bug in forum tag emoji parsing * inherit forum channel from `INesteeChannel` * implement `INestedChannel` in forum channels * Add `Flags` property to channels * add iteraface for forum tags & add equality operators * Add default reaction emoji property * add support for modifing default reaction & some renaming * add createForumChannelAsync to guild * *fix resharper being a d... and moving code to next line* * add a `ForumChannels` property * Some fixes & add support for `default_sort_order` * fix misleading comment * fix #2502 * support creating post with applied tags * fix xmldoc * set category id on model update * add limit checks for tag counttags/3.9.0
@@ -0,0 +1,22 @@ | |||||
namespace Discord; | |||||
/// <summary> | |||||
/// Represents public flags for a channel. | |||||
/// </summary> | |||||
public enum ChannelFlags | |||||
{ | |||||
/// <summary> | |||||
/// Default value for flags, when none are given to a channel. | |||||
/// </summary> | |||||
None = 0, | |||||
/// <summary> | |||||
/// Flag given to a thread channel pinned on top of parent forum channel. | |||||
/// </summary> | |||||
Pinned = 1 << 1, | |||||
/// <summary> | |||||
/// Flag given to a forum channel that requires people to select tags when posting. | |||||
/// </summary> | |||||
RequireTag = 1 << 4 | |||||
} |
@@ -0,0 +1,60 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
namespace Discord; | |||||
public class ForumChannelProperties : TextChannelProperties | |||||
{ | |||||
/// <summary> | |||||
/// Gets or sets the topic of the channel. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// Not available in forum channels. | |||||
/// </remarks> | |||||
public new Optional<int> SlowModeInterval { get; } | |||||
/// <summary> | |||||
/// Gets or sets rate limit on creating posts in this forum channel. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// Setting this value to anything above zero will require each user to wait X seconds before | |||||
/// creating another thread; setting this value to <c>0</c> will disable rate limits for this channel. | |||||
/// <note> | |||||
/// Users with <see cref="Discord.ChannelPermission.ManageMessages"/> or | |||||
/// <see cref="ChannelPermission.ManageChannels"/> will be exempt from rate limits. | |||||
/// </note> | |||||
/// </remarks> | |||||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 21600].</exception> | |||||
public Optional<int> ThreadCreationInterval { get; set; } | |||||
/// <summary> | |||||
/// Gets or sets the default slow-mode for threads in this channel. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// Setting this value to anything above zero will require each user to wait X seconds before | |||||
/// sending another message; setting this value to <c>0</c> will disable slow-mode for child threads. | |||||
/// <note> | |||||
/// Users with <see cref="Discord.ChannelPermission.ManageMessages"/> or | |||||
/// <see cref="ChannelPermission.ManageChannels"/> will be exempt from slow-mode. | |||||
/// </note> | |||||
/// </remarks> | |||||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 21600].</exception> | |||||
public Optional<int> DefaultSlowModeInterval { get; set; } | |||||
/// <summary> | |||||
/// Gets or sets a collection of tags inside of this forum channel. | |||||
/// </summary> | |||||
public Optional<IEnumerable<ForumTagProperties>> Tags { get; set; } | |||||
/// <summary> | |||||
/// Gets or sets a new default reaction emoji in this forum channel. | |||||
/// </summary> | |||||
public Optional<IEmote> DefaultReactionEmoji { get; set; } | |||||
/// <summary> | |||||
/// Gets or sets the rule used to order posts in forum channels. | |||||
/// </summary> | |||||
public Optional<ForumSortOrder> DefaultSortOrder { get; set; } | |||||
} |
@@ -0,0 +1,17 @@ | |||||
namespace Discord; | |||||
/// <summary> | |||||
/// Defines the rule used to order posts in forum channels. | |||||
/// </summary> | |||||
public enum ForumSortOrder | |||||
{ | |||||
/// <summary> | |||||
/// Sort forum posts by activity. | |||||
/// </summary> | |||||
LatestActivity = 0, | |||||
/// <summary> | |||||
/// Sort forum posts by creation time (from most recent to oldest). | |||||
/// </summary> | |||||
CreationDate = 1 | |||||
} |
@@ -36,5 +36,10 @@ namespace Discord | |||||
/// Gets or sets the permission overwrites for this channel. | /// Gets or sets the permission overwrites for this channel. | ||||
/// </summary> | /// </summary> | ||||
public Optional<IEnumerable<Overwrite>> PermissionOverwrites { get; set; } | public Optional<IEnumerable<Overwrite>> PermissionOverwrites { get; set; } | ||||
/// <summary> | |||||
/// Gets or sets the flags of the channel. | |||||
/// </summary> | |||||
public Optional<ChannelFlags> Flags { get; set; } | |||||
} | } | ||||
} | } |
@@ -7,7 +7,7 @@ using System.Threading.Tasks; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public interface IForumChannel : IGuildChannel, IMentionable | |||||
public interface IForumChannel : IGuildChannel, IMentionable, INestedChannel | |||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Gets a value that indicates whether the channel is NSFW. | /// Gets a value that indicates whether the channel is NSFW. | ||||
@@ -35,6 +35,55 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
IReadOnlyCollection<ForumTag> Tags { get; } | IReadOnlyCollection<ForumTag> Tags { get; } | ||||
/// <summary> | |||||
/// Gets the current rate limit on creating posts in this forum channel. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// An <see cref="int"/> representing the time in seconds required before the user can send another | |||||
/// message; <c>0</c> if disabled. | |||||
/// </returns> | |||||
int ThreadCreationInterval { get; } | |||||
/// <summary> | |||||
/// Gets the current default slow-mode delay for threads in this forum channel. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// An <see cref="int"/> representing the time in seconds required before the user can send another | |||||
/// message; <c>0</c> if disabled. | |||||
/// </returns> | |||||
int DefaultSlowModeInterval { get; } | |||||
/// <summary> | |||||
/// Gets the emoji to show in the add reaction button on a thread in a forum channel | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// If the emoji is <see cref="Emote"/> only the <see cref="Emote.Id"/> will be populated. | |||||
/// Use <see cref="IGuild.GetEmoteAsync"/> to get the emoji. | |||||
/// </remarks> | |||||
IEmote DefaultReactionEmoji { get; } | |||||
/// <summary> | |||||
/// Gets or sets the rule used to order posts in forum channels. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// Defaults to null, which indicates a preferred sort order hasn't been set | |||||
/// </remarks> | |||||
ForumSortOrder? DefaultSortOrder { get; } | |||||
/// <summary> | |||||
/// Modifies this forum channel. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This method modifies the current forum channel with the specified properties. To see an example of this | |||||
/// method and what properties are available, please refer to <see cref="ForumChannelProperties"/>. | |||||
/// </remarks> | |||||
/// <param name="func">The delegate containing the properties to modify the channel with.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous modification operation. | |||||
/// </returns> | |||||
Task ModifyAsync(Action<ForumChannelProperties> func, RequestOptions options = null); | |||||
/// <summary> | /// <summary> | ||||
/// Creates a new post (thread) within the forum. | /// Creates a new post (thread) within the forum. | ||||
/// </summary> | /// </summary> | ||||
@@ -52,12 +101,13 @@ namespace Discord | |||||
/// <param name="stickers">A collection of stickers to send with the message.</param> | /// <param name="stickers">A collection of stickers to send with the message.</param> | ||||
/// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | /// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | ||||
/// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | /// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | ||||
/// <param name="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param> | |||||
/// <returns> | /// <returns> | ||||
/// A task that represents the asynchronous creation operation. | /// A task that represents the asynchronous creation operation. | ||||
/// </returns> | /// </returns> | ||||
Task<IThreadChannel> CreatePostAsync(string title, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, | Task<IThreadChannel> CreatePostAsync(string title, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, | ||||
string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | ||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None); | |||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null); | |||||
/// <summary> | /// <summary> | ||||
/// Creates a new post (thread) within the forum. | /// Creates a new post (thread) within the forum. | ||||
@@ -78,13 +128,14 @@ namespace Discord | |||||
/// <param name="stickers">A collection of stickers to send with the file.</param> | /// <param name="stickers">A collection of stickers to send with the file.</param> | ||||
/// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | /// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | ||||
/// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | /// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | ||||
/// <param name="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param> | |||||
/// <returns> | /// <returns> | ||||
/// A task that represents the asynchronous creation operation. | /// A task that represents the asynchronous creation operation. | ||||
/// </returns> | /// </returns> | ||||
Task<IThreadChannel> CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | Task<IThreadChannel> CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | ||||
AllowedMentions allowedMentions = null, MessageComponent components = null, | AllowedMentions allowedMentions = null, MessageComponent components = null, | ||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None); | |||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null); | |||||
/// <summary> | /// <summary> | ||||
/// Creates a new post (thread) within the forum. | /// Creates a new post (thread) within the forum. | ||||
@@ -106,13 +157,14 @@ namespace Discord | |||||
/// <param name="stickers">A collection of stickers to send with the file.</param> | /// <param name="stickers">A collection of stickers to send with the file.</param> | ||||
/// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | /// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | ||||
/// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | /// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | ||||
/// <param name="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param> | |||||
/// <returns> | /// <returns> | ||||
/// A task that represents the asynchronous creation operation. | /// A task that represents the asynchronous creation operation. | ||||
/// </returns> | /// </returns> | ||||
public Task<IThreadChannel> CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public Task<IThreadChannel> CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | ||||
AllowedMentions allowedMentions = null, MessageComponent components = null, | AllowedMentions allowedMentions = null, MessageComponent components = null, | ||||
ISticker[] stickers = null, Embed[] embeds = null,MessageFlags flags = MessageFlags.None); | |||||
ISticker[] stickers = null, Embed[] embeds = null,MessageFlags flags = MessageFlags.None, ForumTag[] tags = null); | |||||
/// <summary> | /// <summary> | ||||
/// Creates a new post (thread) within the forum. | /// Creates a new post (thread) within the forum. | ||||
@@ -132,12 +184,13 @@ namespace Discord | |||||
/// <param name="stickers">A collection of stickers to send with the file.</param> | /// <param name="stickers">A collection of stickers to send with the file.</param> | ||||
/// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | /// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | ||||
/// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | /// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | ||||
/// <param name="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param> | |||||
/// <returns> | /// <returns> | ||||
/// A task that represents the asynchronous creation operation. | /// A task that represents the asynchronous creation operation. | ||||
/// </returns> | /// </returns> | ||||
public Task<IThreadChannel> CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public Task<IThreadChannel> CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | ||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None); | |||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null); | |||||
/// <summary> | /// <summary> | ||||
/// Creates a new post (thread) within the forum. | /// Creates a new post (thread) within the forum. | ||||
@@ -155,14 +208,15 @@ namespace Discord | |||||
/// </param> | /// </param> | ||||
/// <param name="components">The message components to be included with this message. Used for interactions.</param> | /// <param name="components">The message components to be included with this message. Used for interactions.</param> | ||||
/// <param name="stickers">A collection of stickers to send with the file.</param> | /// <param name="stickers">A collection of stickers to send with the file.</param> | ||||
/// <param name="embeds">A array of <see cref="Embed"/>s to send with this response. Max 10.</param> | |||||
/// <param name="embeds">An array of <see cref="Embed"/>s to send with this response. Max 10.</param> | |||||
/// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | /// <param name="flags">A message flag to be applied to the sent message, only <see cref="MessageFlags.SuppressEmbeds"/> is permitted.</param> | ||||
/// <param name="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param> | |||||
/// <returns> | /// <returns> | ||||
/// A task that represents the asynchronous creation operation. | /// A task that represents the asynchronous creation operation. | ||||
/// </returns> | /// </returns> | ||||
public Task<IThreadChannel> CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public Task<IThreadChannel> CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | ||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None); | |||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null); | |||||
/// <summary> | /// <summary> | ||||
/// Gets a collection of active threads within this forum channel. | /// Gets a collection of active threads within this forum channel. | ||||
@@ -21,6 +21,17 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
int Position { get; } | int Position { get; } | ||||
/// <summary> | |||||
/// Gets the flags related to this channel. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This value is determined by bitwise OR-ing <see cref="ChannelFlags"/> values together. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// A channel's flags, if any is associated. | |||||
/// </returns> | |||||
ChannelFlags Flags { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the guild associated with this channel. | /// Gets the guild associated with this channel. | ||||
/// </summary> | /// </summary> | ||||
@@ -1,4 +1,5 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace Discord | namespace Discord | ||||
@@ -56,6 +57,14 @@ namespace Discord | |||||
/// </remarks> | /// </remarks> | ||||
bool? IsInvitable { get; } | bool? IsInvitable { get; } | ||||
/// <summary> | |||||
/// Gets ids of tags applied to a forum thread | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This property is only available on forum threads. | |||||
/// </remarks> | |||||
IReadOnlyCollection<ulong> AppliedTags { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets when the thread was created. | /// Gets when the thread was created. | ||||
/// </summary> | /// </summary> | ||||
@@ -102,5 +111,16 @@ namespace Discord | |||||
/// A task that represents the asynchronous operation of removing a user from this thread. | /// A task that represents the asynchronous operation of removing a user from this thread. | ||||
/// </returns> | /// </returns> | ||||
Task RemoveUserAsync(IGuildUser user, RequestOptions options = null); | Task RemoveUserAsync(IGuildUser user, RequestOptions options = null); | ||||
/// <summary> | |||||
/// Modifies this thread channel. | |||||
/// </summary> | |||||
/// <param name="func">The delegate containing the properties to modify the channel with.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous modification operation. | |||||
/// </returns> | |||||
/// <seealso cref="ThreadChannelProperties"/> | |||||
Task ModifyAsync(Action<ThreadChannelProperties> func, RequestOptions options = null); | |||||
} | } | ||||
} | } |
@@ -1,4 +1,5 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
@@ -39,20 +40,10 @@ namespace Discord | |||||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 21600].</exception> | /// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 21600].</exception> | ||||
public Optional<int> SlowModeInterval { get; set; } | public Optional<int> SlowModeInterval { get; set; } | ||||
/// <summary> | |||||
/// Gets or sets whether or not the thread is archived. | |||||
/// </summary> | |||||
public Optional<bool> Archived { get; set; } | |||||
/// <summary> | |||||
/// Gets or sets whether or not the thread is locked. | |||||
/// </summary> | |||||
public Optional<bool> Locked { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the auto archive duration. | /// Gets or sets the auto archive duration. | ||||
/// </summary> | /// </summary> | ||||
public Optional<ThreadArchiveDuration> AutoArchiveDuration { get; set; } | public Optional<ThreadArchiveDuration> AutoArchiveDuration { get; set; } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,26 @@ | |||||
using System.Collections.Generic; | |||||
namespace Discord; | |||||
/// <summary> | |||||
/// Provides properties that are used to modify an <see cref="IThreadChannel"/> with the specified changes. | |||||
/// </summary> | |||||
/// <seealso cref="IThreadChannel.ModifyAsync(System.Action{ThreadChannelProperties}, RequestOptions)"/> | |||||
public class ThreadChannelProperties : TextChannelProperties | |||||
{ | |||||
/// <summary> | |||||
/// Gets or sets the tags applied to a forum thread | |||||
/// </summary> | |||||
public Optional<IEnumerable<ulong>> AppliedTags { get; set; } | |||||
/// <summary> | |||||
/// Gets or sets whether or not the thread is locked. | |||||
/// </summary> | |||||
public Optional<bool> Locked { get; set; } | |||||
/// <summary> | |||||
/// Gets or sets whether or not the thread is archived. | |||||
/// </summary> | |||||
public Optional<bool> Archived { get; set; } | |||||
} |
@@ -1,42 +0,0 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// A struct representing a forum channel tag. | |||||
/// </summary> | |||||
public struct ForumTag | |||||
{ | |||||
/// <summary> | |||||
/// Gets the Id of the tag. | |||||
/// </summary> | |||||
public ulong Id { get; } | |||||
/// <summary> | |||||
/// Gets the name of the tag. | |||||
/// </summary> | |||||
public string Name { get; } | |||||
/// <summary> | |||||
/// Gets the emoji of the tag or <see langword="null"/> if none is set. | |||||
/// </summary> | |||||
public IEmote Emoji { get; } | |||||
internal ForumTag(ulong id, string name, ulong? emojiId, string emojiName) | |||||
{ | |||||
if (emojiId.HasValue && emojiId.Value != 0) | |||||
Emoji = new Emote(emojiId.Value, emojiName, false); | |||||
else if (emojiName != null) | |||||
Emoji = new Emoji(name); | |||||
else | |||||
Emoji = null; | |||||
Id = id; | |||||
Name = name; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,67 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
#nullable enable | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// A struct representing a forum channel tag. | |||||
/// </summary> | |||||
public struct ForumTag : ISnowflakeEntity, IForumTag | |||||
{ | |||||
/// <summary> | |||||
/// Gets the Id of the tag. | |||||
/// </summary> | |||||
public ulong Id { get; } | |||||
/// <inheritdoc/> | |||||
public string Name { get; } | |||||
/// <inheritdoc/> | |||||
public IEmote? Emoji { get; } | |||||
/// <inheritdoc/> | |||||
public bool IsModerated { get; } | |||||
/// <inheritdoc/> | |||||
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | |||||
internal ForumTag(ulong id, string name, ulong? emojiId = null, string? emojiName = null, bool moderated = false) | |||||
{ | |||||
if (emojiId.HasValue && emojiId.Value != 0) | |||||
Emoji = new Emote(emojiId.Value, null, false); | |||||
else if (emojiName != null) | |||||
Emoji = new Emoji(emojiName); | |||||
else | |||||
Emoji = null; | |||||
Id = id; | |||||
Name = name; | |||||
IsModerated = moderated; | |||||
} | |||||
public override int GetHashCode() => (Id, Name, Emoji, IsModerated).GetHashCode(); | |||||
public override bool Equals(object? obj) | |||||
=> obj is ForumTag tag && Equals(tag); | |||||
/// <summary> | |||||
/// Gets whether supplied tag is equals to the current one. | |||||
/// </summary> | |||||
public bool Equals(ForumTag tag) | |||||
=> Id == tag.Id && | |||||
Name == tag.Name && | |||||
(Emoji is Emoji emoji && tag.Emoji is Emoji otherEmoji && emoji.Equals(otherEmoji) || | |||||
Emoji is Emote emote && tag.Emoji is Emote otherEmote && emote.Equals(otherEmote)) && | |||||
IsModerated == tag.IsModerated; | |||||
public static bool operator ==(ForumTag? left, ForumTag? right) | |||||
=> left?.Equals(right) ?? right is null; | |||||
public static bool operator !=(ForumTag? left, ForumTag? right) => !(left == right); | |||||
} | |||||
} |
@@ -0,0 +1,191 @@ | |||||
#nullable enable | |||||
using System; | |||||
namespace Discord; | |||||
public class ForumTagBuilder | |||||
{ | |||||
private string? _name; | |||||
private IEmote? _emoji; | |||||
private bool _moderated; | |||||
private ulong? _id; | |||||
/// <summary> | |||||
/// Returns the maximum length of name allowed by Discord. | |||||
/// </summary> | |||||
public const int MaxNameLength = 20; | |||||
/// <summary> | |||||
/// Gets or sets the snowflake Id of the tag. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// If set this will update existing tag or will create a new one otherwise. | |||||
/// </remarks> | |||||
public ulong? Id | |||||
{ | |||||
get { return _id; } | |||||
set { _id = value; } | |||||
} | |||||
/// <summary> | |||||
/// Gets or sets the name of the tag. | |||||
/// </summary> | |||||
/// <exception cref="ArgumentException">Name length must be less than or equal to <see cref="MaxNameLength"/>.</exception> | |||||
public string? Name | |||||
{ | |||||
get { return _name; } | |||||
set | |||||
{ | |||||
if (value?.Length > MaxNameLength) | |||||
throw new ArgumentException(message: $"Name length must be less than or equal to {MaxNameLength}.", paramName: nameof(Name)); | |||||
_name = value; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Gets or sets the emoji of the tag. | |||||
/// </summary> | |||||
public IEmote? Emoji | |||||
{ | |||||
get { return _emoji; } | |||||
set { _emoji = value; } | |||||
} | |||||
/// <summary> | |||||
/// Gets or sets whether this tag can only be added to or removed from threads by a member | |||||
/// with the <see cref="GuildPermissions.ManageThreads"/> permission | |||||
/// </summary> | |||||
public bool IsModerated | |||||
{ | |||||
get { return _moderated; } | |||||
set { _moderated = value; } | |||||
} | |||||
/// <summary> | |||||
/// Initializes a new <see cref="ForumTagBuilder"/> class. | |||||
/// </summary> | |||||
public ForumTagBuilder() | |||||
{ | |||||
} | |||||
/// <summary> | |||||
/// Initializes a new <see cref="ForumTagBuilder"/> class with values | |||||
/// </summary> | |||||
/// <param name="id"> If set existing tag will be updated or a new one will be created otherwise.</param> | |||||
/// <param name="name"> Name of the tag.</param> | |||||
/// <param name="isModerated"> Sets whether this tag can only be added to or removed from threads by a member | |||||
/// with the <see cref="GuildPermissions.ManageThreads"/> permission. </param> | |||||
public ForumTagBuilder(string name, ulong? id = null, bool isModerated = false) | |||||
{ | |||||
Name = name; | |||||
IsModerated = isModerated; | |||||
Id = id; | |||||
} | |||||
/// <summary> | |||||
/// Initializes a new <see cref="ForumTagBuilder"/> class with values | |||||
/// </summary> | |||||
/// <param name="name"> Name of the tag.</param> | |||||
/// <param name="id"> If set existing tag will be updated or a new one will be created otherwise.</param> | |||||
/// <param name="emoji"> Display emoji of the tag.</param> | |||||
/// <param name="isModerated"> Sets whether this tag can only be added to or removed from threads by a member | |||||
/// with the <see cref="GuildPermissions.ManageThreads"/> permission. </param> | |||||
public ForumTagBuilder(string name, ulong? id = null, bool isModerated = false, IEmote? emoji = null) | |||||
{ | |||||
Name = name; | |||||
Emoji = emoji; | |||||
IsModerated = isModerated; | |||||
Id = id; | |||||
} | |||||
/// <summary> | |||||
/// Initializes a new <see cref="ForumTagBuilder"/> class with values | |||||
/// </summary> | |||||
/// /// <param name="name"> Name of the tag.</param> | |||||
/// <param name="id"> If set existing tag will be updated or a new one will be created otherwise.</param> | |||||
/// <param name="emoteId"> The id of custom Display emoji of the tag.</param> | |||||
/// <param name="isModerated"> Sets whether this tag can only be added to or removed from threads by a member | |||||
/// with the <see cref="GuildPermissions.ManageThreads"/> permission </param> | |||||
public ForumTagBuilder(string name, ulong? id = null, bool isModerated = false, ulong? emoteId = null) | |||||
{ | |||||
Name = name; | |||||
if(emoteId is not null) | |||||
Emoji = new Emote(emoteId.Value, null, false); | |||||
IsModerated = isModerated; | |||||
Id = id; | |||||
} | |||||
/// <summary> | |||||
/// Builds the Tag. | |||||
/// </summary> | |||||
/// <returns>An instance of <see cref="ForumTagProperties"/></returns> | |||||
/// <exception cref="ArgumentNullException">"Name must be set to build the tag"</exception> | |||||
public ForumTagProperties Build() | |||||
{ | |||||
if (_name is null) | |||||
throw new ArgumentNullException(nameof(Name), "Name must be set to build the tag"); | |||||
return new ForumTagProperties(_name!, _emoji, _moderated); | |||||
} | |||||
/// <summary> | |||||
/// Sets the name of the tag. | |||||
/// </summary> | |||||
/// <exception cref="ArgumentException">Name length must be less than or equal to <see cref="MaxNameLength"/>.</exception> | |||||
public ForumTagBuilder WithName(string name) | |||||
{ | |||||
Name = name; | |||||
return this; | |||||
} | |||||
/// <summary> | |||||
/// Sets the id of the tag. | |||||
/// </summary> | |||||
/// <param name="id"> If set existing tag will be updated or a new one will be created otherwise.</param> | |||||
/// <exception cref="ArgumentException">Name length must be less than or equal to <see cref="MaxNameLength"/>.</exception> | |||||
public ForumTagBuilder WithId(ulong? id) | |||||
{ | |||||
Id = id; | |||||
return this; | |||||
} | |||||
/// <summary> | |||||
/// Sets the emoji of the tag. | |||||
/// </summary> | |||||
public ForumTagBuilder WithEmoji(IEmote? emoji) | |||||
{ | |||||
Emoji = emoji; | |||||
return this; | |||||
} | |||||
/// <summary> | |||||
/// Sets whether this tag can only be added to or removed from threads by a member | |||||
/// with the <see cref="GuildPermissions.ManageThreads"/> permission | |||||
/// </summary> | |||||
public ForumTagBuilder WithModerated(bool moderated) | |||||
{ | |||||
IsModerated = moderated; | |||||
return this; | |||||
} | |||||
public override int GetHashCode() => base.GetHashCode(); | |||||
public override bool Equals(object? obj) | |||||
=> obj is ForumTagBuilder builder && Equals(builder); | |||||
/// <summary> | |||||
/// Gets whether supplied tag builder is equals to the current one. | |||||
/// </summary> | |||||
public bool Equals(ForumTagBuilder? builder) | |||||
=> builder is not null && | |||||
Id == builder.Id && | |||||
Name == builder.Name && | |||||
(Emoji is Emoji emoji && builder.Emoji is Emoji otherEmoji && emoji.Equals(otherEmoji) || | |||||
Emoji is Emote emote && builder.Emoji is Emote otherEmote && emote.Equals(otherEmote)) && | |||||
IsModerated == builder.IsModerated; | |||||
public static bool operator ==(ForumTagBuilder? left, ForumTagBuilder? right) | |||||
=> left?.Equals(right) ?? right is null ; | |||||
public static bool operator !=(ForumTagBuilder? left, ForumTagBuilder? right) => !(left == right); | |||||
} |
@@ -0,0 +1,11 @@ | |||||
namespace Discord; | |||||
public static class ForumTagBuilderExtensions | |||||
{ | |||||
public static ForumTagBuilder ToForumTagBuilder(this ForumTag tag) | |||||
=> new ForumTagBuilder(tag.Name, tag.Id, tag.IsModerated, tag.Emoji); | |||||
public static ForumTagBuilder ToForumTagBuilder(this ForumTagProperties tag) | |||||
=> new ForumTagBuilder(tag.Name, tag.Id, tag.IsModerated, tag.Emoji); | |||||
} |
@@ -0,0 +1,48 @@ | |||||
namespace Discord; | |||||
#nullable enable | |||||
public class ForumTagProperties : IForumTag | |||||
{ | |||||
/// <summary> | |||||
/// Gets the Id of the tag. | |||||
/// </summary> | |||||
public ulong Id { get; } | |||||
/// <inheritdoc/> | |||||
public string Name { get; } | |||||
/// <inheritdoc/> | |||||
public IEmote? Emoji { get; } | |||||
/// <inheritdoc/> | |||||
public bool IsModerated { get; } | |||||
internal ForumTagProperties(string name, IEmote? emoji = null, bool isMmoderated = false) | |||||
{ | |||||
Name = name; | |||||
Emoji = emoji; | |||||
IsModerated = isMmoderated; | |||||
} | |||||
public override int GetHashCode() => (Id, Name, Emoji, IsModerated).GetHashCode(); | |||||
public override bool Equals(object? obj) | |||||
=> obj is ForumTagProperties tag && Equals(tag); | |||||
/// <summary> | |||||
/// Gets whether supplied tag is equals to the current one. | |||||
/// </summary> | |||||
public bool Equals(ForumTagProperties? tag) | |||||
=> tag is not null && | |||||
Id == tag.Id && | |||||
Name == tag.Name && | |||||
(Emoji is Emoji emoji && tag.Emoji is Emoji otherEmoji && emoji.Equals(otherEmoji) || | |||||
Emoji is Emote emote && tag.Emoji is Emote otherEmote && emote.Equals(otherEmote)) && | |||||
IsModerated == tag.IsModerated; | |||||
public static bool operator ==(ForumTagProperties? left, ForumTagProperties? right) | |||||
=> left?.Equals(right) ?? right is null; | |||||
public static bool operator !=(ForumTagProperties? left, ForumTagProperties? right) => !(left == right); | |||||
} |
@@ -0,0 +1,29 @@ | |||||
namespace Discord; | |||||
#nullable enable | |||||
/// <summary> | |||||
/// Represents a Discord forum tag | |||||
/// </summary> | |||||
public interface IForumTag | |||||
{ | |||||
/// <summary> | |||||
/// Gets the name of the tag. | |||||
/// </summary> | |||||
string Name { get; } | |||||
/// <summary> | |||||
/// Gets the emoji of the tag or <see langword="null"/> if none is set. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// If the emoji is <see cref="Emote"/> only the <see cref="Emote.Id"/> will be populated. | |||||
/// Use <see cref="IGuild.GetEmoteAsync"/> to get the emoji. | |||||
/// </remarks> | |||||
IEmote? Emoji { get; } | |||||
/// <summary> | |||||
/// Gets whether this tag can only be added to or removed from threads by a member | |||||
/// with the <see cref="GuildPermissions.ManageThreads"/> permission | |||||
/// </summary> | |||||
bool IsModerated { get; } | |||||
} |
@@ -761,6 +761,18 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task<ICategoryChannel> CreateCategoryAsync(string name, Action<GuildChannelProperties> func = null, RequestOptions options = null); | Task<ICategoryChannel> CreateCategoryAsync(string name, Action<GuildChannelProperties> func = null, RequestOptions options = null); | ||||
/// <summary> | |||||
/// Creates a new channel forum in this guild. | |||||
/// </summary> | |||||
/// <param name="name">The new name for the forum.</param> | |||||
/// <param name="func">The delegate containing the properties to be applied to the channel upon its creation.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous creation operation. The task result contains the newly created | |||||
/// forum channel. | |||||
/// </returns> | |||||
Task<IForumChannel> CreateForumChannelAsync(string name, Action<ForumChannelProperties> func = null, RequestOptions options = null); | |||||
/// <summary> | /// <summary> | ||||
/// Gets a collection of all the voice regions this guild can access. | /// Gets a collection of all the voice regions this guild can access. | ||||
/// </summary> | /// </summary> | ||||
@@ -21,7 +21,7 @@ namespace Discord | |||||
String = 3, | String = 3, | ||||
/// <summary> | /// <summary> | ||||
/// An <see langword="int"/>. | |||||
/// An <see langword="long"/>. | |||||
/// </summary> | /// </summary> | ||||
Integer = 4, | Integer = 4, | ||||
@@ -46,6 +46,9 @@ namespace Discord | |||||
case ITextChannel: | case ITextChannel: | ||||
return ChannelType.Text; | return ChannelType.Text; | ||||
case IForumChannel: | |||||
return ChannelType.Forum; | |||||
} | } | ||||
return null; | return null; | ||||
@@ -70,8 +70,24 @@ namespace Discord.API | |||||
//ForumChannel | //ForumChannel | ||||
[JsonProperty("available_tags")] | [JsonProperty("available_tags")] | ||||
public Optional<ForumTags[]> ForumTags { get; set; } | public Optional<ForumTags[]> ForumTags { get; set; } | ||||
[JsonProperty("applied_tags")] | |||||
public Optional<ulong[]> AppliedTags { get; set; } | |||||
[JsonProperty("default_auto_archive_duration")] | [JsonProperty("default_auto_archive_duration")] | ||||
public Optional<ThreadArchiveDuration> AutoArchiveDuration { get; set; } | public Optional<ThreadArchiveDuration> AutoArchiveDuration { get; set; } | ||||
[JsonProperty("default_thread_rate_limit_per_user")] | |||||
public Optional<int> ThreadRateLimitPerUser { get; set; } | |||||
[JsonProperty("flags")] | |||||
public Optional<ChannelFlags> Flags { get; set; } | |||||
[JsonProperty("default_sort_order")] | |||||
public Optional<ForumSortOrder?> DefaultSortOrder { get; set; } | |||||
[JsonProperty("default_reaction_emoji")] | |||||
public Optional<ForumReactionEmoji> DefaultReactionEmoji { get; set; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,12 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API; | |||||
public class ForumReactionEmoji | |||||
{ | |||||
[JsonProperty("emoji_id")] | |||||
public ulong? EmojiId { get; set; } | |||||
[JsonProperty("emoji_name")] | |||||
public Optional<string> EmojiName { get; set; } | |||||
} |
@@ -17,5 +17,8 @@ namespace Discord.API | |||||
public Optional<ulong?> EmojiId { get; set; } | public Optional<ulong?> EmojiId { get; set; } | ||||
[JsonProperty("emoji_name")] | [JsonProperty("emoji_name")] | ||||
public Optional<string> EmojiName { get; set; } | public Optional<string> EmojiName { get; set; } | ||||
[JsonProperty("moderated")] | |||||
public bool Moderated { get; set; } | |||||
} | } | ||||
} | } |
@@ -23,6 +23,8 @@ namespace Discord.API.Rest | |||||
public Optional<bool> IsNsfw { get; set; } | public Optional<bool> IsNsfw { get; set; } | ||||
[JsonProperty("rate_limit_per_user")] | [JsonProperty("rate_limit_per_user")] | ||||
public Optional<int> SlowModeInterval { get; set; } | public Optional<int> SlowModeInterval { get; set; } | ||||
[JsonProperty("default_auto_archive_duration")] | |||||
public Optional<ThreadArchiveDuration> DefaultAutoArchiveDuration { get; set; } | |||||
//Voice channels | //Voice channels | ||||
[JsonProperty("bitrate")] | [JsonProperty("bitrate")] | ||||
@@ -30,6 +32,16 @@ namespace Discord.API.Rest | |||||
[JsonProperty("user_limit")] | [JsonProperty("user_limit")] | ||||
public Optional<int?> UserLimit { get; set; } | public Optional<int?> UserLimit { get; set; } | ||||
//Forum channels | |||||
[JsonProperty("default_reaction_emoji")] | |||||
public Optional<ModifyForumReactionEmojiParams> DefaultReactionEmoji { get; set; } | |||||
[JsonProperty("default_thread_rate_limit_per_user")] | |||||
public Optional<int> ThreadRateLimitPerUser { get; set; } | |||||
[JsonProperty("available_tags")] | |||||
public Optional<ModifyForumTagParams[]> AvailableTags { get; set; } | |||||
[JsonProperty("default_sort_order")] | |||||
public Optional<ForumSortOrder?> DefaultSortOrder { get; set; } | |||||
public CreateGuildChannelParams(string name, ChannelType type) | public CreateGuildChannelParams(string name, ChannelType type) | ||||
{ | { | ||||
Name = name; | Name = name; | ||||
@@ -27,6 +27,7 @@ namespace Discord.API.Rest | |||||
public Optional<ActionRowComponent[]> MessageComponent { get; set; } | public Optional<ActionRowComponent[]> MessageComponent { get; set; } | ||||
public Optional<MessageFlags?> Flags { get; set; } | public Optional<MessageFlags?> Flags { get; set; } | ||||
public Optional<ulong[]> Stickers { get; set; } | public Optional<ulong[]> Stickers { get; set; } | ||||
public Optional<ulong[]> TagIds { get; set; } | |||||
public CreateMultipartPostAsync(params FileAttachment[] attachments) | public CreateMultipartPostAsync(params FileAttachment[] attachments) | ||||
{ | { | ||||
@@ -59,6 +60,8 @@ namespace Discord.API.Rest | |||||
message["sticker_ids"] = Stickers.Value; | message["sticker_ids"] = Stickers.Value; | ||||
if (Flags.IsSpecified) | if (Flags.IsSpecified) | ||||
message["flags"] = Flags.Value; | message["flags"] = Flags.Value; | ||||
if (TagIds.IsSpecified) | |||||
message["applied_tags"] = TagIds.Value; | |||||
List<object> attachments = new(); | List<object> attachments = new(); | ||||
@@ -21,5 +21,8 @@ namespace Discord.API.Rest | |||||
[JsonProperty("message")] | [JsonProperty("message")] | ||||
public ForumThreadMessage Message { get; set; } | public ForumThreadMessage Message { get; set; } | ||||
[JsonProperty("applied_tags")] | |||||
public Optional<ulong[]> Tags { get; set; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,23 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Rest; | |||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
internal class ModifyForumChannelParams : ModifyTextChannelParams | |||||
{ | |||||
[JsonProperty("available_tags")] | |||||
public Optional<ModifyForumTagParams[]> Tags { get; set; } | |||||
[JsonProperty("default_thread_rate_limit_per_user")] | |||||
public Optional<int> DefaultSlowModeInterval { get; set; } | |||||
[JsonProperty("rate_limit_per_user")] | |||||
public Optional<int> ThreadCreationInterval { get; set; } | |||||
[JsonProperty("default_reaction_emoji")] | |||||
public Optional<ModifyForumReactionEmojiParams> DefaultReactionEmoji { get; set; } | |||||
[JsonProperty("default_sort_order")] | |||||
public Optional<ForumSortOrder> DefaultSortOrder { get; set; } | |||||
} |
@@ -0,0 +1,15 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API; | |||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
public class ModifyForumReactionEmojiParams | |||||
{ | |||||
[JsonProperty("emoji_id")] | |||||
public Optional<ulong?> EmojiId { get; set; } | |||||
[JsonProperty("emoji_name")] | |||||
public Optional<string> EmojiName { get; set; } | |||||
} | |||||
@@ -0,0 +1,23 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
internal class ModifyForumTagParams | |||||
{ | |||||
[JsonProperty("id")] | |||||
public Optional<ulong> Id { get; set; } | |||||
[JsonProperty("name")] | |||||
public string Name { get; set; } | |||||
[JsonProperty("emoji_id")] | |||||
public Optional<ulong?> EmojiId { get; set; } | |||||
[JsonProperty("emoji_name")] | |||||
public Optional<string> EmojiName { get; set; } | |||||
[JsonProperty("moderated")] | |||||
public bool Moderated { get; set; } | |||||
} | |||||
} |
@@ -13,5 +13,7 @@ namespace Discord.API.Rest | |||||
public Optional<ulong?> CategoryId { get; set; } | public Optional<ulong?> CategoryId { get; set; } | ||||
[JsonProperty("permission_overwrites")] | [JsonProperty("permission_overwrites")] | ||||
public Optional<Overwrite[]> Overwrites { get; set; } | public Optional<Overwrite[]> Overwrites { get; set; } | ||||
[JsonProperty("flags")] | |||||
public Optional<ChannelFlags?> Flags { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,4 +1,5 @@ | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System.Collections.Generic; | |||||
namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
{ | { | ||||
@@ -18,5 +19,11 @@ namespace Discord.API.Rest | |||||
[JsonProperty("rate_limit_per_user")] | [JsonProperty("rate_limit_per_user")] | ||||
public Optional<int> Slowmode { get; set; } | public Optional<int> Slowmode { get; set; } | ||||
[JsonProperty("applied_tags")] | |||||
public Optional<IEnumerable<ulong>> AppliedTags { get; set; } | |||||
[JsonProperty("flags")] | |||||
public Optional<ChannelFlags> Flags { get; set; } | |||||
} | } | ||||
} | } |
@@ -38,6 +38,7 @@ namespace Discord.Rest | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | Deny = overwrite.Permissions.DenyValue.ToString() | ||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
Flags = args.Flags.GetValueOrDefault(), | |||||
}; | }; | ||||
return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
} | } | ||||
@@ -0,0 +1,63 @@ | |||||
using Discord.API; | |||||
using System; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Model = Discord.API.Channel; | |||||
namespace Discord.Rest; | |||||
internal static class ForumHelper | |||||
{ | |||||
public static async Task<Model> ModifyAsync(IForumChannel channel, BaseDiscordClient client, | |||||
Action<ForumChannelProperties> func, | |||||
RequestOptions options) | |||||
{ | |||||
var args = new ForumChannelProperties(); | |||||
func(args); | |||||
Preconditions.AtMost(args.Tags.IsSpecified ? args.Tags.Value.Count() : 0, 5, nameof(args.Tags), "Forum channel can have max 20 tags."); | |||||
var apiArgs = new API.Rest.ModifyForumChannelParams() | |||||
{ | |||||
Name = args.Name, | |||||
Position = args.Position, | |||||
CategoryId = args.CategoryId, | |||||
Overwrites = args.PermissionOverwrites.IsSpecified | |||||
? args.PermissionOverwrites.Value.Select(overwrite => new API.Overwrite | |||||
{ | |||||
TargetId = overwrite.TargetId, | |||||
TargetType = overwrite.TargetType, | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | |||||
: Optional.Create<API.Overwrite[]>(), | |||||
DefaultSlowModeInterval = args.DefaultSlowModeInterval, | |||||
ThreadCreationInterval = args.ThreadCreationInterval, | |||||
Tags = args.Tags.IsSpecified | |||||
? args.Tags.Value.Select(tag => new API.ModifyForumTagParams | |||||
{ | |||||
Name = tag.Name, | |||||
EmojiId = tag.Emoji is Emote emote | |||||
? emote.Id | |||||
: Optional<ulong?>.Unspecified, | |||||
EmojiName = tag.Emoji is Emoji emoji | |||||
? emoji.Name | |||||
: Optional<string>.Unspecified | |||||
}).ToArray() | |||||
: Optional.Create<API.ModifyForumTagParams[]>(), | |||||
Flags = args.Flags.GetValueOrDefault(), | |||||
Topic = args.Topic, | |||||
DefaultReactionEmoji = args.DefaultReactionEmoji.IsSpecified | |||||
? new API.ModifyForumReactionEmojiParams | |||||
{ | |||||
EmojiId = args.DefaultReactionEmoji.Value is Emote emote ? | |||||
emote.Id : Optional<ulong?>.Unspecified, | |||||
EmojiName = args.DefaultReactionEmoji.Value is Emoji emoji ? | |||||
emoji.Name : Optional<string>.Unspecified | |||||
} | |||||
: Optional<ModifyForumReactionEmojiParams>.Unspecified, | |||||
DefaultSortOrder = args.DefaultSortOrder | |||||
}; | |||||
return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | |||||
} | |||||
} |
@@ -30,13 +30,15 @@ namespace Discord.Rest | |||||
ChannelType.Stage or | ChannelType.Stage or | ||||
ChannelType.NewsThread or | ChannelType.NewsThread or | ||||
ChannelType.PrivateThread or | ChannelType.PrivateThread or | ||||
ChannelType.PublicThread | |||||
ChannelType.PublicThread or | |||||
ChannelType.Forum | |||||
=> RestGuildChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model), | => RestGuildChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model), | ||||
ChannelType.DM or ChannelType.Group => CreatePrivate(discord, model) as RestChannel, | ChannelType.DM or ChannelType.Group => CreatePrivate(discord, model) as RestChannel, | ||||
ChannelType.Category => RestCategoryChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model), | ChannelType.Category => RestCategoryChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model), | ||||
_ => new RestChannel(discord, model.Id), | _ => new RestChannel(discord, model.Id), | ||||
}; | }; | ||||
} | } | ||||
internal static RestChannel Create(BaseDiscordClient discord, Model model, IGuild guild) | internal static RestChannel Create(BaseDiscordClient discord, Model model, IGuild guild) | ||||
{ | { | ||||
return model.Type switch | return model.Type switch | ||||
@@ -47,7 +49,8 @@ namespace Discord.Rest | |||||
ChannelType.Stage or | ChannelType.Stage or | ||||
ChannelType.NewsThread or | ChannelType.NewsThread or | ||||
ChannelType.PrivateThread or | ChannelType.PrivateThread or | ||||
ChannelType.PublicThread | |||||
ChannelType.PublicThread or | |||||
ChannelType.Forum | |||||
=> RestGuildChannel.Create(discord, guild, model), | => RestGuildChannel.Create(discord, guild, model), | ||||
ChannelType.DM or ChannelType.Group => CreatePrivate(discord, model) as RestChannel, | ChannelType.DM or ChannelType.Group => CreatePrivate(discord, model) as RestChannel, | ||||
ChannelType.Category => RestCategoryChannel.Create(discord, guild, model), | ChannelType.Category => RestCategoryChannel.Create(discord, guild, model), | ||||
@@ -26,6 +26,21 @@ namespace Discord.Rest | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public IReadOnlyCollection<ForumTag> Tags { get; private set; } | public IReadOnlyCollection<ForumTag> Tags { get; private set; } | ||||
/// <inheritdoc/> | |||||
public int ThreadCreationInterval { get; private set; } | |||||
/// <inheritdoc/> | |||||
public int DefaultSlowModeInterval { get; private set; } | |||||
/// <inheritdoc/> | |||||
public ulong? CategoryId { get; private set; } | |||||
/// <inheritdoc/> | |||||
public IEmote DefaultReactionEmoji { get; private set; } | |||||
/// <inheritdoc/> | |||||
public ForumSortOrder? DefaultSortOrder { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string Mention => MentionUtils.MentionChannel(Id); | public string Mention => MentionUtils.MentionChannel(Id); | ||||
@@ -35,9 +50,9 @@ namespace Discord.Rest | |||||
} | } | ||||
internal new static RestStageChannel Create(BaseDiscordClient discord, IGuild guild, Model model) | |||||
internal new static RestForumChannel Create(BaseDiscordClient discord, IGuild guild, Model model) | |||||
{ | { | ||||
var entity = new RestStageChannel(discord, guild, model.Id); | |||||
var entity = new RestForumChannel(discord, guild, model.Id); | |||||
entity.Update(model); | entity.Update(model); | ||||
return entity; | return entity; | ||||
} | } | ||||
@@ -49,46 +64,75 @@ namespace Discord.Rest | |||||
Topic = model.Topic.GetValueOrDefault(); | Topic = model.Topic.GetValueOrDefault(); | ||||
DefaultAutoArchiveDuration = model.AutoArchiveDuration.GetValueOrDefault(ThreadArchiveDuration.OneDay); | DefaultAutoArchiveDuration = model.AutoArchiveDuration.GetValueOrDefault(ThreadArchiveDuration.OneDay); | ||||
if (model.ThreadRateLimitPerUser.IsSpecified) | |||||
DefaultSlowModeInterval = model.ThreadRateLimitPerUser.Value; | |||||
if(model.SlowMode.IsSpecified) | |||||
ThreadCreationInterval = model.SlowMode.Value; | |||||
DefaultSortOrder = model.DefaultSortOrder.GetValueOrDefault(); | |||||
Tags = model.ForumTags.GetValueOrDefault(Array.Empty<API.ForumTags>()).Select( | Tags = model.ForumTags.GetValueOrDefault(Array.Empty<API.ForumTags>()).Select( | ||||
x => new ForumTag(x.Id, x.Name, x.EmojiId.GetValueOrDefault(null), x.EmojiName.GetValueOrDefault()) | |||||
x => new ForumTag(x.Id, x.Name, x.EmojiId.GetValueOrDefault(null), x.EmojiName.GetValueOrDefault(), x.Moderated) | |||||
).ToImmutableArray(); | ).ToImmutableArray(); | ||||
if (model.DefaultReactionEmoji.IsSpecified && model.DefaultReactionEmoji.Value is not null) | |||||
{ | |||||
if (model.DefaultReactionEmoji.Value.EmojiId.HasValue && model.DefaultReactionEmoji.Value.EmojiId.Value != 0) | |||||
DefaultReactionEmoji = new Emote(model.DefaultReactionEmoji.Value.EmojiId.GetValueOrDefault(), null, false); | |||||
else if (model.DefaultReactionEmoji.Value.EmojiName.IsSpecified) | |||||
DefaultReactionEmoji = new Emoji(model.DefaultReactionEmoji.Value.EmojiName.Value); | |||||
else | |||||
DefaultReactionEmoji = null; | |||||
} | |||||
CategoryId = model.CategoryId.GetValueOrDefault(); | |||||
} | |||||
/// <inheritdoc/> | |||||
public async Task ModifyAsync(Action<ForumChannelProperties> func, RequestOptions options = null) | |||||
{ | |||||
var model = await ForumHelper.ModifyAsync(this, Discord, func, options); | |||||
Update(model); | |||||
} | } | ||||
/// <inheritdoc cref="IForumChannel.CreatePostAsync(string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
public Task<RestThreadChannel> CreatePostAsync(string title, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | |||||
/// <inheritdoc cref="IForumChannel.CreatePostAsync(string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public Task<RestThreadChannel> CreatePostAsync(string title, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, | |||||
string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, ISticker[] stickers = null, | |||||
Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()); | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | ||||
AllowedMentions allowedMentions = null, MessageComponent components = null, | AllowedMentions allowedMentions = null, MessageComponent components = null, | ||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
{ | { | ||||
using var file = new FileAttachment(filePath, isSpoiler: isSpoiler); | using var file = new FileAttachment(filePath, isSpoiler: isSpoiler); | ||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | |||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()).ConfigureAwait(false); | |||||
} | } | ||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, Stream, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, Stream, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | ||||
AllowedMentions allowedMentions = null, MessageComponent components = null, | AllowedMentions allowedMentions = null, MessageComponent components = null, | ||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
{ | { | ||||
using var file = new FileAttachment(stream, filename, isSpoiler: isSpoiler); | using var file = new FileAttachment(stream, filename, isSpoiler: isSpoiler); | ||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | |||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()).ConfigureAwait(false); | |||||
} | } | ||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, FileAttachment, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, FileAttachment, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public Task<RestThreadChannel> CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public Task<RestThreadChannel> CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | ||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { attachment }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | |||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { attachment }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()); | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFilesAsync(string, IEnumerable{FileAttachment}, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFilesAsync(string, IEnumerable{FileAttachment}, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public Task<RestThreadChannel> CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public Task<RestThreadChannel> CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | ||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | |||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()); | |||||
/// <inheritdoc cref="IForumChannel.GetActiveThreadsAsync(RequestOptions)"/> | /// <inheritdoc cref="IForumChannel.GetActiveThreadsAsync(RequestOptions)"/> | ||||
public Task<IReadOnlyCollection<RestThreadChannel>> GetActiveThreadsAsync(RequestOptions options = null) | public Task<IReadOnlyCollection<RestThreadChannel>> GetActiveThreadsAsync(RequestOptions options = null) | ||||
@@ -115,17 +159,45 @@ namespace Discord.Rest | |||||
=> await GetPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | => await GetPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | ||||
async Task<IReadOnlyCollection<IThreadChannel>> IForumChannel.GetJoinedPrivateArchivedThreadsAsync(int? limit, DateTimeOffset? before, RequestOptions options) | async Task<IReadOnlyCollection<IThreadChannel>> IForumChannel.GetJoinedPrivateArchivedThreadsAsync(int? limit, DateTimeOffset? before, RequestOptions options) | ||||
=> await GetJoinedPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | => await GetJoinedPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostAsync(string title, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostAsync(string title, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostAsync(title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostAsync(title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFileAsync(title, filePath, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostWithFileAsync(title, filePath, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFileAsync(title, stream, filename, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostWithFileAsync(title, stream, filename, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFileAsync(title, attachment, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostWithFileAsync(title, attachment, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFilesAsync(title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | => await CreatePostWithFilesAsync(title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | ||||
#endregion | #endregion | ||||
#region INestedChannel | |||||
/// <inheritdoc /> | |||||
public virtual async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | |||||
public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options); | |||||
/// <inheritdoc /> | |||||
public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); | |||||
public virtual Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> throw new NotImplementedException(); | |||||
/// <inheritdoc /> | |||||
public virtual async Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||||
=> await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); | |||||
/// <inheritdoc /> | |||||
async Task<ICategoryChannel> INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) | |||||
{ | |||||
if (CategoryId.HasValue && mode == CacheMode.AllowDownload) | |||||
return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; | |||||
return null; | |||||
} | |||||
/// <inheritdoc /> | |||||
public Task SyncPermissionsAsync(RequestOptions options = null) | |||||
=> ChannelHelper.SyncPermissionsAsync(this, Discord, options); | |||||
#endregion | |||||
} | } | ||||
} | } |
@@ -26,6 +26,9 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong GuildId => Guild.Id; | public ulong GuildId => Guild.Id; | ||||
/// <inheritdoc /> | |||||
public ChannelFlags Flags { get; private set; } | |||||
internal RestGuildChannel(BaseDiscordClient discord, IGuild guild, ulong id) | internal RestGuildChannel(BaseDiscordClient discord, IGuild guild, ulong id) | ||||
: base(discord, id) | : base(discord, id) | ||||
{ | { | ||||
@@ -62,6 +65,8 @@ namespace Discord.Rest | |||||
newOverwrites.Add(overwrites[i].ToEntity()); | newOverwrites.Add(overwrites[i].ToEntity()); | ||||
_overwrites = newOverwrites.ToImmutable(); | _overwrites = newOverwrites.ToImmutable(); | ||||
} | } | ||||
Flags = model.Flags.GetValueOrDefault(ChannelFlags.None); | |||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -37,6 +37,9 @@ namespace Discord.Rest | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public bool? IsInvitable { get; private set; } | public bool? IsInvitable { get; private set; } | ||||
/// <inheritdoc/> | |||||
public IReadOnlyCollection<ulong> AppliedTags { get; private set; } | |||||
/// <inheritdoc cref="IThreadChannel.CreatedAt"/> | /// <inheritdoc cref="IThreadChannel.CreatedAt"/> | ||||
public override DateTimeOffset CreatedAt { get; } | public override DateTimeOffset CreatedAt { get; } | ||||
@@ -77,6 +80,8 @@ namespace Discord.Rest | |||||
MessageCount = model.MessageCount.GetValueOrDefault(0); | MessageCount = model.MessageCount.GetValueOrDefault(0); | ||||
Type = (ThreadType)model.Type; | Type = (ThreadType)model.Type; | ||||
ParentChannelId = model.CategoryId.Value; | ParentChannelId = model.CategoryId.Value; | ||||
AppliedTags = model.AppliedTags.GetValueOrDefault(Array.Empty<ulong>()).ToImmutableArray(); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -109,6 +114,13 @@ namespace Discord.Rest | |||||
Update(model); | Update(model); | ||||
} | } | ||||
/// <inheritdoc/> | |||||
public async Task ModifyAsync(Action<ThreadChannelProperties> func, RequestOptions options = null) | |||||
{ | |||||
var model = await ThreadHelper.ModifyAsync(this, Discord, func, options); | |||||
Update(model); | |||||
} | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
/// <remarks> | /// <remarks> | ||||
/// <b>This method is not supported in threads.</b> | /// <b>This method is not supported in threads.</b> | ||||
@@ -1,3 +1,4 @@ | |||||
using Discord.API; | |||||
using Discord.API.Rest; | using Discord.API.Rest; | ||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
@@ -46,18 +47,23 @@ namespace Discord.Rest | |||||
} | } | ||||
public static async Task<Model> ModifyAsync(IThreadChannel channel, BaseDiscordClient client, | public static async Task<Model> ModifyAsync(IThreadChannel channel, BaseDiscordClient client, | ||||
Action<TextChannelProperties> func, | |||||
Action<ThreadChannelProperties> func, | |||||
RequestOptions options) | RequestOptions options) | ||||
{ | { | ||||
var args = new TextChannelProperties(); | |||||
var args = new ThreadChannelProperties(); | |||||
func(args); | func(args); | ||||
Preconditions.AtMost(args.AppliedTags.IsSpecified ? args.AppliedTags.Value.Count() : 0, 5, nameof(args.AppliedTags), "Forum post can have max 5 applied tags."); | |||||
var apiArgs = new ModifyThreadParams | var apiArgs = new ModifyThreadParams | ||||
{ | { | ||||
Name = args.Name, | Name = args.Name, | ||||
Archived = args.Archived, | Archived = args.Archived, | ||||
AutoArchiveDuration = args.AutoArchiveDuration, | AutoArchiveDuration = args.AutoArchiveDuration, | ||||
Locked = args.Locked, | Locked = args.Locked, | ||||
Slowmode = args.SlowModeInterval | |||||
Slowmode = args.SlowModeInterval, | |||||
AppliedTags = args.AppliedTags, | |||||
Flags = args.Flags, | |||||
}; | }; | ||||
return await client.ApiClient.ModifyThreadAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyThreadAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
} | } | ||||
@@ -103,7 +109,10 @@ namespace Discord.Rest | |||||
return RestThreadUser.Create(client, channel.Guild, model, channel); | return RestThreadUser.Create(client, channel.Guild, model, channel); | ||||
} | } | ||||
public static async Task<RestThreadChannel> CreatePostAsync(IForumChannel channel, BaseDiscordClient client, string title, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
public static async Task<RestThreadChannel> CreatePostAsync(IForumChannel channel, BaseDiscordClient client, string title, | |||||
ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, string text = null, Embed embed = null, | |||||
RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, ISticker[] stickers = null, | |||||
Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ulong[] tagIds = null) | |||||
{ | { | ||||
embeds ??= Array.Empty<Embed>(); | embeds ??= Array.Empty<Embed>(); | ||||
if (embed != null) | if (embed != null) | ||||
@@ -112,6 +121,7 @@ namespace Discord.Rest | |||||
Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); | Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); | ||||
Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); | Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); | ||||
Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); | Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); | ||||
Preconditions.AtMost(tagIds?.Length ?? 0, 5, nameof(tagIds), "Forum post can have max 5 applied tags."); | |||||
// check that user flag and user Id list are exclusive, same with role flag and role Id list | // check that user flag and user Id list are exclusive, same with role flag and role Id list | ||||
if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) | if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) | ||||
@@ -134,10 +144,12 @@ namespace Discord.Rest | |||||
Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | ||||
} | } | ||||
if (flags is not MessageFlags.None and not MessageFlags.SuppressEmbeds) | if (flags is not MessageFlags.None and not MessageFlags.SuppressEmbeds) | ||||
throw new ArgumentException("The only valid MessageFlags are SuppressEmbeds and none.", nameof(flags)); | throw new ArgumentException("The only valid MessageFlags are SuppressEmbeds and none.", nameof(flags)); | ||||
if (channel.Flags.HasFlag(ChannelFlags.RequireTag)) | |||||
throw new ArgumentException($"The channel {channel.Name} requires posts to have at least one tag."); | |||||
var args = new CreatePostParams() | var args = new CreatePostParams() | ||||
{ | { | ||||
Title = title, | Title = title, | ||||
@@ -151,7 +163,8 @@ namespace Discord.Rest | |||||
Flags = flags, | Flags = flags, | ||||
Components = components?.Components?.Any() ?? false ? components.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | Components = components?.Components?.Any() ?? false ? components.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | ||||
Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional<ulong[]>.Unspecified, | Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional<ulong[]>.Unspecified, | ||||
} | |||||
}, | |||||
Tags = tagIds | |||||
}; | }; | ||||
var model = await client.ApiClient.CreatePostAsync(channel.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreatePostAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
@@ -159,7 +172,9 @@ namespace Discord.Rest | |||||
return RestThreadChannel.Create(client, channel.Guild, model); | return RestThreadChannel.Create(client, channel.Guild, model); | ||||
} | } | ||||
public static async Task<RestThreadChannel> CreatePostAsync(IForumChannel channel, BaseDiscordClient client, string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
public static async Task<RestThreadChannel> CreatePostAsync(IForumChannel channel, BaseDiscordClient client, string title, IEnumerable<FileAttachment> attachments, | |||||
ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, | |||||
ISticker[] stickers, Embed[] embeds, MessageFlags flags, ulong[] tagIds = null) | |||||
{ | { | ||||
embeds ??= Array.Empty<Embed>(); | embeds ??= Array.Empty<Embed>(); | ||||
if (embed != null) | if (embed != null) | ||||
@@ -168,6 +183,8 @@ namespace Discord.Rest | |||||
Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); | Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); | ||||
Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); | Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); | ||||
Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); | Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); | ||||
Preconditions.AtMost(tagIds?.Length ?? 0, 5, nameof(tagIds), "Forum post can have max 5 applied tags."); | |||||
// check that user flag and user Id list are exclusive, same with role flag and role Id list | // check that user flag and user Id list are exclusive, same with role flag and role Id list | ||||
if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) | if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) | ||||
@@ -190,9 +207,11 @@ namespace Discord.Rest | |||||
Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); | ||||
} | } | ||||
if (flags is not MessageFlags.None and not MessageFlags.SuppressEmbeds) | if (flags is not MessageFlags.None and not MessageFlags.SuppressEmbeds) | ||||
throw new ArgumentException("The only valid MessageFlags are SuppressEmbeds and none.", nameof(flags)); | throw new ArgumentException("The only valid MessageFlags are SuppressEmbeds and none.", nameof(flags)); | ||||
if (channel.Flags.HasFlag(ChannelFlags.RequireTag)) | |||||
throw new ArgumentException($"The channel {channel.Name} requires posts to have at least one tag."); | |||||
var args = new CreateMultipartPostAsync(attachments.ToArray()) | var args = new CreateMultipartPostAsync(attachments.ToArray()) | ||||
{ | { | ||||
@@ -1,3 +1,4 @@ | |||||
using Discord.API; | |||||
using Discord.API.Rest; | using Discord.API.Rest; | ||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
@@ -252,6 +253,7 @@ namespace Discord.Rest | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | Deny = overwrite.Permissions.DenyValue.ToString() | ||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
DefaultAutoArchiveDuration = props.AutoArchiveDuration | |||||
}; | }; | ||||
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); | ||||
return RestTextChannel.Create(client, guild, model); | return RestTextChannel.Create(client, guild, model); | ||||
@@ -338,6 +340,65 @@ namespace Discord.Rest | |||||
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); | ||||
return RestCategoryChannel.Create(client, guild, model); | return RestCategoryChannel.Create(client, guild, model); | ||||
} | } | ||||
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c>.</exception> | |||||
public static async Task<RestForumChannel> CreateForumChannelAsync(IGuild guild, BaseDiscordClient client, | |||||
string name, RequestOptions options, Action<ForumChannelProperties> func = null) | |||||
{ | |||||
if (name == null) | |||||
throw new ArgumentNullException(paramName: nameof(name)); | |||||
var props = new ForumChannelProperties(); | |||||
func?.Invoke(props); | |||||
Preconditions.AtMost(props.Tags.IsSpecified ? props.Tags.Value.Count() : 0, 5, nameof(props.Tags), "Forum channel can have max 20 tags."); | |||||
var args = new CreateGuildChannelParams(name, ChannelType.Forum) | |||||
{ | |||||
Position = props.Position, | |||||
Overwrites = props.PermissionOverwrites.IsSpecified | |||||
? props.PermissionOverwrites.Value.Select(overwrite => new API.Overwrite | |||||
{ | |||||
TargetId = overwrite.TargetId, | |||||
TargetType = overwrite.TargetType, | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | |||||
: Optional.Create<API.Overwrite[]>(), | |||||
SlowModeInterval = props.ThreadCreationInterval, | |||||
AvailableTags = props.Tags.GetValueOrDefault(Array.Empty<ForumTagProperties>()).Select( | |||||
x => new ModifyForumTagParams | |||||
{ | |||||
Id = x.Id, | |||||
Name = x.Name, | |||||
EmojiId = x.Emoji is Emote emote | |||||
? emote.Id | |||||
: Optional<ulong?>.Unspecified, | |||||
EmojiName = x.Emoji is Emoji emoji | |||||
? emoji.Name | |||||
: Optional<string>.Unspecified, | |||||
Moderated = x.IsModerated | |||||
}).ToArray(), | |||||
DefaultReactionEmoji = props.DefaultReactionEmoji.IsSpecified | |||||
? new API.ModifyForumReactionEmojiParams | |||||
{ | |||||
EmojiId = props.DefaultReactionEmoji.Value is Emote emote ? | |||||
emote.Id : Optional<ulong?>.Unspecified, | |||||
EmojiName = props.DefaultReactionEmoji.Value is Emoji emoji ? | |||||
emoji.Name : Optional<string>.Unspecified | |||||
} | |||||
: Optional<ModifyForumReactionEmojiParams>.Unspecified, | |||||
ThreadRateLimitPerUser = props.DefaultSlowModeInterval, | |||||
CategoryId = props.CategoryId, | |||||
IsNsfw = props.IsNsfw, | |||||
Topic = props.Topic, | |||||
DefaultAutoArchiveDuration = props.AutoArchiveDuration, | |||||
DefaultSortOrder = props.DefaultSortOrder.GetValueOrDefault(ForumSortOrder.LatestActivity) | |||||
}; | |||||
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); | |||||
return RestForumChannel.Create(client, guild, model); | |||||
} | |||||
#endregion | #endregion | ||||
#region Voice Regions | #region Voice Regions | ||||
@@ -710,6 +710,19 @@ namespace Discord.Rest | |||||
public Task<RestCategoryChannel> CreateCategoryChannelAsync(string name, Action<GuildChannelProperties> func = null, RequestOptions options = null) | public Task<RestCategoryChannel> CreateCategoryChannelAsync(string name, Action<GuildChannelProperties> func = null, RequestOptions options = null) | ||||
=> GuildHelper.CreateCategoryChannelAsync(this, Discord, name, options, func); | => GuildHelper.CreateCategoryChannelAsync(this, Discord, name, options, func); | ||||
/// <summary> | |||||
/// Creates a category channel with the provided name. | |||||
/// </summary> | |||||
/// <param name="name">The name of the new channel.</param> | |||||
/// <param name="func">The delegate containing the properties to be applied to the channel upon its creation.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <exception cref="ArgumentNullException"><paramref name="name" /> is <see langword="null"/>.</exception> | |||||
/// <returns> | |||||
/// The created category channel. | |||||
/// </returns> | |||||
public Task<RestForumChannel> CreateForumChannelAsync(string name, Action<ForumChannelProperties> func = null, RequestOptions options = null) | |||||
=> GuildHelper.CreateForumChannelAsync(this, Discord, name, options, func); | |||||
/// <summary> | /// <summary> | ||||
/// Gets a collection of all the voice regions this guild can access. | /// Gets a collection of all the voice regions this guild can access. | ||||
/// </summary> | /// </summary> | ||||
@@ -1370,6 +1383,9 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<ICategoryChannel> IGuild.CreateCategoryAsync(string name, Action<GuildChannelProperties> func, RequestOptions options) | async Task<ICategoryChannel> IGuild.CreateCategoryAsync(string name, Action<GuildChannelProperties> func, RequestOptions options) | ||||
=> await CreateCategoryChannelAsync(name, func, options).ConfigureAwait(false); | => await CreateCategoryChannelAsync(name, func, options).ConfigureAwait(false); | ||||
/// <inheritdoc /> | |||||
async Task<IForumChannel> IGuild.CreateForumChannelAsync(string name, Action<ForumChannelProperties> func, RequestOptions options) | |||||
=> await CreateForumChannelAsync(name, func, options).ConfigureAwait(false); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IReadOnlyCollection<IVoiceRegion>> IGuild.GetVoiceRegionsAsync(RequestOptions options) | async Task<IReadOnlyCollection<IVoiceRegion>> IGuild.GetVoiceRegionsAsync(RequestOptions options) | ||||
@@ -27,9 +27,33 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public IReadOnlyCollection<ForumTag> Tags { get; private set; } | public IReadOnlyCollection<ForumTag> Tags { get; private set; } | ||||
/// <inheritdoc/> | |||||
public int ThreadCreationInterval { get; private set; } | |||||
/// <inheritdoc/> | |||||
public int DefaultSlowModeInterval { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string Mention => MentionUtils.MentionChannel(Id); | public string Mention => MentionUtils.MentionChannel(Id); | ||||
/// <inheritdoc/> | |||||
public ulong? CategoryId { get; private set; } | |||||
/// <inheritdoc/> | |||||
public IEmote DefaultReactionEmoji { get; private set; } | |||||
/// <inheritdoc/> | |||||
public ForumSortOrder? DefaultSortOrder { get; private set; } | |||||
/// <summary> | |||||
/// Gets the parent (category) of this channel in the guild's channel list. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// An <see cref="ICategoryChannel"/> representing the parent of this channel; <c>null</c> if none is set. | |||||
/// </returns> | |||||
public ICategoryChannel Category | |||||
=> CategoryId.HasValue ? Guild.GetChannel(CategoryId.Value) as ICategoryChannel : null; | |||||
internal SocketForumChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) : base(discord, id, guild) { } | internal SocketForumChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) : base(discord, id, guild) { } | ||||
internal new static SocketForumChannel Create(SocketGuild guild, ClientState state, Model model) | internal new static SocketForumChannel Create(SocketGuild guild, ClientState state, Model model) | ||||
@@ -46,46 +70,70 @@ namespace Discord.WebSocket | |||||
Topic = model.Topic.GetValueOrDefault(); | Topic = model.Topic.GetValueOrDefault(); | ||||
DefaultAutoArchiveDuration = model.AutoArchiveDuration.GetValueOrDefault(ThreadArchiveDuration.OneDay); | DefaultAutoArchiveDuration = model.AutoArchiveDuration.GetValueOrDefault(ThreadArchiveDuration.OneDay); | ||||
if (model.ThreadRateLimitPerUser.IsSpecified) | |||||
DefaultSlowModeInterval = model.ThreadRateLimitPerUser.Value; | |||||
if (model.SlowMode.IsSpecified) | |||||
ThreadCreationInterval = model.SlowMode.Value; | |||||
DefaultSortOrder = model.DefaultSortOrder.GetValueOrDefault(); | |||||
Tags = model.ForumTags.GetValueOrDefault(Array.Empty<API.ForumTags>()).Select( | Tags = model.ForumTags.GetValueOrDefault(Array.Empty<API.ForumTags>()).Select( | ||||
x => new ForumTag(x.Id, x.Name, x.EmojiId.GetValueOrDefault(null), x.EmojiName.GetValueOrDefault()) | |||||
x => new ForumTag(x.Id, x.Name, x.EmojiId.GetValueOrDefault(null), x.EmojiName.GetValueOrDefault(), x.Moderated) | |||||
).ToImmutableArray(); | ).ToImmutableArray(); | ||||
if (model.DefaultReactionEmoji.IsSpecified && model.DefaultReactionEmoji.Value is not null) | |||||
{ | |||||
if (model.DefaultReactionEmoji.Value.EmojiId.HasValue && model.DefaultReactionEmoji.Value.EmojiId.Value != 0) | |||||
DefaultReactionEmoji = new Emote(model.DefaultReactionEmoji.Value.EmojiId.GetValueOrDefault(), null, false); | |||||
else if (model.DefaultReactionEmoji.Value.EmojiName.IsSpecified) | |||||
DefaultReactionEmoji = new Emoji(model.DefaultReactionEmoji.Value.EmojiName.Value); | |||||
else | |||||
DefaultReactionEmoji = null; | |||||
} | |||||
CategoryId = model.CategoryId.GetValueOrDefault(); | |||||
} | } | ||||
/// <inheritdoc cref="IForumChannel.CreatePostAsync(string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
public Task<RestThreadChannel> CreatePostAsync(string title, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | |||||
/// <inheritdoc /> | |||||
public virtual Task ModifyAsync(Action<ForumChannelProperties> func, RequestOptions options = null) | |||||
=> ForumHelper.ModifyAsync(this, Discord, func, options); | |||||
/// <inheritdoc cref="IForumChannel.CreatePostAsync(string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public Task<RestThreadChannel> CreatePostAsync(string title, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()); | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | ||||
AllowedMentions allowedMentions = null, MessageComponent components = null, | AllowedMentions allowedMentions = null, MessageComponent components = null, | ||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
{ | { | ||||
using var file = new FileAttachment(filePath, isSpoiler: isSpoiler); | using var file = new FileAttachment(filePath, isSpoiler: isSpoiler); | ||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | |||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()).ConfigureAwait(false); | |||||
} | } | ||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, Stream, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, Stream, string, ThreadArchiveDuration, int?, string, Embed, RequestOptions, bool, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public async Task<RestThreadChannel> CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, | ||||
AllowedMentions allowedMentions = null, MessageComponent components = null, | AllowedMentions allowedMentions = null, MessageComponent components = null, | ||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
{ | { | ||||
using var file = new FileAttachment(stream, filename, isSpoiler: isSpoiler); | using var file = new FileAttachment(stream, filename, isSpoiler: isSpoiler); | ||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | |||||
return await ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { file }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()).ConfigureAwait(false); | |||||
} | } | ||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, FileAttachment, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFileAsync(string, FileAttachment, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public Task<RestThreadChannel> CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public Task<RestThreadChannel> CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | ||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { attachment }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | |||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, new FileAttachment[] { attachment }, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()); | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFilesAsync(string, IEnumerable{FileAttachment}, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||||
/// <inheritdoc cref="IForumChannel.CreatePostWithFilesAsync(string, IEnumerable{FileAttachment}, ThreadArchiveDuration, int?, string, Embed, RequestOptions, AllowedMentions, MessageComponent, ISticker[], Embed[], MessageFlags, ForumTag[])"/> | |||||
public Task<RestThreadChannel> CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | public Task<RestThreadChannel> CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay, | ||||
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | ||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | |||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null) | |||||
=> ThreadHelper.CreatePostAsync(this, Discord, title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags, tags?.Select(tag => tag.Id).ToArray()); | |||||
/// <inheritdoc cref="IForumChannel.GetActiveThreadsAsync(RequestOptions)"/> | /// <inheritdoc cref="IForumChannel.GetActiveThreadsAsync(RequestOptions)"/> | ||||
public Task<IReadOnlyCollection<RestThreadChannel>> GetActiveThreadsAsync(RequestOptions options = null) | public Task<IReadOnlyCollection<RestThreadChannel>> GetActiveThreadsAsync(RequestOptions options = null) | ||||
@@ -112,17 +160,41 @@ namespace Discord.WebSocket | |||||
=> await GetPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | => await GetPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | ||||
async Task<IReadOnlyCollection<IThreadChannel>> IForumChannel.GetJoinedPrivateArchivedThreadsAsync(int? limit, DateTimeOffset? before, RequestOptions options) | async Task<IReadOnlyCollection<IThreadChannel>> IForumChannel.GetJoinedPrivateArchivedThreadsAsync(int? limit, DateTimeOffset? before, RequestOptions options) | ||||
=> await GetJoinedPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | => await GetJoinedPrivateArchivedThreadsAsync(limit, before, options).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostAsync(string title, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostAsync(string title, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostAsync(title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostAsync(title, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, string filePath, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFileAsync(title, filePath, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostWithFileAsync(title, filePath, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFileAsync(title, stream, filename, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostWithFileAsync(title, stream, filename, archiveDuration, slowmode, text, embed, options, isSpoiler, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFileAsync(string title, FileAttachment attachment, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFileAsync(title, attachment, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | => await CreatePostWithFileAsync(title, attachment, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags).ConfigureAwait(false); | ||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags) | |||||
async Task<IThreadChannel> IForumChannel.CreatePostWithFilesAsync(string title, IEnumerable<FileAttachment> attachments, ThreadArchiveDuration archiveDuration, int? slowmode, string text, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageComponent components, ISticker[] stickers, Embed[] embeds, MessageFlags flags, ForumTag[] tags) | |||||
=> await CreatePostWithFilesAsync(title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | => await CreatePostWithFilesAsync(title, attachments, archiveDuration, slowmode, text, embed, options, allowedMentions, components, stickers, embeds, flags); | ||||
#endregion | #endregion | ||||
#region INestedChannel | |||||
/// <inheritdoc /> | |||||
public virtual async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | |||||
public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options); | |||||
/// <inheritdoc /> | |||||
public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); | |||||
public virtual Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
=> throw new NotImplementedException(); | |||||
/// <inheritdoc /> | |||||
public virtual async Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||||
=> await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); | |||||
/// <inheritdoc /> | |||||
Task<ICategoryChannel> INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) | |||||
=> Task.FromResult(Category); | |||||
/// <inheritdoc /> | |||||
public virtual Task SyncPermissionsAsync(RequestOptions options = null) | |||||
=> ChannelHelper.SyncPermissionsAsync(this, Discord, options); | |||||
#endregion | |||||
} | } | ||||
} | } |
@@ -30,6 +30,9 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public int Position { get; private set; } | public int Position { get; private set; } | ||||
/// <inheritdoc /> | |||||
public ChannelFlags Flags { get; private set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public virtual IReadOnlyCollection<Overwrite> PermissionOverwrites => _overwrites; | public virtual IReadOnlyCollection<Overwrite> PermissionOverwrites => _overwrites; | ||||
/// <summary> | /// <summary> | ||||
@@ -74,6 +77,8 @@ namespace Discord.WebSocket | |||||
for (int i = 0; i < overwrites.Length; i++) | for (int i = 0; i < overwrites.Length; i++) | ||||
newOverwrites.Add(overwrites[i].ToEntity()); | newOverwrites.Add(overwrites[i].ToEntity()); | ||||
_overwrites = newOverwrites.ToImmutable(); | _overwrites = newOverwrites.ToImmutable(); | ||||
Flags = model.Flags.GetValueOrDefault(ChannelFlags.None); | |||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -89,6 +89,9 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public bool? IsInvitable { get; private set; } | public bool? IsInvitable { get; private set; } | ||||
/// <inheritdoc/> | |||||
public IReadOnlyCollection<ulong> AppliedTags { get; private set; } | |||||
/// <inheritdoc cref="IThreadChannel.CreatedAt"/> | /// <inheritdoc cref="IThreadChannel.CreatedAt"/> | ||||
public override DateTimeOffset CreatedAt { get; } | public override DateTimeOffset CreatedAt { get; } | ||||
@@ -149,6 +152,8 @@ namespace Discord.WebSocket | |||||
} | } | ||||
HasJoined = model.ThreadMember.IsSpecified; | HasJoined = model.ThreadMember.IsSpecified; | ||||
AppliedTags = model.AppliedTags.GetValueOrDefault(Array.Empty<ulong>()).ToImmutableArray(); | |||||
} | } | ||||
internal IReadOnlyCollection<SocketThreadUser> RemoveUsers(ulong[] users) | internal IReadOnlyCollection<SocketThreadUser> RemoveUsers(ulong[] users) | ||||
@@ -334,12 +339,13 @@ namespace Discord.WebSocket | |||||
=> throw new NotSupportedException("This method is not supported in threads."); | => throw new NotSupportedException("This method is not supported in threads."); | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
/// <remarks> | |||||
/// <b>This method is not supported in threads.</b> | |||||
/// </remarks> | |||||
public override Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null) | public override Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null) | ||||
=> ThreadHelper.ModifyAsync(this, Discord, func, options); | => ThreadHelper.ModifyAsync(this, Discord, func, options); | ||||
/// <inheritdoc/> | |||||
public Task ModifyAsync(Action<ThreadChannelProperties> func, RequestOptions options = null) | |||||
=> ThreadHelper.ModifyAsync(this, Discord, func, options); | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
/// <remarks> | /// <remarks> | ||||
/// <b>This method is not supported in threads.</b> | /// <b>This method is not supported in threads.</b> | ||||
@@ -302,6 +302,16 @@ namespace Discord.WebSocket | |||||
/// </returns> | /// </returns> | ||||
public IReadOnlyCollection<SocketThreadChannel> ThreadChannels | public IReadOnlyCollection<SocketThreadChannel> ThreadChannels | ||||
=> Channels.OfType<SocketThreadChannel>().ToImmutableArray(); | => Channels.OfType<SocketThreadChannel>().ToImmutableArray(); | ||||
/// <summary> | |||||
/// Gets a collection of all forum channels in this guild. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A read-only collection of forum channels found within this guild. | |||||
/// </returns> | |||||
public IReadOnlyCollection<SocketForumChannel> ForumChannels | |||||
=> Channels.OfType<SocketForumChannel>().ToImmutableArray(); | |||||
/// <summary> | /// <summary> | ||||
/// Gets the current logged-in user. | /// Gets the current logged-in user. | ||||
/// </summary> | /// </summary> | ||||
@@ -790,6 +800,7 @@ namespace Discord.WebSocket | |||||
/// </returns> | /// </returns> | ||||
public Task<RestStageChannel> CreateStageChannelAsync(string name, Action<VoiceChannelProperties> func = null, RequestOptions options = null) | public Task<RestStageChannel> CreateStageChannelAsync(string name, Action<VoiceChannelProperties> func = null, RequestOptions options = null) | ||||
=> GuildHelper.CreateStageChannelAsync(this, Discord, name, options, func); | => GuildHelper.CreateStageChannelAsync(this, Discord, name, options, func); | ||||
/// <summary> | /// <summary> | ||||
/// Creates a new channel category in this guild. | /// Creates a new channel category in this guild. | ||||
/// </summary> | /// </summary> | ||||
@@ -804,6 +815,20 @@ namespace Discord.WebSocket | |||||
public Task<RestCategoryChannel> CreateCategoryChannelAsync(string name, Action<GuildChannelProperties> func = null, RequestOptions options = null) | public Task<RestCategoryChannel> CreateCategoryChannelAsync(string name, Action<GuildChannelProperties> func = null, RequestOptions options = null) | ||||
=> GuildHelper.CreateCategoryChannelAsync(this, Discord, name, options, func); | => GuildHelper.CreateCategoryChannelAsync(this, Discord, name, options, func); | ||||
/// <summary> | |||||
/// Creates a new channel forum in this guild. | |||||
/// </summary> | |||||
/// <param name="name">The new name for the forum.</param> | |||||
/// <param name="func">The delegate containing the properties to be applied to the channel upon its creation.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <see langword="null"/>.</exception> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous creation operation. The task result contains the newly created | |||||
/// forum channel. | |||||
/// </returns> | |||||
public Task<RestForumChannel> CreateForumChannelAsync(string name, Action<ForumChannelProperties> func = null, RequestOptions options = null) | |||||
=> GuildHelper.CreateForumChannelAsync(this, Discord, name, options, func); | |||||
internal SocketGuildChannel AddChannel(ClientState state, ChannelModel model) | internal SocketGuildChannel AddChannel(ClientState state, ChannelModel model) | ||||
{ | { | ||||
var channel = SocketGuildChannel.Create(this, state, model); | var channel = SocketGuildChannel.Create(this, state, model); | ||||
@@ -1897,6 +1922,9 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<ICategoryChannel> IGuild.CreateCategoryAsync(string name, Action<GuildChannelProperties> func, RequestOptions options) | async Task<ICategoryChannel> IGuild.CreateCategoryAsync(string name, Action<GuildChannelProperties> func, RequestOptions options) | ||||
=> await CreateCategoryChannelAsync(name, func, options).ConfigureAwait(false); | => await CreateCategoryChannelAsync(name, func, options).ConfigureAwait(false); | ||||
/// <inheritdoc /> | |||||
async Task<IForumChannel> IGuild.CreateForumChannelAsync(string name, Action<ForumChannelProperties> func, RequestOptions options) | |||||
=> await CreateForumChannelAsync(name, func, options).ConfigureAwait(false); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IReadOnlyCollection<IVoiceRegion>> IGuild.GetVoiceRegionsAsync(RequestOptions options) | async Task<IReadOnlyCollection<IVoiceRegion>> IGuild.GetVoiceRegionsAsync(RequestOptions options) | ||||
@@ -20,6 +20,8 @@ namespace Discord | |||||
public DateTimeOffset CreatedAt => throw new NotImplementedException(); | public DateTimeOffset CreatedAt => throw new NotImplementedException(); | ||||
public ulong Id => throw new NotImplementedException(); | public ulong Id => throw new NotImplementedException(); | ||||
public ChannelFlags Flags => throw new NotImplementedException(); | |||||
public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | ||||
{ | { | ||||
@@ -34,6 +34,8 @@ namespace Discord | |||||
public ulong Id => throw new NotImplementedException(); | public ulong Id => throw new NotImplementedException(); | ||||
public ChannelFlags Flags => throw new NotImplementedException(); | |||||
public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | ||||
{ | { | ||||
throw new NotImplementedException(); | throw new NotImplementedException(); | ||||
@@ -36,6 +36,8 @@ namespace Discord | |||||
public string Mention => throw new NotImplementedException(); | public string Mention => throw new NotImplementedException(); | ||||
public ChannelFlags Flags => throw new NotImplementedException(); | |||||
public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) => throw new NotImplementedException(); | public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) => throw new NotImplementedException(); | ||||
public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) => throw new NotImplementedException(); | public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) => throw new NotImplementedException(); | ||||
public Task<IAudioClient> ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false) => throw new NotImplementedException(); | public Task<IAudioClient> ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false) => throw new NotImplementedException(); | ||||