Documentation Overhaul (#1161)

* Add XML docs

* Clean up style switcher

* Squash commits on branch docs/faq-n-patches

* Fix broken theme selector

* Add local image embed instruction

* Add a bunch of XML docs

* Add a bunch of XML docs

* Fix broken search
+ DocFX by default ships with an older version of jQuery, switching to a newer version confuses parts of the DocFX Javascript.

* Minor fixes for CONTRIBUTING.md and README.md

* Clean up filterConfig.yml

+ New config exposes Discord.Net namespace since it has several common public exceptions that may be helpful to users

* Add XML docs

* Read token from Environment Variable instead of hardcode

* Add XMLDocs

* Compress some assets & add OAuth2 URL generator

* Fix sample link & add missing pictures

* Add tag examples

* Fix embed docs consistency

* Add details regarding userbot support

* Add XML Docs

* Add XML Docs

* Add XML Docs

* Minor fixes in documentations
+ Fix unescaped '<'
+ Fix typo

* Fix seealso for preconditions and add missing descriptions

* Add missing exceptions

* Document exposed TypeReaders

* Fix letter-casing for files

* Add 'last modified' plugin

Source: https://github.com/Still34/DocFx.Plugin.LastModified
Licensed under MIT License

* XML Docs

* Fix minor consistencies & redundant impl

* Add properties examples to overwrite

* Fix missing Username prop

* Add warning for bulk-delete endpoint

* Replace note block

* Add BaseSocketClient docs

* Add XML docs

* Replace langword null to code block null instead

- Because DocFX sucks at rendering langword

* Replace all langword placements with code block

* Add more IGuild docs

* Add details to SpotifyGame

* Initial proofread of the articles

* Add explanation for RunMode

* Add event docs

- MessageReceived
- ChannelUpdated/Destroyed/Created

* Fix light theme link color

* Fix xml docs error

* Add partial documentation for audit log impl

* Add documentation for some REST-based objects

* Add partial documentation for audit log objects

* Add more XML comments to quotation mark alias map stuff, including an example

* Add reference to CommandServiceConfig from the util docs'

* Add explanation that if " is removed then it wont work

* Fix missing service provider in example

* Add documentation for new INestedChannel

* Add documentation

* Add documentation for new API version & few events

* Revise guide paragraphs/samples

+ Fix various formatting.
+ Provide a more detailed walkthrough for dependency injection.
+ Add C# note at intro.

* Fix typos & formatting

* Improve group module example

* Small amount to see if I'm doing it right

* Remove/cleanup redundant variables

* Fix EnterTypingState impl for doc inheritance

* Fix Test to resolve changes made in 15b58e

* Improve precondition documentation

+ Add precondition usage sample
+ Add precondition group usage sample
+ Move precondition samples to its own sample folder

* Move samples to individual folders

* Clarify token source

* Cleanup styling of README.md for docs

* Replace InvalidPathChars for NS1.3

* InvalidPathChars does not exist in NS1.3; replaced with GetInvalidPathChars instead.

* Add a missing change for 2c7cc738

* Update LastModified to v1.1.0 & add license

* Rewrite installation page for Core 2.1

* Fix anchor link

* Bump post-processor to v1.1.1

* Add fixes to partial file & add license

* Moved theme-switcher code to scripts partial file
+ Add author's MIT license to featherlight javascript

* Remove unused bootstrap plugin

* Bump LastModified plugin

* Changed the path from 'lastmodified' to 'last-modified' for consistency

* Cleanup README & Contribution guide

* Changes to last pr

* Fix GetCategoryAsync docs

* Proofread and cleanup articles

* Change passive voice in "Get Started" to active
* Fix improper preposition in Commands Introduction page
* Fix minor grammar mistakes in "Your First Bot" (future tense -> present tense/subjunctive mood -> indicative mood/proper noun casing/incorrect noun/add missing article)
* Fix minor grammar mistakes in "Installation" (missing article)

* no hablo ingles

* Try try try again

* I'm sure you're having as much fun as I am

* Cleanup TOC & fix titles

* Improve styling

+ Change title font to Noto Sans
+ Add materialized design for commit message box

* Add DescriptionGenerator plugin

* Add nightly section for clarification

* Fix typos in Nightlies & Post-execution

* Bump DescriptionGenerator to v1.1.0

+ This build adds the functionality of generating managed references' summary into the description tag.

* Initial emoji article draft

* Add 'additional information' section for emoji article

* Add cosmetic changes to the master css

* Alter info box color
+ Add transition to article content

* Add clarification in the emoji article

* Emphasize that normal emoji string will not translate to its Unicode representation.
* Clean up or add some of the samples featured in the article.
+ Add emoji/emote declaration section for clarification.
+ Add WebSocket emote sample.
- Remove inconsistent styling ('wacky memes' proves to be too out of place).

* Improve readability for nightlies article

* Move 'Bundled Preconditions' section

* Bump LastModified to fix UTC DateTime parsing

* Add langwordMapping.yml

* Add XML docs

* Add VSC workspace rule

* The root workspace limits the ruler to 120 characters for member documentations and excludes folders such as 'samples' and 'docs'.
* The docs workspace limits the ruler to 70 characters for standard conceptual article to comply with documentation's CONTRIBUTING.md rule, and excludes temprorary folders created by DocFX.

* Update CONTRIBUTING.md

* Add documentation style rule

* Fix styling of several member documentation

* Fix ' />' caused by Agent Smith oddities
* Fix styling to be more specific about the mention of IDs

* Fix exception summary to comply with official Microsoft Docs style

* References
https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception?view=netframework-4.7.2
https://docs.microsoft.com/en-us/dotnet/api/system.platformnotsupportedexception?view=netframework-4.7.2
https://docs.microsoft.com/en-us/dotnet/api/system.badimageformatexception?view=netframework-4.7.2

* Add XML documentations

* Shift color return docs

* Fix minor docs

* Added documentation for SocketDMChannel, SocketGuildChannel, and SocketTextChannel

* Add XML docs

* Corrections to SocketGuildChannel

* Corrections to SocketTextChannel

* Corrections to SocketDMChannel

* Swapped out 'id' for 'snowflake identifier

* Swapped out 'id' for 'snowflake identifier'

* SocketDMChannel amendments

* SocketGuildChannel amendments

* SocketTextChannel amendments

* Add XML docs & patch return types
+ Starting from this commit, all return types for tasks will use style similar to most documentations featured on docs.microsoft.com

References:
https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext.-ctor?view=efcore-2.1
https://docs.microsoft.com/en-us/dotnet/api/system.io.filestream.readasync?view=netcore-2.1
https://docs.microsoft.com/en-us/dotnet/api/system.io.textwriter.writelineasync?view=netcore-2.1#System_IO_TextWriter_WriteLineAsync_System_Char___
And many more other asynchronous method documentations featured in the latest BCL.

* Added documentation for many audit log data types, fixed vowel indefinite articles

* Change audit log data types to start with 'Contains' (verb) instead of an article

* Fix some documentation issues and document some more audit log data types

* Fix English posession

* Add XML doc

* Documented two more types

* Documented RoleCreateAuditLogData

* Document remaining audit log data types

* Added RestDMChannel documentation

* Added RestGuildChannel documentation

* Added RestTextChannel documentation

* Added RestVoiceChannel documentation

* Added RestUser documentation

* Added RestRole documentation

* Added RestMessage documentation

* Slightly better wording

* Contains -> Contains a piece of (describe article)

* [EN] Present perf. -> past perf.

* Add XML docs

* Fix arrow alignment

* Clarify supported nullable type

* Fixed a typo in ISnowflakeEntity

* Added RestUser Documentation

* Added RestInvite documentation

* Add XML docs & minor optimizations

* Minor optimization for doc rendering

* Rollback font optimization changes

* Amendments to RestUser

* Added SocketDMChannel documentation

* Added RestDMChannel documentation

* Added RestGuild documentation

* Adjustment to SocketDMChannel

* Added minimal descriptions from the API documentation for Integration types

* Added obsolete mention to the ReadMessages flag.

* Added remarks about 2FA requirement for guild permissions

* Added xmldoc for GuildPermission methods

* Added xml doc for ToAllowList and ToDenyList

* Added specification of how the bits of the color raw value are packed

* Added discord API documentation to IConnection interface

* I can spell :^)

