Browse Source

Merge branch 'dev' into feature/automod

pull/2578/head
Misha133 GitHub 2 years ago
parent
commit
d07fc5ac53
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 7569 additions and 6191 deletions
  1. +68
    -0
      docs/guides/bearer_token/bearer_token_guide.md
  2. +11
    -0
      docs/guides/bearer_token/samples/app_role_connection.cs
  3. +5
    -0
      docs/guides/bearer_token/samples/current_user.cs
  4. +2
    -0
      docs/guides/bearer_token/samples/current_user_connections.cs
  5. +6
    -0
      docs/guides/bearer_token/samples/current_user_guild_member.cs
  6. +2
    -0
      docs/guides/bearer_token/samples/current_user_guilds.cs
  7. +5
    -0
      docs/guides/bearer_token/samples/rest_client_init.cs
  8. +2
    -2
      docs/guides/int_framework/samples/intro/context.cs
  9. +2
    -0
      docs/guides/toc.yml
  10. +6
    -6
      experiment/Discord.Net.BuildOverrides/BuildOverrides.cs
  11. +4
    -3
      samples/BasicBot/Program.cs
  12. +2
    -1
      samples/InteractionFramework/Attributes/DoUserCheckAttribute.cs
  13. +1
    -1
      samples/InteractionFramework/Attributes/RequireOwnerAttribute.cs
  14. +1
    -1
      samples/InteractionFramework/Modules/ExampleModule.cs
  15. +5
    -5
      samples/InteractionFramework/Program.cs
  16. +4
    -4
      src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs
  17. +2
    -2
      src/Discord.Net.Analyzers/SymbolExtensions.cs
  18. +2
    -2
      src/Discord.Net.Commands/Attributes/OverrideTypeReaderAttribute.cs
  19. +1
    -1
      src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs
  20. +1
    -1
      src/Discord.Net.Commands/Builders/CommandBuilder.cs
  21. +3
    -1
      src/Discord.Net.Commands/Builders/ModuleBuilder.cs
  22. +8
    -9
      src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs
  23. +2
    -3
      src/Discord.Net.Commands/Builders/ParameterBuilder.cs
  24. +4
    -4
      src/Discord.Net.Commands/CommandService.cs
  25. +1
    -1
      src/Discord.Net.Commands/CommandServiceConfig.cs
  26. +1
    -1
      src/Discord.Net.Commands/EmptyServiceProvider.cs
  27. +1
    -1
      src/Discord.Net.Commands/Extensions/IEnumerableExtensions.cs
  28. +8
    -4
      src/Discord.Net.Commands/Extensions/MessageExtensions.cs
  29. +2
    -2
      src/Discord.Net.Commands/Info/CommandInfo.cs
  30. +2
    -2
      src/Discord.Net.Commands/Info/ModuleInfo.cs
  31. +1
    -1
      src/Discord.Net.Commands/ModuleBase.cs
  32. +2
    -2
      src/Discord.Net.Commands/Readers/EnumTypeReader.cs
  33. +1
    -1
      src/Discord.Net.Commands/Readers/NamedArgumentTypeReader.cs
  34. +1
    -1
      src/Discord.Net.Commands/Readers/RoleTypeReader.cs
  35. +1
    -1
      src/Discord.Net.Commands/Readers/UserTypeReader.cs
  36. +3
    -3
      src/Discord.Net.Commands/Results/MatchResult.cs
  37. +1
    -1
      src/Discord.Net.Commands/Utilities/ReflectionUtils.cs
  38. +1
    -1
      src/Discord.Net.Core/Audio/AudioApplication.cs
  39. +2
    -2
      src/Discord.Net.Core/Audio/AudioInStream.cs
  40. +2
    -2
      src/Discord.Net.Core/Audio/AudioStream.cs
  41. +1
    -1
      src/Discord.Net.Core/Audio/RTPFrame.cs
  42. +5
    -5
      src/Discord.Net.Core/CDN.cs
  43. +1
    -1
      src/Discord.Net.Core/Discord.Net.Core.csproj
  44. +25
    -17
      src/Discord.Net.Core/DiscordConfig.cs
  45. +1
    -1
      src/Discord.Net.Core/Entities/Activities/Game.cs
  46. +1
    -1
      src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadataProperties.cs
  47. +3
    -3
      src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionProperties.cs
  48. +1
    -1
      src/Discord.Net.Core/Entities/Channels/AudioChannelProperties.cs
  49. +5
    -2
      src/Discord.Net.Core/Entities/Channels/IForumChannel.cs
  50. +44
    -0
      src/Discord.Net.Core/Entities/Channels/IIntegrationChannel.cs
  51. +3
    -3
      src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs
  52. +9
    -0
      src/Discord.Net.Core/Entities/Channels/INewsChannel.cs
  53. +1
    -32
      src/Discord.Net.Core/Entities/Channels/ITextChannel.cs
  54. +5
    -0
      src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs
  55. +17
    -0
      src/Discord.Net.Core/Entities/Channels/VideoQualityMode.cs
  56. +5
    -0
      src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs
  57. +6979
    -5862
      src/Discord.Net.Core/Entities/Emotes/Emoji.cs
  58. +7
    -4
      src/Discord.Net.Core/Entities/Emotes/Emote.cs
  59. +1
    -1
      src/Discord.Net.Core/Entities/ForumTags/ForumTag.cs
  60. +4
    -4
      src/Discord.Net.Core/Entities/ForumTags/ForumTagBuilder.cs
  61. +8
    -0
      src/Discord.Net.Core/Entities/Guilds/IUserGuild.cs
  62. +1
    -1
      src/Discord.Net.Core/Entities/Guilds/NsfwLevel.cs
  63. +1
    -1
      src/Discord.Net.Core/Entities/Guilds/WelcomeScreenChannelProperties.cs
  64. +1
    -1
      src/Discord.Net.Core/Entities/IApplication.cs
  65. +1
    -1
      src/Discord.Net.Core/Entities/Integrations/IIntegration.cs
  66. +2
    -2
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs
  67. +1
    -1
      src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs
  68. +3
    -3
      src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandBuilder.cs
  69. +3
    -3
      src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandBuilder.cs
  70. +2
    -2
      src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs
  71. +1
    -1
      src/Discord.Net.Core/Entities/Interactions/MessageComponents/TextInputComponent.cs
  72. +1
    -1
      src/Discord.Net.Core/Entities/Interactions/MessageComponents/TextInputStyle.cs
  73. +3
    -3
      src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs
  74. +13
    -13
      src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs
  75. +12
    -12
      src/Discord.Net.Core/Entities/Invites/InviteGuild.cs
  76. +4
    -4
      src/Discord.Net.Core/Entities/Messages/AllowedMentionTypes.cs
  77. +6
    -6
      src/Discord.Net.Core/Entities/Messages/Embed.cs
  78. +23
    -13
      src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs
  79. +10
    -2
      src/Discord.Net.Core/Entities/Messages/IMessage.cs
  80. +1
    -1
      src/Discord.Net.Core/Entities/Messages/ITag.cs
  81. +9
    -1
      src/Discord.Net.Core/Entities/Messages/MessageFlags.cs
  82. +1
    -1
      src/Discord.Net.Core/Entities/Messages/Tag.cs
  83. +5
    -1
      src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs
  84. +56
    -0
      src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs
  85. +25
    -25
      src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
  86. +41
    -41
      src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
  87. +1
    -1
      src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
  88. +16
    -15
      src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs
  89. +5
    -0
      src/Discord.Net.Core/Entities/Users/IThreadUser.cs
  90. +1
    -1
      src/Discord.Net.Core/Entities/Users/IUser.cs
  91. +1
    -1
      src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs
  92. +1
    -1
      src/Discord.Net.Core/Extensions/TaskCompletionSourceExtensions.cs
  93. +1
    -1
      src/Discord.Net.Core/Extensions/UserExtensions.cs
  94. +1
    -1
      src/Discord.Net.Core/Format.cs
  95. +1
    -1
      src/Discord.Net.Core/Logging/LogManager.cs
  96. +5
    -14
      src/Discord.Net.Core/Logging/LogMessage.cs
  97. +1
    -1
      src/Discord.Net.Core/Net/ApplicationCommandException.cs
  98. +2
    -2
      src/Discord.Net.Core/Net/BucketId.cs
  99. +1
    -1
      src/Discord.Net.Core/Net/Rest/RestClientProvider.cs
  100. +1
    -1
      src/Discord.Net.Core/Net/Rest/RestResponse.cs

+ 68
- 0
docs/guides/bearer_token/bearer_token_guide.md View File

@@ -0,0 +1,68 @@
---
uid: Guides.BearerToken
title: Working with Bearer token
---

# Working with Bearer token

