Browse Source

Merge branch 'refactor/3.x' of https://github.com/Discord-Net-Labs/Discord.Net-Labs into merger-labs

pull/1923/head
quin lynch 4 years ago
parent
commit
6d5f0cb43c
29 changed files with 394 additions and 140 deletions
  1. +8
    -3
      src/Discord.Net.Commands/Builders/CommandBuilder.cs
  2. +7
    -2
      src/Discord.Net.Commands/Builders/ModuleBuilder.cs
  3. +7
    -2
      src/Discord.Net.Commands/Builders/ParameterBuilder.cs
  4. +10
    -3
      src/Discord.Net.Commands/CommandService.cs
  5. +4
    -1
      src/Discord.Net.Commands/ModuleBase.cs
  6. +15
    -0
      src/Discord.Net.Core/Entities/Guilds/IGuild.cs
  7. +2
    -2
      src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs
  8. +78
    -25
      src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs
  9. +4
    -1
      src/Discord.Net.Rest/BaseDiscordClient.cs
  10. +2
    -1
      src/Discord.Net.Rest/ClientHelper.cs
  11. +61
    -30
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  12. +5
    -1
      src/Discord.Net.Rest/DiscordRestClient.cs
  13. +4
    -1
      src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs
  14. +4
    -1
      src/Discord.Net.Rest/Entities/Channels/RestChannel.cs
  15. +6
    -2
      src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs
  16. +14
    -6
      src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs
  17. +10
    -4
      src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs
  18. +24
    -12
      src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
  19. +45
    -14
      src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
  20. +10
    -4
      src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs
  21. +4
    -1
      src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs
  22. +4
    -2
      src/Discord.Net.Rest/Entities/Roles/RestRole.cs
  23. +2
    -1
      src/Discord.Net.Rest/Entities/Roles/RoleHelper.cs
  24. +6
    -2
      src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
  25. +4
    -1
      src/Discord.Net.Rest/Entities/Users/RestUser.cs
  26. +6
    -2
      src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs
  27. +4
    -1
      src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs
  28. +4
    -1
      src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs
  29. +40
    -14
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs

+ 8
- 3
src/Discord.Net.Commands/Builders/CommandBuilder.cs View File

@@ -7,6 +7,7 @@ namespace Discord.Commands.Builders
{ {
public class CommandBuilder public class CommandBuilder
{ {
#region CommandBuilder
private readonly List<PreconditionAttribute> _preconditions; private readonly List<PreconditionAttribute> _preconditions;
private readonly List<ParameterBuilder> _parameters; private readonly List<ParameterBuilder> _parameters;
private readonly List<Attribute> _attributes; private readonly List<Attribute> _attributes;
@@ -27,8 +28,9 @@ namespace Discord.Commands.Builders
public IReadOnlyList<ParameterBuilder> Parameters => _parameters; public IReadOnlyList<ParameterBuilder> Parameters => _parameters;
public IReadOnlyList<Attribute> Attributes => _attributes; public IReadOnlyList<Attribute> Attributes => _attributes;
public IReadOnlyList<string> Aliases => _aliases; public IReadOnlyList<string> Aliases => _aliases;
#endregion


//Automatic
#region Automatic
internal CommandBuilder(ModuleBuilder module) internal CommandBuilder(ModuleBuilder module)
{ {
Module = module; Module = module;
@@ -38,7 +40,9 @@ namespace Discord.Commands.Builders
_attributes = new List<Attribute>(); _attributes = new List<Attribute>();
_aliases = new List<string>(); _aliases = new List<string>();
} }
//User-defined
#endregion

#region User-defined
internal CommandBuilder(ModuleBuilder module, string primaryAlias, Func<ICommandContext, object[], IServiceProvider, CommandInfo, Task> callback) internal CommandBuilder(ModuleBuilder module, string primaryAlias, Func<ICommandContext, object[], IServiceProvider, CommandInfo, Task> callback)
: this(module) : this(module)
{ {
@@ -132,7 +136,7 @@ namespace Discord.Commands.Builders
var firstMultipleParam = _parameters.FirstOrDefault(x => x.IsMultiple); var firstMultipleParam = _parameters.FirstOrDefault(x => x.IsMultiple);
if ((firstMultipleParam != null) && (firstMultipleParam != lastParam)) if ((firstMultipleParam != null) && (firstMultipleParam != lastParam))
throw new InvalidOperationException($"Only the last parameter in a command may have the Multiple flag. Parameter: {firstMultipleParam.Name} in {PrimaryAlias}"); throw new InvalidOperationException($"Only the last parameter in a command may have the Multiple flag. Parameter: {firstMultipleParam.Name} in {PrimaryAlias}");
var firstRemainderParam = _parameters.FirstOrDefault(x => x.IsRemainder); var firstRemainderParam = _parameters.FirstOrDefault(x => x.IsRemainder);
if ((firstRemainderParam != null) && (firstRemainderParam != lastParam)) if ((firstRemainderParam != null) && (firstRemainderParam != lastParam))
throw new InvalidOperationException($"Only the last parameter in a command may have the Remainder flag. Parameter: {firstRemainderParam.Name} in {PrimaryAlias}"); throw new InvalidOperationException($"Only the last parameter in a command may have the Remainder flag. Parameter: {firstRemainderParam.Name} in {PrimaryAlias}");
@@ -140,5 +144,6 @@ namespace Discord.Commands.Builders


return new CommandInfo(this, info, service); return new CommandInfo(this, info, service);
} }
#endregion
} }
} }

+ 7
- 2
src/Discord.Net.Commands/Builders/ModuleBuilder.cs View File

@@ -7,6 +7,7 @@ namespace Discord.Commands.Builders
{ {
public class ModuleBuilder public class ModuleBuilder
{ {
#region ModuleBuilder
private readonly List<CommandBuilder> _commands; private readonly List<CommandBuilder> _commands;
private readonly List<ModuleBuilder> _submodules; private readonly List<ModuleBuilder> _submodules;
private readonly List<PreconditionAttribute> _preconditions; private readonly List<PreconditionAttribute> _preconditions;
@@ -27,8 +28,9 @@ namespace Discord.Commands.Builders
public IReadOnlyList<string> Aliases => _aliases; public IReadOnlyList<string> Aliases => _aliases;


internal TypeInfo TypeInfo { get; set; } internal TypeInfo TypeInfo { get; set; }
#endregion


//Automatic
#region Automatic
internal ModuleBuilder(CommandService service, ModuleBuilder parent) internal ModuleBuilder(CommandService service, ModuleBuilder parent)
{ {
Service = service; Service = service;
@@ -40,7 +42,9 @@ namespace Discord.Commands.Builders
_attributes = new List<Attribute>(); _attributes = new List<Attribute>();
_aliases = new List<string>(); _aliases = new List<string>();
} }
//User-defined
#endregion

#region User-defined
internal ModuleBuilder(CommandService service, ModuleBuilder parent, string primaryAlias) internal ModuleBuilder(CommandService service, ModuleBuilder parent, string primaryAlias)
: this(service, parent) : this(service, parent)
{ {
@@ -132,5 +136,6 @@ namespace Discord.Commands.Builders
public ModuleInfo Build(CommandService service, IServiceProvider services) => BuildImpl(service, services); public ModuleInfo Build(CommandService service, IServiceProvider services) => BuildImpl(service, services);


internal ModuleInfo Build(CommandService service, IServiceProvider services, ModuleInfo parent) => BuildImpl(service, services, parent); internal ModuleInfo Build(CommandService service, IServiceProvider services, ModuleInfo parent) => BuildImpl(service, services, parent);
#endregion
} }
} }

+ 7
- 2
src/Discord.Net.Commands/Builders/ParameterBuilder.cs View File

@@ -8,6 +8,7 @@ namespace Discord.Commands.Builders
{ {
public class ParameterBuilder public class ParameterBuilder
{ {
#region ParameterBuilder
private readonly List<ParameterPreconditionAttribute> _preconditions; private readonly List<ParameterPreconditionAttribute> _preconditions;
private readonly List<Attribute> _attributes; private readonly List<Attribute> _attributes;


@@ -24,8 +25,9 @@ namespace Discord.Commands.Builders


public IReadOnlyList<ParameterPreconditionAttribute> Preconditions => _preconditions; public IReadOnlyList<ParameterPreconditionAttribute> Preconditions => _preconditions;
public IReadOnlyList<Attribute> Attributes => _attributes; public IReadOnlyList<Attribute> Attributes => _attributes;
#endregion


//Automatic
#region Automatic
internal ParameterBuilder(CommandBuilder command) internal ParameterBuilder(CommandBuilder command)
{ {
_preconditions = new List<ParameterPreconditionAttribute>(); _preconditions = new List<ParameterPreconditionAttribute>();
@@ -33,7 +35,9 @@ namespace Discord.Commands.Builders


Command = command; Command = command;
} }
//User-defined
#endregion

#region User-defined
internal ParameterBuilder(CommandBuilder command, string name, Type type) internal ParameterBuilder(CommandBuilder command, string name, Type type)
: this(command) : this(command)
{ {
@@ -132,5 +136,6 @@ namespace Discord.Commands.Builders


return new ParameterInfo(this, info, Command.Module.Service); return new ParameterInfo(this, info, Command.Module.Service);
} }
#endregion
} }
} }

+ 10
- 3
src/Discord.Net.Commands/CommandService.cs View File

@@ -29,6 +29,7 @@ namespace Discord.Commands
/// </remarks> /// </remarks>
public class CommandService : IDisposable public class CommandService : IDisposable
{ {
#region CommandService
/// <summary> /// <summary>
/// Occurs when a command-related information is received. /// Occurs when a command-related information is received.
/// </summary> /// </summary>
@@ -131,8 +132,9 @@ namespace Discord.Commands
entityTypeReaders.Add((typeof(IUser), typeof(UserTypeReader<>))); entityTypeReaders.Add((typeof(IUser), typeof(UserTypeReader<>)));
_entityTypeReaders = entityTypeReaders.ToImmutable(); _entityTypeReaders = entityTypeReaders.ToImmutable();
} }
#endregion


//Modules
#region Modules
public async Task<ModuleInfo> CreateModuleAsync(string primaryAlias, Action<ModuleBuilder> buildFunc) public async Task<ModuleInfo> CreateModuleAsync(string primaryAlias, Action<ModuleBuilder> buildFunc)
{ {
await _moduleLock.WaitAsync().ConfigureAwait(false); await _moduleLock.WaitAsync().ConfigureAwait(false);
@@ -322,8 +324,9 @@ namespace Discord.Commands


return true; return true;
} }
#endregion


//Type Readers
#region Type Readers
/// <summary> /// <summary>
/// Adds a custom <see cref="TypeReader" /> to this <see cref="CommandService" /> for the supplied object /// Adds a custom <see cref="TypeReader" /> to this <see cref="CommandService" /> for the supplied object
/// type. /// type.
@@ -448,8 +451,9 @@ namespace Discord.Commands
} }
return null; return null;
} }
#endregion


//Execution
#region Execution
/// <summary> /// <summary>
/// Searches for the command. /// Searches for the command.
/// </summary> /// </summary>
@@ -602,7 +606,9 @@ namespace Discord.Commands
await _commandExecutedEvent.InvokeAsync(chosenOverload.Key.Command, context, result); await _commandExecutedEvent.InvokeAsync(chosenOverload.Key.Command, context, result);
return result; return result;
} }
#endregion


#region Dispose
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!_isDisposed) if (!_isDisposed)
@@ -620,5 +626,6 @@ namespace Discord.Commands
{ {
Dispose(true); Dispose(true);
} }
#endregion
} }
} }

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

