Browse Source

Add a whole bunch of XML docs

pull/988/head
Hsu Still 7 years ago
parent
commit
9a1d777e3e
No known key found for this signature in database GPG Key ID: 8601A145FDA95209
96 changed files with 1734 additions and 683 deletions
  1. +1
    -1
      src/Discord.Net.Commands/Attributes/AliasAttribute.cs
  2. +2
    -2
      src/Discord.Net.Commands/Attributes/CommandAttribute.cs
  3. +9
    -7
      src/Discord.Net.Commands/Attributes/DontInjectAttribute.cs
  4. +6
    -2
      src/Discord.Net.Commands/Attributes/NameAttribute.cs
  5. +3
    -1
      src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs
  6. +8
    -5
      src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs
  7. +9
    -3
      src/Discord.Net.Commands/Attributes/PriorityAttribute.cs
  8. +3
    -1
      src/Discord.Net.Commands/Attributes/RemainderAttribute.cs
  9. +1
    -1
      src/Discord.Net.Commands/CommandError.cs
  10. +13
    -3
      src/Discord.Net.Commands/CommandException.cs
  11. +99
    -44
      src/Discord.Net.Commands/CommandService.cs
  12. +14
    -2
      src/Discord.Net.Commands/Extensions/MessageExtensions.cs
  13. +47
    -25
      src/Discord.Net.Commands/Info/CommandInfo.cs
  14. +0
    -1
      src/Discord.Net.Commands/Info/ModuleInfo.cs
  15. +0
    -1
      src/Discord.Net.Commands/Info/ParameterInfo.cs
  16. +1
    -2
      src/Discord.Net.Commands/Map/CommandMap.cs
  17. +3
    -3
      src/Discord.Net.Commands/Map/CommandMapNode.cs
  18. +1
    -1
      src/Discord.Net.Commands/Results/ExecuteResult.cs
  19. +1
    -1
      src/Discord.Net.Commands/Results/IResult.cs
  20. +7
    -7
      src/Discord.Net.Core/Audio/AudioStream.cs
  21. +18
    -6
      src/Discord.Net.Core/Commands/ICommandContext.cs
  22. +15
    -5
      src/Discord.Net.Core/Entities/Activities/ActivityType.cs
  23. +7
    -3
      src/Discord.Net.Core/Entities/Activities/Game.cs
  24. +12
    -4
      src/Discord.Net.Core/Entities/Activities/GameAsset.cs
  25. +6
    -0
      src/Discord.Net.Core/Entities/Activities/GameParty.cs
  26. +11
    -2
      src/Discord.Net.Core/Entities/Activities/GameSecrets.cs
  27. +9
    -1
      src/Discord.Net.Core/Entities/Activities/GameTimestamps.cs
  28. +9
    -3
      src/Discord.Net.Core/Entities/Activities/IActivity.cs
  29. +28
    -1
      src/Discord.Net.Core/Entities/Activities/RichGame.cs
  30. +24
    -8
      src/Discord.Net.Core/Entities/Activities/SpotifyGame.cs
  31. +14
    -3
      src/Discord.Net.Core/Entities/Activities/StreamingGame.cs
  32. +9
    -3
      src/Discord.Net.Core/Entities/CacheMode.cs
  33. +15
    -13
      src/Discord.Net.Core/Entities/Channels/GuildChannelProperties.cs
  34. +7
    -2
      src/Discord.Net.Core/Entities/Channels/IAudioChannel.cs
  35. +3
    -6
      src/Discord.Net.Core/Entities/Channels/ICategoryChannel.cs
  36. +12
    -4
      src/Discord.Net.Core/Entities/Channels/IChannel.cs
  37. +11
    -4
      src/Discord.Net.Core/Entities/Channels/IDMChannel.cs
  38. +8
    -3
      src/Discord.Net.Core/Entities/Channels/IGroupChannel.cs
  39. +66
    -21
      src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs
  40. +34
    -10
      src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs
  41. +7
    -1
      src/Discord.Net.Core/Entities/Channels/IPrivateChannel.cs
  42. +29
    -10
      src/Discord.Net.Core/Entities/Channels/ITextChannel.cs
  43. +15
    -5
      src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs
  44. +9
    -3
      src/Discord.Net.Core/Entities/Channels/ReorderChannelProperties.cs
  45. +6
    -4
      src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs
  46. +6
    -4
      src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs
  47. +13
    -5
      src/Discord.Net.Core/Entities/Emotes/Emoji.cs
  48. +18
    -6
      src/Discord.Net.Core/Entities/Emotes/Emote.cs
  49. +3
    -1
      src/Discord.Net.Core/Entities/Emotes/GuildEmote.cs
  50. +7
    -3
      src/Discord.Net.Core/Entities/Emotes/IEmote.cs
  51. +9
    -3
      src/Discord.Net.Core/Entities/Guilds/DefaultMessageNotifications.cs
  52. +4
    -4
      src/Discord.Net.Core/Entities/Guilds/GuildEmbedProperties.cs
  53. +12
    -4
      src/Discord.Net.Core/Entities/Guilds/GuildIntegrationProperties.cs
  54. +24
    -23
      src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs
  55. +10
    -1
      src/Discord.Net.Core/Entities/Guilds/IBan.cs
  56. +232
    -88
      src/Discord.Net.Core/Entities/Guilds/IGuild.cs
  57. +23
    -8
      src/Discord.Net.Core/Entities/Guilds/IVoiceRegion.cs
  58. +9
    -3
      src/Discord.Net.Core/Entities/Guilds/MfaLevel.cs
  59. +9
    -3
      src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs
  60. +18
    -6
      src/Discord.Net.Core/Entities/Guilds/VerificationLevel.cs
  61. +6
    -2
      src/Discord.Net.Core/Entities/IDeletable.cs
  62. +3
    -1
      src/Discord.Net.Core/Entities/IEntity.cs
  63. +6
    -2
      src/Discord.Net.Core/Entities/IMentionable.cs
  64. +1
    -0
      src/Discord.Net.Core/Entities/ISnowflakeEntity.cs
  65. +6
    -2
      src/Discord.Net.Core/Entities/IUpdateable.cs
  66. +9
    -5
      src/Discord.Net.Core/Entities/Image.cs
  67. +18
    -1
      src/Discord.Net.Core/Entities/ImageFormat.cs
  68. +28
    -10
      src/Discord.Net.Core/Entities/Invites/IInvite.cs
  69. +25
    -9
      src/Discord.Net.Core/Entities/Invites/IInviteMetadata.cs
  70. +2
    -1
      src/Discord.Net.Core/Entities/Messages/ISystemMessage.cs
  71. +1
    -1
      src/Discord.Net.Core/Entities/Messages/IUserMessage.cs
  72. +85
    -42
      src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
  73. +106
    -20
      src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
  74. +13
    -5
      src/Discord.Net.Core/Entities/Permissions/Overwrite.cs
  75. +24
    -9
      src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs
  76. +3
    -1
      src/Discord.Net.Core/Entities/Roles/Color.cs
  77. +31
    -10
      src/Discord.Net.Core/Entities/Roles/IRole.cs
  78. +9
    -3
      src/Discord.Net.Core/Entities/Roles/ReorderRoleProperties.cs
  79. +19
    -19
      src/Discord.Net.Core/Entities/Roles/RoleProperties.cs
  80. +33
    -20
      src/Discord.Net.Core/Entities/Users/GuildUserProperties.cs
  81. +3
    -1
      src/Discord.Net.Core/Entities/Users/IGroupUser.cs
  82. +49
    -20
      src/Discord.Net.Core/Entities/Users/IGuildUser.cs
  83. +9
    -3
      src/Discord.Net.Core/Entities/Users/IPresence.cs
  84. +15
    -4
      src/Discord.Net.Core/Entities/Users/ISelfUser.cs
  85. +31
    -10
      src/Discord.Net.Core/Entities/Users/IUser.cs
  86. +24
    -7
      src/Discord.Net.Core/Entities/Users/IVoiceState.cs
  87. +1
    -0
      src/Discord.Net.Core/Entities/Users/IWebhookUser.cs
  88. +10
    -10
      src/Discord.Net.Core/Entities/Users/SelfUserProperties.cs
  89. +21
    -7
      src/Discord.Net.Core/Entities/Users/UserStatus.cs
  90. +33
    -10
      src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs
  91. +10
    -10
      src/Discord.Net.Core/Entities/Webhooks/WebhookProperties.cs
  92. +18
    -0
      src/Discord.Net.Core/Net/HttpException.cs
  93. +10
    -0
      src/Discord.Net.Core/Net/RateLimitedException.cs
  94. +14
    -1
      src/Discord.Net.Core/Net/WebSocketClosedException.cs
  95. +10
    -18
      src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs
  96. +39
    -19
      src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs

+ 1
- 1
src/Discord.Net.Commands/Attributes/AliasAttribute.cs View File

