| @@ -82,8 +82,8 @@ | |||
| <Compile Include="..\Discord.Net\API\Enums\AvatarImageType.cs"> | |||
| <Link>API\Enums\AvatarImageType.cs</Link> | |||
| </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 Include="..\Discord.Net\API\Enums\PermissionTarget.cs"> | |||
| <Link>API\Enums\PermissionTarget.cs</Link> | |||
| @@ -91,6 +91,9 @@ | |||
| <Compile Include="..\Discord.Net\API\Enums\Regions.cs"> | |||
| <Link>API\Enums\Regions.cs</Link> | |||
| </Compile> | |||
| <Compile Include="..\Discord.Net\API\Enums\StringEnum.cs"> | |||
| <Link>API\Enums\StringEnum.cs</Link> | |||
| </Compile> | |||
| <Compile Include="..\Discord.Net\API\Enums\UserStatus.cs"> | |||
| <Link>API\Enums\UserStatus.cs</Link> | |||
| </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 | |||
| { | |||
| 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 | |||
| { | |||
| 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 | |||
| { | |||
| public static class UserStatus | |||
| public class UserStatus : StringEnum | |||
| { | |||
| /// <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> | |||
| public const string Idle = "idle"; | |||
| public static readonly UserStatus Idle = new UserStatus("idle"); | |||
| /// <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> | |||
| public Task Ban(Member member) | |||
| { | |||
| CheckReady(); | |||
| if (member == null) throw new ArgumentNullException(nameof(member)); | |||
| CheckReady(); | |||
| return _api.Ban(member.ServerId, member.Id); | |||
| } | |||
| @@ -44,8 +44,8 @@ namespace Discord | |||
| /// <summary> Unbans a user from the provided server. </summary> | |||
| public async Task Unban(Member member) | |||
| { | |||
| CheckReady(); | |||
| if (member == null) throw new ArgumentNullException(nameof(member)); | |||
| CheckReady(); | |||
| try { await _api.Unban(member.ServerId, member.Id).ConfigureAwait(false); } | |||
| 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> | |||
| /// <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)); | |||
| @@ -74,21 +74,21 @@ namespace Discord | |||
| string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); | |||
| } | |||
| if (type != null) | |||
| if (type != (string)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 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 (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(); | |||
| 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); | |||
| channel.Update(response); | |||
| return channel; | |||
| @@ -153,15 +153,16 @@ namespace Discord | |||
| { | |||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||
| if (channels == null) throw new ArgumentNullException(nameof(channels)); | |||
| CheckReady(); | |||
| return _api.ReorderChannels(server.Id, channels.Select(x => x.Id), after.Position); | |||
| } | |||
| /// <summary> Destroys the provided channel. </summary> | |||
| public async Task<Channel> DestroyChannel(Channel channel) | |||
| { | |||
| CheckReady(); | |||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||
| CheckReady(); | |||
| try { await _api.DestroyChannel(channel.Id).ConfigureAwait(false); } | |||
| 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> | |||
| public async Task<Invite> GetInvite(string inviteIdOrXkcd) | |||
| { | |||
| CheckReady(); | |||
| if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); | |||
| CheckReady(); | |||
| //Remove trailing slash | |||
| 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) | |||
| { | |||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||
| CheckReady(); | |||
| return CreateInvite(server.DefaultChannel, maxAge, maxUses, tempMembership, hasXkcd); | |||
| } | |||
| /// <summary> Creates a new invite to the provided channel. </summary> | |||
| @@ -59,8 +61,8 @@ namespace Discord | |||
| /// <summary> Deletes the provided invite. </summary> | |||
| public async Task DestroyInvite(Invite invite) | |||
| { | |||
| CheckReady(); | |||
| if (invite == null) throw new ArgumentNullException(nameof(invite)); | |||
| CheckReady(); | |||
| try { await _api.DeleteInvite(invite.Id).ConfigureAwait(false); } | |||
| catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
| @@ -69,8 +71,8 @@ namespace Discord | |||
| /// <summary> Accepts the provided invite. </summary> | |||
| public Task AcceptInvite(Invite invite) | |||
| { | |||
| CheckReady(); | |||
| if (invite == null) throw new ArgumentNullException(nameof(invite)); | |||
| CheckReady(); | |||
| return _api.AcceptInvite(invite.Id); | |||
| } | |||
| @@ -190,7 +190,7 @@ namespace Discord | |||
| CheckReady(); | |||
| if (count == 0) return new Message[0]; | |||
| if (channel != null && channel.Type == ChannelTypes.Text) | |||
| if (channel != null && channel.Type == ChannelType.Text) | |||
| { | |||
| try | |||
| { | |||
| @@ -8,20 +8,39 @@ namespace Discord | |||
| public partial class DiscordClient | |||
| { | |||
| 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) | |||
| => 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) | |||
| => 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(); | |||
| 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 (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 denyValue = deny?.RawValue ?? 0; | |||
| bool changed = false; | |||
| @@ -29,7 +48,7 @@ namespace Discord | |||
| 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); | |||
| await _api.SetChannelPermissions(channel.Id, targetId, targetType.Value, allowValue, denyValue); | |||
| if (perms != null) | |||
| { | |||
| perms.Allow.SetRawValueInternal(allowValue); | |||
| @@ -84,19 +103,19 @@ namespace Discord | |||
| 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 | |||
| { | |||
| 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); | |||
| 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(); | |||
| else if (idType == PermissionTarget.Member) | |||
| else if (targetType == PermissionTarget.Member) | |||
| channel.InvalidatePermissionsCache(userOrRoleId); | |||
| } | |||
| } | |||
| @@ -63,13 +63,20 @@ namespace Discord | |||
| 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]; | |||
| 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> | |||
| /// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks> | |||
| public IEnumerable<Role> FindRoles(Server server, string name) | |||
| { | |||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||
| if (name == null) throw new ArgumentNullException(nameof(name)); | |||
| CheckReady(); | |||
| if (name.StartsWith("@")) | |||
| { | |||
| @@ -83,18 +90,16 @@ namespace Discord | |||
| 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) | |||
| 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(); | |||
| 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); | |||
| await EditRole(role, name: name); | |||
| @@ -98,48 +98,43 @@ namespace Discord | |||
| public IEnumerable<Server> FindServers(string name) | |||
| { | |||
| if (name == null) throw new ArgumentNullException(nameof(name)); | |||
| CheckReady(); | |||
| 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) | |||
| public async Task<Server> CreateServer(string name, Region region) | |||
| { | |||
| CheckReady(); | |||
| 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); | |||
| 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) | |||
| 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)); | |||
| 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); | |||
| } | |||
| /// <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(); | |||
| 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) { } | |||
| return _servers.TryRemove(serverId); | |||
| return _servers.TryRemove(server.Id); | |||
| } | |||
| } | |||
| } | |||
| @@ -62,14 +62,18 @@ namespace Discord | |||
| ImageType avatarType = ImageType.Png, byte[] avatar = null) | |||
| { | |||
| if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword)); | |||
| CheckReady(); | |||
| return _api.EditUser(currentPassword: currentPassword, | |||
| username: username ?? _currentUser?.Name, email: email ?? _currentUser?.GlobalUser.Email, password: password, | |||
| 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) | |||
| throw new ArgumentException($"Invalid status, must be {UserStatus.Online} or {UserStatus.Idle}"); | |||
| _status = status; | |||
| @@ -77,6 +81,8 @@ namespace Discord | |||
| } | |||
| public Task SetGame(int? gameId) | |||
| { | |||
| CheckReady(); | |||
| _gameId = gameId; | |||
| return SendStatus(); | |||
| } | |||
| @@ -19,7 +19,7 @@ namespace Discord | |||
| private readonly ConcurrentDictionary<string, DiscordWSClient> _voiceClients; | |||
| private bool _sentInitialLog; | |||
| private uint _nextVoiceClientId; | |||
| private string _status; | |||
| private UserStatus _status; | |||
| private int? _gameId; | |||
| public new DiscordClientConfig Config => _config as DiscordClientConfig; | |||
| @@ -11,12 +11,12 @@ namespace Discord | |||
| { | |||
| public sealed class PermissionOverwrite | |||
| { | |||
| public string TargetType { get; } | |||
| public PermissionTarget TargetType { get; } | |||
| public string TargetId { get; } | |||
| public ChannelPermissions Allow { 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; | |||
| TargetId = targetId; | |||
| @@ -138,7 +138,7 @@ namespace Discord | |||
| if (model.PermissionOverwrites != null) | |||
| { | |||
| _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(); | |||
| InvalidatePermissionsCache(); | |||
| } | |||
| @@ -62,8 +62,8 @@ namespace Discord | |||
| public static ChannelPermissions All(string channelType, bool isPrivate) | |||
| { | |||
| 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; | |||
| } | |||
| @@ -8,7 +8,6 @@ namespace Discord | |||
| public sealed class Role : CachedObject | |||
| { | |||
| private readonly string _serverId; | |||
| private Server _server; | |||
| /// <summary> Returns the name of this role. </summary> | |||
| public string Name { get; private set; } | |||
| @@ -26,7 +25,7 @@ namespace Discord | |||
| /// <summary> Returns the server this role is a member of. </summary> | |||
| [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> | |||
| public bool IsEveryone => Id == _serverId; | |||
| @@ -48,14 +47,16 @@ namespace Discord | |||
| } | |||
| 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() | |||
| { | |||
| if (_server != null) | |||
| _server.RemoveRole(this); | |||
| _server = null; | |||
| var server = Server; | |||
| if (server != null) | |||
| server.RemoveRole(this); | |||
| Server = null; | |||
| } | |||
| internal void Update(RoleInfo model) | |||
| @@ -60,10 +60,10 @@ namespace Discord | |||
| public IEnumerable<Channel> Channels => _channels.Select(x => _client.Channels[x.Key]); | |||
| /// <summary> Returns a collection of all channels within this server. </summary> | |||
| [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> | |||
| [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> | |||
| [JsonIgnore] | |||
| @@ -40,7 +40,7 @@ namespace Discord | |||
| /// <summary> Returns the id for the game this user is currently playing. </summary> | |||
| public string GameId { get; private set; } | |||
| /// <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> | |||
| public DateTime? LastActivityAt { get; private set; } | |||
| /// <summary> Returns the time this user was last seen online in this server. </summary> | |||
| @@ -152,7 +152,7 @@ namespace Discord | |||
| UpdateRoles(model.Roles); | |||
| if (model.Status != null && Status != model.Status) | |||
| { | |||
| Status = model.Status; | |||
| Status = UserStatus.FromString(model.Status); | |||
| if (Status == UserStatus.Offline) | |||
| _lastOnline = DateTime.UtcNow; | |||
| } | |||
| @@ -19,11 +19,14 @@ namespace Discord.Net.Rest | |||
| _client = new RestSharp.RestClient(Endpoints.BaseApi) | |||
| { | |||
| PreAuthenticate = false, | |||
| Proxy = new WebProxy(_config.ProxyUrl, true, new string[0], _config.ProxyCredentials), | |||
| ReadWriteTimeout = _config.APITimeout, | |||
| 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-encoding", "gzip,deflate"); | |||
| } | |||
| @@ -38,7 +38,7 @@ namespace Discord.Tests | |||
| _observerBot.AllServers.Select(x => _observerBot.LeaveServer(x))); | |||
| //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; | |||
| Invite invite = _hostClient.CreateInvite(_testServer, 60, 1, false, false).Result; | |||
| WaitAll( | |||
| @@ -49,11 +49,11 @@ namespace Discord.Tests | |||
| //Channels | |||
| [TestMethod] | |||
| public void TestCreateTextChannel() | |||
| => TestCreateChannel(ChannelTypes.Text); | |||
| => TestCreateChannel(ChannelType.Text); | |||
| [TestMethod] | |||
| public void TestCreateVoiceChannel() | |||
| => TestCreateChannel(ChannelTypes.Voice); | |||
| private void TestCreateChannel(string type) | |||
| => TestCreateChannel(ChannelType.Voice); | |||
| private void TestCreateChannel(ChannelType type) | |||
| { | |||
| Channel channel = null; | |||
| string name = $"#test_{_random.Next()}"; | |||
| @@ -76,21 +76,21 @@ namespace Discord.Tests | |||
| [ExpectedException(typeof(InvalidOperationException))] | |||
| public async Task TestCreateChannel_NoName() | |||
| { | |||
| await _hostClient.CreateChannel(_testServer, $"", ChannelTypes.Text); | |||
| await _hostClient.CreateChannel(_testServer, $"", ChannelType.Text); | |||
| } | |||
| [TestMethod] | |||
| [ExpectedException(typeof(InvalidOperationException))] | |||
| public async Task TestCreateChannel_NoType() | |||
| { | |||
| string name = $"#test_{_random.Next()}"; | |||
| await _hostClient.CreateChannel(_testServer, $"", ""); | |||
| await _hostClient.CreateChannel(_testServer, $"", ChannelType.FromString("")); | |||
| } | |||
| [TestMethod] | |||
| [ExpectedException(typeof(InvalidOperationException))] | |||
| public async Task TestCreateChannel_BadType() | |||
| { | |||
| string name = $"#test_{_random.Next()}"; | |||
| await _hostClient.CreateChannel(_testServer, $"", "badtype"); | |||
| await _hostClient.CreateChannel(_testServer, $"", ChannelType.FromString("badtype")); | |||
| } | |||
| //Messages | |||