@@ -82,8 +82,8 @@ | |||||
<Compile Include="..\Discord.Net\API\Enums\AvatarImageType.cs"> | <Compile Include="..\Discord.Net\API\Enums\AvatarImageType.cs"> | ||||
<Link>API\Enums\AvatarImageType.cs</Link> | <Link>API\Enums\AvatarImageType.cs</Link> | ||||
</Compile> | </Compile> | ||||
<Compile Include="..\Discord.Net\API\Enums\ChannelTypes.cs"> | |||||
<Link>API\Enums\ChannelTypes.cs</Link> | |||||
<Compile Include="..\Discord.Net\API\Enums\ChannelType.cs"> | |||||
<Link>API\Enums\ChannelType.cs</Link> | |||||
</Compile> | </Compile> | ||||
<Compile Include="..\Discord.Net\API\Enums\PermissionTarget.cs"> | <Compile Include="..\Discord.Net\API\Enums\PermissionTarget.cs"> | ||||
<Link>API\Enums\PermissionTarget.cs</Link> | <Link>API\Enums\PermissionTarget.cs</Link> | ||||
@@ -91,6 +91,9 @@ | |||||
<Compile Include="..\Discord.Net\API\Enums\Regions.cs"> | <Compile Include="..\Discord.Net\API\Enums\Regions.cs"> | ||||
<Link>API\Enums\Regions.cs</Link> | <Link>API\Enums\Regions.cs</Link> | ||||
</Compile> | </Compile> | ||||
<Compile Include="..\Discord.Net\API\Enums\StringEnum.cs"> | |||||
<Link>API\Enums\StringEnum.cs</Link> | |||||
</Compile> | |||||
<Compile Include="..\Discord.Net\API\Enums\UserStatus.cs"> | <Compile Include="..\Discord.Net\API\Enums\UserStatus.cs"> | ||||
<Link>API\Enums\UserStatus.cs</Link> | <Link>API\Enums\UserStatus.cs</Link> | ||||
</Compile> | </Compile> | ||||
@@ -0,0 +1,28 @@ | |||||
namespace Discord | |||||
{ | |||||
public class ChannelType : StringEnum | |||||
{ | |||||
/// <summary> A text-only channel. </summary> | |||||
public static readonly ChannelType Text = new ChannelType("text"); | |||||
/// <summary> A voice-only channel. </summary> | |||||
public static readonly ChannelType Voice = new ChannelType("voice"); | |||||
private ChannelType(string value) | |||||
: base(value) { } | |||||
public static ChannelType FromString(string value) | |||||
{ | |||||
switch (value) | |||||
{ | |||||
case null: | |||||
return null; | |||||
case "text": | |||||
return ChannelType.Text; | |||||
case "voice": | |||||
return ChannelType.Voice; | |||||
default: | |||||
return new ChannelType(value); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,10 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
public static class ChannelTypes | |||||
{ | |||||
/// <summary> A text-only channel. </summary> | |||||
public const string Text = "text"; | |||||
/// <summary> A voice-only channel. </summary> | |||||
public const string Voice = "voice"; | |||||
} | |||||
} |
@@ -1,8 +1,28 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public static class PermissionTarget | |||||
{ | |||||
public const string Role = "role"; | |||||
public const string Member = "member"; | |||||
public class PermissionTarget : StringEnum | |||||
{ | |||||
/// <summary> A text-only channel. </summary> | |||||
public static readonly PermissionTarget Role = new PermissionTarget("role"); | |||||
/// <summary> A voice-only channel. </summary> | |||||
public static readonly PermissionTarget Member = new PermissionTarget("member"); | |||||
private PermissionTarget(string value) | |||||
: base(value) { } | |||||
public static PermissionTarget FromString(string value) | |||||
{ | |||||
switch (value) | |||||
{ | |||||
case null: | |||||
return null; | |||||
case "role": | |||||
return PermissionTarget.Role; | |||||
case "member": | |||||
return PermissionTarget.Member; | |||||
default: | |||||
return new PermissionTarget(value); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -1,12 +1,38 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public static class Regions | |||||
public class Region : StringEnum | |||||
{ | { | ||||
public const string US_West = "us-west"; | |||||
public const string US_East = "us-east"; | |||||
public const string Singapore = "singapore"; | |||||
public const string London = "london"; | |||||
public const string Sydney = "sydney"; | |||||
public const string Amsterdam = "amsterdam"; | |||||
public static readonly Region USWest = new Region("us-west"); | |||||
public static readonly Region USEast = new Region("us-east"); | |||||
public static readonly Region Singapore = new Region("singapore"); | |||||
public static readonly Region London = new Region("london"); | |||||
public static readonly Region Sydney = new Region("sydney"); | |||||
public static readonly Region Amsterdam = new Region("amsterdam"); | |||||
private Region(string value) | |||||
: base(value) { } | |||||
public static Region FromString(string value) | |||||
{ | |||||
switch (value) | |||||
{ | |||||
case null: | |||||
return null; | |||||
case "us-west": | |||||
return Region.USWest; | |||||
case "us-east": | |||||
return Region.USEast; | |||||
case "singapore": | |||||
return Region.Singapore; | |||||
case "london": | |||||
return Region.London; | |||||
case "sydney": | |||||
return Region.Sydney; | |||||
case "amsterdam": | |||||
return Region.Amsterdam; | |||||
default: | |||||
return new Region(value); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -0,0 +1,52 @@ | |||||
namespace Discord | |||||
{ | |||||
public abstract class StringEnum | |||||
{ | |||||
private string _value; | |||||
protected StringEnum(string value) | |||||
{ | |||||
_value = value; | |||||
} | |||||
public string Value => _value; | |||||
public override string ToString() => _value; | |||||
public override bool Equals(object obj) | |||||
{ | |||||
var enum2 = obj as StringEnum; | |||||
if (enum2 == (StringEnum)null) | |||||
return false; | |||||
else | |||||
return _value == enum2._value; | |||||
} | |||||
public override int GetHashCode() | |||||
{ | |||||
return _value.GetHashCode(); | |||||
} | |||||
public static bool operator ==(StringEnum a, StringEnum b) | |||||
{ | |||||
return a?._value == b?._value; | |||||
} | |||||
public static bool operator !=(StringEnum a, StringEnum b) | |||||
{ | |||||
return a?._value != b?._value; | |||||
} | |||||
public static bool operator ==(StringEnum a, string b) | |||||
{ | |||||
return a?._value == b; | |||||
} | |||||
public static bool operator !=(StringEnum a, string b) | |||||
{ | |||||
return a?._value != b; | |||||
} | |||||
public static bool operator ==(string a, StringEnum b) | |||||
{ | |||||
return a == b?._value; | |||||
} | |||||
public static bool operator !=(string a, StringEnum b) | |||||
{ | |||||
return a != b?._value; | |||||
} | |||||
} | |||||
} |
@@ -1,12 +1,32 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public static class UserStatus | |||||
public class UserStatus : StringEnum | |||||
{ | { | ||||
/// <summary> User is currently online and active. </summary> | /// <summary> User is currently online and active. </summary> | ||||
public const string Online = "online"; | |||||
public static readonly UserStatus Online = new UserStatus("online"); | |||||
/// <summary> User is currently online but inactive. </summary> | /// <summary> User is currently online but inactive. </summary> | ||||
public const string Idle = "idle"; | |||||
public static readonly UserStatus Idle = new UserStatus("idle"); | |||||
/// <summary> User is offline. </summary> | /// <summary> User is offline. </summary> | ||||
public const string Offline = "offline"; | |||||
public static readonly UserStatus Offline = new UserStatus("offline"); | |||||
private UserStatus(string value) | |||||
: base(value) { } | |||||
public static UserStatus FromString(string value) | |||||
{ | |||||
switch (value) | |||||
{ | |||||
case null: | |||||
return null; | |||||
case "online": | |||||
return UserStatus.Online; | |||||
case "idle": | |||||
return UserStatus.Idle; | |||||
case "offline": | |||||
return UserStatus.Offline; | |||||
default: | |||||
return new UserStatus(value); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -35,8 +35,8 @@ namespace Discord | |||||
/// <summary> Bans a user from the provided server. </summary> | /// <summary> Bans a user from the provided server. </summary> | ||||
public Task Ban(Member member) | public Task Ban(Member member) | ||||
{ | { | ||||
CheckReady(); | |||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
CheckReady(); | |||||
return _api.Ban(member.ServerId, member.Id); | return _api.Ban(member.ServerId, member.Id); | ||||
} | } | ||||
@@ -44,8 +44,8 @@ namespace Discord | |||||
/// <summary> Unbans a user from the provided server. </summary> | /// <summary> Unbans a user from the provided server. </summary> | ||||
public async Task Unban(Member member) | public async Task Unban(Member member) | ||||
{ | { | ||||
CheckReady(); | |||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
CheckReady(); | |||||
try { await _api.Unban(member.ServerId, member.Id).ConfigureAwait(false); } | try { await _api.Unban(member.ServerId, member.Id).ConfigureAwait(false); } | ||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | ||||
@@ -56,7 +56,7 @@ namespace Discord | |||||
/// <summary> Returns all channels with the specified server and name. </summary> | /// <summary> Returns all channels with the specified server and name. </summary> | ||||
/// <remarks> Name formats supported: Name and #Name. Search is case-insensitive. </remarks> | /// <remarks> Name formats supported: Name and #Name. Search is case-insensitive. </remarks> | ||||
public IEnumerable<Channel> FindChannels(Server server, string name, string type = null) | |||||
public IEnumerable<Channel> FindChannels(Server server, string name, ChannelType type = null) | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
@@ -74,21 +74,21 @@ namespace Discord | |||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); | string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); | ||||
} | } | ||||
if (type != null) | |||||
if (type != (string)null) | |||||
result = result.Where(x => x.Type == type); | result = result.Where(x => x.Type == type); | ||||
return result; | return result; | ||||
} | } | ||||
/// <summary> Creates a new channel with the provided name and type (see ChannelTypes). </summary> | |||||
public async Task<Channel> CreateChannel(Server server, string name, string type = ChannelTypes.Text) | |||||
/// <summary> Creates a new channel with the provided name and type. </summary> | |||||
public async Task<Channel> CreateChannel(Server server, string name, ChannelType type) | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
if (name == null) throw new ArgumentNullException(nameof(name)); | if (name == null) throw new ArgumentNullException(nameof(name)); | ||||
if (type == null) throw new ArgumentNullException(nameof(type)); | |||||
if (type == (string)null) throw new ArgumentNullException(nameof(type)); | |||||
CheckReady(); | CheckReady(); | ||||
var response = await _api.CreateChannel(server.Id, name, type).ConfigureAwait(false); | |||||
var response = await _api.CreateChannel(server.Id, name, type.Value).ConfigureAwait(false); | |||||
var channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id); | var channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id); | ||||
channel.Update(response); | channel.Update(response); | ||||
return channel; | return channel; | ||||
@@ -153,15 +153,16 @@ namespace Discord | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
if (channels == null) throw new ArgumentNullException(nameof(channels)); | if (channels == null) throw new ArgumentNullException(nameof(channels)); | ||||
CheckReady(); | |||||
return _api.ReorderChannels(server.Id, channels.Select(x => x.Id), after.Position); | return _api.ReorderChannels(server.Id, channels.Select(x => x.Id), after.Position); | ||||
} | } | ||||
/// <summary> Destroys the provided channel. </summary> | /// <summary> Destroys the provided channel. </summary> | ||||
public async Task<Channel> DestroyChannel(Channel channel) | public async Task<Channel> DestroyChannel(Channel channel) | ||||
{ | { | ||||
CheckReady(); | |||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
CheckReady(); | |||||
try { await _api.DestroyChannel(channel.Id).ConfigureAwait(false); } | try { await _api.DestroyChannel(channel.Id).ConfigureAwait(false); } | ||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | ||||
@@ -10,8 +10,8 @@ namespace Discord | |||||
/// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks> | /// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks> | ||||
public async Task<Invite> GetInvite(string inviteIdOrXkcd) | public async Task<Invite> GetInvite(string inviteIdOrXkcd) | ||||
{ | { | ||||
CheckReady(); | |||||
if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); | if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); | ||||
CheckReady(); | |||||
//Remove trailing slash | //Remove trailing slash | ||||
if (inviteIdOrXkcd.Length > 0 && inviteIdOrXkcd[inviteIdOrXkcd.Length - 1] == '/') | if (inviteIdOrXkcd.Length > 0 && inviteIdOrXkcd[inviteIdOrXkcd.Length - 1] == '/') | ||||
@@ -35,6 +35,8 @@ namespace Discord | |||||
public Task<Invite> CreateInvite(Server server, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false) | public Task<Invite> CreateInvite(Server server, int maxAge = 1800, int maxUses = 0, bool tempMembership = false, bool hasXkcd = false) | ||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
CheckReady(); | |||||
return CreateInvite(server.DefaultChannel, maxAge, maxUses, tempMembership, hasXkcd); | return CreateInvite(server.DefaultChannel, maxAge, maxUses, tempMembership, hasXkcd); | ||||
} | } | ||||
/// <summary> Creates a new invite to the provided channel. </summary> | /// <summary> Creates a new invite to the provided channel. </summary> | ||||
@@ -59,8 +61,8 @@ namespace Discord | |||||
/// <summary> Deletes the provided invite. </summary> | /// <summary> Deletes the provided invite. </summary> | ||||
public async Task DestroyInvite(Invite invite) | public async Task DestroyInvite(Invite invite) | ||||
{ | { | ||||
CheckReady(); | |||||
if (invite == null) throw new ArgumentNullException(nameof(invite)); | if (invite == null) throw new ArgumentNullException(nameof(invite)); | ||||
CheckReady(); | |||||
try { await _api.DeleteInvite(invite.Id).ConfigureAwait(false); } | try { await _api.DeleteInvite(invite.Id).ConfigureAwait(false); } | ||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | ||||
@@ -69,8 +71,8 @@ namespace Discord | |||||
/// <summary> Accepts the provided invite. </summary> | /// <summary> Accepts the provided invite. </summary> | ||||
public Task AcceptInvite(Invite invite) | public Task AcceptInvite(Invite invite) | ||||
{ | { | ||||
CheckReady(); | |||||
if (invite == null) throw new ArgumentNullException(nameof(invite)); | if (invite == null) throw new ArgumentNullException(nameof(invite)); | ||||
CheckReady(); | |||||
return _api.AcceptInvite(invite.Id); | return _api.AcceptInvite(invite.Id); | ||||
} | } | ||||
@@ -190,7 +190,7 @@ namespace Discord | |||||
CheckReady(); | CheckReady(); | ||||
if (count == 0) return new Message[0]; | if (count == 0) return new Message[0]; | ||||
if (channel != null && channel.Type == ChannelTypes.Text) | |||||
if (channel != null && channel.Type == ChannelType.Text) | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
@@ -8,20 +8,39 @@ namespace Discord | |||||
public partial class DiscordClient | public partial class DiscordClient | ||||
{ | { | ||||
public Task SetChannelUserPermissions(Channel channel, Member member, ChannelPermissions allow = null, ChannelPermissions deny = null) | public Task SetChannelUserPermissions(Channel channel, Member member, ChannelPermissions allow = null, ChannelPermissions deny = null) | ||||
=> SetChannelPermissions(channel, member?.Id, PermissionTarget.Member, allow, deny); | |||||
{ | |||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
if (member == null) throw new ArgumentNullException(nameof(member)); | |||||
CheckReady(); | |||||
return SetChannelPermissions(channel, member?.Id, PermissionTarget.Member, allow, deny); | |||||
} | |||||
public Task SetChannelUserPermissions(Channel channel, Member member, DualChannelPermissions permissions = null) | public Task SetChannelUserPermissions(Channel channel, Member member, DualChannelPermissions permissions = null) | ||||
=> SetChannelPermissions(channel, member?.Id, PermissionTarget.Member, permissions?.Allow, permissions?.Deny); | |||||
{ | |||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
if (member == null) throw new ArgumentNullException(nameof(member)); | |||||
CheckReady(); | |||||
return SetChannelPermissions(channel, member?.Id, PermissionTarget.Member, permissions?.Allow, permissions?.Deny); | |||||
} | |||||
public Task SetChannelRolePermissions(Channel channel, Role role, ChannelPermissions allow = null, ChannelPermissions deny = null) | public Task SetChannelRolePermissions(Channel channel, Role role, ChannelPermissions allow = null, ChannelPermissions deny = null) | ||||
=> SetChannelPermissions(channel, role?.Id, PermissionTarget.Role, allow, deny); | |||||
public Task SetChannelRolePermissions(Channel channel, Role role, DualChannelPermissions permissions = null) | |||||
=> SetChannelPermissions(channel, role?.Id, PermissionTarget.Role, permissions?.Allow, permissions?.Deny); | |||||
private async Task SetChannelPermissions(Channel channel, string targetId, string targetType, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||||
{ | { | ||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
if (role == null) throw new ArgumentNullException(nameof(role)); | |||||
CheckReady(); | CheckReady(); | ||||
return SetChannelPermissions(channel, role?.Id, PermissionTarget.Role, allow, deny); | |||||
} | |||||
public Task SetChannelRolePermissions(Channel channel, Role role, DualChannelPermissions permissions = null) | |||||
{ | |||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
if (targetId == null) throw new ArgumentNullException(nameof(targetId)); | |||||
if (targetType == null) throw new ArgumentNullException(nameof(targetType)); | |||||
if (role == null) throw new ArgumentNullException(nameof(role)); | |||||
CheckReady(); | |||||
return SetChannelPermissions(channel, role?.Id, PermissionTarget.Role, permissions?.Allow, permissions?.Deny); | |||||
} | |||||
private async Task SetChannelPermissions(Channel channel, string targetId, PermissionTarget targetType, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||||
{ | |||||
uint allowValue = allow?.RawValue ?? 0; | uint allowValue = allow?.RawValue ?? 0; | ||||
uint denyValue = deny?.RawValue ?? 0; | uint denyValue = deny?.RawValue ?? 0; | ||||
bool changed = false; | bool changed = false; | ||||
@@ -29,7 +48,7 @@ namespace Discord | |||||
var perms = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).FirstOrDefault(); | var perms = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).FirstOrDefault(); | ||||
if (allowValue != 0 || denyValue != 0) | if (allowValue != 0 || denyValue != 0) | ||||
{ | { | ||||
await _api.SetChannelPermissions(channel.Id, targetId, targetType, allowValue, denyValue); | |||||
await _api.SetChannelPermissions(channel.Id, targetId, targetType.Value, allowValue, denyValue); | |||||
if (perms != null) | if (perms != null) | ||||
{ | { | ||||
perms.Allow.SetRawValueInternal(allowValue); | perms.Allow.SetRawValueInternal(allowValue); | ||||
@@ -84,19 +103,19 @@ namespace Discord | |||||
return RemoveChannelPermissions(channel, role?.Id, PermissionTarget.Role); | return RemoveChannelPermissions(channel, role?.Id, PermissionTarget.Role); | ||||
} | } | ||||
private async Task RemoveChannelPermissions(Channel channel, string userOrRoleId, string idType) | |||||
private async Task RemoveChannelPermissions(Channel channel, string userOrRoleId, PermissionTarget targetType) | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
var perms = channel.PermissionOverwrites.Where(x => x.TargetType != idType || x.TargetId != userOrRoleId).FirstOrDefault(); | |||||
var perms = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != userOrRoleId).FirstOrDefault(); | |||||
await _api.DeleteChannelPermissions(channel.Id, userOrRoleId).ConfigureAwait(false); | await _api.DeleteChannelPermissions(channel.Id, userOrRoleId).ConfigureAwait(false); | ||||
if (perms != null) | if (perms != null) | ||||
{ | { | ||||
channel.PermissionOverwrites.Where(x => x.TargetType != idType || x.TargetId != userOrRoleId).ToArray(); | |||||
channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != userOrRoleId).ToArray(); | |||||
if (idType == PermissionTarget.Role) | |||||
if (targetType == PermissionTarget.Role) | |||||
channel.InvalidatePermissionsCache(); | channel.InvalidatePermissionsCache(); | ||||
else if (idType == PermissionTarget.Member) | |||||
else if (targetType == PermissionTarget.Member) | |||||
channel.InvalidatePermissionsCache(userOrRoleId); | channel.InvalidatePermissionsCache(userOrRoleId); | ||||
} | } | ||||
} | } | ||||
@@ -63,13 +63,20 @@ namespace Discord | |||||
private readonly Roles _roles; | private readonly Roles _roles; | ||||
/// <summary> Returns the role with the specified id, or null if none was found. </summary> | /// <summary> Returns the role with the specified id, or null if none was found. </summary> | ||||
public Role GetRole(string id) => _roles[id]; | |||||
public Role GetRole(string id) | |||||
{ | |||||
if (id == null) throw new ArgumentNullException(nameof(id)); | |||||
CheckReady(); | |||||
return _roles[id]; | |||||
} | |||||
/// <summary> Returns all roles with the specified server and name. </summary> | /// <summary> Returns all roles with the specified server and name. </summary> | ||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks> | /// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks> | ||||
public IEnumerable<Role> FindRoles(Server server, string name) | public IEnumerable<Role> FindRoles(Server server, string name) | ||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
if (name == null) throw new ArgumentNullException(nameof(name)); | if (name == null) throw new ArgumentNullException(nameof(name)); | ||||
CheckReady(); | |||||
if (name.StartsWith("@")) | if (name.StartsWith("@")) | ||||
{ | { | ||||
@@ -83,18 +90,16 @@ namespace Discord | |||||
string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); | 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> | /// <summary> Note: due to current API limitations, the created role cannot be returned. </summary> | ||||
public async Task<Role> CreateRole(string serverId, string name) | |||||
public async Task<Role> CreateRole(Server server, string name) | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
if (name == null) throw new ArgumentNullException(nameof(name)); | |||||
CheckReady(); | CheckReady(); | ||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||||
var response = await _api.CreateRole(serverId).ConfigureAwait(false); | |||||
var role = _roles.GetOrAdd(response.Id, serverId); | |||||
var response = await _api.CreateRole(server.Id).ConfigureAwait(false); | |||||
var role = _roles.GetOrAdd(response.Id, server.Id); | |||||
role.Update(response); | role.Update(response); | ||||
await EditRole(role, name: name); | await EditRole(role, name: name); | ||||
@@ -98,48 +98,43 @@ namespace Discord | |||||
public IEnumerable<Server> FindServers(string name) | public IEnumerable<Server> FindServers(string name) | ||||
{ | { | ||||
if (name == null) throw new ArgumentNullException(nameof(name)); | if (name == null) throw new ArgumentNullException(nameof(name)); | ||||
CheckReady(); | |||||
return _servers.Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); | 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> | /// <summary> Creates a new server with the provided name and region (see Regions). </summary> | ||||
public async Task<Server> CreateServer(string name, string region) | |||||
public async Task<Server> CreateServer(string name, Region region) | |||||
{ | { | ||||
CheckReady(); | |||||
if (name == null) throw new ArgumentNullException(nameof(name)); | if (name == null) throw new ArgumentNullException(nameof(name)); | ||||
if (region == null) throw new ArgumentNullException(nameof(region)); | |||||
if (region == (string)null) throw new ArgumentNullException(nameof(region)); | |||||
CheckReady(); | |||||
var response = await _api.CreateServer(name, region).ConfigureAwait(false); | |||||
var response = await _api.CreateServer(name, region.Value).ConfigureAwait(false); | |||||
var server = _servers.GetOrAdd(response.Id); | var server = _servers.GetOrAdd(response.Id); | ||||
server.Update(response); | server.Update(response); | ||||
return server; | 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> | /// <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) | |||||
public async Task EditServer(Server server, string name = null, Region region = null, ImageType iconType = ImageType.Png, byte[] icon = null) | |||||
{ | { | ||||
CheckReady(); | |||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
CheckReady(); | |||||
var response = await _api.EditServer(server.Id, name: name ?? server.Name, region: region, iconType: iconType, icon: icon); | |||||
var response = await _api.EditServer(server.Id, name: name ?? server.Name, region: region.Value, iconType: iconType, icon: icon); | |||||
server.Update(response); | server.Update(response); | ||||
} | } | ||||
/// <summary> Leaves the provided server, destroying it if you are the owner. </summary> | /// <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) | |||||
public async Task<Server> LeaveServer(Server server) | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
CheckReady(); | CheckReady(); | ||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||||
try { await _api.LeaveServer(serverId).ConfigureAwait(false); } | |||||
try { await _api.LeaveServer(server.Id).ConfigureAwait(false); } | |||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | ||||
return _servers.TryRemove(serverId); | |||||
return _servers.TryRemove(server.Id); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -62,14 +62,18 @@ namespace Discord | |||||
ImageType avatarType = ImageType.Png, byte[] avatar = null) | ImageType avatarType = ImageType.Png, byte[] avatar = null) | ||||
{ | { | ||||
if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword)); | if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword)); | ||||
CheckReady(); | |||||
return _api.EditUser(currentPassword: currentPassword, | return _api.EditUser(currentPassword: currentPassword, | ||||
username: username ?? _currentUser?.Name, email: email ?? _currentUser?.GlobalUser.Email, password: password, | username: username ?? _currentUser?.Name, email: email ?? _currentUser?.GlobalUser.Email, password: password, | ||||
avatarType: avatarType, avatar: avatar); | avatarType: avatarType, avatar: avatar); | ||||
} | } | ||||
public Task SetStatus(string status) | |||||
public Task SetStatus(UserStatus status) | |||||
{ | { | ||||
if (status == (string)null) throw new ArgumentNullException(nameof(status)); | |||||
CheckReady(); | |||||
if (status != UserStatus.Online && status != UserStatus.Idle) | if (status != UserStatus.Online && status != UserStatus.Idle) | ||||
throw new ArgumentException($"Invalid status, must be {UserStatus.Online} or {UserStatus.Idle}"); | throw new ArgumentException($"Invalid status, must be {UserStatus.Online} or {UserStatus.Idle}"); | ||||
_status = status; | _status = status; | ||||
@@ -77,6 +81,8 @@ namespace Discord | |||||
} | } | ||||
public Task SetGame(int? gameId) | public Task SetGame(int? gameId) | ||||
{ | { | ||||
CheckReady(); | |||||
_gameId = gameId; | _gameId = gameId; | ||||
return SendStatus(); | return SendStatus(); | ||||
} | } | ||||
@@ -19,7 +19,7 @@ namespace Discord | |||||
private readonly ConcurrentDictionary<string, DiscordWSClient> _voiceClients; | private readonly ConcurrentDictionary<string, DiscordWSClient> _voiceClients; | ||||
private bool _sentInitialLog; | private bool _sentInitialLog; | ||||
private uint _nextVoiceClientId; | private uint _nextVoiceClientId; | ||||
private string _status; | |||||
private UserStatus _status; | |||||
private int? _gameId; | private int? _gameId; | ||||
public new DiscordClientConfig Config => _config as DiscordClientConfig; | public new DiscordClientConfig Config => _config as DiscordClientConfig; | ||||
@@ -11,12 +11,12 @@ namespace Discord | |||||
{ | { | ||||
public sealed class PermissionOverwrite | public sealed class PermissionOverwrite | ||||
{ | { | ||||
public string TargetType { get; } | |||||
public PermissionTarget TargetType { get; } | |||||
public string TargetId { get; } | public string TargetId { get; } | ||||
public ChannelPermissions Allow { get; } | public ChannelPermissions Allow { get; } | ||||
public ChannelPermissions Deny { get; } | public ChannelPermissions Deny { get; } | ||||
internal PermissionOverwrite(string targetType, string targetId, uint allow, uint deny) | |||||
internal PermissionOverwrite(PermissionTarget targetType, string targetId, uint allow, uint deny) | |||||
{ | { | ||||
TargetType = targetType; | TargetType = targetType; | ||||
TargetId = targetId; | TargetId = targetId; | ||||
@@ -138,7 +138,7 @@ namespace Discord | |||||
if (model.PermissionOverwrites != null) | if (model.PermissionOverwrites != null) | ||||
{ | { | ||||
_permissionOverwrites = model.PermissionOverwrites | _permissionOverwrites = model.PermissionOverwrites | ||||
.Select(x => new PermissionOverwrite(x.Type, x.Id, x.Allow, x.Deny)) | |||||
.Select(x => new PermissionOverwrite(PermissionTarget.FromString(x.Type), x.Id, x.Allow, x.Deny)) | |||||
.ToArray(); | .ToArray(); | ||||
InvalidatePermissionsCache(); | InvalidatePermissionsCache(); | ||||
} | } | ||||
@@ -62,8 +62,8 @@ namespace Discord | |||||
public static ChannelPermissions All(string channelType, bool isPrivate) | public static ChannelPermissions All(string channelType, bool isPrivate) | ||||
{ | { | ||||
if (isPrivate) return PrivateOnly; | if (isPrivate) return PrivateOnly; | ||||
else if (channelType == ChannelTypes.Text) return TextOnly; | |||||
else if (channelType == ChannelTypes.Voice) return VoiceOnly; | |||||
else if (channelType == ChannelType.Text) return TextOnly; | |||||
else if (channelType == ChannelType.Voice) return VoiceOnly; | |||||
else return None; | else return None; | ||||
} | } | ||||
@@ -8,7 +8,6 @@ namespace Discord | |||||
public sealed class Role : CachedObject | public sealed class Role : CachedObject | ||||
{ | { | ||||
private readonly string _serverId; | private readonly string _serverId; | ||||
private Server _server; | |||||
/// <summary> Returns the name of this role. </summary> | /// <summary> Returns the name of this role. </summary> | ||||
public string Name { get; private set; } | public string Name { get; private set; } | ||||
@@ -26,7 +25,7 @@ namespace Discord | |||||
/// <summary> Returns the server this role is a member of. </summary> | /// <summary> Returns the server this role is a member of. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public Server Server => _server; | |||||
public Server Server { get; private set; } | |||||
/// <summary> Returns true if this is the role representing all users in a server. </summary> | /// <summary> Returns true if this is the role representing all users in a server. </summary> | ||||
public bool IsEveryone => Id == _serverId; | public bool IsEveryone => Id == _serverId; | ||||
@@ -48,14 +47,16 @@ namespace Discord | |||||
} | } | ||||
internal override void OnCached() | internal override void OnCached() | ||||
{ | { | ||||
_server = _client.Servers[_serverId]; | |||||
_server.AddRole(this); | |||||
var server = _client.Servers[_serverId]; | |||||
server.AddRole(this); | |||||
Server = server; | |||||
} | } | ||||
internal override void OnUncached() | internal override void OnUncached() | ||||
{ | { | ||||
if (_server != null) | |||||
_server.RemoveRole(this); | |||||
_server = null; | |||||
var server = Server; | |||||
if (server != null) | |||||
server.RemoveRole(this); | |||||
Server = null; | |||||
} | } | ||||
internal void Update(RoleInfo model) | internal void Update(RoleInfo model) | ||||
@@ -60,10 +60,10 @@ namespace Discord | |||||
public IEnumerable<Channel> Channels => _channels.Select(x => _client.Channels[x.Key]); | public IEnumerable<Channel> Channels => _channels.Select(x => _client.Channels[x.Key]); | ||||
/// <summary> Returns a collection of all channels within this server. </summary> | /// <summary> Returns a collection of all channels within this server. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Channel> TextChannels => _channels.Select(x => _client.Channels[x.Key]).Where(x => x.Type == ChannelTypes.Text); | |||||
public IEnumerable<Channel> TextChannels => _channels.Select(x => _client.Channels[x.Key]).Where(x => x.Type == ChannelType.Text); | |||||
/// <summary> Returns a collection of all channels within this server. </summary> | /// <summary> Returns a collection of all channels within this server. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Channel> VoiceChannels => _channels.Select(x => _client.Channels[x.Key]).Where(x => x.Type == ChannelTypes.Voice); | |||||
public IEnumerable<Channel> VoiceChannels => _channels.Select(x => _client.Channels[x.Key]).Where(x => x.Type == ChannelType.Voice); | |||||
/// <summary> Returns a collection of all invites to this server. </summary> | /// <summary> Returns a collection of all invites to this server. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
@@ -40,7 +40,7 @@ namespace Discord | |||||
/// <summary> Returns the id for the game this user is currently playing. </summary> | /// <summary> Returns the id for the game this user is currently playing. </summary> | ||||
public string GameId { get; private set; } | public string GameId { get; private set; } | ||||
/// <summary> Returns the current status for this user. </summary> | /// <summary> Returns the current status for this user. </summary> | ||||
public string Status { get; private set; } | |||||
public UserStatus Status { get; private set; } | |||||
/// <summary> Returns the time this user last sent/edited a message, started typing or sent voice data in this server. </summary> | /// <summary> Returns the time this user last sent/edited a message, started typing or sent voice data in this server. </summary> | ||||
public DateTime? LastActivityAt { get; private set; } | public DateTime? LastActivityAt { get; private set; } | ||||
/// <summary> Returns the time this user was last seen online in this server. </summary> | /// <summary> Returns the time this user was last seen online in this server. </summary> | ||||
@@ -152,7 +152,7 @@ namespace Discord | |||||
UpdateRoles(model.Roles); | UpdateRoles(model.Roles); | ||||
if (model.Status != null && Status != model.Status) | if (model.Status != null && Status != model.Status) | ||||
{ | { | ||||
Status = model.Status; | |||||
Status = UserStatus.FromString(model.Status); | |||||
if (Status == UserStatus.Offline) | if (Status == UserStatus.Offline) | ||||
_lastOnline = DateTime.UtcNow; | _lastOnline = DateTime.UtcNow; | ||||
} | } | ||||
@@ -19,11 +19,14 @@ namespace Discord.Net.Rest | |||||
_client = new RestSharp.RestClient(Endpoints.BaseApi) | _client = new RestSharp.RestClient(Endpoints.BaseApi) | ||||
{ | { | ||||
PreAuthenticate = false, | PreAuthenticate = false, | ||||
Proxy = new WebProxy(_config.ProxyUrl, true, new string[0], _config.ProxyCredentials), | |||||
ReadWriteTimeout = _config.APITimeout, | ReadWriteTimeout = _config.APITimeout, | ||||
UserAgent = _config.UserAgent | UserAgent = _config.UserAgent | ||||
}; | }; | ||||
_client.RemoveDefaultParameter("Accept"); | |||||
if (_config.ProxyUrl != null) | |||||
_client.Proxy = new WebProxy(_config.ProxyUrl, true, new string[0], _config.ProxyCredentials); | |||||
else | |||||
_client.Proxy = null; | |||||
_client.RemoveDefaultParameter("Accept"); | |||||
_client.AddDefaultHeader("accept", "*/*"); | _client.AddDefaultHeader("accept", "*/*"); | ||||
_client.AddDefaultHeader("accept-encoding", "gzip,deflate"); | _client.AddDefaultHeader("accept-encoding", "gzip,deflate"); | ||||
} | } | ||||
@@ -38,7 +38,7 @@ namespace Discord.Tests | |||||
_observerBot.AllServers.Select(x => _observerBot.LeaveServer(x))); | _observerBot.AllServers.Select(x => _observerBot.LeaveServer(x))); | ||||
//Create new server and invite the other bots to it | //Create new server and invite the other bots to it | ||||
_testServer = _hostClient.CreateServer("Discord.Net Testing", Regions.US_East).Result; | |||||
_testServer = _hostClient.CreateServer("Discord.Net Testing", Region.USEast).Result; | |||||
_testServerChannel = _testServer.DefaultChannel; | _testServerChannel = _testServer.DefaultChannel; | ||||
Invite invite = _hostClient.CreateInvite(_testServer, 60, 1, false, false).Result; | Invite invite = _hostClient.CreateInvite(_testServer, 60, 1, false, false).Result; | ||||
WaitAll( | WaitAll( | ||||
@@ -49,11 +49,11 @@ namespace Discord.Tests | |||||
//Channels | //Channels | ||||
[TestMethod] | [TestMethod] | ||||
public void TestCreateTextChannel() | public void TestCreateTextChannel() | ||||
=> TestCreateChannel(ChannelTypes.Text); | |||||
=> TestCreateChannel(ChannelType.Text); | |||||
[TestMethod] | [TestMethod] | ||||
public void TestCreateVoiceChannel() | public void TestCreateVoiceChannel() | ||||
=> TestCreateChannel(ChannelTypes.Voice); | |||||
private void TestCreateChannel(string type) | |||||
=> TestCreateChannel(ChannelType.Voice); | |||||
private void TestCreateChannel(ChannelType type) | |||||
{ | { | ||||
Channel channel = null; | Channel channel = null; | ||||
string name = $"#test_{_random.Next()}"; | string name = $"#test_{_random.Next()}"; | ||||
@@ -76,21 +76,21 @@ namespace Discord.Tests | |||||
[ExpectedException(typeof(InvalidOperationException))] | [ExpectedException(typeof(InvalidOperationException))] | ||||
public async Task TestCreateChannel_NoName() | public async Task TestCreateChannel_NoName() | ||||
{ | { | ||||
await _hostClient.CreateChannel(_testServer, $"", ChannelTypes.Text); | |||||
await _hostClient.CreateChannel(_testServer, $"", ChannelType.Text); | |||||
} | } | ||||
[TestMethod] | [TestMethod] | ||||
[ExpectedException(typeof(InvalidOperationException))] | [ExpectedException(typeof(InvalidOperationException))] | ||||
public async Task TestCreateChannel_NoType() | public async Task TestCreateChannel_NoType() | ||||
{ | { | ||||
string name = $"#test_{_random.Next()}"; | string name = $"#test_{_random.Next()}"; | ||||
await _hostClient.CreateChannel(_testServer, $"", ""); | |||||
await _hostClient.CreateChannel(_testServer, $"", ChannelType.FromString("")); | |||||
} | } | ||||
[TestMethod] | [TestMethod] | ||||
[ExpectedException(typeof(InvalidOperationException))] | [ExpectedException(typeof(InvalidOperationException))] | ||||
public async Task TestCreateChannel_BadType() | public async Task TestCreateChannel_BadType() | ||||
{ | { | ||||
string name = $"#test_{_random.Next()}"; | string name = $"#test_{_random.Next()}"; | ||||
await _hostClient.CreateChannel(_testServer, $"", "badtype"); | |||||
await _hostClient.CreateChannel(_testServer, $"", ChannelType.FromString("badtype")); | |||||
} | } | ||||
//Messages | //Messages | ||||