* Fix whitespace in ChannelPermission

* fix spacing of values in guildpermission

* Made changes to get field descriptions from feedback, added returns tag to IConnection

* Added property get standard for IntegrationAccount

* Added property get pattern to xml docs and identical returns tag.

* Change all color class references to struct
...because it isn't a class.

* Add XML docs

* Rewrote the returns tags in IGuildIntegration, removed the ones I was unsure about.

* Rewrote the rest of the returns tags

* Amendments

* Cleanup doc for c1d78189

* Added types to <returns> tags where missing

* Added second sample for adding reactions

* Added some class summaries

* Missed a period

* Amendments

* restored the removed line break

* Removed unnecessary see tag

* Use consistent quotation marks around subscribers, the name for these users are dependant on the source of where they are integrated from (youtube or twitch), so we should not use a name that is specific to one platform

* Add <remarks> tag to the IGuildIntegration xmldocs

* Fix grammar issue

* Update DescriptionGenerator

* Cleanup of https://github.com/Still34/Discord.Net/pull/8

* Cleanup previous PR

* Fix for misleading behaviour in the emoji guide
+ Original lines stated that sending a emoji wrapped in colon will not be parsed, but that was incorrect; replaced with reactions instead of sending messages as the example

* Add strings for dictionary in DotSettings