@@ -16,6 +16,7 @@ namespace Discord.Commands
public abstract class ModuleBase<T> : IModuleBase public abstract class ModuleBase<T> : IModuleBase
where T : class, ICommandContext where T : class, ICommandContext
{ {
#region ModuleBase
/// <summary> /// <summary>
/// The underlying context of the command. /// The underlying context of the command.
/// </summary> /// </summary>
@@ -65,8 +66,9 @@ namespace Discord.Commands
protected virtual void OnModuleBuilding(CommandService commandService, ModuleBuilder builder) protected virtual void OnModuleBuilding(CommandService commandService, ModuleBuilder builder)
{ {
} }
#endregion


//IModuleBase
#region IModuleBase
void IModuleBase.SetContext(ICommandContext context) void IModuleBase.SetContext(ICommandContext context)
{ {
var newValue = context as T; var newValue = context as T;
@@ -75,5 +77,6 @@ namespace Discord.Commands
void IModuleBase.BeforeExecute(CommandInfo command) => BeforeExecute(command); void IModuleBase.BeforeExecute(CommandInfo command) => BeforeExecute(command);
void IModuleBase.AfterExecute(CommandInfo command) => AfterExecute(command); void IModuleBase.AfterExecute(CommandInfo command) => AfterExecute(command);
void IModuleBase.OnModuleBuilding(CommandService commandService, ModuleBuilder builder) => OnModuleBuilding(commandService, builder); void IModuleBase.OnModuleBuilding(CommandService commandService, ModuleBuilder builder) => OnModuleBuilding(commandService, builder);
#endregion
} }
} }

+ 15
- 0
src/Discord.Net.Core/Entities/Guilds/IGuild.cs View File

@@ -771,6 +771,12 @@ namespace Discord
/// <returns>A guild user associated with the specified <paramref name="userId" />; <see langword="null" /> if the user is already in the guild.</returns> /// <returns>A guild user associated with the specified <paramref name="userId" />; <see langword="null" /> if the user is already in the guild.</returns>
Task<IGuildUser> AddGuildUserAsync(ulong userId, string accessToken, Action<AddGuildUserProperties> func = null, RequestOptions options = null); Task<IGuildUser> AddGuildUserAsync(ulong userId, string accessToken, Action<AddGuildUserProperties> func = null, RequestOptions options = null);
/// <summary> /// <summary>
/// Disconnects the user from its current voice channel
/// </summary>
/// <param name="user">The user to disconnect.</param>
/// <returns>A task that represents the asynchronous operation for disconnecting a user.</returns>
Task DisconnectAsync(IGuildUser user);
/// <summary>
/// Gets a collection of all users in this guild. /// Gets a collection of all users in this guild.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
@@ -951,6 +957,15 @@ namespace Discord
/// emote. /// emote.
/// </returns> /// </returns>
Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null); Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null);

/// <summary>
/// Moves the user to the voice channel.
/// </summary>
/// <param name="user">The user to move.</param>
/// <param name="targetChannel">the channel where the user gets moved to.</param>
/// <returns>A task that represents the asynchronous operation for moving a user.</returns>
Task MoveAsync(IGuildUser user, IVoiceChannel targetChannel);

/// <summary> /// <summary>
/// Deletes an existing <see cref="GuildEmote"/> from this guild. /// Deletes an existing <see cref="GuildEmote"/> from this guild.
/// </summary> /// </summary>


+ 2
- 2
src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs View File

@@ -22,16 +22,16 @@ namespace Discord
/// </summary> /// </summary>
Pong = 1, Pong = 1,


