@@ -7,7 +7,7 @@ public async Task SendAndReactAsync(ISocketMessageChannel channel) | |||||
var message = await channel.SendMessageAsync("I am a message."); | var message = await channel.SendMessageAsync("I am a message."); | ||||
// Creates a Unicode-based emoji based on the Unicode string. | // 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"); | var heartEmoji = new Emoji("\U0001f495"); | ||||
// Reacts to the message with the Emoji. | // Reacts to the message with the Emoji. | ||||
await message.AddReactionAsync(heartEmoji); | await message.AddReactionAsync(heartEmoji); | ||||
@@ -24,7 +24,7 @@ remarks: *content | |||||
> [!NOTE] | > [!NOTE] | ||||
> A valid @Discord.Emote format is `<:emoteName:emoteId>`. This can be | > A valid @Discord.Emote format is `<:emoteName:emoteId>`. This can be | ||||
> obtained by escaping with a `\` in front of the emote using the | > 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 | This class represents a custom emoji. This type of emoji can be | ||||
created via the @Discord.Emote.Parse* or @Discord.Emote.TryParse* | created via the @Discord.Emote.Parse* or @Discord.Emote.TryParse* | ||||
@@ -42,11 +42,15 @@ remarks: *content | |||||
> [!NOTE] | > [!NOTE] | ||||
> A valid @Discord.Emoji format is Unicode-based. This means only | > 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:`. | > `: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 | 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 | uid: Discord.IEmote | ||||
@@ -15,10 +15,16 @@ namespace Discord.Commands | |||||
/// </summary> | /// </summary> | ||||
public RunMode RunMode { get; set; } = RunMode.Default; | public RunMode RunMode { get; set; } = RunMode.Default; | ||||
/// <inheritdoc /> | |||||
public CommandAttribute() | public CommandAttribute() | ||||
{ | { | ||||
Text = null; | 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) | public CommandAttribute(string text) | ||||
{ | { | ||||
Text = text; | Text = text; | ||||
@@ -2,19 +2,26 @@ using System; | |||||
namespace Discord.Commands | 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)] | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] | ||||
public class GroupAttribute : Attribute | 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; } | public string Prefix { get; } | ||||
/// <inheritdoc /> | |||||
public GroupAttribute() | public GroupAttribute() | ||||
{ | { | ||||
Prefix = null; | 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) | public GroupAttribute(string prefix) | ||||
{ | { | ||||
Prefix = prefix; | Prefix = prefix; | ||||
@@ -14,8 +14,10 @@ namespace Discord.Commands | |||||
/// </summary> | /// </summary> | ||||
public string Text { get; } | 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) | public NameAttribute(string text) | ||||
{ | { | ||||
Text = text; | Text = text; | ||||
@@ -4,20 +4,24 @@ using System.Reflection; | |||||
namespace Discord.Commands | 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)] | [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] | ||||
public class OverrideTypeReaderAttribute : Attribute | 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; } | 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> | /// <param name="overridenTypeReader">The <see cref="TypeReader"/> to be used with the parameter. </param> | ||||
public OverrideTypeReaderAttribute(Type overridenTypeReader) | public OverrideTypeReaderAttribute(Type overridenTypeReader) | ||||
{ | { | ||||
if (!_typeReaderTypeInfo.IsAssignableFrom(overridenTypeReader.GetTypeInfo())) | |||||
if (!TypeReaderTypeInfo.IsAssignableFrom(overridenTypeReader.GetTypeInfo())) | |||||
throw new ArgumentException($"{nameof(overridenTypeReader)} must inherit from {nameof(TypeReader)}."); | throw new ArgumentException($"{nameof(overridenTypeReader)} must inherit from {nameof(TypeReader)}."); | ||||
TypeReader = overridenTypeReader; | TypeReader = overridenTypeReader; | ||||
@@ -9,6 +9,13 @@ namespace Discord.Commands | |||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] | ||||
public abstract class ParameterPreconditionAttribute : Attribute | 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); | 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. | /// Specify a group that this precondition belongs to. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <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> | /// </remarks> | ||||
public string Group { get; set; } = null; | public string Group { get; set; } = null; | ||||
@@ -4,43 +4,49 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | /// <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> | /// </summary> | ||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | ||||
public class RequireBotPermissionAttribute : PreconditionAttribute | public class RequireBotPermissionAttribute : PreconditionAttribute | ||||
{ | { | ||||
/// <summary> | |||||
/// Gets the specified <see cref="Discord.GuildPermission" /> of the precondition. | |||||
/// </summary> | |||||
public GuildPermission? GuildPermission { get; } | public GuildPermission? GuildPermission { get; } | ||||
/// <summary> | |||||
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition. | |||||
/// </summary> | |||||
public ChannelPermission? ChannelPermission { get; } | public ChannelPermission? ChannelPermission { get; } | ||||
/// <summary> | /// <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> | /// </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) | public RequireBotPermissionAttribute(GuildPermission permission) | ||||
{ | { | ||||
GuildPermission = permission; | GuildPermission = permission; | ||||
ChannelPermission = null; | ChannelPermission = null; | ||||
} | } | ||||
/// <summary> | /// <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> | /// </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) | public RequireBotPermissionAttribute(ChannelPermission permission) | ||||
{ | { | ||||
ChannelPermission = permission; | ChannelPermission = permission; | ||||
GuildPermission = null; | GuildPermission = null; | ||||
} | } | ||||
/// <inheritdoc /> | |||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | ||||
{ | { | ||||
IGuildUser guildUser = null; | IGuildUser guildUser = null; | ||||
@@ -3,28 +3,38 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | 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] | [Flags] | ||||
public enum ContextType | 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, | 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, | 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 | Group = 0x04 | ||||
} | } | ||||
/// <summary> | /// <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> | /// </summary> | ||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | ||||
public class RequireContextAttribute : PreconditionAttribute | 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; } | 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> | /// <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> | /// <example> | ||||
/// <code language="c#"> | /// <code language="c#"> | ||||
@@ -4,11 +4,12 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Requires the command to be invoked in a channel marked NSFW. | |||||
/// Requires the command to be invoked in a channel marked NSFW. | |||||
/// </summary> | /// </summary> | ||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | ||||
public class RequireNsfwAttribute : PreconditionAttribute | public class RequireNsfwAttribute : PreconditionAttribute | ||||
{ | { | ||||
/// <inheritdoc /> | |||||
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | ||||
{ | { | ||||
if (context.Channel is ITextChannel text && text.IsNsfw) | if (context.Channel is ITextChannel text && text.IsNsfw) | ||||
@@ -10,6 +10,7 @@ namespace Discord.Commands | |||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | ||||
public class RequireOwnerAttribute : PreconditionAttribute | public class RequireOwnerAttribute : PreconditionAttribute | ||||
{ | { | ||||
/// <inheritdoc /> | |||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | ||||
{ | { | ||||
switch (context.Client.TokenType) | switch (context.Client.TokenType) | ||||
@@ -9,39 +9,44 @@ namespace Discord.Commands | |||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] | ||||
public class RequireUserPermissionAttribute : PreconditionAttribute | public class RequireUserPermissionAttribute : PreconditionAttribute | ||||
{ | { | ||||
/// <summary> | |||||
/// Gets the specified <see cref="Discord.GuildPermission" /> of the precondition. | |||||
/// </summary> | |||||
public GuildPermission? GuildPermission { get; } | public GuildPermission? GuildPermission { get; } | ||||
/// <summary> | |||||
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition. | |||||
/// </summary> | |||||
public ChannelPermission? ChannelPermission { get; } | public ChannelPermission? ChannelPermission { get; } | ||||
/// <summary> | /// <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> | /// </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) | public RequireUserPermissionAttribute(GuildPermission permission) | ||||
{ | { | ||||
GuildPermission = permission; | GuildPermission = permission; | ||||
ChannelPermission = null; | ChannelPermission = null; | ||||
} | } | ||||
/// <summary> | /// <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> | /// </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) | public RequireUserPermissionAttribute(ChannelPermission permission) | ||||
{ | { | ||||
ChannelPermission = permission; | ChannelPermission = permission; | ||||
GuildPermission = null; | GuildPermission = null; | ||||
} | } | ||||
/// <inheritdoc /> | |||||
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) | ||||
{ | { | ||||
var guildUser = context.User as IGuildUser; | var guildUser = context.User as IGuildUser; | ||||
@@ -14,7 +14,7 @@ namespace Discord.Commands | |||||
public int Priority { get; } | public int Priority { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Creates a new <see cref="PriorityAttribute" /> with the given priority. | |||||
/// Initializes a new <see cref="PriorityAttribute" /> attribute with the given priority. | |||||
/// </summary> | /// </summary> | ||||
public PriorityAttribute(int priority) | public PriorityAttribute(int priority) | ||||
{ | { | ||||
@@ -1,8 +1,7 @@ | |||||
using System; | |||||
using System; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
namespace Discord.Commands.Builders | namespace Discord.Commands.Builders | ||||
{ | { | ||||
@@ -140,4 +139,4 @@ namespace Discord.Commands.Builders | |||||
return new CommandInfo(this, info, service); | return new CommandInfo(this, info, service); | ||||
} | } | ||||
} | } | ||||
} | |||||
} |
@@ -2,7 +2,6 @@ using System; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Reflection; | using System.Reflection; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
namespace Discord.Commands.Builders | namespace Discord.Commands.Builders | ||||
{ | { | ||||
@@ -1,7 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
@@ -6,7 +6,6 @@ using System.Linq; | |||||
using System.Reflection; | using System.Reflection; | ||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Discord.Commands.Builders; | using Discord.Commands.Builders; | ||||
using Discord.Logging; | using Discord.Logging; | ||||
@@ -24,7 +24,7 @@ namespace Discord.Commands | |||||
Error = error; | Error = error; | ||||
ErrorReason = errorReason; | ErrorReason = errorReason; | ||||
} | } | ||||
public static ParseResult FromSuccess(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues) | public static ParseResult FromSuccess(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues) | ||||
{ | { | ||||
for (int i = 0; i < argValues.Count; i++) | for (int i = 0; i < argValues.Count; i++) | ||||
@@ -2,6 +2,9 @@ using System.Diagnostics; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | |||||
/// Represents a result type for command preconditions. | |||||
/// </summary> | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class PreconditionResult : IResult | public class PreconditionResult : IResult | ||||
{ | { | ||||
@@ -13,19 +16,40 @@ namespace Discord.Commands | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public bool IsSuccess => !Error.HasValue; | 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) | protected PreconditionResult(CommandError? error, string errorReason) | ||||
{ | { | ||||
Error = error; | Error = error; | ||||
ErrorReason = errorReason; | ErrorReason = errorReason; | ||||
} | } | ||||
/// <summary> | |||||
/// Returns a <see cref="PreconditionResult" /> with no errors. | |||||
/// </summary> | |||||
public static PreconditionResult FromSuccess() | public static PreconditionResult FromSuccess() | ||||
=> new PreconditionResult(null, null); | => 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) | public static PreconditionResult FromError(string reason) | ||||
=> new PreconditionResult(CommandError.UnmetPrecondition, 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) | public static PreconditionResult FromError(IResult result) | ||||
=> new PreconditionResult(result.Error, result.ErrorReason); | => 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}"; | public override string ToString() => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; | ||||
private string DebuggerDisplay => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; | private string DebuggerDisplay => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; | ||||
} | } | ||||
@@ -5,6 +5,11 @@ namespace Discord.Commands | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public abstract class RuntimeResult : IResult | 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) | protected RuntimeResult(CommandError? error, string reason) | ||||
{ | { | ||||
Error = error; | Error = error; | ||||
@@ -3,7 +3,7 @@ using System; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <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> | /// </summary> | ||||
public static class CDN | public static class CDN | ||||
{ | { | ||||
@@ -1,31 +1,33 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> Specifies the severity of the log message. </summary> | |||||
/// <summary> | |||||
/// Specifies the severity of the log message. | |||||
/// </summary> | |||||
public enum LogSeverity | 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> | /// </summary> | ||||
Critical = 0, | 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> | /// </summary> | ||||
Error = 1, | 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> | /// </summary> | ||||
Warning = 2, | Warning = 2, | ||||
/// <summary> | |||||
/// Logs that track the general flow of the application. | |||||
/// <summary> | |||||
/// Logs that track the general flow of the application. | |||||
/// </summary> | /// </summary> | ||||
Info = 3, | Info = 3, | ||||
/// <summary> | |||||
/// Logs that are used for interactive investigation during development. | |||||
/// <summary> | |||||
/// Logs that are used for interactive investigation during development. | |||||
/// </summary> | /// </summary> | ||||
Verbose = 4, | Verbose = 4, | ||||
/// <summary> | |||||
/// Logs that contain the most detailed messages. | |||||
/// <summary> | |||||
/// Logs that contain the most detailed messages. | |||||
/// </summary> | /// </summary> | ||||
Debug = 5 | Debug = 5 | ||||
} | } | ||||
@@ -3,20 +3,29 @@ using System.Threading.Tasks; | |||||
namespace Discord | 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> | public struct Cacheable<TEntity, TId> | ||||
where TEntity : IEntity<TId> | where TEntity : IEntity<TId> | ||||
where TId : IEquatable<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; } | public bool HasValue { get; } | ||||
/// <summary> Gets the ID of this entity. </summary> | |||||
/// <summary> | |||||
/// Gets the ID of this entity. | |||||
/// </summary> | |||||
public TId Id { get; } | 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> | /// <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> | /// </remarks> | ||||
public TEntity Value { get; } | public TEntity Value { get; } | ||||
private Func<Task<TEntity>> DownloadFunc { get; } | private Func<Task<TEntity>> DownloadFunc { get; } | ||||
@@ -29,19 +38,27 @@ namespace Discord | |||||
DownloadFunc = downloadFunc; | 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="Discord.Net.HttpException">Thrown when used from a user account.</exception> | ||||
/// <exception cref="NullReferenceException">Thrown when the message is deleted.</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() | public async Task<TEntity> DownloadAsync() | ||||
{ | { | ||||
return await DownloadFunc().ConfigureAwait(false); | 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="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> | /// <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); | public async Task<TEntity> GetOrDownloadAsync() => HasValue ? Value : await DownloadAsync().ConfigureAwait(false); | ||||
} | } | ||||
} | } |
@@ -4,7 +4,7 @@ using System.Collections.Generic; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <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> | /// </summary> | ||||
public static class DiscordComparers | public static class DiscordComparers | ||||
{ | { | ||||
@@ -4,30 +4,42 @@ using System.Text; | |||||
namespace Discord | 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 | public static class MentionUtils | ||||
{ | { | ||||
private const char SanitizeChar = '\x200b'; | private const char SanitizeChar = '\x200b'; | ||||
//If the system can't be positive a user doesn't have a nickname, assume useNickname = true (source: Jake) | //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}>"; | 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); | public static string MentionUser(ulong id) => MentionUser(id.ToString(), true); | ||||
internal static string MentionChannel(string id) => $"<#{id}>"; | 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()); | public static string MentionChannel(ulong id) => MentionChannel(id.ToString()); | ||||
internal static string MentionRole(string id) => $"<@&{id}>"; | 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()); | 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) | public static ulong ParseUser(string text) | ||||
{ | { | ||||
if (TryParseUser(text, out ulong id)) | if (TryParseUser(text, out ulong id)) | ||||
return id; | return id; | ||||
throw new ArgumentException("Invalid mention format", nameof(text)); | 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) | public static bool TryParseUser(string text, out ulong userId) | ||||
{ | { | ||||
if (text.Length >= 3 && text[0] == '<' && text[1] == '@' && text[text.Length - 1] == '>') | if (text.Length >= 3 && text[0] == '<' && text[1] == '@' && text[text.Length - 1] == '>') | ||||
@@ -44,14 +56,18 @@ namespace Discord | |||||
return false; | return false; | ||||
} | } | ||||
/// <summary> Parses a provided channel mention string. </summary> | |||||
/// <summary> | |||||
/// Parses a provided channel mention string. | |||||
/// </summary> | |||||
public static ulong ParseChannel(string text) | public static ulong ParseChannel(string text) | ||||
{ | { | ||||
if (TryParseChannel(text, out ulong id)) | if (TryParseChannel(text, out ulong id)) | ||||
return id; | return id; | ||||
throw new ArgumentException("Invalid mention format", nameof(text)); | 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) | public static bool TryParseChannel(string text, out ulong channelId) | ||||
{ | { | ||||
if (text.Length >= 3 && text[0] == '<' && text[1] == '#' && text[text.Length - 1] == '>') | if (text.Length >= 3 && text[0] == '<' && text[1] == '#' && text[text.Length - 1] == '>') | ||||
@@ -65,14 +81,18 @@ namespace Discord | |||||
return false; | return false; | ||||
} | } | ||||
/// <summary> Parses a provided role mention string. </summary> | |||||
/// <summary> | |||||
/// Parses a provided role mention string. | |||||
/// </summary> | |||||
public static ulong ParseRole(string text) | public static ulong ParseRole(string text) | ||||
{ | { | ||||
if (TryParseRole(text, out ulong id)) | if (TryParseRole(text, out ulong id)) | ||||
return id; | return id; | ||||
throw new ArgumentException("Invalid mention format", nameof(text)); | 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) | public static bool TryParseRole(string text, out ulong roleId) | ||||
{ | { | ||||
if (text.Length >= 4 && text[0] == '<' && text[1] == '@' && text[2] == '&' && text[text.Length - 1] == '>') | if (text.Length >= 4 && text[0] == '<' && text[1] == '@' && text[2] == '&' && text[text.Length - 1] == '>') | ||||