Browse Source

Merge branch 'dev' into webhooks

pull/843/head
Christopher F GitHub 7 years ago
parent
commit
e468569fa8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 936 additions and 112 deletions
  1. +2
    -2
      Discord.Net.targets
  2. +2
    -2
      README.md
  3. +1
    -1
      appveyor.yml
  4. +1
    -1
      docs/guides/getting_started/intro.md
  5. +4
    -3
      docs/guides/getting_started/samples/intro/structure.cs
  6. +1
    -1
      docs/guides/getting_started/samples/project.csproj
  7. +4
    -5
      docs/guides/voice/samples/audio_create_ffmpeg.cs
  8. +7
    -5
      docs/guides/voice/samples/audio_ffmpeg.cs
  9. +1
    -1
      docs/guides/voice/samples/joining_audio.cs
  10. +1
    -1
      src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs
  11. +2
    -2
      src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs
  12. +3
    -5
      src/Discord.Net.Commands/Attributes/Preconditions/RequireBotPermissionAttribute.cs
  13. +1
    -1
      src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs
  14. +1
    -1
      src/Discord.Net.Commands/Attributes/Preconditions/RequireNsfwAttribute.cs
  15. +1
    -1
      src/Discord.Net.Commands/Attributes/Preconditions/RequireOwnerAttribute.cs
  16. +3
    -5
      src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs
  17. +3
    -3
      src/Discord.Net.Commands/CommandParser.cs
  18. +10
    -7
      src/Discord.Net.Commands/Info/CommandInfo.cs
  19. +3
    -3
      src/Discord.Net.Commands/Info/ParameterInfo.cs
  20. +1
    -1
      src/Discord.Net.Commands/Readers/ChannelTypeReader.cs
  21. +1
    -1
      src/Discord.Net.Commands/Readers/EnumTypeReader.cs
  22. +1
    -1
      src/Discord.Net.Commands/Readers/MessageTypeReader.cs
  23. +2
    -2
      src/Discord.Net.Commands/Readers/NullableTypeReader.cs
  24. +1
    -1
      src/Discord.Net.Commands/Readers/PrimitiveTypeReader.cs
  25. +1
    -1
      src/Discord.Net.Commands/Readers/RoleTypeReader.cs
  26. +1
    -1
      src/Discord.Net.Commands/Readers/TypeReader.cs
  27. +1
    -1
      src/Discord.Net.Commands/Readers/UserTypeReader.cs
  28. +1
    -1
      src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs
  29. +10
    -0
      src/Discord.Net.Core/Entities/Emotes/EmoteProperties.cs
  30. +9
    -0
      src/Discord.Net.Core/Entities/Guilds/IGuild.cs
  31. +1
    -1
      src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
  32. +24
    -19
      src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
  33. +1
    -1
      src/Discord.Net.Core/Utils/Optional.cs
  34. +2
    -1
      src/Discord.Net.Core/Utils/Preconditions.cs
  35. +16
    -0
      src/Discord.Net.Rest/API/Rest/CreateGuildEmoteParams.cs
  36. +14
    -0
      src/Discord.Net.Rest/API/Rest/ModifyGuildEmoteParams.cs
  37. +44
    -0
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  38. +2
    -2
      src/Discord.Net.Rest/Entities/Channels/RestChannel.cs
  39. +5
    -5
      src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs
  40. +41
    -0
      src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
  41. +10
    -0
      src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
  42. +35
    -0
      src/Discord.Net.Rest/Extensions/EmbedBuilderExtensions.cs
  43. +1
    -1
      src/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs
  44. +3
    -3
      src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs
  45. +10
    -0
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
  46. +19
    -19
      src/Discord.Net/Discord.Net.nuspec
  47. +324
    -0
      test/Discord.Net.Tests/Tests.ChannelPermissions.cs
  48. +304
    -0
      test/Discord.Net.Tests/Tests.GuildPermissions.cs

+ 2
- 2
Discord.Net.targets View File

@@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<VersionPrefix>2.0.0-alpha</VersionPrefix>
<VersionSuffix></VersionSuffix>
<VersionPrefix>2.0.0</VersionPrefix>
<VersionSuffix>beta</VersionSuffix>
<Authors>RogueException</Authors> <Authors>RogueException</Authors>
<PackageTags>discord;discordapp</PackageTags> <PackageTags>discord;discordapp</PackageTags>
<PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl> <PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl>


+ 2
- 2
README.md View File