@@ -6,7 +6,7 @@ namespace Discord.Commands
[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>


+ 2
- 2
src/Discord.Net.Commands/Attributes/CommandAttribute.cs View File

@@ -7,11 +7,11 @@ namespace Discord.Commands
public class CommandAttribute : Attribute
{
/// <summary>
/// Gets the text that has been set to be recognized as a command.
/// 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.
/// Specifies the <see cref="RunMode" /> of the command. This affects how the command is executed.
/// </summary>
public RunMode RunMode { get; set; } = RunMode.Default;



+ 9
- 7
src/Discord.Net.Commands/Attributes/DontInjectAttribute.cs View File

@@ -1,10 +1,12 @@
using System;

namespace Discord.Commands {

/// <summary> Prevents the marked property from being injected into a module. </summary>
[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>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class DontInjectAttribute : Attribute
{
}
}

+ 6
- 2
src/Discord.Net.Commands/Attributes/NameAttribute.cs View File

@@ -3,11 +3,15 @@ using System;
namespace Discord.Commands
{
// Override public name of command/module
/// <summary> Marks the public name of a command, module, or parameter. </summary>
/// <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>
/// <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>


+ 3
- 1
src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs View File

@@ -3,7 +3,9 @@ using System.Threading.Tasks;

namespace Discord.Commands
{
/// <summary> Requires the parameter to pass the specified precondition before execution can begin. </summary>
/// <summary>
/// Requires the parameter to pass the specified precondition before execution can begin.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)]
public abstract class ParameterPreconditionAttribute : Attribute
{


+ 8
- 5
src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs View File

@@ -7,12 +7,15 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public abstract class PreconditionAttribute : Attribute
{
/// <summary> Specify a group that this precondition belongs to. </summary>
/// <summary>
/// Specify 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"/> = <see langword="null"/>
/// or not at all will require *all* preconditions to pass, just like normal (A &amp;&amp; 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).
/// </para>
/// </remarks>
public string Group { get; set; } = null;



+ 9
- 3
src/Discord.Net.Commands/Attributes/PriorityAttribute.cs 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> Gets 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>
/// Creates a new <see cref="PriorityAttribute" /> with the given priority.
/// </summary>
public PriorityAttribute(int priority)
{
Priority = priority;


+ 3
- 1
src/Discord.Net.Commands/Attributes/RemainderAttribute.cs View File

@@ -2,7 +2,9 @@ using System;

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


+ 1
- 1
src/Discord.Net.Commands/CommandError.cs View File

@@ -1,6 +1,6 @@
namespace Discord.Commands
{
/// <summary> The type of error the command throws. </summary>
/// <summary> Defines the type of error a command can throw. </summary>
public enum CommandError
{
//Search


+ 13
- 3
src/Discord.Net.Commands/CommandException.cs View File

@@ -2,14 +2,24 @@ using System;

namespace Discord.Commands
{
/// <summary> Thrown when a command fails to execute. </summary>
/// <summary>
/// Describes an exception that occurred during a command execution.
/// </summary>
public class CommandException : Exception
{
/// <summary> The command that caused the exception. </summary>
/// <summary> Gets the command that caused the exception. </summary>
public CommandInfo Command { get; }
/// <summary> The command context of the exception. </summary>
/// <summary> Gets the command context of the exception. </summary>
public ICommandContext Context { get; }

/// <summary>
/// Initializes a new instance of the <see cref="CommandException" /> class using a
/// <paramref name="command"/> information, a <paramref name="command"/> context, and the exception that
/// interrupted the execution.
/// </summary>
/// <param name="command">The command information.</param>
/// <param name="context">The context of the command.</param>
/// <param name="ex">The exception that interrupted the command execution.</param>
public CommandException(CommandInfo command, ICommandContext context, Exception ex)
: base($"Error occurred executing {command.GetLogText(context)}.", ex)
{


+ 99
- 44
src/Discord.Net.Commands/CommandService.cs View File

@@ -18,7 +18,7 @@ namespace Discord.Commands
internal readonly AsyncEvent<Func<LogMessage, Task>> _logEvent = new AsyncEvent<Func<LogMessage, Task>>();

/// <summary>
/// Fired when a command is successfully executed.
/// Fired when a command is successfully executed without any runtime error.
/// </summary>
public event Func<CommandInfo, ICommandContext, IResult, Task> CommandExecuted { add { _commandExecutedEvent.Add(value); } remove { _commandExecutedEvent.Remove(value); } }
internal readonly AsyncEvent<Func<CommandInfo, ICommandContext, IResult, Task>> _commandExecutedEvent = new AsyncEvent<Func<CommandInfo, ICommandContext, IResult, Task>>();
@@ -38,17 +38,17 @@ namespace Discord.Commands
internal readonly LogManager _logManager;

/// <summary>
/// Represents all modules loaded within <see cref="CommandService"/>.
/// Represents all modules loaded within <see cref="CommandService" /> .
/// </summary>
public IEnumerable<ModuleInfo> Modules => _moduleDefs.Select(x => x);

/// <summary>
/// Represents all commands loaded within <see cref="CommandService"/>.
/// Represents all commands loaded within <see cref="CommandService" /> .
/// </summary>
public IEnumerable<CommandInfo> Commands => _moduleDefs.SelectMany(x => x.Commands);

/// <summary>
/// Represents all <see cref="TypeReader"/> loaded within <see cref="CommandService"/>.
/// Represents all <see cref="TypeReader" /> loaded within <see cref="CommandService" /> .
/// </summary>
public ILookup<Type, TypeReader> TypeReaders => _typeReaders.SelectMany(x => x.Value.Select(y => new { y.Key, y.Value })).ToLookup(x => x.Key, x => x.Value);

@@ -111,12 +111,28 @@ namespace Discord.Commands
}

/// <summary>
/// Add a command module from a <see cref="Type"/>.
/// Add a command module from a <see cref="Type" /> .
/// </summary>
/// <typeparam name="T">The type of module.</typeparam>
/// <param name="services">An <see cref="IServiceProvider"/> for your dependency injection solution, if using one - otherwise, pass <see langword="null"/>. </param>
/// <returns>A built module.</returns>
/// <param name="services">
/// The <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass
/// <see langword="null" /> .
/// </param>
/// <returns>
/// A built module.
/// </returns>
public Task<ModuleInfo> AddModuleAsync<T>(IServiceProvider services) => AddModuleAsync(typeof(T), services);
/// <summary>
/// Adds a command module from a <see cref="Type" /> .
/// </summary>
/// <param name="type">The type of module.</param>
/// <param name="services">
/// The <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass
/// <see langword="null" /> .
/// </param>
/// <returns>
/// A built module.
/// </returns>
public async Task<ModuleInfo> AddModuleAsync(Type type, IServiceProvider services)
{
services = services ?? EmptyServiceProvider.Instance;
@@ -144,11 +160,16 @@ namespace Discord.Commands
}
}
/// <summary>
/// Add command modules from an <see cref="Assembly"/>.
/// Add command modules from an <see cref="Assembly" /> .
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing command modules.</param>
/// <param name="services">An <see cref="IServiceProvider"/> for your dependency injection solution, if using one - otherwise, pass <see langword="null"/>.</param>
/// <returns>A collection of built modules.</returns>
/// <param name="assembly">The <see cref="Assembly" /> containing command modules.</param>
/// <param name="services">
/// An <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass
/// <see langword="null" /> .
/// </param>
/// <returns>
/// A collection of built modules.
/// </returns>
public async Task<IEnumerable<ModuleInfo>> AddModulesAsync(Assembly assembly, IServiceProvider services)
{
services = services ?? EmptyServiceProvider.Instance;
@@ -184,7 +205,13 @@ namespace Discord.Commands

return module;
}

/// <summary>
/// Removes the command module.
/// </summary>
/// <param name="module">The <see cref="ModuleInfo" /> to be removed from the service.</param>
/// <returns>
/// Returns whether the <paramref name="module"/> is successfully removed.
/// </returns>
public async Task<bool> RemoveModuleAsync(ModuleInfo module)
{
await _moduleLock.WaitAsync().ConfigureAwait(false);
@@ -231,29 +258,25 @@ namespace Discord.Commands

//Type Readers
/// <summary>
/// Adds a custom <see cref="TypeReader"/> to this <see cref="CommandService"/> for the supplied object type.
/// <para>
/// If <typeparamref name="T"/> is a <see cref="ValueType"/>, a <see cref="NullableTypeReader{T}"/> will also be added.
/// </para>
/// <para>
/// If a default <see cref="TypeReader"/> exists for <typeparamref name="T"/>, a warning will be logged and the default <see cref="TypeReader"/> will be replaced.
/// </para>
/// Adds a custom <see cref="TypeReader" /> to this <see cref="CommandService" /> for the supplied object type.
/// If <typeparamref name="T" /> is a <see cref="ValueType" />, a nullable <see cref="TypeReader" /> will also be
/// added.
/// If a default <see cref="TypeReader" /> exists for <typeparamref name="T" />, a warning will be logged and the
/// default <see cref="TypeReader" /> will be replaced.
/// </summary>
/// <typeparam name="T">The object type to be read by the <see cref="TypeReader"/>.</typeparam>
/// <param name="reader">An instance of the <see cref="TypeReader"/> to be added.</param>
/// <typeparam name="T">The object type to be read by the <see cref="TypeReader" />.</typeparam>
/// <param name="reader">An instance of the <see cref="TypeReader" /> to be added.</param>
public void AddTypeReader<T>(TypeReader reader)
=> AddTypeReader(typeof(T), reader);
/// <summary>
/// Adds a custom <see cref="TypeReader"/> to this <see cref="CommandService"/> for the supplied object type.
/// <para>
/// If <paramref name="type"/> is a <see cref="ValueType"/>, a <see cref="NullableTypeReader{T}"/> for the value type will also be added.
/// </para>
/// <para>
/// If a default <see cref="TypeReader"/> exists for <paramref name="type"/>, a warning will be logged and the default <see cref="TypeReader"/> will be replaced.
/// </para>
/// Adds a custom <see cref="TypeReader" /> to this <see cref="CommandService" /> for the supplied object type.
/// If <paramref name="type" /> is a <see cref="ValueType" />, a nullable <see cref="TypeReader" /> for the value
/// type will also be added.
/// If a default <see cref="TypeReader" /> exists for <paramref name="type" />, a warning will be logged and the
/// default <see cref="TypeReader" /> will be replaced.
/// </summary>
/// <param name="type">A <see cref="Type"/> instance for the type to be read.</param>
/// <param name="reader">An instance of the <see cref="TypeReader"/> to be added.</param>
/// <param name="type">A <see cref="Type" /> instance for the type to be read.</param>
/// <param name="reader">An instance of the <see cref="TypeReader" /> to be added.</param>
public void AddTypeReader(Type type, TypeReader reader)
{
if (_defaultTypeReaders.ContainsKey(type))
@@ -262,25 +285,29 @@ namespace Discord.Commands
AddTypeReader(type, reader, true);
}
/// <summary>
/// Adds a custom <see cref="TypeReader"/> to this <see cref="CommandService"/> for the supplied object type.
/// <para>
/// If <typeparamref name="T"/> is a <see cref="ValueType"/>, a <see cref="NullableTypeReader{T}"/> will also be added.
/// </para>
/// Adds a custom <see cref="TypeReader" /> to this <see cref="CommandService" /> for the supplied object type.
/// If <typeparamref name="T" /> is a <see cref="ValueType" />, a nullable <see cref="TypeReader" /> will also be
/// added.
/// </summary>
/// <typeparam name="T">The object type to be read by the <see cref="TypeReader"/>.</typeparam>
/// <param name="reader">An instance of the <see cref="TypeReader"/> to be added.</param>
/// <param name="replaceDefault">If <paramref name="reader"/> should replace the default <see cref="TypeReader"/> for <typeparamref name="T"/> if one exists.</param>
/// <typeparam name="T">The object type to be read by the <see cref="TypeReader" />.</typeparam>
/// <param name="reader">An instance of the <see cref="TypeReader" /> to be added.</param>
/// <param name="replaceDefault">
/// Defines whether the <see cref="TypeReader"/> should replace the default one for
/// <see cref="Type" /> if it exists.
/// </param>
public void AddTypeReader<T>(TypeReader reader, bool replaceDefault)
=> AddTypeReader(typeof(T), reader, replaceDefault);
/// <summary>
/// Adds a custom <see cref="TypeReader"/> to this <see cref="CommandService"/> for the supplied object type.
/// <para>
/// If <paramref name="type"/> is a <see cref="ValueType"/>, a <see cref="NullableTypeReader{T}"/> for the value type will also be added.
/// </para>
/// Adds a custom <see cref="TypeReader" /> to this <see cref="CommandService" /> for the supplied object type.
/// If <paramref name="type" /> is a <see cref="ValueType" />, a nullable <see cref="TypeReader" /> for the value
/// type will also be added.
/// </summary>
/// <param name="type">A <see cref="Type"/> instance for the type to be read.</param>
/// <param name="reader">An instance of the <see cref="TypeReader"/> to be added.</param>
/// <param name="replaceDefault">If <paramref name="reader"/> should replace the default <see cref="TypeReader"/> for <paramref name="type"/> if one exists.</param>
/// <param name="type">A <see cref="Type" /> instance for the type to be read.</param>
/// <param name="reader">An instance of the <see cref="TypeReader" /> to be added.</param>
/// <param name="replaceDefault">
/// Defines whether the <see cref="TypeReader"/> should replace the default one for
/// <see cref="Type" /> if it exists.
/// </param>
public void AddTypeReader(Type type, TypeReader reader, bool replaceDefault)
{
if (replaceDefault && _defaultTypeReaders.ContainsKey(type))
@@ -342,8 +369,20 @@ namespace Discord.Commands
}

//Execution
/// <summary>
/// Searches for the command.
/// </summary>
/// <param name="context">The context of the command.</param>
/// <param name="argPos">The position of which the command starts at.</param>
/// <returns>The result containing the matching commands.</returns>
public SearchResult Search(ICommandContext context, int argPos)
=> Search(context, context.Message.Content.Substring(argPos));
/// <summary>
/// Searches for the command.
/// </summary>
/// <param name="context">The context of the command.</param>
/// <param name="input">The command string.</param>
/// <returns>The result containing the matching commands.</returns>
public SearchResult Search(ICommandContext context, string input)
{
string searchInput = _caseSensitive ? input : input.ToLowerInvariant();
@@ -355,8 +394,24 @@ namespace Discord.Commands
return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command.");
}

/// <summary>
/// Executes the command.
/// </summary>
/// <param name="context">The context of the command.</param>
/// <param name="argPos">The position of which the command starts at.</param>
/// <param name="services">The service to be used in the command's dependency injection.</param>
/// <param name="multiMatchHandling">The handling mode when multiple command matches are found.</param>
/// <returns>The result of the command execution.</returns>
public Task<IResult> ExecuteAsync(ICommandContext context, int argPos, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
=> ExecuteAsync(context, context.Message.Content.Substring(argPos), services, multiMatchHandling);
/// <summary>
/// Executes the command.
/// </summary>
/// <param name="context">The context of the command.</param>
/// <param name="input">The command string.</param>
/// <param name="services">The service to be used in the command's dependency injection.</param>
/// <param name="multiMatchHandling">The handling mode when multiple command matches are found.</param>
/// <returns>The result of the command execution.</returns>
public async Task<IResult> ExecuteAsync(ICommandContext context, string input, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
services = services ?? EmptyServiceProvider.Instance;


+ 14
- 2
src/Discord.Net.Commands/Extensions/MessageExtensions.cs View File

@@ -1,9 +1,15 @@
using System;
using System;

namespace Discord.Commands
{
/// <summary>
/// Extension methods for <see cref="IUserMessage"/> that related to commands.
/// </summary>
public static class MessageExtensions
{
/// <summary>
/// Gets whether the message starts with the provided <see langword="char" />.
/// </summary>
public static bool HasCharPrefix(this IUserMessage msg, char c, ref int argPos)
{
var text = msg.Content;
@@ -14,6 +20,9 @@ namespace Discord.Commands
}
return false;
}
/// <summary>
/// Gets whether the message starts with the provided <see langword="string" />.
/// </summary>
public static bool HasStringPrefix(this IUserMessage msg, string str, ref int argPos, StringComparison comparisonType = StringComparison.Ordinal)
{
var text = msg.Content;
@@ -24,6 +33,9 @@ namespace Discord.Commands
}
return false;
}
/// <summary>
/// Gets whether the message starts with the user's mention string.
/// </summary>
public static bool HasMentionPrefix(this IUserMessage msg, IUser user, ref int argPos)
{
var text = msg.Content;
@@ -43,4 +55,4 @@ namespace Discord.Commands
return false;
}
}
}
}

+ 47
- 25
src/Discord.Net.Commands/Info/CommandInfo.cs View File

@@ -8,14 +8,15 @@ using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

namespace Discord.Commands
{
/// <summary> The information of a command. </summary>
/// <remarks>
/// This object contains the information of a command.
/// This can include the module of the command, various descriptions regarding the command, and its <see cref="RunMode"/>.
/// <summary>
/// Provides the information of a command.
/// </summary>
/// <remarks>
/// This object contains the information of a command. This can include the module of the command, various
/// descriptions regarding the command, and its <see cref="RunMode" /> .
/// </remarks>
[DebuggerDisplay("{Name,nq}")]
public class CommandInfo
@@ -26,36 +27,59 @@ namespace Discord.Commands
private readonly CommandService _commandService;
private readonly Func<ICommandContext, object[], IServiceProvider, CommandInfo, Task> _action;

/// <summary> The module that the command belongs in. </summary>
/// <summary>
/// Gets the module that the command belongs in.
/// </summary>
public ModuleInfo Module { get; }
/// <summary> Name of the command. If none is set, the first alias is used. </summary>
/// <summary>
/// Gets the name of the command. If none is set, the first alias is used.
/// </summary>
public string Name { get; }
/// <summary> Summary of the command. </summary>
/// <remarks>
/// This field returns the summary of the command.
/// Summary and remarks can be useful in help commands and various implementation that fetches details of the command for the user.
/// <summary>
/// Gets the summary of the command.
/// </summary>
/// <remarks>
/// This field returns the summary of the command. <see cref="Summary"/> and <see cref="Remarks"/> can be
/// useful in help commands and various implementation that fetches details of the command for the user.
/// </remarks>
public string Summary { get; }
/// <summary> Remarks of the command. </summary>
/// <remarks>
/// This field returns the remarks of the command.
/// Summary and remarks can be useful in help commands and various implementation that fetches details of the command for the user.
/// <summary>
/// Gets the remarks of the command.
/// </summary>
/// <remarks>
/// This field returns the summary of the command. <see cref="Summary"/> and <see cref="Remarks"/> can be
/// useful in help commands and various implementation that fetches details of the command for the user.
/// </remarks>
public string Remarks { get; }
/// <summary> The priority of the command. This is used when there are multiple overloads of the command. </summary>
/// <summary>
/// Gets the priority of the command. This is used when there are multiple overloads of the command.
/// </summary>
public int Priority { get; }
/// <summary> Indicates whether the command accepts a <see langword="params"/> <see cref="Type"/>[] for its parameter. </summary>
/// <summary>
/// Indicates whether the command accepts a <see langword="params"/> <see cref="Type"/>[] for its
/// parameter.
/// </summary>
public bool HasVarArgs { get; }
/// <summary> Indicates the <see cref="RunMode"/> that is being used for the command. </summary>
/// <summary>
/// Gets the <see cref="RunMode" /> that is being used for the command.
/// </summary>
public RunMode RunMode { get; }

/// <summary> List of aliases defined by the <see cref="AliasAttribute"/> of the command. </summary>
/// <summary>
/// Gets a list of aliases defined by the <see cref="AliasAttribute" /> of the command.
/// </summary>
public IReadOnlyList<string> Aliases { get; }
/// <summary> List of information about the parameters of the command. </summary>
/// <summary>
/// Gets a list of information about the parameters of the command.
/// </summary>
public IReadOnlyList<ParameterInfo> Parameters { get; }
/// <summary> List of preconditions defined by the <see cref="PreconditionAttribute"/> of the command. </summary>
/// <summary>
/// Gets a list of preconditions defined by the <see cref="PreconditionAttribute" /> of the command.
/// </summary>
public IReadOnlyList<PreconditionAttribute> Preconditions { get; }
/// <summary> List of attributes of the command. </summary>
/// <summary>
/// Gets a list of attributes of the command.
/// </summary>
public IReadOnlyList<Attribute> Attributes { get; }

internal CommandInfo(CommandBuilder builder, ModuleInfo module, CommandService service)
@@ -145,8 +169,7 @@ namespace Discord.Commands
string input = searchResult.Text.Substring(startIndex);
return await CommandParser.ParseArgsAsync(this, context, _commandService._ignoreExtraArgs, services, input, 0).ConfigureAwait(false);
}

/// <summary> Executes the command with the provided context, parsed value, and service provider. </summary>
public Task<IResult> ExecuteAsync(ICommandContext context, ParseResult parseResult, IServiceProvider services)
{
if (!parseResult.IsSuccess)
@@ -170,7 +193,6 @@ namespace Discord.Commands

return ExecuteAsync(context, argList, paramList, services);
}
/// <summary> Executes the command with the provided context, argument and parameter list, and service provider. </summary>
public async Task<IResult> ExecuteAsync(ICommandContext context, IEnumerable<object> argList, IEnumerable<object> paramList, IServiceProvider services)
{
services = services ?? EmptyServiceProvider.Instance;


+ 0
- 1
src/Discord.Net.Commands/Info/ModuleInfo.cs View File

@@ -2,7 +2,6 @@ using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection;
using Discord.Commands.Builders;

namespace Discord.Commands


+ 0
- 1
src/Discord.Net.Commands/Info/ParameterInfo.cs View File

@@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

namespace Discord.Commands
{


+ 1
- 2
src/Discord.Net.Commands/Map/CommandMap.cs View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;

namespace Discord.Commands
{
@@ -6,7 +6,6 @@ namespace Discord.Commands
{
private readonly CommandService _service;
private readonly CommandMapNode _root;
private static readonly string[] _blankAliases = new[] { "" };

public CommandMap(CommandService service)
{


+ 3
- 3
src/Discord.Net.Commands/Map/CommandMapNode.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -7,7 +7,7 @@ namespace Discord.Commands
{
internal class CommandMapNode
{
private static readonly char[] _whitespaceChars = new[] { ' ', '\r', '\n' };
private static readonly char[] WhitespaceChars = new[] { ' ', '\r', '\n' };

private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
private readonly string _name;
@@ -100,7 +100,7 @@ namespace Discord.Commands
}

//Check if this is the last command segment before args
nextSegment = NextSegment(text, index, _whitespaceChars, service._separatorChar);
nextSegment = NextSegment(text, index, WhitespaceChars, service._separatorChar);
if (nextSegment != -1)
{
name = text.Substring(index, nextSegment - index);


+ 1
- 1
src/Discord.Net.Commands/Results/ExecuteResult.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;

namespace Discord.Commands


+ 1
- 1
src/Discord.Net.Commands/Results/IResult.cs View File

@@ -1,6 +1,6 @@
namespace Discord.Commands
{
/// <summary> Represents the information of command execution result. </summary>
/// <summary> Represents information of the command execution result. </summary>
public interface IResult
{
/// <summary> Describes the error type that may have occurred during the operation. </summary>


+ 7
- 7
src/Discord.Net.Core/Audio/AudioStream.cs View File

@@ -11,10 +11,8 @@ namespace Discord.Audio
public override bool CanSeek => false;
public override bool CanWrite => false;

public virtual void WriteHeader(ushort seq, uint timestamp, bool missed)
{
throw new InvalidOperationException("This stream does not accept headers");
}
public virtual void WriteHeader(ushort seq, uint timestamp, bool missed) =>
throw new InvalidOperationException("This stream does not accept headers.");
public override void Write(byte[] buffer, int offset, int count)
{
WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
@@ -30,11 +28,13 @@ namespace Discord.Audio

public virtual Task ClearAsync(CancellationToken cancellationToken) { return Task.Delay(0); }

public override long Length { get { throw new NotSupportedException(); } }
public override long Length =>
throw new NotSupportedException();

public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}

public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }


+ 18
- 6
src/Discord.Net.Core/Commands/ICommandContext.cs View File

@@ -1,17 +1,29 @@
namespace Discord.Commands
{
/// <summary> Represents the context of a command. This may include the client, guild, channel, user, and message. </summary>
/// <summary>
/// Represents the context of a command. This may include the client, guild, channel, user, and message.
/// </summary>
public interface ICommandContext
{
/// <summary> Gets the <see cref="IDiscordClient"/> that the command is executed with. </summary>
/// <summary>
/// Gets the <see cref="IDiscordClient" /> that the command is executed with.
/// </summary>
IDiscordClient Client { get; }
/// <summary> Gets the <see cref="IGuild"/> that the command is executed in. </summary>
/// <summary>
/// Gets the <see cref="IGuild" /> that the command is executed in.
/// </summary>
IGuild Guild { get; }
/// <summary> Gets the <see cref="IMessageChannel"/> that the command is executed in. </summary>
/// <summary>
/// Gets the <see cref="IMessageChannel" /> that the command is executed in.
/// </summary>
IMessageChannel Channel { get; }
/// <summary> Gets the <see cref="IUser"/> who executed the command. </summary>
/// <summary>
/// Gets the <see cref="IUser" /> who executed the command.
/// </summary>
IUser User { get; }
/// <summary> Gets the <see cref="IUserMessage"/> that the command is interpreted from. </summary>
/// <summary>
/// Gets the <see cref="IUserMessage" /> that the command is interpreted from.
/// </summary>
IUserMessage Message { get; }
}
}

+ 15
- 5
src/Discord.Net.Core/Entities/Activities/ActivityType.cs View File

@@ -1,15 +1,25 @@
namespace Discord
{
/// <summary> Specifies a Discord user's activity type. </summary>
/// <summary>
/// Specifies a Discord user's activity type.
/// </summary>
public enum ActivityType
{
/// <summary> The user is playing a game. </summary>
/// <summary>
/// The user is playing a game.
/// </summary>
Playing = 0,
/// <summary> The user is streaming online. </summary>
/// <summary>
/// The user is streaming online.
/// </summary>
Streaming = 1,
/// <summary> The user is listening to a song. </summary>
/// <summary>
/// The user is listening to a song.
/// </summary>
Listening = 2,
/// <summary> The user is watching a media. </summary>
/// <summary>
/// The user is watching a media.
/// </summary>
Watching = 3
}
}

+ 7
- 3
src/Discord.Net.Core/Entities/Activities/Game.cs View File

@@ -2,7 +2,9 @@ using System.Diagnostics;

namespace Discord
{
/// <summary> A user's game activity. </summary>
/// <summary>
/// A user's game activity.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class Game : IActivity
{
@@ -12,9 +14,11 @@ namespace Discord
public ActivityType Type { get; internal set; }

internal Game() { }
/// <summary> Creates a <see cref="Game"/> with the provided name and <see cref="ActivityType"/>. </summary>
/// <summary>
/// Creates a <see cref="Game"/> with the provided <paramref name="name"/> and <see cref="ActivityType"/>.
/// </summary>
/// <param name="name">The name of the game.</param>
/// <param name="type">The type of activity. Default is <see cref="ActivityType.Playing"/>. </param>
/// <param name="type">The type of activity. Default is <see cref="Discord.ActivityType.Playing" /> .</param>
public Game(string name, ActivityType type = ActivityType.Playing)
{
Name = name;


+ 12
- 4
src/Discord.Net.Core/Entities/Activities/GameAsset.cs View File

@@ -1,18 +1,26 @@
namespace Discord
{
/// <summary> An asset for a <see cref="RichGame"/> object. </summary>
/// <summary>
/// An asset for a <see cref="RichGame" /> object.
/// </summary>
public class GameAsset
{
internal GameAsset() { }

internal ulong? ApplicationId { get; set; }

/// <summary> The description of the asset. </summary>
/// <summary>
/// Gets the description of the asset.
/// </summary>
public string Text { get; internal set; }
/// <summary> The image ID of the asset. </summary>
/// <summary>
/// Gets the image ID of the asset.
/// </summary>
public string ImageId { get; internal set; }

/// <summary> The image URL of the asset; may return null when the application ID does not exist.</summary>
/// <summary>
/// Returns the image URL of the asset, or <see langword="null"/> when the application ID does not exist.
/// </summary>
public string GetImageUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128)
=> ApplicationId.HasValue ? CDN.GetRichAssetUrl(ApplicationId.Value, ImageId, size, format) : null;
}


+ 6
- 0
src/Discord.Net.Core/Entities/Activities/GameParty.cs View File

@@ -4,8 +4,14 @@ namespace Discord
{
internal GameParty() { }

/// <summary>
/// Gets the id of the party.
/// </summary>
public string Id { get; internal set; }
public long Members { get; internal set; }
/// <summary>
/// Gets the party's current and maximum size.
/// </summary>
public long Capacity { get; internal set; }
}
}

+ 11
- 2
src/Discord.Net.Core/Entities/Activities/GameSecrets.cs View File

@@ -1,9 +1,18 @@
namespace Discord
namespace Discord
{
public class GameSecrets
{
/// <summary>
/// Gets the secret for a specific instanced match.
/// </summary>
public string Match { get; }
/// <summary>
/// Gets the secret for joining a party.
/// </summary>
public string Join { get; }
/// <summary>
/// Gets the secret for spectating a game.
/// </summary>
public string Spectate { get; }

internal GameSecrets(string match, string join, string spectate)
@@ -13,4 +22,4 @@
Spectate = spectate;
}
}
}
}

+ 9
- 1
src/Discord.Net.Core/Entities/Activities/GameTimestamps.cs View File

@@ -2,10 +2,18 @@ using System;

namespace Discord
{
/// <summary> Timestamps for a <see cref="RichGame"/> object. </summary>
/// <summary>
/// Timestamps for a <see cref="RichGame" /> object.
/// </summary>
public class GameTimestamps
{
/// <summary>
/// Gets when the activity started.
/// </summary>
public DateTimeOffset? Start { get; }
/// <summary>
/// Gets when the activity ends.
/// </summary>
public DateTimeOffset? End { get; }

internal GameTimestamps(DateTimeOffset? start, DateTimeOffset? end)


+ 9
- 3
src/Discord.Net.Core/Entities/Activities/IActivity.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> A Discord activity. </summary>
/// <summary>
/// A Discord activity, typically a game.
/// </summary>
public interface IActivity
{
/// <summary> Gets the name of the activity. </summary>
/// <summary>
/// Gets the name of the activity.
/// </summary>
string Name { get; }
/// <summary> Gets the type of the activity. </summary>
/// <summary>
/// Gets the type of the activity.
/// </summary>
ActivityType Type { get; }
}
}

+ 28
- 1
src/Discord.Net.Core/Entities/Activities/RichGame.cs View File

@@ -7,15 +7,42 @@ namespace Discord
{
internal RichGame() { }

/// <summary>
/// Gets what the player is currently doing.
/// </summary>
public string Details { get; internal set; }
/// <summary>
/// Gets the user's current party status.
/// </summary>
public string State { get; internal set; }
/// <summary>
/// Gets the application ID for the game.
/// </summary>
public ulong ApplicationId { get; internal set; }
/// <summary>
/// Gets the small image for the presence and their hover texts.
/// </summary>
public GameAsset SmallAsset { get; internal set; }
/// <summary>
/// Gets the large image for the presence and their hover texts.
/// </summary>
public GameAsset LargeAsset { get; internal set; }
/// <summary>
/// Gets the information for the current party of the player.
/// </summary>
public GameParty Party { get; internal set; }
/// <summary>
/// Gets the secrets for Rich Presence joining and spectating.
/// </summary>
public GameSecrets Secrets { get; internal set; }
/// <summary>
/// Gets the timestamps for start and/or end of the game.
/// </summary>
public GameTimestamps Timestamps { get; internal set; }

/// <summary>
/// Returns the name of the Rich Presence.
/// </summary>
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} (Rich)";
}


+ 24
- 8
src/Discord.Net.Core/Entities/Activities/SpotifyGame.cs View File

@@ -4,23 +4,39 @@ using System.Diagnostics;

namespace Discord
{
/// <summary> A user's activity for listening to a song on Spotify. </summary>
/// <summary>
/// A user's activity for listening to a song on Spotify.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class SpotifyGame : Game
{
/// <summary> Gets the song's artist(s). </summary>
/// <summary>
/// Gets the song's artist(s).
/// </summary>
public IEnumerable<string> Artists { get; internal set; }
/// <summary> Gets the Spotify album art for the song. </summary>
/// <summary>
/// Gets the Spotify album art of the song.
/// </summary>
public string AlbumArt { get; internal set; }
/// <summary> Gets the Spotify album title for the song. </summary>
/// <summary>
/// Gets the Spotify album title of the song.
/// </summary>
public string AlbumTitle { get; internal set; }
/// <summary> Gets the track title for the song. </summary>
/// <summary>
/// Gets the track title of the song.
/// </summary>
public string TrackTitle { get; internal set; }
/// <summary> Gets the synchronization ID for the song. </summary>
/// <summary>
/// Gets the synchronization ID of the song.
/// </summary>
public string SyncId { get; internal set; }
/// <summary> Gets the session ID for the song. </summary>
/// <summary>
/// Gets the session ID of the song.
/// </summary>
public string SessionId { get; internal set; }
/// <summary> Gets the duration for the song. </summary>
/// <summary>
/// Gets the duration of the song.
/// </summary>
public TimeSpan? Duration { get; internal set; }

internal SpotifyGame() { }


+ 14
- 3
src/Discord.Net.Core/Entities/Activities/StreamingGame.cs View File

@@ -2,13 +2,22 @@ using System.Diagnostics;

namespace Discord
{
/// <summary> A user's activity for streaming on services such as Twitch. </summary>
/// <summary>
/// A user's activity for streaming on services such as Twitch.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class StreamingGame : Game
{
/// <summary> Gets the URL of the stream. </summary>
/// <summary>
/// Gets the URL of the stream.
/// </summary>
public string Url { get; internal set; }

/// <summary>
/// Creates a new <see cref="StreamingGame" /> based on the <paramref name="name"/> on the stream URL.
/// </summary>
/// <param name="name">The name of the stream.</param>
/// <param name="url">The URL of the stream.</param>
public StreamingGame(string name, string url)
{
Name = name;
@@ -16,7 +25,9 @@ namespace Discord
Type = ActivityType.Streaming;
}

/// <summary> Gets the name of the stream. </summary>
/// <summary>
/// Gets the name of the stream.
/// </summary>
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Url})";
}


+ 9
- 3
src/Discord.Net.Core/Entities/CacheMode.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> Specifies the cache mode that should be used. </summary>
/// <summary>
/// Specifies the cache mode that should be used.
/// </summary>
public enum CacheMode
{
/// <summary> Allows the object to be downloaded if it does not exist in the current cache. </summary>
/// <summary>
/// Allows the object to be downloaded if it does not exist in the current cache.
/// </summary>
AllowDownload,
/// <summary> Only allows the object to be pulled from the existing cache. </summary>
/// <summary>
/// Only allows the object to be pulled from the existing cache.
/// </summary>
CacheOnly
}
}

+ 15
- 13
src/Discord.Net.Core/Entities/Channels/GuildChannelProperties.cs View File

@@ -1,33 +1,35 @@
namespace Discord
{
/// <summary>
/// Properties that are used to modify an <see cref="IGuildChannel"/> with the specified changes.
/// Properties that are used to modify an <see cref="IGuildChannel" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await (Context.Channel as ITextChannel)?.ModifyAsync(x =>
/// {
/// x.Name = "do-not-enter";
/// });
/// </code>
/// <code lang="c#">
/// await (Context.Channel as ITextChannel)?.ModifyAsync(x =&gt;
/// {
/// x.Name = "do-not-enter";
/// });
/// </code>
/// </example>
public class GuildChannelProperties
{
/// <summary>
/// Sets the channel to this name.
/// Gets or sets the channel to this name.
/// </summary>
/// <remarks>
/// When modifying an ITextChannel, the Name MUST be alphanumeric with dashes.
/// It must match the following RegEx: [a-z0-9-_]{2,100}
/// When modifying an <see cref="ITextChannel" />, the <see cref="Name" />
/// MUST be alphanumeric with dashes. It must match the following RegEx: [a-z0-9-_]{2,100}
/// </remarks>
/// <exception cref="Net.HttpException">A BadRequest will be thrown if the name does not match the above RegEx.</exception>
/// <exception cref="Discord.Net.HttpException">
/// A BadRequest will be thrown if the name does not match the above RegEx.
/// </exception>
public Optional<string> Name { get; set; }
/// <summary>
/// Moves the channel to the following position. This is 0-based!
/// Moves the channel to the following position. This is 0-based!
/// </summary>
public Optional<int> Position { get; set; }
/// <summary>
/// Sets the category for this channel.
/// Gets or sets the category for this channel.
/// </summary>
public Optional<ulong?> CategoryId { get; set; }
}


+ 7
- 2
src/Discord.Net.Core/Entities/Channels/IAudioChannel.cs View File

@@ -1,12 +1,17 @@
using Discord.Audio;
using Discord.Audio;
using System;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a generic audio channel.
/// </summary>
public interface IAudioChannel : IChannel
{
/// <summary> Connects to this audio channel. </summary>
/// <summary>
/// Connects to this audio channel.
/// </summary>
Task<IAudioClient> ConnectAsync(Action<IAudioClient> configAction = null);
}
}

+ 3
- 6
src/Discord.Net.Core/Entities/Channels/ICategoryChannel.cs View File

@@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a generic category channel.
/// </summary>
public interface ICategoryChannel : IGuildChannel
{
}


+ 12
- 4
src/Discord.Net.Core/Entities/Channels/IChannel.cs View File

@@ -3,16 +3,24 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary> Represents a generic Discord channel. </summary>
/// <summary>
/// Represents a generic Discord channel.
/// </summary>
public interface IChannel : ISnowflakeEntity
{
/// <summary> Gets the name of this channel. </summary>
/// <summary>
/// Gets the name of this channel.
/// </summary>
string Name { get; }
/// <summary> Gets a collection of all users in this channel. </summary>
/// <summary>
/// Gets a collection of all users in this channel.
/// </summary>
IAsyncEnumerable<IReadOnlyCollection<IUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a user in this channel with the provided id. </summary>
/// <summary>
/// Gets a user in this channel with the provided ID.
/// </summary>
Task<IUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
}
}

+ 11
- 4
src/Discord.Net.Core/Entities/Channels/IDMChannel.cs View File

@@ -1,13 +1,20 @@
using System.Threading.Tasks;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a generic DM channel.
/// </summary>
public interface IDMChannel : IMessageChannel, IPrivateChannel
{
/// <summary> Gets the recipient of all messages in this channel. </summary>
/// <summary>
/// Gets the recipient of all messages in this channel.
/// </summary>
IUser Recipient { get; }

/// <summary> Closes this private channel, removing it from your channel list. </summary>
/// <summary>
/// Closes this private channel, removing it from your channel list.
/// </summary>
Task CloseAsync(RequestOptions options = null);
}
}
}

+ 8
- 3
src/Discord.Net.Core/Entities/Channels/IGroupChannel.cs View File

@@ -1,10 +1,15 @@
using System.Threading.Tasks;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a generic group channel.
/// </summary>
public interface IGroupChannel : IMessageChannel, IPrivateChannel, IAudioChannel
{
/// <summary> Leaves this group. </summary>
/// <summary>
/// Leaves this group.
/// </summary>
Task LeaveAsync(RequestOptions options = null);
}
}
}

+ 66
- 21
src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs View File

@@ -4,50 +4,95 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary> Represents a guild channel (text, voice, category). </summary>
/// <summary>
/// Represents a guild channel (text, voice, category).
/// </summary>
public interface IGuildChannel : IChannel, IDeletable
{
/// <summary> Gets the position of this channel in the guild's channel list, relative to others of the same type. </summary>
/// <summary>
/// Gets the position of this channel in the guild's channel list, relative to others of the same type.
/// </summary>
int Position { get; }

/// <summary> Gets the parent ID (category) of this channel in the guild's channel list. </summary>
/// <summary>
/// Gets the parent ID (category) of this channel in the guild's channel list.
/// </summary>
ulong? CategoryId { get; }
/// <summary> Gets the parent channel (category) of this channel. </summary>
/// <summary>
/// Gets the parent channel (category) of this channel.
/// </summary>
Task<ICategoryChannel> GetCategoryAsync();
/// <summary> Gets the guild this channel is a member of. </summary>
/// <summary>
/// Gets the guild this channel is a member of.
/// </summary>
IGuild Guild { get; }
/// <summary> Gets the id of the guild this channel is a member of. </summary>
/// <summary>
/// Gets the id of the guild this channel is a member of.
/// </summary>
ulong GuildId { get; }
/// <summary> Gets a collection of permission overwrites for this channel. </summary>
/// <summary>
/// Gets a collection of permission overwrites for this channel.
/// </summary>
IReadOnlyCollection<Overwrite> PermissionOverwrites { get; }

/// <summary> Creates a new invite to this channel. </summary>
/// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param>
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param>
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param>
/// <summary>
/// Creates a new invite to this channel.
/// </summary>
/// <param name="maxAge">
/// The time (in seconds) until the invite expires. Set to <see langword="null"/> to never expire.
/// </param>
/// <param name="maxUses">
/// The max amount of times this invite may be used. Set to <see langword="null"/> to have unlimited uses.
/// </param>
/// <param name="isTemporary">
/// If <see langword="true"/>, a user accepting this invite will be kicked from the guild after closing their client.
/// </param>
/// <param name="isUnique">
/// If <see langword="true"/>, don't try to reuse a similar invite (useful for creating many unique one time use invites).
/// </param>
Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null);
/// <summary> Returns a collection of all invites to this channel. </summary>
/// <summary>
/// Returns a collection of all invites to this channel.
/// </summary>
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null);

/// <summary> Modifies this guild channel. </summary>
/// <summary>
/// Modifies this guild channel.
/// </summary>
Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null);

/// <summary> Gets the permission overwrite for a specific role, or null if one does not exist. </summary>
/// <summary>
/// Gets the permission overwrite for a specific role, or <see langword="null"/> if one does not exist.
/// </summary>
OverwritePermissions? GetPermissionOverwrite(IRole role);
/// <summary> Gets the permission overwrite for a specific user, or null if one does not exist. </summary>
/// <summary>
/// Gets the permission overwrite for a specific user, or <see langword="null"/> if one does not exist.
/// </summary>
OverwritePermissions? GetPermissionOverwrite(IUser user);
/// <summary> Removes the permission overwrite for the given role, if one exists. </summary>
/// <summary>
/// Removes the permission overwrite for the given role, if one exists.
/// </summary>
Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null);
/// <summary> Removes the permission overwrite for the given user, if one exists. </summary>
/// <summary>
/// Removes the permission overwrite for the given user, if one exists.
/// </summary>
Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null);
/// <summary> Adds or updates the permission overwrite for the given role. </summary>
/// <summary>
/// Adds or updates the permission overwrite for the given role.
/// </summary>
Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null);
/// <summary> Adds or updates the permission overwrite for the given user. </summary>
/// <summary>
/// Adds or updates the permission overwrite for the given user.
/// </summary>
Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null);

/// <summary> Gets a collection of all users in this channel. </summary>
/// <summary>
/// Gets a collection of all users in this channel.
/// </summary>
new IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a user in this channel with the provided id.</summary>
/// <summary>
/// Gets a user in this channel with the provided ID.
/// </summary>
new Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
}
}

+ 34
- 10
src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs View File

@@ -5,34 +5,58 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a generic channel that can send and receive messages.
/// </summary>
public interface IMessageChannel : IChannel
{
/// <summary> Sends a message to this message channel. </summary>
/// <summary>
/// Sends a message to this message channel.
/// </summary>
Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#if FILESYSTEM
/// <summary> Sends a file to this text channel, with an optional caption. </summary>
/// <summary>
/// Sends a file to this <paramref name="text"/> channel, with an optional caption.
/// </summary>
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#endif
/// <summary> Sends a file to this text channel, with an optional caption. </summary>
/// <summary>
/// Sends a file to this <paramref name="text"/> channel, with an optional caption.
/// </summary>
Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);

/// <summary> Gets a message from this message channel with the given id, or null if not found. </summary>
/// <summary>
/// Gets a message from this message channel with the given id, or <see langword="null"/> if not found.
/// </summary>
Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the last N messages from this message channel. </summary>
/// <summary>
/// Gets the last N messages from this message channel.
/// </summary>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of messages in this channel. </summary>
/// <summary>
/// Gets a collection of messages in this channel.
/// </summary>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of messages in this channel. </summary>
/// <summary>
/// Gets a collection of messages in this channel.
/// </summary>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of pinned messages in this channel. </summary>
/// <summary>
/// Gets a collection of pinned messages in this channel.
/// </summary>
Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null);

/// <summary> Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds. </summary>
/// <summary>
/// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.
/// </summary>
Task TriggerTypingAsync(RequestOptions options = null);
/// <summary> Continuously broadcasts the "user is typing" message to all users in this channel until the returned object is disposed. </summary>
/// <summary>
/// Continuously broadcasts the "user is typing" message to all users in this channel until the returned
/// object is disposed.
/// </summary>
IDisposable EnterTypingState(RequestOptions options = null);
}
}

+ 7
- 1
src/Discord.Net.Core/Entities/Channels/IPrivateChannel.cs View File

@@ -1,9 +1,15 @@
using System.Collections.Generic;
using System.Collections.Generic;

namespace Discord
{
/// <summary>
/// Represents a generic channel that is private to select recipients.
/// </summary>
public interface IPrivateChannel : IChannel
{
/// <summary>
/// Users that can access this channel.
/// </summary>
IReadOnlyCollection<IUser> Recipients { get; }
}
}

+ 29
- 10
src/Discord.Net.Core/Entities/Channels/ITextChannel.cs View File

@@ -1,31 +1,50 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a generic channel in a guild that can send and receive messages.
/// </summary>
public interface ITextChannel : IMessageChannel, IMentionable, IGuildChannel
{
/// <summary> Checks if the channel is NSFW. </summary>
/// <summary>
/// Gets whether the channel is NSFW.
/// </summary>
bool IsNsfw { get; }

/// <summary> Gets the current topic for this text channel. </summary>
/// <summary>
/// Gets the current topic for this text channel.
/// </summary>
string Topic { get; }

/// <summary> Bulk deletes multiple messages. </summary>
/// <summary>
/// Bulk deletes multiple messages.
/// </summary>
Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null);
/// <summary> Bulk deletes multiple messages. </summary>
/// <summary>
/// Bulk deletes multiple messages.
/// </summary>
Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null);

/// <summary> Modifies this text channel. </summary>
/// <summary>
/// Modifies this text channel.
/// </summary>
Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null);

/// <summary> Creates a webhook in this text channel. </summary>
/// <summary>
/// Creates a webhook in this text channel.
/// </summary>
Task<IWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null);
/// <summary> Gets the webhook in this text channel with the provided id, or null if not found. </summary>
/// <summary>
/// Gets the webhook in this text channel with the provided ID, or <see langword="null"/> if not found.
/// </summary>
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null);
/// <summary> Gets the webhooks for this text channel. </summary>
/// <summary>
/// Gets the webhooks for this text channel.
/// </summary>
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null);
}
}
}

