@@ -7,7 +7,7 @@ public async Task SendAndReactAsync(ISocketMessageChannel channel) | |||
var message = await channel.SendMessageAsync("I am a message."); | |||
// Creates a Unicode-based emoji based on the Unicode string. | |||
// This is effctively the same as new Emoji("💕"). | |||
// This is effectively the same as new Emoji("💕"). | |||
var heartEmoji = new Emoji("\U0001f495"); | |||
// Reacts to the message with the Emoji. | |||
await message.AddReactionAsync(heartEmoji); | |||
@@ -24,7 +24,7 @@ remarks: *content | |||
> [!NOTE] | |||
> A valid @Discord.Emote format is `<:emoteName:emoteId>`. This can be | |||
> obtained by escaping with a `\` in front of the emote using the | |||
> Discord chat client. | |||
> Discord chat client. | |||
This class represents a custom emoji. This type of emoji can be | |||
created via the @Discord.Emote.Parse* or @Discord.Emote.TryParse* | |||
@@ -42,11 +42,15 @@ remarks: *content | |||
> [!NOTE] | |||
> A valid @Discord.Emoji format is Unicode-based. This means only | |||
> something like `🙃` or `\U0001f643` would work, instead of | |||
> something like `🙃` or `\U0001f643` would work, instead of | |||
> `:upside_down:`. | |||
> | |||
> A Unicode-based emoji can be obtained by escaping with a `\` in | |||
> front of the emote using the Discord chat client or by looking up on | |||
> [Emojipedia](https://emojipedia.org). | |||
This class represents a standard Unicode-based emoji. This type of emoji | |||
can be created by passing the unicode into its constructor. | |||
can be created by passing the Unicode into the constructor. | |||
--- | |||
uid: Discord.IEmote | |||
@@ -15,10 +15,16 @@ namespace Discord.Commands | |||
/// </summary> | |||
public RunMode RunMode { get; set; } = RunMode.Default; | |||
/// <inheritdoc /> | |||
public CommandAttribute() | |||
{ | |||
Text = null; | |||
} | |||
/// <summary> | |||
/// Initializes a new <see cref="CommandAttribute" /> attribute with the specified name. | |||
/// </summary> | |||
/// <param name="text">The name of the command.</param> | |||
public CommandAttribute(string text) | |||
{ | |||
Text = text; | |||
@@ -2,19 +2,26 @@ using System; | |||
namespace Discord.Commands | |||
{ | |||
/// <summary> Marks the module as a command group. </summary> | |||
/// <summary> | |||
/// Marks the module as a command group. | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] | |||
public class GroupAttribute : Attribute | |||
{ | |||
/// <summary> Gets the prefix set for the module. </summary> | |||
/// <summary> | |||
/// Gets the prefix set for the module. | |||
/// </summary> | |||
public string Prefix { get; } | |||
/// <inheritdoc /> | |||
public GroupAttribute() | |||
{ | |||
Prefix = null; | |||
} | |||
/// <summary> Creates a <see cref="GroupAttribute"/> with the provided prefix. </summary> | |||
/// <param name="prefix"> The prefix of the module group. </param> | |||
/// <summary> | |||
/// Initializes a new <see cref="GroupAttribute" /> with the provided prefix. | |||
/// </summary> | |||
/// <param name="prefix">The prefix of the module group.</param> | |||
public GroupAttribute(string prefix) | |||
{ | |||
Prefix = prefix; | |||
@@ -14,8 +14,10 @@ namespace Discord.Commands | |||
/// </summary> | |||
public string Text { get; } | |||
/// <summary> Marks the public name of a command, module, or parameter with the provided name. </summary> | |||
/// <param name="text"> The public name of the object. </param> | |||
/// <summary> | |||
/// Marks the public name of a command, module, or parameter with the provided name. | |||
/// </summary> | |||
/// <param name="text">The public name of the object.</param> | |||
public NameAttribute(string text) | |||
{ | |||
Text = text; | |||
@@ -4,20 +4,24 @@ using System.Reflection; | |||
namespace Discord.Commands | |||
{ | |||
/// <summary> Marks the <see cref="Type"/> to be read by the specified <see cref="TypeReader"/>. </summary> | |||
/// <summary> | |||
/// Marks the <see cref="Type"/> to be read by the specified <see cref="TypeReader" />. | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] | |||
public class OverrideTypeReaderAttribute : Attribute | |||
{ | |||
private static readonly TypeInfo _typeReaderTypeInfo = typeof(TypeReader).GetTypeInfo(); | |||
private static readonly TypeInfo TypeReaderTypeInfo = typeof(TypeReader).GetTypeInfo(); | |||
/// <summary> Gets the specified <see cref="TypeReader"/> of the parameter. </summary> | |||
/// <summary> | |||
/// Gets the specified <see cref="TypeReader"/> of the parameter. | |||
/// </summary> | |||
public Type TypeReader { get; } | |||
/// <summary> Marks the parameter to be read with the specified <see cref="TypeReader"/>. </summary> | |||
/// <inheritdoc/> | |||
/// <param name="overridenTypeReader">The <see cref="TypeReader"/> to be used with the parameter. </param> | |||
public OverrideTypeReaderAttribute(Type overridenTypeReader) | |||
{ | |||
if (!_typeReaderTypeInfo.IsAssignableFrom(overridenTypeReader.GetTypeInfo())) | |||
if (!TypeReaderTypeInfo.IsAssignableFrom(overridenTypeReader.GetTypeInfo())) | |||
throw new ArgumentException($"{nameof(overridenTypeReader)} must inherit from {nameof(TypeReader)}."); | |||
TypeReader = overridenTypeReader; | |||
@@ -9,6 +9,13 @@ namespace Discord.Commands | |||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] | |||
public abstract class ParameterPreconditionAttribute : Attribute | |||
{ | |||
/// <summary> | |||
/// Checks whether the condition is met before execution of the command. | |||
/// </summary> | |||
/// <param name="context">The context of the command.</param> | |||
/// <param name="parameter">The parameter of the command being checked against.</param> | |||
/// <param name="value">The raw value of the type.</param> | |||
/// <param name="services">The service collection used for dependency injection.</param> | |||
public abstract Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, ParameterInfo parameter, object value, IServiceProvider services); | |||
} | |||
} |
@@ -11,11 +11,9 @@ namespace Discord.Commands | |||
/// Specify a group that this precondition belongs to. | |||
/// </summary> | |||
/// <remarks> | |||
/// <para> | |||
/// <see cref="Preconditions" /> of the same group require only one of the preconditions to pass in | |||
/// order to be successful (A || B). Specifying <see cref="Group" /> = <see langword="null" /> or not | |||
/// at all will require *all* preconditions to pass, just like normal (A && B). | |||
/// </para> | |||
/// <see cref="Preconditions" /> of the same group require only one of the preconditions to pass in order to | |||
/// be successful (A || B). Specifying <see cref="Group" /> = <see langword="null" /> or not at all will | |||
/// require *all* preconditions to pass, just like normal (A && B). | |||
/// </remarks> | |||
public string Group { get; set; } = null; | |||
@@ -4,43 +4,49 @@ using System.Threading.Tasks; | |||
namespace Discord.Commands | |||
{ | |||
/// <summary> | |||
/// Requires the bot to have a specific permission in the channel a command is invoked in. | |||
/// Requires the bot to have a specific permission in the channel a command is invoked in. | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | |||
public class RequireBotPermissionAttribute : PreconditionAttribute | |||
{ | |||
/// <summary> | |||
/// Gets the specified <see cref="Discord.GuildPermission" /> of the precondition. | |||
/// </summary> | |||
public GuildPermission? GuildPermission { get; } | |||
/// <summary> | |||
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition. | |||
/// </summary> | |||
public ChannelPermission? ChannelPermission { get; } | |||
/// <summary> | |||
/// Requires the bot account to have a specific <see cref="GuildPermission"/>. | |||
/// Requires the bot account to have a specific <see cref="Discord.GuildPermission" />. | |||
/// </summary> | |||
/// <remarks>This precondition will always fail if the command is being invoked in a private channel.</remarks> | |||
/// <param name="permission">The GuildPermission that the bot must have. Multiple permissions can be specified by ORing the permissions together.</param> | |||
/// <remarks> | |||
/// This precondition will always fail if the command is being invoked in a <see cref="IPrivateChannel"/>. | |||
/// </remarks> | |||
/// <param name="permission"> | |||
/// The <see cref="Discord.GuildPermission"/> that the bot must have. Multiple permissions can be specified | |||
/// by ORing the permissions together. | |||
/// </param> | |||
public RequireBotPermissionAttribute(GuildPermission permission) | |||
{ | |||
GuildPermission = permission; | |||
ChannelPermission = null; | |||
} | |||
/// <summary> | |||
/// Requires that the bot account to have a specific <see cref="ChannelPermission"/>. | |||
/// Requires that the bot account to have a specific <see cref="Discord.ChannelPermission"/>. | |||
/// </summary> | |||
/// <param name="permission">The ChannelPermission that the bot must have. Multiple permissions can be specified by ORing the permissions together.</param> | |||
/// <example> | |||
/// <code language="c#"> | |||
/// [Command("permission")] | |||
/// [RequireBotPermission(ChannelPermission.ManageMessages)] | |||
/// public async Task Purge() | |||
/// { | |||
/// } | |||
/// </code> | |||
/// </example> | |||
/// <param name="permission"> | |||
/// The <see cref="Discord.ChannelPermission"/> that the bot must have. Multiple permissions can be | |||
/// specified by ORing the permissions together. | |||
/// </param> | |||
public RequireBotPermissionAttribute(ChannelPermission permission) | |||
{ | |||
ChannelPermission = permission; | |||
GuildPermission = null; | |||
} | |||
/// <inheritdoc /> | |||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | |||
{ | |||
IGuildUser guildUser = null; | |||
@@ -3,28 +3,38 @@ using System.Threading.Tasks; | |||
namespace Discord.Commands | |||
{ | |||
/// <summary> Defines the type of command context. </summary> | |||
/// <summary> | |||
/// Defines the type of command context (i.e. where the command is being executed). | |||
/// </summary> | |||
[Flags] | |||
public enum ContextType | |||
{ | |||
/// <summary> Specifies the command to be executed within a guild. </summary> | |||
/// <summary> | |||
/// Specifies the command to be executed within a guild. | |||
/// </summary> | |||
Guild = 0x01, | |||
/// <summary> Specifies the command to be executed within a DM. </summary> | |||
/// <summary> | |||
/// Specifies the command to be executed within a DM. | |||
/// </summary> | |||
DM = 0x02, | |||
/// <summary> Specifies the command to be executed within a group. </summary> | |||
/// <summary> | |||
/// Specifies the command to be executed within a group. | |||
/// </summary> | |||
Group = 0x04 | |||
} | |||
/// <summary> | |||
/// Requires the command to be invoked in a specified context (e.g. in guild, DM). | |||
/// Requires the command to be invoked in a specified context (e.g. in guild, DM). | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | |||
public class RequireContextAttribute : PreconditionAttribute | |||
{ | |||
/// <summary> Gets the context required to execute the command. </summary> | |||
/// <summary> | |||
/// Gets the context required to execute the command. | |||
/// </summary> | |||
public ContextType Contexts { get; } | |||
/// <summary> Requires that the command be invoked in the specified context. </summary> | |||
/// <summary> Requires the command to be invoked in the specified context. </summary> | |||
/// <param name="contexts">The type of context the command can be invoked in. Multiple contexts can be specified by ORing the contexts together.</param> | |||
/// <example> | |||
/// <code language="c#"> | |||
@@ -4,11 +4,12 @@ using System.Threading.Tasks; | |||
namespace Discord.Commands | |||
{ | |||
/// <summary> | |||
/// Requires the command to be invoked in a channel marked NSFW. | |||
/// Requires the command to be invoked in a channel marked NSFW. | |||
/// </summary> | |||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | |||
public class RequireNsfwAttribute : PreconditionAttribute | |||
{ | |||
/// <inheritdoc /> | |||
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | |||
{ | |||
if (context.Channel is ITextChannel text && text.IsNsfw) | |||
@@ -10,6 +10,7 @@ namespace Discord.Commands | |||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | |||
public class RequireOwnerAttribute : PreconditionAttribute | |||
{ | |||
/// <inheritdoc /> | |||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | |||
{ | |||
switch (context.Client.TokenType) | |||
@@ -9,39 +9,44 @@ namespace Discord.Commands | |||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | |||
public class RequireUserPermissionAttribute : PreconditionAttribute | |||
{ | |||
/// <summary> | |||
/// Gets the specified <see cref="Discord.GuildPermission" /> of the precondition. | |||
/// </summary> | |||
public GuildPermission? GuildPermission { get; } | |||
/// <summary> | |||
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition. | |||
/// </summary> | |||
public ChannelPermission? ChannelPermission { get; } | |||
/// <summary> | |||
/// Requires that the user invoking the command to have a specific <see cref="GuildPermission"/>. | |||
/// Requires that the user invoking the command to have a specific <see cref="Discord.GuildPermission" />. | |||
/// </summary> | |||
/// <remarks>This precondition will always fail if the command is being invoked in a private channel.</remarks> | |||
/// <param name="permission">The GuildPermission that the user must have. Multiple permissions can be specified by ORing the permissions together.</param> | |||
/// <remarks> | |||
/// This precondition will always fail if the command is being invoked in a <see cref="IPrivateChannel"/>. | |||
/// </remarks> | |||
/// <param name="permission"> | |||
/// The <see cref="Discord.GuildPermission" /> that the user must have. Multiple permissions can be | |||
/// specified by ORing the permissions together. | |||
/// </param> | |||
public RequireUserPermissionAttribute(GuildPermission permission) | |||
{ | |||
GuildPermission = permission; | |||
ChannelPermission = null; | |||
} | |||
/// <summary> | |||
/// Requires that the user invoking the command to have a specific <see cref="ChannelPermission"/>. | |||
/// Requires that the user invoking the command to have a specific <see cref="Discord.ChannelPermission"/>. | |||
/// </summary> | |||
/// <param name="permission">The ChannelPermission that the user must have. Multiple permissions can be specified by ORing the permissions together.</param> | |||
/// <example> | |||
/// <code language="c#"> | |||
/// [Command("permission")] | |||
/// [RequireUserPermission(ChannelPermission.ReadMessageHistory | ChannelPermission.ReadMessages)] | |||
/// public async Task HasPermission() | |||
/// { | |||
/// await ReplyAsync("You can read messages and the message history!"); | |||
/// } | |||
/// </code> | |||
/// </example> | |||
/// <param name="permission"> | |||
/// The <see cref="Discord.ChannelPermission"/> that the user must have. Multiple permissions can be | |||
/// specified by ORing the permissions together. | |||
/// </param> | |||
public RequireUserPermissionAttribute(ChannelPermission permission) | |||
{ | |||
ChannelPermission = permission; | |||
GuildPermission = null; | |||
} | |||
/// <inheritdoc /> | |||
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | |||
{ | |||
var guildUser = context.User as IGuildUser; | |||
@@ -14,7 +14,7 @@ namespace Discord.Commands | |||
public int Priority { get; } | |||
/// <summary> | |||
/// Creates a new <see cref="PriorityAttribute" /> with the given priority. | |||
/// Initializes a new <see cref="PriorityAttribute" /> attribute with the given priority. | |||
/// </summary> | |||
public PriorityAttribute(int priority) | |||
{ | |||
@@ -1,8 +1,7 @@ | |||
using System; | |||
using System; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using System.Collections.Generic; | |||
using Microsoft.Extensions.DependencyInjection; | |||
namespace Discord.Commands.Builders | |||
{ | |||
@@ -140,4 +139,4 @@ namespace Discord.Commands.Builders | |||
return new CommandInfo(this, info, service); | |||
} | |||
} | |||
} | |||
} |
@@ -2,7 +2,6 @@ using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using System.Threading.Tasks; | |||
using Microsoft.Extensions.DependencyInjection; | |||
namespace Discord.Commands.Builders | |||
{ | |||
@@ -1,7 +1,6 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Threading.Tasks; | |||
using Microsoft.Extensions.DependencyInjection; | |||
namespace Discord.Commands | |||
{ | |||
@@ -6,7 +6,6 @@ using System.Linq; | |||
using System.Reflection; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Discord.Commands.Builders; | |||
using Discord.Logging; | |||
@@ -24,7 +24,7 @@ namespace Discord.Commands | |||
Error = error; | |||
ErrorReason = errorReason; | |||
} | |||
public static ParseResult FromSuccess(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues) | |||
{ | |||
for (int i = 0; i < argValues.Count; i++) | |||
@@ -2,6 +2,9 @@ using System.Diagnostics; | |||
namespace Discord.Commands | |||
{ | |||
/// <summary> | |||
/// Represents a result type for command preconditions. | |||
/// </summary> | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class PreconditionResult : IResult | |||
{ | |||
@@ -13,19 +16,40 @@ namespace Discord.Commands | |||
/// <inheritdoc/> | |||
public bool IsSuccess => !Error.HasValue; | |||
/// <summary> | |||
/// Initializes a new <see cref="PreconditionResult" /> class with the command <paramref name="error"/> type | |||
/// and reason. | |||
/// </summary> | |||
/// <param name="error">The type of failure.</param> | |||
/// <param name="errorReason">The reason of failure.</param> | |||
protected PreconditionResult(CommandError? error, string errorReason) | |||
{ | |||
Error = error; | |||
ErrorReason = errorReason; | |||
} | |||
/// <summary> | |||
/// Returns a <see cref="PreconditionResult" /> with no errors. | |||
/// </summary> | |||
public static PreconditionResult FromSuccess() | |||
=> new PreconditionResult(null, null); | |||
/// <summary> | |||
/// Returns a <see cref="PreconditionResult" /> with <see cref="CommandError.UnmetPrecondition" /> and the | |||
/// specified reason. | |||
/// </summary> | |||
/// <param name="reason">The reason of failure.</param> | |||
public static PreconditionResult FromError(string reason) | |||
=> new PreconditionResult(CommandError.UnmetPrecondition, reason); | |||
/// <summary> | |||
/// Returns a <see cref="PreconditionResult" /> with the specified <paramref name="result"/> type. | |||
/// </summary> | |||
/// <param name="result">The result of failure.</param> | |||
public static PreconditionResult FromError(IResult result) | |||
=> new PreconditionResult(result.Error, result.ErrorReason); | |||
/// <summary> | |||
/// Returns a string indicating whether the <see cref="PreconditionResult"/> is successful. | |||
/// </summary> | |||
public override string ToString() => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; | |||
private string DebuggerDisplay => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; | |||
} | |||
@@ -5,6 +5,11 @@ namespace Discord.Commands | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public abstract class RuntimeResult : IResult | |||
{ | |||
/// <summary> | |||
/// Initializes a new <see cref="RuntimeResult" /> class with the type of error and reason. | |||
/// </summary> | |||
/// <param name="error">The type of failure, or <see langword="null" /> if none.</param> | |||
/// <param name="reason">The reason of failure.</param> | |||
protected RuntimeResult(CommandError? error, string reason) | |||
{ | |||
Error = error; | |||
@@ -3,7 +3,7 @@ using System; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// A class containing the strings related to various Content Delivery Networks (CDNs). | |||
/// Represents a class containing the strings related to various Content Delivery Networks (CDNs). | |||
/// </summary> | |||
public static class CDN | |||
{ | |||
@@ -1,31 +1,33 @@ | |||
namespace Discord | |||
{ | |||
/// <summary> Specifies the severity of the log message. </summary> | |||
/// <summary> | |||
/// Specifies the severity of the log message. | |||
/// </summary> | |||
public enum LogSeverity | |||
{ | |||
/// <summary> | |||
/// Logs that contain the most severe level of error. | |||
/// This type of error indicate that immediate attention may be required. | |||
/// <summary> | |||
/// Logs that contain the most severe level of error. This type of error indicate that immediate attention | |||
/// may be required. | |||
/// </summary> | |||
Critical = 0, | |||
/// <summary> | |||
/// Logs that highlight when the flow of execution is stopped due to a failure. | |||
/// <summary> | |||
/// Logs that highlight when the flow of execution is stopped due to a failure. | |||
/// </summary> | |||
Error = 1, | |||
/// <summary> | |||
/// Logs that highlight an abnormal activity in the flow of execution. | |||
/// <summary> | |||
/// Logs that highlight an abnormal activity in the flow of execution. | |||
/// </summary> | |||
Warning = 2, | |||
/// <summary> | |||
/// Logs that track the general flow of the application. | |||
/// <summary> | |||
/// Logs that track the general flow of the application. | |||
/// </summary> | |||
Info = 3, | |||
/// <summary> | |||
/// Logs that are used for interactive investigation during development. | |||
/// <summary> | |||
/// Logs that are used for interactive investigation during development. | |||
/// </summary> | |||
Verbose = 4, | |||
/// <summary> | |||
/// Logs that contain the most detailed messages. | |||
/// <summary> | |||
/// Logs that contain the most detailed messages. | |||
/// </summary> | |||
Debug = 5 | |||
} | |||
@@ -3,20 +3,29 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
/// <summary> Contains an entity that may be cached. </summary> | |||
/// <typeparam name="TEntity"> The type of entity that is cached. </typeparam> | |||
/// <typeparam name="TId"> The type of this entity's ID. </typeparam> | |||
/// <summary> | |||
/// Represents a <see langword="struct"/> that contains an entity that may be cached. | |||
/// </summary> | |||
/// <typeparam name="TEntity">The type of entity that is cached.</typeparam> | |||
/// <typeparam name="TId">The type of this entity's ID.</typeparam> | |||
public struct Cacheable<TEntity, TId> | |||
where TEntity : IEntity<TId> | |||
where TId : IEquatable<TId> | |||
{ | |||
/// <summary> Indicates whether this entity is cached. </summary> | |||
/// <summary> | |||
/// Gets whether this entity is cached. | |||
/// </summary> | |||
public bool HasValue { get; } | |||
/// <summary> Gets the ID of this entity. </summary> | |||
/// <summary> | |||
/// Gets the ID of this entity. | |||
/// </summary> | |||
public TId Id { get; } | |||
/// <summary> Gets the entity if it could be pulled from cache. </summary> | |||
/// <summary> | |||
/// Gets the entity if it could be pulled from cache. | |||
/// </summary> | |||
/// <remarks> | |||
/// This value is not guaranteed to be set; in cases where the entity cannot be pulled from cache, it is null. | |||
/// This value is not guaranteed to be set; in cases where the entity cannot be pulled from cache, it is | |||
/// null. | |||
/// </remarks> | |||
public TEntity Value { get; } | |||
private Func<Task<TEntity>> DownloadFunc { get; } | |||
@@ -29,19 +38,27 @@ namespace Discord | |||
DownloadFunc = downloadFunc; | |||
} | |||
/// <summary> Downloads this entity to cache. </summary> | |||
/// <returns>An awaitable Task containing the downloaded entity.</returns> | |||
/// <summary> | |||
/// Downloads this entity to cache. | |||
/// </summary> | |||
/// <exception cref="Discord.Net.HttpException">Thrown when used from a user account.</exception> | |||
/// <exception cref="NullReferenceException">Thrown when the message is deleted.</exception> | |||
/// <returns> | |||
/// An awaitable <see cref="Task"/> containing the downloaded entity. | |||
/// </returns> | |||
public async Task<TEntity> DownloadAsync() | |||
{ | |||
return await DownloadFunc().ConfigureAwait(false); | |||
} | |||
/// <summary> Returns the cached entity if it exists; otherwise downloads it. </summary> | |||
/// <returns>An awaitable Task containing a cached or downloaded entity.</returns> | |||
/// <summary> | |||
/// Returns the cached entity if it exists; otherwise downloads it. | |||
/// </summary> | |||
/// <exception cref="Discord.Net.HttpException">Thrown when used from a user account.</exception> | |||
/// <exception cref="NullReferenceException">Thrown when the message is deleted and is not in cache.</exception> | |||
/// <returns> | |||
/// An awaitable <see cref="Task"/> containing a cached or downloaded entity. | |||
/// </returns> | |||
public async Task<TEntity> GetOrDownloadAsync() => HasValue ? Value : await DownloadAsync().ConfigureAwait(false); | |||
} | |||
} |
@@ -4,7 +4,7 @@ using System.Collections.Generic; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// Represents a collection of <see cref="IEqualityComparer{T}"/> for various Discord objects. | |||
/// Represents a collection of <see cref="IEqualityComparer{T}"/> for various Discord objects. | |||
/// </summary> | |||
public static class DiscordComparers | |||
{ | |||
@@ -4,30 +4,42 @@ using System.Text; | |||
namespace Discord | |||
{ | |||
/// <summary> A helper class for mention-related parsing. </summary> | |||
/// <summary> | |||
/// Represents a helper class for mention-related parsing. | |||
/// </summary> | |||
public static class MentionUtils | |||
{ | |||
private const char SanitizeChar = '\x200b'; | |||
//If the system can't be positive a user doesn't have a nickname, assume useNickname = true (source: Jake) | |||
internal static string MentionUser(string id, bool useNickname = true) => useNickname ? $"<@!{id}>" : $"<@{id}>"; | |||
/// <summary> Returns a mention string based on the user ID. </summary> | |||
/// <summary> | |||
/// Returns a mention string based on the user ID. | |||
/// </summary> | |||
public static string MentionUser(ulong id) => MentionUser(id.ToString(), true); | |||
internal static string MentionChannel(string id) => $"<#{id}>"; | |||
/// <summary> Returns a mention string based on the channel ID. </summary> | |||
/// <summary> | |||
/// Returns a mention string based on the channel ID. | |||
/// </summary> | |||
public static string MentionChannel(ulong id) => MentionChannel(id.ToString()); | |||
internal static string MentionRole(string id) => $"<@&{id}>"; | |||
/// <summary> Returns a mention string based on the role ID. </summary> | |||
/// <summary> | |||
/// Returns a mention string based on the role ID. | |||
/// </summary> | |||
public static string MentionRole(ulong id) => MentionRole(id.ToString()); | |||
/// <summary> Parses a provided user mention string. </summary> | |||
/// <summary> | |||
/// Parses a provided user mention string. | |||
/// </summary> | |||
public static ulong ParseUser(string text) | |||
{ | |||
if (TryParseUser(text, out ulong id)) | |||
return id; | |||
throw new ArgumentException("Invalid mention format", nameof(text)); | |||
} | |||
/// <summary> Tries to parse a provided user mention string. </summary> | |||
/// <summary> | |||
/// Tries to parse a provided user mention string. | |||
/// </summary> | |||
public static bool TryParseUser(string text, out ulong userId) | |||
{ | |||
if (text.Length >= 3 && text[0] == '<' && text[1] == '@' && text[text.Length - 1] == '>') | |||
@@ -44,14 +56,18 @@ namespace Discord | |||
return false; | |||
} | |||
/// <summary> Parses a provided channel mention string. </summary> | |||
/// <summary> | |||
/// Parses a provided channel mention string. | |||
/// </summary> | |||
public static ulong ParseChannel(string text) | |||
{ | |||
if (TryParseChannel(text, out ulong id)) | |||
return id; | |||
throw new ArgumentException("Invalid mention format", nameof(text)); | |||
} | |||
/// <summary>Tries to parse a provided channel mention string. </summary> | |||
/// <summary> | |||
/// Tries to parse a provided channel mention string. | |||
/// </summary> | |||
public static bool TryParseChannel(string text, out ulong channelId) | |||
{ | |||
if (text.Length >= 3 && text[0] == '<' && text[1] == '#' && text[text.Length - 1] == '>') | |||
@@ -65,14 +81,18 @@ namespace Discord | |||
return false; | |||
} | |||
/// <summary> Parses a provided role mention string. </summary> | |||
/// <summary> | |||
/// Parses a provided role mention string. | |||
/// </summary> | |||
public static ulong ParseRole(string text) | |||
{ | |||
if (TryParseRole(text, out ulong id)) | |||
return id; | |||
throw new ArgumentException("Invalid mention format", nameof(text)); | |||
} | |||
/// <summary>Tries to parse a provided role mention string. </summary> | |||
/// <summary> | |||
/// Tries to parse a provided role mention string. | |||
/// </summary> | |||
public static bool TryParseRole(string text, out ulong roleId) | |||
{ | |||
if (text.Length >= 4 && text[0] == '<' && text[1] == '@' && text[2] == '&' && text[text.Length - 1] == '>') | |||