Some endpoints in Discord API require a Bearer token, which can be obtained through [OAuth2 flow](https://discord.com/developers/docs/topics/oauth2). Discord.Net allows you to interact with these endpoints using the [DiscordRestClient].

## Initializing a new instance of the client
[!code-csharp[Initialize DiscordRestClient](samples/rest_client_init.cs)]

## Getting current user

The [DiscordRestClient] gets the current user when `LoginAsync()` is called. The user object can be found in the `CurrentUser` property.

If you need to fetch the user again, the `GetCurrentUserAsync()` method can be used.

[!code-csharp[Get current user](samples/current_user.cs)]

> [!NOTE]
> Some properties might be `null` depending on which scopes users authorized your app with.
> For example: `email` scope is required to fetch current user's email address.

## Fetching current user's guilds

The `GetGuildSummariesAsync()` method is used to fetch current user's guilds. Since it returns an `IAsyncEnumerable` you need to call `FlattenAsync()` to get a plain `IEnumerable` containing [RestUserGuild] objects.

[!code-csharp[Get current user's guilds](samples/current_user_guilds.cs)]

> [!WARNING]
> This method requires `guilds` scope

## Fetching current user's guild member object

To fetch the current user's guild member object, the `GetCurrentUserGuildMemberAsync()` method can be used.

[!code-csharp[Get current user's guild member](samples/current_user_guild_member.cs)]

> [!WARNING]
> This method requires `guilds.members.read` scope

## Get user connections

The `GetConnectionsAsync` method can be used to fetch current user's connections to other platforms.

[!code-csharp[Get current user's connections](samples/current_user_connections.cs)]

> [!WARNING]
> This method requires `connections` scope

## Application role connection

In addition to previous features, Discord.Net supports fetching & updating user's application role connection metadata values. `GetUserApplicationRoleConnectionAsync()` returns a [RoleConnection] object of the current user for the given application id.

The `ModifyUserApplicationRoleConnectionAsync()` method is used to update current user's role connection metadata values. A new set of values can be created with [RoleConnectionProperties] object.

[!code-csharp[Get current user's connections](samples/app_role_connection.cs)]

> [!WARNING]
> This method requires `role_connections.write` scope



[DiscordRestClient]: xref:Discord.Rest.DiscordRestClient
[RestUserGuild]: xref:Discord.Rest.RestUserGuild
[RoleConnection]: xref:Discord.RoleConnection
[RoleConnectionProperties]: xref:Discord.RoleConnectionProperties

+ 11
- 0
docs/guides/bearer_token/samples/app_role_connection.cs View File

@@ -0,0 +1,11 @@
// fetch application role connection of the current user for the app with provided id.
var roleConnection = await client.GetUserApplicationRoleConnectionAsync(applicationid);

// create a new role connection metadata properties object & set some values.
var properties = new RoleConnectionProperties("Discord.Net Docs", "Cool Coding Guy")
.WithNumber("eaten_cookies", 69)
.WithBool("loves_cookies", true)
.WithDate("last_eaten_cookie", DateTimeOffset.UtcNow);

// update current user's values with the given properties.
await client.ModifyUserApplicationRoleConnectionAsync(applicationId, properties);

+ 5
- 0
docs/guides/bearer_token/samples/current_user.cs View File

@@ -0,0 +1,5 @@
// gets the user object stored in the DiscordRestClient.
var user = client.CurrentUser;

// fetches the current user with a REST call & updates the CurrentUser property.
var refreshedUser = await client.GetCurrentUserAsync();

+ 2
- 0
docs/guides/bearer_token/samples/current_user_connections.cs View File

@@ -0,0 +1,2 @@
// fetches the current user's connections.
var connections = await client.GetConnectionsAsync();

+ 6
- 0
docs/guides/bearer_token/samples/current_user_guild_member.cs View File

@@ -0,0 +1,6 @@
// fetches the current user's guild member object in a guild with provided id.
var member = await client.GetCurrentUserGuildMemberAsync(guildId);

// fetches the current user's guild member object in a RestUserGuild.
var guild = await client.GetGuildSummariesAsync().FlattenAsync().First();
var member = await guild.GetCurrentUserGuildMemberAsync();

+ 2
- 0
docs/guides/bearer_token/samples/current_user_guilds.cs View File

@@ -0,0 +1,2 @@
// fetches the guilds the current user participate in.
var guilds = await client.GetGuildSummariesAsync().FlattenAsync();

+ 5
- 0
docs/guides/bearer_token/samples/rest_client_init.cs View File

@@ -0,0 +1,5 @@
using Discord;
using Discord.Rest;

await using var client = new DiscordRestClient();
await client.LoginAsync(TokenType.Bearer, "bearer token obtained through oauth2 flow");

+ 2
- 2
docs/guides/int_framework/samples/intro/context.cs View File

@@ -7,8 +7,8 @@ discordClient.ButtonExecuted += async (interaction) =>
public class MessageComponentModule : InteractionModuleBase<SocketInteractionContext<SocketMessageComponent>>
{
[ComponentInteraction("custom_id")]
public async Command()
public async Task Command()
{
Context.Interaction.UpdateAsync(...);
await Context.Interaction.UpdateAsync(...);
}
}

+ 2
- 0
docs/guides/toc.yml View File

@@ -126,6 +126,8 @@
topicUid: Guides.OtherLibs.MediatR
- name: Emoji
topicUid: Guides.Emoji
- name: Bearer Tokens
topicUid: Guides.BearerToken
- name: Voice
topicUid: Guides.Voice.SendingVoice
- name: Deployment


+ 6
- 6
experiment/Discord.Net.BuildOverrides/BuildOverrides.cs View File

@@ -48,8 +48,8 @@ namespace Discord
{
var result = new Override();

using(var textReader = new StringReader(json))
using(var reader = new JsonTextReader(textReader))
using (var textReader = new StringReader(json))
using (var reader = new JsonTextReader(textReader))
{
var obj = JObject.ReadFrom(reader);
result.Id = obj["id"].ToObject<Guid>();
@@ -100,14 +100,14 @@ namespace Discord
/// Gets a read-only dictionary containing the currently loaded overrides.
/// </summary>
public IReadOnlyDictionary<Override, IReadOnlyCollection<LoadedOverride>> LoadedOverrides
=> _loadedOverrides.Select(x => new KeyValuePair<Override, IReadOnlyCollection<LoadedOverride>> (x.Key, x.Value)).ToDictionary(x => x.Key, x => x.Value);
=> _loadedOverrides.Select(x => new KeyValuePair<Override, IReadOnlyCollection<LoadedOverride>>(x.Key, x.Value)).ToDictionary(x => x.Key, x => x.Value);

private static AssemblyLoadContext _overrideDomain;
private static List<Func<Override, string, Task>> _logEvents = new();
private static ConcurrentDictionary<Override, List<LoadedOverride>> _loadedOverrides = new ConcurrentDictionary<Override, List<LoadedOverride>>();

private const string ApiUrl = "https://overrides.discordnet.dev";
static BuildOverrides()
{
_overrideDomain = new AssemblyLoadContext("Discord.Net.Overrides.Runtime");
@@ -258,14 +258,14 @@ namespace Discord

private static async Task<Assembly> GetDependencyAsync(Guid id, string name)
{
using(var client = new HttpClient())
using (var client = new HttpClient())
{
var result = await client.PostAsync($"{ApiUrl}/overrides/{id}/dependency", new StringContent($"{{ \"info\": \"{name}\"}}", Encoding.UTF8, "application/json"));

if (!result.IsSuccessStatusCode)
throw new Exception("Failed to get dependency");

using(var ms = new MemoryStream())
using (var ms = new MemoryStream())
{
var innerStream = await result.Content.ReadAsStreamAsync();
await innerStream.CopyToAsync(ms);


+ 4
- 3
samples/BasicBot/Program.cs View File

@@ -1,8 +1,8 @@
using Discord;
using Discord.WebSocket;
using System;
using System.Threading;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;

namespace BasicBot
{
@@ -112,7 +112,8 @@ namespace BasicBot
if (component.Data.CustomId == "unique-id")
await interaction.RespondAsync("Thank you for clicking my button!");

else Console.WriteLine("An ID has been received that has no handler!");
else
Console.WriteLine("An ID has been received that has no handler!");
}
}
}


+ 2
- 1
samples/InteractionFramework/Attributes/DoUserCheckAttribute.cs View File

@@ -30,7 +30,8 @@ namespace InteractionFramework.Attributes
? Task.FromResult(PreconditionResult.FromSuccess())
: Task.FromResult(PreconditionResult.FromError("User ID does not match component ID!"));

else return Task.FromResult(PreconditionResult.FromError("Parse cannot be done if no userID exists."));
else
return Task.FromResult(PreconditionResult.FromError("Parse cannot be done if no userID exists."));
}
}
}


+ 1
- 1
samples/InteractionFramework/Attributes/RequireOwnerAttribute.cs View File

@@ -10,7 +10,7 @@ namespace InteractionFramework.Attributes
{
public class RequireOwnerAttribute : PreconditionAttribute
{
public override async Task<PreconditionResult> CheckRequirementsAsync (IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services)
public override async Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services)
{
switch (context.Client.TokenType)
{


+ 1
- 1
samples/InteractionFramework/Modules/ExampleModule.cs View File

@@ -26,7 +26,7 @@ namespace InteractionFramework.Modules

// [Summary] lets you customize the name and the description of a parameter
[SlashCommand("echo", "Repeat the input")]
public async Task Echo(string echo, [Summary(description: "mention the user")]bool mention = false)
public async Task Echo(string echo, [Summary(description: "mention the user")] bool mention = false)
=> await RespondAsync(echo + (mention ? Context.User.Mention : string.Empty));

[SlashCommand("ping", "Pings the bot and returns its latency.")]


+ 5
- 5
samples/InteractionFramework/Program.cs View File

@@ -64,11 +64,11 @@ namespace InteractionFramework

public static bool IsDebug()
{
#if DEBUG
return true;
#else
return false;
#endif
#if DEBUG
return true;
#else
return false;
#endif
}
}
}

+ 4
- 4
src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs View File

@@ -1,11 +1,11 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using Discord.Commands;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Discord.Commands;
using System;
using System.Collections.Immutable;
using System.Linq;

namespace Discord.Analyzers
{


+ 2
- 2
src/Discord.Net.Analyzers/SymbolExtensions.cs View File

@@ -1,6 +1,6 @@
using System;
using Microsoft.CodeAnalysis;
using Discord.Commands;
using Microsoft.CodeAnalysis;
using System;

namespace Discord.Analyzers
{


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

@@ -43,8 +43,8 @@ namespace Discord.Commands
{
if (!TypeReaderTypeInfo.IsAssignableFrom(overridenTypeReader.GetTypeInfo()))
throw new ArgumentException($"{nameof(overridenTypeReader)} must inherit from {nameof(TypeReader)}.");
TypeReader = overridenTypeReader;
}
}
}
}

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

@@ -61,7 +61,7 @@ namespace Discord.Commands
if (GuildPermission.HasValue)
{
if (guildUser == null)
return Task.FromResult(PreconditionResult.FromError(NotAGuildErrorMessage ?? "Command must be used in a guild channel."));
return Task.FromResult(PreconditionResult.FromError(NotAGuildErrorMessage ?? "Command must be used in a guild channel."));
if (!guildUser.GuildPermissions.Has(GuildPermission.Value))
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"User requires guild permission {GuildPermission.Value}."));
}


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

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Discord.Commands.Builders
{


+ 3
- 1
src/Discord.Net.Commands/Builders/ModuleBuilder.cs View File

@@ -20,7 +20,9 @@ namespace Discord.Commands.Builders
public string Name { get; set; }
public string Summary { get; set; }
public string Remarks { get; set; }
public string Group { get => _group;
public string Group
{
get => _group;
set
{
_aliases.Remove(_group);


+ 8
- 9
src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs View File

@@ -1,11 +1,10 @@
using Discord.Commands.Builders;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

using Discord.Commands.Builders;

namespace Discord.Commands
{
internal static class ModuleClassBuilder
@@ -80,11 +79,11 @@ namespace Discord.Commands
{
if (!IsValidModuleDefinition(typeInfo))
continue;
if (builtTypes.Contains(typeInfo))
continue;
builder.AddModule((module) =>
builder.AddModule((module) =>
{
BuildModule(module, typeInfo, service, services);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service, services);
@@ -139,7 +138,7 @@ namespace Discord.Commands

foreach (var method in validCommands)
{
builder.AddCommand((command) =>
builder.AddCommand((command) =>
{
BuildCommand(command, typeInfo, method, service, services);
});
@@ -149,7 +148,7 @@ namespace Discord.Commands
private static void BuildCommand(CommandBuilder builder, TypeInfo typeInfo, MethodInfo method, CommandService service, IServiceProvider serviceprovider)
{
var attributes = method.GetCustomAttributes();
foreach (var attribute in attributes)
{
switch (attribute)
@@ -191,7 +190,7 @@ namespace Discord.Commands
int pos = 0, count = parameters.Length;
foreach (var paramInfo in parameters)
{
builder.AddParameter((parameter) =>
builder.AddParameter((parameter) =>
{
BuildParameter(parameter, paramInfo, pos++, count, service, serviceprovider);
});


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

@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using System.Collections.Generic;

namespace Discord.Commands.Builders
{
public class ParameterBuilder
@@ -25,7 +24,7 @@ namespace Discord.Commands.Builders

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

#region Automatic
internal ParameterBuilder(CommandBuilder command)


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

@@ -1,3 +1,5 @@
using Discord.Commands.Builders;
using Discord.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -6,8 +8,6 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Discord.Commands.Builders;
using Discord.Logging;

namespace Discord.Commands
{
@@ -653,7 +653,7 @@ namespace Discord.Commands
var bestCandidate = preconditionResults
.OrderByDescending(x => x.Key.Command.Priority)
.FirstOrDefault(x => !x.Value.IsSuccess);
return MatchResult.FromSuccess(bestCandidate.Key,bestCandidate.Value);
return MatchResult.FromSuccess(bestCandidate.Key, bestCandidate.Value);
}

var parseResults = new Dictionary<CommandMatch, ParseResult>();
@@ -685,7 +685,7 @@ namespace Discord.Commands
.Where(x => x.Value.IsSuccess)
.ToArray();

if(successfulParses.Length == 0)
if (successfulParses.Length == 0)
{
var bestMatch = parseResults
.FirstOrDefault(x => !x.Value.IsSuccess);


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

@@ -17,7 +17,7 @@ namespace Discord.Commands
/// Gets or sets the <see cref="char"/> that separates an argument with another.
/// </summary>
public char SeparatorChar { get; set; } = ' ';
/// <summary>
/// Gets or sets whether commands should be case-sensitive.
/// </summary>


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

@@ -5,7 +5,7 @@ namespace Discord.Commands
internal class EmptyServiceProvider : IServiceProvider
{
public static readonly EmptyServiceProvider Instance = new EmptyServiceProvider();
public object GetService(Type serviceType) => null;
}
}

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

@@ -19,4 +19,4 @@ namespace Discord.Commands
}
}
}
}
}

+ 8
- 4
src/Discord.Net.Commands/Extensions/MessageExtensions.cs View File

@@ -45,13 +45,17 @@ namespace Discord.Commands
public static bool HasMentionPrefix(this IUserMessage msg, IUser user, ref int argPos)
{
var text = msg.Content;
if (string.IsNullOrEmpty(text) || text.Length <= 3 || text[0] != '<' || text[1] != '@') return false;
if (string.IsNullOrEmpty(text) || text.Length <= 3 || text[0] != '<' || text[1] != '@')
return false;

int endPos = text.IndexOf('>');
if (endPos == -1) return false;
if (text.Length < endPos + 2 || text[endPos + 1] != ' ') return false; //Must end in "> "
if (endPos == -1)
return false;
if (text.Length < endPos + 2 || text[endPos + 1] != ' ')
return false; //Must end in "> "

if (!MentionUtils.TryParseUser(text.Substring(0, endPos + 1), out ulong userId)) return false;
if (!MentionUtils.TryParseUser(text.Substring(0, endPos + 1), out ulong userId))
return false;
if (userId == user.Id)
{
argPos = endPos + 2;


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

@@ -1,8 +1,8 @@
using Discord.Commands.Builders;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
@@ -175,7 +175,7 @@ namespace Discord.Commands

return await CommandParser.ParseArgsAsync(this, context, _commandService._ignoreExtraArgs, services, input, 0, _commandService._quotationMarkAliasMap).ConfigureAwait(false);
}
public Task<IResult> ExecuteAsync(ICommandContext context, ParseResult parseResult, IServiceProvider services)
{
if (!parseResult.IsSuccess)


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

@@ -1,8 +1,8 @@
using Discord.Commands.Builders;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using Discord.Commands.Builders;
using System.Linq;

namespace Discord.Commands
{


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

@@ -1,6 +1,6 @@
using Discord.Commands.Builders;
using System;
using System.Threading.Tasks;
using Discord.Commands.Builders;

namespace Discord.Commands
{


+ 2
- 2
src/Discord.Net.Commands/Readers/EnumTypeReader.cs View File

@@ -23,7 +23,7 @@ namespace Discord.Commands
private readonly IReadOnlyDictionary<T, object> _enumsByValue;
private readonly Type _enumType;
private readonly TryParseDelegate<T> _tryParse;
public EnumTypeReader(Type type, TryParseDelegate<T> parser)
{
_enumType = type;
@@ -33,7 +33,7 @@ namespace Discord.Commands
var byValueBuilder = ImmutableDictionary.CreateBuilder<T, object>();

foreach (var v in Enum.GetNames(_enumType))
{
{
var parsedValue = Enum.Parse(_enumType, v);
byNameBuilder.Add(v.ToLower(), parsedValue);
if (!byValueBuilder.ContainsKey((T)parsedValue))


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

@@ -116,7 +116,7 @@ namespace Discord.Commands
argv = input.Substring(beginRead + 1, currentRead - beginRead - 1).Trim();
currentRead++;
}
else
else
argv = input.Substring(beginRead, currentRead - beginRead);

return _tProps[currentParam];


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

@@ -27,7 +27,7 @@ namespace Discord.Commands

//By Id (0.9)
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
AddResult(results, context.Guild.GetRole(id) as T, 0.90f);
AddResult(results, context.Guild.GetRole(id) as T, 0.90f);

//By Name (0.7-0.8)
foreach (var role in roles.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)))


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

@@ -65,7 +65,7 @@ namespace Discord.Commands
.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase))
.ForEachAsync(channelUser => AddResult(results, channelUser as T, channelUser.Username == input ? 0.65f : 0.55f))
.ConfigureAwait(false);
foreach (var guildUser in guildUsers.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase)))
AddResult(results, guildUser as T, guildUser.Username == input ? 0.60f : 0.50f);
}


+ 3
- 3
src/Discord.Net.Commands/Results/MatchResult.cs View File

@@ -30,13 +30,13 @@ namespace Discord.Commands
}

public static MatchResult FromSuccess(CommandMatch match, IResult pipeline)
=> new MatchResult(match,pipeline,null, null);
=> new MatchResult(match, pipeline, null, null);
public static MatchResult FromError(CommandError error, string reason)
=> new MatchResult(null,null,error, reason);
=> new MatchResult(null, null, error, reason);
public static MatchResult FromError(Exception ex)
=> FromError(CommandError.Exception, ex.Message);
public static MatchResult FromError(IResult result)
=> new MatchResult(null, null,result.Error, result.ErrorReason);
=> new MatchResult(null, null, result.Error, result.ErrorReason);
public static MatchResult FromError(IResult pipeline, CommandError error, string reason)
=> new MatchResult(null, pipeline, error, reason);



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

@@ -24,7 +24,7 @@ namespace Discord.Commands
args[i] = GetMember(commands, services, parameters[i].ParameterType, typeInfo);
var obj = InvokeConstructor<T>(constructor, args, typeInfo);

foreach(var property in properties)
foreach (var property in properties)
property.SetValue(obj, GetMember(commands, services, property.PropertyType, typeInfo));
return obj;
};


+ 1
- 1
src/Discord.Net.Core/Audio/AudioApplication.cs View File

@@ -6,4 +6,4 @@ namespace Discord.Audio
Music,
Mixed
}
}
}

+ 2
- 2
src/Discord.Net.Core/Audio/AudioInStream.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;

@@ -9,7 +9,7 @@ namespace Discord.Audio
public abstract int AvailableFrames { get; }

public override bool CanRead => true;
public override bool CanWrite => true;
public override bool CanWrite => true;

public abstract Task<RTPFrame> ReadFrameAsync(CancellationToken cancelToken);
public abstract bool TryReadFrame(CancellationToken cancelToken, out RTPFrame frame);


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

@@ -12,7 +12,7 @@ namespace Discord.Audio
public override bool CanWrite => false;

/// <exception cref="InvalidOperationException">This stream does not accept headers.</exception>
public virtual void WriteHeader(ushort seq, uint timestamp, bool missed) =>
public virtual void WriteHeader(ushort seq, uint timestamp, bool missed) =>
throw new InvalidOperationException("This stream does not accept headers.");
public override void Write(byte[] buffer, int offset, int count)
{
@@ -31,7 +31,7 @@ namespace Discord.Audio

/// <inheritdoc />
/// <exception cref="NotSupportedException">Reading stream length is not supported.</exception>
public override long Length =>
public override long Length =>
throw new NotSupportedException();

/// <inheritdoc />


+ 1
- 1
src/Discord.Net.Core/Audio/RTPFrame.cs View File

@@ -15,4 +15,4 @@ namespace Discord.Audio
Missed = missed;
}
}
}
}

+ 5
- 5
src/Discord.Net.Core/CDN.cs View File

@@ -146,10 +146,10 @@ namespace Discord
/// </returns>
public static string GetGuildBannerUrl(ulong guildId, string bannerId, ImageFormat format, ushort? size = null)
{
if (string.IsNullOrEmpty(bannerId))
return null;
string extension = FormatToExtension(format, bannerId);
return $"{DiscordConfig.CDNUrl}banners/{guildId}/{bannerId}.{extension}" + (size.HasValue ? $"?size={size}" : string.Empty);
if (string.IsNullOrEmpty(bannerId))
return null;
string extension = FormatToExtension(format, bannerId);
return $"{DiscordConfig.CDNUrl}banners/{guildId}/{bannerId}.{extension}" + (size.HasValue ? $"?size={size}" : string.Empty);
}
/// <summary>
/// Returns an emoji URL.
@@ -218,7 +218,7 @@ namespace Discord
/// <param name="size">The size of the image.</param>
/// <returns></returns>
public static string GetEventCoverImageUrl(ulong guildId, ulong eventId, string assetId, ImageFormat format = ImageFormat.Auto, ushort size = 1024)
=> $"{DiscordConfig.CDNUrl}guild-events/{guildId}/{eventId}/{assetId}.{FormatToExtension(format, assetId)}?size={size}";
=> $"{DiscordConfig.CDNUrl}guild-events/{eventId}/{assetId}.{FormatToExtension(format, assetId)}?size={size}";

private static string FormatToExtension(StickerFormatType format)
{


+ 1
- 1
src/Discord.Net.Core/Discord.Net.Core.csproj View File

@@ -11,7 +11,7 @@
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="System.Interactive.Async" Version="5.0.0" />
<PackageReference Include="IDisposableAnalyzers" Version="3.4.15">
<PrivateAssets>all</PrivateAssets>


+ 25
- 17
src/Discord.Net.Core/DiscordConfig.cs View File

@@ -175,23 +175,23 @@ namespace Discord
/// </remarks>
internal bool DisplayInitialLog { get; set; } = true;

/// <summary>
/// Gets or sets whether or not rate-limits should use the system clock.
/// </summary>
/// <remarks>
/// If set to <c>false</c>, we will use the X-RateLimit-Reset-After header
/// to determine when a rate-limit expires, rather than comparing the
/// X-RateLimit-Reset timestamp to the system time.
///
/// This should only be changed to false if the system is known to have
/// a clock that is out of sync. Relying on the Reset-After header will
/// incur network lag.
///
/// Regardless of this property, we still rely on the system's wall-clock
/// to determine if a bucket is rate-limited; we do not use any monotonic
/// clock. Your system will still need a stable clock.
/// </remarks>
public bool UseSystemClock { get; set; } = true;
/// <summary>
/// Gets or sets whether or not rate-limits should use the system clock.
/// </summary>
/// <remarks>
/// If set to <c>false</c>, we will use the X-RateLimit-Reset-After header
/// to determine when a rate-limit expires, rather than comparing the
/// X-RateLimit-Reset timestamp to the system time.
///
/// This should only be changed to false if the system is known to have
/// a clock that is out of sync. Relying on the Reset-After header will
/// incur network lag.
///
/// Regardless of this property, we still rely on the system's wall-clock
/// to determine if a bucket is rate-limited; we do not use any monotonic
/// clock. Your system will still need a stable clock.
/// </remarks>
public bool UseSystemClock { get; set; } = true;

/// <summary>
/// Gets or sets whether or not the internal experation check uses the system date
@@ -214,5 +214,13 @@ namespace Discord
/// If set to <see langword="false"/>, this value will be "Discord#1234".
/// </remarks>
public bool FormatUsersInBidirectionalUnicode { get; set; } = true;

/// <summary>
/// Returns the max thread members allowed to be in a request.
/// </summary>
/// <returns>
/// The maximum number of thread members that can be gotten per-batch.
/// </returns>
public const int MaxThreadMembersPerBatch = 100;
}
}

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

@@ -30,7 +30,7 @@ namespace Discord
Flags = flags;
Details = details;
}
/// <summary> Returns the name of the <see cref="Game"/>. </summary>
public override string ToString() => Name;
private string DebuggerDisplay => Name;


+ 1
- 1
src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadataProperties.cs View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;

namespace Discord;


+ 3
- 3
src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionProperties.cs View File

@@ -38,7 +38,7 @@ public class RoleConnectionProperties
get => _platformUsername;
set
{
if(value is not null)
if (value is not null)
Preconditions.AtMost(value.Length, MaxPlatformUsernameLength, nameof(PlatformUsername), $"Platform username length must be less or equal to {MaxPlatformUsernameLength}");
_platformUsername = value;
}
@@ -103,7 +103,7 @@ public class RoleConnectionProperties
internal RoleConnectionProperties AddMetadataRecord(string key, string value)
{
Metadata ??= new Dictionary<string, string>();
if(!Metadata.ContainsKey(key))
if (!Metadata.ContainsKey(key))
Preconditions.AtMost(Metadata.Count + 1, MaxPlatformUsernameLength, nameof(Metadata), $"Metadata records count must be less or equal to {MaxMetadataRecords}");

_metadata[key] = value;
@@ -126,7 +126,7 @@ public class RoleConnectionProperties
/// <summary>
/// Initializes a new instance of <see cref="RoleConnectionProperties"/>.
/// </summary>
public RoleConnectionProperties() {}
public RoleConnectionProperties() { }

/// <summary>
/// Initializes a new <see cref="RoleConnectionProperties"/> with the data from provided <see cref="RoleConnection"/>.


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

@@ -1,4 +1,4 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Provides properties that are used to modify an <see cref="IAudioChannel" /> with the specified changes.


+ 5
- 2
src/Discord.Net.Core/Entities/Channels/IForumChannel.cs View File

@@ -7,7 +7,10 @@ using System.Threading.Tasks;

namespace Discord
{
public interface IForumChannel : IGuildChannel, IMentionable, INestedChannel
/// <summary>
/// Represents a forum channel in a guild that can create posts.
/// </summary>
public interface IForumChannel : IMentionable, INestedChannel, IIntegrationChannel
{
/// <summary>
/// Gets a value that indicates whether the channel is NSFW.
@@ -169,7 +172,7 @@ namespace Discord
public Task<IThreadChannel> CreatePostWithFileAsync(string title, Stream stream, string filename, ThreadArchiveDuration archiveDuration = ThreadArchiveDuration.OneDay,
int? slowmode = null, string text = null, Embed embed = null, RequestOptions options = null, bool isSpoiler = false,
AllowedMentions allowedMentions = null, MessageComponent components = null,
ISticker[] stickers = null, Embed[] embeds = null,MessageFlags flags = MessageFlags.None, ForumTag[] tags = null);
ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None, ForumTag[] tags = null);

/// <summary>
/// Creates a new post (thread) within the forum.


+ 44
- 0
src/Discord.Net.Core/Entities/Channels/IIntegrationChannel.cs View File

@@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace Discord;

/// <summary>
/// Represents a channel in a guild that can create webhooks.
/// </summary>
public interface IIntegrationChannel : IGuildChannel
{
/// <summary>
/// Creates a webhook in this channel.
/// </summary>
/// <param name="name">The name of the webhook.</param>
/// <param name="avatar">The avatar of the webhook.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// webhook.
/// </returns>
Task<IWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null);

/// <summary>
/// Gets a webhook available in this channel.
/// </summary>
/// <param name="id">The identifier of the webhook.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a webhook associated
/// with the identifier; <c>null</c> if the webhook is not found.
/// </returns>
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null);

/// <summary>
/// Gets the webhooks available in this channel.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of webhooks that is available in this channel.
/// </returns>
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null);
}

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

@@ -222,7 +222,7 @@ namespace Discord
/// <returns>
/// Paged collection of messages.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch,
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a collection of messages in this channel.
@@ -263,7 +263,7 @@ namespace Discord
/// <returns>
/// Paged collection of messages.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a collection of messages in this channel.
@@ -300,7 +300,7 @@ namespace Discord
/// <returns>
/// Paged collection of messages.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a collection of pinned messages in this channel.


+ 9
- 0
src/Discord.Net.Core/Entities/Channels/INewsChannel.cs View File

@@ -1,3 +1,5 @@
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
@@ -5,5 +7,12 @@ namespace Discord
/// </summary>
public interface INewsChannel : ITextChannel
{
/// <summary>
/// Follow this channel to send messages to a target channel.
/// </summary>
/// <returns>
/// The Id of the created webhook.
/// </returns>
Task<ulong> FollowAnnouncementChannelAsync(ulong channelId, RequestOptions options);
}
}

+ 1
- 32
src/Discord.Net.Core/Entities/Channels/ITextChannel.cs View File

@@ -8,7 +8,7 @@ namespace Discord
/// <summary>
/// Represents a generic channel in a guild that can send and receive messages.
/// </summary>
public interface ITextChannel : IMessageChannel, IMentionable, INestedChannel
public interface ITextChannel : IMessageChannel, IMentionable, INestedChannel, IIntegrationChannel
{
/// <summary>
/// Gets a value that indicates whether the channel is NSFW.
@@ -94,37 +94,6 @@ namespace Discord
/// </returns>
/// <seealso cref="TextChannelProperties"/>
Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null);
/// <summary>
/// Creates a webhook in this text channel.
/// </summary>
/// <param name="name">The name of the webhook.</param>
/// <param name="avatar">The avatar of the webhook.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// webhook.
/// </returns>
Task<IWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null);
/// <summary>
/// Gets a webhook available in this text channel.
/// </summary>
/// <param name="id">The identifier of the webhook.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a webhook associated
/// with the identifier; <c>null</c> if the webhook is not found.
/// </returns>
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null);
/// <summary>
/// Gets the webhooks available in this text channel.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of webhooks that is available in this channel.
/// </returns>
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null);

/// <summary>
/// Creates a thread within this <see cref="ITextChannel"/>.


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

@@ -26,6 +26,11 @@ namespace Discord
/// </returns>
int? UserLimit { get; }

/// <summary>
/// Gets the video quality mode for this channel.
/// </summary>
VideoQualityMode VideoQualityMode { get; }

/// <summary>
/// Bulk-deletes multiple messages.
/// </summary>


+ 17
- 0
src/Discord.Net.Core/Entities/Channels/VideoQualityMode.cs View File

@@ -0,0 +1,17 @@
namespace Discord;

/// <summary>
/// Represents a video quality mode for voice channels.
/// </summary>
public enum VideoQualityMode
{
/// <summary>
/// Discord chooses the quality for optimal performance.
/// </summary>
Auto = 1,

/// <summary>
/// 720p.
/// </summary>
Full = 2
}

+ 5
- 0
src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs View File

@@ -17,5 +17,10 @@ namespace Discord
/// Gets or sets the channel voice region id, automatic when set to <see langword="null"/>.
/// </summary>
public Optional<string> RTCRegion { get; set; }

/// <summary>
/// Get or sets the video quality mode for this channel.
/// </summary>
public Optional<VideoQualityMode> VideoQualityMode { get; set; }
}
}