+ 15
- 5
src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs View File

@@ -1,16 +1,26 @@
using System;
using System;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a voice channel in a guild.
/// </summary>
public interface IVoiceChannel : IGuildChannel, IAudioChannel
{
/// <summary> Gets the bitrate, in bits per second, clients in this voice channel are requested to use. </summary>
/// <summary>
/// Gets the bitrate, in bits per second, clients in this voice channel are requested to use.
/// </summary>
int Bitrate { get; }
/// <summary> Gets the max amount of users allowed to be connected to this channel at one time. </summary>
/// <summary>
/// Gets the max amount of users allowed to be connected to this channel at one time, or
/// <see langword="null"/> if none is set.
/// </summary>
int? UserLimit { get; }

/// <summary> Modifies this voice channel. </summary>
/// <summary>
/// Modifies this voice channel.
/// </summary>
Task ModifyAsync(Action<VoiceChannelProperties> func, RequestOptions options = null);
}
}
}

+ 9
- 3
src/Discord.Net.Core/Entities/Channels/ReorderChannelProperties.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> Properties that are used to reorder an <see cref="IGuildChannel"/>. </summary>
/// <summary>
/// Properties that are used to reorder an <see cref="IGuildChannel" /> .
/// </summary>
public class ReorderChannelProperties
{
/// <summary> Gets the ID of the channel to apply this position to. </summary>
/// <summary>
/// Gets the ID of the channel to apply this position to.
/// </summary>
public ulong Id { get; }
/// <summary> Gets the new zero-based position of this channel. </summary>
/// <summary>
/// Gets the new zero-based position of this channel.
/// </summary>
public int Position { get; }

/// <summary> Creates a <see cref="ReorderChannelProperties"/> used to reorder a channel. </summary>


+ 6
- 4
src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs View File

@@ -1,14 +1,16 @@
namespace Discord
namespace Discord
{
/// <inheritdoc />
/// <summary>
/// Properties that are used to modify an <see cref="ITextChannel"/> with the specified changes.
/// </summary>
public class TextChannelProperties : GuildChannelProperties
{
/// <summary>
/// What the topic of the channel should be set to.
/// Gets or sets the topic of the channel.
/// </summary>
public Optional<string> Topic { get; set; }
/// <summary>
/// Should this channel be flagged as NSFW?
/// Gets or sets whether this channel should be flagged as NSFW.
/// </summary>
public Optional<bool> IsNsfw { get; set; }
}


+ 6
- 4
src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs View File

@@ -1,14 +1,16 @@
namespace Discord
namespace Discord
{
/// <inheritdoc />
/// <summary>
/// Properties that are used to modify an <see cref="IVoiceChannel" /> with the specified changes.
/// </summary>
public class VoiceChannelProperties : GuildChannelProperties
{
/// <summary>
/// The bitrate of the voice connections in this channel. Must be greater than 8000
/// Gets or sets the bitrate of the voice connections in this channel. Must be greater than 8000.
/// </summary>
public Optional<int> Bitrate { get; set; }
/// <summary>
/// The maximum number of users that can be present in a channel.
/// Gets or sets the maximum number of users that can be present in a channel, or <see langword="null"/> if none.
/// </summary>
public Optional<int?> UserLimit { get; set; }
}


+ 13
- 5
src/Discord.Net.Core/Entities/Emotes/Emoji.cs View File

@@ -1,17 +1,25 @@
namespace Discord
{
/// <summary> A Unicode emoji. </summary>
/// <summary>
/// A Unicode emoji.
/// </summary>
public class Emoji : IEmote
{
// TODO: need to constrain this to Unicode-only emojis somehow
/// <summary> Gets the Unicode representation of this emote. </summary>
/// <summary>
/// Gets the Unicode representation of this emote.
/// </summary>
public string Name { get; }
/// <summary> Gets the Unicode representation of this emote. </summary>
/// <summary>
/// Gets the Unicode representation of this emote.
/// </summary>
public override string ToString() => Name;

/// <summary> Creates a Unicode emoji. </summary>
/// <param name="unicode">The pure UTF-8 encoding of an emoji</param>
/// <summary>
/// Creates a Unicode emoji.
/// </summary>
/// <param name="unicode">The pure UTF-8 encoding of an emoji.</param>
public Emoji(string unicode)
{
Name = unicode;


+ 18
- 6
src/Discord.Net.Core/Entities/Emotes/Emote.cs View File

@@ -3,18 +3,30 @@ using System.Globalization;

namespace Discord
{
/// <summary> A custom image-based emote. </summary>
/// <summary>
/// A custom image-based emote.
/// </summary>
public class Emote : IEmote, ISnowflakeEntity
{
/// <summary> Gets the display name (tooltip) of this emote. </summary>
/// <summary>
/// Gets the display name (tooltip) of this emote.
/// </summary>
public string Name { get; }
/// <summary> Gets the ID of this emote. </summary>
/// <summary>
/// Gets the ID of this emote.
/// </summary>
public ulong Id { get; }
/// <summary> Gets whether this emote animated? </summary>
/// <summary>
/// Gets whether this emote is animated.
/// </summary>
public bool Animated { get; }
/// <summary> Gets the date when this emote is created. </summary>
/// <summary>
/// Gets the date when this emote is created.
/// </summary>
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
/// <summary> Gets the image URL of this emote. </summary>
/// <summary>
/// Gets the image URL of this emote.
/// </summary>
public string Url => CDN.GetEmojiUrl(Id, Animated);

internal Emote(ulong id, string name, bool animated)


+ 3
- 1
src/Discord.Net.Core/Entities/Emotes/GuildEmote.cs View File

@@ -3,7 +3,9 @@ using System.Diagnostics;

namespace Discord
{
/// <summary> An image-based emote that is attached to a guild. </summary>
/// <summary>
/// An image-based emote that is attached to a guild.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class GuildEmote : Emote
{


+ 7
- 3
src/Discord.Net.Core/Entities/Emotes/IEmote.cs View File

@@ -1,9 +1,13 @@
namespace Discord
namespace Discord
{
/// <summary> Represents a general container for any type of emote in a message. </summary>
/// <summary>
/// Represents a general container for any type of emote in a message.
/// </summary>
public interface IEmote
{
/// <summary> Gets the display name or Unicode representation of this emote. </summary>
/// <summary>
/// Gets the display name or Unicode representation of this emote.
/// </summary>
string Name { get; }
}
}

+ 9
- 3
src/Discord.Net.Core/Entities/Guilds/DefaultMessageNotifications.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> Specifies the default message notification behavior the guild uses. </summary>
/// <summary>
/// Specifies the default message notification behavior the guild uses.
/// </summary>
public enum DefaultMessageNotifications
{
/// <summary> By default, all messages will trigger notifications. </summary>
/// <summary>
/// By default, all messages will trigger notifications.
/// </summary>
AllMessages = 0,
/// <summary> By default, only mentions will trigger notifications. </summary>
/// <summary>
/// By default, only mentions will trigger notifications.
/// </summary>
MentionsOnly = 1
}
}

+ 4
- 4
src/Discord.Net.Core/Entities/Guilds/GuildEmbedProperties.cs View File

@@ -1,20 +1,20 @@
namespace Discord
{
/// <summary>
/// Properties that are used to modify the widget of an <see cref="IGuild"/> with the specified changes.
/// Properties that are used to modify the widget of an <see cref="IGuild" /> with the specified changes.
/// </summary>
public class GuildEmbedProperties
{
/// <summary>
/// Should the widget be enabled?
/// Sets whether the widget should be enabled.
/// </summary>
public Optional<bool> Enabled { get; set; }
/// <summary>
/// What channel should the invite place users in, if not null.
/// Sets the channel that the invite should place its users in, if not <see langword="null"/>.
/// </summary>
public Optional<IChannel> Channel { get; set; }
/// <summary>
/// What channel should the invite place users in, if not null.
/// Sets the channel the invite should place its users in, if not <see langword="null"/>.
/// </summary>
public Optional<ulong?> ChannelId { get; set; }
}


+ 12
- 4
src/Discord.Net.Core/Entities/Guilds/GuildIntegrationProperties.cs View File

@@ -1,13 +1,21 @@
namespace Discord
{
/// <summary> Properties used to modify an <see cref="IGuildIntegration"/> with the specified changes.</summary>
/// <summary>
/// Properties used to modify an <see cref="IGuildIntegration" /> with the specified changes.
/// </summary>
public class GuildIntegrationProperties
{
/// <summary> Gets or sets the behavior when an integration subscription lapses. </summary>
/// <summary>
/// Gets or sets the behavior when an integration subscription lapses.
/// </summary>
public Optional<int> ExpireBehavior { get; set; }
/// <summary> Gets or sets the period (in seconds) where the integration will ignore lapsed subscriptions. </summary>
/// <summary>
/// Gets or sets the period (in seconds) where the integration will ignore lapsed subscriptions.
/// </summary>
public Optional<int> ExpireGracePeriod { get; set; }
/// <summary> Gets or sets whether emoticons should be synced for this integration. </summary>
/// <summary>
/// Gets or sets whether emoticons should be synced for this integration.
/// </summary>
public Optional<bool> EnableEmoticons { get; set; }
}
}

+ 24
- 23
src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs View File

@@ -1,78 +1,79 @@
namespace Discord
{
/// <summary>
/// Properties that are used to modify an <see cref="IGuild"/> with the specified changes.
/// Properties that are used to modify an <see cref="IGuild" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await Context.Guild.ModifyAsync(async x =>
/// {
/// x.Name = "aaaaaah";
/// x.RegionId = (await Context.Client.GetOptimalVoiceRegionAsync()).Id;
/// });
/// <code lang="c#">
/// await Context.Guild.ModifyAsync(async x =&gt;
/// {
/// x.Name = "aaaaaah";
/// x.RegionId = (await Context.Client.GetOptimalVoiceRegionAsync()).Id;
/// });
/// </code>
/// </example>
/// <see cref="IGuild"/>
/// <see cref="T:Discord.IGuild" />
public class GuildProperties
{
public Optional<string> Username { get; set; }
/// <summary>
/// The name of the Guild.
/// Gets or sets the name of the Guild.
/// </summary>
public Optional<string> Name { get; set; }
/// <summary>
/// The region for the Guild's voice connections.
/// Gets or sets the region for the Guild's voice connections.
/// </summary>
public Optional<IVoiceRegion> Region { get; set; }
/// <summary>
/// The ID of the region for the Guild's voice connections.
/// Gets or sets the ID of the region for the Guild's voice connections.
/// </summary>
public Optional<string> RegionId { get; set; }
/// <summary>
/// What verification level new users need to achieve before speaking.
/// Gets or sets the verification level new users need to achieve before speaking.
/// </summary>
public Optional<VerificationLevel> VerificationLevel { get; set; }
/// <summary>
/// The default message notification state for the guild.
/// Gets or sets the default message notification state for the guild.
/// </summary>
public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; }
/// <summary>
/// How many seconds before a user is sent to AFK. This value MUST be one of: (60, 300, 900, 1800, 3600).
/// Gets or sets how many seconds before a user is sent to AFK. This value MUST be one of: (60, 300, 900,
/// 1800, 3600).
/// </summary>
public Optional<int> AfkTimeout { get; set; }
/// <summary>
/// The icon of the guild.
/// Gets or sets the icon of the guild.
/// </summary>
public Optional<Image?> Icon { get; set; }
/// <summary>
/// The guild's splash image.
/// Gets or sets the guild's splash image.
/// </summary>
/// <remarks>
/// The guild must be partnered for this value to have any effect.
/// The guild must be partnered for this value to have any effect.
/// </remarks>
public Optional<Image?> Splash { get; set; }
/// <summary>
/// The IVoiceChannel where AFK users should be sent.
/// Gets or sets the <see cref="IVoiceChannel"/> where AFK users should be sent.
/// </summary>
public Optional<IVoiceChannel> AfkChannel { get; set; }
/// <summary>
/// The ID of the IVoiceChannel where AFK users should be sent.
/// Gets or sets the ID of the <see cref="IVoiceChannel"/> where AFK users should be sent.
/// </summary>
public Optional<ulong?> AfkChannelId { get; set; }
/// <summary>
/// The ITextChannel where System messages should be sent.
/// Gets or sets the <see cref="ITextChannel" /> where System messages should be sent.
/// </summary>
public Optional<ITextChannel> SystemChannel { get; set; }
/// <summary>
/// The ID of the ITextChannel where System messages should be sent.
/// Gets or sets the ID of the <see cref="ITextChannel" /> where System messages should be sent.
/// </summary>
public Optional<ulong?> SystemChannelId { get; set; }
/// <summary>
/// The owner of this guild.
/// Gets or sets the owner of this guild.
/// </summary>
public Optional<IUser> Owner { get; set; }
/// <summary>
/// The ID of the owner of this guild.
/// Gets or sets the ID of the owner of this guild.
/// </summary>
public Optional<ulong> OwnerId { get; set; }
}


+ 10
- 1
src/Discord.Net.Core/Entities/Guilds/IBan.cs View File

@@ -1,8 +1,17 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represents a generic ban object.
/// </summary>
public interface IBan
{
/// <summary>
/// Gets the banned user.
/// </summary>
IUser User { get; }
/// <summary>
/// Gets the reason why the user is banned.
/// </summary>
string Reason { get; }
}
}

+ 232
- 88
src/Discord.Net.Core/Entities/Guilds/IGuild.cs View File

@@ -7,166 +7,310 @@ namespace Discord
{
public interface IGuild : IDeletable, ISnowflakeEntity
{
/// <summary> Gets the name of this guild. </summary>
/// <summary>
/// Gets the name of this guild.
/// </summary>
string Name { get; }
/// <summary> Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are automatically moved to the AFK voice channel, if one is set. </summary>
/// <summary>
/// Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are
/// automatically moved to the AFK voice channel, if one is set.
/// </summary>
int AFKTimeout { get; }
/// <summary> Returns true if this guild is embeddable (e.g. widget) </summary>
/// <summary>
/// Returns <see langword="true"/> if this guild is embeddable (e.g. widget)
/// </summary>
bool IsEmbeddable { get; }
/// <summary> Gets the default message notifications for users who haven't explicitly set their notification settings. </summary>
/// <summary>
/// Gets the default message notifications for users who haven't explicitly set their notification settings.
/// </summary>
DefaultMessageNotifications DefaultMessageNotifications { get; }
/// <summary> Gets the level of Multi-Factor Authentication requirements a user must fulfill before being allowed to perform administrative actions in this guild. </summary>
/// <summary>
/// Gets the level of Multi-Factor Authentication requirements a user must fulfill before being allowed to
/// perform administrative actions in this guild.
/// </summary>
MfaLevel MfaLevel { get; }
/// <summary> Gets the level of requirements a user must fulfill before being allowed to post messages in this guild. </summary>
/// <summary>
/// Gets the level of requirements a user must fulfill before being allowed to post messages in this guild.
/// </summary>
VerificationLevel VerificationLevel { get; }
/// <summary> Returns the ID of this guild's icon, or null if one is not set. </summary>
/// <summary>
/// Returns the ID of this guild's icon, or <see langword="null"/> if one is not set.
/// </summary>
string IconId { get; }
/// <summary> Returns the url to this guild's icon, or null if one is not set. </summary>
/// <summary>
/// Returns the URL of this guild's icon, or <see langword="null"/> if one is not set.
/// </summary>
string IconUrl { get; }
/// <summary> Returns the ID of this guild's splash image, or null if one is not set. </summary>
/// <summary>
/// Returns the ID of this guild's splash image, or <see langword="null"/> if one is not set.
/// </summary>
string SplashId { get; }
/// <summary> Returns the url to this guild's splash image, or null if one is not set. </summary>
/// <summary>
/// Returns the URL of this guild's splash image, or <see langword="null"/> if one is not set.
/// </summary>
string SplashUrl { get; }
/// <summary> Returns true if this guild is currently connected and ready to be used. Only applies to the WebSocket client. </summary>
/// <summary>
/// Returns <see langword="true"/> if this guild is currently connected and ready to be used. Only applies
/// to the WebSocket client.
/// </summary>
bool Available { get; }

/// <summary> Gets the ID of the AFK voice channel for this guild if set, or null if not. </summary>
/// <summary>
/// Gets the ID of the AFK voice channel for this guild if set, or <see langword="null"/> if not.
/// </summary>
ulong? AFKChannelId { get; }
/// <summary> Gets the ID of the the default channel for this guild. </summary>
/// <summary>
/// Gets the ID of the the default channel for this guild.
/// </summary>
ulong DefaultChannelId { get; }
/// <summary> Gets the ID of the embed channel for this guild if set, or null if not. </summary>
/// <summary>
/// Gets the ID of the embed channel for this guild if set, or <see langword="null"/> if not.
/// </summary>
ulong? EmbedChannelId { get; }
/// <summary> Gets the ID of the channel where randomized welcome messages are sent, or null if not. </summary>
/// <summary>
/// Gets the ID of the channel where randomized welcome messages are sent, or <see langword="null"/> if not.
/// </summary>
ulong? SystemChannelId { get; }
/// <summary> Gets the ID of the user that created this guild. </summary>
/// <summary>
/// Gets the ID of the user that created this guild.
/// </summary>
ulong OwnerId { get; }
/// <summary> Gets the ID of the region hosting this guild's voice channels. </summary>
/// <summary>
/// Gets the ID of the region hosting this guild's voice channels.
/// </summary>
string VoiceRegionId { get; }
/// <summary> Gets the <see cref="IAudioClient"/> currently associated with this guild. </summary>
/// <summary>
/// Gets the <see cref="IAudioClient" /> currently associated with this guild.
/// </summary>
IAudioClient AudioClient { get; }
/// <summary> Gets the built-in role containing all users in this guild. </summary>
/// <summary>
/// Gets the built-in role containing all users in this guild.
/// </summary>
IRole EveryoneRole { get; }
/// <summary> Gets a collection of all custom emojis for this guild. </summary>
/// <summary>
/// Gets a collection of all custom emotes for this guild.
/// </summary>
IReadOnlyCollection<GuildEmote> Emotes { get; }
/// <summary> Gets a collection of all extra features added to this guild. </summary>
/// <summary>
/// Gets a collection of all extra features added to this guild.
/// </summary>
IReadOnlyCollection<string> Features { get; }
/// <summary> Gets a collection of all roles in this guild. </summary>
/// <summary>
/// Gets a collection of all roles in this guild.
/// </summary>
IReadOnlyCollection<IRole> Roles { get; }

/// <summary> Modifies this guild. </summary>
/// <summary>
/// Modifies this guild.
/// </summary>
Task ModifyAsync(Action<GuildProperties> func, RequestOptions options = null);
/// <summary> Modifies this guild's embed. </summary>
/// <summary>
/// Modifies this guild's embed channel.
/// </summary>
Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null);
/// <summary> Bulk modifies the channels of this guild. </summary>
/// <summary>
/// Bulk modifies the order of channels in this guild.
/// </summary>
Task ReorderChannelsAsync(IEnumerable<ReorderChannelProperties> args, RequestOptions options = null);
/// <summary> Bulk modifies the roles of this guild. </summary>
/// <summary>
/// Bulk modifies the order of roles in this guild.
/// </summary>
Task ReorderRolesAsync(IEnumerable<ReorderRoleProperties> args, RequestOptions options = null);
/// <summary> Leaves this guild. If you are the owner, use Delete instead. </summary>
/// <summary>
/// Leaves this guild. If you are the owner, use
/// <see cref="IDeletable.DeleteAsync(Discord.RequestOptions)" /> instead.
/// </summary>
Task LeaveAsync(RequestOptions options = null);

/// <summary> Gets a collection of all users banned on this guild. </summary>
/// <summary>
/// Gets a collection of all users banned on this guild.
/// </summary>
Task<IReadOnlyCollection<IBan>> GetBansAsync(RequestOptions options = null);
/// <summary> Bans the provided user from this guild and optionally prunes their recent messages. </summary>
/// <param name="user"> The user to ban. </param>
/// <param name="pruneDays"> The number of days to remove messages from this user for - must be between [0, 7]</param>
/// <param name="reason"> The reason of the ban to be written in the audit log. </param>
/// <summary>
/// Bans the provided <paramref name="user"/> from this guild and optionally prunes their recent messages.
/// </summary>
/// <param name="user">
/// The user to ban.
/// </param>
/// <param name="pruneDays">
/// The number of days to remove messages from this <paramref name="user"/> for - must be between [0, 7]
/// </param>
/// <param name="reason">
/// The reason of the ban to be written in the audit log.
/// </param>
Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null);
/// <summary> Bans the provided user ID from this guild and optionally prunes their recent messages. </summary>
/// <param name="userId"> The ID of the user to ban. </param>
/// <param name="pruneDays">The number of days to remove messages from this user for - must be between [0, 7]</param>
/// <param name="reason"> The reason of the ban to be written in the audit log. </param>
/// <summary>
/// Bans the provided user ID from this guild and optionally prunes their recent messages.
/// </summary>
/// <param name="userId">
/// The ID of the user to ban.
/// </param>
/// <param name="pruneDays">
/// The number of days to remove messages from this user for - must be between [0, 7]
/// </param>
/// <param name="reason">
/// The reason of the ban to be written in the audit log.
/// </param>
Task AddBanAsync(ulong userId, int pruneDays = 0, string reason = null, RequestOptions options = null);
/// <summary> Unbans the provided user if it is currently banned. </summary>
/// <summary>
/// Unbans the provided <paramref name="user"/> if they are currently banned.
/// </summary>
Task RemoveBanAsync(IUser user, RequestOptions options = null);
/// <summary> Unbans the provided user ID if it is currently banned. </summary>
/// <summary>
/// Unbans the provided user ID if it is currently banned.
/// </summary>
Task RemoveBanAsync(ulong userId, RequestOptions options = null);

/// <summary> Gets a collection of all channels in this guild. </summary>
/// <summary>
/// Gets a collection of all channels in this guild.
/// </summary>
Task<IReadOnlyCollection<IGuildChannel>> GetChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the channel in this guild with the provided ID, or null if not found. </summary>
/// <param name="id"> The channel ID. </param>
/// <summary>
/// Gets the channel in this guild with the provided ID, or <see langword="null"/> if not found.
/// </summary>
/// <param name="id">The channel ID.</param>
Task<IGuildChannel> GetChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of all text channels in this guild. </summary>
/// <summary>
/// Gets a collection of all text channels in this guild.
/// </summary>
Task<IReadOnlyCollection<ITextChannel>> GetTextChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a text channel in this guild with the provided ID, or null if not found. </summary>
/// <param name="id"> The text channel ID. </param>
/// <summary>
/// Gets a text channel in this guild with the provided ID, or <see langword="null"/> if not found.
/// </summary>
/// <param name="id">The text channel ID.</param>
Task<ITextChannel> GetTextChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of all voice channels in this guild. </summary>
/// <summary>
/// Gets a collection of all voice channels in this guild.
/// </summary>
Task<IReadOnlyCollection<IVoiceChannel>> GetVoiceChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of all category channels in this guild. </summary>
/// <summary>
/// Gets a collection of all category channels in this guild.
/// </summary>
Task<IReadOnlyCollection<ICategoryChannel>> GetCategoriesAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the voice channel in this guild with the provided ID, or null if not found. </summary>
/// <param name="id"> The text channel ID. </param>
/// <summary>
/// Gets the voice channel in this guild with the provided ID, or <see langword="null"/> if not found.
/// </summary>
/// <param name="id">The text channel ID.</param>
Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the voice AFK channel in this guild with the provided ID, or null if not found. </summary>
/// <summary>
/// Gets the voice AFK channel in this guild with the provided ID, or <see langword="null"/> if not found.
/// </summary>
Task<IVoiceChannel> GetAFKChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the default system text channel in this guild with the provided ID, or null if none is set. </summary>
/// <summary>
/// Gets the default system text channel in this guild with the provided ID, or <see langword="null"/> if
/// none is set.
/// </summary>
Task<ITextChannel> GetSystemChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the top viewable text channel in this guild with the provided ID, or null if not found. </summary>
/// <summary>
/// Gets the top viewable text channel in this guild with the provided ID, or <see langword="null"/> if not
/// found.
/// </summary>
Task<ITextChannel> GetDefaultChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the embed channel in this guild. </summary>
/// <summary>
/// Gets the embed channel in this guild.
/// </summary>
Task<IGuildChannel> GetEmbedChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Creates a new text channel. </summary>
/// <param name="name"> The new name for the text channel. </param>
/// <summary>
/// Creates a new text channel.
/// </summary>
/// <param name="name">The new name for the text channel.</param>
Task<ITextChannel> CreateTextChannelAsync(string name, RequestOptions options = null);
/// <summary> Creates a new voice channel. </summary>
/// <param name="name"> The new name for the voice channel. </param>
/// <summary>
/// Creates a new voice channel.
/// </summary>
/// <param name="name">The new name for the voice channel.</param>
Task<IVoiceChannel> CreateVoiceChannelAsync(string name, RequestOptions options = null);
/// <summary> Creates a new channel category. </summary>
/// <param name="name"> The new name for the category. </param>
/// <summary>
/// Creates a new channel category.
/// </summary>
/// <param name="name">The new name for the category.</param>
Task<ICategoryChannel> CreateCategoryAsync(string name, RequestOptions options = null);

Task<IReadOnlyCollection<IGuildIntegration>> GetIntegrationsAsync(RequestOptions options = null);
Task<IGuildIntegration> CreateIntegrationAsync(ulong id, string type, RequestOptions options = null);

/// <summary> Gets a collection of all invites to this guild. </summary>
/// <summary>
/// Gets a collection of all invites to this guild.
/// </summary>
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null);

/// <summary> Gets the role in this guild with the provided ID, or null if not found. </summary>
/// <param name="id"> The role ID. </param>
/// <summary>
/// Gets the role in this guild with the provided ID, or <see langword="null"/> if not found.
/// </summary>
/// <param name="id">The role ID.</param>
IRole GetRole(ulong id);
/// <summary> Creates a new role with the provided name. </summary>
/// <param name="name"> The new name for the role. </param>
/// <param name="permissions"> The guild permission that the role should possess. </param>
/// <param name="color"> The color of the role. </param>
/// <param name="isHoisted"> Whether the role is separated from others on the sidebar. </param>
/// <summary>
/// Creates a new role with the provided name.
/// </summary>
/// <param name="name">The new name for the role.</param>
/// <param name="permissions">The guild permission that the role should possess.</param>
/// <param name="color">The color of the role.</param>
/// <param name="isHoisted">Whether the role is separated from others on the sidebar.</param>
Task<IRole> CreateRoleAsync(string name, GuildPermissions? permissions = null, Color? color = null, bool isHoisted = false, RequestOptions options = null);

/// <summary> Gets a collection of all users in this guild. </summary>
/// <summary>
/// Gets a collection of all users in this guild.
/// </summary>
Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); //TODO: shouldnt this be paged?
/// <summary> Gets the user in this guild with the provided ID, or null if not found. </summary>
/// <param name="id"> The user ID. </param>
/// <summary>
/// Gets the user in this guild with the provided ID, or <see langword="null"/> if not found.
/// </summary>
/// <param name="id">The user ID.</param>
Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the current user for this guild. </summary>
/// <summary>
/// Gets the current user for this guild.
/// </summary>
Task<IGuildUser> GetCurrentUserAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the owner of this guild. </summary>
/// <summary>
/// Gets the owner of this guild.
/// </summary>
Task<IGuildUser> GetOwnerAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Downloads all users for this guild if the current list is incomplete. </summary>
/// <summary>
/// Downloads all users for this guild if the current list is incomplete.
/// </summary>
Task DownloadUsersAsync();
/// <summary> Removes all users from this guild if they have not logged on in a provided number of days or, if simulate is true, returns the number of users that would be removed. </summary>
/// <param name="days"> The number of days required for the users to be kicked. </param>
/// <param name="simulate"> Whether this prune action is a simulation. </param>
/// <return> The number of users removed from this guild. </return>
/// <summary>
/// Removes all users from this guild if they have not logged on in a provided number of
/// <paramref name="days"/> or, if <paramref name="simulate"/> is true, returns the number of users that
/// would be removed.
/// </summary>
/// <param name="days">The number of days required for the users to be kicked.</param>
/// <param name="simulate">Whether this prune action is a simulation.</param>
/// <returns>
/// The number of users removed from this guild.
/// </returns>
Task<int> PruneUsersAsync(int days = 30, bool simulate = false, RequestOptions options = null);

/// <summary> Gets the webhook in this guild with the provided ID, or null if not found. </summary>
/// <param name="id"> The webhook ID. </param>
/// <summary>
/// Gets the webhook in this guild with the provided ID, or <see langword="null"/> if not found.
/// </summary>
/// <param name="id">The webhook ID.</param>
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null);
/// <summary> Gets a collection of all webhooks for this guild. </summary>
/// <summary>
/// Gets a collection of all webhooks from this guild.
/// </summary>
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null);
/// <summary> Gets a specific emote from this guild. </summary>
/// <param name="id"> The guild emote ID. </param>
/// <summary>
/// Gets a specific emote from this guild.
/// </summary>
/// <param name="id">The guild emote ID.</param>
Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null);
/// <summary> Creates a new emote in this guild. </summary>
/// <param name="name"> The name of the guild emote. </param>
/// <param name="image"> The image of the new emote. </param>
/// <param name="roles"> The roles to limit the emote usage to. </param>
/// <summary>
/// Creates a new emote in this guild.
/// </summary>
/// <param name="name">The name of the guild emote.</param>
/// <param name="image">The image of the new emote.</param>
/// <param name="roles">The roles to limit the emote usage to.</param>
Task<GuildEmote> CreateEmoteAsync(string name, Image image, Optional<IEnumerable<IRole>> roles = default(Optional<IEnumerable<IRole>>), RequestOptions options = null);
/// <summary> Modifies an existing emote in this guild. </summary>
/// <summary>
/// Modifies an existing <paramref name="emote"/> in this guild.
/// </summary>
Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null);
/// <summary> Deletes an existing emote from this guild. </summary>
/// <param name="emote"> The guild emote to delete. </param>
/// <summary>
/// Deletes an existing <paramref name="emote"/> from this guild.
/// </summary>
/// <param name="emote">The guild emote to delete.</param>
Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null);
}
}