[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or DeferredChannelMessageWithSource", true)]
/// <summary> /// <summary>
/// ACK a command without sending a message, eating the user's input. /// ACK a command without sending a message, eating the user's input.
/// </summary> /// </summary>
[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or DeferredChannelMessageWithSource", true)]
Acknowledge = 2, Acknowledge = 2,


[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or DeferredChannelMessageWithSource", true)]
/// <summary> /// <summary>
/// Respond with a message, showing the user's input. /// Respond with a message, showing the user's input.
/// </summary> /// </summary>
[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or DeferredChannelMessageWithSource", true)]
ChannelMessage = 3, ChannelMessage = 3,


/// <summary> /// <summary>


+ 78
- 25
src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs View File

@@ -10,11 +10,6 @@ namespace Discord
/// </summary> /// </summary>
public class ComponentBuilder public class ComponentBuilder
{ {
/// <summary>
/// The max length of a <see cref="ButtonComponent.Label"/>.
/// </summary>
public const int MaxButtonLabelLength = 80;

/// <summary> /// <summary>
/// The max length of a <see cref="ButtonComponent.CustomId"/>. /// The max length of a <see cref="ButtonComponent.CustomId"/>.
/// </summary> /// </summary>
@@ -124,6 +119,8 @@ namespace Discord
public ComponentBuilder WithSelectMenu(SelectMenuBuilder menu, int row = 0) public ComponentBuilder WithSelectMenu(SelectMenuBuilder menu, int row = 0)
{ {
Preconditions.LessThan(row, MaxActionRowCount, nameof(row)); Preconditions.LessThan(row, MaxActionRowCount, nameof(row));
if (menu.Options.Distinct().Count() != menu.Options.Count())
throw new InvalidOperationException("Please make sure that there is no duplicates values.");


var builtMenu = menu.Build(); var builtMenu = menu.Build();


@@ -351,19 +348,27 @@ namespace Discord
/// <summary> /// <summary>
/// The max length of a <see cref="ButtonComponent.Label"/>. /// The max length of a <see cref="ButtonComponent.Label"/>.
/// </summary> /// </summary>
public const int MaxLabelLength = 80;
public const int MaxButtonLabelLength = 80;


/// <summary> /// <summary>
/// Gets or sets the label of the current button. /// Gets or sets the label of the current button.
/// </summary> /// </summary>
/// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="ComponentBuilder.MaxButtonLabelLength"/>.</exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="MaxButtonLabelLength"/>.</exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="MaxButtonLabelLength"/>.</exception>
public string Label public string Label
{ {
get => _label; get => _label;
set set
{ {
if (value != null && value.Length > ComponentBuilder.MaxButtonLabelLength)
throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxButtonLabelLength} characters or less!", paramName: nameof(Label));
if (value != null)
{
if (value.Length > MaxButtonLabelLength)
throw new ArgumentException($"Button label must be {MaxButtonLabelLength} characters or less!", paramName: nameof(Label));
if (value.Length < 1)
throw new ArgumentException("Button label must be 1 character or more!", paramName: nameof(Label));
}
else
throw new ArgumentException("Button label must not be null or empty!", paramName: nameof(Label));


_label = value; _label = value;
} }
@@ -373,13 +378,21 @@ namespace Discord
/// Gets or sets the custom id of the current button. /// Gets or sets the custom id of the current button.
/// </summary> /// </summary>
/// <exception cref="ArgumentException" accessor="set"><see cref="CustomId"/> length exceeds <see cref="ComponentBuilder.MaxCustomIdLength"/></exception> /// <exception cref="ArgumentException" accessor="set"><see cref="CustomId"/> length exceeds <see cref="ComponentBuilder.MaxCustomIdLength"/></exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="CustomId"/> length subceeds 1.</exception>
public string CustomId public string CustomId
{ {
get => _customId; get => _customId;
set set
{ {
if (value != null && value.Length > ComponentBuilder.MaxCustomIdLength)
throw new ArgumentException(message: $"Custom Id must be {ComponentBuilder.MaxCustomIdLength} characters or less!", paramName: nameof(CustomId));
if (value != null)
{
if (value.Length > ComponentBuilder.MaxCustomIdLength)
throw new ArgumentException($"Custom Id must be {ComponentBuilder.MaxCustomIdLength} characters or less!", paramName: nameof(CustomId));
if (value.Length < 1)
throw new ArgumentException("Custom Id must be 1 character or more!", paramName: nameof(CustomId));
}
else
throw new ArgumentException("Custom Id must not be null or empty!", paramName: nameof(CustomId));
_customId = value; _customId = value;
} }
} }
@@ -617,14 +630,22 @@ namespace Discord
/// <summary> /// <summary>
/// Gets or sets the custom id of the current select menu. /// Gets or sets the custom id of the current select menu.
/// </summary> /// </summary>
/// <exception cref="ArgumentException" accessor="set"><see cref="CustomId"/> length exceeds <see cref="ComponentBuilder.MaxCustomIdLength"/>.</exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="CustomId"/> length exceeds <see cref="ComponentBuilder.MaxCustomIdLength"/></exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="CustomId"/> length subceeds 1.</exception>
public string CustomId public string CustomId
{ {
get => _customId; get => _customId;
set set
{ {
if (value != null && value.Length > ComponentBuilder.MaxCustomIdLength)
throw new ArgumentException(message: $"Custom Id must be {ComponentBuilder.MaxCustomIdLength} characters or less!", paramName: nameof(CustomId));
if (value != null)
{
if (value.Length > ComponentBuilder.MaxCustomIdLength)
throw new ArgumentException($"Custom Id must be {ComponentBuilder.MaxCustomIdLength} characters or less!", paramName: nameof(CustomId));
if (value.Length < 1)
throw new ArgumentException("Custom Id must be 1 character or more!", paramName: nameof(CustomId));
}
else
throw new ArgumentException("Custom Id must not be null or empty!", paramName: nameof(CustomId));
_customId = value; _customId = value;
} }
} }
@@ -633,13 +654,21 @@ namespace Discord
/// Gets or sets the placeholder text of the current select menu. /// Gets or sets the placeholder text of the current select menu.
/// </summary> /// </summary>
/// <exception cref="ArgumentException" accessor="set"><see cref="Placeholder"/> length exceeds <see cref="MaxPlaceholderLength"/>.</exception> /// <exception cref="ArgumentException" accessor="set"><see cref="Placeholder"/> length exceeds <see cref="MaxPlaceholderLength"/>.</exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="Placeholder"/> length subceeds 1.</exception>
public string Placeholder public string Placeholder
{ {
get => _placeholder; get => _placeholder;
set set
{ {
if (value?.Length > MaxPlaceholderLength)
throw new ArgumentException(message: $"Placeholder must be {MaxPlaceholderLength} characters or less!", paramName: nameof(Placeholder));
if (value != null)
{
if (value.Length > MaxPlaceholderLength)
throw new ArgumentException($"The placeholder must be {MaxPlaceholderLength} characters or less!", paramName: nameof(Placeholder));
if (value.Length < 1)
throw new ArgumentException("The placeholder must be 1 character or more!", paramName: nameof(Placeholder));
}
else
throw new ArgumentException("The placeholder must not be null or empty!", paramName: nameof(Placeholder));


_placeholder = value; _placeholder = value;
} }
@@ -880,7 +909,7 @@ namespace Discord
/// <summary> /// <summary>
/// The maximum length of a <see cref="SelectMenuOption.Label"/>. /// The maximum length of a <see cref="SelectMenuOption.Label"/>.
/// </summary> /// </summary>
public const int MaxLabelLength = 100;
public const int MaxSelectLabelLength = 100;


/// <summary> /// <summary>
/// The maximum length of a <see cref="SelectMenuOption.Description"/>. /// The maximum length of a <see cref="SelectMenuOption.Description"/>.
@@ -888,22 +917,29 @@ namespace Discord
public const int MaxDescriptionLength = 100; public const int MaxDescriptionLength = 100;
/// <summary> /// <summary>
/// The maximum length of a <see cref="SelectMenuOption.Label"/>.
/// The maximum length of a <see cref="SelectMenuOption.Value"/>.
/// </summary> /// </summary>
public const int MaxSelectLabelLength = 100;
public const int MaxSelectValueLength = 100;


/// <summary> /// <summary>
/// Gets or sets the label of the current select menu. /// Gets or sets the label of the current select menu.
/// </summary> /// </summary>
/// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="MaxSelectLabelLength"/></exception> /// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length exceeds <see cref="MaxSelectLabelLength"/></exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length subceeds 1.</exception>
public string Label public string Label
{ {
get => _label; get => _label;
set set
{ {
if (value != null) if (value != null)
{
if (value.Length > MaxSelectLabelLength) if (value.Length > MaxSelectLabelLength)
throw new ArgumentException(message: $"Button label must be {MaxSelectLabelLength} characters or less!", paramName: nameof(Label));
throw new ArgumentException($"Select option label must be {MaxSelectLabelLength} characters or less!", paramName: nameof(Label));
if (value.Length < 1)
throw new ArgumentException("Select option label must be 1 character or more!", paramName: nameof(Label));
}
else
throw new ArgumentException("Select option label must not be null or empty!", paramName: nameof(Label));


_label = value; _label = value;
} }
@@ -912,14 +948,23 @@ namespace Discord
/// <summary> /// <summary>
/// Gets or sets the custom id of the current select menu. /// Gets or sets the custom id of the current select menu.
/// </summary> /// </summary>
/// <exception cref="ArgumentException" accessor="set"><see cref="Value"/> length exceeds <see cref="ComponentBuilder.MaxCustomIdLength"/>.</exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="Value"/> length exceeds <see cref="MaxSelectValueLength"/>.</exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="Value"/> length subceeds 1.</exception>
public string Value public string Value
{ {
get => _value; get => _value;
set set
{ {
if (value != null && value.Length > ComponentBuilder.MaxCustomIdLength)
throw new ArgumentException(message: $"Value must be {ComponentBuilder.MaxCustomIdLength} characters or less!", paramName: nameof(Value));
if (value != null)
{
if (value.Length > MaxSelectValueLength)
throw new ArgumentException($"Select option value must be {MaxSelectValueLength} characters or less!", paramName: nameof(Label));
if (value.Length < 1)
throw new ArgumentException("Select option value must be 1 character or more!", paramName: nameof(Label));
}
else
throw new ArgumentException("Select option value must not be null or empty!", paramName: nameof(Label));

_value = value; _value = value;
} }
} }
@@ -928,13 +973,21 @@ namespace Discord
/// Gets or sets this menu options description. /// Gets or sets this menu options description.
/// </summary> /// </summary>
/// <exception cref="ArgumentException" accessor="set"><see cref="Description"/> length exceeds <see cref="MaxDescriptionLength"/>.</exception> /// <exception cref="ArgumentException" accessor="set"><see cref="Description"/> length exceeds <see cref="MaxDescriptionLength"/>.</exception>
/// <exception cref="ArgumentException" accessor="set"><see cref="Label"/> length subceeds 1.</exception>
public string Description public string Description
{ {
get => _description; get => _description;
set set
{ {
if (value != null && value.Length > MaxDescriptionLength)
throw new ArgumentException($"Description must be {MaxDescriptionLength} characters or less!", nameof(Description));
if (value != null)
{
if (value.Length > MaxDescriptionLength)
throw new ArgumentException($"The description must be {MaxDescriptionLength} characters or less!", paramName: nameof(Label));
if (value.Length < 1)
throw new ArgumentException("The description must be 1 character or more!", paramName: nameof(Label));
}
else
throw new ArgumentException("The description must not be null or empty!", paramName: nameof(Label));


_description = value; _description = value;
} }


+ 4
- 1
src/Discord.Net.Rest/BaseDiscordClient.cs View File

@@ -10,6 +10,7 @@ namespace Discord.Rest
{ {
public abstract class BaseDiscordClient : IDiscordClient public abstract class BaseDiscordClient : IDiscordClient
{ {
#region BaseDiscordClient
public event Func<LogMessage, Task> Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } } public event Func<LogMessage, Task> Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } }
internal readonly AsyncEvent<Func<LogMessage, Task>> _logEvent = new AsyncEvent<Func<LogMessage, Task>>(); internal readonly AsyncEvent<Func<LogMessage, Task>> _logEvent = new AsyncEvent<Func<LogMessage, Task>>();


@@ -155,8 +156,9 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
public Task<BotGateway> GetBotGatewayAsync(RequestOptions options = null) public Task<BotGateway> GetBotGatewayAsync(RequestOptions options = null)
=> ClientHelper.GetBotGatewayAsync(this, options); => ClientHelper.GetBotGatewayAsync(this, options);
#endregion


//IDiscordClient
#region IDiscordClient
/// <inheritdoc /> /// <inheritdoc />
ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected; ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected;
/// <inheritdoc /> /// <inheritdoc />
@@ -235,5 +237,6 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
Task IDiscordClient.StopAsync() Task IDiscordClient.StopAsync()
=> Task.Delay(0); => Task.Delay(0);
#endregion
} }
} }

+ 2
- 1
src/Discord.Net.Rest/ClientHelper.cs View File

@@ -10,7 +10,7 @@ namespace Discord.Rest
{ {
internal static class ClientHelper internal static class ClientHelper
{ {
//Applications
#region Applications
public static async Task<RestApplication> GetApplicationInfoAsync(BaseDiscordClient client, RequestOptions options) public static async Task<RestApplication> GetApplicationInfoAsync(BaseDiscordClient client, RequestOptions options)
{ {
var model = await client.ApiClient.GetMyApplicationAsync(options).ConfigureAwait(false); var model = await client.ApiClient.GetMyApplicationAsync(options).ConfigureAwait(false);
@@ -263,5 +263,6 @@ namespace Discord.Rest
public static Task RemoveRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) public static Task RemoveRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null)
=> client.ApiClient.RemoveRoleAsync(guildId, userId, roleId, options); => client.ApiClient.RemoveRoleAsync(guildId, userId, roleId, options);
#endregion
} }
} }

+ 61
- 30
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -24,6 +24,7 @@ namespace Discord.API
{ {
internal class DiscordRestApiClient : IDisposable internal class DiscordRestApiClient : IDisposable
{ {
#region DiscordRestApiClient
private static readonly ConcurrentDictionary<string, Func<BucketIds, BucketId>> _bucketIdGenerators = new ConcurrentDictionary<string, Func<BucketIds, BucketId>>(); private static readonly ConcurrentDictionary<string, Func<BucketIds, BucketId>> _bucketIdGenerators = new ConcurrentDictionary<string, Func<BucketIds, BucketId>>();


public event Func<string, string, double, Task> SentRequest { add { _sentRequestEvent.Add(value); } remove { _sentRequestEvent.Remove(value); } } public event Func<string, string, double, Task> SentRequest { add { _sentRequestEvent.Add(value); } remove { _sentRequestEvent.Remove(value); } }
@@ -167,8 +168,9 @@ namespace Discord.API


internal virtual Task ConnectInternalAsync() => Task.Delay(0); internal virtual Task ConnectInternalAsync() => Task.Delay(0);
internal virtual Task DisconnectInternalAsync(Exception ex = null) => Task.Delay(0); internal virtual Task DisconnectInternalAsync(Exception ex = null) => Task.Delay(0);
#endregion


//Core
#region Core
internal Task SendAsync(string method, Expression<Func<string>> endpointExpr, BucketIds ids, internal Task SendAsync(string method, Expression<Func<string>> endpointExpr, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendAsync(method, GetEndpoint(endpointExpr), GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options); => SendAsync(method, GetEndpoint(endpointExpr), GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options);
@@ -271,15 +273,17 @@ namespace Discord.API


return responseStream; return responseStream;
} }
#endregion


//Auth
#region Auth
public async Task ValidateTokenAsync(RequestOptions options = null) public async Task ValidateTokenAsync(RequestOptions options = null)
{ {
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
await SendAsync("GET", () => "auth/login", new BucketIds(), options: options).ConfigureAwait(false); await SendAsync("GET", () => "auth/login", new BucketIds(), options: options).ConfigureAwait(false);
} }
#endregion


//Gateway
#region Gateway
public async Task<GetGatewayResponse> GetGatewayAsync(RequestOptions options = null) public async Task<GetGatewayResponse> GetGatewayAsync(RequestOptions options = null)
{ {
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
@@ -290,8 +294,9 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
return await SendAsync<GetBotGatewayResponse>("GET", () => "gateway/bot", new BucketIds(), options: options).ConfigureAwait(false); return await SendAsync<GetBotGatewayResponse>("GET", () => "gateway/bot", new BucketIds(), options: options).ConfigureAwait(false);
} }
#endregion


//Channels
#region Channels
public async Task<Channel> GetChannelAsync(ulong channelId, RequestOptions options = null) public async Task<Channel> GetChannelAsync(ulong channelId, RequestOptions options = null)
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
@@ -414,8 +419,9 @@ namespace Discord.API
break; break;
} }
} }
#endregion


// Threads
#region Threads
public async Task<Channel> ModifyThreadAsync(ulong channelId, ModifyThreadParams args, RequestOptions options = null) public async Task<Channel> ModifyThreadAsync(ulong channelId, ModifyThreadParams args, RequestOptions options = null)
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
@@ -582,8 +588,9 @@ namespace Discord.API


return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/users/@me/threads/archived/private{query}", bucket, options: options); return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/users/@me/threads/archived/private{query}", bucket, options: options);
} }
#endregion


// stage
#region Stage
public async Task<StageInstance> CreateStageInstanceAsync(CreateStageInstanceParams args, RequestOptions options = null) public async Task<StageInstance> CreateStageInstanceAsync(CreateStageInstanceParams args, RequestOptions options = null)
{ {
@@ -658,8 +665,9 @@ namespace Discord.API


await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/{userId}", args, bucket, options: options).ConfigureAwait(false); await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/{userId}", args, bucket, options: options).ConfigureAwait(false);
} }
#endregion


// roles
#region Roles
public async Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) public async Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -682,8 +690,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
await SendAsync("DELETE", () => $"guilds/{guildId}/members/{userId}/roles/{roleId}", ids, options: options).ConfigureAwait(false); await SendAsync("DELETE", () => $"guilds/{guildId}/members/{userId}/roles/{roleId}", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Channel Messages
#region Channel Messages
public async Task<Message> GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) public async Task<Message> GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
@@ -886,8 +895,9 @@ namespace Discord.API
var ids = new BucketIds(channelId: channelId); var ids = new BucketIds(channelId: channelId);
return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
} }
#endregion


// Stickers
#region Stickers
public async Task<Sticker> GetStickerAsync(ulong id, RequestOptions options = null) public async Task<Sticker> GetStickerAsync(ulong id, RequestOptions options = null)
{ {
Preconditions.NotEqual(id, 0, nameof(id)); Preconditions.NotEqual(id, 0, nameof(id));
@@ -1044,8 +1054,9 @@ namespace Discord.API
var ids = new BucketIds(channelId: channelId); var ids = new BucketIds(channelId: channelId);
await SendAsync("POST", () => $"channels/{channelId}/messages/{messageId}/crosspost", ids, options: options).ConfigureAwait(false); await SendAsync("POST", () => $"channels/{channelId}/messages/{messageId}/crosspost", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Channel Permissions
#region Channel Permissions
public async Task ModifyChannelPermissionsAsync(ulong channelId, ulong targetId, ModifyChannelPermissionsParams args, RequestOptions options = null) public async Task ModifyChannelPermissionsAsync(ulong channelId, ulong targetId, ModifyChannelPermissionsParams args, RequestOptions options = null)
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
@@ -1065,8 +1076,9 @@ namespace Discord.API
var ids = new BucketIds(channelId: channelId); var ids = new BucketIds(channelId: channelId);
await SendAsync("DELETE", () => $"channels/{channelId}/permissions/{targetId}", ids, options: options).ConfigureAwait(false); await SendAsync("DELETE", () => $"channels/{channelId}/permissions/{targetId}", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Channel Pins
#region Channel Pins
public async Task AddPinAsync(ulong channelId, ulong messageId, RequestOptions options = null) public async Task AddPinAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{ {
Preconditions.GreaterThan(channelId, 0, nameof(channelId)); Preconditions.GreaterThan(channelId, 0, nameof(channelId));
@@ -1094,8 +1106,9 @@ namespace Discord.API
var ids = new BucketIds(channelId: channelId); var ids = new BucketIds(channelId: channelId);
return await SendAsync<IReadOnlyCollection<Message>>("GET", () => $"channels/{channelId}/pins", ids, options: options).ConfigureAwait(false); return await SendAsync<IReadOnlyCollection<Message>>("GET", () => $"channels/{channelId}/pins", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Channel Recipients
#region Channel Recipients
public async Task AddGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null) public async Task AddGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null)
{ {
Preconditions.GreaterThan(channelId, 0, nameof(channelId)); Preconditions.GreaterThan(channelId, 0, nameof(channelId));
@@ -1115,8 +1128,9 @@ namespace Discord.API
var ids = new BucketIds(channelId: channelId); var ids = new BucketIds(channelId: channelId);
await SendAsync("DELETE", () => $"channels/{channelId}/recipients/{userId}", ids, options: options).ConfigureAwait(false); await SendAsync("DELETE", () => $"channels/{channelId}/recipients/{userId}", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Interactions
#region Interactions
public async Task<ApplicationCommand[]> GetGlobalApplicationCommandsAsync(RequestOptions options = null) public async Task<ApplicationCommand[]> GetGlobalApplicationCommandsAsync(RequestOptions options = null)
{ {
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
@@ -1252,8 +1266,9 @@ namespace Discord.API


return await TrySendApplicationCommand(SendJsonAsync<ApplicationCommand[]>("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false); return await TrySendApplicationCommand(SendJsonAsync<ApplicationCommand[]>("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false);
} }
#endregion


//Interaction Responses
#region Interaction Responses
public async Task CreateInteractionResponse(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null) public async Task CreateInteractionResponse(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null)
{ {
if(response.Data.IsSpecified && response.Data.Value.Content.IsSpecified) if(response.Data.IsSpecified && response.Data.Value.Content.IsSpecified)
@@ -1322,8 +1337,9 @@ namespace Discord.API


await SendAsync("DELETE", () => $"webhooks/{CurrentUserId}/{token}/messages/{id}", new BucketIds(), options: options).ConfigureAwait(false); await SendAsync("DELETE", () => $"webhooks/{CurrentUserId}/{token}/messages/{id}", new BucketIds(), options: options).ConfigureAwait(false);
} }
#endregion


// Application Command permissions
#region Application Command permissions
public async Task<GuildApplicationCommandPermission[]> GetGuildApplicationCommandPermissions(ulong guildId, RequestOptions options = null) public async Task<GuildApplicationCommandPermission[]> GetGuildApplicationCommandPermissions(ulong guildId, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -1362,8 +1378,9 @@ namespace Discord.API


return await SendJsonAsync<GuildApplicationCommandPermission[]>("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false); return await SendJsonAsync<GuildApplicationCommandPermission[]>("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false);
} }
#endregion


//Guilds
#region Guilds
public async Task<Guild> GetGuildAsync(ulong guildId, bool withCounts, RequestOptions options = null) public async Task<Guild> GetGuildAsync(ulong guildId, bool withCounts, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -1436,8 +1453,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
return await SendAsync<GetGuildPruneCountResponse>("GET", () => $"guilds/{guildId}/prune?days={args.Days}{endpointRoleIds}", ids, options: options).ConfigureAwait(false); return await SendAsync<GetGuildPruneCountResponse>("GET", () => $"guilds/{guildId}/prune?days={args.Days}{endpointRoleIds}", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Guild Bans
#region Guild Bans
public async Task<IReadOnlyCollection<Ban>> GetGuildBansAsync(ulong guildId, RequestOptions options = null) public async Task<IReadOnlyCollection<Ban>> GetGuildBansAsync(ulong guildId, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -1488,8 +1506,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
await SendAsync("DELETE", () => $"guilds/{guildId}/bans/{userId}", ids, options: options).ConfigureAwait(false); await SendAsync("DELETE", () => $"guilds/{guildId}/bans/{userId}", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Guild Widget
#region Guild Widget
/// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception> /// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception>
public async Task<GuildWidget> GetGuildWidgetAsync(ulong guildId, RequestOptions options = null) public async Task<GuildWidget> GetGuildWidgetAsync(ulong guildId, RequestOptions options = null)
{ {
@@ -1514,8 +1533,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
return await SendJsonAsync<GuildWidget>("PATCH", () => $"guilds/{guildId}/widget", args, ids, options: options).ConfigureAwait(false); return await SendJsonAsync<GuildWidget>("PATCH", () => $"guilds/{guildId}/widget", args, ids, options: options).ConfigureAwait(false);
} }
#endregion


//Guild Integrations
#region Guild Integrations
/// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception> /// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception>
public async Task<IReadOnlyCollection<Integration>> GetGuildIntegrationsAsync(ulong guildId, RequestOptions options = null) public async Task<IReadOnlyCollection<Integration>> GetGuildIntegrationsAsync(ulong guildId, RequestOptions options = null)
{ {
@@ -1567,8 +1587,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
return await SendAsync<Integration>("POST", () => $"guilds/{guildId}/integrations/{integrationId}/sync", ids, options: options).ConfigureAwait(false); return await SendAsync<Integration>("POST", () => $"guilds/{guildId}/integrations/{integrationId}/sync", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Guild Invites
#region Guild Invites
/// <exception cref="ArgumentException"><paramref name="inviteId"/> cannot be blank.</exception> /// <exception cref="ArgumentException"><paramref name="inviteId"/> cannot be blank.</exception>
/// <exception cref="ArgumentNullException"><paramref name="inviteId"/> must not be <see langword="null"/>.</exception> /// <exception cref="ArgumentNullException"><paramref name="inviteId"/> must not be <see langword="null"/>.</exception>
public async Task<InviteMetadata> GetInviteAsync(string inviteId, RequestOptions options = null) public async Task<InviteMetadata> GetInviteAsync(string inviteId, RequestOptions options = null)
@@ -1651,8 +1672,9 @@ namespace Discord.API


return await SendAsync<Invite>("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false); return await SendAsync<Invite>("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false);
} }
#endregion


//Guild Members
#region Guild Members
public async Task<GuildMember> AddGuildMemberAsync(ulong guildId, ulong userId, AddGuildMemberParams args, RequestOptions options = null) public async Task<GuildMember> AddGuildMemberAsync(ulong guildId, ulong userId, AddGuildMemberParams args, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -1750,8 +1772,9 @@ namespace Discord.API
Expression<Func<string>> endpoint = () => $"guilds/{guildId}/members/search?limit={limit}&query={query}"; Expression<Func<string>> endpoint = () => $"guilds/{guildId}/members/search?limit={limit}&query={query}";
return await SendAsync<IReadOnlyCollection<GuildMember>>("GET", endpoint, ids, options: options).ConfigureAwait(false); return await SendAsync<IReadOnlyCollection<GuildMember>>("GET", endpoint, ids, options: options).ConfigureAwait(false);
} }
#endregion


//Guild Roles
#region Guild Roles
public async Task<IReadOnlyCollection<Role>> GetGuildRolesAsync(ulong guildId, RequestOptions options = null) public async Task<IReadOnlyCollection<Role>> GetGuildRolesAsync(ulong guildId, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -1798,8 +1821,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
return await SendJsonAsync<IReadOnlyCollection<Role>>("PATCH", () => $"guilds/{guildId}/roles", args, ids, options: options).ConfigureAwait(false); return await SendJsonAsync<IReadOnlyCollection<Role>>("PATCH", () => $"guilds/{guildId}/roles", args, ids, options: options).ConfigureAwait(false);
} }
#endregion


//Guild emoji
#region Guild emoji
public async Task<IReadOnlyCollection<Emoji>> GetGuildEmotesAsync(ulong guildId, RequestOptions options = null) public async Task<IReadOnlyCollection<Emoji>> GetGuildEmotesAsync(ulong guildId, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -1851,8 +1875,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
await SendAsync("DELETE", () => $"guilds/{guildId}/emojis/{emoteId}", ids, options: options).ConfigureAwait(false); await SendAsync("DELETE", () => $"guilds/{guildId}/emojis/{emoteId}", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Users
#region Users
public async Task<User> GetUserAsync(ulong userId, RequestOptions options = null) public async Task<User> GetUserAsync(ulong userId, RequestOptions options = null)
{ {
Preconditions.NotEqual(userId, 0, nameof(userId)); Preconditions.NotEqual(userId, 0, nameof(userId));
@@ -1864,8 +1889,9 @@ namespace Discord.API
} }
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; } catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; }
} }
#endregion


//Current User/DMs
#region Current User/DMs
public async Task<User> GetMyUserAsync(RequestOptions options = null) public async Task<User> GetMyUserAsync(RequestOptions options = null)
{ {
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
@@ -1924,8 +1950,9 @@ namespace Discord.API


return await SendJsonAsync<Channel>("POST", () => "users/@me/channels", args, new BucketIds(), options: options).ConfigureAwait(false); return await SendJsonAsync<Channel>("POST", () => "users/@me/channels", args, new BucketIds(), options: options).ConfigureAwait(false);
} }
#endregion


//Voice Regions
#region Voice Regions
public async Task<IReadOnlyCollection<VoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null) public async Task<IReadOnlyCollection<VoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null)
{ {
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
@@ -1939,8 +1966,9 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false); return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Audit logs
#region Audit logs
public async Task<AuditLog> GetAuditLogsAsync(ulong guildId, GetAuditLogsParams args, RequestOptions options = null) public async Task<AuditLog> GetAuditLogsAsync(ulong guildId, GetAuditLogsParams args, RequestOptions options = null)
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -1969,12 +1997,13 @@ namespace Discord.API
.Append(args.ActionType.Value); .Append(args.ActionType.Value);
} }


// still use string interp for the query w/o params, as this is necessary for CreateBucketId
// Still use string interp for the query w/o params, as this is necessary for CreateBucketId
endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}{queryArgs.ToString()}"; endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}{queryArgs.ToString()}";
return await SendAsync<AuditLog>("GET", endpoint, ids, options: options).ConfigureAwait(false); return await SendAsync<AuditLog>("GET", endpoint, ids, options: options).ConfigureAwait(false);
} }
#endregion


//Webhooks
#region Webhooks
public async Task<Webhook> CreateWebhookAsync(ulong channelId, CreateWebhookParams args, RequestOptions options = null) public async Task<Webhook> CreateWebhookAsync(ulong channelId, CreateWebhookParams args, RequestOptions options = null)
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
@@ -2037,8 +2066,9 @@ namespace Discord.API
var ids = new BucketIds(channelId: channelId); var ids = new BucketIds(channelId: channelId);
return await SendAsync<IReadOnlyCollection<Webhook>>("GET", () => $"channels/{channelId}/webhooks", ids, options: options).ConfigureAwait(false); return await SendAsync<IReadOnlyCollection<Webhook>>("GET", () => $"channels/{channelId}/webhooks", ids, options: options).ConfigureAwait(false);
} }
#endregion


//Helpers
#region Helpers
/// <exception cref="InvalidOperationException">Client is not logged in.</exception> /// <exception cref="InvalidOperationException">Client is not logged in.</exception>
protected void CheckState() protected void CheckState()
{ {
@@ -2248,5 +2278,6 @@ namespace Discord.API


return (expr as MemberExpression).Member.Name; return (expr as MemberExpression).Member.Name;
} }
#endregion
} }
} }

+ 5
- 1
src/Discord.Net.Rest/DiscordRestClient.cs View File

@@ -12,6 +12,7 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class DiscordRestClient : BaseDiscordClient, IDiscordClient public class DiscordRestClient : BaseDiscordClient, IDiscordClient
{ {
#region DiscordRestClient
private RestApplication _applicationInfo; private RestApplication _applicationInfo;


/// <summary> /// <summary>
@@ -138,7 +139,9 @@ namespace Discord.Rest
=> MessageHelper.RemoveAllReactionsAsync(channelId, messageId, this, options); => MessageHelper.RemoveAllReactionsAsync(channelId, messageId, this, options);
public Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, IEmote emote, RequestOptions options = null) public Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, IEmote emote, RequestOptions options = null)
=> MessageHelper.RemoveAllReactionsForEmoteAsync(channelId, messageId, emote, this, options); => MessageHelper.RemoveAllReactionsForEmoteAsync(channelId, messageId, emote, this, options);
//IDiscordClient
#endregion

#region IDiscordClient
/// <inheritdoc /> /// <inheritdoc />
async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options)
=> await GetApplicationInfoAsync(options).ConfigureAwait(false); => await GetApplicationInfoAsync(options).ConfigureAwait(false);
@@ -229,5 +232,6 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
async Task<IApplicationCommand> IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) async Task<IApplicationCommand> IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options)
=> await ClientHelper.GetGlobalApplicationCommand(this, id, options).ConfigureAwait(false); => await ClientHelper.GetGlobalApplicationCommand(this, id, options).ConfigureAwait(false);
#endregion
} }
} }