+ 6979
- 5862
src/Discord.Net.Core/Entities/Emotes/Emoji.cs
File diff suppressed because it is too large
View File


+ 7
- 4
src/Discord.Net.Core/Entities/Emotes/Emote.cs View File

@@ -1,6 +1,6 @@
using System;
using System.Globalization;
using System.Diagnostics;
using System.Globalization;

namespace Discord
{
@@ -44,11 +44,14 @@ namespace Discord
/// <param name="other">The object to compare with the current object.</param>
public override bool Equals(object other)
{
if (other == null) return false;
if (other == this) return true;
if (other == null)
return false;
if (other == this)
return true;

var otherEmote = other as Emote;
if (otherEmote == null) return false;
if (otherEmote == null)
return false;

return Id == otherEmote.Id;
}


+ 1
- 1
src/Discord.Net.Core/Entities/ForumTags/ForumTag.cs View File

@@ -45,7 +45,7 @@ namespace Discord
}

public override int GetHashCode() => (Id, Name, Emoji, IsModerated).GetHashCode();
public override bool Equals(object? obj)
=> obj is ForumTag tag && Equals(tag);



+ 4
- 4
src/Discord.Net.Core/Entities/ForumTags/ForumTagBuilder.cs View File

@@ -110,8 +110,8 @@ public class ForumTagBuilder
public ForumTagBuilder(string name, ulong? id = null, bool isModerated = false, ulong? emoteId = null)
{
Name = name;
if(emoteId is not null)
Emoji = new Emote(emoteId.Value, null, false);
if (emoteId is not null)
Emoji = new Emote(emoteId.Value, null, false);
IsModerated = isModerated;
Id = id;
}
@@ -180,12 +180,12 @@ public class ForumTagBuilder
=> builder is not null &&
Id == builder.Id &&
Name == builder.Name &&
(Emoji is Emoji emoji && builder.Emoji is Emoji otherEmoji && emoji.Equals(otherEmoji) ||
(Emoji is Emoji emoji && builder.Emoji is Emoji otherEmoji && emoji.Equals(otherEmoji) ||
Emoji is Emote emote && builder.Emoji is Emote otherEmote && emote.Equals(otherEmote)) &&
IsModerated == builder.IsModerated;

public static bool operator ==(ForumTagBuilder? left, ForumTagBuilder? right)
=> left?.Equals(right) ?? right is null ;
=> left?.Equals(right) ?? right is null;

public static bool operator !=(ForumTagBuilder? left, ForumTagBuilder? right) => !(left == right);
}