+ 23
- 8
src/Discord.Net.Core/Entities/Guilds/IVoiceRegion.cs View File

@@ -1,18 +1,33 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represents a region of which the user connects to when using voice.
/// </summary>
public interface IVoiceRegion
{
/// <summary> Gets the unique identifier for this voice region. </summary>
/// <summary>
/// Gets the unique identifier for this voice region.
/// </summary>
string Id { get; }
/// <summary> Gets the name of this voice region. </summary>
/// <summary>
/// Gets the name of this voice region.
/// </summary>
string Name { get; }
/// <summary> Returns true if this voice region is exclusive to VIP accounts. </summary>
/// <summary>
/// Returns <see langword="true"/> if this voice region is exclusive to VIP accounts.
/// </summary>
bool IsVip { get; }
/// <summary> Returns true if this voice region is the closest to your machine. </summary>
/// <summary>
/// Returns <see langword="true"/> if this voice region is the closest to your machine.
/// </summary>
bool IsOptimal { get; }
/// <summary> Gets an example hostname for this voice region. </summary>
/// <summary>
/// Gets an example hostname for this voice region.
/// </summary>
string SampleHostname { get; }
/// <summary> Gets an example port for this voice region. </summary>
/// <summary>
/// Gets an example port for this voice region.
/// </summary>
int SamplePort { get; }
}
}
}