+ 4
- 1
src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs View File

@@ -12,6 +12,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestCategoryChannel : RestGuildChannel, ICategoryChannel public class RestCategoryChannel : RestGuildChannel, ICategoryChannel
{ {
#region RestCategoryChannel
internal RestCategoryChannel(BaseDiscordClient discord, IGuild guild, ulong id) internal RestCategoryChannel(BaseDiscordClient discord, IGuild guild, ulong id)
: base(discord, guild, id) : base(discord, guild, id)
{ {
@@ -24,8 +25,9 @@ namespace Discord.Rest
} }


private string DebuggerDisplay => $"{Name} ({Id}, Category)"; private string DebuggerDisplay => $"{Name} ({Id}, Category)";
#endregion


//IChannel
#region IChannel
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NotSupportedException">This method is not supported with category channels.</exception> /// <exception cref="NotSupportedException">This method is not supported with category channels.</exception>
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
@@ -34,5 +36,6 @@ namespace Discord.Rest
/// <exception cref="NotSupportedException">This method is not supported with category channels.</exception> /// <exception cref="NotSupportedException">This method is not supported with category channels.</exception>
Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> throw new NotSupportedException(); => throw new NotSupportedException();
#endregion
} }
} }

+ 4
- 1
src/Discord.Net.Rest/Entities/Channels/RestChannel.cs View File