+ 8
- 0
src/Discord.Net.Core/Entities/Guilds/IUserGuild.cs View File

@@ -18,5 +18,13 @@ namespace Discord
/// Returns the current user's permissions for this guild.
/// </summary>
GuildPermissions Permissions { get; }

/// <summary>
/// Gets the features for this guild.
/// </summary>
/// <returns>
/// A flags enum containing all the features for the guild.
/// </returns>
GuildFeatures Features { get; }
}
}

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

@@ -19,4 +19,4 @@ namespace Discord
/// </summary>
AgeRestricted = 3
}
}
}

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

@@ -50,5 +50,5 @@ public class WelcomeScreenChannelProperties : ISnowflakeEntity
/// <param name="channel">A welcome screen channel to modify.</param>
/// <returns>A new instance of <see cref="WelcomeScreenChannelProperties"/>.</returns>
public static WelcomeScreenChannelProperties FromWelcomeScreenChannel(WelcomeScreenChannel channel)
=> new (channel.Id, channel.Description, channel.Emoji);
=> new(channel.Id, channel.Description, channel.Emoji);
}

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

@@ -34,7 +34,7 @@ namespace Discord
/// <summary>
/// Gets the icon URL of the application.
/// </summary>
string IconUrl { get; }
string IconUrl { get; }
/// <summary>
/// Gets if the bot is public.
/// </summary>