+ 9
- 3
src/Discord.Net.Core/Entities/Guilds/MfaLevel.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> Specifies the guild's Multi-Factor Authentication (MFA) level requirement. </summary>
/// <summary>
/// Specifies the guild's Multi-Factor Authentication (MFA) level requirement.
/// </summary>
public enum MfaLevel
{
/// <summary> Users have no additional MFA restriction on this guild. </summary>
/// <summary>
/// Users have no additional MFA restriction on this guild.
/// </summary>
Disabled = 0,
/// <summary> Users must have MFA enabled on their account to perform administrative actions. </summary>
/// <summary>
/// Users must have MFA enabled on their account to perform administrative actions.
/// </summary>
Enabled = 1
}
}

+ 9
- 3
src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> Specifies the target of the permission. </summary>
/// <summary>
/// Specifies the target of the permission.
/// </summary>
public enum PermissionTarget
{
/// <summary> The target of the permission is a role. </summary>
/// <summary>
/// The target of the permission is a role.
/// </summary>
Role,
/// <summary> The target of the permission is a user. </summary>
/// <summary>
/// The target of the permission is a user.
/// </summary>
User
}
}

+ 18
- 6
src/Discord.Net.Core/Entities/Guilds/VerificationLevel.cs View File

@@ -1,17 +1,29 @@
namespace Discord
{
/// <summary> Specifies the verification level the guild uses. </summary>
/// <summary>
/// Specifies the verification level the guild uses.
/// </summary>
public enum VerificationLevel
{
/// <summary> Users have no additional restrictions on sending messages to this guild. </summary>
/// <summary>
/// Users have no additional restrictions on sending messages to this guild.
/// </summary>
None = 0,
/// <summary> Users must have a verified email on their account. </summary>
/// <summary>
/// Users must have a verified email on their account.
/// </summary>
Low = 1,
/// <summary> Users must fulfill the requirements of Low, and be registered on Discord for at least 5 minutes. </summary>
/// <summary>
/// Users must fulfill the requirements of Low and be registered on Discord for at least 5 minutes.
/// </summary>
Medium = 2,
/// <summary> Users must fulfill the requirements of Medium, and be a member of this guild for at least 10 minutes. </summary>
/// <summary>
/// Users must fulfill the requirements of Medium and be a member of this guild for at least 10 minutes.
/// </summary>
High = 3,
/// <summary> Users must fulfill the requirements of High, and must have a verified phone on their Discord account. </summary>
/// <summary>
/// Users must fulfill the requirements of High and must have a verified phone on their Discord account.
/// </summary>
Extreme = 4
}
}

