[Feature] Add missing properties in forum & thread channels (#2469)
* 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 count
This commit is contained in:
22
src/Discord.Net.Core/Entities/Channels/ChannelFlags.cs
Normal file
22
src/Discord.Net.Core/Entities/Channels/ChannelFlags.cs
Normal file
@@ -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; }
|
||||
}
|
||||
17
src/Discord.Net.Core/Entities/Channels/ForumSortOrder.cs
Normal file
17
src/Discord.Net.Core/Entities/Channels/ForumSortOrder.cs
Normal file
@@ -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.
|
||||
/// </summary>
|
||||
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
|
||||
{
|
||||
public interface IForumChannel : IGuildChannel, IMentionable
|
||||
public interface IForumChannel : IGuildChannel, IMentionable, INestedChannel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the channel is NSFW.
|
||||
@@ -35,6 +35,55 @@ namespace Discord
|
||||
/// </summary>
|
||||
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>
|
||||
/// Creates a new post (thread) within the forum.
|
||||
/// </summary>
|
||||
@@ -52,12 +101,13 @@ namespace Discord
|
||||
/// <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="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>
|
||||
/// A task that represents the asynchronous creation operation.
|
||||
/// </returns>
|
||||
Task<IThreadChannel> 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);
|
||||
MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null);
|
||||
|
||||
/// <summary>
|
||||
/// 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="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="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous creation operation.
|
||||
/// </returns>
|
||||
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,
|
||||
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>
|
||||
/// 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="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="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous creation operation.
|
||||
/// </returns>
|
||||
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,
|
||||
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>
|
||||
/// 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="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="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous creation operation.
|
||||
/// </returns>
|
||||
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,
|
||||
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>
|
||||
/// Creates a new post (thread) within the forum.
|
||||
@@ -155,14 +208,15 @@ namespace Discord
|
||||
/// </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="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="tags">An array of <see cref="ForumTag"/> to be applied to the post.</param>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous creation operation.
|
||||
/// </returns>
|
||||
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,
|
||||
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>
|
||||
/// Gets a collection of active threads within this forum channel.
|
||||
|
||||
@@ -21,6 +21,17 @@ namespace Discord
|
||||
/// </returns>
|
||||
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>
|
||||
/// Gets the guild associated with this channel.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
@@ -56,6 +57,14 @@ namespace Discord
|
||||
/// </remarks>
|
||||
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>
|
||||
/// Gets when the thread was created.
|
||||
/// </summary>
|
||||
@@ -102,5 +111,16 @@ namespace Discord
|
||||
/// A task that represents the asynchronous operation of removing a user from this thread.
|
||||
/// </returns>
|
||||
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.Collections.Generic;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
@@ -39,20 +40,10 @@ namespace Discord
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 21600].</exception>
|
||||
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>
|
||||
/// Gets or sets the auto archive duration.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/Discord.Net.Core/Entities/ForumTags/ForumTag.cs
Normal file
67
src/Discord.Net.Core/Entities/ForumTags/ForumTag.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
191
src/Discord.Net.Core/Entities/ForumTags/ForumTagBuilder.cs
Normal file
191
src/Discord.Net.Core/Entities/ForumTags/ForumTagBuilder.cs
Normal file
@@ -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);
|
||||
}
|
||||
29
src/Discord.Net.Core/Entities/ForumTags/IForumTag.cs
Normal file
29
src/Discord.Net.Core/Entities/ForumTags/IForumTag.cs
Normal file
@@ -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>
|
||||
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>
|
||||
/// Gets a collection of all the voice regions this guild can access.
|
||||
/// </summary>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Discord
|
||||
String = 3,
|
||||
|
||||
/// <summary>
|
||||
/// An <see langword="int"/>.
|
||||
/// An <see langword="long"/>.
|
||||
/// </summary>
|
||||
Integer = 4,
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@ namespace Discord
|
||||
|
||||
case ITextChannel:
|
||||
return ChannelType.Text;
|
||||
|
||||
case IForumChannel:
|
||||
return ChannelType.Forum;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user