@@ -11,6 +11,7 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class RestChannel : RestEntity<ulong>, IChannel, IUpdateable public class RestChannel : RestEntity<ulong>, IChannel, IUpdateable
{ {
#region RestChannel
/// <inheritdoc /> /// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);


@@ -53,8 +54,9 @@ namespace Discord.Rest


/// <inheritdoc /> /// <inheritdoc />
public virtual Task UpdateAsync(RequestOptions options = null) => Task.Delay(0); public virtual Task UpdateAsync(RequestOptions options = null) => Task.Delay(0);
#endregion


//IChannel
#region IChannel
/// <inheritdoc /> /// <inheritdoc />
string IChannel.Name => null; string IChannel.Name => null;


@@ -64,5 +66,6 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
=> AsyncEnumerable.Empty<IReadOnlyCollection<IUser>>(); //Overridden => AsyncEnumerable.Empty<IReadOnlyCollection<IUser>>(); //Overridden
#endregion
} }
} }

+ 6
- 2
src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs View File

@@ -12,6 +12,7 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class RestGuildChannel : RestChannel, IGuildChannel public class RestGuildChannel : RestChannel, IGuildChannel
{ {
#region RestGuildChannel
private ImmutableArray<Overwrite> _overwrites; private ImmutableArray<Overwrite> _overwrites;


/// <inheritdoc /> /// <inheritdoc />
@@ -191,8 +192,9 @@ namespace Discord.Rest
/// A string that is the name of this channel. /// A string that is the name of this channel.
/// </returns> /// </returns>
public override string ToString() => Name; public override string ToString() => Name;
#endregion


//IGuildChannel
#region IGuildChannel
/// <inheritdoc /> /// <inheritdoc />
IGuild IGuildChannel.Guild IGuild IGuildChannel.Guild
{ {
@@ -229,13 +231,15 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IGuildUser>(null); //Overridden in Text/Voice => Task.FromResult<IGuildUser>(null); //Overridden in Text/Voice
#endregion


//IChannel
#region IChannel
/// <inheritdoc /> /// <inheritdoc />
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
=> AsyncEnumerable.Empty<IReadOnlyCollection<IUser>>(); //Overridden in Text/Voice => AsyncEnumerable.Empty<IReadOnlyCollection<IUser>>(); //Overridden in Text/Voice
/// <inheritdoc /> /// <inheritdoc />
Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IUser>(null); //Overridden in Text/Voice => Task.FromResult<IUser>(null); //Overridden in Text/Voice
#endregion
} }
} }

+ 14
- 6
src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs View File

@@ -14,6 +14,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel
{ {
#region RestTextChannel
/// <inheritdoc /> /// <inheritdoc />
public string Topic { get; private set; } public string Topic { get; private set; }
/// <inheritdoc /> /// <inheritdoc />
@@ -210,8 +211,9 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
public Task SyncPermissionsAsync(RequestOptions options = null) public Task SyncPermissionsAsync(RequestOptions options = null)
=> ChannelHelper.SyncPermissionsAsync(this, Discord, options); => ChannelHelper.SyncPermissionsAsync(this, Discord, options);
#endregion


//Invites
#region Invites
/// <inheritdoc /> /// <inheritdoc />
public virtual async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) public virtual async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false);
@@ -261,8 +263,9 @@ namespace Discord.Rest
var model = await ThreadHelper.CreateThreadAsync(Discord, this, name, type, autoArchiveDuration, message, options); var model = await ThreadHelper.CreateThreadAsync(Discord, this, name, type, autoArchiveDuration, message, options);
return RestThreadChannel.Create(Discord, this.Guild, model); return RestThreadChannel.Create(Discord, this.Guild, model);
} }
#endregion


//ITextChannel
#region ITextChannel
/// <inheritdoc /> /// <inheritdoc />
async Task<IWebhook> ITextChannel.CreateWebhookAsync(string name, Stream avatar, RequestOptions options) async Task<IWebhook> ITextChannel.CreateWebhookAsync(string name, Stream avatar, RequestOptions options)
=> await CreateWebhookAsync(name, avatar, options).ConfigureAwait(false); => await CreateWebhookAsync(name, avatar, options).ConfigureAwait(false);
@@ -275,8 +278,9 @@ namespace Discord.Rest


async Task<IThreadChannel> ITextChannel.CreateThreadAsync(string name, ThreadType type, ThreadArchiveDuration autoArchiveDuration, IMessage message, RequestOptions options) async Task<IThreadChannel> ITextChannel.CreateThreadAsync(string name, ThreadType type, ThreadArchiveDuration autoArchiveDuration, IMessage message, RequestOptions options)
=> await CreateThreadAsync(name, type, autoArchiveDuration, message, options); => await CreateThreadAsync(name, type, autoArchiveDuration, message, options);
#endregion


//IMessageChannel
#region IMessageChannel
/// <inheritdoc /> /// <inheritdoc />
async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options)
{ {
@@ -324,8 +328,9 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers) async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers)
=> await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false); => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers).ConfigureAwait(false);
#endregion


//IGuildChannel
#region IGuildChannel
/// <inheritdoc /> /// <inheritdoc />
async Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) async Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
{ {
@@ -342,8 +347,9 @@ namespace Discord.Rest
else else
return AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>(); return AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>();
} }
#endregion


//IChannel
#region IChannel
/// <inheritdoc /> /// <inheritdoc />
async Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) async Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
{ {
@@ -360,8 +366,9 @@ namespace Discord.Rest
else else
return AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>(); return AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>();
} }
#endregion


// INestedChannel
#region ITextChannel
/// <inheritdoc /> /// <inheritdoc />
async Task<ICategoryChannel> INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) async Task<ICategoryChannel> INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options)
{ {
@@ -369,5 +376,6 @@ namespace Discord.Rest
return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel;
return null; return null;
} }
#endregion
} }
} }

+ 10
- 4
src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs View File

@@ -14,6 +14,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel
{ {
#region RestVoiceChannel
/// <inheritdoc /> /// <inheritdoc />
public int Bitrate { get; private set; } public int Bitrate { get; private set; }
/// <inheritdoc /> /// <inheritdoc />
@@ -63,8 +64,9 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
public Task SyncPermissionsAsync(RequestOptions options = null) public Task SyncPermissionsAsync(RequestOptions options = null)
=> ChannelHelper.SyncPermissionsAsync(this, Discord, options); => ChannelHelper.SyncPermissionsAsync(this, Discord, options);
#endregion


//Invites
#region Invites
/// <inheritdoc /> /// <inheritdoc />
public async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) public async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false);
@@ -79,22 +81,25 @@ namespace Discord.Rest
=> await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false);


private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; private string DebuggerDisplay => $"{Name} ({Id}, Voice)";
#endregion


//IAudioChannel
#region IAudioChannel
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NotSupportedException">Connecting to a REST-based channel is not supported.</exception> /// <exception cref="NotSupportedException">Connecting to a REST-based channel is not supported.</exception>
Task<IAudioClient> IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } Task<IAudioClient> IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); }
Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); }
#endregion


//IGuildChannel
#region IGuildChannel
/// <inheritdoc /> /// <inheritdoc />
Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IGuildUser>(null); => Task.FromResult<IGuildUser>(null);
/// <inheritdoc /> /// <inheritdoc />
IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
=> AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>(); => AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>();
#endregion


// INestedChannel
#region INestedChannel
/// <inheritdoc /> /// <inheritdoc />
async Task<ICategoryChannel> INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) async Task<ICategoryChannel> INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options)
{ {
@@ -102,5 +107,6 @@ namespace Discord.Rest
return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel;
return null; return null;
} }
#endregion
} }
} }

+ 24
- 12
src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs View File