+ 6
- 2
src/Discord.Net.Core/Entities/IDeletable.cs View File

@@ -2,10 +2,14 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary> Represents whether the object is deletable or not. </summary>
/// <summary>
/// Represents whether the object is deletable or not.
/// </summary>
public interface IDeletable
{
/// <summary> Deletes this object and all its children. </summary>
/// <summary>
/// Deletes this object and all its children.
/// </summary>
Task DeleteAsync(RequestOptions options = null);
}
}

+ 3
- 1
src/Discord.Net.Core/Entities/IEntity.cs View File

@@ -8,7 +8,9 @@ namespace Discord
///// <summary> Gets the IDiscordClient that created this object. </summary>
//IDiscordClient Discord { get; }

/// <summary> Gets the unique identifier for this object. </summary>
/// <summary>
/// Gets the unique identifier for this object.
/// </summary>
TId Id { get; }

}


+ 6
- 2
src/Discord.Net.Core/Entities/IMentionable.cs View File

@@ -1,9 +1,13 @@
namespace Discord
{
/// <summary> Represents whether the object is mentionable or not. </summary>
/// <summary>
/// Represents whether the object is mentionable or not.
/// </summary>
public interface IMentionable
{
/// <summary> Returns a special string used to mention this object. </summary>
/// <summary>
/// Returns a special string used to mention this object.
/// </summary>
string Mention { get; }
}
}

+ 1
- 0
src/Discord.Net.Core/Entities/ISnowflakeEntity.cs View File

@@ -5,6 +5,7 @@ namespace Discord
/// <summary> Represents a Discord snowflake entity. </summary>
public interface ISnowflakeEntity : IEntity<ulong>
{
/// <summary> Gets when the snowflake is created. </summary>
DateTimeOffset CreatedAt { get; }
}
}

+ 6
- 2
src/Discord.Net.Core/Entities/IUpdateable.cs View File

@@ -2,10 +2,14 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary> Represents whether the object is updatable or not. </summary>
/// <summary>
/// Represents whether the object is updatable or not.
/// </summary>
public interface IUpdateable
{
/// <summary> Updates this object's properties with its current state. </summary>
/// <summary>
/// Updates this object's properties with its current state.
/// </summary>
Task UpdateAsync(RequestOptions options = null);
}
}

+ 9
- 5
src/Discord.Net.Core/Entities/Image.cs View File

@@ -2,25 +2,29 @@
namespace Discord
{
/// <summary>
/// An image that will be uploaded to Discord.
/// An image that will be uploaded to Discord.
/// </summary>
public struct Image
{
public Stream Stream { get; }
/// <summary>
/// Create the image with a Stream.
/// Create the image with a <see cref="System.IO.Stream" /> .
/// </summary>
/// <param name="stream">This must be some type of stream with the contents of a file in it.</param>
/// <param name="stream">
/// The <see cref="System.IO.Stream" /> to create the image with. Note that this must be some type of stream
/// with the contents of a file in it.
/// </param>
public Image(Stream stream)
{
Stream = stream;
}
#if FILESYSTEM
/// <summary>
/// Create the image from a file path.
/// Create the image from a file path.
/// </summary>
/// <remarks>
/// This file path is NOT validated, and is passed directly into a <see cref="File.OpenRead(string)"/>
/// This file <paramref name="path" /> is NOT validated, and is passed directly into a
/// <see cref="File.OpenRead" />
/// </remarks>
/// <param name="path">The path to the file.</param>
public Image(string path)


+ 18
- 1
src/Discord.Net.Core/Entities/ImageFormat.cs View File

@@ -1,12 +1,29 @@
namespace Discord
{
/// <summary> Specifies the type of format the image should return in. </summary>
/// <summary>
/// Specifies the type of format the image should return in.
/// </summary>
public enum ImageFormat
{
/// <summary>
/// Use automatically detected format.
/// </summary>
Auto,
/// <summary>
/// Use Google's WebP image format.
/// </summary>
WebP,
/// <summary>
/// Use PNG.
/// </summary>
Png,
/// <summary>
/// Use JPEG.
/// </summary>
Jpeg,
/// <summary>
/// Use GIF.
/// </summary>
Gif,
}
}

+ 28
- 10
src/Discord.Net.Core/Entities/Invites/IInvite.cs View File

@@ -1,29 +1,47 @@
using System.Threading.Tasks;
using System.Threading.Tasks;

namespace Discord
{
public interface IInvite : IEntity<string>, IDeletable
{
/// <summary> Gets the unique identifier for this invite. </summary>
/// <summary>
/// Gets the unique identifier for this invite.
/// </summary>
string Code { get; }
/// <summary> Gets the url used to accept this invite, using Code. </summary>
/// <summary>
/// Gets the URL used to accept this invite, using Code.
/// </summary>
string Url { get; }

/// <summary> Gets the channel this invite is linked to. </summary>
/// <summary>
/// Gets the channel this invite is linked to.
/// </summary>
IChannel Channel { get; }
/// <summary> Gets the id of the channel this invite is linked to. </summary>
/// <summary>
/// Gets the ID of the channel this invite is linked to.
/// </summary>
ulong ChannelId { get; }
/// <summary> Gets the name of the channel this invite is linked to. </summary>
/// <summary>
/// Gets the name of the channel this invite is linked to.
/// </summary>
string ChannelName { get; }

/// <summary> Gets the guild this invite is linked to. </summary>
/// <summary>
/// Gets the guild this invite is linked to.
/// </summary>
IGuild Guild { get; }
/// <summary> Gets the id of the guild this invite is linked to. </summary>
/// <summary>
/// Gets the ID of the guild this invite is linked to.
/// </summary>
ulong GuildId { get; }
/// <summary> Gets the name of the guild this invite is linked to. </summary>
/// <summary>
/// Gets the name of the guild this invite is linked to.
/// </summary>
string GuildName { get; }

/// <summary> Accepts this invite and joins the target guild. This will fail on bot accounts. </summary>
/// <summary>
/// Accepts this invite and joins the target guild. This will fail on bot accounts.
/// </summary>
Task AcceptAsync(RequestOptions options = null);
}
}

+ 25
- 9
src/Discord.Net.Core/Entities/Invites/IInviteMetadata.cs View File

@@ -1,22 +1,38 @@
using System;
using System;

namespace Discord
{
/// <summary> Represents additional information regarding the invite object. </summary>
public interface IInviteMetadata : IInvite
{
/// <summary> Gets the user that created this invite. </summary>
/// <summary>
/// Gets the user that created this invite.
/// </summary>
IUser Inviter { get; }
/// <summary> Returns true if this invite was revoked. </summary>
/// <summary>
/// Returns <see langword="true"/> if this invite was revoked.
/// </summary>
bool IsRevoked { get; }
/// <summary> Returns true if users accepting this invite will be removed from the guild when they log off. </summary>
/// <summary>
/// Returns <see langword="true"/> if users accepting this invite will be removed from the guild when they
/// log off.
/// </summary>
bool IsTemporary { get; }
/// <summary> Gets the time (in seconds) until the invite expires, or null if it never expires. </summary>
/// <summary>
/// Gets the time (in seconds) until the invite expires, or <see langword="null"/> if it never expires.
/// </summary>
int? MaxAge { get; }
/// <summary> Gets the max amount of times this invite may be used, or null if there is no limit. </summary>
/// <summary>
/// Gets the max amount of times this invite may be used, or <see langword="null"/> if there is no limit.
/// </summary>
int? MaxUses { get; }
/// <summary> Gets the amount of times this invite has been used. </summary>
/// <summary>
/// Gets the amount of times this invite has been used.
/// </summary>
int Uses { get; }
/// <summary> Gets when this invite was created. </summary>
/// <summary>
/// Gets when this invite was created.
/// </summary>
DateTimeOffset CreatedAt { get; }
}
}
}

+ 2
- 1
src/Discord.Net.Core/Entities/Messages/ISystemMessage.cs View File

@@ -1,5 +1,6 @@
namespace Discord
namespace Discord
{
/// <summary> Represents a message sent by the system. </summary>
public interface ISystemMessage : IMessage
{
}


+ 1
- 1
src/Discord.Net.Core/Entities/Messages/IUserMessage.cs View File

@@ -23,7 +23,7 @@ namespace Discord
Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null);
/// <summary> Removes all reactions from this message. </summary>
Task RemoveAllReactionsAsync(RequestOptions options = null);
/// <summary> Gets all users that reacted to a message with a given emote </summary>
/// <summary> Gets all users that reacted to a message with a given emote. </summary>
Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emoji, int limit = 100, ulong? afterUserId = null, RequestOptions options = null);

/// <summary> Transforms this message's text into a human-readable form by resolving its tags. </summary>


+ 85
- 42
src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs View File

@@ -7,54 +7,97 @@ namespace Discord
public enum ChannelPermission : ulong
{
// General
/// <summary> Allows creation of instant invites. </summary>
CreateInstantInvite = 0x00_00_00_01,
/// <summary> Allows management and editing of channels. </summary>
ManageChannels = 0x00_00_00_10,
/// <summary>
/// Allows creation of instant invites.
/// </summary>
CreateInstantInvite = 0x00_00_00_01,
/// <summary>
/// Allows management and editing of channels.
/// </summary>
ManageChannels = 0x00_00_00_10,

// Text
/// <summary> Allows for the addition of reactions to messages. </summary>
AddReactions = 0x00_00_00_40,
/// <summary> Allows for reading of message. </summary>
/// <summary>
/// Allows for the addition of reactions to messages.
/// </summary>
AddReactions = 0x00_00_00_40,
/// <summary>
/// Allows for reading of message.
/// </summary>
[Obsolete("Use ViewChannel instead.")]
ReadMessages = ViewChannel,
/// <summary> Allows guild members to view a channel, which includes reading messages in text channels. </summary>
ViewChannel = 0x00_00_04_00,
/// <summary> Allows for sending messages in a channel. </summary>
SendMessages = 0x00_00_08_00,
/// <summary> Allows for sending of text-to-speech messages. </summary>
SendTTSMessages = 0x00_00_10_00,
/// <summary> Allows for deletion of other users messages. </summary>
ManageMessages = 0x00_00_20_00,
/// <summary> Allows links sent by users with this permission will be auto-embedded. </summary>
EmbedLinks = 0x00_00_40_00,
/// <summary> Allows for uploading images and files. </summary>
AttachFiles = 0x00_00_80_00,
/// <summary> Allows for reading of message history. </summary>
ReadMessageHistory = 0x00_01_00_00,
/// <summary> Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all online users in a channel. </summary>
MentionEveryone = 0x00_02_00_00,
/// <summary> Allows the usage of custom emojis from other servers. </summary>
UseExternalEmojis = 0x00_04_00_00,
ReadMessages = ViewChannel,
/// <summary>
/// Allows guild members to view a channel, which includes reading messages in text channels.
/// </summary>
ViewChannel = 0x00_00_04_00,
/// <summary>
/// Allows for sending messages in a channel.
/// </summary>
SendMessages = 0x00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.
/// </summary>
SendTTSMessages = 0x00_00_10_00,
/// <summary>
/// Allows for deletion of other users messages.
/// </summary>
ManageMessages = 0x00_00_20_00,
/// <summary>
/// Allows links sent by users with this permission will be auto-embedded.
/// </summary>
EmbedLinks = 0x00_00_40_00,
/// <summary>
/// Allows for uploading images and files.
/// </summary>
AttachFiles = 0x00_00_80_00,
/// <summary>
/// Allows for reading of message history.
/// </summary>
ReadMessageHistory = 0x00_01_00_00,
/// <summary>
/// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all
/// online users in a channel.
/// </summary>
MentionEveryone = 0x00_02_00_00,
/// <summary>
/// Allows the usage of custom emojis from other servers.
/// </summary>
UseExternalEmojis = 0x00_04_00_00,

// Voice
/// <summary> Allows for joining of a voice channel. </summary>
Connect = 0x00_10_00_00,
/// <summary> Allows for speaking in a voice channel. </summary>
Speak = 0x00_20_00_00,
/// <summary> Allows for muting members in a voice channel. </summary>
MuteMembers = 0x00_40_00_00,
/// <summary> Allows for deafening of members in a voice channel. </summary>
DeafenMembers = 0x00_80_00_00,
/// <summary> Allows for moving of members between voice channels. </summary>
MoveMembers = 0x01_00_00_00,
/// <summary> Allows for using voice-activity-detection in a voice channel. </summary>
UseVAD = 0x02_00_00_00,
/// <summary>
/// Allows for joining of a voice channel.
/// </summary>
Connect = 0x00_10_00_00,
/// <summary>
/// Allows for speaking in a voice channel.
/// </summary>
Speak = 0x00_20_00_00,
/// <summary>
/// Allows for muting members in a voice channel.
/// </summary>
MuteMembers = 0x00_40_00_00,
/// <summary>
/// Allows for deafening of members in a voice channel.
/// </summary>
DeafenMembers = 0x00_80_00_00,
/// <summary>
/// Allows for moving of members between voice channels.
/// </summary>
MoveMembers = 0x01_00_00_00,
/// <summary>
/// Allows for using voice-activity-detection in a voice channel.
/// </summary>
UseVAD = 0x02_00_00_00,

// More General
/// <summary> Allows management and editing of roles. </summary>
ManageRoles = 0x10_00_00_00,
/// <summary> Allows management and editing of webhooks. </summary>
ManageWebhooks = 0x20_00_00_00,
/// <summary>
/// Allows management and editing of roles.
/// </summary>
ManageRoles = 0x10_00_00_00,
/// <summary>
/// Allows management and editing of webhooks.
/// </summary>
ManageWebhooks = 0x20_00_00_00,
}
}

+ 106
- 20
src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs View File

@@ -3,43 +3,129 @@ using System;
namespace Discord
{
/// <summary> Defines the available permissions for a channel. </summary>
[FlagsAttribute]
[Flags]
public enum GuildPermission : ulong
{
// General
/// <summary>
/// Allows creation of instant invites.
/// </summary>
CreateInstantInvite = 0x00_00_00_01,
KickMembers = 0x00_00_00_02,
BanMembers = 0x00_00_00_04,
Administrator = 0x00_00_00_08,
ManageChannels = 0x00_00_00_10,
ManageGuild = 0x00_00_00_20,
/// <summary>
/// Allows kicking members.
/// </summary>
KickMembers = 0x00_00_00_02,
/// <summary>
/// Allows banning members.
/// </summary>
BanMembers = 0x00_00_00_04,
/// <summary>
/// Allows all permissions and bypasses channel permission overwrites.
/// </summary>
Administrator = 0x00_00_00_08,
/// <summary>
/// Allows management and editing of channels.
/// </summary>
ManageChannels = 0x00_00_00_10,
/// <summary>
/// Allows management and editing of the guild.
/// </summary>
ManageGuild = 0x00_00_00_20,

// Text
/// <summary>
/// Allows for the addition of reactions to messages.
/// </summary>
AddReactions = 0x00_00_00_40,
/// <summary>
/// Allows for viewing of audit logs.
/// </summary>
ViewAuditLog = 0x00_00_00_80,
ReadMessages = 0x00_00_04_00,
/// <summary>
/// Allows for reading of message.
/// </summary>
ReadMessages = 0x00_00_04_00,
/// <summary>
/// Allows for sending messages in a channel.
/// </summary>
SendMessages = 0x00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.
/// </summary>
SendTTSMessages = 0x00_00_10_00,
ManageMessages = 0x00_00_20_00,
EmbedLinks = 0x00_00_40_00,
AttachFiles = 0x00_00_80_00,
ReadMessageHistory = 0x00_01_00_00,
MentionEveryone = 0x00_02_00_00,
UseExternalEmojis = 0x00_04_00_00,
/// <summary>
/// Allows for deletion of other users messages.
/// </summary>
ManageMessages = 0x00_00_20_00,
/// <summary>
/// Allows links sent by users with this permission will be auto-embedded.
/// </summary>
EmbedLinks = 0x00_00_40_00,
/// <summary>
/// Allows for uploading images and files.
/// </summary>
AttachFiles = 0x00_00_80_00,
/// <summary>
/// Allows for reading of message history.
/// </summary>
ReadMessageHistory = 0x00_01_00_00,
/// <summary>
/// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all
/// online users in a channel.
/// </summary>
MentionEveryone = 0x00_02_00_00,
/// <summary>
/// Allows the usage of custom emojis from other servers.
/// </summary>
UseExternalEmojis = 0x00_04_00_00,


// Voice
Connect = 0x00_10_00_00,
Speak = 0x00_20_00_00,
MuteMembers = 0x00_40_00_00,
DeafenMembers = 0x00_80_00_00,
MoveMembers = 0x01_00_00_00,
UseVAD = 0x02_00_00_00,
/// <summary>
/// Allows for joining of a voice channel.
/// </summary>
Connect = 0x00_10_00_00,
/// <summary>
/// Allows for speaking in a voice channel.
/// </summary>
Speak = 0x00_20_00_00,
/// <summary>
/// Allows for muting members in a voice channel.
/// </summary>
MuteMembers = 0x00_40_00_00,
/// <summary>
/// Allows for deafening of members in a voice channel.
/// </summary>
DeafenMembers = 0x00_80_00_00,
/// <summary>
/// Allows for moving of members between voice channels.
/// </summary>
MoveMembers = 0x01_00_00_00,
/// <summary>
/// Allows for using voice-activity-detection in a voice channel.
/// </summary>
UseVAD = 0x02_00_00_00,

// General 2
ChangeNickname = 0x04_00_00_00,
/// <summary>
/// Allows for modification of own nickname.
/// </summary>
ChangeNickname = 0x04_00_00_00,
/// <summary>
/// Allows for modification of other users nicknames.
/// </summary>
ManageNicknames = 0x08_00_00_00,
/// <summary>
/// Allows management and editing of roles.
/// </summary>
ManageRoles = 0x10_00_00_00,
/// <summary>
/// Allows management and editing of webhooks.
/// </summary>
ManageWebhooks = 0x20_00_00_00,
/// <summary>
/// Allows management and editing of emojis.
/// </summary>
ManageEmojis = 0x40_00_00_00
}
}