+ 1
- 1
src/Discord.Net.Core/Entities/Integrations/IIntegration.cs View File

@@ -90,7 +90,7 @@ namespace Discord
/// Gets the bot/OAuth2 application for a discord integration.
/// </summary>
IIntegrationApplication Application { get; }
IGuild Guild { get; }
ulong GuildId { get; }
}


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

@@ -110,7 +110,7 @@ namespace Discord
{
foreach (var (locale, name) in value)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidOptionName(name);
@@ -134,7 +134,7 @@ namespace Discord
{
foreach (var (locale, description) in value)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidOptionDescription(description);


+ 1
- 1
src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs View File

@@ -45,7 +45,7 @@ namespace Discord
public object Value
{
get => _value;
set
set
{
if (value is not string && !value.IsNumericType())
throw new ArgumentException($"{nameof(value)} must be a numeric type or a string!");


+ 3
- 3
src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandBuilder.cs View File

@@ -49,7 +49,7 @@ namespace Discord
/// <summary>
/// Gets or sets whether or not this command is age restricted.
/// </summary>
public bool IsNsfw{ get; set; } = false;
public bool IsNsfw { get; set; } = false;

/// <summary>
/// Gets or sets the default permission required to use this slash command.
@@ -118,7 +118,7 @@ namespace Discord

foreach (var (locale, name) in nameLocalizations)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandName(name);
@@ -159,7 +159,7 @@ namespace Discord
/// <exception cref="ArgumentException">Thrown if <paramref name="locale"/> is an invalid locale string.</exception>
public MessageCommandBuilder AddNameLocalization(string locale, string name)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandName(name);


+ 3
- 3
src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandBuilder.cs View File

@@ -116,7 +116,7 @@ namespace Discord

foreach (var (locale, name) in nameLocalizations)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandName(name);
@@ -125,7 +125,7 @@ namespace Discord
_nameLocalizations = new Dictionary<string, string>(nameLocalizations);
return this;
}
/// <summary>
/// Sets whether or not this command can be used in dms.
/// </summary>
@@ -157,7 +157,7 @@ namespace Discord
/// <exception cref="ArgumentException">Thrown if <paramref name="locale"/> is an invalid locale string.</exception>
public UserCommandBuilder AddNameLocalization(string locale, string name)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandName(name);


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

@@ -130,7 +130,7 @@ namespace Discord
async Task RespondWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
{
using(var file = new FileAttachment(fileStream, fileName))
using (var file = new FileAttachment(fileStream, fileName))
{
await RespondWithFileAsync(file, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options).ConfigureAwait(false);
}
@@ -249,7 +249,7 @@ namespace Discord
async Task<IUserMessage> FollowupWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null)
{
using(var file = new FileAttachment(fileStream, fileName))
using (var file = new FileAttachment(fileStream, fileName))
{
return await FollowupWithFileAsync(file, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options).ConfigureAwait(false);
}


+ 1
- 1
src/Discord.Net.Core/Entities/Interactions/MessageComponents/TextInputComponent.cs View File

@@ -46,7 +46,7 @@ namespace Discord
/// </summary>
public string Value { get; }

internal TextInputComponent(string customId, string label, string placeholder, int? minLength, int? maxLength,
internal TextInputComponent(string customId, string label, string placeholder, int? minLength, int? maxLength,
TextInputStyle style, bool? required, string value)
{
CustomId = customId;


+ 1
- 1
src/Discord.Net.Core/Entities/Interactions/MessageComponents/TextInputStyle.cs View File

@@ -1,4 +1,4 @@
namespace Discord
namespace Discord
{
public enum TextInputStyle
{


+ 3
- 3
src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs View File

@@ -93,7 +93,7 @@ namespace Discord
/// <param name="maxLength">The input's maximum length.</param>
/// <param name="style">The input's style.</param>
/// <returns>The current builder.</returns>
public ModalBuilder AddTextInput(string label, string customId, TextInputStyle style = TextInputStyle.Short,
public ModalBuilder AddTextInput(string label, string customId, TextInputStyle style = TextInputStyle.Short,
string placeholder = "", int? minLength = null, int? maxLength = null, bool? required = null, string value = null)
=> AddTextInput(new(label, customId, style, placeholder, minLength, maxLength, required, value));

@@ -204,7 +204,7 @@ namespace Discord
/// <param name="maxLength">The input's maximum length.</param>
/// <param name="style">The input's style.</param>
/// <returns>The current builder.</returns>
public ModalComponentBuilder WithTextInput(string label, string customId, TextInputStyle style = TextInputStyle.Short,
public ModalComponentBuilder WithTextInput(string label, string customId, TextInputStyle style = TextInputStyle.Short,
string placeholder = null, int? minLength = null, int? maxLength = null, int row = 0, bool? required = null,
string value = null)
=> WithTextInput(new(label, customId, style, placeholder, minLength, maxLength, required, value), row);
@@ -263,6 +263,6 @@ namespace Discord
/// </summary>
/// <returns>A <see cref="ModalComponent"/> representing the builder.</returns>
public ModalComponent Build()
=> new (ActionRows?.Select(x => x.Build()).ToList());
=> new(ActionRows?.Select(x => x.Build()).ToList());
}
}

+ 13
- 13
src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs View File

@@ -84,7 +84,7 @@ namespace Discord
/// Gets or sets whether or not this command can be used in DMs.
/// </summary>
public bool IsDMEnabled { get; set; } = true;
/// <summary>
/// Gets or sets whether or not this command is age restricted.
/// </summary>
@@ -312,7 +312,7 @@ namespace Discord

foreach (var (locale, name) in nameLocalizations)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandName(name);
@@ -336,7 +336,7 @@ namespace Discord

foreach (var (locale, description) in descriptionLocalizations)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandDescription(description);
@@ -355,7 +355,7 @@ namespace Discord
/// <exception cref="ArgumentException">Thrown if <paramref name="locale"/> is an invalid locale string.</exception>
public SlashCommandBuilder AddNameLocalization(string locale, string name)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandName(name);
@@ -375,7 +375,7 @@ namespace Discord
/// <exception cref="ArgumentException">Thrown if <paramref name="locale"/> is an invalid locale string.</exception>
public SlashCommandBuilder AddDescriptionLocalization(string locale, string description)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandDescription(description);
@@ -549,7 +549,7 @@ namespace Discord
if (isIntType && MaxValue != null && MaxValue % 1 != 0)
throw new InvalidOperationException("MaxValue cannot have decimals on Integer command options.");

if(isStrType && MinLength is not null && MinLength < 0)
if (isStrType && MinLength is not null && MinLength < 0)
throw new InvalidOperationException("MinLength cannot be smaller than 0.");

if (isStrType && MaxLength is not null && MaxLength < 1)
@@ -627,10 +627,10 @@ namespace Discord
ChannelTypes = channelTypes,
};

if(nameLocalizations is not null)
if (nameLocalizations is not null)
option.WithNameLocalizations(nameLocalizations);

if(descriptionLocalizations is not null)
if (descriptionLocalizations is not null)
option.WithDescriptionLocalizations(descriptionLocalizations);

return AddOption(option);
@@ -749,7 +749,7 @@ namespace Discord
Preconditions.AtLeast(name.Length, 1, nameof(name));
Preconditions.AtMost(name.Length, 100, nameof(name));

if(value is string str)
if (value is string str)
{
Preconditions.AtLeast(str.Length, 1, nameof(value));
Preconditions.AtMost(str.Length, 100, nameof(value));
@@ -904,7 +904,7 @@ namespace Discord

foreach (var (locale, name) in nameLocalizations)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandOptionName(name);
@@ -928,7 +928,7 @@ namespace Discord

foreach (var (locale, description) in descriptionLocalizations)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandOptionDescription(description);
@@ -947,7 +947,7 @@ namespace Discord
/// <exception cref="ArgumentException">Thrown if <paramref name="locale"/> is an invalid locale string.</exception>
public SlashCommandOptionBuilder AddNameLocalization(string locale, string name)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandOptionName(name);
@@ -967,7 +967,7 @@ namespace Discord
/// <exception cref="ArgumentException">Thrown if <paramref name="locale"/> is an invalid locale string.</exception>
public SlashCommandOptionBuilder AddDescriptionLocalization(string locale, string description)
{
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale));

EnsureValidCommandOptionDescription(description);


+ 12
- 12
src/Discord.Net.Core/Entities/Invites/InviteGuild.cs View File

@@ -81,7 +81,7 @@ public class InviteGuild : ISnowflakeEntity
/// A URL pointing to the guild's icon; <see langword="null" /> if none is set.
/// </returns>
public string IconUrl => CDN.GetGuildIconUrl(Id, IconId);
/// <summary>
///
/// Gets the level of requirements a user must fulfill before being allowed to post messages in this guild.
@@ -127,17 +127,17 @@ public class InviteGuild : ISnowflakeEntity
public WelcomeScreen WelcomeScreen { get; private set; }

internal InviteGuild(
ulong id,
string name,
string description,
string splashId,
string bannerId,
GuildFeatures features,
string iconId,
VerificationLevel verificationLevel,
string vanityURLCode,
int premiumSubscriptionCount,
NsfwLevel nsfwLevel,
ulong id,
string name,
string description,
string splashId,
string bannerId,
GuildFeatures features,
string iconId,
VerificationLevel verificationLevel,
string vanityURLCode,
int premiumSubscriptionCount,
NsfwLevel nsfwLevel,
WelcomeScreen welcomeScreen)
{
Id = id;


+ 4
- 4
src/Discord.Net.Core/Entities/Messages/AllowedMentionTypes.cs View File

@@ -17,18 +17,18 @@ namespace Discord
/// It will always be present and does not mean mentions will not be allowed.
/// </note>
/// </remarks>
None = 0,
None = 0,
/// <summary>
/// Controls role mentions.
/// </summary>
Roles = 1,
Roles = 1,
/// <summary>
/// Controls user mentions.
/// </summary>
Users = 2,
Users = 2,
/// <summary>
/// Controls <code>@everyone</code> and <code>@here</code> mentions.
/// </summary>
Everyone = 4,
Everyone = 4,
}
}

+ 6
- 6
src/Discord.Net.Core/Entities/Messages/Embed.cs View File

@@ -44,7 +44,7 @@ namespace Discord
Type = type;
Fields = ImmutableArray.Create<EmbedField>();
}
internal Embed(EmbedType type,
internal Embed(EmbedType type,
string title,
string description,
string url,
@@ -52,10 +52,10 @@ namespace Discord
Color? color,
EmbedImage? image,
EmbedVideo? video,
EmbedAuthor? author,
EmbedFooter? footer,
EmbedProvider? provider,
EmbedThumbnail? thumbnail,
EmbedAuthor? author,
EmbedFooter? footer,
EmbedProvider? provider,
EmbedThumbnail? thumbnail,
ImmutableArray<EmbedField> fields)
{
Type = type;
@@ -128,7 +128,7 @@ namespace Discord
{
var hash = 17;
hash = hash * 23 + (Type, Title, Description, Timestamp, Color, Image, Video, Author, Footer, Provider, Thumbnail).GetHashCode();
foreach(var field in Fields)
foreach (var field in Fields)
hash = hash * 23 + field.GetHashCode();
return hash;
}


+ 23
- 13
src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs View File

@@ -1,9 +1,9 @@
using Discord.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Discord.Utils;
using Newtonsoft.Json;

namespace Discord
{
@@ -50,7 +50,8 @@ namespace Discord
get => _title;
set
{
if (value?.Length > MaxTitleLength) throw new ArgumentException(message: $"Title length must be less than or equal to {MaxTitleLength}.", paramName: nameof(Title));
if (value?.Length > MaxTitleLength)
throw new ArgumentException(message: $"Title length must be less than or equal to {MaxTitleLength}.", paramName: nameof(Title));
_title = value;
}
}
@@ -63,7 +64,8 @@ namespace Discord
get => _description;
set
{
if (value?.Length > MaxDescriptionLength) throw new ArgumentException(message: $"Description length must be less than or equal to {MaxDescriptionLength}.", paramName: nameof(Description));
if (value?.Length > MaxDescriptionLength)
throw new ArgumentException(message: $"Description length must be less than or equal to {MaxDescriptionLength}.", paramName: nameof(Description));
_description = value;
}
}
@@ -100,8 +102,10 @@ namespace Discord
get => _fields;
set
{
if (value == null) throw new ArgumentNullException(paramName: nameof(Fields), message: "Cannot set an embed builder's fields collection to null.");
if (value.Count > MaxFieldCount) throw new ArgumentException(message: $"Field count must be less than or equal to {MaxFieldCount}.", paramName: nameof(Fields));
if (value == null)
throw new ArgumentNullException(paramName: nameof(Fields), message: "Cannot set an embed builder's fields collection to null.");
if (value.Count > MaxFieldCount)
throw new ArgumentException(message: $"Field count must be less than or equal to {MaxFieldCount}.", paramName: nameof(Fields));
_fields = value;
}
}
@@ -470,7 +474,7 @@ namespace Discord
if (!string.IsNullOrEmpty(Author.IconUrl))
UrlValidation.Validate(Author.IconUrl, true);
}
if(Footer != null)
if (Footer != null)
{
if (!string.IsNullOrEmpty(Footer.IconUrl))
UrlValidation.Validate(Footer.IconUrl, true);
@@ -564,8 +568,10 @@ namespace Discord
get => _name;
set
{
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException(message: "Field name must not be null, empty or entirely whitespace.", paramName: nameof(Name));
if (value.Length > MaxFieldNameLength) throw new ArgumentException(message: $"Field name length must be less than or equal to {MaxFieldNameLength}.", paramName: nameof(Name));
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException(message: "Field name must not be null, empty or entirely whitespace.", paramName: nameof(Name));
if (value.Length > MaxFieldNameLength)
throw new ArgumentException(message: $"Field name length must be less than or equal to {MaxFieldNameLength}.", paramName: nameof(Name));
_name = value;
}
}
@@ -587,8 +593,10 @@ namespace Discord
set
{
var stringValue = value?.ToString();
if (string.IsNullOrWhiteSpace(stringValue)) throw new ArgumentException(message: "Field value must not be null or empty.", paramName: nameof(Value));
if (stringValue.Length > MaxFieldValueLength) throw new ArgumentException(message: $"Field value length must be less than or equal to {MaxFieldValueLength}.", paramName: nameof(Value));
if (string.IsNullOrWhiteSpace(stringValue))
throw new ArgumentException(message: "Field value must not be null or empty.", paramName: nameof(Value));
if (stringValue.Length > MaxFieldValueLength)
throw new ArgumentException(message: $"Field value length must be less than or equal to {MaxFieldValueLength}.", paramName: nameof(Value));
_value = stringValue;
}
}
@@ -704,7 +712,8 @@ namespace Discord
get => _name;
set
{
if (value?.Length > MaxAuthorNameLength) throw new ArgumentException(message: $"Author name length must be less than or equal to {MaxAuthorNameLength}.", paramName: nameof(Name));
if (value?.Length > MaxAuthorNameLength)
throw new ArgumentException(message: $"Author name length must be less than or equal to {MaxAuthorNameLength}.", paramName: nameof(Name));
_name = value;
}
}
@@ -836,7 +845,8 @@ namespace Discord
get => _text;
set
{
if (value?.Length > MaxFooterTextLength) throw new ArgumentException(message: $"Footer text length must be less than or equal to {MaxFooterTextLength}.", paramName: nameof(Text));
if (value?.Length > MaxFooterTextLength)
throw new ArgumentException(message: $"Footer text length must be less than or equal to {MaxFooterTextLength}.", paramName: nameof(Text));
_text = value;
}
}


+ 10
- 2
src/Discord.Net.Core/Entities/Messages/IMessage.cs View File

@@ -79,7 +79,7 @@ namespace Discord
/// Time of when the message was last edited; <c>null</c> if the message is never edited.
/// </returns>
DateTimeOffset? EditedTimestamp { get; }
/// <summary>
/// Gets the source channel of the message.
/// </summary>
@@ -89,6 +89,14 @@ namespace Discord
/// </summary>
IUser Author { get; }

/// <summary>
/// Gets the thread that was started from this message.
/// </summary>
/// <returns>
/// An <see cref="IThreadChannel"/> object if this message has thread attached; otherwise <see langword="null"/>.
/// </returns>
IThreadChannel Thread { get; }

/// <summary>
/// Gets all attachments included in this message.
/// </summary>
@@ -189,7 +197,7 @@ namespace Discord
/// A read-only collection of sticker item objects.
/// </returns>
IReadOnlyCollection<IStickerItem> Stickers { get; }
/// <summary>
/// Gets the flags related to this message.
/// </summary>


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

@@ -1,4 +1,4 @@
namespace Discord
namespace Discord
{
public interface ITag
{


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

@@ -43,6 +43,14 @@ namespace Discord
/// <summary>
/// Flag given to messages that is an Interaction Response and the bot is "thinking"
/// </summary>
Loading = 1 << 7
Loading = 1 << 7,
/// <summary>
/// Flag given to messages that failed to mention some roles and add their members to the thread.
/// </summary>
FailedToMentionRolesInThread = 1 << 8,
/// <summary>
/// Flag give to messages that will not trigger push and desktop notifications.
/// </summary>
SuppressNotification = 1 << 12
}
}

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

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

namespace Discord
{


+ 5
- 1
src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs View File

@@ -12,6 +12,10 @@ namespace Discord
/// <summary>
/// The target of the permission is a user.
/// </summary>
User = 2
User = 2,
/// <summary>
/// The target of the permission is a channel.
/// </summary>
Channel = 3
}
}

