diff --git a/Discord.Net.sln b/Discord.Net.sln
index bac38366c..1c32308ff 100644
--- a/Discord.Net.sln
+++ b/Discord.Net.sln
@@ -26,6 +26,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Commands", "src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj", "{1B5603B4-6F8F-4289-B945-7BAAE523D740}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Modules", "src\Discord.Net.Modules\Discord.Net.Modules.xproj", "{01584E8A-78DA-486F-9EF9-A894E435841B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Modules", "src\Discord.Net.Modules.Net45\Discord.Net.Modules.csproj", "{3091164F-66AE-4543-A63D-167C1116241D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -63,6 +67,18 @@ Global
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU
+ {01584E8A-78DA-486F-9EF9-A894E435841B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01584E8A-78DA-486F-9EF9-A894E435841B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01584E8A-78DA-486F-9EF9-A894E435841B}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01584E8A-78DA-486F-9EF9-A894E435841B}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
+ {01584E8A-78DA-486F-9EF9-A894E435841B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01584E8A-78DA-486F-9EF9-A894E435841B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
+ {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -75,5 +91,7 @@ Global
{855D6B1D-847B-42DA-BE6A-23683EA89511} = {6317A2E6-8E36-4C3E-949B-3F10EC888AB9}
{8D71A857-879A-4A10-859E-5FF824ED6688} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD}
{1B5603B4-6F8F-4289-B945-7BAAE523D740} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD}
+ {01584E8A-78DA-486F-9EF9-A894E435841B} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35}
+ {3091164F-66AE-4543-A63D-167C1116241D} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD}
EndGlobalSection
EndGlobal
diff --git a/src/Discord.Net.Commands.Net45/Properties/AssemblyInfo.cs b/src/Discord.Net.Commands.Net45/Properties/AssemblyInfo.cs
index e242053d8..c9652a642 100644
--- a/src/Discord.Net.Commands.Net45/Properties/AssemblyInfo.cs
+++ b/src/Discord.Net.Commands.Net45/Properties/AssemblyInfo.cs
@@ -13,6 +13,6 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")]
-[assembly: AssemblyVersion("0.8.0.0")]
-[assembly: AssemblyFileVersion("0.8.0.0")]
+[assembly: AssemblyVersion("0.8.1.0")]
+[assembly: AssemblyFileVersion("0.8.1.0")]
diff --git a/src/Discord.Net.Commands/project.json b/src/Discord.Net.Commands/project.json
index aac273d4e..259f9606a 100644
--- a/src/Discord.Net.Commands/project.json
+++ b/src/Discord.Net.Commands/project.json
@@ -1,5 +1,5 @@
{
- "version": "0.8.0-beta1",
+ "version": "0.8.1-beta1",
"description": "A Discord.Net extension adding basic command support.",
"authors": [ "RogueException" ],
"tags": [ "discord", "discordapp" ],
@@ -13,7 +13,7 @@
"warningsAsErrors": true
},
"dependencies": {
- "Discord.Net": "0.8.0-beta1"
+ "Discord.Net": "0.8.1-beta1"
},
"frameworks": {
"net45": { },
diff --git a/src/Discord.Net.Modules.Net45/Discord.Net.Modules.csproj b/src/Discord.Net.Modules.Net45/Discord.Net.Modules.csproj
new file mode 100644
index 000000000..4bc5bf376
--- /dev/null
+++ b/src/Discord.Net.Modules.Net45/Discord.Net.Modules.csproj
@@ -0,0 +1,56 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {3091164F-66AE-4543-A63D-167C1116241D}
+ Library
+ Properties
+ Discord
+ Discord.Net.Commands
+ 512
+ v4.5
+ False
+
+
+ true
+ full
+ false
+ bin\Debug\
+ TRACE;DEBUG;NET45
+ prompt
+ 4
+ 6
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE;NET45
+ prompt
+ 4
+ true
+ 6
+
+
+
+
+
+
+
+
+
+ {8d71a857-879a-4a10-859e-5ff824ed6688}
+ Discord.Net
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Discord.Net.Modules.Net45/Properties/AssemblyInfo.cs b/src/Discord.Net.Modules.Net45/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..f61c1c991
--- /dev/null
+++ b/src/Discord.Net.Modules.Net45/Properties/AssemblyInfo.cs
@@ -0,0 +1,18 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Discord.Net.Modules")]
+[assembly: AssemblyDescription("A Discord.Net extension adding basic plugin support.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("RogueException")]
+[assembly: AssemblyProduct("Discord.Net.Modules")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")]
+
+[assembly: AssemblyVersion("0.8.1.0")]
+[assembly: AssemblyFileVersion("0.8.1.0")]
+
diff --git a/src/Discord.Net.Modules/Discord.Net.Modules.xproj b/src/Discord.Net.Modules/Discord.Net.Modules.xproj
new file mode 100644
index 000000000..f6db54ed1
--- /dev/null
+++ b/src/Discord.Net.Modules/Discord.Net.Modules.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 01584e8a-78da-486f-9ef9-a894e435841b
+ Discord
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+
+
+ True
+
+
+
\ No newline at end of file
diff --git a/src/Discord.Net.Modules/project.json b/src/Discord.Net.Modules/project.json
new file mode 100644
index 000000000..9f71ee00c
--- /dev/null
+++ b/src/Discord.Net.Modules/project.json
@@ -0,0 +1,22 @@
+{
+ "version": "0.8.1-beta1",
+ "description": "A Discord.Net extension adding basic plugin support.",
+ "authors": [ "RogueException" ],
+ "tags": [ "discord", "discordapp" ],
+ "projectUrl": "https://github.com/RogueException/Discord.Net",
+ "licenseUrl": "http://opensource.org/licenses/MIT",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/RogueException/Discord.Net"
+ },
+ "compilationOptions": {
+ "warningsAsErrors": true
+ },
+ "dependencies": {
+ "Discord.Net": "0.8.1-beta1"
+ },
+ "frameworks": {
+ "net45": { },
+ "dnx451": { }
+ }
+}
diff --git a/src/Discord.Net.Net45/Properties/AssemblyInfo.cs b/src/Discord.Net.Net45/Properties/AssemblyInfo.cs
index 857ea2201..2825ff2a9 100644
--- a/src/Discord.Net.Net45/Properties/AssemblyInfo.cs
+++ b/src/Discord.Net.Net45/Properties/AssemblyInfo.cs
@@ -13,5 +13,5 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")]
-[assembly: AssemblyVersion("0.8.0")]
-[assembly: AssemblyFileVersion("0.8.0")]
+[assembly: AssemblyVersion("0.8.1.0")]
+[assembly: AssemblyFileVersion("0.8.1.0")]
diff --git a/src/Discord.Net/API/Endpoints.cs b/src/Discord.Net/API/Endpoints.cs
index 67c256a88..2ff2711bc 100644
--- a/src/Discord.Net/API/Endpoints.cs
+++ b/src/Discord.Net/API/Endpoints.cs
@@ -13,19 +13,22 @@
public const string Channels = "channels";
public static string Channel(string channelId) => $"channels/{channelId}";
- public static string ChannelTyping(string channelId) => $"channels/{channelId}/typing";
+ public static string ChannelInvites(string channelId) => $"channels/{channelId}/invites";
public static string ChannelMessages(string channelId) => $"channels/{channelId}/messages";
public static string ChannelMessages(string channelId, int limit) => $"channels/{channelId}/messages?limit={limit}";
+ public static string ChannelMessages(string channelId, int limit, string beforeId) => $"channels/{channelId}/messages?limit={limit}&before={beforeId}";
public static string ChannelMessage(string channelId, string msgId) => $"channels/{channelId}/messages/{msgId}";
public static string ChannelMessageAck(string channelId, string msgId) => $"channels/{channelId}/messages/{msgId}/ack";
- public static string ChannelInvites(string channelId) => $"channels/{channelId}/invites";
public static string ChannelPermission(string channelId, string userOrRoleId) => $"channels/{channelId}/permissions/{userOrRoleId}";
+ public static string ChannelTyping(string channelId) => $"channels/{channelId}/typing";
public const string Servers = "guilds";
public static string Server(string serverId) => $"guilds/{serverId}";
+ public static string ServerBan(string serverId, string userId) => $"guilds/{serverId}/bans/{userId}";
public static string ServerChannels(string serverId) => $"guilds/{serverId}/channels";
+ public static string ServerInvites(string serverId) => $"guilds/{serverId}/invites";
public static string ServerMember(string serverId, string userId) => $"guilds/{serverId}/members/{userId}";
- public static string ServerBan(string serverId, string userId) => $"guilds/{serverId}/bans/{userId}";
+ public static string ServerPrune(string serverId, int days) => $"guilds/{serverId}/prune?days={days}";
public static string ServerRoles(string serverId) => $"guilds/{serverId}/roles";
public static string ServerRole(string serverId, string roleId) => $"guilds/{serverId}/roles/{roleId}";
@@ -34,10 +37,10 @@
public static string InviteUrl(string inviteId) => $"https://discord.gg/{inviteId}";
public const string Users = "users";
- public static string UserMe => $"users/@me";
- public static string UserChannels(string userId) => $"users/{userId}/channels";
public static string UserAvatar(string userId, string avatarId) => $"users/{userId}/avatars/{avatarId}.jpg";
-
+ public static string UserChannels(string userId) => $"users/{userId}/channels";
+ public static string UserMe => $"users/@me";
+
public const string Voice = "voice";
public const string VoiceRegions = "voice/regions";
//public const string VoiceIce = "voice/ice";
diff --git a/src/Discord.Net/API/Invites.cs b/src/Discord.Net/API/Invites.cs
index 62d2049b3..d2344dae2 100644
--- a/src/Discord.Net/API/Invites.cs
+++ b/src/Discord.Net/API/Invites.cs
@@ -4,6 +4,7 @@
using Newtonsoft.Json;
using System;
+using System.Collections.Generic;
namespace Discord.API
{
@@ -53,6 +54,7 @@ namespace Discord.API
//Get
public class GetInviteResponse : InviteReference { }
+ public class GetInvitesResponse : List { }
//Accept
public class AcceptInviteResponse : InviteReference { }
diff --git a/src/Discord.Net/API/Members.cs b/src/Discord.Net/API/Members.cs
index 2a48b653d..1f702719e 100644
--- a/src/Discord.Net/API/Members.cs
+++ b/src/Discord.Net/API/Members.cs
@@ -82,9 +82,20 @@ namespace Discord.API
public IEnumerable Roles;
}
+ public class PruneUsersResponse
+ {
+ [JsonProperty("pruned")]
+ public int? Pruned;
+ }
+
//Events
internal sealed class MemberAddEvent : MemberInfo { }
internal sealed class MemberUpdateEvent : MemberInfo { }
internal sealed class MemberRemoveEvent : MemberInfo { }
- internal sealed class MemberVoiceStateUpdateEvent : VoiceMemberInfo { }
+ internal sealed class MemberVoiceStateUpdateEvent : VoiceMemberInfo { }
+ internal sealed class MembersChunkEvent
+ {
+ [JsonProperty("members")]
+ public MemberInfo[] Members;
+ }
}
diff --git a/src/Discord.Net/API/Messages.cs b/src/Discord.Net/API/Messages.cs
index 8fc031dd1..a5edb27ec 100644
--- a/src/Discord.Net/API/Messages.cs
+++ b/src/Discord.Net/API/Messages.cs
@@ -125,6 +125,21 @@ namespace Discord.API
//Get
public sealed class GetMessagesResponse : List { }
+ //Commands
+ internal sealed class GetUsersCommand : WebSocketMessage
+ {
+ public GetUsersCommand() : base(8) { }
+ public class Data
+ {
+ [JsonProperty("guild_id")]
+ public string ServerId;
+ [JsonProperty("query")]
+ public string Query;
+ [JsonProperty("limit")]
+ public int Limit;
+ }
+ }
+
//Events
internal sealed class MessageCreateEvent : MessageInfo { }
internal sealed class MessageUpdateEvent : MessageInfo { }
diff --git a/src/Discord.Net/DiscordAPIClient.cs b/src/Discord.Net/DiscordAPIClient.cs
index 8b3590a27..f547d81f7 100644
--- a/src/Discord.Net/DiscordAPIClient.cs
+++ b/src/Discord.Net/DiscordAPIClient.cs
@@ -92,11 +92,14 @@ namespace Discord
var request = new ReorderChannelsRequest(channels);
return _rest.Patch(Endpoints.ServerChannels(serverId), request);
}
- public Task GetMessages(string channelId, int count)
+ public Task GetMessages(string channelId, int count, string beforeMessageId = null)
{
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
- return _rest.Get(Endpoints.ChannelMessages(channelId, count));
+ if (beforeMessageId != null)
+ return _rest.Get(Endpoints.ChannelMessages(channelId, count, beforeMessageId));
+ else
+ return _rest.Get(Endpoints.ChannelMessages(channelId, count));
}
//Incidents
@@ -123,6 +126,12 @@ namespace Discord
return _rest.Get(Endpoints.Invite(inviteIdOrXkcd));
}
+ public Task GetInvites(string serverId)
+ {
+ if (serverId == null) throw new ArgumentNullException(nameof(serverId));
+
+ return _rest.Get(Endpoints.ServerInvites(serverId));
+ }
public Task AcceptInvite(string inviteId)
{
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId));
@@ -136,7 +145,7 @@ namespace Discord
return _rest.Delete(Endpoints.Invite(inviteId));
}
- //Members
+ //Users
public Task EditUser(string serverId, string userId, bool? mute = null, bool? deaf = null, IEnumerable roles = null)
{
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
@@ -145,27 +154,37 @@ namespace Discord
var request = new EditMemberRequest { Mute = mute, Deaf = deaf, Roles = roles };
return _rest.Patch(Endpoints.ServerMember(serverId, userId), request);
}
- public Task Kick(string serverId, string userId)
+ public Task KickUser(string serverId, string userId)
{
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
if (userId == null) throw new ArgumentNullException(nameof(userId));
return _rest.Delete(Endpoints.ServerMember(serverId, userId));
}
- public Task Ban(string serverId, string userId)
+ public Task BanUser(string serverId, string userId)
{
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
if (userId == null) throw new ArgumentNullException(nameof(userId));
return _rest.Put(Endpoints.ServerBan(serverId, userId));
}
- public Task Unban(string serverId, string userId)
+ public Task UnbanUser(string serverId, string userId)
{
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
if (userId == null) throw new ArgumentNullException(nameof(userId));
return _rest.Delete(Endpoints.ServerBan(serverId, userId));
}
+ public Task PruneUsers(string serverId, int days, bool simulate)
+ {
+ if (serverId == null) throw new ArgumentNullException(nameof(serverId));
+ if (days <= 0) throw new ArgumentOutOfRangeException(nameof(days));
+
+ if (simulate)
+ return _rest.Get(Endpoints.ServerPrune(serverId, days));
+ else
+ return _rest.Post(Endpoints.ServerPrune(serverId, days));
+ }
//Messages
public Task SendMessage(string channelId, string message, IEnumerable mentionedUserIds = null, string nonce = null, bool isTTS = false)
diff --git a/src/Discord.Net/DiscordClient.Bans.cs b/src/Discord.Net/DiscordClient.Bans.cs
index e910d4bf6..6272f9d0b 100644
--- a/src/Discord.Net/DiscordClient.Bans.cs
+++ b/src/Discord.Net/DiscordClient.Bans.cs
@@ -38,7 +38,7 @@ namespace Discord
if (user.Server == null) throw new ArgumentException("Unable to ban a user in a private chat.");
CheckReady();
- return _api.Ban(user.Server.Id, user.Id);
+ return _api.BanUser(user.Server.Id, user.Id);
}
/// Unbans a user from the provided server.
@@ -48,7 +48,7 @@ namespace Discord
if (userId == null) throw new ArgumentNullException(nameof(userId));
CheckReady();
- try { await _api.Unban(server.Id, userId).ConfigureAwait(false); }
+ try { await _api.UnbanUser(server.Id, userId).ConfigureAwait(false); }
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
}
}
diff --git a/src/Discord.Net/DiscordClient.Invites.cs b/src/Discord.Net/DiscordClient.Invites.cs
index 10d1ee016..0d3b8804e 100644
--- a/src/Discord.Net/DiscordClient.Invites.cs
+++ b/src/Discord.Net/DiscordClient.Invites.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using System.Net;
using System.Threading.Tasks;
@@ -10,8 +11,6 @@ namespace Discord
/// Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode
public async Task GetInvite(string inviteIdOrXkcd)
{
- //This doesn't work well if it's an invite to a different server!
-
if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd));
CheckReady();
@@ -26,7 +25,24 @@ namespace Discord
var response = await _api.GetInvite(inviteIdOrXkcd).ConfigureAwait(false);
var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id, response.Inviter?.Id, response.Channel?.Id);
invite.Cache(); //Builds references
- return invite;
+ invite.Update(response);
+ return invite;
+ }
+
+ /// Gets all active (non-expired) invites to a provided server.
+ public async Task GetInvites(Server server)
+ {
+ if (server == null) throw new ArgumentNullException(nameof(server));
+ CheckReady();
+
+ var response = await _api.GetInvites(server.Id).ConfigureAwait(false);
+ return response.Select(x =>
+ {
+ var invite = new Invite(this, x.Code, x.XkcdPass, x.Guild.Id, x.Inviter?.Id, x.Channel?.Id);
+ invite.Cache(); //Builds references
+ invite.Update(x);
+ return invite;
+ }).ToArray();
}
/// Creates a new invite to the default channel of the provided server.
diff --git a/src/Discord.Net/DiscordClient.Messages.cs b/src/Discord.Net/DiscordClient.Messages.cs
index 670164f4f..28b3c068c 100644
--- a/src/Discord.Net/DiscordClient.Messages.cs
+++ b/src/Discord.Net/DiscordClient.Messages.cs
@@ -46,7 +46,7 @@ namespace Discord
public const int MaxMessageSize = 2000;
public event EventHandler MessageReceived;
- private void RaiseMessageCreated(Message msg)
+ private void RaiseMessageReceived(Message msg)
{
if (MessageReceived != null)
RaiseEvent(nameof(MessageReceived), () => MessageReceived(this, new MessageEventArgs(msg)));
@@ -93,6 +93,7 @@ namespace Discord
{
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (text == null) throw new ArgumentNullException(nameof(text));
+ if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less.");
CheckReady();
return SendMessage(channel, text, false);
@@ -102,6 +103,7 @@ namespace Discord
{
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (text == null) throw new ArgumentNullException(nameof(text));
+ if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less.");
CheckReady();
return SendMessage(channel, text, false);
@@ -111,7 +113,8 @@ namespace Discord
{
if (user == null) throw new ArgumentNullException(nameof(user));
if (text == null) throw new ArgumentNullException(nameof(text));
- CheckReady();
+ if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less.");
+ CheckReady();
var channel = await CreatePMChannel(user).ConfigureAwait(false);
return await SendMessage(channel, text).ConfigureAwait(false);
@@ -164,6 +167,8 @@ namespace Discord
public Task EditMessage(Message message, string text)
{
if (message == null) throw new ArgumentNullException(nameof(message));
+ if (text == null) throw new ArgumentNullException(nameof(text));
+ if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less.");
CheckReady();
if (text != null && text.Length > MaxMessageSize)
@@ -210,7 +215,7 @@ namespace Discord
{
try
{
- var msgs = await _api.GetMessages(channel.Id, count).ConfigureAwait(false);
+ var msgs = await _api.GetMessages(channel.Id, count, beforeMessageId).ConfigureAwait(false);
return msgs.Select(x =>
{
Message msg = null;
diff --git a/src/Discord.Net/DiscordClient.Users.cs b/src/Discord.Net/DiscordClient.Users.cs
index dba8f06a4..e63fd04c1 100644
--- a/src/Discord.Net/DiscordClient.Users.cs
+++ b/src/Discord.Net/DiscordClient.Users.cs
@@ -1,5 +1,4 @@
-using Discord.API;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -85,7 +84,7 @@ namespace Discord
RaiseEvent(nameof(UserRemoved), () => UserRemoved(this, new UserEventArgs(user)));
}
public event EventHandler UserUpdated;
- private void RaiseMemberUpdated(User user)
+ private void RaiseUserUpdated(User user)
{
if (UserUpdated != null)
RaiseEvent(nameof(UserUpdated), () => UserUpdated(this, new UserEventArgs(user)));
@@ -170,10 +169,51 @@ namespace Discord
if (user == null) throw new ArgumentNullException(nameof(user));
CheckReady();
- return _api.EditUser(user.Server?.Id, user.Id, mute: mute, deaf: deaf, roles: roles.Select(x => x.Id));
+ var serverId = user.Server?.Id;
+ return _api.EditUser(serverId, user.Id,
+ mute: mute, deaf: deaf,
+ roles: roles.Select(x => x.Id).Where(x => x != serverId));
}
- public Task EditProfile(string currentPassword = "",
+ public Task KickUser(User user)
+ {
+ if (user == null) throw new ArgumentNullException(nameof(user));
+
+ return _api.KickUser(user.Server?.Id, user.Id);
+ }
+ public Task BanUser(User user)
+ {
+ if (user == null) throw new ArgumentNullException(nameof(user));
+
+ return _api.BanUser(user.Server?.Id, user.Id);
+ }
+ public Task UnbanUser(Server server, string userId)
+ {
+ if (server == null) throw new ArgumentNullException(nameof(server));
+ if (userId == null) throw new ArgumentNullException(nameof(userId));
+
+ return _api.UnbanUser(server.Id, userId);
+ }
+
+ public async Task PruneUsers(string serverId, int days, bool simulate = false)
+ {
+ if (serverId == null) throw new ArgumentNullException(nameof(serverId));
+ if (days <= 0) throw new ArgumentOutOfRangeException(nameof(days));
+ CheckReady();
+
+ var response = await _api.PruneUsers(serverId, days, simulate);
+ return response.Pruned ?? 0;
+ }
+
+ /// When Config.UseLargeThreshold is enabled, running this command will request the Discord server to provide you with all offline users for a particular server.
+ public void RequestOfflineUsers(string serverId)
+ {
+ if (serverId == null) throw new ArgumentNullException(nameof(serverId));
+
+ _dataSocket.SendGetUsers(serverId);
+ }
+
+ public Task EditProfile(string currentPassword = "",
string username = null, string email = null, string password = null,
ImageType avatarType = ImageType.Png, byte[] avatar = null)
{
diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs
index c162c237f..f14874dee 100644
--- a/src/Discord.Net/DiscordClient.cs
+++ b/src/Discord.Net/DiscordClient.cs
@@ -90,7 +90,7 @@ namespace Discord
ChannelUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
$"Channel Updated: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}");
MessageReceived += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
- $"Message Created: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}");
+ $"Message Received: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}");
MessageDeleted += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
$"Message Deleted: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}");
MessageUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
@@ -106,26 +106,26 @@ namespace Discord
UserUnbanned += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
$"Unbanned User: {e.Server?.Name ?? "[Private]"}/{e.UserId}");
UserAdded += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
- $"User Joined: {e.Server?.Name ?? "[Private]"}/{e.User.Id}");
+ $"User Joined: {e.Server?.Name ?? "[Private]"}/{e.User.Name}");
UserRemoved += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
- $"User Left: {e.Server?.Name ?? "[Private]"}/{e.User.Id}");
+ $"User Left: {e.Server?.Name ?? "[Private]"}/{e.User.Name}");
UserUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
- $"User Updated: {e.Server?.Name ?? "[Private]"}/{e.User.Id}");
+ $"User Updated: {e.Server?.Name ?? "[Private]"}/{e.User.Name}");
UserVoiceStateUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
- $"User Updated (Voice State): {e.Server?.Name ?? "[Private]"}/{e.User.Id}");
+ $"User Updated (Voice State): {e.Server?.Name ?? "[Private]"}/{e.User.Name}");
ProfileUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client,
"Profile Updated");
}
if (_config.LogLevel >= LogMessageSeverity.Verbose)
{
UserIsTypingUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client,
- $"Updated User (Is Typing): {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.User?.Name}");
+ $"User Updated (Is Typing): {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.User?.Name}");
MessageReadRemotely += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client,
$"Read Message (Remotely): {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}");
MessageSent += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client,
$"Sent Message: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}");
UserPresenceUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client,
- $"Updated Member (Presence): {e.Server?.Name ?? "[Private]"}/{e.User?.Name}");
+ $"User Updated (Presence): {e.Server?.Name ?? "[Private]"}/{e.User?.Name}");
_api.RestClient.OnRequest += (s, e) =>
{
@@ -140,9 +140,9 @@ namespace Discord
_channels.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created Channel {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}");
_channels.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed Channel {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}");
_channels.Cleared += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Cleared Channels");
- _users.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created Member {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}");
- _users.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed Member {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}");
- _users.Cleared += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Cleared Members");
+ _users.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created User {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}");
+ _users.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed User {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}");
+ _users.Cleared += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Cleared Users");
_messages.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created Message {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Channel.Id}/{e.Item.Id}");
_messages.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed Message {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Channel.Id}/{e.Item.Id}");
_messages.ItemRemapped += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Remapped Message {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Channel.Id}/[{e.OldId} -> {e.NewId}]");
@@ -406,7 +406,7 @@ namespace Discord
if (user != null)
{
user.Update(data);
- RaiseMemberUpdated(user);
+ RaiseUserUpdated(user);
}
}
break;
@@ -418,6 +418,17 @@ namespace Discord
RaiseUserRemoved(user);
}
break;
+ case "GUILD_MEMBERS_CHUNK":
+ {
+ var data = e.Payload.ToObject(_serializer);
+ foreach (var memberData in data.Members)
+ {
+ var user = _users.GetOrAdd(memberData.User.Id, memberData.GuildId);
+ user.Update(memberData);
+ //RaiseUserAdded(user);
+ }
+ }
+ break;
//Roles
case "GUILD_ROLE_CREATE":
@@ -499,7 +510,7 @@ namespace Discord
}
}
- RaiseMessageCreated(msg);
+ RaiseMessageReceived(msg);
if (Config.AckMessages && !isAuthor)
await _api.AckMessage(data.Id, data.ChannelId).ConfigureAwait(false);
diff --git a/src/Discord.Net/Helpers/Reference.cs b/src/Discord.Net/Helpers/Reference.cs
index e02932e9b..4b2aecaa6 100644
--- a/src/Discord.Net/Helpers/Reference.cs
+++ b/src/Discord.Net/Helpers/Reference.cs
@@ -63,6 +63,6 @@ namespace Discord
_getItem = getItem;
_onCache = onCache;
_onUncache = onUncache;
- }
+ }
}
}
diff --git a/src/Discord.Net/Models/Invite.cs b/src/Discord.Net/Models/Invite.cs
index f08f1c6cc..97ad94a04 100644
--- a/src/Discord.Net/Models/Invite.cs
+++ b/src/Discord.Net/Models/Invite.cs
@@ -26,24 +26,54 @@ namespace Discord
[JsonIgnore]
public User Inviter => _inviter.Value;
private readonly Reference _inviter;
+ private User _generatedInviter;
/// Returns the server this invite is to.
[JsonIgnore]
public Server Server => _server.Value;
private readonly Reference _server;
+ private Server _generatedServer;
/// Returns the channel this invite is to.
[JsonIgnore]
public Channel Channel => _channel.Value;
private readonly Reference _channel;
+ private Channel _generatedChannel;
internal Invite(DiscordClient client, string code, string xkcdPass, string serverId, string inviterId, string channelId)
: base(client, code)
{
XkcdCode = xkcdPass;
- _server = new Reference(serverId, x => _client.Servers[x] ?? new Server(client, x));
- _inviter = new Reference(serverId, x => _client.Users[x, _server.Id] ?? new User(client, x, _server.Id));
- _channel = new Reference(serverId, x => _client.Channels[x] ?? new Channel(client, x, _server.Id, null));
+ _server = new Reference(serverId, x =>
+ {
+ var server = _client.Servers[x];
+ if (server == null)
+ {
+ server = _generatedServer = new Server(client, x);
+ server.Cache();
+ }
+ return server;
+ });
+ _inviter = new Reference(serverId, x =>
+ {
+ var inviter = _client.Users[x, _server.Id];
+ if (inviter == null)
+ {
+ inviter = _generatedInviter = new User(client, x, _server.Id);
+ inviter.Cache();
+ }
+ return inviter;
+ });
+ _channel = new Reference(serverId, x =>
+ {
+ var channel = _client.Channels[x];
+ if (channel == null)
+ {
+ channel = _generatedChannel = new Channel(client, x, _server.Id, null);
+ channel.Cache();
+ }
+ return channel;
+ });
}
internal override void LoadReferences()
{
@@ -54,10 +84,21 @@ namespace Discord
internal override void UnloadReferences() { }
public override string ToString() => XkcdCode ?? Id;
-
- internal void Update(InviteInfo model)
+
+ internal void Update(InviteReference model)
+ {
+ if (model.Guild != null && _generatedServer != null)
+ _generatedServer.Update(model.Guild);
+ if (model.Inviter != null && _generatedInviter != null)
+ _generatedInviter.Update(model.Inviter);
+ if (model.Channel != null && _generatedChannel != null)
+ _generatedChannel.Update(model.Channel);
+ }
+ internal void Update(InviteInfo model)
{
+ Update(model as InviteReference);
+
if (model.IsRevoked != null)
IsRevoked = model.IsRevoked.Value;
if (model.IsTemporary != null)
@@ -68,6 +109,6 @@ namespace Discord
MaxUses = model.MaxUses.Value;
if (model.Uses != null)
Uses = model.Uses.Value;
- }
+ }
}
}
diff --git a/src/Discord.Net/Models/Server.cs b/src/Discord.Net/Models/Server.cs
index d6689d1a4..602f01db0 100644
--- a/src/Discord.Net/Models/Server.cs
+++ b/src/Discord.Net/Models/Server.cs
@@ -55,11 +55,6 @@ namespace Discord
public IEnumerable VoiceChannels => _channels.Select(x => x.Value).Where(x => x.Type == ChannelType.Voice);
private ConcurrentDictionary _channels;
- /// Returns a collection of all invites to this server.
- [JsonIgnore]
- public IEnumerable Invites => _invites.Values;
- private ConcurrentDictionary _invites;
-
/// Returns a collection of all users within this server with their server-specific data.
[JsonIgnore]
public IEnumerable Members => _members.Select(x => x.Value);
@@ -85,7 +80,6 @@ namespace Discord
//Local Cache
_bans = new ConcurrentDictionary();
- _invites = new ConcurrentDictionary();
}
internal override void LoadReferences()
{
@@ -113,25 +107,26 @@ namespace Discord
roles.Clear();
//Local Cache
- var invites = _invites;
- foreach (var invite in invites)
- invite.Value.Uncache();
- invites.Clear();
-
_bans.Clear();
_afkChannel.Unload();
}
- internal void Update(GuildInfo model)
+ internal void Update(GuildReference model)
+ {
+ if (model.Name != null)
+ Name = model.Name;
+ }
+
+ internal void Update(GuildInfo model)
{
+ Update(model as GuildReference);
+
if (model.AFKTimeout != null)
AFKTimeout = model.AFKTimeout.Value;
if (model.AFKChannelId != null)
if (model.JoinedAt != null)
JoinedAt = model.JoinedAt.Value;
- if (model.Name != null)
- Name = model.Name;
if (model.OwnerId != null && _ownerId != model.OwnerId)
{
_ownerId = model.OwnerId;
@@ -212,9 +207,6 @@ namespace Discord
_channels.TryRemove(channel.Id, out channel);
}
- internal void AddInvite(Invite invite) => _invites.TryAdd(invite.Id, invite);
- internal void RemoveInvite(Invite invite) => _invites.TryRemove(invite.Id, out invite);
-
internal void AddMember(User user)
{
if (_members.TryAdd(user.Id, user))
diff --git a/src/Discord.Net/Models/User.cs b/src/Discord.Net/Models/User.cs
index 4fba8ae5b..1c28c5531 100644
--- a/src/Discord.Net/Models/User.cs
+++ b/src/Discord.Net/Models/User.cs
@@ -24,7 +24,7 @@ namespace Discord
/// Returns the unique identifier for this user's current avatar.
public string AvatarId { get; private set; }
/// Returns the URL to this user's current avatar.
- public string AvatarUrl => API.Endpoints.UserAvatar(Id, AvatarId);
+ public string AvatarUrl => AvatarId != null ? API.Endpoints.UserAvatar(Id, AvatarId) : null;
/// Returns the datetime that this user joined this server.
public DateTime JoinedAt { get; private set; }
@@ -61,7 +61,8 @@ namespace Discord
private readonly Reference _server;
[JsonIgnore]
- public Channel VoiceChannel { get; private set; }
+ public Channel VoiceChannel => _voiceChannel.Value;
+ private Reference _voiceChannel;
[JsonIgnore]
public IEnumerable Roles => _roles.Select(x => x.Value);
@@ -130,6 +131,8 @@ namespace Discord
if (Id == _client.CurrentUserId)
x.CurrentUser = null;
});
+ _voiceChannel = new Reference(x => _client.Channels[x]);
+
Status = UserStatus.Offline;
_channels = new ConcurrentDictionary();
if (serverId != null)
@@ -210,16 +213,16 @@ namespace Discord
SessionId = model.SessionId;
if (model.Token != null)
Token = model.Token;
-
- if (model.ChannelId != null)
- VoiceChannel = _client.Channels[model.ChannelId];
+
if (model.IsSelfDeafened != null)
IsSelfDeafened = model.IsSelfDeafened.Value;
if (model.IsSelfMuted != null)
IsSelfMuted = model.IsSelfMuted.Value;
if (model.IsServerSuppressed != null)
IsServerSuppressed = model.IsServerSuppressed.Value;
- }
+
+ _voiceChannel.Id = model.ChannelId; //Can be null
+ }
private void UpdateRoles(IEnumerable roles)
{
if (_server.Id != null)
diff --git a/src/Discord.Net/Net/WebSockets/DataWebSocket.cs b/src/Discord.Net/Net/WebSockets/DataWebSocket.cs
index 49d368748..7e59565d7 100644
--- a/src/Discord.Net/Net/WebSockets/DataWebSocket.cs
+++ b/src/Discord.Net/Net/WebSockets/DataWebSocket.cs
@@ -27,7 +27,7 @@ namespace Discord.Net.WebSockets
msg.Payload.Token = token;
msg.Payload.Properties["$device"] = "Discord.Net";
if (_client.Config.UseLargeThreshold)
- msg.Payload.LargeThreshold = 50;
+ msg.Payload.LargeThreshold = 100;
msg.Payload.Compress = true;
QueueMessage(msg);
}
@@ -141,5 +141,11 @@ namespace Discord.Net.WebSockets
leaveVoice.Payload.ServerId = serverId;
QueueMessage(leaveVoice);
}
+ public void SendGetUsers(string serverId, string query = "", int limit = 0)
+ {
+ var getOfflineUsers = new GetUsersCommand();
+ getOfflineUsers.Payload.ServerId = serverId;
+ QueueMessage(getOfflineUsers);
+ }
}
}
diff --git a/src/Discord.Net/project.json b/src/Discord.Net/project.json
index 8a2b2e1b2..3d0b55689 100644
--- a/src/Discord.Net/project.json
+++ b/src/Discord.Net/project.json
@@ -1,5 +1,5 @@
{
- "version": "0.8.0-beta1",
+ "version": "0.8.1-beta1",
"description": "An unofficial .Net API wrapper for the Discord client.",
"authors": [
"RogueException"