@@ -14,7 +14,7 @@ namespace Discord.Rest
{ {
internal static class GuildHelper internal static class GuildHelper
{ {
//General
#region General
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException"><paramref name="func"/> is <c>null</c>.</exception>
public static async Task<Model> ModifyAsync(IGuild guild, BaseDiscordClient client, public static async Task<Model> ModifyAsync(IGuild guild, BaseDiscordClient client,
Action<GuildProperties> func, RequestOptions options) Action<GuildProperties> func, RequestOptions options)
@@ -123,8 +123,9 @@ namespace Discord.Rest
{ {
await client.ApiClient.DeleteGuildAsync(guild.Id, options).ConfigureAwait(false); await client.ApiClient.DeleteGuildAsync(guild.Id, options).ConfigureAwait(false);
} }
#endregion


//Bans
#region Bans
public static async Task<IReadOnlyCollection<RestBan>> GetBansAsync(IGuild guild, BaseDiscordClient client, public static async Task<IReadOnlyCollection<RestBan>> GetBansAsync(IGuild guild, BaseDiscordClient client,
RequestOptions options) RequestOptions options)
{ {
@@ -148,8 +149,9 @@ namespace Discord.Rest
{ {
await client.ApiClient.RemoveGuildBanAsync(guild.Id, userId, options).ConfigureAwait(false); await client.ApiClient.RemoveGuildBanAsync(guild.Id, userId, options).ConfigureAwait(false);
} }
#endregion


//Channels
#region Channels
public static async Task<RestGuildChannel> GetChannelAsync(IGuild guild, BaseDiscordClient client, public static async Task<RestGuildChannel> GetChannelAsync(IGuild guild, BaseDiscordClient client,
ulong id, RequestOptions options) ulong id, RequestOptions options)
{ {
@@ -275,16 +277,18 @@ namespace Discord.Rest
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false);
return RestCategoryChannel.Create(client, guild, model); return RestCategoryChannel.Create(client, guild, model);
} }
#endregion


//Voice Regions
#region Voice Regions
public static async Task<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(IGuild guild, BaseDiscordClient client, public static async Task<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(IGuild guild, BaseDiscordClient client,
RequestOptions options) RequestOptions options)
{ {
var models = await client.ApiClient.GetGuildVoiceRegionsAsync(guild.Id, options).ConfigureAwait(false); var models = await client.ApiClient.GetGuildVoiceRegionsAsync(guild.Id, options).ConfigureAwait(false);
return models.Select(x => RestVoiceRegion.Create(client, x)).ToImmutableArray(); return models.Select(x => RestVoiceRegion.Create(client, x)).ToImmutableArray();
} }
#endregion


//Integrations
#region Integrations
public static async Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(IGuild guild, BaseDiscordClient client, public static async Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(IGuild guild, BaseDiscordClient client,
RequestOptions options) RequestOptions options)
{ {
@@ -298,8 +302,9 @@ namespace Discord.Rest
var model = await client.ApiClient.CreateGuildIntegrationAsync(guild.Id, args, options).ConfigureAwait(false); var model = await client.ApiClient.CreateGuildIntegrationAsync(guild.Id, args, options).ConfigureAwait(false);
return RestGuildIntegration.Create(client, guild, model); return RestGuildIntegration.Create(client, guild, model);
} }
#endregion


//Interactions
#region Interactions
public static async Task<IReadOnlyCollection<RestGuildCommand>> GetSlashCommandsAsync(IGuild guild, BaseDiscordClient client, public static async Task<IReadOnlyCollection<RestGuildCommand>> GetSlashCommandsAsync(IGuild guild, BaseDiscordClient client,
RequestOptions options) RequestOptions options)
{ {
@@ -312,8 +317,9 @@ namespace Discord.Rest
var model = await client.ApiClient.GetGuildApplicationCommandAsync(guild.Id, id, options); var model = await client.ApiClient.GetGuildApplicationCommandAsync(guild.Id, id, options);
return RestGuildCommand.Create(client, model, guild.Id); return RestGuildCommand.Create(client, model, guild.Id);
} }
#endregion


//Invites
#region Invites
public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuild guild, BaseDiscordClient client, public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuild guild, BaseDiscordClient client,
RequestOptions options) RequestOptions options)
{ {
@@ -329,8 +335,9 @@ namespace Discord.Rest
inviteModel.Uses = vanityModel.Uses; inviteModel.Uses = vanityModel.Uses;
return RestInviteMetadata.Create(client, guild, null, inviteModel); return RestInviteMetadata.Create(client, guild, null, inviteModel);
} }
#endregion


//Roles
#region Roles
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c>.</exception>
public static async Task<RestRole> CreateRoleAsync(IGuild guild, BaseDiscordClient client, public static async Task<RestRole> CreateRoleAsync(IGuild guild, BaseDiscordClient client,
string name, GuildPermissions? permissions, Color? color, bool isHoisted, bool isMentionable, RequestOptions options) string name, GuildPermissions? permissions, Color? color, bool isHoisted, bool isMentionable, RequestOptions options)
@@ -350,8 +357,9 @@ namespace Discord.Rest


return RestRole.Create(client, guild, model); return RestRole.Create(client, guild, model);
} }
#endregion


//Users
#region Users
public static async Task<RestGuildUser> AddGuildUserAsync(IGuild guild, BaseDiscordClient client, ulong userId, string accessToken, public static async Task<RestGuildUser> AddGuildUserAsync(IGuild guild, BaseDiscordClient client, ulong userId, string accessToken,
Action<AddGuildUserProperties> func, RequestOptions options) Action<AddGuildUserProperties> func, RequestOptions options)
{ {
@@ -470,8 +478,9 @@ namespace Discord.Rest
var models = await client.ApiClient.SearchGuildMembersAsync(guild.Id, apiArgs, options).ConfigureAwait(false); var models = await client.ApiClient.SearchGuildMembersAsync(guild.Id, apiArgs, options).ConfigureAwait(false);
return models.Select(x => RestGuildUser.Create(client, guild, x)).ToImmutableArray(); return models.Select(x => RestGuildUser.Create(client, guild, x)).ToImmutableArray();
} }
#endregion


// Audit logs
#region Audit logs
public static IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(IGuild guild, BaseDiscordClient client, public static IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(IGuild guild, BaseDiscordClient client,
ulong? from, int? limit, RequestOptions options, ulong? userId = null, ActionType? actionType = null) ulong? from, int? limit, RequestOptions options, ulong? userId = null, ActionType? actionType = null)
{ {
@@ -503,8 +512,9 @@ namespace Discord.Rest
count: limit count: limit
); );
} }
#endregion


//Webhooks
#region Webhooks
public static async Task<RestWebhook> GetWebhookAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) public static async Task<RestWebhook> GetWebhookAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options)
{ {
var model = await client.ApiClient.GetWebhookAsync(id, options: options).ConfigureAwait(false); var model = await client.ApiClient.GetWebhookAsync(id, options: options).ConfigureAwait(false);
@@ -517,8 +527,9 @@ namespace Discord.Rest
var models = await client.ApiClient.GetGuildWebhooksAsync(guild.Id, options).ConfigureAwait(false); var models = await client.ApiClient.GetGuildWebhooksAsync(guild.Id, options).ConfigureAwait(false);
return models.Select(x => RestWebhook.Create(client, guild, x)).ToImmutableArray(); return models.Select(x => RestWebhook.Create(client, guild, x)).ToImmutableArray();
} }
#endregion


//Emotes
#region Emotes
public static async Task<IReadOnlyCollection<GuildEmote>> GetEmotesAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) public static async Task<IReadOnlyCollection<GuildEmote>> GetEmotesAsync(IGuild guild, BaseDiscordClient client, RequestOptions options)
{ {
var models = await client.ApiClient.GetGuildEmotesAsync(guild.Id, options).ConfigureAwait(false); var models = await client.ApiClient.GetGuildEmotesAsync(guild.Id, options).ConfigureAwait(false);
@@ -637,5 +648,6 @@ namespace Discord.Rest


public static async Task DeleteStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, RequestOptions options = null) public static async Task DeleteStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, RequestOptions options = null)
=> await client.ApiClient.DeleteStickerAsync(guildId, sticker.Id, options).ConfigureAwait(false); => await client.ApiClient.DeleteStickerAsync(guildId, sticker.Id, options).ConfigureAwait(false);
#endregion
} }
} }

+ 45
- 14
src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs View File

@@ -18,6 +18,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestGuild : RestEntity<ulong>, IGuild, IUpdateable public class RestGuild : RestEntity<ulong>, IGuild, IUpdateable
{ {
#region RestGuild
private ImmutableDictionary<ulong, RestRole> _roles; private ImmutableDictionary<ulong, RestRole> _roles;
private ImmutableArray<GuildEmote> _emotes; private ImmutableArray<GuildEmote> _emotes;
private ImmutableArray<CustomSticker> _stickers; private ImmutableArray<CustomSticker> _stickers;
@@ -217,8 +218,9 @@ namespace Discord.Rest
WidgetChannelId = model.ChannelId; WidgetChannelId = model.ChannelId;
IsWidgetEnabled = model.Enabled; IsWidgetEnabled = model.Enabled;
} }
#endregion


//General
#region General
/// <inheritdoc /> /// <inheritdoc />
public async Task UpdateAsync(RequestOptions options = null) public async Task UpdateAsync(RequestOptions options = null)
=> Update(await Discord.ApiClient.GetGuildAsync(Id, false, options).ConfigureAwait(false)); => Update(await Discord.ApiClient.GetGuildAsync(Id, false, options).ConfigureAwait(false));
@@ -277,8 +279,9 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
public Task LeaveAsync(RequestOptions options = null) public Task LeaveAsync(RequestOptions options = null)
=> GuildHelper.LeaveAsync(this, Discord, options); => GuildHelper.LeaveAsync(this, Discord, options);
#endregion


//Interactions
#region Interactions
/// <summary> /// <summary>
/// Deletes all slash commands in the current guild. /// Deletes all slash commands in the current guild.
/// </summary> /// </summary>
@@ -311,8 +314,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public Task<RestGuildCommand> GetSlashCommandAsync(ulong id, RequestOptions options = null) public Task<RestGuildCommand> GetSlashCommandAsync(ulong id, RequestOptions options = null)
=> GuildHelper.GetSlashCommandAsync(this, id, Discord, options); => GuildHelper.GetSlashCommandAsync(this, id, Discord, options);
#endregion


//Bans
#region Bans
/// <summary> /// <summary>
/// Gets a collection of all users banned in this guild. /// Gets a collection of all users banned in this guild.
/// </summary> /// </summary>
@@ -360,8 +364,9 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
public Task RemoveBanAsync(ulong userId, RequestOptions options = null) public Task RemoveBanAsync(ulong userId, RequestOptions options = null)
=> GuildHelper.RemoveBanAsync(this, Discord, userId, options); => GuildHelper.RemoveBanAsync(this, Discord, userId, options);
#endregion


//Channels
#region Channels
/// <summary> /// <summary>
/// Gets a collection of all channels in this guild. /// Gets a collection of all channels in this guild.
/// </summary> /// </summary>
@@ -697,14 +702,16 @@ namespace Discord.Rest
/// </returns> /// </returns>
public Task<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null) public Task<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null)
=> GuildHelper.GetVoiceRegionsAsync(this, Discord, options); => GuildHelper.GetVoiceRegionsAsync(this, Discord, options);
#endregion


//Integrations
#region Integrations
public Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(RequestOptions options = null) public Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(RequestOptions options = null)
=> GuildHelper.GetIntegrationsAsync(this, Discord, options); => GuildHelper.GetIntegrationsAsync(this, Discord, options);
public Task<RestGuildIntegration> CreateIntegrationAsync(ulong id, string type, RequestOptions options = null) public Task<RestGuildIntegration> CreateIntegrationAsync(ulong id, string type, RequestOptions options = null)
=> GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options); => GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options);
#endregion


//Invites
#region Invites
/// <summary> /// <summary>
/// Gets a collection of all invites in this guild. /// Gets a collection of all invites in this guild.
/// </summary> /// </summary>
@@ -724,8 +731,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public Task<RestInviteMetadata> GetVanityInviteAsync(RequestOptions options = null) public Task<RestInviteMetadata> GetVanityInviteAsync(RequestOptions options = null)
=> GuildHelper.GetVanityInviteAsync(this, Discord, options); => GuildHelper.GetVanityInviteAsync(this, Discord, options);
#endregion


//Roles
#region Roles
/// <summary> /// <summary>
/// Gets a role in this guild. /// Gets a role in this guild.
/// </summary> /// </summary>
@@ -765,8 +773,9 @@ namespace Discord.Rest
_roles = _roles.Add(role.Id, role); _roles = _roles.Add(role.Id, role);
return role; return role;
} }
#endregion


//Users
#region Users
/// <summary> /// <summary>
/// Gets a collection of all users in this guild. /// Gets a collection of all users in this guild.
/// </summary> /// </summary>
@@ -860,8 +869,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public Task<IReadOnlyCollection<RestGuildUser>> SearchUsersAsync(string query, int limit = DiscordConfig.MaxUsersPerBatch, RequestOptions options = null) public Task<IReadOnlyCollection<RestGuildUser>> SearchUsersAsync(string query, int limit = DiscordConfig.MaxUsersPerBatch, RequestOptions options = null)
=> GuildHelper.SearchUsersAsync(this, Discord, query, limit, options); => GuildHelper.SearchUsersAsync(this, Discord, query, limit, options);
#endregion


//Audit logs
#region Audit logs
/// <summary> /// <summary>
/// Gets the specified number of audit log entries for this guild. /// Gets the specified number of audit log entries for this guild.
/// </summary> /// </summary>
@@ -876,8 +886,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null) public IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null)
=> GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType); => GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType);
#endregion


//Webhooks
#region Webhooks
/// <summary> /// <summary>
/// Gets a webhook found within this guild. /// Gets a webhook found within this guild.
/// </summary> /// </summary>
@@ -900,8 +911,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null) public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null)
=> GuildHelper.GetWebhooksAsync(this, Discord, options); => GuildHelper.GetWebhooksAsync(this, Discord, options);
#endregion


//Interactions
#region Interactions
/// <summary> /// <summary>
/// Gets this guilds slash commands commands /// Gets this guilds slash commands commands
/// </summary> /// </summary>
@@ -961,8 +973,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public override string ToString() => Name; public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id})"; private string DebuggerDisplay => $"{Name} ({Id})";
#endregion


