Re-partialed DiscordClient by object type and moved Finds from collections.
This commit is contained in:
@@ -154,17 +154,35 @@
|
||||
<Compile Include="..\Discord.Net\DiscordAPIClientConfig.cs">
|
||||
<Link>DiscordAPIClientConfig.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.API.cs">
|
||||
<Link>DiscordClient.API.cs</Link>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Bans.cs">
|
||||
<Link>DiscordClient.Bans.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Cache.cs">
|
||||
<Link>DiscordClient.Cache.cs</Link>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Channels.cs">
|
||||
<Link>DiscordClient.Channels.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.cs">
|
||||
<Link>DiscordClient.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Events.cs">
|
||||
<Link>DiscordClient.Events.cs</Link>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Invites.cs">
|
||||
<Link>DiscordClient.Invites.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Members.cs">
|
||||
<Link>DiscordClient.Members.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Messages.cs">
|
||||
<Link>DiscordClient.Messages.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Permissions.cs">
|
||||
<Link>DiscordClient.Permissions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Roles.cs">
|
||||
<Link>DiscordClient.Roles.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Servers.cs">
|
||||
<Link>DiscordClient.Servers.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClient.Users.cs">
|
||||
<Link>DiscordClient.Users.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\DiscordClientConfig.cs">
|
||||
<Link>DiscordClientConfig.cs</Link>
|
||||
|
||||
@@ -127,8 +127,8 @@ namespace Discord.Collections
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void OnCreated(TValue item);
|
||||
protected abstract void OnRemoved(TValue item);
|
||||
protected virtual void OnCreated(TValue item) { }
|
||||
protected virtual void OnRemoved(TValue item) { }
|
||||
|
||||
public IEnumerator<TValue> GetEnumerator()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Discord.Collections
|
||||
{
|
||||
@@ -46,29 +44,13 @@ namespace Discord.Collections
|
||||
}
|
||||
}
|
||||
|
||||
internal Channel this[string id] => Get(id);
|
||||
|
||||
internal IEnumerable<Channel> Find(string serverId, string name, string type = null)
|
||||
internal Channel this[string id]
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
|
||||
IEnumerable<Channel> result;
|
||||
if (name.StartsWith("#"))
|
||||
get
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
result = this.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase));
|
||||
if (id == null) throw new ArgumentNullException(nameof(id));
|
||||
return Get(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = this.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (type != null)
|
||||
result = result.Where(x => x.Type == type);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Discord.Collections
|
||||
{
|
||||
@@ -45,52 +43,8 @@ namespace Discord.Collections
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
return Get(GetKey(userId, serverId));
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<Member> Find(Server server, string name)
|
||||
{
|
||||
if (server == null) throw new ArgumentNullException(nameof(server));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (name.StartsWith("@"))
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
return server.Members.Where(x =>
|
||||
{
|
||||
var user = x.User;
|
||||
if (user == null)
|
||||
return false;
|
||||
return string.Equals(user.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(user.Name, name2, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return server.Members.Where(x =>
|
||||
{
|
||||
var user = x.User;
|
||||
if (user == null)
|
||||
return false;
|
||||
return string.Equals(x.User.Name, name, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal Member Find(string username, string discriminator)
|
||||
{
|
||||
if (username == null) throw new ArgumentNullException(nameof(username));
|
||||
if (discriminator == null) throw new ArgumentNullException(nameof(discriminator));
|
||||
|
||||
if (username.StartsWith("@"))
|
||||
username = username.Substring(1);
|
||||
|
||||
return this.Where(x =>
|
||||
string.Equals(x.Name, username, StringComparison.OrdinalIgnoreCase) &&
|
||||
x.Discriminator == discriminator
|
||||
)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
namespace Discord.Collections
|
||||
using System;
|
||||
|
||||
namespace Discord.Collections
|
||||
{
|
||||
public sealed class Messages : AsyncCollection<Message>
|
||||
{
|
||||
internal Messages(DiscordClient client, object writerLock)
|
||||
: base(client, writerLock)
|
||||
{
|
||||
}
|
||||
: base(client, writerLock) { }
|
||||
|
||||
internal Message GetOrAdd(string id, string channelId, string userId) => GetOrAdd(id, () => new Message(_client, id, channelId, userId));
|
||||
internal new Message TryRemove(string id) => base.TryRemove(id);
|
||||
@@ -26,6 +26,13 @@
|
||||
user.RemoveRef();
|
||||
}
|
||||
|
||||
internal Message this[string id] => Get(id);
|
||||
internal Message this[string id]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (id == null) throw new ArgumentNullException(nameof(id));
|
||||
return Get(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Discord.Collections
|
||||
{
|
||||
@@ -23,23 +21,12 @@ namespace Discord.Collections
|
||||
item.Server.RemoveRole(item.Id);
|
||||
}
|
||||
|
||||
internal Role this[string id] => Get(id);
|
||||
|
||||
internal IEnumerable<Role> Find(string serverId, string name)
|
||||
internal Role this[string id]
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (name.StartsWith("@"))
|
||||
get
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
return this.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
if (id == null) throw new ArgumentNullException(nameof(id));
|
||||
return Get(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ namespace Discord.Collections
|
||||
|
||||
internal Server GetOrAdd(string id) => base.GetOrAdd(id, () => new Server(_client, id));
|
||||
internal new Server TryRemove(string id) => base.TryRemove(id);
|
||||
|
||||
protected override void OnCreated(Server item) { }
|
||||
|
||||
protected override void OnRemoved(Server item)
|
||||
{
|
||||
var channels = _client.Channels;
|
||||
@@ -29,12 +28,5 @@ namespace Discord.Collections
|
||||
}
|
||||
|
||||
internal Server this[string id] => Get(id);
|
||||
|
||||
internal IEnumerable<Server> Find(string name)
|
||||
{
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
return this.Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Discord.Collections
|
||||
{
|
||||
@@ -15,22 +13,12 @@ namespace Discord.Collections
|
||||
protected override void OnCreated(User item) { }
|
||||
protected override void OnRemoved(User item) { }
|
||||
|
||||
internal User this[string id] => Get(id);
|
||||
|
||||
internal IEnumerable<User> Find(string name)
|
||||
internal User this[string id]
|
||||
{
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (name.StartsWith("@"))
|
||||
get
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
return this.Where(x =>
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.Where(x =>
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
if (id == null) throw new ArgumentNullException(nameof(id));
|
||||
return Get(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,756 +0,0 @@
|
||||
using Discord.API;
|
||||
using Discord.Net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public const int MaxMessageSize = 2000;
|
||||
|
||||
//Bans
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(Member member)
|
||||
=> Ban(member?.ServerId, member?.UserId);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(Server server, User user)
|
||||
=> Ban(server?.Id, user?.Id);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(Server server, string userId)
|
||||
=> Ban(server?.Id, userId);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(string server, User user)
|
||||
=> Ban(server, user?.Id);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(string serverId, string userId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
return _api.Ban(serverId, userId);
|
||||
}
|
||||
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(Member member)
|
||||
=> Unban(member?.ServerId, member?.UserId);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(Server server, User user)
|
||||
=> Unban(server?.Id, user?.Id);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(Server server, string userId)
|
||||
=> Unban(server?.Id, userId);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(string server, User user)
|
||||
=> Unban(server, user?.Id);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public async Task Unban(string serverId, string userId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
try { await _api.Unban(serverId, userId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
|
||||
//Channels
|
||||
/// <summary> Creates a new channel with the provided name and type (see ChannelTypes). </summary>
|
||||
public Task<Channel> CreateChannel(Server server, string name, string type = ChannelTypes.Text)
|
||||
=> CreateChannel(server?.Id, name, type);
|
||||
/// <summary> Creates a new channel with the provided name and type (see ChannelTypes). </summary>
|
||||
public async Task<Channel> CreateChannel(string serverId, string name, string type = ChannelTypes.Text)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
|
||||
var response = await _api.CreateChannel(serverId, name, type).ConfigureAwait(false);
|
||||
var channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id);
|
||||
channel.Update(response);
|
||||
return channel;
|
||||
}
|
||||
|
||||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary>
|
||||
public Task<Channel> CreatePMChannel(string userId) => CreatePMChannel(_users[userId], userId);
|
||||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary>
|
||||
public Task<Channel> CreatePMChannel(User user) => CreatePMChannel(user, user?.Id);
|
||||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary>
|
||||
public Task<Channel> CreatePMChannel(Member member) => CreatePMChannel(member.User, member.UserId);
|
||||
private async Task<Channel> CreatePMChannel(User user, string userId)
|
||||
{
|
||||
CheckReady();
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
Channel channel = null;
|
||||
if (user != null)
|
||||
channel = user.PrivateChannel;
|
||||
if (channel == null)
|
||||
{
|
||||
var response = await _api.CreatePMChannel(CurrentUserId, userId).ConfigureAwait(false);
|
||||
user = _users.GetOrAdd(response.Recipient?.Id);
|
||||
user.Update(response.Recipient);
|
||||
channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id);
|
||||
channel.Update(response);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
/// <summary> Edits the provided channel, changing only non-null attributes. </summary>
|
||||
public Task EditChannel(string channelId, string name = null, string topic = null, int? position = null)
|
||||
=> EditChannel(_channels[channelId], name: name, topic: topic, position: position);
|
||||
/// <summary> Edits the provided channel, changing only non-null attributes. </summary>
|
||||
public async Task EditChannel(Channel channel, string name = null, string topic = null, int? position = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
await _api.EditChannel(channel.Id, name: name, topic: topic);
|
||||
|
||||
if (position != null)
|
||||
{
|
||||
int oldPos = channel.Position;
|
||||
int newPos = position.Value;
|
||||
int minPos;
|
||||
Channel[] channels = channel.Server.Channels.OrderBy(x => x.Position).ToArray();
|
||||
|
||||
if (oldPos < newPos) //Moving Down
|
||||
{
|
||||
minPos = oldPos;
|
||||
for (int i = oldPos; i < newPos; i++)
|
||||
channels[i] = channels[i + 1];
|
||||
channels[newPos] = channel;
|
||||
}
|
||||
else //(oldPos > newPos) Moving Up
|
||||
{
|
||||
minPos = newPos;
|
||||
for (int i = oldPos; i > newPos; i--)
|
||||
channels[i] = channels[i - 1];
|
||||
channels[newPos] = channel;
|
||||
}
|
||||
await _api.ReorderChannels(channel.ServerId, channels.Skip(minPos).Select(x => x.Id), minPos);
|
||||
}
|
||||
}
|
||||
|
||||
public Task ReorderChannels(Server server, IEnumerable<object> channels, int startPos = 0)
|
||||
=> ReorderChannels(server.Id, channels, startPos);
|
||||
public Task ReorderChannels(string serverId, IEnumerable<object> channels, int startPos = 0)
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (channels == null) throw new ArgumentNullException(nameof(channels));
|
||||
if (startPos < 0) throw new ArgumentOutOfRangeException(nameof(startPos), "startPos must be a positive integer.");
|
||||
|
||||
var channelIds = CollectionHelper.FlattenChannels(channels);
|
||||
return _api.ReorderChannels(serverId, channelIds, startPos);
|
||||
}
|
||||
|
||||
/// <summary> Destroys the provided channel. </summary>
|
||||
public Task<Channel> DestroyChannel(Channel channel)
|
||||
=> DestroyChannel(channel?.Id);
|
||||
/// <summary> Destroys the provided channel. </summary>
|
||||
public async Task<Channel> DestroyChannel(string channelId)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
|
||||
try { await _api.DestroyChannel(channelId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
return _channels.TryRemove(channelId);
|
||||
}
|
||||
|
||||
//Invites
|
||||
/// <summary> Creates a new invite to the default channel of the provided server. </summary>
|
||||
/// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param>
|
||||
/// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param>
|
||||
/// <param name="hasXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to 0. </param>
|
||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to 0 to have unlimited uses. </param>
|
||||
public Task<Invite> CreateInvite(Server server, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false)
|
||||
=> CreateInvite(server?.DefaultChannelId, maxAge, maxUses, tempMembership, hasXkcd);
|
||||
/// <summary> Creates a new invite to the provided channel. </summary>
|
||||
/// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param>
|
||||
/// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param>
|
||||
/// <param name="hasXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to 0. </param>
|
||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to 0 to have unlimited uses. </param>
|
||||
public Task<Invite> CreateInvite(Channel channel, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false)
|
||||
=> CreateInvite(channel?.Id, maxAge, maxUses, tempMembership, hasXkcd);
|
||||
/// <summary> Creates a new invite to the provided channel. </summary>
|
||||
/// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param>
|
||||
/// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param>
|
||||
/// <param name="hasXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to 0. </param>
|
||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to 0 to have unlimited uses. </param>
|
||||
public async Task<Invite> CreateInvite(string serverOrChannelId, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverOrChannelId == null) throw new ArgumentNullException(nameof(serverOrChannelId));
|
||||
if (maxAge <= 0) throw new ArgumentOutOfRangeException(nameof(maxAge));
|
||||
if (maxUses <= 0) throw new ArgumentOutOfRangeException(nameof(maxUses));
|
||||
|
||||
var response = await _api.CreateInvite(serverOrChannelId, maxAge, maxUses, tempMembership, hasXkcd).ConfigureAwait(false);
|
||||
var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id);
|
||||
invite.Update(response);
|
||||
return invite;
|
||||
}
|
||||
|
||||
/// <summary> Deletes the provided invite. </summary>
|
||||
public async Task DestroyInvite(string inviteId)
|
||||
{
|
||||
CheckReady();
|
||||
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId));
|
||||
|
||||
try
|
||||
{
|
||||
//Check if this is a human-readable link and get its ID
|
||||
var response = await _api.GetInvite(inviteId).ConfigureAwait(false);
|
||||
await _api.DeleteInvite(response.Code).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
|
||||
/// <summary> Gets more info about the provided invite code. </summary>
|
||||
/// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks>
|
||||
public async Task<Invite> GetInvite(string inviteIdOrXkcd)
|
||||
{
|
||||
CheckReady();
|
||||
if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd));
|
||||
|
||||
var response = await _api.GetInvite(inviteIdOrXkcd).ConfigureAwait(false);
|
||||
var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id);
|
||||
invite.Update(response);
|
||||
return invite;
|
||||
}
|
||||
|
||||
/// <summary> Accepts the provided invite. </summary>
|
||||
public Task AcceptInvite(Invite invite)
|
||||
{
|
||||
CheckReady();
|
||||
if (invite == null) throw new ArgumentNullException(nameof(invite));
|
||||
|
||||
return _api.AcceptInvite(invite.Id);
|
||||
}
|
||||
/// <summary> Accepts the provided invite. </summary>
|
||||
public async Task AcceptInvite(string inviteId)
|
||||
{
|
||||
CheckReady();
|
||||
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId));
|
||||
|
||||
//Remove trailing slash and any non-code url parts
|
||||
if (inviteId.Length > 0 && inviteId[inviteId.Length - 1] == '/')
|
||||
inviteId = inviteId.Substring(0, inviteId.Length - 1);
|
||||
int index = inviteId.LastIndexOf('/');
|
||||
if (index >= 0)
|
||||
inviteId = inviteId.Substring(index + 1);
|
||||
|
||||
//Check if this is a human-readable link and get its ID
|
||||
var invite = await GetInvite(inviteId).ConfigureAwait(false);
|
||||
await _api.AcceptInvite(invite.Id).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//Members
|
||||
public Task EditMember(Member member, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
=> EditMember(member?.ServerId, member?.UserId, mute, deaf, roles);
|
||||
public Task EditMember(Server server, User user, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
=> EditMember(server?.Id, user?.Id, mute, deaf, roles);
|
||||
public Task EditMember(Server server, string userId, bool? mute = null, bool? deaf = null, IEnumerable<string> roles = null)
|
||||
=> EditMember(server?.Id, userId, mute, deaf, roles);
|
||||
public Task EditMember(string serverId, User user, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
=> EditMember(serverId, user?.Id, mute, deaf, roles);
|
||||
public Task EditMember(string serverId, string userId, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
if (userId == null) throw new NullReferenceException(nameof(userId));
|
||||
|
||||
var newRoles = CollectionHelper.FlattenRoles(roles);
|
||||
return _api.EditMember(serverId, userId, mute: mute, deaf: deaf, roles: newRoles);
|
||||
}
|
||||
|
||||
//Messages
|
||||
/// <summary> Sends a message to the provided channel. To include a mention, see the Mention static helper class. </summary>
|
||||
public Task<Message[]> SendMessage(Channel channel, string text)
|
||||
=> SendMessage(channel, text, MentionHelper.GetUserIds(text), false);
|
||||
/// <summary> Sends a message to the provided channel. To include a mention, see the Mention static helper class. </summary>
|
||||
public Task<Message[]> SendMessage(string channelId, string text)
|
||||
=> SendMessage(_channels[channelId], text, MentionHelper.GetUserIds(text), false);
|
||||
private async Task<Message[]> SendMessage(Channel channel, string text, IEnumerable<object> mentionedUsers = null, bool isTextToSpeech = false)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||
if (text == null) throw new ArgumentNullException(nameof(text));
|
||||
var mentionedUserIds = CollectionHelper.FlattenUsers(mentionedUsers);
|
||||
|
||||
int blockCount = (int)Math.Ceiling(text.Length / (double)MaxMessageSize);
|
||||
Message[] result = new Message[blockCount];
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
{
|
||||
int index = i * MaxMessageSize;
|
||||
string blockText = text.Substring(index, Math.Min(2000, text.Length - index));
|
||||
var nonce = GenerateNonce();
|
||||
if (Config.UseMessageQueue)
|
||||
{
|
||||
var msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, CurrentUserId);
|
||||
var currentUser = msg.User;
|
||||
msg.Update(new MessageInfo
|
||||
{
|
||||
Content = blockText,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
Author = new UserReference { Avatar = currentUser.AvatarId, Discriminator = currentUser.Discriminator, Id = CurrentUserId, Username = currentUser.Name },
|
||||
ChannelId = channel.Id,
|
||||
IsTextToSpeech = isTextToSpeech
|
||||
});
|
||||
msg.IsQueued = true;
|
||||
msg.Nonce = nonce;
|
||||
result[i] = msg;
|
||||
_pendingMessages.Enqueue(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
var model = await _api.SendMessage(channel.Id, blockText, mentionedUserIds, nonce, isTextToSpeech).ConfigureAwait(false);
|
||||
var msg = _messages.GetOrAdd(model.Id, channel.Id, model.Author.Id);
|
||||
msg.Update(model);
|
||||
RaiseMessageSent(msg);
|
||||
result[i] = msg;
|
||||
}
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Sends a private message to the provided user. </summary>
|
||||
public Task<Message[]> SendPrivateMessage(Member member, string text)
|
||||
=> SendPrivateMessage(member?.UserId, text);
|
||||
/// <summary> Sends a private message to the provided user. </summary>
|
||||
public Task<Message[]> SendPrivateMessage(User user, string text)
|
||||
=> SendPrivateMessage(user?.Id, text);
|
||||
/// <summary> Sends a private message to the provided user. </summary>
|
||||
public async Task<Message[]> SendPrivateMessage(string userId, string text)
|
||||
{
|
||||
var channel = await CreatePMChannel(userId).ConfigureAwait(false);
|
||||
return await SendMessage(channel, text, new string[0]).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary> Sends a file to the provided channel. </summary>
|
||||
public Task SendFile(Channel channel, string filePath)
|
||||
=> SendFile(channel?.Id, filePath);
|
||||
/// <summary> Sends a file to the provided channel. </summary>
|
||||
public Task SendFile(string channelId, string filePath)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
if (filePath == null) throw new ArgumentNullException(nameof(filePath));
|
||||
|
||||
return _api.SendFile(channelId, filePath);
|
||||
}
|
||||
|
||||
/// <summary> Edits the provided message, changing only non-null attributes. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks>
|
||||
public Task EditMessage(Message message, string text = null, IEnumerable<object> mentionedUsers = null)
|
||||
=> EditMessage(message?.ChannelId, message?.Id, text, mentionedUsers);
|
||||
/// <summary> Edits the provided message, changing only non-null attributes. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks>
|
||||
public Task EditMessage(Channel channel, string messageId, string text = null, IEnumerable<object> mentionedUsers = null)
|
||||
=> EditMessage(channel?.Id, messageId, text, mentionedUsers);
|
||||
/// <summary> Edits the provided message, changing only non-null attributes. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks>
|
||||
public async Task EditMessage(string channelId, string messageId, string text = null, IEnumerable<object> mentionedUsers = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
if (messageId == null) throw new ArgumentNullException(nameof(messageId));
|
||||
var mentionedUserIds = CollectionHelper.FlattenUsers(mentionedUsers);
|
||||
|
||||
if (text != null && text.Length > MaxMessageSize)
|
||||
text = text.Substring(0, MaxMessageSize);
|
||||
|
||||
var model = await _api.EditMessage(messageId, channelId, text, mentionedUserIds).ConfigureAwait(false);
|
||||
var msg = _messages[messageId];
|
||||
if (msg != null)
|
||||
msg.Update(model);
|
||||
}
|
||||
|
||||
/// <summary> Deletes the provided message. </summary>
|
||||
public Task DeleteMessage(Message msg)
|
||||
=> DeleteMessage(msg?.ChannelId, msg?.Id);
|
||||
/// <summary> Deletes the provided message. </summary>
|
||||
public async Task DeleteMessage(string channelId, string msgId)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
if (msgId == null) throw new ArgumentNullException(nameof(msgId));
|
||||
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(msgId, channelId).ConfigureAwait(false);
|
||||
_messages.TryRemove(msgId);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
public async Task DeleteMessages(IEnumerable<Message> msgs)
|
||||
{
|
||||
CheckReady();
|
||||
if (msgs == null) throw new ArgumentNullException(nameof(msgs));
|
||||
|
||||
foreach (var msg in msgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(msg.Id, msg.ChannelId).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
}
|
||||
public async Task DeleteMessages(string channelId, IEnumerable<string> msgIds)
|
||||
{
|
||||
CheckReady();
|
||||
if (msgIds == null) throw new ArgumentNullException(nameof(msgIds));
|
||||
|
||||
foreach (var msgId in msgIds)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(msgId, channelId).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Downloads last count messages from the server, starting at beforeMessageId if it's provided. </summary>
|
||||
public Task<Message[]> DownloadMessages(Channel channel, int count, string beforeMessageId = null, bool cache = true)
|
||||
=> DownloadMessages(channel.Id, count, beforeMessageId, cache);
|
||||
/// <summary> Downloads last count messages from the server, starting at beforeMessageId if it's provided. </summary>
|
||||
public async Task<Message[]> DownloadMessages(string channelId, int count, string beforeMessageId = null, bool cache = true)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new NullReferenceException(nameof(channelId));
|
||||
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
|
||||
if (count == 0) return new Message[0];
|
||||
|
||||
Channel channel = _channels[channelId];
|
||||
if (channel != null && channel.Type == ChannelTypes.Text)
|
||||
{
|
||||
try
|
||||
{
|
||||
var msgs = await _api.GetMessages(channel.Id, count).ConfigureAwait(false);
|
||||
return msgs.Select(x =>
|
||||
{
|
||||
Message msg;
|
||||
if (cache)
|
||||
msg = _messages.GetOrAdd(x.Id, x.ChannelId, x.Author.Id);
|
||||
else
|
||||
msg = _messages[x.Id] ?? new Message(this, x.Id, x.ChannelId, x.Author.Id);
|
||||
if (msg != null)
|
||||
{
|
||||
msg.Update(x);
|
||||
if (Config.TrackActivity)
|
||||
{
|
||||
/*if (channel.IsPrivate)
|
||||
{
|
||||
var user = msg.User;
|
||||
if (user != null)
|
||||
user.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp);
|
||||
}
|
||||
else*/
|
||||
if (!channel.IsPrivate)
|
||||
{
|
||||
var member = msg.Member;
|
||||
if (member != null)
|
||||
member.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
catch (HttpException) { } //Bad Permissions?
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Permissions
|
||||
public Task SetChannelUserPermissions(Channel channel, Member member, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, member?.UserId, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(string channelId, Member member, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], member?.UserId, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(Channel channel, User user, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, user?.Id, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(string channelId, User user, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], user?.Id, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(Channel channel, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, userId, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(string channelId, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], userId, PermissionTarget.Member, allow, deny);
|
||||
|
||||
public Task SetChannelRolePermissions(Channel channel, Role role, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, role?.Id, PermissionTarget.Role, allow, deny);
|
||||
public Task SetChannelRolePermissions(string channelId, Role role, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], role?.Id, PermissionTarget.Role, allow, deny);
|
||||
public Task SetChannelRolePermissions(Channel channel, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, userId, PermissionTarget.Role, allow, deny);
|
||||
public Task SetChannelRolePermissions(string channelId, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], userId, PermissionTarget.Role, allow, deny);
|
||||
|
||||
private async Task SetChannelPermissions(Channel channel, string targetId, string targetType, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new NullReferenceException(nameof(channel));
|
||||
if (targetId == null) throw new NullReferenceException(nameof(targetId));
|
||||
if (targetType == null) throw new NullReferenceException(nameof(targetType));
|
||||
|
||||
uint allowValue = allow?.RawValue ?? 0;
|
||||
uint denyValue = deny?.RawValue ?? 0;
|
||||
bool changed = false;
|
||||
|
||||
var perms = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).FirstOrDefault();
|
||||
if (allowValue != 0 || denyValue != 0)
|
||||
{
|
||||
await _api.SetChannelPermissions(channel.Id, targetId, targetType, allowValue, denyValue);
|
||||
if (perms != null)
|
||||
{
|
||||
perms.Allow.SetRawValueInternal(allowValue);
|
||||
perms.Deny.SetRawValueInternal(denyValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldPerms = channel._permissionOverwrites;
|
||||
var newPerms = new Channel.PermissionOverwrite[oldPerms.Length + 1];
|
||||
Array.Copy(oldPerms, newPerms, oldPerms.Length);
|
||||
newPerms[oldPerms.Length] = new Channel.PermissionOverwrite(targetType, targetId, allowValue, denyValue);
|
||||
channel._permissionOverwrites = newPerms;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteChannelPermissions(channel.Id, targetId);
|
||||
if (perms != null)
|
||||
{
|
||||
channel._permissionOverwrites = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).ToArray();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
if (targetType == PermissionTarget.Role)
|
||||
channel.InvalidatePermissionsCache();
|
||||
else if (targetType == PermissionTarget.Member)
|
||||
channel.InvalidatePermissionsCache(targetId);
|
||||
}
|
||||
}
|
||||
|
||||
public Task RemoveChannelUserPermissions(Channel channel, Member member)
|
||||
=> RemoveChannelPermissions(channel, member?.UserId, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(string channelId, Member member)
|
||||
=> RemoveChannelPermissions(_channels[channelId], member?.UserId, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(Channel channel, User user)
|
||||
=> RemoveChannelPermissions(channel, user?.Id, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(string channelId, User user)
|
||||
=> RemoveChannelPermissions(_channels[channelId], user?.Id, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(Channel channel, string userId)
|
||||
=> RemoveChannelPermissions(channel, userId, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(string channelId, string userId)
|
||||
=> RemoveChannelPermissions(_channels[channelId], userId, PermissionTarget.Member);
|
||||
|
||||
public Task RemoveChannelRolePermissions(Channel channel, Role role)
|
||||
=> RemoveChannelPermissions(channel, role?.Id, PermissionTarget.Role);
|
||||
public Task RemoveChannelRolePermissions(string channelId, Role role)
|
||||
=> RemoveChannelPermissions(_channels[channelId], role?.Id, PermissionTarget.Role);
|
||||
public Task RemoveChannelRolePermissions(Channel channel, string roleId)
|
||||
=> RemoveChannelPermissions(channel, roleId, PermissionTarget.Role);
|
||||
public Task RemoveChannelRolePermissions(string channelId, string roleId)
|
||||
=> RemoveChannelPermissions(_channels[channelId], roleId, PermissionTarget.Role);
|
||||
|
||||
private async Task RemoveChannelPermissions(Channel channel, string userOrRoleId, string idType)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new NullReferenceException(nameof(channel));
|
||||
if (userOrRoleId == null) throw new NullReferenceException(nameof(userOrRoleId));
|
||||
if (idType == null) throw new NullReferenceException(nameof(idType));
|
||||
|
||||
try
|
||||
{
|
||||
var perms = channel.PermissionOverwrites.Where(x => x.TargetType != idType || x.TargetId != userOrRoleId).FirstOrDefault();
|
||||
await _api.DeleteChannelPermissions(channel.Id, userOrRoleId).ConfigureAwait(false);
|
||||
if (perms != null)
|
||||
{
|
||||
channel.PermissionOverwrites.Where(x => x.TargetType != idType || x.TargetId != userOrRoleId).ToArray();
|
||||
|
||||
if (idType == PermissionTarget.Role)
|
||||
channel.InvalidatePermissionsCache();
|
||||
else if (idType == PermissionTarget.Member)
|
||||
channel.InvalidatePermissionsCache(userOrRoleId);
|
||||
}
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
|
||||
//Profile
|
||||
public Task<EditUserResponse> EditProfile(string currentPassword = "",
|
||||
string username = null, string email = null, string password = null,
|
||||
ImageType avatarType = ImageType.Png, byte[] avatar = null)
|
||||
{
|
||||
if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword));
|
||||
|
||||
return _api.EditUser(currentPassword: currentPassword, username: username ?? _currentUser?.Name, email: email ?? _currentUser?.Email, password: password,
|
||||
avatarType: avatarType, avatar: avatar);
|
||||
}
|
||||
public Task SetStatus(string status)
|
||||
{
|
||||
if (status != UserStatus.Online && status != UserStatus.Idle)
|
||||
throw new ArgumentException($"Invalid status, must be {UserStatus.Online} or {UserStatus.Idle}");
|
||||
_status = status;
|
||||
return SendStatus();
|
||||
}
|
||||
public Task SetGame(int? gameId)
|
||||
{
|
||||
_gameId = gameId;
|
||||
return SendStatus();
|
||||
}
|
||||
private Task SendStatus()
|
||||
{
|
||||
_dataSocket.SendStatus(_status == UserStatus.Idle ? EpochTime.GetMilliseconds() - (10 * 60 * 1000) : (ulong?)null, _gameId);
|
||||
return TaskHelper.CompletedTask;
|
||||
}
|
||||
|
||||
//Roles
|
||||
/// <summary> Note: due to current API limitations, the created role cannot be returned. </summary>
|
||||
public Task<Role> CreateRole(Server server, string name)
|
||||
=> CreateRole(server?.Id, name);
|
||||
/// <summary> Note: due to current API limitations, the created role cannot be returned. </summary>
|
||||
public async Task<Role> CreateRole(string serverId, string name)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
|
||||
var response = await _api.CreateRole(serverId).ConfigureAwait(false);
|
||||
var role = _roles.GetOrAdd(response.Id, serverId);
|
||||
role.Update(response);
|
||||
|
||||
await EditRole(role, name: name);
|
||||
|
||||
return role;
|
||||
}
|
||||
|
||||
public Task EditRole(Role role, string name = null, PackedServerPermissions permissions = null, PackedColor color = null, bool? hoist = null, int? position = null)
|
||||
=> EditRole(role.ServerId, role.Id, name: name, permissions: permissions, color: color, hoist: hoist, position: position);
|
||||
public async Task EditRole(string serverId, string roleId, string name = null, PackedServerPermissions permissions = null, PackedColor color = null, bool? hoist = null, int? position = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
if (roleId == null) throw new NullReferenceException(nameof(roleId));
|
||||
|
||||
var response = await _api.EditRole(serverId, roleId, name: name,
|
||||
permissions: permissions?.RawValue, color: color?.RawValue, hoist: hoist);
|
||||
|
||||
var role = _roles[response.Id];
|
||||
if (role != null)
|
||||
role.Update(response);
|
||||
|
||||
if (position != null)
|
||||
{
|
||||
int oldPos = role.Position;
|
||||
int newPos = position.Value;
|
||||
int minPos;
|
||||
Role[] roles = role.Server.Roles.OrderBy(x => x.Position).ToArray();
|
||||
|
||||
if (oldPos < newPos) //Moving Down
|
||||
{
|
||||
minPos = oldPos;
|
||||
for (int i = oldPos; i < newPos; i++)
|
||||
roles[i] = roles[i + 1];
|
||||
roles[newPos] = role;
|
||||
}
|
||||
else //(oldPos > newPos) Moving Up
|
||||
{
|
||||
minPos = newPos;
|
||||
for (int i = oldPos; i > newPos; i--)
|
||||
roles[i] = roles[i - 1];
|
||||
roles[newPos] = role;
|
||||
}
|
||||
await _api.ReorderRoles(role.ServerId, roles.Skip(minPos).Select(x => x.Id), minPos);
|
||||
}
|
||||
}
|
||||
|
||||
public Task DeleteRole(Role role)
|
||||
=> DeleteRole(role?.ServerId, role?.Id);
|
||||
public Task DeleteRole(string serverId, string roleId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
if (roleId == null) throw new NullReferenceException(nameof(roleId));
|
||||
|
||||
return _api.DeleteRole(serverId, roleId);
|
||||
}
|
||||
|
||||
public Task ReorderRoles(Server server, IEnumerable<object> roles, int startPos = 0)
|
||||
=> ReorderChannels(server.Id, roles, startPos);
|
||||
public Task ReorderRoles(string serverId, IEnumerable<object> roles, int startPos = 0)
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (roles == null) throw new ArgumentNullException(nameof(roles));
|
||||
if (startPos < 0) throw new ArgumentOutOfRangeException(nameof(startPos), "startPos must be a positive integer.");
|
||||
|
||||
var roleIds = roles.Select(x =>
|
||||
{
|
||||
if (x is string)
|
||||
return x as string;
|
||||
else if (x is Role)
|
||||
return (x as Role).Id;
|
||||
else
|
||||
throw new ArgumentException("Channels must be a collection of string or Role.", nameof(roles));
|
||||
});
|
||||
|
||||
return _api.ReorderRoles(serverId, roleIds, startPos);
|
||||
}
|
||||
|
||||
//Servers
|
||||
/// <summary> Creates a new server with the provided name and region (see Regions). </summary>
|
||||
public async Task<Server> CreateServer(string name, string region)
|
||||
{
|
||||
CheckReady();
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (region == null) throw new ArgumentNullException(nameof(region));
|
||||
|
||||
var response = await _api.CreateServer(name, region).ConfigureAwait(false);
|
||||
var server = _servers.GetOrAdd(response.Id);
|
||||
server.Update(response);
|
||||
return server;
|
||||
}
|
||||
|
||||
/// <summary> Edits the provided server, changing only non-null attributes. </summary>
|
||||
public Task EditServer(string serverId, string name = null, string region = null, ImageType iconType = ImageType.Png, byte[] icon = null)
|
||||
=> EditServer(_servers[serverId], name: name, region: region, iconType: iconType, icon: icon);
|
||||
/// <summary> Edits the provided server, changing only non-null attributes. </summary>
|
||||
public async Task EditServer(Server server, string name = null, string region = null, ImageType iconType = ImageType.Png, byte[] icon = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (server == null) throw new ArgumentNullException(nameof(server));
|
||||
|
||||
var response = await _api.EditServer(server.Id, name: name ?? server.Name, region: region, iconType: iconType, icon: icon);
|
||||
server.Update(response);
|
||||
}
|
||||
|
||||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary>
|
||||
public Task<Server> LeaveServer(Server server)
|
||||
=> LeaveServer(server?.Id);
|
||||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary>
|
||||
public async Task<Server> LeaveServer(string serverId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
|
||||
try { await _api.LeaveServer(serverId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
return _servers.TryRemove(serverId);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/Discord.Net/DiscordClient.Bans.cs
Normal file
68
src/Discord.Net/DiscordClient.Bans.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using Discord.Net;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public event EventHandler<BanEventArgs> BanAdded;
|
||||
private void RaiseBanAdded(string userId, Server server)
|
||||
{
|
||||
if (BanAdded != null)
|
||||
RaiseEvent(nameof(BanAdded), () => BanAdded(this, new BanEventArgs(_users[userId], userId, server)));
|
||||
}
|
||||
public event EventHandler<BanEventArgs> BanRemoved;
|
||||
private void RaiseBanRemoved(string userId, Server server)
|
||||
{
|
||||
if (BanRemoved != null)
|
||||
RaiseEvent(nameof(BanRemoved), () => BanRemoved(this, new BanEventArgs(_users[userId], userId, server)));
|
||||
}
|
||||
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(Member member)
|
||||
=> Ban(member?.ServerId, member?.UserId);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(Server server, User user)
|
||||
=> Ban(server?.Id, user?.Id);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(Server server, string userId)
|
||||
=> Ban(server?.Id, userId);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(string server, User user)
|
||||
=> Ban(server, user?.Id);
|
||||
/// <summary> Bans a user from the provided server. </summary>
|
||||
public Task Ban(string serverId, string userId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
return _api.Ban(serverId, userId);
|
||||
}
|
||||
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(Member member)
|
||||
=> Unban(member?.ServerId, member?.UserId);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(Server server, User user)
|
||||
=> Unban(server?.Id, user?.Id);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(Server server, string userId)
|
||||
=> Unban(server?.Id, userId);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public Task Unban(string server, User user)
|
||||
=> Unban(server, user?.Id);
|
||||
/// <summary> Unbans a user from the provided server. </summary>
|
||||
public async Task Unban(string serverId, string userId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
try { await _api.Unban(serverId, userId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public partial class DiscordClient
|
||||
{
|
||||
/// <summary> Returns the channel with the specified id, or null if none was found. </summary>
|
||||
public Channel GetChannel(string id) => _channels[id];
|
||||
/// <summary> Returns all channels with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and #Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Channel> FindChannels(Server server, string name, string type = null) => _channels.Find(server?.Id, name, type);
|
||||
/// <summary> Returns all channels with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and #Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Channel> FindChannels(string serverId, string name, string type = null) => _channels.Find(serverId, name, type);
|
||||
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(string serverId, User user) => _members[user?.Id, serverId];
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(Server server, User user) => _members[user?.Id, server?.Id];
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(Server server, string userId) => _members[userId, server?.Id];
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(string serverId, string userId) => _members[userId, serverId];
|
||||
/// <summary> Returns all users in with the specified server and name, along with their server-specific data. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive.</remarks>
|
||||
public IEnumerable<Member> FindMembers(Server server, string name) => _members.Find(server, name);
|
||||
/// <summary> Returns all users in with the specified server and name, along with their server-specific data. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive.</remarks>
|
||||
public IEnumerable<Member> FindMembers(string serverId, string name) => _members.Find(_servers[serverId], name);
|
||||
|
||||
/// <summary> Returns the message with the specified id, or null if none was found. </summary>
|
||||
public Message GetMessage(string id) => _messages[id];
|
||||
|
||||
/// <summary> Returns the role with the specified id, or null if none was found. </summary>
|
||||
public Role GetRole(string id) => _roles[id];
|
||||
/// <summary> Returns all roles with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Role> FindRoles(Server server, string name) => _roles.Find(server?.Id, name);
|
||||
/// <summary> Returns all roles with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Role> FindRoles(string serverId, string name) => _roles.Find(serverId, name);
|
||||
|
||||
/// <summary> Returns the server with the specified id, or null if none was found. </summary>
|
||||
public Server GetServer(string id) => _servers[id];
|
||||
/// <summary> Returns all servers with the specified name. </summary>
|
||||
/// <remarks> Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Server> FindServers(string name) => _servers.Find(name);
|
||||
|
||||
/// <summary> Returns the user with the specified id, or null if none was found. </summary>
|
||||
public User GetUser(string id) => _users[id];
|
||||
/// <summary> Returns the user with the specified name and discriminator, or null if none was found. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public User GetUser(string name, string discriminator) => _members[name, discriminator]?.User;
|
||||
/// <summary> Returns all users with the specified name across all servers. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<User> FindUsers(string name) => _users.Find(name);
|
||||
|
||||
}
|
||||
}
|
||||
182
src/Discord.Net/DiscordClient.Channels.cs
Normal file
182
src/Discord.Net/DiscordClient.Channels.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using Discord.Collections;
|
||||
using Discord.Net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public sealed class ChannelEventArgs : EventArgs
|
||||
{
|
||||
public Channel Channel { get; }
|
||||
public string ChannelId => Channel.Id;
|
||||
public Server Server => Channel.Server;
|
||||
public string ServerId => Channel.ServerId;
|
||||
|
||||
internal ChannelEventArgs(Channel channel) { Channel = channel; }
|
||||
}
|
||||
|
||||
public partial class DiscordClient
|
||||
{
|
||||
/// <summary> Returns a collection of all channels this client is a member of. </summary>
|
||||
public Channels Channels => _channels;
|
||||
private readonly Channels _channels;
|
||||
|
||||
public event EventHandler<ChannelEventArgs> ChannelCreated;
|
||||
private void RaiseChannelCreated(Channel channel)
|
||||
{
|
||||
if (ChannelCreated != null)
|
||||
RaiseEvent(nameof(ChannelCreated), () => ChannelCreated(this, new ChannelEventArgs(channel)));
|
||||
}
|
||||
public event EventHandler<ChannelEventArgs> ChannelDestroyed;
|
||||
private void RaiseChannelDestroyed(Channel channel)
|
||||
{
|
||||
if (ChannelDestroyed != null)
|
||||
RaiseEvent(nameof(ChannelDestroyed), () => ChannelDestroyed(this, new ChannelEventArgs(channel)));
|
||||
}
|
||||
public event EventHandler<ChannelEventArgs> ChannelUpdated;
|
||||
private void RaiseChannelUpdated(Channel channel)
|
||||
{
|
||||
if (ChannelUpdated != null)
|
||||
RaiseEvent(nameof(ChannelUpdated), () => ChannelUpdated(this, new ChannelEventArgs(channel)));
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Returns the channel with the specified id, or null if none was found. </summary>
|
||||
public Channel GetChannel(string id) => _channels[id];
|
||||
/// <summary> Returns all channels with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and #Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Channel> FindChannels(Server server, string name, string type = null) => FindChannels(server?.Id, name, type);
|
||||
/// <summary> Returns all channels with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and #Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Channel> FindChannels(string serverId, string name, string type = null)
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
|
||||
IEnumerable<Channel> result;
|
||||
if (name.StartsWith("#"))
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
result = _channels.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _channels.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (type != null)
|
||||
result = result.Where(x => x.Type == type);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Creates a new channel with the provided name and type (see ChannelTypes). </summary>
|
||||
public Task<Channel> CreateChannel(Server server, string name, string type = ChannelTypes.Text)
|
||||
=> CreateChannel(server?.Id, name, type);
|
||||
/// <summary> Creates a new channel with the provided name and type (see ChannelTypes). </summary>
|
||||
public async Task<Channel> CreateChannel(string serverId, string name, string type = ChannelTypes.Text)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
|
||||
var response = await _api.CreateChannel(serverId, name, type).ConfigureAwait(false);
|
||||
var channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id);
|
||||
channel.Update(response);
|
||||
return channel;
|
||||
}
|
||||
|
||||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary>
|
||||
public Task<Channel> CreatePMChannel(string userId) => CreatePMChannel(_users[userId], userId);
|
||||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary>
|
||||
public Task<Channel> CreatePMChannel(User user) => CreatePMChannel(user, user?.Id);
|
||||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary>
|
||||
public Task<Channel> CreatePMChannel(Member member) => CreatePMChannel(member.User, member.UserId);
|
||||
private async Task<Channel> CreatePMChannel(User user, string userId)
|
||||
{
|
||||
CheckReady();
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
Channel channel = null;
|
||||
if (user != null)
|
||||
channel = user.PrivateChannel;
|
||||
if (channel == null)
|
||||
{
|
||||
var response = await _api.CreatePMChannel(CurrentUserId, userId).ConfigureAwait(false);
|
||||
user = _users.GetOrAdd(response.Recipient?.Id);
|
||||
user.Update(response.Recipient);
|
||||
channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id);
|
||||
channel.Update(response);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
/// <summary> Edits the provided channel, changing only non-null attributes. </summary>
|
||||
public Task EditChannel(string channelId, string name = null, string topic = null, int? position = null)
|
||||
=> EditChannel(_channels[channelId], name: name, topic: topic, position: position);
|
||||
/// <summary> Edits the provided channel, changing only non-null attributes. </summary>
|
||||
public async Task EditChannel(Channel channel, string name = null, string topic = null, int? position = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
await _api.EditChannel(channel.Id, name: name, topic: topic);
|
||||
|
||||
if (position != null)
|
||||
{
|
||||
int oldPos = channel.Position;
|
||||
int newPos = position.Value;
|
||||
int minPos;
|
||||
Channel[] channels = channel.Server.Channels.OrderBy(x => x.Position).ToArray();
|
||||
|
||||
if (oldPos < newPos) //Moving Down
|
||||
{
|
||||
minPos = oldPos;
|
||||
for (int i = oldPos; i < newPos; i++)
|
||||
channels[i] = channels[i + 1];
|
||||
channels[newPos] = channel;
|
||||
}
|
||||
else //(oldPos > newPos) Moving Up
|
||||
{
|
||||
minPos = newPos;
|
||||
for (int i = oldPos; i > newPos; i--)
|
||||
channels[i] = channels[i - 1];
|
||||
channels[newPos] = channel;
|
||||
}
|
||||
await _api.ReorderChannels(channel.ServerId, channels.Skip(minPos).Select(x => x.Id), minPos);
|
||||
}
|
||||
}
|
||||
|
||||
public Task ReorderChannels(Server server, IEnumerable<object> channels, int startPos = 0)
|
||||
=> ReorderChannels(server.Id, channels, startPos);
|
||||
public Task ReorderChannels(string serverId, IEnumerable<object> channels, int startPos = 0)
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (channels == null) throw new ArgumentNullException(nameof(channels));
|
||||
if (startPos < 0) throw new ArgumentOutOfRangeException(nameof(startPos), "startPos must be a positive integer.");
|
||||
|
||||
var channelIds = CollectionHelper.FlattenChannels(channels);
|
||||
return _api.ReorderChannels(serverId, channelIds, startPos);
|
||||
}
|
||||
|
||||
/// <summary> Destroys the provided channel. </summary>
|
||||
public Task<Channel> DestroyChannel(Channel channel)
|
||||
=> DestroyChannel(channel?.Id);
|
||||
/// <summary> Destroys the provided channel. </summary>
|
||||
public async Task<Channel> DestroyChannel(string channelId)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
|
||||
try { await _api.DestroyChannel(channelId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
return _channels.TryRemove(channelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public sealed class ServerEventArgs : EventArgs
|
||||
{
|
||||
public Server Server { get; }
|
||||
public string ServerId => Server.Id;
|
||||
|
||||
internal ServerEventArgs(Server server) { Server = server; }
|
||||
}
|
||||
public sealed class ChannelEventArgs : EventArgs
|
||||
{
|
||||
public Channel Channel { get; }
|
||||
public string ChannelId => Channel.Id;
|
||||
public Server Server => Channel.Server;
|
||||
public string ServerId => Channel.ServerId;
|
||||
|
||||
internal ChannelEventArgs(Channel channel) { Channel = channel; }
|
||||
}
|
||||
public sealed class UserEventArgs : EventArgs
|
||||
{
|
||||
public User User { get; }
|
||||
public string UserId => User.Id;
|
||||
|
||||
internal UserEventArgs(User user) { User = user; }
|
||||
}
|
||||
public sealed class MessageEventArgs : EventArgs
|
||||
{
|
||||
public Message Message { get; }
|
||||
public string MessageId => Message.Id;
|
||||
public Member Member => Message.Member;
|
||||
public Channel Channel => Message.Channel;
|
||||
public string ChannelId => Message.ChannelId;
|
||||
public Server Server => Message.Server;
|
||||
public string ServerId => Message.ServerId;
|
||||
public User User => Member.User;
|
||||
public string UserId => Message.UserId;
|
||||
|
||||
internal MessageEventArgs(Message msg) { Message = msg; }
|
||||
}
|
||||
public sealed class RoleEventArgs : EventArgs
|
||||
{
|
||||
public Role Role { get; }
|
||||
public string RoleId => Role.Id;
|
||||
public Server Server => Role.Server;
|
||||
public string ServerId => Role.ServerId;
|
||||
|
||||
internal RoleEventArgs(Role role) { Role = role; }
|
||||
}
|
||||
public sealed class BanEventArgs : EventArgs
|
||||
{
|
||||
public User User { get; }
|
||||
public string UserId { get; }
|
||||
public Server Server { get; }
|
||||
public string ServerId => Server.Id;
|
||||
|
||||
internal BanEventArgs(User user, string userId, Server server)
|
||||
{
|
||||
User = user;
|
||||
UserId = userId;
|
||||
Server = server;
|
||||
}
|
||||
}
|
||||
public sealed class MemberEventArgs : EventArgs
|
||||
{
|
||||
public Member Member { get; }
|
||||
public User User => Member.User;
|
||||
public string UserId => Member.UserId;
|
||||
public Server Server => Member.Server;
|
||||
public string ServerId => Member.ServerId;
|
||||
|
||||
internal MemberEventArgs(Member member) { Member = member; }
|
||||
}
|
||||
public sealed class UserTypingEventArgs : EventArgs
|
||||
{
|
||||
public Channel Channel { get; }
|
||||
public string ChannelId => Channel.Id;
|
||||
public Server Server => Channel.Server;
|
||||
public string ServerId => Channel.ServerId;
|
||||
public User User { get; }
|
||||
public string UserId => User.Id;
|
||||
|
||||
internal UserTypingEventArgs(User user, Channel channel)
|
||||
{
|
||||
User = user;
|
||||
Channel = channel;
|
||||
}
|
||||
}
|
||||
public sealed class UserIsSpeakingEventArgs : EventArgs
|
||||
{
|
||||
public Channel Channel => Member.VoiceChannel;
|
||||
public string ChannelId => Member.VoiceChannelId;
|
||||
public Server Server => Member.Server;
|
||||
public string ServerId => Member.ServerId;
|
||||
public User User => Member.User;
|
||||
public string UserId => Member.UserId;
|
||||
public Member Member { get; }
|
||||
public bool IsSpeaking { get; }
|
||||
|
||||
internal UserIsSpeakingEventArgs(Member member, bool isSpeaking)
|
||||
{
|
||||
Member = member;
|
||||
IsSpeaking = isSpeaking;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class DiscordClient
|
||||
{
|
||||
//Server
|
||||
public event EventHandler<ServerEventArgs> ServerCreated;
|
||||
private void RaiseServerCreated(Server server)
|
||||
{
|
||||
if (ServerCreated != null)
|
||||
RaiseEvent(nameof(ServerCreated), () => ServerCreated(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerDestroyed;
|
||||
private void RaiseServerDestroyed(Server server)
|
||||
{
|
||||
if (ServerDestroyed != null)
|
||||
RaiseEvent(nameof(ServerDestroyed), () => ServerDestroyed(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerUpdated;
|
||||
private void RaiseServerUpdated(Server server)
|
||||
{
|
||||
if (ServerUpdated != null)
|
||||
RaiseEvent(nameof(ServerUpdated), () => ServerUpdated(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerUnavailable;
|
||||
private void RaiseServerUnavailable(Server server)
|
||||
{
|
||||
if (ServerUnavailable != null)
|
||||
RaiseEvent(nameof(ServerUnavailable), () => ServerUnavailable(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerAvailable;
|
||||
private void RaiseServerAvailable(Server server)
|
||||
{
|
||||
if (ServerAvailable != null)
|
||||
RaiseEvent(nameof(ServerAvailable), () => ServerAvailable(this, new ServerEventArgs(server)));
|
||||
}
|
||||
|
||||
//Channel
|
||||
public event EventHandler<ChannelEventArgs> ChannelCreated;
|
||||
private void RaiseChannelCreated(Channel channel)
|
||||
{
|
||||
if (ChannelCreated != null)
|
||||
RaiseEvent(nameof(ChannelCreated), () => ChannelCreated(this, new ChannelEventArgs(channel)));
|
||||
}
|
||||
public event EventHandler<ChannelEventArgs> ChannelDestroyed;
|
||||
private void RaiseChannelDestroyed(Channel channel)
|
||||
{
|
||||
if (ChannelDestroyed != null)
|
||||
RaiseEvent(nameof(ChannelDestroyed), () => ChannelDestroyed(this, new ChannelEventArgs(channel)));
|
||||
}
|
||||
public event EventHandler<ChannelEventArgs> ChannelUpdated;
|
||||
private void RaiseChannelUpdated(Channel channel)
|
||||
{
|
||||
if (ChannelUpdated != null)
|
||||
RaiseEvent(nameof(ChannelUpdated), () => ChannelUpdated(this, new ChannelEventArgs(channel)));
|
||||
}
|
||||
|
||||
//Message
|
||||
public event EventHandler<MessageEventArgs> MessageCreated;
|
||||
private void RaiseMessageCreated(Message msg)
|
||||
{
|
||||
if (MessageCreated != null)
|
||||
RaiseEvent(nameof(MessageCreated), () => MessageCreated(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageDeleted;
|
||||
private void RaiseMessageDeleted(Message msg)
|
||||
{
|
||||
if (MessageDeleted != null)
|
||||
RaiseEvent(nameof(MessageDeleted), () => MessageDeleted(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageUpdated;
|
||||
private void RaiseMessageUpdated(Message msg)
|
||||
{
|
||||
if (MessageUpdated != null)
|
||||
RaiseEvent(nameof(MessageUpdated), () => MessageUpdated(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageReadRemotely;
|
||||
private void RaiseMessageReadRemotely(Message msg)
|
||||
{
|
||||
if (MessageReadRemotely != null)
|
||||
RaiseEvent(nameof(MessageReadRemotely), () => MessageReadRemotely(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageSent;
|
||||
private void RaiseMessageSent(Message msg)
|
||||
{
|
||||
if (MessageSent != null)
|
||||
RaiseEvent(nameof(MessageSent), () => MessageSent(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
|
||||
//Role
|
||||
public event EventHandler<RoleEventArgs> RoleCreated;
|
||||
private void RaiseRoleCreated(Role role)
|
||||
{
|
||||
if (RoleCreated != null)
|
||||
RaiseEvent(nameof(RoleCreated), () => RoleCreated(this, new RoleEventArgs(role)));
|
||||
}
|
||||
public event EventHandler<RoleEventArgs> RoleUpdated;
|
||||
private void RaiseRoleDeleted(Role role)
|
||||
{
|
||||
if (RoleDeleted != null)
|
||||
RaiseEvent(nameof(RoleDeleted), () => RoleDeleted(this, new RoleEventArgs(role)));
|
||||
}
|
||||
public event EventHandler<RoleEventArgs> RoleDeleted;
|
||||
private void RaiseRoleUpdated(Role role)
|
||||
{
|
||||
if (RoleUpdated != null)
|
||||
RaiseEvent(nameof(RoleUpdated), () => RoleUpdated(this, new RoleEventArgs(role)));
|
||||
}
|
||||
|
||||
//Ban
|
||||
public event EventHandler<BanEventArgs> BanAdded;
|
||||
private void RaiseBanAdded(string userId, Server server)
|
||||
{
|
||||
if (BanAdded != null)
|
||||
RaiseEvent(nameof(BanAdded), () => BanAdded(this, new BanEventArgs(_users[userId], userId, server)));
|
||||
}
|
||||
public event EventHandler<BanEventArgs> BanRemoved;
|
||||
private void RaiseBanRemoved(string userId, Server server)
|
||||
{
|
||||
if (BanRemoved != null)
|
||||
RaiseEvent(nameof(BanRemoved), () => BanRemoved(this, new BanEventArgs(_users[userId], userId, server)));
|
||||
}
|
||||
|
||||
//User
|
||||
public event EventHandler<MemberEventArgs> UserAdded;
|
||||
private void RaiseUserAdded(Member member)
|
||||
{
|
||||
if (UserAdded != null)
|
||||
RaiseEvent(nameof(UserAdded), () => UserAdded(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> UserRemoved;
|
||||
private void RaiseUserRemoved(Member member)
|
||||
{
|
||||
if (UserRemoved != null)
|
||||
RaiseEvent(nameof(UserRemoved), () => UserRemoved(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<UserEventArgs> UserUpdated;
|
||||
private void RaiseUserUpdated(User user)
|
||||
{
|
||||
if (UserUpdated != null)
|
||||
RaiseEvent(nameof(UserUpdated), () => UserUpdated(this, new UserEventArgs(user)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> MemberUpdated;
|
||||
private void RaiseMemberUpdated(Member member)
|
||||
{
|
||||
if (MemberUpdated != null)
|
||||
RaiseEvent(nameof(MemberUpdated), () => MemberUpdated(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> UserPresenceUpdated;
|
||||
private void RaiseUserPresenceUpdated(Member member)
|
||||
{
|
||||
if (UserPresenceUpdated != null)
|
||||
RaiseEvent(nameof(UserPresenceUpdated), () => UserPresenceUpdated(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> UserVoiceStateUpdated;
|
||||
private void RaiseUserVoiceStateUpdated(Member member)
|
||||
{
|
||||
if (UserVoiceStateUpdated != null)
|
||||
RaiseEvent(nameof(UserVoiceStateUpdated), () => UserVoiceStateUpdated(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<UserTypingEventArgs> UserIsTyping;
|
||||
private void RaiseUserIsTyping(User user, Channel channel)
|
||||
{
|
||||
if (UserIsTyping != null)
|
||||
RaiseEvent(nameof(UserIsTyping), () => UserIsTyping(this, new UserTypingEventArgs(user, channel)));
|
||||
}
|
||||
public event EventHandler<UserIsSpeakingEventArgs> UserIsSpeaking;
|
||||
private void RaiseUserIsSpeaking(Member member, bool isSpeaking)
|
||||
{
|
||||
if (UserIsSpeaking != null)
|
||||
RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new UserIsSpeakingEventArgs(member, isSpeaking)));
|
||||
}
|
||||
}
|
||||
}
|
||||
96
src/Discord.Net/DiscordClient.Invites.cs
Normal file
96
src/Discord.Net/DiscordClient.Invites.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Discord.Net;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public partial class DiscordClient
|
||||
{
|
||||
/// <summary> Creates a new invite to the default channel of the provided server. </summary>
|
||||
/// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param>
|
||||
/// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param>
|
||||
/// <param name="hasXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to 0. </param>
|
||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to 0 to have unlimited uses. </param>
|
||||
public Task<Invite> CreateInvite(Server server, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false)
|
||||
=> CreateInvite(server?.DefaultChannelId, maxAge, maxUses, tempMembership, hasXkcd);
|
||||
/// <summary> Creates a new invite to the provided channel. </summary>
|
||||
/// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param>
|
||||
/// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param>
|
||||
/// <param name="hasXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to 0. </param>
|
||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to 0 to have unlimited uses. </param>
|
||||
public Task<Invite> CreateInvite(Channel channel, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false)
|
||||
=> CreateInvite(channel?.Id, maxAge, maxUses, tempMembership, hasXkcd);
|
||||
/// <summary> Creates a new invite to the provided channel. </summary>
|
||||
/// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param>
|
||||
/// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param>
|
||||
/// <param name="hasXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to 0. </param>
|
||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to 0 to have unlimited uses. </param>
|
||||
public async Task<Invite> CreateInvite(string serverOrChannelId, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverOrChannelId == null) throw new ArgumentNullException(nameof(serverOrChannelId));
|
||||
if (maxAge <= 0) throw new ArgumentOutOfRangeException(nameof(maxAge));
|
||||
if (maxUses <= 0) throw new ArgumentOutOfRangeException(nameof(maxUses));
|
||||
|
||||
var response = await _api.CreateInvite(serverOrChannelId, maxAge, maxUses, tempMembership, hasXkcd).ConfigureAwait(false);
|
||||
var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id);
|
||||
invite.Update(response);
|
||||
return invite;
|
||||
}
|
||||
|
||||
/// <summary> Deletes the provided invite. </summary>
|
||||
public async Task DestroyInvite(string inviteId)
|
||||
{
|
||||
CheckReady();
|
||||
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId));
|
||||
|
||||
try
|
||||
{
|
||||
//Check if this is a human-readable link and get its ID
|
||||
var response = await _api.GetInvite(inviteId).ConfigureAwait(false);
|
||||
await _api.DeleteInvite(response.Code).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
|
||||
/// <summary> Gets more info about the provided invite code. </summary>
|
||||
/// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks>
|
||||
public async Task<Invite> GetInvite(string inviteIdOrXkcd)
|
||||
{
|
||||
CheckReady();
|
||||
if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd));
|
||||
|
||||
var response = await _api.GetInvite(inviteIdOrXkcd).ConfigureAwait(false);
|
||||
var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id);
|
||||
invite.Update(response);
|
||||
return invite;
|
||||
}
|
||||
|
||||
/// <summary> Accepts the provided invite. </summary>
|
||||
public Task AcceptInvite(Invite invite)
|
||||
{
|
||||
CheckReady();
|
||||
if (invite == null) throw new ArgumentNullException(nameof(invite));
|
||||
|
||||
return _api.AcceptInvite(invite.Id);
|
||||
}
|
||||
/// <summary> Accepts the provided invite. </summary>
|
||||
public async Task AcceptInvite(string inviteId)
|
||||
{
|
||||
CheckReady();
|
||||
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId));
|
||||
|
||||
//Remove trailing slash and any non-code url parts
|
||||
if (inviteId.Length > 0 && inviteId[inviteId.Length - 1] == '/')
|
||||
inviteId = inviteId.Substring(0, inviteId.Length - 1);
|
||||
int index = inviteId.LastIndexOf('/');
|
||||
if (index >= 0)
|
||||
inviteId = inviteId.Substring(index + 1);
|
||||
|
||||
//Check if this is a human-readable link and get its ID
|
||||
var invite = await GetInvite(inviteId).ConfigureAwait(false);
|
||||
await _api.AcceptInvite(invite.Id).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
135
src/Discord.Net/DiscordClient.Members.cs
Normal file
135
src/Discord.Net/DiscordClient.Members.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using Discord.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public sealed class MemberTypingEventArgs : EventArgs
|
||||
{
|
||||
public Channel Channel { get; }
|
||||
public string ChannelId => Channel.Id;
|
||||
public Server Server => Channel.Server;
|
||||
public string ServerId => Channel.ServerId;
|
||||
public Member Member { get; }
|
||||
public string UserId => User.Id;
|
||||
public User User => Member.User;
|
||||
|
||||
internal MemberTypingEventArgs(Member member, Channel channel)
|
||||
{
|
||||
Member = member;
|
||||
Channel = channel;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MemberIsSpeakingEventArgs : EventArgs
|
||||
{
|
||||
public Channel Channel => Member.VoiceChannel;
|
||||
public string ChannelId => Member.VoiceChannelId;
|
||||
public Server Server => Member.Server;
|
||||
public string ServerId => Member.ServerId;
|
||||
public User User => Member.User;
|
||||
public string UserId => Member.UserId;
|
||||
public Member Member { get; }
|
||||
public bool IsSpeaking { get; }
|
||||
|
||||
internal MemberIsSpeakingEventArgs(Member member, bool isSpeaking)
|
||||
{
|
||||
Member = member;
|
||||
IsSpeaking = isSpeaking;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public event EventHandler<MemberTypingEventArgs> UserIsTyping;
|
||||
private void RaiseUserIsTyping(Member member, Channel channel)
|
||||
{
|
||||
if (UserIsTyping != null)
|
||||
RaiseEvent(nameof(UserIsTyping), () => UserIsTyping(this, new MemberTypingEventArgs(member, channel)));
|
||||
}
|
||||
public event EventHandler<MemberIsSpeakingEventArgs> UserIsSpeaking;
|
||||
private void RaiseUserIsSpeaking(Member member, bool isSpeaking)
|
||||
{
|
||||
if (UserIsSpeaking != null)
|
||||
RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new MemberIsSpeakingEventArgs(member, isSpeaking)));
|
||||
}
|
||||
|
||||
/// <summary> Returns a collection of all user-server pairs this client can currently see. </summary>
|
||||
public Members Members => _members;
|
||||
private readonly Members _members;
|
||||
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(Server server, User user) => _members[user?.Id, server?.Id];
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(Server server, string userId) => _members[userId, server?.Id];
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(string serverId, User user) => _members[user?.Id, serverId];
|
||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary>
|
||||
public Member GetMember(string serverId, string userId) => _members[userId, serverId];
|
||||
/// <summary> Returns the user with the specified name and discriminator, along withtheir server-specific data, or null if they couldn't be found. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public Member GetMember(Server server, string username, string discriminator)
|
||||
=> GetMember(server?.Id, username, discriminator);
|
||||
/// <summary> Returns the user with the specified name and discriminator, along withtheir server-specific data, or null if they couldn't be found. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public Member GetMember(string serverId, string username, string discriminator)
|
||||
{
|
||||
User user = GetUser(username, discriminator);
|
||||
return _members[user?.Id, serverId];
|
||||
}
|
||||
|
||||
/// <summary> Returns all users in with the specified server and name, along with their server-specific data. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive.</remarks>
|
||||
public IEnumerable<Member> FindMembers(string serverId, string name) => FindMembers(_servers[serverId], name);
|
||||
/// <summary> Returns all users in with the specified server and name, along with their server-specific data. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive.</remarks>
|
||||
public IEnumerable<Member> FindMembers(Server server, string name)
|
||||
{
|
||||
if (server == null) throw new ArgumentNullException(nameof(server));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (name.StartsWith("@"))
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
return server.Members.Where(x =>
|
||||
{
|
||||
var user = x.User;
|
||||
if (user == null)
|
||||
return false;
|
||||
return string.Equals(user.Name, name, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(user.Name, name2, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return server.Members.Where(x =>
|
||||
{
|
||||
var user = x.User;
|
||||
if (user == null)
|
||||
return false;
|
||||
return string.Equals(x.User.Name, name, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Task EditMember(Member member, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
=> EditMember(member?.ServerId, member?.UserId, mute, deaf, roles);
|
||||
public Task EditMember(Server server, User user, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
=> EditMember(server?.Id, user?.Id, mute, deaf, roles);
|
||||
public Task EditMember(Server server, string userId, bool? mute = null, bool? deaf = null, IEnumerable<string> roles = null)
|
||||
=> EditMember(server?.Id, userId, mute, deaf, roles);
|
||||
public Task EditMember(string serverId, User user, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
=> EditMember(serverId, user?.Id, mute, deaf, roles);
|
||||
public Task EditMember(string serverId, string userId, bool? mute = null, bool? deaf = null, IEnumerable<object> roles = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
if (userId == null) throw new NullReferenceException(nameof(userId));
|
||||
|
||||
var newRoles = CollectionHelper.FlattenRoles(roles);
|
||||
return _api.EditMember(serverId, userId, mute: mute, deaf: deaf, roles: newRoles);
|
||||
}
|
||||
}
|
||||
}
|
||||
296
src/Discord.Net/DiscordClient.Messages.cs
Normal file
296
src/Discord.Net/DiscordClient.Messages.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
using Discord.API;
|
||||
using Discord.Collections;
|
||||
using Discord.Net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public const int MaxMessageSize = 2000;
|
||||
|
||||
/// <summary> Returns a collection of all messages this client has seen since logging in and currently has in cache. </summary>
|
||||
public Messages Messages => _messages;
|
||||
private readonly Messages _messages;
|
||||
|
||||
public event EventHandler<MessageEventArgs> MessageCreated;
|
||||
private void RaiseMessageCreated(Message msg)
|
||||
{
|
||||
if (MessageCreated != null)
|
||||
RaiseEvent(nameof(MessageCreated), () => MessageCreated(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageDeleted;
|
||||
private void RaiseMessageDeleted(Message msg)
|
||||
{
|
||||
if (MessageDeleted != null)
|
||||
RaiseEvent(nameof(MessageDeleted), () => MessageDeleted(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageUpdated;
|
||||
private void RaiseMessageUpdated(Message msg)
|
||||
{
|
||||
if (MessageUpdated != null)
|
||||
RaiseEvent(nameof(MessageUpdated), () => MessageUpdated(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageReadRemotely;
|
||||
private void RaiseMessageReadRemotely(Message msg)
|
||||
{
|
||||
if (MessageReadRemotely != null)
|
||||
RaiseEvent(nameof(MessageReadRemotely), () => MessageReadRemotely(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
public event EventHandler<MessageEventArgs> MessageSent;
|
||||
private void RaiseMessageSent(Message msg)
|
||||
{
|
||||
if (MessageSent != null)
|
||||
RaiseEvent(nameof(MessageSent), () => MessageSent(this, new MessageEventArgs(msg)));
|
||||
}
|
||||
|
||||
/// <summary> Returns the message with the specified id, or null if none was found. </summary>
|
||||
public Message GetMessage(string id) => _messages[id];
|
||||
|
||||
/// <summary> Sends a message to the provided channel. To include a mention, see the Mention static helper class. </summary>
|
||||
public Task<Message[]> SendMessage(Channel channel, string text)
|
||||
=> SendMessage(channel, text, MentionHelper.GetUserIds(text), false);
|
||||
/// <summary> Sends a message to the provided channel. To include a mention, see the Mention static helper class. </summary>
|
||||
public Task<Message[]> SendMessage(string channelId, string text)
|
||||
=> SendMessage(_channels[channelId], text, MentionHelper.GetUserIds(text), false);
|
||||
private async Task<Message[]> SendMessage(Channel channel, string text, IEnumerable<object> mentionedUsers = null, bool isTextToSpeech = false)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||
if (text == null) throw new ArgumentNullException(nameof(text));
|
||||
var mentionedUserIds = CollectionHelper.FlattenUsers(mentionedUsers);
|
||||
|
||||
int blockCount = (int)Math.Ceiling(text.Length / (double)MaxMessageSize);
|
||||
Message[] result = new Message[blockCount];
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
{
|
||||
int index = i * MaxMessageSize;
|
||||
string blockText = text.Substring(index, Math.Min(2000, text.Length - index));
|
||||
var nonce = GenerateNonce();
|
||||
if (Config.UseMessageQueue)
|
||||
{
|
||||
var msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, CurrentUserId);
|
||||
var currentUser = msg.User;
|
||||
msg.Update(new MessageInfo
|
||||
{
|
||||
Content = blockText,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
Author = new UserReference { Avatar = currentUser.AvatarId, Discriminator = currentUser.Discriminator, Id = CurrentUserId, Username = currentUser.Name },
|
||||
ChannelId = channel.Id,
|
||||
IsTextToSpeech = isTextToSpeech
|
||||
});
|
||||
msg.IsQueued = true;
|
||||
msg.Nonce = nonce;
|
||||
result[i] = msg;
|
||||
_pendingMessages.Enqueue(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
var model = await _api.SendMessage(channel.Id, blockText, mentionedUserIds, nonce, isTextToSpeech).ConfigureAwait(false);
|
||||
var msg = _messages.GetOrAdd(model.Id, channel.Id, model.Author.Id);
|
||||
msg.Update(model);
|
||||
RaiseMessageSent(msg);
|
||||
result[i] = msg;
|
||||
}
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Sends a private message to the provided user. </summary>
|
||||
public Task<Message[]> SendPrivateMessage(Member member, string text)
|
||||
=> SendPrivateMessage(member?.UserId, text);
|
||||
/// <summary> Sends a private message to the provided user. </summary>
|
||||
public Task<Message[]> SendPrivateMessage(User user, string text)
|
||||
=> SendPrivateMessage(user?.Id, text);
|
||||
/// <summary> Sends a private message to the provided user. </summary>
|
||||
public async Task<Message[]> SendPrivateMessage(string userId, string text)
|
||||
{
|
||||
var channel = await CreatePMChannel(userId).ConfigureAwait(false);
|
||||
return await SendMessage(channel, text, new string[0]).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary> Sends a file to the provided channel. </summary>
|
||||
public Task SendFile(Channel channel, string filePath)
|
||||
=> SendFile(channel?.Id, filePath);
|
||||
/// <summary> Sends a file to the provided channel. </summary>
|
||||
public Task SendFile(string channelId, string filePath)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
if (filePath == null) throw new ArgumentNullException(nameof(filePath));
|
||||
|
||||
return _api.SendFile(channelId, filePath);
|
||||
}
|
||||
|
||||
/// <summary> Edits the provided message, changing only non-null attributes. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks>
|
||||
public Task EditMessage(Message message, string text = null, IEnumerable<object> mentionedUsers = null)
|
||||
=> EditMessage(message?.ChannelId, message?.Id, text, mentionedUsers);
|
||||
/// <summary> Edits the provided message, changing only non-null attributes. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks>
|
||||
public Task EditMessage(Channel channel, string messageId, string text = null, IEnumerable<object> mentionedUsers = null)
|
||||
=> EditMessage(channel?.Id, messageId, text, mentionedUsers);
|
||||
/// <summary> Edits the provided message, changing only non-null attributes. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see Mention.User). </remarks>
|
||||
public async Task EditMessage(string channelId, string messageId, string text = null, IEnumerable<object> mentionedUsers = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
if (messageId == null) throw new ArgumentNullException(nameof(messageId));
|
||||
var mentionedUserIds = CollectionHelper.FlattenUsers(mentionedUsers);
|
||||
|
||||
if (text != null && text.Length > MaxMessageSize)
|
||||
text = text.Substring(0, MaxMessageSize);
|
||||
|
||||
var model = await _api.EditMessage(messageId, channelId, text, mentionedUserIds).ConfigureAwait(false);
|
||||
var msg = _messages[messageId];
|
||||
if (msg != null)
|
||||
msg.Update(model);
|
||||
}
|
||||
|
||||
/// <summary> Deletes the provided message. </summary>
|
||||
public Task DeleteMessage(Message msg)
|
||||
=> DeleteMessage(msg?.ChannelId, msg?.Id);
|
||||
/// <summary> Deletes the provided message. </summary>
|
||||
public async Task DeleteMessage(string channelId, string msgId)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
if (msgId == null) throw new ArgumentNullException(nameof(msgId));
|
||||
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(msgId, channelId).ConfigureAwait(false);
|
||||
_messages.TryRemove(msgId);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
public async Task DeleteMessages(IEnumerable<Message> msgs)
|
||||
{
|
||||
CheckReady();
|
||||
if (msgs == null) throw new ArgumentNullException(nameof(msgs));
|
||||
|
||||
foreach (var msg in msgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(msg.Id, msg.ChannelId).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
}
|
||||
public async Task DeleteMessages(string channelId, IEnumerable<string> msgIds)
|
||||
{
|
||||
CheckReady();
|
||||
if (msgIds == null) throw new ArgumentNullException(nameof(msgIds));
|
||||
|
||||
foreach (var msgId in msgIds)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(msgId, channelId).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Downloads last count messages from the server, starting at beforeMessageId if it's provided. </summary>
|
||||
public Task<Message[]> DownloadMessages(Channel channel, int count, string beforeMessageId = null, bool cache = true)
|
||||
=> DownloadMessages(channel.Id, count, beforeMessageId, cache);
|
||||
/// <summary> Downloads last count messages from the server, starting at beforeMessageId if it's provided. </summary>
|
||||
public async Task<Message[]> DownloadMessages(string channelId, int count, string beforeMessageId = null, bool cache = true)
|
||||
{
|
||||
CheckReady();
|
||||
if (channelId == null) throw new NullReferenceException(nameof(channelId));
|
||||
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
|
||||
if (count == 0) return new Message[0];
|
||||
|
||||
Channel channel = _channels[channelId];
|
||||
if (channel != null && channel.Type == ChannelTypes.Text)
|
||||
{
|
||||
try
|
||||
{
|
||||
var msgs = await _api.GetMessages(channel.Id, count).ConfigureAwait(false);
|
||||
return msgs.Select(x =>
|
||||
{
|
||||
Message msg;
|
||||
if (cache)
|
||||
msg = _messages.GetOrAdd(x.Id, x.ChannelId, x.Author.Id);
|
||||
else
|
||||
msg = _messages[x.Id] ?? new Message(this, x.Id, x.ChannelId, x.Author.Id);
|
||||
if (msg != null)
|
||||
{
|
||||
msg.Update(x);
|
||||
if (Config.TrackActivity)
|
||||
{
|
||||
/*if (channel.IsPrivate)
|
||||
{
|
||||
var user = msg.User;
|
||||
if (user != null)
|
||||
user.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp);
|
||||
}
|
||||
else*/
|
||||
if (!channel.IsPrivate)
|
||||
{
|
||||
var member = msg.Member;
|
||||
if (member != null)
|
||||
member.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
catch (HttpException) { } //Bad Permissions?
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Task MessageQueueLoop()
|
||||
{
|
||||
var cancelToken = CancelToken;
|
||||
int interval = Config.MessageQueueInterval;
|
||||
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
Message msg;
|
||||
while (!cancelToken.IsCancellationRequested)
|
||||
{
|
||||
while (_pendingMessages.TryDequeue(out msg))
|
||||
{
|
||||
bool hasFailed = false;
|
||||
SendMessageResponse response = null;
|
||||
try
|
||||
{
|
||||
response = await _api.SendMessage(msg.ChannelId, msg.RawText, msg.MentionIds, msg.Nonce, msg.IsTTS).ConfigureAwait(false);
|
||||
}
|
||||
catch (WebException) { break; }
|
||||
catch (HttpException) { hasFailed = true; }
|
||||
|
||||
if (!hasFailed)
|
||||
{
|
||||
_messages.Remap(msg.Id, response.Id);
|
||||
msg.Id = response.Id;
|
||||
msg.Update(response);
|
||||
}
|
||||
msg.IsQueued = false;
|
||||
msg.HasFailed = hasFailed;
|
||||
RaiseMessageSent(msg);
|
||||
}
|
||||
await Task.Delay(interval).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
private string GenerateNonce()
|
||||
{
|
||||
lock (_rand)
|
||||
return _rand.Next().ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
132
src/Discord.Net/DiscordClient.Permissions.cs
Normal file
132
src/Discord.Net/DiscordClient.Permissions.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using Discord.Net;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public Task SetChannelUserPermissions(Channel channel, Member member, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, member?.UserId, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(string channelId, Member member, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], member?.UserId, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(Channel channel, User user, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, user?.Id, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(string channelId, User user, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], user?.Id, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(Channel channel, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, userId, PermissionTarget.Member, allow, deny);
|
||||
public Task SetChannelUserPermissions(string channelId, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], userId, PermissionTarget.Member, allow, deny);
|
||||
|
||||
public Task SetChannelRolePermissions(Channel channel, Role role, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, role?.Id, PermissionTarget.Role, allow, deny);
|
||||
public Task SetChannelRolePermissions(string channelId, Role role, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], role?.Id, PermissionTarget.Role, allow, deny);
|
||||
public Task SetChannelRolePermissions(Channel channel, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(channel, userId, PermissionTarget.Role, allow, deny);
|
||||
public Task SetChannelRolePermissions(string channelId, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
=> SetChannelPermissions(_channels[channelId], userId, PermissionTarget.Role, allow, deny);
|
||||
|
||||
private async Task SetChannelPermissions(Channel channel, string targetId, string targetType, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new NullReferenceException(nameof(channel));
|
||||
if (targetId == null) throw new NullReferenceException(nameof(targetId));
|
||||
if (targetType == null) throw new NullReferenceException(nameof(targetType));
|
||||
|
||||
uint allowValue = allow?.RawValue ?? 0;
|
||||
uint denyValue = deny?.RawValue ?? 0;
|
||||
bool changed = false;
|
||||
|
||||
var perms = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).FirstOrDefault();
|
||||
if (allowValue != 0 || denyValue != 0)
|
||||
{
|
||||
await _api.SetChannelPermissions(channel.Id, targetId, targetType, allowValue, denyValue);
|
||||
if (perms != null)
|
||||
{
|
||||
perms.Allow.SetRawValueInternal(allowValue);
|
||||
perms.Deny.SetRawValueInternal(denyValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldPerms = channel._permissionOverwrites;
|
||||
var newPerms = new Channel.PermissionOverwrite[oldPerms.Length + 1];
|
||||
Array.Copy(oldPerms, newPerms, oldPerms.Length);
|
||||
newPerms[oldPerms.Length] = new Channel.PermissionOverwrite(targetType, targetId, allowValue, denyValue);
|
||||
channel._permissionOverwrites = newPerms;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteChannelPermissions(channel.Id, targetId);
|
||||
if (perms != null)
|
||||
{
|
||||
channel._permissionOverwrites = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).ToArray();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
if (targetType == PermissionTarget.Role)
|
||||
channel.InvalidatePermissionsCache();
|
||||
else if (targetType == PermissionTarget.Member)
|
||||
channel.InvalidatePermissionsCache(targetId);
|
||||
}
|
||||
}
|
||||
|
||||
public Task RemoveChannelUserPermissions(Channel channel, Member member)
|
||||
=> RemoveChannelPermissions(channel, member?.UserId, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(string channelId, Member member)
|
||||
=> RemoveChannelPermissions(_channels[channelId], member?.UserId, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(Channel channel, User user)
|
||||
=> RemoveChannelPermissions(channel, user?.Id, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(string channelId, User user)
|
||||
=> RemoveChannelPermissions(_channels[channelId], user?.Id, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(Channel channel, string userId)
|
||||
=> RemoveChannelPermissions(channel, userId, PermissionTarget.Member);
|
||||
public Task RemoveChannelUserPermissions(string channelId, string userId)
|
||||
=> RemoveChannelPermissions(_channels[channelId], userId, PermissionTarget.Member);
|
||||
|
||||
public Task RemoveChannelRolePermissions(Channel channel, Role role)
|
||||
=> RemoveChannelPermissions(channel, role?.Id, PermissionTarget.Role);
|
||||
public Task RemoveChannelRolePermissions(string channelId, Role role)
|
||||
=> RemoveChannelPermissions(_channels[channelId], role?.Id, PermissionTarget.Role);
|
||||
public Task RemoveChannelRolePermissions(Channel channel, string roleId)
|
||||
=> RemoveChannelPermissions(channel, roleId, PermissionTarget.Role);
|
||||
public Task RemoveChannelRolePermissions(string channelId, string roleId)
|
||||
=> RemoveChannelPermissions(_channels[channelId], roleId, PermissionTarget.Role);
|
||||
|
||||
private async Task RemoveChannelPermissions(Channel channel, string userOrRoleId, string idType)
|
||||
{
|
||||
CheckReady();
|
||||
if (channel == null) throw new NullReferenceException(nameof(channel));
|
||||
if (userOrRoleId == null) throw new NullReferenceException(nameof(userOrRoleId));
|
||||
if (idType == null) throw new NullReferenceException(nameof(idType));
|
||||
|
||||
try
|
||||
{
|
||||
var perms = channel.PermissionOverwrites.Where(x => x.TargetType != idType || x.TargetId != userOrRoleId).FirstOrDefault();
|
||||
await _api.DeleteChannelPermissions(channel.Id, userOrRoleId).ConfigureAwait(false);
|
||||
if (perms != null)
|
||||
{
|
||||
channel.PermissionOverwrites.Where(x => x.TargetType != idType || x.TargetId != userOrRoleId).ToArray();
|
||||
|
||||
if (idType == PermissionTarget.Role)
|
||||
channel.InvalidatePermissionsCache();
|
||||
else if (idType == PermissionTarget.Member)
|
||||
channel.InvalidatePermissionsCache(userOrRoleId);
|
||||
}
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
149
src/Discord.Net/DiscordClient.Roles.cs
Normal file
149
src/Discord.Net/DiscordClient.Roles.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using Discord.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public event EventHandler<RoleEventArgs> RoleCreated;
|
||||
private void RaiseRoleCreated(Role role)
|
||||
{
|
||||
if (RoleCreated != null)
|
||||
RaiseEvent(nameof(RoleCreated), () => RoleCreated(this, new RoleEventArgs(role)));
|
||||
}
|
||||
public event EventHandler<RoleEventArgs> RoleUpdated;
|
||||
private void RaiseRoleDeleted(Role role)
|
||||
{
|
||||
if (RoleDeleted != null)
|
||||
RaiseEvent(nameof(RoleDeleted), () => RoleDeleted(this, new RoleEventArgs(role)));
|
||||
}
|
||||
public event EventHandler<RoleEventArgs> RoleDeleted;
|
||||
private void RaiseRoleUpdated(Role role)
|
||||
{
|
||||
if (RoleUpdated != null)
|
||||
RaiseEvent(nameof(RoleUpdated), () => RoleUpdated(this, new RoleEventArgs(role)));
|
||||
}
|
||||
|
||||
/// <summary> Returns a collection of all role-server pairs this client can currently see. </summary>
|
||||
public Roles Roles => _roles;
|
||||
private readonly Roles _roles;
|
||||
|
||||
/// <summary> Returns the role with the specified id, or null if none was found. </summary>
|
||||
public Role GetRole(string id) => _roles[id];
|
||||
/// <summary> Returns all roles with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Role> FindRoles(Server server, string name) => FindRoles(server?.Id, name);
|
||||
/// <summary> Returns all roles with the specified server and name. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Role> FindRoles(string serverId, string name)
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (name.StartsWith("@"))
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
return _roles.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
return _roles.Where(x => x.ServerId == serverId &&
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Note: due to current API limitations, the created role cannot be returned. </summary>
|
||||
public Task<Role> CreateRole(Server server, string name)
|
||||
=> CreateRole(server?.Id, name);
|
||||
/// <summary> Note: due to current API limitations, the created role cannot be returned. </summary>
|
||||
public async Task<Role> CreateRole(string serverId, string name)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
|
||||
var response = await _api.CreateRole(serverId).ConfigureAwait(false);
|
||||
var role = _roles.GetOrAdd(response.Id, serverId);
|
||||
role.Update(response);
|
||||
|
||||
await EditRole(role, name: name);
|
||||
|
||||
return role;
|
||||
}
|
||||
|
||||
public Task EditRole(Role role, string name = null, PackedServerPermissions permissions = null, PackedColor color = null, bool? hoist = null, int? position = null)
|
||||
=> EditRole(role.ServerId, role.Id, name: name, permissions: permissions, color: color, hoist: hoist, position: position);
|
||||
public async Task EditRole(string serverId, string roleId, string name = null, PackedServerPermissions permissions = null, PackedColor color = null, bool? hoist = null, int? position = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
if (roleId == null) throw new NullReferenceException(nameof(roleId));
|
||||
|
||||
var response = await _api.EditRole(serverId, roleId, name: name,
|
||||
permissions: permissions?.RawValue, color: color?.RawValue, hoist: hoist);
|
||||
|
||||
var role = _roles[response.Id];
|
||||
if (role != null)
|
||||
role.Update(response);
|
||||
|
||||
if (position != null)
|
||||
{
|
||||
int oldPos = role.Position;
|
||||
int newPos = position.Value;
|
||||
int minPos;
|
||||
Role[] roles = role.Server.Roles.OrderBy(x => x.Position).ToArray();
|
||||
|
||||
if (oldPos < newPos) //Moving Down
|
||||
{
|
||||
minPos = oldPos;
|
||||
for (int i = oldPos; i < newPos; i++)
|
||||
roles[i] = roles[i + 1];
|
||||
roles[newPos] = role;
|
||||
}
|
||||
else //(oldPos > newPos) Moving Up
|
||||
{
|
||||
minPos = newPos;
|
||||
for (int i = oldPos; i > newPos; i--)
|
||||
roles[i] = roles[i - 1];
|
||||
roles[newPos] = role;
|
||||
}
|
||||
await _api.ReorderRoles(role.ServerId, roles.Skip(minPos).Select(x => x.Id), minPos);
|
||||
}
|
||||
}
|
||||
|
||||
public Task DeleteRole(Role role)
|
||||
=> DeleteRole(role?.ServerId, role?.Id);
|
||||
public Task DeleteRole(string serverId, string roleId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new NullReferenceException(nameof(serverId));
|
||||
if (roleId == null) throw new NullReferenceException(nameof(roleId));
|
||||
|
||||
return _api.DeleteRole(serverId, roleId);
|
||||
}
|
||||
|
||||
public Task ReorderRoles(Server server, IEnumerable<object> roles, int startPos = 0)
|
||||
=> ReorderChannels(server.Id, roles, startPos);
|
||||
public Task ReorderRoles(string serverId, IEnumerable<object> roles, int startPos = 0)
|
||||
{
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (roles == null) throw new ArgumentNullException(nameof(roles));
|
||||
if (startPos < 0) throw new ArgumentOutOfRangeException(nameof(startPos), "startPos must be a positive integer.");
|
||||
|
||||
var roleIds = roles.Select(x =>
|
||||
{
|
||||
if (x is string)
|
||||
return x as string;
|
||||
else if (x is Role)
|
||||
return (x as Role).Id;
|
||||
else
|
||||
throw new ArgumentException("Channels must be a collection of string or Role.", nameof(roles));
|
||||
});
|
||||
|
||||
return _api.ReorderRoles(serverId, roleIds, startPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
102
src/Discord.Net/DiscordClient.Servers.cs
Normal file
102
src/Discord.Net/DiscordClient.Servers.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using Discord.Net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public sealed class ServerEventArgs : EventArgs
|
||||
{
|
||||
public Server Server { get; }
|
||||
public string ServerId => Server.Id;
|
||||
|
||||
internal ServerEventArgs(Server server) { Server = server; }
|
||||
}
|
||||
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public event EventHandler<ServerEventArgs> ServerCreated;
|
||||
private void RaiseServerCreated(Server server)
|
||||
{
|
||||
if (ServerCreated != null)
|
||||
RaiseEvent(nameof(ServerCreated), () => ServerCreated(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerDestroyed;
|
||||
private void RaiseServerDestroyed(Server server)
|
||||
{
|
||||
if (ServerDestroyed != null)
|
||||
RaiseEvent(nameof(ServerDestroyed), () => ServerDestroyed(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerUpdated;
|
||||
private void RaiseServerUpdated(Server server)
|
||||
{
|
||||
if (ServerUpdated != null)
|
||||
RaiseEvent(nameof(ServerUpdated), () => ServerUpdated(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerUnavailable;
|
||||
private void RaiseServerUnavailable(Server server)
|
||||
{
|
||||
if (ServerUnavailable != null)
|
||||
RaiseEvent(nameof(ServerUnavailable), () => ServerUnavailable(this, new ServerEventArgs(server)));
|
||||
}
|
||||
public event EventHandler<ServerEventArgs> ServerAvailable;
|
||||
private void RaiseServerAvailable(Server server)
|
||||
{
|
||||
if (ServerAvailable != null)
|
||||
RaiseEvent(nameof(ServerAvailable), () => ServerAvailable(this, new ServerEventArgs(server)));
|
||||
}
|
||||
|
||||
/// <summary> Returns the server with the specified id, or null if none was found. </summary>
|
||||
public Server GetServer(string id) => _servers[id];
|
||||
/// <summary> Returns all servers with the specified name. </summary>
|
||||
/// <remarks> Search is case-insensitive. </remarks>
|
||||
public IEnumerable<Server> FindServers(string name)
|
||||
{
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
return _servers.Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary> Creates a new server with the provided name and region (see Regions). </summary>
|
||||
public async Task<Server> CreateServer(string name, string region)
|
||||
{
|
||||
CheckReady();
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (region == null) throw new ArgumentNullException(nameof(region));
|
||||
|
||||
var response = await _api.CreateServer(name, region).ConfigureAwait(false);
|
||||
var server = _servers.GetOrAdd(response.Id);
|
||||
server.Update(response);
|
||||
return server;
|
||||
}
|
||||
|
||||
/// <summary> Edits the provided server, changing only non-null attributes. </summary>
|
||||
public Task EditServer(string serverId, string name = null, string region = null, ImageType iconType = ImageType.Png, byte[] icon = null)
|
||||
=> EditServer(_servers[serverId], name: name, region: region, iconType: iconType, icon: icon);
|
||||
/// <summary> Edits the provided server, changing only non-null attributes. </summary>
|
||||
public async Task EditServer(Server server, string name = null, string region = null, ImageType iconType = ImageType.Png, byte[] icon = null)
|
||||
{
|
||||
CheckReady();
|
||||
if (server == null) throw new ArgumentNullException(nameof(server));
|
||||
|
||||
var response = await _api.EditServer(server.Id, name: name ?? server.Name, region: region, iconType: iconType, icon: icon);
|
||||
server.Update(response);
|
||||
}
|
||||
|
||||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary>
|
||||
public Task<Server> LeaveServer(Server server)
|
||||
=> LeaveServer(server?.Id);
|
||||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary>
|
||||
public async Task<Server> LeaveServer(string serverId)
|
||||
{
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
|
||||
try { await _api.LeaveServer(serverId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
return _servers.TryRemove(serverId);
|
||||
}
|
||||
}
|
||||
}
|
||||
130
src/Discord.Net/DiscordClient.Users.cs
Normal file
130
src/Discord.Net/DiscordClient.Users.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Discord.API;
|
||||
using Discord.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public sealed class UserEventArgs : EventArgs
|
||||
{
|
||||
public User User { get; }
|
||||
public string UserId => User.Id;
|
||||
|
||||
internal UserEventArgs(User user) { User = user; }
|
||||
}
|
||||
|
||||
public partial class DiscordClient
|
||||
{
|
||||
public event EventHandler<MemberEventArgs> UserAdded;
|
||||
private void RaiseUserAdded(Member member)
|
||||
{
|
||||
if (UserAdded != null)
|
||||
RaiseEvent(nameof(UserAdded), () => UserAdded(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> UserRemoved;
|
||||
private void RaiseUserRemoved(Member member)
|
||||
{
|
||||
if (UserRemoved != null)
|
||||
RaiseEvent(nameof(UserRemoved), () => UserRemoved(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<UserEventArgs> UserUpdated;
|
||||
private void RaiseUserUpdated(User user)
|
||||
{
|
||||
if (UserUpdated != null)
|
||||
RaiseEvent(nameof(UserUpdated), () => UserUpdated(this, new UserEventArgs(user)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> MemberUpdated;
|
||||
private void RaiseMemberUpdated(Member member)
|
||||
{
|
||||
if (MemberUpdated != null)
|
||||
RaiseEvent(nameof(MemberUpdated), () => MemberUpdated(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> UserPresenceUpdated;
|
||||
private void RaiseUserPresenceUpdated(Member member)
|
||||
{
|
||||
if (UserPresenceUpdated != null)
|
||||
RaiseEvent(nameof(UserPresenceUpdated), () => UserPresenceUpdated(this, new MemberEventArgs(member)));
|
||||
}
|
||||
public event EventHandler<MemberEventArgs> UserVoiceStateUpdated;
|
||||
private void RaiseUserVoiceStateUpdated(Member member)
|
||||
{
|
||||
if (UserVoiceStateUpdated != null)
|
||||
RaiseEvent(nameof(UserVoiceStateUpdated), () => UserVoiceStateUpdated(this, new MemberEventArgs(member)));
|
||||
}
|
||||
|
||||
/// <summary> Returns a collection of all users this client can currently see. </summary>
|
||||
public Users Users => _users;
|
||||
private readonly Users _users;
|
||||
/// <summary> Returns the current logged-in user. </summary>
|
||||
public User CurrentUser => _currentUser;
|
||||
private User _currentUser;
|
||||
|
||||
/// <summary> Returns the user with the specified id, or null if none was found. </summary>
|
||||
public User GetUser(string id) => _users[id];
|
||||
/// <summary> Returns the user with the specified name and discriminator, or null if none was found. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public User GetUser(string username, string discriminator)
|
||||
{
|
||||
if (username == null) throw new ArgumentNullException(nameof(username));
|
||||
if (discriminator == null) throw new ArgumentNullException(nameof(discriminator));
|
||||
|
||||
if (username.StartsWith("@"))
|
||||
username = username.Substring(1);
|
||||
|
||||
return _users.Where(x =>
|
||||
string.Equals(x.Name, username, StringComparison.OrdinalIgnoreCase) &&
|
||||
x.Discriminator == discriminator
|
||||
)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary> Returns all users with the specified name across all servers. </summary>
|
||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks>
|
||||
public IEnumerable<User> FindUsers(string name)
|
||||
{
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (name.StartsWith("@"))
|
||||
{
|
||||
string name2 = name.Substring(1);
|
||||
return _users.Where(x =>
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
return _users.Where(x =>
|
||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
public Task<EditUserResponse> EditProfile(string currentPassword = "",
|
||||
string username = null, string email = null, string password = null,
|
||||
ImageType avatarType = ImageType.Png, byte[] avatar = null)
|
||||
{
|
||||
if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword));
|
||||
|
||||
return _api.EditUser(currentPassword: currentPassword, username: username ?? _currentUser?.Name, email: email ?? _currentUser?.Email, password: password,
|
||||
avatarType: avatarType, avatar: avatar);
|
||||
}
|
||||
|
||||
public Task SetStatus(string status)
|
||||
{
|
||||
if (status != UserStatus.Online && status != UserStatus.Idle)
|
||||
throw new ArgumentException($"Invalid status, must be {UserStatus.Online} or {UserStatus.Idle}");
|
||||
_status = status;
|
||||
return SendStatus();
|
||||
}
|
||||
public Task SetGame(int? gameId)
|
||||
{
|
||||
_gameId = gameId;
|
||||
return SendStatus();
|
||||
}
|
||||
private Task SendStatus()
|
||||
{
|
||||
_dataSocket.SendStatus(_status == UserStatus.Idle ? EpochTime.GetMilliseconds() - (10 * 60 * 1000) : (ulong?)null, _gameId);
|
||||
return TaskHelper.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,54 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
public sealed class MessageEventArgs : EventArgs
|
||||
{
|
||||
public Message Message { get; }
|
||||
public string MessageId => Message.Id;
|
||||
public Member Member => Message.Member;
|
||||
public Channel Channel => Message.Channel;
|
||||
public string ChannelId => Message.ChannelId;
|
||||
public Server Server => Message.Server;
|
||||
public string ServerId => Message.ServerId;
|
||||
public User User => Member.User;
|
||||
public string UserId => Message.UserId;
|
||||
|
||||
internal MessageEventArgs(Message msg) { Message = msg; }
|
||||
}
|
||||
public sealed class RoleEventArgs : EventArgs
|
||||
{
|
||||
public Role Role { get; }
|
||||
public string RoleId => Role.Id;
|
||||
public Server Server => Role.Server;
|
||||
public string ServerId => Role.ServerId;
|
||||
|
||||
internal RoleEventArgs(Role role) { Role = role; }
|
||||
}
|
||||
public sealed class BanEventArgs : EventArgs
|
||||
{
|
||||
public User User { get; }
|
||||
public string UserId { get; }
|
||||
public Server Server { get; }
|
||||
public string ServerId => Server.Id;
|
||||
|
||||
internal BanEventArgs(User user, string userId, Server server)
|
||||
{
|
||||
User = user;
|
||||
UserId = userId;
|
||||
Server = server;
|
||||
}
|
||||
}
|
||||
public sealed class MemberEventArgs : EventArgs
|
||||
{
|
||||
public Member Member { get; }
|
||||
public User User => Member.User;
|
||||
public string UserId => Member.UserId;
|
||||
public Server Server => Member.Server;
|
||||
public string ServerId => Member.ServerId;
|
||||
|
||||
internal MemberEventArgs(Member member) { Member = member; }
|
||||
}
|
||||
|
||||
/// <summary> Provides a connection to the DiscordApp service. </summary>
|
||||
public partial class DiscordClient : DiscordWSClient
|
||||
{
|
||||
@@ -28,29 +76,10 @@ namespace Discord
|
||||
|
||||
public new DiscordClientConfig Config => _config as DiscordClientConfig;
|
||||
|
||||
/// <summary> Returns the current logged-in user. </summary>
|
||||
public User CurrentUser => _currentUser;
|
||||
private User _currentUser;
|
||||
|
||||
/// <summary> Returns a collection of all channels this client is a member of. </summary>
|
||||
public Channels Channels => _channels;
|
||||
private readonly Channels _channels;
|
||||
/// <summary> Returns a collection of all user-server pairs this client can currently see. </summary>
|
||||
public Members Members => _members;
|
||||
private readonly Members _members;
|
||||
/// <summary> Returns a collection of all messages this client has seen since logging in and currently has in cache. </summary>
|
||||
public Messages Messages => _messages;
|
||||
private readonly Messages _messages;
|
||||
//TODO: Do we need the roles cache?
|
||||
/// <summary> Returns a collection of all role-server pairs this client can currently see. </summary>
|
||||
public Roles Roles => _roles;
|
||||
private readonly Roles _roles;
|
||||
/// <summary> Returns a collection of all servers this client is a member of. </summary>
|
||||
public Servers Servers => _servers;
|
||||
private readonly Servers _servers;
|
||||
/// <summary> Returns a collection of all users this client can currently see. </summary>
|
||||
public Users Users => _users;
|
||||
private readonly Users _users;
|
||||
|
||||
/// <summary> Initializes a new instance of the DiscordClient class. </summary>
|
||||
public DiscordClient(DiscordClientConfig config = null)
|
||||
@@ -69,8 +98,8 @@ namespace Discord
|
||||
_messages = new Messages(this, cacheLock);
|
||||
_roles = new Roles(this, cacheLock);
|
||||
_servers = new Servers(this, cacheLock);
|
||||
_users = new Users(this, cacheLock);
|
||||
_status = UserStatus.Online;
|
||||
_users = new Users(this, cacheLock);
|
||||
|
||||
this.Connected += async (s, e) =>
|
||||
{
|
||||
@@ -321,47 +350,6 @@ namespace Discord
|
||||
return base.GetTasks();
|
||||
}
|
||||
|
||||
private Task MessageQueueLoop()
|
||||
{
|
||||
var cancelToken = CancelToken;
|
||||
int interval = Config.MessageQueueInterval;
|
||||
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
Message msg;
|
||||
while (!cancelToken.IsCancellationRequested)
|
||||
{
|
||||
while (_pendingMessages.TryDequeue(out msg))
|
||||
{
|
||||
bool hasFailed = false;
|
||||
SendMessageResponse response = null;
|
||||
try
|
||||
{
|
||||
response = await _api.SendMessage(msg.ChannelId, msg.RawText, msg.MentionIds, msg.Nonce, msg.IsTTS).ConfigureAwait(false);
|
||||
}
|
||||
catch (WebException) { break; }
|
||||
catch (HttpException) { hasFailed = true; }
|
||||
|
||||
if (!hasFailed)
|
||||
{
|
||||
_messages.Remap(msg.Id, response.Id);
|
||||
msg.Id = response.Id;
|
||||
msg.Update(response);
|
||||
}
|
||||
msg.IsQueued = false;
|
||||
msg.HasFailed = hasFailed;
|
||||
RaiseMessageSent(msg);
|
||||
}
|
||||
await Task.Delay(interval).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
private string GenerateNonce()
|
||||
{
|
||||
lock (_rand)
|
||||
return _rand.Next().ToString();
|
||||
}
|
||||
|
||||
internal override async Task OnReceivedEvent(WebSocketEventEventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -656,7 +644,7 @@ namespace Discord
|
||||
{
|
||||
var data = e.Payload.ToObject<TypingStartEvent>(_serializer);
|
||||
var channel = _channels[data.ChannelId];
|
||||
var user = _users[data.UserId];
|
||||
var user = _members[data.UserId, channel.ServerId];
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user