diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 000000000..a672330d4
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,16 @@
+# Instructions for Building Documentation
+
+The documentation for the Discord.NET library uses [DocFX][docfx-main]. [Instructions for installing this tool can be found here.][docfx-installing]
+
+1. Navigate to the root of the repository.
+2. (Optional) If you intend to target a specific version, ensure that you
+have the correct version checked out.
+3. Build the library. Run `dotnet build` in the root of this repository.
+ Ensure that the build passes without errors.
+4. Build the docs using `docfx .\docs\docfx.json`. Add the `--serve` parameter
+to preview the site locally. Some elements of the page may appear incorrect
+when not hosted by a server.
+ - Remarks: According to the docfx website, this tool does work on Linux under mono.
+
+[docfx-main]: https://dotnet.github.io/docfx/
+[docfx-installing]: https://dotnet.github.io/docfx/tutorial/docfx_getting_started.html
diff --git a/docs/docfx.json b/docs/docfx.json
index 8dc0abd38..a1c1ef2f6 100644
--- a/docs/docfx.json
+++ b/docs/docfx.json
@@ -56,7 +56,7 @@
"default"
],
"globalMetadata":{
- "_appFooter":"Discord.Net (c) 2015-2018",
+ "_appFooter":"Discord.Net (c) 2015-2018 2.0.0-beta",
"_enableSearch":true
},
"noLangKeyword":false,
diff --git a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
index 92cc90c09..b80498307 100644
--- a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
+++ b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
@@ -13,6 +13,8 @@ namespace Discord
public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001);
/// Gets a that grants all permissions for voice channels.
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000000000_010001);
+ /// Gets a that grants all permissions for category channels.
+ public static readonly ChannelPermissions Category = new ChannelPermissions(0b01100_1111110_1111111110001_010001);
/// Gets a that grants all permissions for direct message channels.
public static readonly ChannelPermissions DM = new ChannelPermissions(0b00000_1000110_1011100110000_000000);
/// Gets a that grants all permissions for group channels.
@@ -24,6 +26,7 @@ namespace Discord
{
case ITextChannel _: return Text;
case IVoiceChannel _: return Voice;
+ case ICategoryChannel _: return Category;
case IDMChannel _: return DM;
case IGroupChannel _: return Group;
default: throw new ArgumentException("Unknown channel type", nameof(channel));
diff --git a/src/Discord.Net.Core/Extensions/UserExtensions.cs b/src/Discord.Net.Core/Extensions/UserExtensions.cs
index 863201cfe..d3e968e39 100644
--- a/src/Discord.Net.Core/Extensions/UserExtensions.cs
+++ b/src/Discord.Net.Core/Extensions/UserExtensions.cs
@@ -46,5 +46,8 @@ namespace Discord
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
}
#endif
+
+ public static Task BanAsync(this IGuildUser user, int pruneDays = 0, string reason = null, RequestOptions options = null)
+ => user.Guild.AddBanAsync(user, pruneDays, reason, options);
}
}
diff --git a/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs b/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs
index 5c06a033e..9e909b50c 100644
--- a/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs
+++ b/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs
@@ -30,28 +30,24 @@ namespace Discord.API.Rest
{
var d = new Dictionary();
d["file"] = new MultipartFile(File, Filename.GetValueOrDefault("unknown.dat"));
+
+ var payload = new Dictionary();
if (Content.IsSpecified)
- d["content"] = Content.Value;
+ payload["content"] = Content.Value;
if (IsTTS.IsSpecified)
- d["tts"] = IsTTS.Value.ToString();
+ payload["tts"] = IsTTS.Value.ToString();
if (Nonce.IsSpecified)
- d["nonce"] = Nonce.Value;
+ payload["nonce"] = Nonce.Value;
if (Embed.IsSpecified)
- {
- var payload = new StringBuilder();
- using (var text = new StringWriter(payload))
- using (var writer = new JsonTextWriter(text))
- {
- var map = new Dictionary()
- {
- ["embed"] = Embed.Value,
- };
-
- _serializer.Serialize(writer, map);
- }
- d["payload_json"] = payload.ToString();
-
- }
+ payload["embed"] = Embed.Value;
+
+ var json = new StringBuilder();
+ using (var text = new StringWriter(json))
+ using (var writer = new JsonTextWriter(text))
+ _serializer.Serialize(writer, payload);
+
+ d["payload_json"] = json.ToString();
+
return d;
}
}
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index 556d6fbe6..f0c4358ad 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -470,7 +470,7 @@ namespace Discord.API
if (!args.Embed.IsSpecified || args.Embed.Value == null)
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
- if (args.Content.Length > DiscordConfig.MaxMessageSize)
+ if (args.Content?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
options = RequestOptions.CreateOrClone(options);
@@ -487,7 +487,7 @@ namespace Discord.API
if (!args.Embeds.IsSpecified || args.Embeds.Value == null || args.Embeds.Value.Length == 0)
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
- if (args.Content.Length > DiscordConfig.MaxMessageSize)
+ if (args.Content?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
options = RequestOptions.CreateOrClone(options);
@@ -568,7 +568,7 @@ namespace Discord.API
{
if (!args.Embed.IsSpecified)
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
- if (args.Content.Value.Length > DiscordConfig.MaxMessageSize)
+ if (args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
}
options = RequestOptions.CreateOrClone(options);
diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
index 710746896..6784f7f6a 100644
--- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
@@ -180,7 +180,7 @@ namespace Discord.Rest
public static async Task SendFileAsync(IMessageChannel channel, BaseDiscordClient client,
Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
{
- var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS, Embed = embed?.ToModel() };
+ var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS, Embed = embed != null ? embed.ToModel() : Optional.Unspecified };
var model = await client.ApiClient.UploadFileAsync(channel.Id, args, options).ConfigureAwait(false);
return RestUserMessage.Create(client, channel, client.CurrentUser, model);
}
diff --git a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
index 47bb6f926..8ae41cc37 100644
--- a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
@@ -1,4 +1,4 @@
-using Discord.API.Rest;
+using Discord.API.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -13,6 +13,9 @@ namespace Discord.Rest
public static async Task ModifyAsync(IMessage msg, BaseDiscordClient client, Action func,
RequestOptions options)
{
+ if (msg.Author.Id != client.CurrentUser.Id)
+ throw new InvalidOperationException("Only the author of a message may change it.");
+
var args = new MessageProperties();
func(args);
var apiArgs = new API.Rest.ModifyMessageParams
diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
index e5eed874e..0d1f3be2b 100644
--- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs
index d5a183b1e..e7a165c2f 100644
--- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs
+++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
@@ -15,10 +15,12 @@ namespace Discord.WebSocket
public class SocketCategoryChannel : SocketGuildChannel, ICategoryChannel
{
public override IReadOnlyCollection Users
- => Guild.Users.Where(x => x.VoiceChannel?.Id == Id).ToImmutableArray();
+ => Guild.Users.Where(x => Permissions.GetValue(
+ Permissions.ResolveChannel(Guild, x, this, Permissions.ResolveGuild(Guild, x)),
+ ChannelPermission.ViewChannel)).ToImmutableArray();
public IReadOnlyCollection Channels
- => Guild.Channels.Where(x => x.CategoryId == CategoryId).ToImmutableArray();
+ => Guild.Channels.Where(x => x.CategoryId == Id).ToImmutableArray();
internal SocketCategoryChannel(DiscordSocketClient discord, ulong id, SocketGuild guild)
: base(discord, id, guild)
@@ -31,14 +33,28 @@ namespace Discord.WebSocket
return entity;
}
+ //Users
+ public override SocketGuildUser GetUser(ulong id)
+ {
+ var user = Guild.GetUser(id);
+ if (user != null)
+ {
+ var guildPerms = Permissions.ResolveGuild(Guild, user);
+ var channelPerms = Permissions.ResolveChannel(Guild, user, this, guildPerms);
+ if (Permissions.GetValue(channelPerms, ChannelPermission.ViewChannel))
+ return user;
+ }
+ return null;
+ }
+
private string DebuggerDisplay => $"{Name} ({Id}, Category)";
internal new SocketCategoryChannel Clone() => MemberwiseClone() as SocketCategoryChannel;
// IGuildChannel
IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
- => throw new NotSupportedException();
+ => ImmutableArray.Create>(Users).ToAsyncEnumerable();
Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
- => throw new NotSupportedException();
+ => Task.FromResult(GetUser(id));
Task IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, bool isUnique, RequestOptions options)
=> throw new NotSupportedException();
Task> IGuildChannel.GetInvitesAsync(RequestOptions options)
@@ -46,8 +62,8 @@ namespace Discord.WebSocket
//IChannel
IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options)
- => throw new NotSupportedException();
+ => ImmutableArray.Create>(Users).ToAsyncEnumerable();
Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options)
- => throw new NotSupportedException();
+ => Task.FromResult(GetUser(id));
}
}
diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
index b240645e5..5489ad2bb 100644
--- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
+++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
@@ -1,4 +1,4 @@
-using Discord.Rest;
+using Discord.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;