+ 56
- 0
src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs View File

@@ -58,5 +58,61 @@ namespace Discord
Permission = allow;
TargetType = ApplicationCommandPermissionTarget.Role;
}

/// <summary>
/// Creates a new <see cref="ApplicationCommandPermission"/> targeting <see cref="ApplicationCommandPermissionTarget.Channel"/>.
/// </summary>
/// <param name="channel">The channel you want to target this permission value for.</param>
/// <param name="allow">The value of this permission.</param>
public ApplicationCommandPermission(IChannel channel, bool allow)
{
TargetId = channel.Id;
Permission = allow;
TargetType = ApplicationCommandPermissionTarget.Channel;
}

/// <summary>
/// Creates a new <see cref="ApplicationCommandPermission"/> targeting @everyone in a guild.
/// </summary>
/// <param name="guildId">Id of the target guild.</param>
/// <param name="allow">The value of this permission.</param>
/// <returns>
/// Instance of <see cref="ApplicationCommandPermission"/> targeting @everyone in a guild.
/// </returns>
public static ApplicationCommandPermission ForEveryone(ulong guildId, bool allow) =>
new(guildId, ApplicationCommandPermissionTarget.User, allow);

/// <summary>
/// Creates a new <see cref="ApplicationCommandPermission"/> targeting @everyone in a guild.
/// </summary>
/// <param name="guild">Target guild.</param>
/// <param name="allow">The value of this permission.</param>
/// <returns>
/// Instance of <see cref="ApplicationCommandPermission"/> targeting @everyone in a guild.
/// </returns>
public static ApplicationCommandPermission ForEveryone(IGuild guild, bool allow) =>
ForEveryone(guild.Id, allow);

/// <summary>
/// Creates a new <see cref="ApplicationCommandPermission"/> targeting every channel in a guild.
/// </summary>
/// <param name="guildId">Id of the target guild.</param>
/// <param name="allow">The value of this permission.</param>
/// <returns>
/// Instance of <see cref="ApplicationCommandPermission"/> targeting everychannel in a guild.
/// </returns>
public static ApplicationCommandPermission ForAllChannels(ulong guildId, bool allow) =>
new(guildId - 1, ApplicationCommandPermissionTarget.Channel, allow);