@@ -2,11 +2,11 @@
[![NuGet](https://img.shields.io/nuget/vpre/Discord.Net.svg?maxAge=2592000?style=plastic)](https://www.nuget.org/packages/Discord.Net) [![NuGet](https://img.shields.io/nuget/vpre/Discord.Net.svg?maxAge=2592000?style=plastic)](https://www.nuget.org/packages/Discord.Net)
[![MyGet](https://img.shields.io/myget/discord-net/vpre/Discord.Net.svg)](https://www.myget.org/feed/Packages/discord-net) [![MyGet](https://img.shields.io/myget/discord-net/vpre/Discord.Net.svg)](https://www.myget.org/feed/Packages/discord-net)
[![Build status](https://ci.appveyor.com/api/projects/status/5sb7n8a09w9clute/branch/dev?svg=true)](https://ci.appveyor.com/project/RogueException/discord-net/branch/dev) [![Build status](https://ci.appveyor.com/api/projects/status/5sb7n8a09w9clute/branch/dev?svg=true)](https://ci.appveyor.com/project/RogueException/discord-net/branch/dev)
[![Discord](https://discordapp.com/api/guilds/81384788765712384/widget.png)](https://discord.gg/0SBTUU1wZTVjAMPx)
[![Discord](https://discordapp.com/api/guilds/81384788765712384/widget.png)](https://discord.gg/jkrBmQR)


An unofficial .NET API Wrapper for the Discord client (http://discordapp.com). An unofficial .NET API Wrapper for the Discord client (http://discordapp.com).


Check out the [documentation](https://discord.foxbot.me/docs/) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx).
Check out the [documentation](https://discord.foxbot.me/docs/) or join the [Discord API Chat](https://discord.gg/jkrBmQR).


## Installation ## Installation
### Stable (NuGet) ### Stable (NuGet)


+ 1
- 1
appveyor.yml View File

@@ -34,7 +34,7 @@ after_build:
if ($Env:APPVEYOR_REPO_TAG -eq "true") { if ($Env:APPVEYOR_REPO_TAG -eq "true") {
nuget pack src\Discord.Net\Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="" nuget pack src\Discord.Net\Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix=""
} else { } else {
nuget pack src\Discord.Net\Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="-build-$Env:BUILD"
nuget pack src\Discord.Net\Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="-$Env:BUILD"
} }
- ps: Get-ChildItem artifacts\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } - ps: Get-ChildItem artifacts\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }




+ 1
- 1
docs/guides/getting_started/intro.md View File

@@ -74,7 +74,7 @@ async main.


[!code-csharp[Async Context](samples/intro/async-context.cs)] [!code-csharp[Async Context](samples/intro/async-context.cs)]


As a result of this, your program will now start and immidiately
As a result of this, your program will now start and immediately
jump into an async context. This will allow us to create a connection jump into an async context. This will allow us to create a connection
to Discord later on without needing to worry about setting up the to Discord later on without needing to worry about setting up the
correct async implementation. correct async implementation.


+ 4
- 3
docs/guides/getting_started/samples/intro/structure.cs View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Reflection; using System.Reflection;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Discord; using Discord;
@@ -80,7 +81,7 @@ class Program


private async Task MainAsync() private async Task MainAsync()
{ {
// Centralize the logic for commands into a seperate method.
// Centralize the logic for commands into a separate method.
await InitCommands(); await InitCommands();


// Login and connect. // Login and connect.
@@ -88,7 +89,7 @@ class Program
await _client.StartAsync(); await _client.StartAsync();


// Wait infinitely so your bot actually stays connected. // Wait infinitely so your bot actually stays connected.
await Task.Delay(-1);
await Task.Delay(Timeout.Infinite);
} }


private IServiceProvider _services; private IServiceProvider _services;
@@ -138,7 +139,7 @@ class Program
var context = new SocketCommandContext(_client, msg); var context = new SocketCommandContext(_client, msg);
// Execute the command. (result does not indicate a return value, // Execute the command. (result does not indicate a return value,
// rather an object stating if the command executed succesfully).
// rather an object stating if the command executed successfully).
var result = await _commands.ExecuteAsync(context, pos, _services); var result = await _commands.ExecuteAsync(context, pos, _services);


// Uncomment the following lines if you want the bot // Uncomment the following lines if you want the bot


+ 1
- 1
docs/guides/getting_started/samples/project.csproj View File

@@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net" Version="1.0.0-rc-00617" />
<PackageReference Include="Discord.Net" Version="1.*" />
</ItemGroup> </ItemGroup>


</Project> </Project>

+ 4
- 5
docs/guides/voice/samples/audio_create_ffmpeg.cs View File

@@ -1,11 +1,10 @@
private Process CreateStream(string path) private Process CreateStream(string path)
{ {
var ffmpeg = new ProcessStartInfo
return Process.Start(new ProcessStartInfo
{ {
FileName = "ffmpeg", FileName = "ffmpeg",
Arguments = $"-i {path} -ac 2 -f s16le -ar 48000 pipe:1",
Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1",
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = true, RedirectStandardOutput = true,
};
return Process.Start(ffmpeg);
}
});
}

+ 7
- 5
docs/guides/voice/samples/audio_ffmpeg.cs View File

@@ -1,9 +1,11 @@
private async Task SendAsync(IAudioClient client, string path) private async Task SendAsync(IAudioClient client, string path)
{ {
// Create FFmpeg using the previous example // Create FFmpeg using the previous example
var ffmpeg = CreateStream(path);
var output = ffmpeg.StandardOutput.BaseStream;
var discord = client.CreatePCMStream(AudioApplication.Mixed);
await output.CopyToAsync(discord);
await discord.FlushAsync();
using (var ffmpeg = CreateStream(path))
using (var output = ffmpeg.StandardOutput.BaseStream)
using (var discord = client.CreatePCMStream(AudioApplication.Mixed))
{
try { await output.CopyToAsync(discord); }
finally { await discord.FlushAsync(); }
}
} }

+ 1
- 1
docs/guides/voice/samples/joining_audio.cs View File

@@ -7,4 +7,4 @@ public async Task JoinChannel(IVoiceChannel channel = null)


// For the next step with transmitting audio, you would want to pass this Audio Client in to a service. // For the next step with transmitting audio, you would want to pass this Audio Client in to a service.
var audioClient = await channel.ConnectAsync(); var audioClient = await channel.ConnectAsync();
}
}

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

@@ -7,6 +7,6 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)]
public abstract class ParameterPreconditionAttribute : Attribute public abstract class ParameterPreconditionAttribute : Attribute
{ {
public abstract Task<PreconditionResult> CheckPermissions(ICommandContext context, ParameterInfo parameter, object value, IServiceProvider services);
public abstract Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, ParameterInfo parameter, object value, IServiceProvider services);
} }
} }

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

@@ -8,11 +8,11 @@ namespace Discord.Commands
{ {
/// <summary> /// <summary>
/// Specify a group that this precondition belongs to. Preconditions of the same group require only one /// Specify a group that this precondition belongs to. Preconditions of the same group require only one
/// of the preconditions to pass in order to be successful (A || B). Specifying <see cref="Group"/> = <see cref="null"/>
/// of the preconditions to pass in order to be successful (A || B). Specifying <see cref="Group"/> = <see langword="null"/>
/// or not at all will require *all* preconditions to pass, just like normal (A &amp;&amp; B). /// or not at all will require *all* preconditions to pass, just like normal (A &amp;&amp; B).
/// </summary> /// </summary>
public string Group { get; set; } = null; public string Group { get; set; } = null;


public abstract Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services);
public abstract Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services);
} }
} }

+ 3
- 5
src/Discord.Net.Commands/Attributes/Preconditions/RequireBotPermissionAttribute.cs View File

@@ -41,7 +41,7 @@ namespace Discord.Commands
GuildPermission = null; GuildPermission = null;
} }