//Emotes
#region Emotes
/// <inheritdoc /> /// <inheritdoc />
public Task<IReadOnlyCollection<GuildEmote>> GetEmotesAsync(RequestOptions options = null) public Task<IReadOnlyCollection<GuildEmote>> GetEmotesAsync(RequestOptions options = null)
=> GuildHelper.GetEmotesAsync(this, Discord, options); => GuildHelper.GetEmotesAsync(this, Discord, options);
@@ -976,11 +989,20 @@ namespace Discord.Rest
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception>
public Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null) public Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null)
=> GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options); => GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options);
/// <summary>
/// Moves the user to the voice channel.
/// </summary>
/// <param name="user">The user to move.</param>
/// <param name="targetChannel">the channel where the user gets moved to.</param>
/// <returns>A task that represents the asynchronous operation for moving a user.</returns>
public Task MoveAsync(IGuildUser user, IVoiceChannel targetChannel)
=> user.ModifyAsync(x => x.Channel = new Optional<IVoiceChannel>(targetChannel));
/// <inheritdoc /> /// <inheritdoc />
public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null)
=> GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); => GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options);
#endregion


//Stickers
#region Stickers
/// <summary> /// <summary>
/// Creates a new sticker in this guild. /// Creates a new sticker in this guild.
/// </summary> /// </summary>
@@ -1087,8 +1109,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public Task DeleteStickerAsync(CustomSticker sticker, RequestOptions options = null) public Task DeleteStickerAsync(CustomSticker sticker, RequestOptions options = null)
=> sticker.DeleteAsync(options); => sticker.DeleteAsync(options);
#endregion


//IGuild
#region IGuild
/// <inheritdoc /> /// <inheritdoc />
bool IGuild.Available => Available; bool IGuild.Available => Available;
/// <inheritdoc /> /// <inheritdoc />
@@ -1291,6 +1314,13 @@ namespace Discord.Rest
async Task<IGuildUser> IGuild.AddGuildUserAsync(ulong userId, string accessToken, Action<AddGuildUserProperties> func, RequestOptions options) async Task<IGuildUser> IGuild.AddGuildUserAsync(ulong userId, string accessToken, Action<AddGuildUserProperties> func, RequestOptions options)
=> await AddGuildUserAsync(userId, accessToken, func, options); => await AddGuildUserAsync(userId, accessToken, func, options);


/// <summary>
/// Disconnects the user from its current voice channel
/// </summary>
/// <param name="user">The user to disconnect.</param>
/// <returns>A task that represents the asynchronous operation for disconnecting a user.</returns>
async Task IGuild.DisconnectAsync(IGuildUser user) => await user.ModifyAsync(x => x.Channel = new Optional<IVoiceChannel>());

/// <inheritdoc /> /// <inheritdoc />
async Task<IGuildUser> IGuild.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) async Task<IGuildUser> IGuild.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
{ {
@@ -1399,5 +1429,6 @@ namespace Discord.Rest
else else
return null; return null;
} }
#endregion
} }
} }

+ 10
- 4
src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs View File

@@ -11,6 +11,7 @@ namespace Discord.Rest
{ {
internal static class InteractionHelper internal static class InteractionHelper
{ {
#region InteractionHelper
public static Task DeleteAllGuildCommandsAsync(BaseDiscordClient client, ulong guildId, RequestOptions options = null) public static Task DeleteAllGuildCommandsAsync(BaseDiscordClient client, ulong guildId, RequestOptions options = null)
{ {
return client.ApiClient.BulkOverwriteGuildApplicationCommands(guildId, new CreateApplicationCommandParams[0], options); return client.ApiClient.BulkOverwriteGuildApplicationCommands(guildId, new CreateApplicationCommandParams[0], options);
@@ -42,8 +43,9 @@ namespace Discord.Rest
RestFollowupMessage entity = RestFollowupMessage.Create(client, model, token, channel); RestFollowupMessage entity = RestFollowupMessage.Create(client, model, token, channel);
return entity; return entity;
} }
#endregion


// Global commands
#region Global commands
public static async Task<RestGlobalCommand> GetGlobalCommandAsync(BaseDiscordClient client, ulong id, public static async Task<RestGlobalCommand> GetGlobalCommandAsync(BaseDiscordClient client, ulong id,
RequestOptions options = null) RequestOptions options = null)
{ {
@@ -236,8 +238,9 @@ namespace Discord.Rest


await client.ApiClient.DeleteGlobalApplicationCommandAsync(command.Id, options).ConfigureAwait(false); await client.ApiClient.DeleteGlobalApplicationCommandAsync(command.Id, options).ConfigureAwait(false);
} }
#endregion


// Guild Commands
#region Guild Commands
public static Task<ApplicationCommand> CreateGuildCommand<TArg>(BaseDiscordClient client, ulong guildId, public static Task<ApplicationCommand> CreateGuildCommand<TArg>(BaseDiscordClient client, ulong guildId,
Action<TArg> func, RequestOptions options) where TArg : ApplicationCommandProperties Action<TArg> func, RequestOptions options) where TArg : ApplicationCommandProperties
{ {
@@ -324,8 +327,9 @@ namespace Discord.Rest
return DeleteGlobalCommand(client, command, options); return DeleteGlobalCommand(client, command, options);
} }
} }
#endregion


// Responses
#region Responses
public static async Task<Discord.API.Message> ModifyFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, Action<MessageProperties> func, public static async Task<Discord.API.Message> ModifyFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, Action<MessageProperties> func,
RequestOptions options = null) RequestOptions options = null)
{ {
@@ -412,8 +416,9 @@ namespace Discord.Rest


public static async Task DeletedInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null) public static async Task DeletedInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null)
=> await client.ApiClient.DeleteInteractionFollowupMessage(message.Id, message.Token, options); => await client.ApiClient.DeleteInteractionFollowupMessage(message.Id, message.Token, options);
#endregion


// Guild permissions
#region Guild permissions
public static async Task<IReadOnlyCollection<GuildApplicationCommandPermission>> GetGuildCommandPermissionsAsync(BaseDiscordClient client, public static async Task<IReadOnlyCollection<GuildApplicationCommandPermission>> GetGuildCommandPermissionsAsync(BaseDiscordClient client,
ulong guildId, RequestOptions options) ulong guildId, RequestOptions options)
{ {
@@ -506,5 +511,6 @@ namespace Discord.Rest
x => new GuildApplicationCommandPermission(x.Id, x.ApplicationId, x.GuildId, x.Permissions.Select( x => new GuildApplicationCommandPermission(x.Id, x.ApplicationId, x.GuildId, x.Permissions.Select(
y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray())).ToArray(); y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray())).ToArray();
} }
#endregion
} }
} }

+ 4
- 1
src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs View File

@@ -13,6 +13,7 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class RestApplicationCommandOption : IApplicationCommandOption public class RestApplicationCommandOption : IApplicationCommandOption
{ {
#region RestApplicationCommandOption
/// <inheritdoc/> /// <inheritdoc/>
public ApplicationCommandOptionType Type { get; private set; } public ApplicationCommandOptionType Type { get; private set; }


@@ -67,11 +68,13 @@ namespace Discord.Rest
? model.Choices.Value.Select(x => new RestApplicationCommandChoice(x)).ToImmutableArray() ? model.Choices.Value.Select(x => new RestApplicationCommandChoice(x)).ToImmutableArray()
: null; : null;
} }
#endregion


//IApplicationCommandOption
#region IApplicationCommandOption
IReadOnlyCollection<IApplicationCommandOption> IApplicationCommandOption.Options IReadOnlyCollection<IApplicationCommandOption> IApplicationCommandOption.Options
=> Options; => Options;
IReadOnlyCollection<IApplicationCommandOptionChoice> IApplicationCommandOption.Choices IReadOnlyCollection<IApplicationCommandOptionChoice> IApplicationCommandOption.Choices
=> Choices; => Choices;
#endregion
} }
} }

+ 4
- 2
src/Discord.Net.Rest/Entities/Roles/RestRole.cs View File

@@ -11,6 +11,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestRole : RestEntity<ulong>, IRole public class RestRole : RestEntity<ulong>, IRole
{ {
#region RestRole
internal IGuild Guild { get; } internal IGuild Guild { get; }
/// <inheritdoc /> /// <inheritdoc />
public Color Color { get; private set; } public Color Color { get; private set; }
@@ -64,7 +65,7 @@ namespace Discord.Rest


/// <inheritdoc /> /// <inheritdoc />
public async Task ModifyAsync(Action<RoleProperties> func, RequestOptions options = null) public async Task ModifyAsync(Action<RoleProperties> func, RequestOptions options = null)
{
{
var model = await RoleHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false); var model = await RoleHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false);
Update(model); Update(model);
} }
@@ -83,8 +84,9 @@ namespace Discord.Rest
/// </returns> /// </returns>
public override string ToString() => Name; public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id})"; private string DebuggerDisplay => $"{Name} ({Id})";
#endregion


//IRole
#region IRole
/// <inheritdoc /> /// <inheritdoc />
IGuild IRole.Guild IGuild IRole.Guild
{ {


+ 2
- 1
src/Discord.Net.Rest/Entities/Roles/RoleHelper.cs View File

@@ -7,7 +7,7 @@ namespace Discord.Rest
{ {
internal static class RoleHelper internal static class RoleHelper
{ {
//General
#region General
public static async Task DeleteAsync(IRole role, BaseDiscordClient client, public static async Task DeleteAsync(IRole role, BaseDiscordClient client,
RequestOptions options) RequestOptions options)
{ {
@@ -36,5 +36,6 @@ namespace Discord.Rest
} }
return model; return model;
} }
#endregion
} }
} }

+ 6
- 2
src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs View File

@@ -14,6 +14,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestGuildUser : RestUser, IGuildUser public class RestGuildUser : RestUser, IGuildUser
{ {
#region RestGuildUser
private long? _premiumSinceTicks; private long? _premiumSinceTicks;
private long? _joinedAtTicks; private long? _joinedAtTicks;
private ImmutableArray<ulong> _roleIds; private ImmutableArray<ulong> _roleIds;
@@ -155,8 +156,9 @@ namespace Discord.Rest
var guildPerms = GuildPermissions; var guildPerms = GuildPermissions;
return new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, guildPerms.RawValue)); return new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, guildPerms.RawValue));
} }
#endregion


//IGuildUser
#region IGuildUser
/// <inheritdoc /> /// <inheritdoc />
IGuild IGuildUser.Guild IGuild IGuildUser.Guild
{ {
@@ -167,8 +169,9 @@ namespace Discord.Rest
throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object.");
} }
} }
#endregion


//IVoiceState
#region IVoiceState
/// <inheritdoc /> /// <inheritdoc />
bool IVoiceState.IsSelfDeafened => false; bool IVoiceState.IsSelfDeafened => false;
/// <inheritdoc /> /// <inheritdoc />
@@ -183,5 +186,6 @@ namespace Discord.Rest
bool IVoiceState.IsStreaming => false; bool IVoiceState.IsStreaming => false;
/// <inheritdoc /> /// <inheritdoc />
DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null;
#endregion
} }
} }

+ 4
- 1
src/Discord.Net.Rest/Entities/Users/RestUser.cs View File

@@ -13,6 +13,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestUser : RestEntity<ulong>, IUser, IUpdateable public class RestUser : RestEntity<ulong>, IUser, IUpdateable
{ {
#region RestUser
/// <inheritdoc /> /// <inheritdoc />
public bool IsBot { get; private set; } public bool IsBot { get; private set; }
/// <inheritdoc /> /// <inheritdoc />
@@ -116,10 +117,12 @@ namespace Discord.Rest
/// </returns> /// </returns>
public override string ToString() => $"{Username}#{Discriminator}"; public override string ToString() => $"{Username}#{Discriminator}";
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})";
#endregion


//IUser
#region IUser
/// <inheritdoc /> /// <inheritdoc />
async Task<IDMChannel> IUser.CreateDMChannelAsync(RequestOptions options) async Task<IDMChannel> IUser.CreateDMChannelAsync(RequestOptions options)
=> await CreateDMChannelAsync(options).ConfigureAwait(false); => await CreateDMChannelAsync(options).ConfigureAwait(false);
#endregion
} }
} }