+ 13
- 5
src/Discord.Net.Core/Entities/Permissions/Overwrite.cs View File

@@ -1,15 +1,23 @@
namespace Discord
namespace Discord
{
public struct Overwrite
{
/// <summary> Gets the unique identifier for the object this overwrite is targeting. </summary>
/// <summary>
/// Gets the unique identifier for the object this overwrite is targeting.
/// </summary>
public ulong TargetId { get; }
/// <summary> Gets the type of object this overwrite is targeting. </summary>
/// <summary>
/// Gets the type of object this overwrite is targeting.
/// </summary>
public PermissionTarget TargetType { get; }
/// <summary> Gets the permissions associated with this overwrite entry. </summary>
/// <summary>
/// Gets the permissions associated with this overwrite entry.
/// </summary>
public OverwritePermissions Permissions { get; }

/// <summary> Creates a new Overwrite with provided target information and modified permissions. </summary>
/// <summary>
/// Creates a new <see cref="Overwrite"/> with provided target information and modified permissions.
/// </summary>
public Overwrite(ulong targetId, PermissionTarget targetType, OverwritePermissions permissions)
{
TargetId = targetId;


+ 24
- 9
src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;

@@ -7,18 +7,28 @@ namespace Discord
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct OverwritePermissions
{
/// <summary> Gets a blank OverwritePermissions that inherits all permissions. </summary>
/// <summary>
/// Gets a blank <see cref="OverwritePermissions" /> that inherits all permissions.
/// </summary>
public static OverwritePermissions InheritAll { get; } = new OverwritePermissions();
/// <summary> Gets a OverwritePermissions that grants all permissions for a given channelType. </summary>
/// <summary>
/// Gets a <see cref="OverwritePermissions" /> that grants all permissions for the given channel.
/// </summary>
public static OverwritePermissions AllowAll(IChannel channel)
=> new OverwritePermissions(ChannelPermissions.All(channel).RawValue, 0);
/// <summary> Gets a OverwritePermissions that denies all permissions for a given channelType. </summary>
/// <summary>
/// Gets a <see cref="OverwritePermissions" /> that denies all permissions for the given channel.
/// </summary>
public static OverwritePermissions DenyAll(IChannel channel)
=> new OverwritePermissions(0, ChannelPermissions.All(channel).RawValue);

/// <summary> Gets a packed value representing all the allowed permissions in this OverwritePermissions. </summary>
/// <summary>
/// Gets a packed value representing all the allowed permissions in this <see cref="OverwritePermissions" />.
/// </summary>
public ulong AllowValue { get; }
/// <summary> Gets a packed value representing all the denied permissions in this OverwritePermissions. </summary>
/// <summary>
/// Gets a packed value representing all the denied permissions in this <see cref="OverwritePermissions" />.
/// </summary>
public ulong DenyValue { get; }

/// <summary> If Allowed, a user may create invites. </summary>
@@ -62,7 +72,7 @@ namespace Discord
/// <summary> If Allowed, a user may use voice-activity-detection rather than push-to-talk. </summary>
public PermValue UseVAD => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseVAD);

/// <summary> If Allowed, a user may adjust role permissions. This also implictly grants all other permissions. </summary>
/// <summary> If Allowed, a user may adjust role permissions. This also implicitly grants all other permissions. </summary>
public PermValue ManageRoles => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageRoles);
/// <summary> If True, a user may edit the webhooks for this channel. </summary>
public PermValue ManageWebhooks => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageWebhooks);
@@ -107,7 +117,9 @@ namespace Discord
DenyValue = denyValue;
}

/// <summary> Creates a new ChannelPermissions with the provided permissions. </summary>
/// <summary>
/// Creates a new <see cref="ChannelPermissions" /> with the provided permissions.
/// </summary>
public OverwritePermissions(PermValue createInstantInvite = PermValue.Inherit, PermValue manageChannel = PermValue.Inherit,
PermValue addReactions = PermValue.Inherit,
PermValue readMessages = PermValue.Inherit, PermValue sendMessages = PermValue.Inherit, PermValue sendTTSMessages = PermValue.Inherit, PermValue manageMessages = PermValue.Inherit,
@@ -118,7 +130,10 @@ namespace Discord
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers,
moveMembers, useVoiceActivation, manageRoles, manageWebhooks) { }

/// <summary> Creates a new OverwritePermissions from this one, changing the provided non-null permissions. </summary>
/// <summary>
/// Creates a new <see cref="OverwritePermissions" /> from this one, changing the provided non-null
/// permissions.
/// </summary>
public OverwritePermissions Modify(PermValue? createInstantInvite = null, PermValue? manageChannel = null,
PermValue? addReactions = null,
PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, PermValue? manageMessages = null,


+ 3
- 1
src/Discord.Net.Core/Entities/Roles/Color.cs View File

@@ -3,7 +3,9 @@ using System.Diagnostics;

namespace Discord
{
/// <summary> A color object that Discord uses. </summary>
/// <summary>
/// A color object that Discord uses.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct Color
{


+ 31
- 10
src/Discord.Net.Core/Entities/Roles/IRole.cs View File

@@ -1,29 +1,50 @@
using System;
using System;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a generic role object.
/// </summary>
public interface IRole : ISnowflakeEntity, IDeletable, IMentionable, IComparable<IRole>
{
/// <summary> Gets the guild owning this role.</summary>
/// <summary>
/// Gets the guild owning this role.
/// </summary>
IGuild Guild { get; }

/// <summary> Gets the color given to users of this role. </summary>
/// <summary>
/// Gets the color given to users of this role.
/// </summary>
Color Color { get; }
/// <summary> Returns true if users of this role are separated in the user list. </summary>
/// <summary>
/// Returns <see langword="true"/> if users of this role are separated in the user list.
/// </summary>
bool IsHoisted { get; }
/// <summary> Returns true if this role is automatically managed by Discord. </summary>
/// <summary>
/// Returns <see langword="true"/> if this role is automatically managed by Discord.
/// </summary>
bool IsManaged { get; }
/// <summary> Returns true if this role may be mentioned in messages. </summary>
/// <summary>
/// Returns <see langword="true"/> if this role may be mentioned in messages.
/// </summary>
bool IsMentionable { get; }
/// <summary> Gets the name of this role. </summary>
/// <summary>
/// Gets the name of this role.
/// </summary>
string Name { get; }
/// <summary> Gets the permissions granted to members of this role. </summary>
/// <summary>
/// Gets the permissions granted to members of this role.
/// </summary>
GuildPermissions Permissions { get; }
/// <summary> Gets this role's position relative to other roles in the same guild. </summary>
/// <summary>
/// Gets this role's position relative to other roles in the same guild.
/// </summary>
int Position { get; }

///// <summary> Modifies this role. </summary>
/// <summary>
/// Modifies this role.
/// </summary>
Task ModifyAsync(Action<RoleProperties> func, RequestOptions options = null);
}
}

+ 9
- 3
src/Discord.Net.Core/Entities/Roles/ReorderRoleProperties.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> Properties that are used to reorder an <see cref="IRole"/>. </summary>
/// <summary>
/// Properties that are used to reorder an <see cref="IRole" /> .
/// </summary>
public class ReorderRoleProperties
{
/// <summary> Gets the ID of the role to be edited. </summary>
/// <summary>
/// Gets the ID of the role to be edited.
/// </summary>
public ulong Id { get; }
/// <summary> Gets the new zero-based position of the role. </summary>
/// <summary>
/// Gets the new zero-based position of the role.
/// </summary>
public int Position { get; }

public ReorderRoleProperties(ulong id, int pos)


+ 19
- 19
src/Discord.Net.Core/Entities/Roles/RoleProperties.cs View File

@@ -1,57 +1,57 @@
namespace Discord
{
/// <summary>
/// Properties that are used to modify an <see cref="IRole"/> with the specified changes.
/// Properties that are used to modify an <see cref="IRole" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await role.ModifyAsync(x =>
/// {
/// x.Color = new Color(180, 15, 40);
/// x.Hoist = true;
/// });
/// <code lang="c#">
/// await role.ModifyAsync(x =&gt;
/// {
/// x.Color = new Color(180, 15, 40);
/// x.Hoist = true;
/// });
/// </code>
/// </example>
/// <seealso cref="IRole"/>
/// <seealso cref="T:Discord.IRole" />
public class RoleProperties
{
/// <summary>
/// Gets or sets the name of the role.
/// Gets or sets the name of the role.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// If this role is the EveryoneRole, this value may not be set.
/// </remarks>
public Optional<string> Name { get; set; }
/// <summary>
/// Gets or sets the role's <see cref="GuildPermission"/>.
/// Gets or sets the role's <see cref="GuildPermission" /> .
/// </summary>
public Optional<GuildPermissions> Permissions { get; set; }
/// <summary>
/// Gets or sets the position of the role. This is 0-based!
/// Gets or sets the position of the role. This is 0-based!
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// If this role is the EveryoneRole, this value may not be set.
/// </remarks>
public Optional<int> Position { get; set; }
/// <summary>
/// Gets or sets the color of the Role.
/// Gets or sets the color of the role.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// If this role is the EveryoneRole, this value may not be set.
/// </remarks>
public Optional<Color> Color { get; set; }
/// <summary>
/// Gets or sets whether or not this role should be displayed independently in the userlist.
/// Gets or sets whether or not this role should be displayed independently in the user list.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// If this role is the EveryoneRole, this value may not be set.
/// </remarks>
public Optional<bool> Hoist { get; set; }
/// <summary>
/// Gets or sets whether or not this role can be mentioned.
/// Gets or sets whether or not this role can be mentioned.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// If this role is the EveryoneRole, this value may not be set.
/// </remarks>
public Optional<bool> Mentionable { get; set; }
}


+ 33
- 20
src/Discord.Net.Core/Entities/Users/GuildUserProperties.cs View File

@@ -3,68 +3,81 @@ using System.Collections.Generic;
namespace Discord
{
/// <summary>
/// Properties that are used to modify an <see cref="IGuildUser"/> with the following parameters.
/// Properties that are used to modify an <see cref="IGuildUser" /> with the following parameters.
/// </summary>
/// <example>
/// <code language="c#">
/// await (Context.User as IGuildUser)?.ModifyAsync(x =>
/// <code lang="c#">
/// await (Context.User as IGuildUser)?.ModifyAsync(x =&gt;
/// {
/// x.Nickname = $"festive {Context.User.Username}";
/// });
/// </code>
/// </example>
/// <seealso cref="IGuildUser"/>
/// <seealso cref="T:Discord.IGuildUser" />
public class GuildUserProperties
{
/// <summary>
/// Should the user be guild-muted in a voice channel?
/// Sets whether the user should be muted in a voice channel.
/// </summary>
/// <remarks>
/// If this value is set to true, no user will be able to hear this user speak in the guild.
/// If this value is set to <see langword="true"/>, no user will be able to hear this user speak in the guild.
/// </remarks>
public Optional<bool> Mute { get; set; }
/// <summary>
/// Should the user be guild-deafened in a voice channel?
/// Sets whether the user should be deafened in a voice channel.
/// </summary>
/// <remarks>
/// If this value is set to true, this user will not be able to hear anyone speak in the guild.
/// If this value is set to <see langword="true"/>, this user will not be able to hear anyone speak in the guild.
/// </remarks>
public Optional<bool> Deaf { get; set; }
/// <summary>
/// Should the user have a nickname set?
/// Sets the user's nickname.
/// </summary>
/// <remarks>
/// To clear the user's nickname, this value can be set to <see langword="null" /> or <see cref="string.Empty" />.
/// To clear the user's nickname, this value can be set to <see langword="null" /> or
/// <see cref="string.Empty" /> .
/// </remarks>
public Optional<string> Nickname { get; set; }
/// <summary>
/// What roles should the user have?
/// Sets the roles the user should have.
/// </summary>
/// <remarks>
/// To add a role to a user: <see cref="IGuildUser.AddRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// To remove a role from a user: <see cref="IGuildUser.RemoveRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// <para>
/// To add a role to a user:
/// <see cref="IGuildUser.AddRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// <para>
/// To remove a role from a user:
/// <see cref="IGuildUser.RemoveRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// </remarks>
public Optional<IEnumerable<IRole>> Roles { get; set; }
/// <summary>
/// What roles should the user have?
/// Sets the roles the user should have.
/// </summary>
/// <remarks>
/// To add a role to a user: <see cref="IGuildUser.AddRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// To remove a role from a user: <see cref="IGuildUser.RemoveRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// <para>
/// To add a role to a user:
/// <see cref="IGuildUser.AddRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// <para>
/// To remove a role from a user:
/// <see cref="IGuildUser.RemoveRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// </remarks>
public Optional<IEnumerable<ulong>> RoleIds { get; set; }
/// <summary>
/// Moves a user to a voice channel.
/// Moves a user to a voice channel.
/// </summary>
/// <remarks>
/// This user MUST already be in a Voice Channel for this to work.
/// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work.
/// </remarks>
public Optional<IVoiceChannel> Channel { get; set; }
/// <summary>
/// Moves a user to a voice channel.
/// Moves a user to a voice channel.
/// </summary>
/// <remarks>
/// This user MUST already be in a Voice Channel for this to work.
/// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work.
/// </remarks>
public Optional<ulong> ChannelId { get; set; }
}


+ 3
- 1
src/Discord.Net.Core/Entities/Users/IGroupUser.cs View File

@@ -1,6 +1,8 @@
namespace Discord
{
/// <summary> Represents a Discord user that is in a group. </summary>
/// <summary>
/// Represents a Discord user that is in a group.
/// </summary>
public interface IGroupUser : IUser, IVoiceState
{
///// <summary> Kicks this user from this group. </summary>


+ 49
- 20
src/Discord.Net.Core/Entities/Users/IGuildUser.cs View File

@@ -4,44 +4,73 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary> Represents a Discord user that is in a guild. </summary>
/// <summary>
/// Represents a Discord user that is in a guild.
/// </summary>
public interface IGuildUser : IUser, IVoiceState
{
/// <summary> Gets when this user joined this guild. </summary>
/// <summary>
/// Gets when this user joined this guild.
/// </summary>
DateTimeOffset? JoinedAt { get; }
/// <summary> Gets the nickname for this user. </summary>
/// <summary>
/// Gets the nickname for this user.
/// </summary>
string Nickname { get; }
/// <summary> Gets the guild-level permissions for this user. </summary>
/// <summary>
/// Gets the guild-level permissions for this user.
/// </summary>
GuildPermissions GuildPermissions { get; }

/// <summary> Gets the guild for this user. </summary>
/// <summary>
/// Gets the guild for this user.
/// </summary>
IGuild Guild { get; }
/// <summary> Gets the id of the guild for this user. </summary>
/// <summary>
/// Gets the ID of the guild for this user.
/// </summary>
ulong GuildId { get; }
/// <summary> Returns a collection of the ids of the roles this user is a member of in this guild, including the guild's @everyone role. </summary>
/// <summary>
/// Returns a collection of the ids of the roles this user is a member of in this guild, including the
/// guild's @everyone role.
/// </summary>
IReadOnlyCollection<ulong> RoleIds { get; }

/// <summary> Gets the level permissions granted to this user to a given channel. </summary>
/// <param name="channel"> The channel to get the permission from. </param>
/// <summary>
/// Gets the level permissions granted to this user to a given channel.
/// </summary>
/// <param name="channel">The channel to get the permission from.</param>
ChannelPermissions GetPermissions(IGuildChannel channel);

/// <summary> Kicks this user from this guild. </summary>
/// <param name="reason"> The reason for the kick which will be recorded in the audit log. </param>
/// <summary>
/// Kicks this user from this guild.
/// </summary>
/// <param name="reason">The reason for the kick which will be recorded in the audit log.</param>
Task KickAsync(string reason = null, RequestOptions options = null);
/// <summary> Modifies this user's properties in this guild. </summary>
/// <summary>
/// Modifies this user's properties in this guild.
/// </summary>
Task ModifyAsync(Action<GuildUserProperties> func, RequestOptions options = null);

/// <summary> Adds a role to this user in this guild. </summary>
/// <param name="role"> The role to be added to the user. </param>
/// <summary>
/// Adds a <paramref name="role"/> to this user in this guild.
/// </summary>
/// <param name="role">The role to be added to the user.</param>
Task AddRoleAsync(IRole role, RequestOptions options = null);
/// <summary> Adds roles to this user in this guild. </summary>
/// <param name="roles"> The roles to be added to the user. </param>
/// <summary>
/// Adds <paramref name="roles"/> to this user in this guild.
/// </summary>
/// <param name="roles">The roles to be added to the user.</param>
Task AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null);
/// <summary> Removes a role from this user in this guild. </summary>
/// <param name="role"> The role to be removed from the user. </param>
/// <summary>
/// Removes a <paramref name="role"/> from this user in this guild.
/// </summary>
/// <param name="role">The role to be removed from the user.</param>
Task RemoveRoleAsync(IRole role, RequestOptions options = null);
/// <summary> Removes roles from this user in this guild. </summary>
/// <param name="roles"> The roles to be removed from the user. </param>
/// <summary>
/// Removes <paramref name="roles"/> from this user in this guild.
/// </summary>
/// <param name="roles">The roles to be removed from the user.</param>
Task RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null);
}
}

+ 9
- 3
src/Discord.Net.Core/Entities/Users/IPresence.cs View File

@@ -1,11 +1,17 @@
namespace Discord
{
/// <summary> Represents a Discord user's presence status. </summary>
/// <summary>
/// Represents a Discord user's presence status.
/// </summary>
public interface IPresence
{
/// <summary> Gets the activity this user is currently doing. </summary>
/// <summary>
/// Gets the activity this user is currently doing.
/// </summary>
IActivity Activity { get; }
/// <summary> Gets the current status of this user. </summary>
/// <summary>
/// Gets the current status of this user.
/// </summary>
UserStatus Status { get; }
}
}

+ 15
- 4
src/Discord.Net.Core/Entities/Users/ISelfUser.cs View File

@@ -3,16 +3,27 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary> Represents a logged-in Discord user. </summary>
/// <summary>
/// Represents the logged-in Discord user.
/// </summary>
public interface ISelfUser : IUser
{
/// <summary> Gets the email associated with this user. </summary>
/// <summary>
/// Gets the email associated with this user.
/// </summary>
string Email { get; }
/// <summary> Returns true if this user's email has been verified. </summary>
/// <summary>
/// Returns <see langword="true"/> if this user's email has been verified.
/// </summary>
bool IsVerified { get; }
/// <summary> Returns true if this user has enabled MFA on their account. </summary>
/// <summary>
/// Returns <see langword="true"/> if this user has enabled MFA on their account.
/// </summary>
bool IsMfaEnabled { get; }

/// <summary>
/// Modifies the user's properties.
/// </summary>
Task ModifyAsync(Action<SelfUserProperties> func, RequestOptions options = null);
}
}

+ 31
- 10
src/Discord.Net.Core/Entities/Users/IUser.cs View File

@@ -2,27 +2,48 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary> Represents a Discord user. </summary>
/// <summary>
/// Represents a Discord user.
/// </summary>
public interface IUser : ISnowflakeEntity, IMentionable, IPresence
{
/// <summary> Gets the id of this user's avatar. </summary>
/// <summary>
/// Gets the ID of this user's avatar.
/// </summary>
string AvatarId { get; }
/// <summary> Gets the url to this user's avatar. </summary>
/// <summary>
/// Gets the URL to this user's avatar.
/// </summary>
string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128);
/// <summary> Gets the url to this user's default avatar. </summary>
/// <summary>
/// Gets the URL to this user's default avatar.
/// </summary>
string GetDefaultAvatarUrl();
/// <summary> Gets the per-username unique id for this user. </summary>
/// <summary>
/// Gets the per-username unique ID for this user.
/// </summary>
string Discriminator { get; }
/// <summary> Gets the per-username unique id for this user. </summary>
/// <summary>
/// Gets the per-username unique ID for this user.
/// </summary>
ushort DiscriminatorValue { get; }
/// <summary> Returns true if this user is a bot user. </summary>
/// <summary>
/// Returns <see langword="true"/> if this user is a bot user.
/// </summary>
bool IsBot { get; }
/// <summary> Returns true if this user is a webhook user. </summary>
/// <summary>
/// Returns <see langword="true"/> if this user is a webhook user.
/// </summary>
bool IsWebhook { get; }
/// <summary> Gets the username for this user. </summary>
/// <summary>
/// Gets the username for this user.
/// </summary>
string Username { get; }

/// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary>
/// <summary>
/// Returns a private message channel to this user, creating one if it does not already
/// exist.
/// </summary>
Task<IDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null);
}
}