public override async Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{ {
IGuildUser guildUser = null; IGuildUser guildUser = null;
if (context.Guild != null) if (context.Guild != null)
@@ -57,13 +57,11 @@ namespace Discord.Commands


if (ChannelPermission.HasValue) if (ChannelPermission.HasValue)
{ {
var guildChannel = context.Channel as IGuildChannel;

ChannelPermissions perms; ChannelPermissions perms;
if (guildChannel != null)
if (context.Channel is IGuildChannel guildChannel)
perms = guildUser.GetPermissions(guildChannel); perms = guildUser.GetPermissions(guildChannel);
else else
perms = ChannelPermissions.All(guildChannel);
perms = ChannelPermissions.All(context.Channel);


if (!perms.Has(ChannelPermission.Value)) if (!perms.Has(ChannelPermission.Value))
return PreconditionResult.FromError($"Bot requires channel permission {ChannelPermission.Value}"); return PreconditionResult.FromError($"Bot requires channel permission {ChannelPermission.Value}");


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

@@ -38,7 +38,7 @@ namespace Discord.Commands
Contexts = contexts; Contexts = contexts;
} }


public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{ {
bool isValid = false; bool isValid = false;




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

@@ -9,7 +9,7 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class RequireNsfwAttribute : PreconditionAttribute public class RequireNsfwAttribute : PreconditionAttribute
{ {
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{ {
if (context.Channel is ITextChannel text && text.IsNsfw) if (context.Channel is ITextChannel text && text.IsNsfw)
return Task.FromResult(PreconditionResult.FromSuccess()); return Task.FromResult(PreconditionResult.FromSuccess());


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

@@ -12,7 +12,7 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class RequireOwnerAttribute : PreconditionAttribute public class RequireOwnerAttribute : PreconditionAttribute
{ {
public override async Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{ {
switch (context.Client.TokenType) switch (context.Client.TokenType)
{ {


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

@@ -42,7 +42,7 @@ namespace Discord.Commands
GuildPermission = null; GuildPermission = null;
} }
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{ {
var guildUser = context.User as IGuildUser; var guildUser = context.User as IGuildUser;


@@ -56,13 +56,11 @@ namespace Discord.Commands


if (ChannelPermission.HasValue) if (ChannelPermission.HasValue)
{ {
var guildChannel = context.Channel as IGuildChannel;

ChannelPermissions perms; ChannelPermissions perms;
if (guildChannel != null)
if (context.Channel is IGuildChannel guildChannel)
perms = guildUser.GetPermissions(guildChannel); perms = guildUser.GetPermissions(guildChannel);
else else
perms = ChannelPermissions.All(guildChannel);
perms = ChannelPermissions.All(context.Channel);


if (!perms.Has(ChannelPermission.Value)) if (!perms.Has(ChannelPermission.Value))
return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}")); return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}"));


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

@@ -14,7 +14,7 @@ namespace Discord.Commands
QuotedParameter QuotedParameter
} }
public static async Task<ParseResult> ParseArgs(CommandInfo command, ICommandContext context, IServiceProvider services, string input, int startPos)
public static async Task<ParseResult> ParseArgsAsync(CommandInfo command, ICommandContext context, IServiceProvider services, string input, int startPos)
{ {
ParameterInfo curParam = null; ParameterInfo curParam = null;
StringBuilder argBuilder = new StringBuilder(input.Length); StringBuilder argBuilder = new StringBuilder(input.Length);
@@ -111,7 +111,7 @@ namespace Discord.Commands
if (curParam == null) if (curParam == null)
return ParseResult.FromError(CommandError.BadArgCount, "The input text has too many parameters."); return ParseResult.FromError(CommandError.BadArgCount, "The input text has too many parameters.");


var typeReaderResult = await curParam.Parse(context, argString, services).ConfigureAwait(false);
var typeReaderResult = await curParam.ParseAsync(context, argString, services).ConfigureAwait(false);
if (!typeReaderResult.IsSuccess && typeReaderResult.Error != CommandError.MultipleMatches) if (!typeReaderResult.IsSuccess && typeReaderResult.Error != CommandError.MultipleMatches)
return ParseResult.FromError(typeReaderResult); return ParseResult.FromError(typeReaderResult);


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


if (curParam != null && curParam.IsRemainder) if (curParam != null && curParam.IsRemainder)
{ {
var typeReaderResult = await curParam.Parse(context, argBuilder.ToString(), services).ConfigureAwait(false);
var typeReaderResult = await curParam.ParseAsync(context, argBuilder.ToString(), services).ConfigureAwait(false);
if (!typeReaderResult.IsSuccess) if (!typeReaderResult.IsSuccess)
return ParseResult.FromError(typeReaderResult); return ParseResult.FromError(typeReaderResult);
argList.Add(typeReaderResult); argList.Add(typeReaderResult);


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

@@ -78,7 +78,7 @@ namespace Discord.Commands
{ {
foreach (PreconditionAttribute precondition in preconditionGroup) foreach (PreconditionAttribute precondition in preconditionGroup)
{ {
var result = await precondition.CheckPermissions(context, this, services).ConfigureAwait(false);
var result = await precondition.CheckPermissionsAsync(context, this, services).ConfigureAwait(false);
if (!result.IsSuccess) if (!result.IsSuccess)
return result; return result;
} }
@@ -87,7 +87,7 @@ namespace Discord.Commands
{ {
var results = new List<PreconditionResult>(); var results = new List<PreconditionResult>();
foreach (PreconditionAttribute precondition in preconditionGroup) foreach (PreconditionAttribute precondition in preconditionGroup)
results.Add(await precondition.CheckPermissions(context, this, services).ConfigureAwait(false));
results.Add(await precondition.CheckPermissionsAsync(context, this, services).ConfigureAwait(false));


if (!results.Any(p => p.IsSuccess)) if (!results.Any(p => p.IsSuccess))
return PreconditionGroupResult.FromError($"{type} precondition group {preconditionGroup.Key} failed.", results); return PreconditionGroupResult.FromError($"{type} precondition group {preconditionGroup.Key} failed.", results);
@@ -117,7 +117,7 @@ namespace Discord.Commands
return ParseResult.FromError(preconditionResult); return ParseResult.FromError(preconditionResult);


string input = searchResult.Text.Substring(startIndex); string input = searchResult.Text.Substring(startIndex);
return await CommandParser.ParseArgs(this, context, services, input, 0).ConfigureAwait(false);
return await CommandParser.ParseArgsAsync(this, context, services, input, 0).ConfigureAwait(false);
} }


public Task<IResult> ExecuteAsync(ICommandContext context, ParseResult parseResult, IServiceProvider services) public Task<IResult> ExecuteAsync(ICommandContext context, ParseResult parseResult, IServiceProvider services)
@@ -163,11 +163,11 @@ namespace Discord.Commands
switch (RunMode) switch (RunMode)
{ {
case RunMode.Sync: //Always sync case RunMode.Sync: //Always sync
return await ExecuteAsyncInternal(context, args, services).ConfigureAwait(false);
return await ExecuteAsyncInternalAsync(context, args, services).ConfigureAwait(false);
case RunMode.Async: //Always async case RunMode.Async: //Always async
var t2 = Task.Run(async () => var t2 = Task.Run(async () =>
{ {
await ExecuteAsyncInternal(context, args, services).ConfigureAwait(false);
await ExecuteAsyncInternalAsync(context, args, services).ConfigureAwait(false);
}); });
break; break;
} }
@@ -179,7 +179,7 @@ namespace Discord.Commands
} }
} }


private async Task<IResult> ExecuteAsyncInternal(ICommandContext context, object[] args, IServiceProvider services)
private async Task<IResult> ExecuteAsyncInternalAsync(ICommandContext context, object[] args, IServiceProvider services)
{ {
await Module.Service._cmdLogger.DebugAsync($"Executing {GetLogText(context)}").ConfigureAwait(false); await Module.Service._cmdLogger.DebugAsync($"Executing {GetLogText(context)}").ConfigureAwait(false);
try try
@@ -199,10 +199,13 @@ namespace Discord.Commands
return result; return result;
} }
else else
{
await task.ConfigureAwait(false); await task.ConfigureAwait(false);
var result = ExecuteResult.FromSuccess();
await Module.Service._commandExecutedEvent.InvokeAsync(this, context, result).ConfigureAwait(false);
}


var executeResult = ExecuteResult.FromSuccess(); var executeResult = ExecuteResult.FromSuccess();
await Module.Service._commandExecutedEvent.InvokeAsync(this, context, executeResult).ConfigureAwait(false);
return executeResult; return executeResult;
} }
catch (Exception ex) catch (Exception ex)


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

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


foreach (var precondition in Preconditions) foreach (var precondition in Preconditions)
{ {
var result = await precondition.CheckPermissions(context, this, arg, services).ConfigureAwait(false);
var result = await precondition.CheckPermissionsAsync(context, this, arg, services).ConfigureAwait(false);
if (!result.IsSuccess) if (!result.IsSuccess)
return result; return result;
} }
@@ -56,10 +56,10 @@ namespace Discord.Commands
return PreconditionResult.FromSuccess(); return PreconditionResult.FromSuccess();
} }


public async Task<TypeReaderResult> Parse(ICommandContext context, string input, IServiceProvider services = null)
public async Task<TypeReaderResult> ParseAsync(ICommandContext context, string input, IServiceProvider services = null)
{ {
services = services ?? EmptyServiceProvider.Instance; services = services ?? EmptyServiceProvider.Instance;
return await _reader.Read(context, input, services).ConfigureAwait(false);
return await _reader.ReadAsync(context, input, services).ConfigureAwait(false);
} }


public override string ToString() => Name; public override string ToString() => Name;


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

@@ -9,7 +9,7 @@ namespace Discord.Commands
internal class ChannelTypeReader<T> : TypeReader internal class ChannelTypeReader<T> : TypeReader
where T : class, IChannel where T : class, IChannel
{ {
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{ {
if (context.Guild != null) if (context.Guild != null)
{ {


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

@@ -44,7 +44,7 @@ namespace Discord.Commands
_enumsByValue = byValueBuilder.ToImmutable(); _enumsByValue = byValueBuilder.ToImmutable();
} }


public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{ {
object enumValue; object enumValue;




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

@@ -7,7 +7,7 @@ namespace Discord.Commands
internal class MessageTypeReader<T> : TypeReader internal class MessageTypeReader<T> : TypeReader
where T : class, IMessage where T : class, IMessage
{ {
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{ {
ulong id; ulong id;




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

@@ -24,11 +24,11 @@ namespace Discord.Commands
_baseTypeReader = baseTypeReader; _baseTypeReader = baseTypeReader;
} }


public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{ {
if (string.Equals(input, "null", StringComparison.OrdinalIgnoreCase) || string.Equals(input, "nothing", StringComparison.OrdinalIgnoreCase)) if (string.Equals(input, "null", StringComparison.OrdinalIgnoreCase) || string.Equals(input, "nothing", StringComparison.OrdinalIgnoreCase))
return TypeReaderResult.FromSuccess(new T?()); return TypeReaderResult.FromSuccess(new T?());
return await _baseTypeReader.Read(context, input, services); ;
return await _baseTypeReader.ReadAsync(context, input, services);
} }
} }
} }

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

@@ -30,7 +30,7 @@ namespace Discord.Commands
_score = score; _score = score;
} }


public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{ {
if (_tryParse(input, out T value)) if (_tryParse(input, out T value))
return Task.FromResult(TypeReaderResult.FromSuccess(new TypeReaderValue(value, _score))); return Task.FromResult(TypeReaderResult.FromSuccess(new TypeReaderValue(value, _score)));


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

@@ -9,7 +9,7 @@ namespace Discord.Commands
internal class RoleTypeReader<T> : TypeReader internal class RoleTypeReader<T> : TypeReader
where T : class, IRole where T : class, IRole
{ {
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{ {
ulong id; ulong id;




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

@@ -5,6 +5,6 @@ namespace Discord.Commands
{ {
public abstract class TypeReader public abstract class TypeReader
{ {
public abstract Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services);
public abstract Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services);
} }
} }

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

@@ -10,7 +10,7 @@ namespace Discord.Commands
internal class UserTypeReader<T> : TypeReader internal class UserTypeReader<T> : TypeReader
where T : class, IUser where T : class, IUser
{ {
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{ {
var results = new Dictionary<ulong, TypeReaderValue>(); var results = new Dictionary<ulong, TypeReaderValue>();
IReadOnlyCollection<IUser> channelUsers = (await context.Channel.GetUsersAsync(CacheMode.CacheOnly).Flatten().ConfigureAwait(false)).ToArray(); //TODO: must be a better way? IReadOnlyCollection<IUser> channelUsers = (await context.Channel.GetUsersAsync(CacheMode.CacheOnly).Flatten().ConfigureAwait(false)).ToArray(); //TODO: must be a better way?


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

@@ -20,7 +20,7 @@ namespace Discord
/// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param> /// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param>
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param> /// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param>
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param> /// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param>
Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null);
Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null);
/// <summary> Returns a collection of all invites to this channel. </summary> /// <summary> Returns a collection of all invites to this channel. </summary>
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null); Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null);


+ 10
- 0
src/Discord.Net.Core/Entities/Emotes/EmoteProperties.cs View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace Discord
{
public class EmoteProperties
{
public Optional<string> Name { get; set; }
public Optional<IEnumerable<IRole>> Roles { get; set; }
}
}

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

@@ -122,5 +122,14 @@ namespace Discord
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null); Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null);
/// <summary> Gets a collection of all webhooks for this guild. </summary> /// <summary> Gets a collection of all webhooks for this guild. </summary>
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null); Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null);
/// <summary> Gets a specific emote from this guild. </summary>
Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null);
/// <summary> Creates a new emote in this guild. </summary>
Task<GuildEmote> CreateEmoteAsync(string name, Image image, Optional<IEnumerable<IRole>> roles = default(Optional<IEnumerable<IRole>>), RequestOptions options = null);
/// <summary> Modifies an existing emote in this guild. </summary>
Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null);
/// <summary> Deletes an existing emote from this guild. </summary>
Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null);
} }
} }

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

@@ -10,7 +10,7 @@ namespace Discord
/// <summary> Gets a blank ChannelPermissions that grants no permissions. </summary> /// <summary> Gets a blank ChannelPermissions that grants no permissions. </summary>
public static readonly ChannelPermissions None = new ChannelPermissions(); public static readonly ChannelPermissions None = new ChannelPermissions();
/// <summary> Gets a ChannelPermissions that grants all permissions for text channels. </summary> /// <summary> Gets a ChannelPermissions that grants all permissions for text channels. </summary>
public static readonly ChannelPermissions Text = new ChannelPermissions(0b00100_0000000_1111111110001_010001);
public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001);
/// <summary> Gets a ChannelPermissions that grants all permissions for voice channels. </summary> /// <summary> Gets a ChannelPermissions that grants all permissions for voice channels. </summary>
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000000000_010001); public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000000000_010001);
/// <summary> Gets a ChannelPermissions that grants all permissions for direct message channels. </summary> /// <summary> Gets a ChannelPermissions that grants all permissions for direct message channels. </summary>


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

@@ -11,7 +11,7 @@ namespace Discord
/// <summary> Gets a GuildPermissions that grants all guild permissions for webhook users. </summary> /// <summary> Gets a GuildPermissions that grants all guild permissions for webhook users. </summary>
public static readonly GuildPermissions Webhook = new GuildPermissions(0b00000_0000000_0001101100000_000000); public static readonly GuildPermissions Webhook = new GuildPermissions(0b00000_0000000_0001101100000_000000);
/// <summary> Gets a GuildPermissions that grants all guild permissions. </summary> /// <summary> Gets a GuildPermissions that grants all guild permissions. </summary>
public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111110_0111111110011_111111);
public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111110_1111111110011_111111);


/// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary> /// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary>
public ulong RawValue { get; } public ulong RawValue { get; }
@@ -28,7 +28,7 @@ namespace Discord
public bool ManageChannels => Permissions.GetValue(RawValue, GuildPermission.ManageChannels); public bool ManageChannels => Permissions.GetValue(RawValue, GuildPermission.ManageChannels);
/// <summary> If True, a user may adjust guild properties. </summary> /// <summary> If True, a user may adjust guild properties. </summary>
public bool ManageGuild => Permissions.GetValue(RawValue, GuildPermission.ManageGuild); public bool ManageGuild => Permissions.GetValue(RawValue, GuildPermission.ManageGuild);
/// <summary> If true, a user may add reactions. </summary> /// <summary> If true, a user may add reactions. </summary>
public bool AddReactions => Permissions.GetValue(RawValue, GuildPermission.AddReactions); public bool AddReactions => Permissions.GetValue(RawValue, GuildPermission.AddReactions);
/// <summary> If true, a user may view the audit log. </summary> /// <summary> If true, a user may view the audit log. </summary>
@@ -80,13 +80,13 @@ namespace Discord
/// <summary> Creates a new GuildPermissions with the provided packed value. </summary> /// <summary> Creates a new GuildPermissions with the provided packed value. </summary>
public GuildPermissions(ulong rawValue) { RawValue = rawValue; } public GuildPermissions(ulong rawValue) { RawValue = rawValue; }


private GuildPermissions(ulong initialValue, bool? createInstantInvite = null, bool? kickMembers = null,
bool? banMembers = null, bool? administrator = null, bool? manageChannels = null, bool? manageGuild = null,
private GuildPermissions(ulong initialValue, bool? createInstantInvite = null, bool? kickMembers = null,
bool? banMembers = null, bool? administrator = null, bool? manageChannels = null, bool? manageGuild = null,
bool? addReactions = null, bool? viewAuditLog = null, bool? addReactions = null, bool? viewAuditLog = null,
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null,
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null,
bool? useExternalEmojis = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null,
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null,
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null,
bool? useExternalEmojis = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null,
bool? manageRoles = null, bool? manageWebhooks = null, bool? manageEmojis = null) bool? manageRoles = null, bool? manageWebhooks = null, bool? manageEmojis = null)
{ {
ulong value = initialValue; ulong value = initialValue;
@@ -124,31 +124,36 @@ namespace Discord
} }