/// <summary>
/// Creates a new <see cref="ApplicationCommandPermission"/> targeting every channel in a guild.
/// </summary>
/// <param name="guild">Target guild.</param>
/// <param name="allow">The value of this permission.</param>
/// <returns>
/// Instance of <see cref="ApplicationCommandPermission"/> targeting everychannel in a guild.
/// </returns>
public static ApplicationCommandPermission ForAllChannels(IGuild guild, bool allow) =>
ForAllChannels(guild.Id, allow);
}
}

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

@@ -10,105 +10,105 @@ namespace Discord
/// <summary>
/// Allows creation of instant invites.
/// </summary>
CreateInstantInvite = 0x00_00_00_00_01,
CreateInstantInvite = 0x00_00_00_00_01,
/// <summary>
/// Allows management and editing of channels.
/// </summary>
ManageChannels = 0x00_00_00_00_10,
ManageChannels = 0x00_00_00_00_10,

// Text
/// <summary>
/// Allows for the addition of reactions to messages.
/// </summary>
AddReactions = 0x00_00_00_00_40,
AddReactions = 0x00_00_00_00_40,
/// <summary>
/// Allows guild members to view a channel, which includes reading messages in text channels.
/// </summary>
ViewChannel = 0x00_00_00_04_00,
ViewChannel = 0x00_00_00_04_00,
/// <summary>
/// Allows for sending messages in a channel.
/// </summary>
SendMessages = 0x00_00_00_08_00,
SendMessages = 0x00_00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.
/// </summary>
SendTTSMessages = 0x00_00_00_10_00,
SendTTSMessages = 0x00_00_00_10_00,
/// <summary>
/// Allows for deletion of other users messages.
/// </summary>
ManageMessages = 0x00_00_00_20_00,
ManageMessages = 0x00_00_00_20_00,
/// <summary>
/// Allows links sent by users with this permission will be auto-embedded.
/// </summary>
EmbedLinks = 0x00_00_00_40_00,
EmbedLinks = 0x00_00_00_40_00,
/// <summary>
/// Allows for uploading images and files.
/// </summary>
AttachFiles = 0x00_00_00_80_00,
AttachFiles = 0x00_00_00_80_00,
/// <summary>
/// Allows for reading of message history.
/// </summary>
ReadMessageHistory = 0x00_00_01_00_00,
ReadMessageHistory = 0x00_00_01_00_00,
/// <summary>
/// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all
/// online users in a channel.
/// </summary>
MentionEveryone = 0x00_00_02_00_00,
MentionEveryone = 0x00_00_02_00_00,
/// <summary>
/// Allows the usage of custom emojis from other servers.
/// </summary>
UseExternalEmojis = 0x00_00_04_00_00,
UseExternalEmojis = 0x00_00_04_00_00,

// Voice
/// <summary>
/// Allows for joining of a voice channel.
/// </summary>
Connect = 0x00_00_10_00_00,
Connect = 0x00_00_10_00_00,
/// <summary>
/// Allows for speaking in a voice channel.
/// </summary>
Speak = 0x00_00_20_00_00,
Speak = 0x00_00_20_00_00,
/// <summary>
/// Allows for muting members in a voice channel.
/// </summary>
MuteMembers = 0x00_00_40_00_00,
MuteMembers = 0x00_00_40_00_00,
/// <summary>
/// Allows for deafening of members in a voice channel.
/// </summary>
DeafenMembers = 0x00_00_80_00_00,
DeafenMembers = 0x00_00_80_00_00,
/// <summary>
/// Allows for moving of members between voice channels.
/// </summary>
MoveMembers = 0x00_01_00_00_00,
MoveMembers = 0x00_01_00_00_00,
/// <summary>
/// Allows for using voice-activity-detection in a voice channel.
/// </summary>
UseVAD = 0x00_02_00_00_00,
UseVAD = 0x00_02_00_00_00,

/// <summary>
/// Allows for using priority speaker in a voice channel.
/// </summary>
PrioritySpeaker = 0x00_00_00_01_00,
PrioritySpeaker = 0x00_00_00_01_00,

/// <summary>
/// Allows video streaming in a voice channel.
/// </summary>
Stream = 0x00_00_00_02_00,
Stream = 0x00_00_00_02_00,

// More General
/// <summary>
/// Allows management and editing of roles.
/// </summary>
ManageRoles = 0x00_10_00_00_00,
ManageRoles = 0x00_10_00_00_00,
/// <summary>
/// Allows management and editing of webhooks.
/// </summary>
ManageWebhooks = 0x00_20_00_00_00,
ManageWebhooks = 0x00_20_00_00_00,

/// <summary>
/// Allows management and editing of emojis.
/// </summary>
ManageEmojis = 0x00_40_00_00_00,
ManageEmojis = 0x00_40_00_00_00,

/// <summary>
/// Allows members to use slash commands in text channels.
@@ -118,12 +118,12 @@ namespace Discord
/// <summary>
/// Allows for requesting to speak in stage channels. (This permission is under active development and may be changed or removed.)
/// </summary>
RequestToSpeak = 0x01_00_00_00_00,
RequestToSpeak = 0x01_00_00_00_00,

/// <summary>
/// Allows for deleting and archiving threads, and viewing all private threads
/// </summary>
ManageThreads = 0x04_00_00_00_00,
ManageThreads = 0x04_00_00_00_00,

/// <summary>
/// Allows for creating public threads.


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

@@ -10,7 +10,7 @@ namespace Discord
/// <summary>
/// Allows creation of instant invites.
/// </summary>
CreateInstantInvite = 0x00_00_00_01,
CreateInstantInvite = 0x00_00_00_01,
/// <summary>
/// Allows kicking members.
/// </summary>
@@ -18,7 +18,7 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
KickMembers = 0x00_00_00_02,
KickMembers = 0x00_00_00_02,
/// <summary>
/// Allows banning members.
/// </summary>
@@ -26,7 +26,7 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
BanMembers = 0x00_00_00_04,
BanMembers = 0x00_00_00_04,
/// <summary>
/// Allows all permissions and bypasses channel permission overwrites.
/// </summary>
@@ -34,7 +34,7 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
Administrator = 0x00_00_00_08,
Administrator = 0x00_00_00_08,
/// <summary>
/// Allows management and editing of channels.
/// </summary>
@@ -42,7 +42,7 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageChannels = 0x00_00_00_10,
ManageChannels = 0x00_00_00_10,
/// <summary>
/// Allows management and editing of the guild.
/// </summary>
@@ -50,33 +50,33 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageGuild = 0x00_00_00_20,
ManageGuild = 0x00_00_00_20,
/// <summary>
/// Allows for viewing of guild insights
/// </summary>
ViewGuildInsights = 0x00_08_00_00,
ViewGuildInsights = 0x00_08_00_00,

// Text
/// <summary>
/// Allows for the addition of reactions to messages.
/// </summary>
AddReactions = 0x00_00_00_40,
/// <summary>
/// Allows for viewing of audit logs.
/// </summary>
ViewAuditLog = 0x00_00_00_80,
/// <summary>
/// Allows for the addition of reactions to messages.
/// </summary>
AddReactions = 0x00_00_00_40,
/// <summary>
/// Allows for viewing of audit logs.
/// </summary>
ViewAuditLog = 0x00_00_00_80,
/// <summary>
/// Allows guild members to view a channel, which includes reading messages in text channels.
/// </summary>
ViewChannel = 0x00_00_04_00,
ViewChannel = 0x00_00_04_00,
/// <summary>
/// Allows for sending messages in a channel
/// </summary>
SendMessages = 0x00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.
/// </summary>
SendTTSMessages = 0x00_00_10_00,
SendMessages = 0x00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.
/// </summary>
SendTTSMessages = 0x00_00_10_00,
/// <summary>
/// Allows for deletion of other users messages.
/// </summary>
@@ -84,55 +84,55 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageMessages = 0x00_00_20_00,
ManageMessages = 0x00_00_20_00,
/// <summary>
/// Allows links sent by users with this permission will be auto-embedded.
/// </summary>
EmbedLinks = 0x00_00_40_00,
EmbedLinks = 0x00_00_40_00,
/// <summary>
/// Allows for uploading images and files.
/// </summary>
AttachFiles = 0x00_00_80_00,
AttachFiles = 0x00_00_80_00,
/// <summary>
/// Allows for reading of message history.
/// </summary>
ReadMessageHistory = 0x00_01_00_00,
ReadMessageHistory = 0x00_01_00_00,
/// <summary>
/// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all
/// online users in a channel.
/// </summary>
MentionEveryone = 0x00_02_00_00,
MentionEveryone = 0x00_02_00_00,
/// <summary>
/// Allows the usage of custom emojis from other servers.
/// </summary>
UseExternalEmojis = 0x00_04_00_00,
UseExternalEmojis = 0x00_04_00_00,


// Voice
/// <summary>
/// Allows for joining of a voice channel.
/// </summary>
Connect = 0x00_10_00_00,
Connect = 0x00_10_00_00,
/// <summary>
/// Allows for speaking in a voice channel.
/// </summary>
Speak = 0x00_20_00_00,
Speak = 0x00_20_00_00,
/// <summary>
/// Allows for muting members in a voice channel.
/// </summary>
MuteMembers = 0x00_40_00_00,
MuteMembers = 0x00_40_00_00,
/// <summary>
/// Allows for deafening of members in a voice channel.
/// </summary>
DeafenMembers = 0x00_80_00_00,
DeafenMembers = 0x00_80_00_00,
/// <summary>
/// Allows for moving of members between voice channels.
/// </summary>
MoveMembers = 0x01_00_00_00,
MoveMembers = 0x01_00_00_00,
/// <summary>
/// Allows for using voice-activity-detection in a voice channel.
/// </summary>
UseVAD = 0x02_00_00_00,
UseVAD = 0x02_00_00_00,
/// <summary>
/// Allows for using priority speaker in a voice channel.
/// </summary>
@@ -140,17 +140,17 @@ namespace Discord
/// <summary>
/// Allows video streaming in a voice channel.
/// </summary>
Stream = 0x00_00_02_00,
Stream = 0x00_00_02_00,