+ 6
- 2
src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs View File

@@ -10,6 +10,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestWebhookUser : RestUser, IWebhookUser public class RestWebhookUser : RestUser, IWebhookUser
{ {
#region RestWebhookUser
/// <inheritdoc /> /// <inheritdoc />
public ulong WebhookId { get; } public ulong WebhookId { get; }
internal IGuild Guild { get; } internal IGuild Guild { get; }
@@ -33,8 +34,9 @@ namespace Discord.Rest
entity.Update(model); entity.Update(model);
return entity; return entity;
} }
#endregion


//IGuildUser
#region IGuildUser
/// <inheritdoc /> /// <inheritdoc />
IGuild IGuildUser.Guild IGuild IGuildUser.Guild
{ {
@@ -91,8 +93,9 @@ namespace Discord.Rest
/// <inheritdoc /> /// <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."); throw new NotSupportedException("Roles are not supported on webhook users.");
#endregion


//IVoiceState
#region IVoiceState
/// <inheritdoc /> /// <inheritdoc />
bool IVoiceState.IsDeafened => false; bool IVoiceState.IsDeafened => false;
/// <inheritdoc /> /// <inheritdoc />
@@ -111,5 +114,6 @@ namespace Discord.Rest
bool IVoiceState.IsStreaming => false; bool IVoiceState.IsStreaming => false;
/// <inheritdoc /> /// <inheritdoc />
DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null;
#endregion
} }
} }

+ 4
- 1
src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs View File

@@ -8,6 +8,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestWebhook : RestEntity<ulong>, IWebhook, IUpdateable public class RestWebhook : RestEntity<ulong>, IWebhook, IUpdateable
{ {
#region RestWebhook
internal IGuild Guild { get; private set; } internal IGuild Guild { get; private set; }
internal ITextChannel Channel { get; private set; } internal ITextChannel Channel { get; private set; }


@@ -95,8 +96,9 @@ namespace Discord.Rest


public override string ToString() => $"Webhook: {Name}:{Id}"; public override string ToString() => $"Webhook: {Name}:{Id}";
private string DebuggerDisplay => $"Webhook: {Name} ({Id})"; private string DebuggerDisplay => $"Webhook: {Name} ({Id})";
#endregion


//IWebhook
#region IWebhook
/// <inheritdoc /> /// <inheritdoc />
IGuild IWebhook.Guild IGuild IWebhook.Guild
=> Guild ?? throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); => Guild ?? throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object.");
@@ -106,5 +108,6 @@ namespace Discord.Rest
/// <inheritdoc /> /// <inheritdoc />
Task IWebhook.ModifyAsync(Action<WebhookProperties> func, RequestOptions options) Task IWebhook.ModifyAsync(Action<WebhookProperties> func, RequestOptions options)
=> ModifyAsync(func, options); => ModifyAsync(func, options);
#endregion
} }
} }

+ 4
- 1
src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs View File

@@ -10,6 +10,7 @@ namespace Discord.Net.Converters
{ {
internal class DiscordContractResolver : DefaultContractResolver internal class DiscordContractResolver : DefaultContractResolver
{ {
#region DiscordContractResolver
private static readonly TypeInfo _ienumerable = typeof(IEnumerable<ulong[]>).GetTypeInfo(); private static readonly TypeInfo _ienumerable = typeof(IEnumerable<ulong[]>).GetTypeInfo();
private static readonly MethodInfo _shouldSerialize = typeof(DiscordContractResolver).GetTypeInfo().GetDeclaredMethod("ShouldSerialize"); private static readonly MethodInfo _shouldSerialize = typeof(DiscordContractResolver).GetTypeInfo().GetDeclaredMethod("ShouldSerialize");
@@ -57,8 +58,9 @@ namespace Discord.Net.Converters
else if (genericType == typeof(EntityOrId<>)) else if (genericType == typeof(EntityOrId<>))
return MakeGenericConverter(property, propInfo, typeof(UInt64EntityOrIdConverter<>), type.GenericTypeArguments[0], depth); return MakeGenericConverter(property, propInfo, typeof(UInt64EntityOrIdConverter<>), type.GenericTypeArguments[0], depth);
} }
#endregion


//Primitives
#region Primitives
bool hasInt53 = propInfo.GetCustomAttribute<Int53Attribute>() != null; bool hasInt53 = propInfo.GetCustomAttribute<Int53Attribute>() != null;
if (!hasInt53) if (!hasInt53)
{ {
@@ -107,5 +109,6 @@ namespace Discord.Net.Converters
var innerConverter = GetConverter(property, propInfo, innerType, depth + 1); var innerConverter = GetConverter(property, propInfo, innerType, depth + 1);
return genericType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter; return genericType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter;
} }
#endregion
} }
} }

+ 40
- 14
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -572,7 +572,7 @@ namespace Discord.WebSocket
_emotes = emotes.ToImmutable(); _emotes = emotes.ToImmutable();
} }


//General
#region General
/// <inheritdoc /> /// <inheritdoc />
public Task DeleteAsync(RequestOptions options = null) public Task DeleteAsync(RequestOptions options = null)
=> GuildHelper.DeleteAsync(this, Discord, options); => GuildHelper.DeleteAsync(this, Discord, options);
@@ -596,8 +596,9 @@ namespace Discord.WebSocket
/// <inheritdoc /> /// <inheritdoc />
public Task LeaveAsync(RequestOptions options = null) public Task LeaveAsync(RequestOptions options = null)
=> GuildHelper.LeaveAsync(this, Discord, options); => GuildHelper.LeaveAsync(this, Discord, options);
#endregion


//Bans
#region Bans
/// <summary> /// <summary>
/// Gets a collection of all users banned in this guild. /// Gets a collection of all users banned in this guild.
/// </summary> /// </summary>
@@ -645,8 +646,9 @@ namespace Discord.WebSocket
/// <inheritdoc /> /// <inheritdoc />
public Task RemoveBanAsync(ulong userId, RequestOptions options = null) public Task RemoveBanAsync(ulong userId, RequestOptions options = null)
=> GuildHelper.RemoveBanAsync(this, Discord, userId, options); => GuildHelper.RemoveBanAsync(this, Discord, userId, options);
#endregion


//Channels
#region Channels
/// <summary> /// <summary>
/// Gets a channel in this guild. /// Gets a channel in this guild.
/// </summary> /// </summary>
@@ -807,8 +809,9 @@ namespace Discord.WebSocket


_channels.Clear(); _channels.Clear();
} }
#endregion


//Voice Regions
#region Voice Regions
/// <summary> /// <summary>
/// Gets a collection of all the voice regions this guild can access. /// Gets a collection of all the voice regions this guild can access.
/// </summary> /// </summary>
@@ -819,14 +822,16 @@ namespace Discord.WebSocket
/// </returns> /// </returns>
public Task<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null) public Task<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null)
=> GuildHelper.GetVoiceRegionsAsync(this, Discord, options); => GuildHelper.GetVoiceRegionsAsync(this, Discord, options);
#endregion


//Integrations
#region Integrations
public Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(RequestOptions options = null) public Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(RequestOptions options = null)
=> GuildHelper.GetIntegrationsAsync(this, Discord, options); => GuildHelper.GetIntegrationsAsync(this, Discord, options);
public Task<RestGuildIntegration> CreateIntegrationAsync(ulong id, string type, RequestOptions options = null) public Task<RestGuildIntegration> CreateIntegrationAsync(ulong id, string type, RequestOptions options = null)
=> GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options); => GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options);
#endregion


//Interactions
#region Interactions
/// <summary> /// <summary>
/// Deletes all application commands in the current guild. /// Deletes all application commands in the current guild.
/// </summary> /// </summary>
@@ -932,8 +937,9 @@ namespace Discord.WebSocket


return entities.ToImmutableArray(); return entities.ToImmutableArray();
} }
#endregion


//Invites
#region Invites
/// <summary> /// <summary>
/// Gets a collection of all invites in this guild. /// Gets a collection of all invites in this guild.
/// </summary> /// </summary>
@@ -1040,8 +1046,9 @@ namespace Discord.WebSocket
return sticker; return sticker;
return null; return null;
} }
#endregion


//Users
#region Users
/// <inheritdoc /> /// <inheritdoc />
public Task<RestGuildUser> AddGuildUserAsync(ulong id, string accessToken, Action<AddGuildUserProperties> func = null, RequestOptions options = null) public Task<RestGuildUser> AddGuildUserAsync(ulong id, string accessToken, Action<AddGuildUserProperties> func = null, RequestOptions options = null)
=> GuildHelper.AddGuildUserAsync(this, Discord, id, accessToken, func, options); => GuildHelper.AddGuildUserAsync(this, Discord, id, accessToken, func, options);
@@ -1240,7 +1247,24 @@ namespace Discord.WebSocket
public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null)
=> GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); => GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options);


//Stickers
/// <summary>
/// Moves the user to the voice channel.
/// </summary>
/// <param name="user">The user to move.</param>
/// <param name="targetChannel">the channel where the user gets moved to.</param>
/// <returns>A task that represents the asynchronous operation for moving a user.</returns>
public Task MoveAsync(IGuildUser user, IVoiceChannel targetChannel)
=> user.ModifyAsync(x => x.Channel = new Optional<IVoiceChannel>(targetChannel));

/// <summary>
/// Disconnects the user from its current voice channel
/// </summary>
/// <param name="user">The user to disconnect.</param>
/// <returns>A task that represents the asynchronous operation for disconnecting a user.</returns>
async Task IGuild.DisconnectAsync(IGuildUser user) => await user.ModifyAsync(x => x.Channel = new Optional<IVoiceChannel>());
#endregion

#region Stickers
/// <summary> /// <summary>
/// Gets a specific sticker within this guild. /// Gets a specific sticker within this guild.
/// </summary> /// </summary>
@@ -1368,8 +1392,9 @@ namespace Discord.WebSocket
/// </returns> /// </returns>
public Task DeleteStickerAsync(SocketCustomSticker sticker, RequestOptions options = null) public Task DeleteStickerAsync(SocketCustomSticker sticker, RequestOptions options = null)
=> sticker.DeleteAsync(options); => sticker.DeleteAsync(options);
#endregion


//Voice States
#region Voice States
internal async Task<SocketVoiceState> AddOrUpdateVoiceStateAsync(ClientState state, VoiceStateModel model) internal async Task<SocketVoiceState> AddOrUpdateVoiceStateAsync(ClientState state, VoiceStateModel model)
{ {
var voiceChannel = state.GetChannel(model.ChannelId.Value) as SocketVoiceChannel; var voiceChannel = state.GetChannel(model.ChannelId.Value) as SocketVoiceChannel;
@@ -1413,8 +1438,9 @@ namespace Discord.WebSocket
} }
return null; return null;
} }
#endregion


//Audio
#region Audio
internal AudioInStream GetAudioStream(ulong userId) internal AudioInStream GetAudioStream(ulong userId)
{ {
return _audioClient?.GetInputStream(userId); return _audioClient?.GetInputStream(userId);
@@ -1568,8 +1594,9 @@ namespace Discord.WebSocket
public override string ToString() => Name; public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id})"; private string DebuggerDisplay => $"{Name} ({Id})";
internal SocketGuild Clone() => MemberwiseClone() as SocketGuild; internal SocketGuild Clone() => MemberwiseClone() as SocketGuild;
#endregion


//IGuild
#region IGuild
/// <inheritdoc /> /// <inheritdoc />
ulong? IGuild.AFKChannelId => AFKChannelId; ulong? IGuild.AFKChannelId => AFKChannelId;
/// <inheritdoc /> /// <inheritdoc />
@@ -1781,7 +1808,6 @@ namespace Discord.WebSocket
_audioLock?.Dispose(); _audioLock?.Dispose();
_audioClient?.Dispose(); _audioClient?.Dispose();
} }

#endregion
} }
} }

Loading…
Cancel
Save