/// <summary> Creates a new GuildPermissions with the provided permissions. </summary> /// <summary> Creates a new GuildPermissions with the provided permissions. </summary>
public GuildPermissions(bool createInstantInvite = false, bool kickMembers = false,
public GuildPermissions(bool createInstantInvite = false, bool kickMembers = false,
bool banMembers = false, bool administrator = false, bool manageChannels = false, bool manageGuild = false, bool banMembers = false, bool administrator = false, bool manageChannels = false, bool manageGuild = false,
bool addReactions = false, bool viewAuditLog = false, bool addReactions = false, bool viewAuditLog = false,
bool readMessages = false, bool sendMessages = false, bool sendTTSMessages = false, bool manageMessages = false, bool readMessages = false, bool sendMessages = false, bool sendTTSMessages = false, bool manageMessages = false,
bool embedLinks = false, bool attachFiles = false, bool readMessageHistory = false, bool mentionEveryone = false, bool embedLinks = false, bool attachFiles = false, bool readMessageHistory = false, bool mentionEveryone = false,
bool useExternalEmojis = false, bool connect = false, bool speak = false, bool muteMembers = false, bool deafenMembers = false, bool useExternalEmojis = false, bool connect = false, bool speak = false, bool muteMembers = false, bool deafenMembers = false,
bool moveMembers = false, bool useVoiceActivation = false, bool? changeNickname = false, bool? manageNicknames = false,
bool moveMembers = false, bool useVoiceActivation = false, bool? changeNickname = false, bool? manageNicknames = false,
bool manageRoles = false, bool manageWebhooks = false, bool manageEmojis = false) bool manageRoles = false, bool manageWebhooks = false, bool manageEmojis = false)
: this(0, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannels, manageGuild, addReactions, viewAuditLog,
readMessages, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, useExternalEmojis, connect,
manageWebhooks, manageEmojis) { }
: this(0, createInstantInvite: createInstantInvite, manageRoles: manageRoles, kickMembers: kickMembers, banMembers: banMembers,
administrator: administrator, manageChannels: manageChannels, manageGuild: manageGuild, addReactions: addReactions,
viewAuditLog: viewAuditLog, readMessages: readMessages, sendMessages: sendMessages, sendTTSMessages: sendTTSMessages,
manageMessages: manageMessages, embedLinks: embedLinks, attachFiles: attachFiles, readMessageHistory: readMessageHistory,
mentionEveryone: mentionEveryone, useExternalEmojis: useExternalEmojis, connect: connect, speak: speak, muteMembers: muteMembers,
deafenMembers: deafenMembers, moveMembers: moveMembers, useVoiceActivation: useVoiceActivation, changeNickname: changeNickname,
manageNicknames: manageNicknames, manageWebhooks: manageWebhooks, manageEmojis: manageEmojis)
{ }


/// <summary> Creates a new GuildPermissions from this one, changing the provided non-null permissions. </summary> /// <summary> Creates a new GuildPermissions from this one, changing the provided non-null permissions. </summary>
public GuildPermissions Modify(bool? createInstantInvite = null, bool? kickMembers = null,
public GuildPermissions Modify(bool? createInstantInvite = null, bool? kickMembers = null,
bool? banMembers = null, bool? administrator = null, bool? manageChannels = null, bool? manageGuild = null, bool? banMembers = null, bool? administrator = null, bool? manageChannels = null, bool? manageGuild = null,
bool? addReactions = null, bool? viewAuditLog = null, bool? addReactions = null, bool? viewAuditLog = null,
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null,
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null,
bool? useExternalEmojis = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, bool? useExternalEmojis = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null,
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null,
bool? manageRoles = null, bool? manageWebhooks = null, bool? manageEmojis = null) bool? manageRoles = null, bool? manageWebhooks = null, bool? manageEmojis = null)
=> new GuildPermissions(RawValue, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannels, manageGuild, addReactions, viewAuditLog,
readMessages, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, useExternalEmojis, connect,
speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, changeNickname, manageNicknames, manageRoles,
manageWebhooks, manageEmojis);
=> new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions,
viewAuditLog, readMessages, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles,
readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers,
useVoiceActivation, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);


public bool Has(GuildPermission permission) => Permissions.GetValue(RawValue, permission); public bool Has(GuildPermission permission) => Permissions.GetValue(RawValue, permission);




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

@@ -10,7 +10,7 @@ namespace Discord
public static Optional<T> Unspecified => default(Optional<T>); public static Optional<T> Unspecified => default(Optional<T>);
private readonly T _value; private readonly T _value;


/// <summary> Gets the value for this paramter. </summary>
/// <summary> Gets the value for this parameter. </summary>
public T Value public T Value
{ {
get get


+ 2
- 1
src/Discord.Net.Core/Utils/Preconditions.cs View File

@@ -188,7 +188,8 @@ namespace Discord
var minimum = SnowflakeUtils.ToSnowflake(DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(14))); var minimum = SnowflakeUtils.ToSnowflake(DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(14)));
for (var i = 0; i < collection.Length; i++) for (var i = 0; i < collection.Length; i++)
{ {
if (collection[i] <= minimum)
if (collection[i] == 0) continue;
if (collection[i] <= minimum)
throw new ArgumentOutOfRangeException(name, "Messages must be younger than two weeks old."); throw new ArgumentOutOfRangeException(name, "Messages must be younger than two weeks old.");
} }
} }


+ 16
- 0
src/Discord.Net.Rest/API/Rest/CreateGuildEmoteParams.cs View File

@@ -0,0 +1,16 @@
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateGuildEmoteParams
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("image")]
public Image Image { get; set; }
[JsonProperty("roles")]
public Optional<ulong[]> RoleIds { get; set; }
}
}

+ 14
- 0
src/Discord.Net.Rest/API/Rest/ModifyGuildEmoteParams.cs View File

@@ -0,0 +1,14 @@
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildEmoteParams
{
[JsonProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("roles")]
public Optional<ulong[]> RoleIds { get; set; }
}
}

+ 44
- 0
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -1066,6 +1066,50 @@ namespace Discord.API
return await SendJsonAsync<IReadOnlyCollection<Role>>("PATCH", () => $"guilds/{guildId}/roles", args, ids, options: options).ConfigureAwait(false); return await SendJsonAsync<IReadOnlyCollection<Role>>("PATCH", () => $"guilds/{guildId}/roles", args, ids, options: options).ConfigureAwait(false);
} }


//Guild emoji
public async Task<Emoji> GetGuildEmoteAsync(ulong guildId, ulong emoteId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(emoteId, 0, nameof(emoteId));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendAsync<Emoji>("GET", () => $"guilds/{guildId}/emojis/{emoteId}", ids, options: options);
}

public async Task<Emoji> CreateGuildEmoteAsync(ulong guildId, Rest.CreateGuildEmoteParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));
Preconditions.NotNull(args.Image.Stream, nameof(args.Image));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendJsonAsync<Emoji>("POST", () => $"guilds/{guildId}/emojis", args, ids, options: options);
}

public async Task<Emoji> ModifyGuildEmoteAsync(ulong guildId, ulong emoteId, ModifyGuildEmoteParams args, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(emoteId, 0, nameof(emoteId));
Preconditions.NotNull(args, nameof(args));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendJsonAsync<Emoji>("PATCH", () => $"guilds/{guildId}/emojis/{emoteId}", args, ids, options: options);
}

public async Task DeleteGuildEmoteAsync(ulong guildId, ulong emoteId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(emoteId, 0, nameof(emoteId));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
await SendAsync("DELETE", () => $"guilds/{guildId}/emojis/{emoteId}", ids, options: options);
}

//Users //Users
public async Task<User> GetUserAsync(ulong userId, RequestOptions options = null) public async Task<User> GetUserAsync(ulong userId, RequestOptions options = null)
{ {


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

@@ -48,8 +48,8 @@ namespace Discord.Rest
string IChannel.Name => null; string IChannel.Name => null;


Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IUser>(null); //Overriden
=> Task.FromResult<IUser>(null); //Overridden
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
=> AsyncEnumerable.Empty<IReadOnlyCollection<IUser>>(); //Overriden
=> AsyncEnumerable.Empty<IReadOnlyCollection<IUser>>(); //Overridden
} }
} }

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

@@ -119,7 +119,7 @@ namespace Discord.Rest


public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null)
=> await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false);
public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 3600, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false);