+ 24
- 7
src/Discord.Net.Core/Entities/Users/IVoiceState.cs View File

@@ -1,20 +1,37 @@
namespace Discord
{
/// <summary>
/// Represents a user's voice connection status.
/// </summary>
public interface IVoiceState
{
/// <summary> Returns <see langword="true"/> if the guild has deafened this user. </summary>
/// <summary>
/// Returns <see langword="true" /> if the guild has deafened this user.
/// </summary>
bool IsDeafened { get; }
/// <summary> Returns <see langword="true"/> if the guild has muted this user. </summary>
/// <summary>
/// Returns <see langword="true" /> if the guild has muted this user.
/// </summary>
bool IsMuted { get; }
/// <summary> Returns <see langword="true"/> if this user has marked themselves as deafened. </summary>
/// <summary>
/// Returns <see langword="true" /> if this user has marked themselves as deafened.
/// </summary>
bool IsSelfDeafened { get; }
/// <summary> Returns <see langword="true"/> if this user has marked themselves as muted. </summary>
/// <summary>
/// Returns <see langword="true" /> if this user has marked themselves as muted.
/// </summary>
bool IsSelfMuted { get; }
/// <summary> Returns <see langword="true"/> if the guild is temporarily blocking audio to/from this user. </summary>
/// <summary>
/// Returns <see langword="true" /> if the guild is temporarily blocking audio to/from this user.
/// </summary>
bool IsSuppressed { get; }
/// <summary> Gets the voice channel this user is currently in, if any. </summary>
/// <summary>
/// Gets the voice channel this user is currently in, if any.
/// </summary>
IVoiceChannel VoiceChannel { get; }
/// <summary> Gets the unique identifier for this user's voice session. </summary>
/// <summary>
/// Gets the unique identifier for this user's voice session.
/// </summary>
string VoiceSessionId { get; }
}
}

+ 1
- 0
src/Discord.Net.Core/Entities/Users/IWebhookUser.cs View File

@@ -3,6 +3,7 @@ namespace Discord
/// <summary> Represents a Webhook Discord user. </summary>
public interface IWebhookUser : IGuildUser
{
/// <summary> Gets the ID of a webhook. </summary>
ulong WebhookId { get; }
}
}

+ 10
- 10
src/Discord.Net.Core/Entities/Users/SelfUserProperties.cs View File

@@ -1,25 +1,25 @@
namespace Discord
{
/// <summary>
/// Properties that are used to modify the <see cref="ISelfUser"/> with the specified changes.
/// Properties that are used to modify the <see cref="ISelfUser" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await Context.Client.CurrentUser.ModifyAsync(x =>
/// {
/// x.Avatar = new Image(File.OpenRead("avatar.jpg"));
/// });
/// </code>
/// <code lang="c#">
/// await Context.Client.CurrentUser.ModifyAsync(x =&gt;
/// {
/// x.Avatar = new Image(File.OpenRead("avatar.jpg"));
/// });
/// </code>
/// </example>
/// <seealso cref="ISelfUser"/>
/// <seealso cref="T:Discord.ISelfUser" />
public class SelfUserProperties
{
/// <summary>
/// Your username
/// Sets the username.
/// </summary>
public Optional<string> Username { get; set; }
/// <summary>
/// Your avatar
/// Sets the avatar.
/// </summary>
public Optional<Image?> Avatar { get; set; }
}


+ 21
- 7
src/Discord.Net.Core/Entities/Users/UserStatus.cs View File

@@ -1,19 +1,33 @@
namespace Discord
{
/// <summary> Defines the available Discord user status. </summary>
/// <summary>
/// Defines the available Discord user status.
/// </summary>
public enum UserStatus
{
/// <summary> The user is offline. </summary>
/// <summary>
/// The user is offline.
/// </summary>
Offline,
/// <summary> The user is online. </summary>
/// <summary>
/// The user is online.
/// </summary>
Online,
/// <summary> The user is idle. </summary>
/// <summary>
/// The user is idle.
/// </summary>
Idle,
/// <summary> The user is AFK. </summary>
/// <summary>
/// The user is AFK.
/// </summary>
AFK,
/// <summary> The user is busy. </summary>
/// <summary>
/// The user is busy.
/// </summary>
DoNotDisturb,
/// <summary> The user is invisible. </summary>
/// <summary>
/// The user is invisible.
/// </summary>
Invisible,
}
}

+ 33
- 10
src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs View File

@@ -3,32 +3,55 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a webhook object on Discord.
/// </summary>
public interface IWebhook : IDeletable, ISnowflakeEntity
{
/// <summary> Gets the token of this webhook. </summary>
/// <summary>
/// Gets the token of this webhook.
/// </summary>
string Token { get; }

/// <summary> Gets the default name of this webhook. </summary>
/// <summary>
/// Gets the default name of this webhook.
/// </summary>
string Name { get; }
/// <summary> Gets the id of this webhook's default avatar. </summary>
/// <summary>
/// Gets the ID of this webhook's default avatar.
/// </summary>
string AvatarId { get; }
/// <summary> Gets the url to this webhook's default avatar. </summary>
/// <summary>
/// Gets the URL to this webhook's default avatar.
/// </summary>
string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128);

/// <summary> Gets the channel for this webhook. </summary>
/// <summary>
/// Gets the channel for this webhook.
/// </summary>
ITextChannel Channel { get; }
/// <summary> Gets the id of the channel for this webhook. </summary>
/// <summary>
/// Gets the ID of the channel for this webhook.
/// </summary>
ulong ChannelId { get; }

/// <summary> Gets the guild owning this webhook. </summary>
/// <summary>
/// Gets the guild owning this webhook.
/// </summary>
IGuild Guild { get; }
/// <summary> Gets the id of the guild owning this webhook. </summary>
/// <summary>
/// Gets the ID of the guild owning this webhook.
/// </summary>
ulong? GuildId { get; }

/// <summary> Gets the user that created this webhook. </summary>
/// <summary>
/// Gets the user that created this webhook.
/// </summary>
IUser Creator { get; }

/// <summary> Modifies this webhook. </summary>
/// <summary>
/// Modifies this webhook.
/// </summary>
Task ModifyAsync(Action<WebhookProperties> func, RequestOptions options = null);
}
}

+ 10
- 10
src/Discord.Net.Core/Entities/Webhooks/WebhookProperties.cs View File

@@ -1,40 +1,40 @@
namespace Discord
{
/// <summary>
/// Properties used to modify an <see cref="IWebhook"/> with the specified changes.
/// Properties used to modify an <see cref="IWebhook" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await webhook.ModifyAsync(x =>
/// <code lang="c#">
/// await webhook.ModifyAsync(x =&gt;
/// {
/// x.Name = "Bob";
/// x.Avatar = new Image("avatar.jpg");
/// });
/// </code>
/// </example>
/// <seealso cref="IWebhook"/>
/// <seealso cref="T:Discord.IWebhook" />
public class WebhookProperties
{
/// <summary>
/// Gets or sets the default name of the webhook.
/// Gets or sets the default name of the webhook.
/// </summary>
public Optional<string> Name { get; set; }
/// <summary>
/// Gets or sets the default avatar of the webhook.
/// Gets or sets the default avatar of the webhook.
/// </summary>
public Optional<Image?> Image { get; set; }
/// <summary>
/// Gets or sets the channel for this webhook.
/// Gets or sets the channel for this webhook.
/// </summary>
/// <remarks>
/// This field is not used when authenticated with <see cref="TokenType.Webhook"/>.
/// This field is not used when authenticated with <see cref="Discord.TokenType.Webhook" /> .
/// </remarks>
public Optional<ITextChannel> Channel { get; set; }
/// <summary>
/// Gets or sets the channel ID for this webhook.
/// Gets or sets the channel ID for this webhook.
/// </summary>
/// <remarks>
/// This field is not used when authenticated with <see cref="TokenType.Webhook"/>.
/// This field is not used when authenticated with <see cref="Discord.TokenType.Webhook" /> .
/// </remarks>
public Optional<ulong> ChannelId { get; set; }
}


+ 18
- 0
src/Discord.Net.Core/Net/HttpException.cs View File

@@ -3,13 +3,31 @@ using System.Net;

namespace Discord.Net
{
/// <summary>
/// Describes an exception that occurred during the processing of Discord HTTP requests.
/// </summary>
public class HttpException : Exception
{
/// <summary>
/// Gets the HTTP status code returned by Discord.
/// </summary>
public HttpStatusCode HttpCode { get; }
/// <summary>
/// Gets the JSON error code returned by Discord, or <see langword="null"/> if none.
/// </summary>
public int? DiscordCode { get; }
/// <summary>
/// Gets the reason of the exception.
/// </summary>
public string Reason { get; }
/// <summary>
/// Gets the request object used to send the request.
/// </summary>
public IRequest Request { get; }

/// <summary>
/// Initializes a new instance of the <see cref="HttpException" /> class.
/// </summary>
public HttpException(HttpStatusCode httpCode, IRequest request, int? discordCode = null, string reason = null)
: base(CreateMessage(httpCode, discordCode, reason))
{


+ 10
- 0
src/Discord.Net.Core/Net/RateLimitedException.cs View File

@@ -2,10 +2,20 @@ using System;

namespace Discord.Net
{
/// <summary>
/// An exception that indicates the user is being rate limited by Discord.
/// </summary>
public class RateLimitedException : TimeoutException
{
/// <summary>
/// Gets the request object used to send the request.
/// </summary>
public IRequest Request { get; }

/// <summary>
/// Initializes a new instance of the <see cref="RateLimitedException" /> class using the
/// <paramref name="request"/> sent.
/// </summary>
public RateLimitedException(IRequest request)
: base("You are being rate limited.")
{


+ 14
- 1
src/Discord.Net.Core/Net/WebSocketClosedException.cs View File

@@ -1,11 +1,24 @@
using System;
using System;
namespace Discord.Net
{
/// <summary>
/// Describes an exception that causes the WebSocket to close during a session.
/// </summary>
public class WebSocketClosedException : Exception
{
/// <summary>
/// Gets the close code sent by Discord.
/// </summary>
public int CloseCode { get; }
/// <summary>
/// Gets the reason of the interruption.
/// </summary>
public string Reason { get; }

/// <summary>
/// Initializes a new instance of the <see cref="WebSocketClosedException" /> using the Discord close code
/// and the optional reason.
/// </summary>
public WebSocketClosedException(int closeCode, string reason = null)
: base($"The server sent close {closeCode}{(reason != null ? $": \"{reason}\"" : "")}")
{


+ 10
- 18
src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs View File

@@ -55,36 +55,28 @@ namespace Discord.Rest
/// <inheritdoc />
ChannelPermissions IGuildUser.GetPermissions(IGuildChannel channel) => Permissions.ToChannelPerms(channel, GuildPermissions.Webhook.RawValue);
/// <inheritdoc />
Task IGuildUser.KickAsync(string reason, RequestOptions options)
{
Task IGuildUser.KickAsync(string reason, RequestOptions options) =>
throw new NotSupportedException("Webhook users cannot be kicked.");
}
/// <inheritdoc />
Task IGuildUser.ModifyAsync(Action<GuildUserProperties> func, RequestOptions options)
{
Task IGuildUser.ModifyAsync(Action<GuildUserProperties> func, RequestOptions options) =>
throw new NotSupportedException("Webhook users cannot be modified.");
}

/// <inheritdoc />
Task IGuildUser.AddRoleAsync(IRole role, RequestOptions options)
{
Task IGuildUser.AddRoleAsync(IRole role, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}
/// <inheritdoc />
Task IGuildUser.AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options)
{
Task IGuildUser.AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}
/// <inheritdoc />
Task IGuildUser.RemoveRoleAsync(IRole role, RequestOptions options)
{
Task IGuildUser.RemoveRoleAsync(IRole role, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}
/// <inheritdoc />
Task IGuildUser.RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options)
{
Task IGuildUser.RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}

//IVoiceState
/// <inheritdoc />


+ 39
- 19
src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs View File

@@ -10,18 +10,26 @@ namespace Discord.WebSocket
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class SocketWebhookUser : SocketUser, IWebhookUser
{
/// <summary> Gets the guild of this webhook. </summary>
public SocketGuild Guild { get; }
/// <inheritdoc />
public ulong WebhookId { get; }

/// <inheritdoc />
public override string Username { get; internal set; }
/// <inheritdoc />
public override ushort DiscriminatorValue { get; internal set; }
/// <inheritdoc />
public override string AvatarId { get; internal set; }
/// <inheritdoc />
public override bool IsBot { get; internal set; }

/// <inheritdoc />
public override bool IsWebhook => true;

internal override SocketPresence Presence { get { return new SocketPresence(UserStatus.Offline, null); } set { } }
internal override SocketGlobalUser GlobalUser { get { throw new NotSupportedException(); } }
internal override SocketGlobalUser GlobalUser =>
throw new NotSupportedException();

internal SocketWebhookUser(SocketGuild guild, ulong id, ulong webhookId)
: base(guild.Discord, id)
@@ -39,47 +47,59 @@ namespace Discord.WebSocket


//IGuildUser
/// <inheritdoc />
IGuild IGuildUser.Guild => Guild;
/// <inheritdoc />
ulong IGuildUser.GuildId => Guild.Id;
/// <inheritdoc />
IReadOnlyCollection<ulong> IGuildUser.RoleIds => ImmutableArray.Create<ulong>();
/// <inheritdoc />
DateTimeOffset? IGuildUser.JoinedAt => null;
/// <inheritdoc />
string IGuildUser.Nickname => null;
/// <inheritdoc />
GuildPermissions IGuildUser.GuildPermissions => GuildPermissions.Webhook;

/// <inheritdoc />
ChannelPermissions IGuildUser.GetPermissions(IGuildChannel channel) => Permissions.ToChannelPerms(channel, GuildPermissions.Webhook.RawValue);
Task IGuildUser.KickAsync(string reason, RequestOptions options)
{
/// <inheritdoc />
Task IGuildUser.KickAsync(string reason, RequestOptions options) =>
throw new NotSupportedException("Webhook users cannot be kicked.");
}
Task IGuildUser.ModifyAsync(Action<GuildUserProperties> func, RequestOptions options)
{
/// <inheritdoc />
Task IGuildUser.ModifyAsync(Action<GuildUserProperties> func, RequestOptions options) =>
throw new NotSupportedException("Webhook users cannot be modified.");
}

Task IGuildUser.AddRoleAsync(IRole role, RequestOptions options)
{
/// <inheritdoc />
Task IGuildUser.AddRoleAsync(IRole role, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}
Task IGuildUser.AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options)
{
/// <inheritdoc />
Task IGuildUser.AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}
Task IGuildUser.RemoveRoleAsync(IRole role, RequestOptions options)
{
/// <inheritdoc />
Task IGuildUser.RemoveRoleAsync(IRole role, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}
Task IGuildUser.RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options)
{
/// <inheritdoc />
Task IGuildUser.RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options) =>
throw new NotSupportedException("Roles are not supported on webhook users.");
}

//IVoiceState
/// <inheritdoc />
bool IVoiceState.IsDeafened => false;
/// <inheritdoc />
bool IVoiceState.IsMuted => false;
/// <inheritdoc />
bool IVoiceState.IsSelfDeafened => false;
/// <inheritdoc />
bool IVoiceState.IsSelfMuted => false;
/// <inheritdoc />
bool IVoiceState.IsSuppressed => false;
/// <inheritdoc />
IVoiceChannel IVoiceState.VoiceChannel => null;
/// <inheritdoc />
string IVoiceState.VoiceSessionId => null;
}
}

Loading…
Cancel
Save