* Add XML docs

* Fix lots of typos in comments
+ Geez, I didn't know there were so many.

* Add XML docs & rewrite GetMessagesAsync docs

This commit rewrites the remarks section of GetMessagesAsync, as well as adding examples to several methods.

* Update 'Your First Bot'
+ This commit reflects the new changes made to the Discord Application Developer Portal after its major update

* Initial optimization for DocFX render & add missing files

* Add examples in message methods

* Cleanup https://github.com/RogueException/Discord.Net/pull/1128

* Fix first bot note

* Cleanup FAQ structure

* Add XML docs

* Update docfx plugins

* Fix navbar collapsing issue

* Fix broken xref

* Cleanup FAQ section
+ Add introductory paragraphs to each FAQ section.
+ Add 'missing dependency' entry to commands FAQ.
* Split commands FAQ to 'General' and 'DI' sections.

* Cleanup https://github.com/RogueException/Discord.Net/pull/1139

* Fix missing namespace

* Add missing highlighting css for the light theme

* Add additional clarification for installing packages

* Add indentation to example for clarity

* Cleanup several articles to be more human-friendly and easier to read

* Remove RPC-related notes

* Cleanup slow-mode-related documentation strings

* Add an additional note about cross-guild emote usage

* Add CreateTextChannel sample

* Add XMLDocs
This commit is contained in:
Still Hsu
2018-10-01 05:44:33 +08:00
committed by Christopher F
parent 6b21b11f7d
commit ff0fea98a6
498 changed files with 16064 additions and 2633 deletions

View File