public override string ToString() => Name; public override string ToString() => Name;
@@ -154,14 +154,14 @@ namespace Discord.Rest
=> await RemovePermissionOverwriteAsync(user, options).ConfigureAwait(false); => await RemovePermissionOverwriteAsync(user, options).ConfigureAwait(false);
IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
=> AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>(); //Overriden //Overriden in Text/Voice
=> AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>(); //Overridden //Overridden in Text/Voice
Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IGuildUser>(null); //Overriden in Text/Voice
=> Task.FromResult<IGuildUser>(null); //Overridden in Text/Voice


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

+ 41
- 0
src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs View File

@@ -267,5 +267,46 @@ namespace Discord.Rest
var models = await client.ApiClient.GetGuildWebhooksAsync(guild.Id, options).ConfigureAwait(false); var models = await client.ApiClient.GetGuildWebhooksAsync(guild.Id, options).ConfigureAwait(false);
return models.Select(x => RestWebhook.Create(client, guild, x)).ToImmutableArray(); return models.Select(x => RestWebhook.Create(client, guild, x)).ToImmutableArray();
} }

//Emotes
public static async Task<GuildEmote> GetEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options)
{
var emote = await client.ApiClient.GetGuildEmoteAsync(guild.Id, id, options);
return emote.ToEntity();
}
public static async Task<GuildEmote> CreateEmoteAsync(IGuild guild, BaseDiscordClient client, string name, Image image, Optional<IEnumerable<IRole>> roles,
RequestOptions options)
{
var apiargs = new CreateGuildEmoteParams
{
Name = name,
Image = image.ToModel()
};
if (roles.IsSpecified)
apiargs.RoleIds = roles.Value?.Select(xr => xr.Id)?.ToArray();

var emote = await client.ApiClient.CreateGuildEmoteAsync(guild.Id, apiargs, options);
return emote.ToEntity();
}
public static async Task<GuildEmote> ModifyEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, Action<EmoteProperties> func,
RequestOptions options)
{
if (func == null) throw new ArgumentNullException(nameof(func));

var props = new EmoteProperties();
func(props);

var apiargs = new ModifyGuildEmoteParams
{
Name = props.Name
};
if (props.Roles.IsSpecified)
apiargs.RoleIds = props.Roles.Value?.Select(xr => xr.Id)?.ToArray();

var emote = await client.ApiClient.ModifyGuildEmoteAsync(guild.Id, id, apiargs, options);
return emote.ToEntity();
}
public static Task DeleteEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options)
=> client.ApiClient.DeleteGuildEmoteAsync(guild.Id, id, options);
} }
} }

+ 10
- 0
src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs View File

@@ -266,6 +266,16 @@ namespace Discord.Rest
public override string ToString() => Name; public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Id})"; private string DebuggerDisplay => $"{Name} ({Id})";


//Emotes
public Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null)
=> GuildHelper.GetEmoteAsync(this, Discord, id, options);
public Task<GuildEmote> CreateEmoteAsync(string name, Image image, Optional<IEnumerable<IRole>> roles = default(Optional<IEnumerable<IRole>>), RequestOptions options = null)
=> GuildHelper.CreateEmoteAsync(this, Discord, name, image, roles, options);
public Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null)
=> GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options);
public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null)
=> GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options);

//IGuild //IGuild
bool IGuild.Available => Available; bool IGuild.Available => Available;
IAudioClient IGuild.AudioClient => null; IAudioClient IGuild.AudioClient => null;


+ 35
- 0
src/Discord.Net.Rest/Extensions/EmbedBuilderExtensions.cs View File

@@ -1,3 +1,5 @@
using System;

namespace Discord namespace Discord
{ {
public static class EmbedBuilderExtensions public static class EmbedBuilderExtensions
@@ -19,5 +21,38 @@ namespace Discord


public static EmbedBuilder WithAuthor(this EmbedBuilder builder, IGuildUser user) => public static EmbedBuilder WithAuthor(this EmbedBuilder builder, IGuildUser user) =>
builder.WithAuthor($"{user.Nickname ?? user.Username}#{user.Discriminator}", user.GetAvatarUrl()); builder.WithAuthor($"{user.Nickname ?? user.Username}#{user.Discriminator}", user.GetAvatarUrl());

public static EmbedBuilder ToEmbedBuilder(this IEmbed embed)
{
if (embed.Type != EmbedType.Rich)
throw new InvalidOperationException($"Only {nameof(EmbedType.Rich)} embeds may be built.");

var builder = new EmbedBuilder
{
Author = new EmbedAuthorBuilder
{
Name = embed.Author?.Name,
IconUrl = embed.Author?.IconUrl,
Url = embed.Author?.Url
},
Color = embed.Color ?? Color.Default,
Description = embed.Description,
Footer = new EmbedFooterBuilder
{
Text = embed.Footer?.Text,
IconUrl = embed.Footer?.IconUrl
},
ImageUrl = embed.Image?.Url,
ThumbnailUrl = embed.Thumbnail?.Url,
Timestamp = embed.Timestamp,
Title = embed.Title,
Url = embed.Url
};

foreach (var field in embed.Fields)
builder.AddField(field.Name, field.Value, field.Inline);

return builder;
}
} }
} }

+ 1
- 1
src/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs View File

@@ -51,7 +51,7 @@ namespace Discord.Rpc


public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null)
=> await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false);
public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 3600, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false);


public override string ToString() => Name; public override string ToString() => Name;


+ 3
- 3
src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs View File

@@ -113,7 +113,7 @@ namespace Discord.WebSocket


public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null)
=> await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false);
public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 3600, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null)
=> await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false);


public new virtual SocketGuildUser GetUser(ulong id) => null; public new virtual SocketGuildUser GetUser(ulong id) => null;
@@ -154,8 +154,8 @@ namespace Discord.WebSocket


//IChannel //IChannel
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
=> ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); //Overriden in Text/Voice
=> ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); //Overridden in Text/Voice
Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
=> Task.FromResult<IUser>(GetUser(id)); //Overriden in Text/Voice
=> Task.FromResult<IUser>(GetUser(id)); //Overridden in Text/Voice
} }
} }

+ 10
- 0
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -439,6 +439,16 @@ namespace Discord.WebSocket
public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null) public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null)
=> GuildHelper.GetWebhooksAsync(this, Discord, options); => GuildHelper.GetWebhooksAsync(this, Discord, options);


//Emotes
public Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null)
=> GuildHelper.GetEmoteAsync(this, Discord, id, options);
public Task<GuildEmote> CreateEmoteAsync(string name, Image image, Optional<IEnumerable<IRole>> roles = default(Optional<IEnumerable<IRole>>), RequestOptions options = null)
=> GuildHelper.CreateEmoteAsync(this, Discord, name, image, roles, options);
public Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null)
=> GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options);
public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null)
=> GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options);