// General 2
/// <summary>
/// Allows for modification of own nickname.
/// </summary>
ChangeNickname = 0x04_00_00_00,
ChangeNickname = 0x04_00_00_00,
/// <summary>
/// Allows for modification of other users nicknames.
/// </summary>
ManageNicknames = 0x08_00_00_00,
ManageNicknames = 0x08_00_00_00,
/// <summary>
/// Allows management and editing of roles.
/// </summary>
@@ -158,7 +158,7 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageRoles = 0x10_00_00_00,
ManageRoles = 0x10_00_00_00,
/// <summary>
/// Allows management and editing of webhooks.
/// </summary>
@@ -166,7 +166,7 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageWebhooks = 0x20_00_00_00,
ManageWebhooks = 0x20_00_00_00,
/// <summary>
/// Allows management and editing of emojis and stickers.
/// </summary>
@@ -182,7 +182,7 @@ namespace Discord
/// <summary>
/// Allows for requesting to speak in stage channels.
/// </summary>
RequestToSpeak = 0x01_00_00_00_00,
RequestToSpeak = 0x01_00_00_00_00,
/// <summary>
/// Allows for creating, editing, and deleting guild scheduled events.
/// </summary>
@@ -194,7 +194,7 @@ namespace Discord
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageThreads = 0x04_00_00_00_00,
ManageThreads = 0x04_00_00_00_00,
/// <summary>
/// Allows for creating public threads.
/// </summary>
@@ -206,7 +206,7 @@ namespace Discord
/// <summary>
/// Allows the usage of custom stickers from other servers.
/// </summary>
UseExternalStickers = 0x20_00_00_00_00,
UseExternalStickers = 0x20_00_00_00_00,
/// <summary>
/// Allows for sending messages in threads.
/// </summary>


+ 1
- 1
src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs View File

@@ -281,7 +281,7 @@ namespace Discord
manageThreads: manageThreads,
createPublicThreads: createPublicThreads,
createPrivateThreads: createPrivateThreads,
useExternalStickers: useExternalStickers,
useExternalStickers: useExternalStickers,
sendMessagesInThreads: sendMessagesInThreads,
startEmbeddedActivities: startEmbeddedActivities,
moderateMembers: moderateMembers)


+ 16
- 15
src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs View File

@@ -19,7 +19,7 @@ namespace Discord
/// Gets a <see cref="OverwritePermissions" /> that grants all permissions for the given channel.
/// </summary>
/// <exception cref="ArgumentException">Unknown channel type.</exception>
public static OverwritePermissions AllowAll(IChannel channel)
public static OverwritePermissions AllowAll(IChannel channel)
=> new OverwritePermissions(ChannelPermissions.All(channel).RawValue, 0);
/// <summary>
/// Gets a <see cref="OverwritePermissions" /> that denies all permissions for the given channel.
@@ -116,24 +116,24 @@ namespace Discord

private OverwritePermissions(ulong allowValue, ulong denyValue,
PermValue? createInstantInvite = null,
PermValue? manageChannel = null,
PermValue? manageChannel = null,
PermValue? addReactions = null,
PermValue? viewChannel = null,
PermValue? sendMessages = null,
PermValue? sendTTSMessages = null,
PermValue? manageMessages = null,
PermValue? manageMessages = null,
PermValue? embedLinks = null,
PermValue? attachFiles = null,
PermValue? readMessageHistory = null,
PermValue? mentionEveryone = null,
PermValue? mentionEveryone = null,
PermValue? useExternalEmojis = null,
PermValue? connect = null,
PermValue? speak = null,
PermValue? muteMembers = null,
PermValue? muteMembers = null,
PermValue? deafenMembers = null,
PermValue? moveMembers = null,
PermValue? useVoiceActivation = null,
PermValue? manageRoles = null,
PermValue? manageRoles = null,
PermValue? manageWebhooks = null,
PermValue? prioritySpeaker = null,
PermValue? stream = null,
@@ -194,7 +194,7 @@ namespace Discord
PermValue viewChannel = PermValue.Inherit,
PermValue sendMessages = PermValue.Inherit,
PermValue sendTTSMessages = PermValue.Inherit,
PermValue manageMessages = PermValue.Inherit,
PermValue manageMessages = PermValue.Inherit,
PermValue embedLinks = PermValue.Inherit,
PermValue attachFiles = PermValue.Inherit,
PermValue readMessageHistory = PermValue.Inherit,
@@ -221,11 +221,12 @@ namespace Discord
PermValue useExternalStickers = PermValue.Inherit,
PermValue sendMessagesInThreads = PermValue.Inherit,
PermValue startEmbeddedActivities = PermValue.Inherit)
: this(0, 0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages,
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers,
: this(0, 0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages,
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers,
moveMembers, useVoiceActivation, manageRoles, manageWebhooks, prioritySpeaker, stream, useSlashCommands, useApplicationCommands,
requestToSpeak, manageThreads, createPublicThreads, createPrivateThreads, usePublicThreads, usePrivateThreads, useExternalStickers,
sendMessagesInThreads, startEmbeddedActivities) { }
sendMessagesInThreads, startEmbeddedActivities)
{ }

/// <summary>
/// Initializes a new <see cref="OverwritePermissions" /> from the current one, changing the provided
@@ -238,11 +239,11 @@ namespace Discord
PermValue? viewChannel = null,
PermValue? sendMessages = null,
PermValue? sendTTSMessages = null,
PermValue? manageMessages = null,
PermValue? manageMessages = null,
PermValue? embedLinks = null,
PermValue? attachFiles = null,
PermValue? readMessageHistory = null,
PermValue? mentionEveryone = null,
PermValue? mentionEveryone = null,
PermValue? useExternalEmojis = null,
PermValue? connect = null,
PermValue? speak = null,
@@ -265,8 +266,8 @@ namespace Discord
PermValue? useExternalStickers = null,
PermValue? sendMessagesInThreads = null,
PermValue? startEmbeddedActivities = null)
=> new OverwritePermissions(AllowValue, DenyValue, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages,
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers,
=> new OverwritePermissions(AllowValue, DenyValue, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages,
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers,
moveMembers, useVoiceActivation, manageRoles, manageWebhooks, prioritySpeaker, stream, useSlashCommands, useApplicationCommands,
requestToSpeak, manageThreads, createPublicThreads, createPrivateThreads, usePublicThreads, usePrivateThreads, useExternalStickers,
sendMessagesInThreads, startEmbeddedActivities);
@@ -305,7 +306,7 @@ namespace Discord
}

public override string ToString() => $"Allow {AllowValue}, Deny {DenyValue}";
private string DebuggerDisplay =>
private string DebuggerDisplay =>
$"Allow {string.Join(", ", ToAllowList())}, " +
$"Deny {string.Join(", ", ToDenyList())}";
}


+ 5
- 0
src/Discord.Net.Core/Entities/Users/IThreadUser.cs View File

@@ -21,5 +21,10 @@ namespace Discord
/// Gets the guild this thread was created in.
/// </summary>
IGuild Guild { get; }

/// <summary>
/// Gets the <see cref="IGuildUser"/> on the server this thread was created in.
/// </summary>
IGuildUser GuildUser { get; }
}
}

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

@@ -10,7 +10,7 @@ namespace Discord
/// <summary>
/// Gets the identifier of this user's avatar.
/// </summary>
string AvatarId { get; }
string AvatarId { get; }
/// <summary>
/// Gets the avatar URL for this user.
/// </summary>


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

@@ -29,7 +29,7 @@ namespace Discord
/// <summary>
/// Gets the channel for this webhook.
/// </summary>
ITextChannel Channel { get; }
IIntegrationChannel Channel { get; }
/// <summary>
/// Gets the ID of the channel for this webhook.
/// </summary>


+ 1
- 1
src/Discord.Net.Core/Extensions/TaskCompletionSourceExtensions.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;

namespace Discord


+ 1
- 1
src/Discord.Net.Core/Extensions/UserExtensions.cs View File

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

namespace Discord
{


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

@@ -80,7 +80,7 @@ namespace Discord

return result.ToString();
}
/// <summary>
/// Formats a string as a block quote.
/// </summary>


+ 1
- 1
src/Discord.Net.Core/Logging/LogManager.cs View File

@@ -34,7 +34,7 @@ namespace Discord.Logging
try
{
if (severity <= Level)
await _messageEvent.InvokeAsync(new LogMessage(severity, source, message, ex)).ConfigureAwait(false);
await _messageEvent.InvokeAsync(new LogMessage(severity, source, message, ex)).ConfigureAwait(false);
}
catch
{


+ 5
- 14
src/Discord.Net.Core/Logging/LogMessage.cs View File

@@ -52,7 +52,7 @@ namespace Discord
Message = message;
Exception = exception;
}
public override string ToString() => ToString();
public string ToString(StringBuilder builder = null, bool fullException = true, bool prependTimestamp = true, DateTimeKind timestampKind = DateTimeKind.Local, int? padSource = 11)
{
@@ -60,9 +60,9 @@ namespace Discord
string message = Message;
string exMessage = fullException ? Exception?.ToString() : Exception?.Message;

int maxLength = 1 +
int maxLength = 1 +
(prependTimestamp ? 8 : 0) + 1 +
(padSource.HasValue ? padSource.Value : sourceName?.Length ?? 0) + 1 +
(padSource.HasValue ? padSource.Value : sourceName?.Length ?? 0) + 1 +
(message?.Length ?? 0) +
(exMessage?.Length ?? 0) + 3;

@@ -81,17 +81,8 @@ namespace Discord
now = DateTime.UtcNow;
else
now = DateTime.Now;
if (now.Hour < 10)
builder.Append('0');
builder.Append(now.Hour);
builder.Append(':');
if (now.Minute < 10)
builder.Append('0');
builder.Append(now.Minute);
builder.Append(':');
if (now.Second < 10)
builder.Append('0');
builder.Append(now.Second);
string format = "HH:mm:ss";
builder.Append(now.ToString(format));
builder.Append(' ');
}
if (sourceName != null)


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

@@ -9,7 +9,7 @@ namespace Discord.Net
public ApplicationCommandException(HttpException httpError)
: base(httpError.HttpCode, httpError.Request, httpError.DiscordCode, httpError.Reason, httpError.Errors.ToArray())
{
}
}
}

+ 2
- 2
src/Discord.Net.Core/Net/BucketId.cs View File

@@ -99,7 +99,7 @@ namespace Discord.Net
=> Equals(obj as BucketId);

public override int GetHashCode()
=> IsHashBucket ? (BucketHash, string.Join("/", MajorParameters.Select(x => x.Value))).GetHashCode() : (HttpMethod, Endpoint).GetHashCode();
=> IsHashBucket ? (BucketHash, string.Join("/", MajorParameters.Select(x => x.Value))).GetHashCode() : (HttpMethod, Endpoint).GetHashCode();

public override string ToString()
=> GetBucketHash() ?? GetUniqueEndpoint();
@@ -113,6 +113,6 @@ namespace Discord.Net
if (GetType() != other.GetType())
return false;
return ToString() == other.ToString();
}
}
}
}

+ 1
- 1
src/Discord.Net.Core/Net/Rest/RestClientProvider.cs View File

@@ -1,4 +1,4 @@
namespace Discord.Net.Rest
namespace Discord.Net.Rest
{
public delegate IRestClient RestClientProvider(string baseUrl);
}

+ 1
- 1
src/Discord.Net.Core/Net/Rest/RestResponse.cs View File

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



Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save