@@ -2,14 +2,37 @@ using System;
namespace Discord.Commands
{
/// <summary> Provides aliases for a command. </summary>
/// <summary>
/// Marks the aliases for a command.
/// </summary>
/// <remarks>
/// This attribute allows a command to have one or multiple aliases. In other words, the base command can have
/// multiple aliases when triggering the command itself, giving the end-user more freedom of choices when giving
/// hot-words to trigger the desired command. See the example for a better illustration.
/// </remarks>
/// <example>
/// In the following example, the command can be triggered with the base name, "stats", or either "stat" or
/// "info".
/// <code language="cs">
/// [Command("stats")]
/// [Alias("stat", "info")]
/// public async Task GetStatsAsync(IUser user)
/// {
/// // ...pull stats
/// }
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AliasAttribute : Attribute
{
/// <summary> The aliases which have been defined for the command. </summary>
/// <summary>
/// Gets the aliases which have been defined for the command.
/// </summary>
public string[] Aliases { get; }
/// <summary> Creates a new <see cref="AliasAttribute"/> with the given aliases. </summary>
/// <summary>
/// Creates a new <see cref="AliasAttribute" /> with the given aliases.
/// </summary>
public AliasAttribute(params string[] aliases)
{
Aliases = aliases;

View File

@@ -2,17 +2,32 @@ using System;
namespace Discord.Commands
{
/// <summary>
/// Marks the execution information for a command.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CommandAttribute : Attribute
{
/// <summary>
/// Gets the text that has been set to be recognized as a command.
/// </summary>
public string Text { get; }
/// <summary>
/// Specifies the <see cref="RunMode" /> of the command. This affects how the command is executed.
/// </summary>
public RunMode RunMode { get; set; } = RunMode.Default;
public bool? IgnoreExtraArgs { get; }
/// <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;

View File

@@ -2,6 +2,14 @@ using System;
namespace Discord.Commands
{
/// <summary>
/// Prevents the marked module from being loaded automatically.
/// </summary>
/// <remarks>
/// This attribute tells <see cref="CommandService" /> to ignore the marked module from being loaded
/// automatically (e.g. the <see cref="CommandService.AddModulesAsync" /> method). If a non-public module marked
/// with this attribute is attempted to be loaded manually, the loading process will also fail.
/// </remarks>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class DontAutoLoadAttribute : Attribute
{

View File

@@ -1,9 +1,31 @@
using System;
namespace Discord.Commands {
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class DontInjectAttribute : Attribute {
}
namespace Discord.Commands
{
/// <summary>
/// Prevents the marked property from being injected into a module.
/// </summary>
/// <remarks>
/// This attribute prevents the marked member from being injected into its parent module. Useful when you have a
/// public property that you do not wish to invoke the library's dependency injection service.
/// </remarks>
/// <example>
/// In the following example, <c>DatabaseService</c> will not be automatically injected into the module and will
/// not throw an error message if the dependency fails to be resolved.
/// <code language="cs">
/// public class MyModule : ModuleBase
/// {
/// [DontInject]
/// public DatabaseService DatabaseService;
/// public MyModule()
/// {
/// DatabaseService = DatabaseFactory.Generate();
/// }
/// }
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class DontInjectAttribute : Attribute
{
}
}

View File

@@ -2,15 +2,26 @@ using System;
namespace Discord.Commands
{
/// <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>
public string Prefix { get; }
/// <inheritdoc />
public GroupAttribute()
{
Prefix = null;
}
/// <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;

View File

@@ -3,11 +3,21 @@ using System;
namespace Discord.Commands
{
// Override public name of command/module
/// <summary>
/// Marks the public name of a command, module, or parameter.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class NameAttribute : Attribute
{
/// <summary>
/// Gets the name of the command.
/// </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>
public NameAttribute(string text)
{
Text = text;

View File

@@ -4,17 +4,46 @@ using System.Reflection;
namespace Discord.Commands
{
/// <summary>
/// Marks the <see cref="Type"/> to be read by the specified <see cref="Discord.Commands.TypeReader"/>.
/// </summary>
/// <remarks>
/// This attribute will override the <see cref="Discord.Commands.TypeReader"/> to be used when parsing for the
/// desired type in the command. This is useful when one wishes to use a particular
/// <see cref="Discord.Commands.TypeReader"/> without affecting other commands that are using the same target
/// type.
/// <note type="warning">
/// If the given type reader does not inherit from <see cref="Discord.Commands.TypeReader"/>, an
/// <see cref="ArgumentException"/> will be thrown.
/// </note>
/// </remarks>
/// <example>
/// In this example, the <see cref="TimeSpan"/> will be read by a custom
/// <see cref="Discord.Commands.TypeReader"/>, <c>FriendlyTimeSpanTypeReader</c>, instead of the
/// <see cref="TimeSpanTypeReader"/> shipped by Discord.Net.
/// <code language="cs">
/// [Command("time")]
/// public Task GetTimeAsync([OverrideTypeReader(typeof(FriendlyTimeSpanTypeReader))]TimeSpan time)
/// => ReplyAsync(time);
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class OverrideTypeReaderAttribute : Attribute
{
private static readonly TypeInfo TypeReaderTypeInfo = typeof(TypeReader).GetTypeInfo();
/// <summary>
/// Gets the specified <see cref="TypeReader"/> of the parameter.
/// </summary>
public Type TypeReader { get; }
/// <inheritdoc/>
/// <param name="overridenTypeReader">The <see cref="TypeReader"/> to be used with the parameter. </param>
/// <exception cref="ArgumentException">The given <paramref name="overridenTypeReader"/> does not inherit from <see cref="TypeReader"/>.</exception>
public OverrideTypeReaderAttribute(Type overridenTypeReader)
{
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;
}

View File

@@ -3,9 +3,20 @@ using System.Threading.Tasks;
namespace Discord.Commands
{
/// <summary>
/// Requires the parameter to pass the specified precondition before execution can begin.
/// </summary>
/// <seealso cref="PreconditionAttribute"/>
[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 parameter.</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);
}
}

View File

@@ -1,18 +1,31 @@
using System;
using System;
using System.Threading.Tasks;
namespace Discord.Commands
{
/// <summary>
/// Requires the module or class to pass the specified precondition before execution can begin.
/// </summary>
/// <seealso cref="ParameterPreconditionAttribute"/>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public abstract class PreconditionAttribute : Attribute
{
/// <summary>
/// Specify a group that this precondition belongs to. 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 &amp;&amp; B).
/// Specifies a group that this precondition belongs to.
/// </summary>
/// <remarks>
/// <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" /> = <c>null</c> or not at all will
/// require *all* preconditions to pass, just like normal (A &amp;&amp; B).
/// </remarks>
public string Group { get; set; } = null;
/// <summary>
/// Checks if the <paramref name="command"/> has the sufficient permission to be executed.
/// </summary>
/// <param name="context">The context of the command.</param>
/// <param name="command">The command being executed.</param>
/// <param name="services">The service collection used for dependency injection.</param>
public abstract Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services);
}
}

View File

@@ -1,46 +1,52 @@
using System;
using System;
using System.Threading.Tasks;
namespace Discord.Commands
{
/// <summary>
/// This attribute requires that the bot has a specified 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>
/// Require that the bot account has a specified 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>
/// Require that the bot account has a specified 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;
@@ -50,9 +56,9 @@ namespace Discord.Commands
if (GuildPermission.HasValue)
{
if (guildUser == null)
return PreconditionResult.FromError("Command must be used in a guild channel");
return PreconditionResult.FromError("Command must be used in a guild channel.");
if (!guildUser.GuildPermissions.Has(GuildPermission.Value))
return PreconditionResult.FromError($"Bot requires guild permission {GuildPermission.Value}");
return PreconditionResult.FromError($"Bot requires guild permission {GuildPermission.Value}.");
}
if (ChannelPermission.HasValue)
@@ -64,7 +70,7 @@ namespace Discord.Commands
perms = ChannelPermissions.All(context.Channel);
if (!perms.Has(ChannelPermission.Value))
return PreconditionResult.FromError($"Bot requires channel permission {ChannelPermission.Value}");
return PreconditionResult.FromError($"Bot requires channel permission {ChannelPermission.Value}.");
}
return PreconditionResult.FromSuccess();

View File

@@ -1,35 +1,48 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace Discord.Commands
{
/// <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>
Guild = 0x01,
/// <summary>
/// Specifies the command to be executed within a DM.
/// </summary>
DM = 0x02,
/// <summary>
/// Specifies the command to be executed within a group.
/// </summary>
Group = 0x04
}
/// <summary>
/// Require that the command be invoked in a specified context.
/// 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>
public ContextType Contexts { get; }
/// <summary>
/// Require that the command be invoked in a 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#">
/// [Command("private_only")]
/// <code language="cs">
/// [Command("secret")]
/// [RequireContext(ContextType.DM | ContextType.Group)]
/// public async Task PrivateOnly()
/// public Task PrivateOnlyAsync()
/// {
/// return ReplyAsync("shh, this command is a secret");
/// }
/// </code>
/// </example>
@@ -38,12 +51,13 @@ namespace Discord.Commands
Contexts = contexts;
}
/// <inheritdoc />
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{
bool isValid = false;
if ((Contexts & ContextType.Guild) != 0)
isValid = isValid || context.Channel is IGuildChannel;
isValid = context.Channel is IGuildChannel;
if ((Contexts & ContextType.DM) != 0)
isValid = isValid || context.Channel is IDMChannel;
if ((Contexts & ContextType.Group) != 0)
@@ -52,7 +66,7 @@ namespace Discord.Commands
if (isValid)
return Task.FromResult(PreconditionResult.FromSuccess());
else
return Task.FromResult(PreconditionResult.FromError($"Invalid context for command; accepted contexts: {Contexts}"));
return Task.FromResult(PreconditionResult.FromError($"Invalid context for command; accepted contexts: {Contexts}."));
}
}
}

View File

@@ -4,11 +4,33 @@ using System.Threading.Tasks;
namespace Discord.Commands
{
/// <summary>
/// Require that the command is invoked in a channel marked NSFW
/// Requires the command to be invoked in a channel marked NSFW.
/// </summary>
/// <remarks>
/// The precondition will restrict the access of the command or module to be accessed within a guild channel
/// that has been marked as mature or NSFW. If the channel is not of type <see cref="ITextChannel"/> or the
/// channel is not marked as NSFW, the precondition will fail with an erroneous <see cref="PreconditionResult"/>.
/// </remarks>
/// <example>
/// The following example restricts the command <c>too-cool</c> to an NSFW-enabled channel only.
/// <code language="cs">
/// public class DankModule : ModuleBase
/// {
/// [Command("cool")]
/// public Task CoolAsync()
/// => ReplyAsync("I'm cool for everyone.");
///
/// [RequireNsfw]
/// [Command("too-cool")]
/// public Task TooCoolAsync()
/// => ReplyAsync("You can only see this if you're cool enough.");
/// }
/// </code>
/// </example>
[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)

View File

@@ -4,20 +4,45 @@ using System.Threading.Tasks;
namespace Discord.Commands
{
/// <summary>
/// Require that the command is invoked by the owner of the bot.
/// Requires the command to be invoked by the owner of the bot.
/// </summary>
/// <remarks>This precondition will only work if the bot is a bot account.</remarks>
/// <remarks>
/// This precondition will restrict the access of the command or module to the owner of the Discord application.
/// If the precondition fails to be met, an erroneous <see cref="PreconditionResult"/> will be returned with the
/// message "Command can only be run by the owner of the bot."
/// <note>
/// This precondition will only work if the account has a <see cref="TokenType"/> of <see cref="TokenType.Bot"/>
/// ;otherwise, this precondition will always fail.
/// </note>
/// </remarks>
/// <example>
/// The following example restricts the command to a set of sensitive commands that only the owner of the bot
/// application should be able to access.
/// <code language="cs">
/// [RequireOwner]
/// [Group("admin")]
/// public class AdminModule : ModuleBase
/// {
/// [Command("exit")]
/// public async Task ExitAsync()
/// {
/// Environment.Exit(0);
/// }
/// }
/// </code>
/// </example>
[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)
{
case TokenType.Bot:
var application = await context.Client.GetApplicationInfoAsync();
var application = await context.Client.GetApplicationInfoAsync().ConfigureAwait(false);
if (context.User.Id != application.Owner.Id)
return PreconditionResult.FromError("Command can only be run by the owner of the bot");
return PreconditionResult.FromError("Command can only be run by the owner of the bot.");
return PreconditionResult.FromSuccess();
default:
return PreconditionResult.FromError($"{nameof(RequireOwnerAttribute)} is not supported by this {nameof(TokenType)}.");

View File

@@ -1,47 +1,52 @@
using System;
using System;
using System.Threading.Tasks;
namespace Discord.Commands
{
/// <summary>
/// This attribute requires that the user invoking the command has a specified permission.
/// Requires the user invoking the command to have a specified permission.
/// </summary>
[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>
/// Require that the user invoking the command has a specified 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>
/// Require that the user invoking the command has a specified 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;
@@ -49,9 +54,9 @@ namespace Discord.Commands
if (GuildPermission.HasValue)
{
if (guildUser == null)
return Task.FromResult(PreconditionResult.FromError("Command must be used in a guild channel"));
return Task.FromResult(PreconditionResult.FromError("Command must be used in a guild channel."));
if (!guildUser.GuildPermissions.Has(GuildPermission.Value))
return Task.FromResult(PreconditionResult.FromError($"User requires guild permission {GuildPermission.Value}"));
return Task.FromResult(PreconditionResult.FromError($"User requires guild permission {GuildPermission.Value}."));
}
if (ChannelPermission.HasValue)
@@ -63,7 +68,7 @@ namespace Discord.Commands
perms = ChannelPermissions.All(context.Channel);
if (!perms.Has(ChannelPermission.Value))
return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}"));
return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}."));
}
return Task.FromResult(PreconditionResult.FromSuccess());

View File

@@ -2,14 +2,20 @@ using System;
namespace Discord.Commands
{
/// <summary> Sets priority of commands </summary>
/// <summary>
/// Sets priority of commands.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class PriorityAttribute : Attribute
{
/// <summary> The priority which has been set for the command </summary>
/// <summary>
/// Gets the priority which has been set for the command.
/// </summary>
public int Priority { get; }
/// <summary> Creates a new <see cref="PriorityAttribute"/> with the given priority. </summary>
/// <summary>
/// Initializes a new <see cref="PriorityAttribute" /> attribute with the given priority.
/// </summary>
public PriorityAttribute(int priority)
{
Priority = priority;

View File

@@ -2,6 +2,9 @@ using System;
namespace Discord.Commands
{
/// <summary>
/// Marks the input to not be parsed by the parser.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class RemainderAttribute : Attribute
{

View File

@@ -3,6 +3,9 @@ using System;
namespace Discord.Commands
{
// Extension of the Cosmetic Summary, for Groups, Commands, and Parameters
/// <summary>
/// Attaches remarks to your commands.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class RemarksAttribute : Attribute
{

View File

@@ -3,6 +3,9 @@ using System;
namespace Discord.Commands
{
// Cosmetic Summary, for Groups and Commands
/// <summary>
/// Attaches a summary to your command.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class SummaryAttribute : Attribute
{