//Voice States //Voice States
internal async Task<SocketVoiceState> AddOrUpdateVoiceStateAsync(ClientState state, VoiceStateModel model) internal async Task<SocketVoiceState> AddOrUpdateVoiceStateAsync(ClientState state, VoiceStateModel model)
{ {


+ 19
- 19
src/Discord.Net/Discord.Net.nuspec View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>Discord.Net</id> <id>Discord.Net</id>
<version>2.0.0-alpha$suffix$</version>
<version>2.0.0-beta$suffix$</version>
<title>Discord.Net</title> <title>Discord.Net</title>
<authors>Discord.Net Contributors</authors> <authors>Discord.Net Contributors</authors>
<owners>RogueException</owners> <owners>RogueException</owners>
@@ -13,28 +13,28 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<dependencies> <dependencies>
<group targetFramework="net45"> <group targetFramework="net45">
<dependency id="Discord.Net.Core" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Rest" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Rpc" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Commands" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Core" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Rest" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Rpc" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Commands" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.0.0-beta$suffix$" />
</group> </group>
<group targetFramework="netstandard1.1"> <group targetFramework="netstandard1.1">
<dependency id="Discord.Net.Core" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Rest" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Rpc" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Commands" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Core" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Rest" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Rpc" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Commands" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.0.0-beta$suffix$" />
</group> </group>
<group targetFramework="netstandard1.3"> <group targetFramework="netstandard1.3">
<dependency id="Discord.Net.Core" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Rest" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Rpc" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Commands" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.0.0-alpha$suffix$" />
<dependency id="Discord.Net.Core" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Rest" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Rpc" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Commands" version="2.0.0-beta$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.0.0-beta$suffix$" />
</group> </group>
</dependencies> </dependencies>
</metadata> </metadata>


+ 324
- 0
test/Discord.Net.Tests/Tests.ChannelPermissions.cs View File

@@ -0,0 +1,324 @@
using System;
using System.Threading.Tasks;
using Xunit;

namespace Discord
{
public partial class Tests
{
[Fact]
public void TestChannelPermission()
{
var perm = new ChannelPermissions();

// check initial values
Assert.Equal((ulong)0, perm.RawValue);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// permissions list empty by default
Assert.Empty(perm.ToList());

// test modify with no parameters
var copy = perm.Modify();
Assert.Equal((ulong)0, copy.RawValue);

// test the values that are returned by ChannelPermission.All
Assert.Equal((ulong)0, ChannelPermissions.None.RawValue);

// for text channels
ulong textChannel = (ulong)( ChannelPermission.CreateInstantInvite
| ChannelPermission.ManageChannels
| ChannelPermission.AddReactions
| ChannelPermission.ReadMessages
| ChannelPermission.SendMessages
| ChannelPermission.SendTTSMessages
| ChannelPermission.ManageMessages
| ChannelPermission.EmbedLinks
| ChannelPermission.AttachFiles
| ChannelPermission.ReadMessageHistory
| ChannelPermission.MentionEveryone
| ChannelPermission.UseExternalEmojis
| ChannelPermission.ManageRoles
| ChannelPermission.ManageWebhooks);

Assert.Equal(textChannel, ChannelPermissions.Text.RawValue);

// voice channels
ulong voiceChannel = (ulong)(
ChannelPermission.CreateInstantInvite
| ChannelPermission.ManageChannels
| ChannelPermission.Connect
| ChannelPermission.Speak
| ChannelPermission.MuteMembers
| ChannelPermission.DeafenMembers
| ChannelPermission.MoveMembers
| ChannelPermission.UseVAD
| ChannelPermission.ManageRoles);

Assert.Equal(voiceChannel, ChannelPermissions.Voice.RawValue);

// DM Channels
ulong dmChannel = (ulong)(
ChannelPermission.ReadMessages
| ChannelPermission.SendMessages
| ChannelPermission.EmbedLinks
| ChannelPermission.AttachFiles
| ChannelPermission.ReadMessageHistory
| ChannelPermission.UseExternalEmojis
| ChannelPermission.Connect
| ChannelPermission.Speak
| ChannelPermission.UseVAD
);
Assert.Equal(dmChannel, ChannelPermissions.DM.RawValue);

// group channel
ulong groupChannel = (ulong)(
ChannelPermission.SendMessages
| ChannelPermission.EmbedLinks
| ChannelPermission.AttachFiles
| ChannelPermission.SendTTSMessages
| ChannelPermission.Connect
| ChannelPermission.Speak
| ChannelPermission.UseVAD
);
Assert.Equal(groupChannel, ChannelPermissions.Group.RawValue);
}

public void TestChannelPermissionModify()
{
// test channel permission modify

var perm = new ChannelPermissions();

// ensure that the permission is initially false
Assert.False(perm.CreateInstantInvite);

// ensure that when modified it works
perm = perm.Modify(createInstantInvite: true);
Assert.True(perm.CreateInstantInvite);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.CreateInstantInvite);

// set false again, move on to next permission
perm = perm.Modify(createInstantInvite: false);
Assert.False(perm.CreateInstantInvite);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.ManageChannel);

perm = perm.Modify(manageChannel: true);
Assert.True(perm.ManageChannel);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageChannels);

perm = perm.Modify(manageChannel: false);
Assert.False(perm.ManageChannel);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.AddReactions);

perm = perm.Modify(addReactions: true);
Assert.True(perm.AddReactions);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.AddReactions);

perm = perm.Modify(addReactions: false);
Assert.False(perm.AddReactions);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.ReadMessages);

perm = perm.Modify(readMessages: true);
Assert.True(perm.ReadMessages);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ReadMessages);

perm = perm.Modify(readMessages: false);
Assert.False(perm.ReadMessages);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.SendMessages);

perm = perm.Modify(sendMessages: true);
Assert.True(perm.SendMessages);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.SendMessages);

perm = perm.Modify(sendMessages: false);
Assert.False(perm.SendMessages);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.SendTTSMessages);

perm = perm.Modify(sendTTSMessages: true);
Assert.True(perm.SendTTSMessages);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.SendTTSMessages);

perm = perm.Modify(sendTTSMessages: false);
Assert.False(perm.SendTTSMessages);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.ManageMessages);

perm = perm.Modify(manageMessages: true);
Assert.True(perm.ManageMessages);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageMessages);

perm = perm.Modify(manageMessages: false);
Assert.False(perm.ManageMessages);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.EmbedLinks);

perm = perm.Modify(embedLinks: true);
Assert.True(perm.EmbedLinks);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.EmbedLinks);

perm = perm.Modify(embedLinks: false);
Assert.False(perm.EmbedLinks);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.AttachFiles);

perm = perm.Modify(attachFiles: true);
Assert.True(perm.AttachFiles);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.AttachFiles);

perm = perm.Modify(attachFiles: false);
Assert.False(perm.AttachFiles);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.ReadMessageHistory);

perm = perm.Modify(readMessageHistory: true);
Assert.True(perm.ReadMessageHistory);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ReadMessageHistory);

perm = perm.Modify(readMessageHistory: false);
Assert.False(perm.ReadMessageHistory);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.MentionEveryone);

perm = perm.Modify(mentionEveryone: true);
Assert.True(perm.MentionEveryone);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.MentionEveryone);

perm = perm.Modify(mentionEveryone: false);
Assert.False(perm.MentionEveryone);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.UseExternalEmojis);

perm = perm.Modify(useExternalEmojis: true);
Assert.True(perm.UseExternalEmojis);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.UseExternalEmojis);

perm = perm.Modify(useExternalEmojis: false);
Assert.False(perm.UseExternalEmojis);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.Connect);

perm = perm.Modify(connect: true);
Assert.True(perm.Connect);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.Connect);

perm = perm.Modify(connect: false);
Assert.False(perm.Connect);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);
// individual permission test
Assert.False(perm.Speak);

perm = perm.Modify(speak: true);
Assert.True(perm.Speak);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.Speak);

perm = perm.Modify(speak: false);
Assert.False(perm.Speak);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.MuteMembers);

perm = perm.Modify(muteMembers: true);
Assert.True(perm.MuteMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.MuteMembers);

perm = perm.Modify(muteMembers: false);
Assert.False(perm.MuteMembers);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.DeafenMembers);

perm = perm.Modify(deafenMembers: true);
Assert.True(perm.DeafenMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.DeafenMembers);

perm = perm.Modify(deafenMembers: false);
Assert.False(perm.DeafenMembers);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.MoveMembers);

perm = perm.Modify(moveMembers: true);
Assert.True(perm.MoveMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.MoveMembers);

perm = perm.Modify(moveMembers: false);
Assert.False(perm.MoveMembers);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.UseVAD);

perm = perm.Modify(useVoiceActivation: true);
Assert.True(perm.UseVAD);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.UseVAD);

perm = perm.Modify(useVoiceActivation: false);
Assert.False(perm.UseVAD);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.ManageRoles);

perm = perm.Modify(manageRoles: true);
Assert.True(perm.ManageRoles);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageRoles);

perm = perm.Modify(manageRoles: false);
Assert.False(perm.ManageRoles);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);

// individual permission test
Assert.False(perm.ManageWebhooks);

perm = perm.Modify(manageWebhooks: true);
Assert.True(perm.ManageWebhooks);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageWebhooks);

perm = perm.Modify(manageWebhooks: false);
Assert.False(perm.ManageWebhooks);
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue);
}

[Fact]
public void TestChannelTypeResolution()
{
ITextChannel someChannel = null;
// null channels will throw exception
Assert.Throws<ArgumentException>(() => ChannelPermissions.All(someChannel));
}
}
}

+ 304
- 0
test/Discord.Net.Tests/Tests.GuildPermissions.cs View File

@@ -0,0 +1,304 @@
using System;
using System.Threading.Tasks;
using Xunit;

namespace Discord
{
public partial class Tests
{
[Fact]
public void TestGuildPermission()
{
// Test Guild Permission Constructors
var perm = new GuildPermissions();

// the default raw value is 0
Assert.Equal((ulong)0, perm.RawValue);
// also check that it is the same as none
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// permissions list is empty by default
Assert.Empty(perm.ToList());
Assert.NotNull(perm.ToList());

// Test modify with no parameters
var copy = perm.Modify();
// ensure that the raw values match
Assert.Equal((ulong)0, copy.RawValue);

// test GuildPermissions.All
ulong sumOfAllGuildPermissions = 0;
foreach(var v in Enum.GetValues(typeof(GuildPermission)))
{
sumOfAllGuildPermissions |= (ulong)v;
}

// assert that the raw values match
Assert.Equal(sumOfAllGuildPermissions, GuildPermissions.All.RawValue);
Assert.Equal((ulong)0, GuildPermissions.None.RawValue);

// assert that GuildPermissions.All contains the same number of permissions as the
// GuildPermissions enum
Assert.Equal(Enum.GetValues(typeof(GuildPermission)).Length, GuildPermissions.All.ToList().Count);

// assert that webhook has the same raw value
ulong webHookPermissions = (ulong)(
GuildPermission.SendMessages | GuildPermission.SendTTSMessages | GuildPermission.EmbedLinks |
GuildPermission.AttachFiles);
Assert.Equal(webHookPermissions, GuildPermissions.Webhook.RawValue);
}

[Fact]
public void TestGuildPermissionModify()
{
var perm = new GuildPermissions();

// tests each of the parameters of Modify one by one

// test modify with each of the parameters
// test initially false state
Assert.False(perm.CreateInstantInvite);

// ensure that when we modify it the parameter works
perm = perm.Modify(createInstantInvite: true);
Assert.True(perm.CreateInstantInvite);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.CreateInstantInvite);

// set it false again, then move on to the next permission
perm = perm.Modify(createInstantInvite: false);
Assert.False(perm.CreateInstantInvite);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(kickMembers: true);
Assert.True(perm.KickMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.KickMembers);

perm = perm.Modify(kickMembers: false);
Assert.False(perm.KickMembers);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(banMembers: true);
Assert.True(perm.BanMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.BanMembers);

perm = perm.Modify(banMembers: false);
Assert.False(perm.BanMembers);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(administrator: true);
Assert.True(perm.Administrator);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.Administrator);

perm = perm.Modify(administrator: false);
Assert.False(perm.Administrator);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(manageChannels: true);
Assert.True(perm.ManageChannels);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageChannels);

perm = perm.Modify(manageChannels: false);
Assert.False(perm.ManageChannels);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(manageGuild: true);
Assert.True(perm.ManageGuild);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageGuild);

perm = perm.Modify(manageGuild: false);
Assert.False(perm.ManageGuild);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);


// individual permission test
perm = perm.Modify(addReactions: true);
Assert.True(perm.AddReactions);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.AddReactions);

perm = perm.Modify(addReactions: false);
Assert.False(perm.AddReactions);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);


// individual permission test
perm = perm.Modify(viewAuditLog: true);
Assert.True(perm.ViewAuditLog);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ViewAuditLog);

perm = perm.Modify(viewAuditLog: false);
Assert.False(perm.ViewAuditLog);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);


// individual permission test
perm = perm.Modify(readMessages: true);
Assert.True(perm.ReadMessages);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ReadMessages);

perm = perm.Modify(readMessages: false);
Assert.False(perm.ReadMessages);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);


// individual permission test
perm = perm.Modify(sendMessages: true);
Assert.True(perm.SendMessages);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.SendMessages);

perm = perm.Modify(sendMessages: false);
Assert.False(perm.SendMessages);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(embedLinks: true);
Assert.True(perm.EmbedLinks);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.EmbedLinks);

perm = perm.Modify(embedLinks: false);
Assert.False(perm.EmbedLinks);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(attachFiles: true);
Assert.True(perm.AttachFiles);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.AttachFiles);

perm = perm.Modify(attachFiles: false);
Assert.False(perm.AttachFiles);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(readMessageHistory: true);
Assert.True(perm.ReadMessageHistory);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ReadMessageHistory);

perm = perm.Modify(readMessageHistory: false);
Assert.False(perm.ReadMessageHistory);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(mentionEveryone: true);
Assert.True(perm.MentionEveryone);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.MentionEveryone);

perm = perm.Modify(mentionEveryone: false);
Assert.False(perm.MentionEveryone);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(useExternalEmojis: true);
Assert.True(perm.UseExternalEmojis);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.UseExternalEmojis);

perm = perm.Modify(useExternalEmojis: false);
Assert.False(perm.UseExternalEmojis);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(connect: true);
Assert.True(perm.Connect);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.Connect);

perm = perm.Modify(connect: false);
Assert.False(perm.Connect);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(speak: true);
Assert.True(perm.Speak);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.Speak);

perm = perm.Modify(speak: false);
Assert.False(perm.Speak);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(muteMembers: true);
Assert.True(perm.MuteMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.MuteMembers);

perm = perm.Modify(muteMembers: false);
Assert.False(perm.MuteMembers);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(deafenMembers: true);
Assert.True(perm.DeafenMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.DeafenMembers);

perm = perm.Modify(deafenMembers: false);
Assert.False(perm.DeafenMembers);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(moveMembers: true);
Assert.True(perm.MoveMembers);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.MoveMembers);

perm = perm.Modify(moveMembers: false);
Assert.False(perm.MoveMembers);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(useVoiceActivation: true);
Assert.True(perm.UseVAD);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.UseVAD);

perm = perm.Modify(useVoiceActivation: false);
Assert.False(perm.UseVAD);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(changeNickname: true);
Assert.True(perm.ChangeNickname);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ChangeNickname);

perm = perm.Modify(changeNickname: false);
Assert.False(perm.ChangeNickname);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(manageNicknames: true);
Assert.True(perm.ManageNicknames);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageNicknames);

perm = perm.Modify(manageNicknames: false);
Assert.False(perm.ManageNicknames);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(manageRoles: true);
Assert.True(perm.ManageRoles);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageRoles);

perm = perm.Modify(manageRoles: false);
Assert.False(perm.ManageRoles);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(manageWebhooks: true);
Assert.True(perm.ManageWebhooks);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageWebhooks);

perm = perm.Modify(manageWebhooks: false);
Assert.False(perm.ManageWebhooks);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

// individual permission test
perm = perm.Modify(manageEmojis: true);
Assert.True(perm.ManageEmojis);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ManageEmojis);

perm = perm.Modify(manageEmojis: false);
Assert.False(perm.ManageEmojis);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);

}

}
}

Loading…
Cancel
Save