diff --git a/src/Discord.Net/API/Rest/CreateGuildChannel.cs b/src/Discord.Net/API/Rest/CreateGuildChannel.cs index 839f3cc1d..73791825f 100644 --- a/src/Discord.Net/API/Rest/CreateGuildChannel.cs +++ b/src/Discord.Net/API/Rest/CreateGuildChannel.cs @@ -4,7 +4,7 @@ using Newtonsoft.Json; namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class CreateChannelRequest : IRestRequest + public class CreateGuildChannelRequest : IRestRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"guilds/{GuildId}/channels"; @@ -19,7 +19,7 @@ namespace Discord.API.Rest [JsonProperty("bitrate")] public int Bitrate { get; set; } - public CreateChannelRequest(ulong guildId) + public CreateGuildChannelRequest(ulong guildId) { GuildId = guildId; } diff --git a/src/Discord.Net/API/Rest/CreateGuildRole.cs b/src/Discord.Net/API/Rest/CreateGuildRole.cs index 0d21805d8..367c25465 100644 --- a/src/Discord.Net/API/Rest/CreateGuildRole.cs +++ b/src/Discord.Net/API/Rest/CreateGuildRole.cs @@ -2,7 +2,7 @@ namespace Discord.API.Rest { - public class CreateRoleRequest : IRestRequest + public class CreateGuildRoleRequest : IRestRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"guilds/{GuildId}/roles"; @@ -10,7 +10,7 @@ namespace Discord.API.Rest public ulong GuildId { get; } - public CreateRoleRequest(ulong guildId) + public CreateGuildRoleRequest(ulong guildId) { GuildId = guildId; } diff --git a/src/Discord.Net/API/Rest/ModifyGuild.cs b/src/Discord.Net/API/Rest/ModifyGuild.cs index 1405a8144..03bf58073 100644 --- a/src/Discord.Net/API/Rest/ModifyGuild.cs +++ b/src/Discord.Net/API/Rest/ModifyGuild.cs @@ -27,7 +27,7 @@ namespace Discord.API.Rest [JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] public Stream Icon { get; set; } [JsonProperty("owner_id")] - public GuildPresence Owner { get; set; } + public GuildMember Owner { get; set; } [JsonProperty("splash"), JsonConverter(typeof(ImageConverter))] public Stream Splash { get; set; } diff --git a/src/Discord.Net/API/Rest/ModifyGuildMember.cs b/src/Discord.Net/API/Rest/ModifyGuildMember.cs index 07a662645..cdbc1271f 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildMember.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildMember.cs @@ -4,7 +4,7 @@ using Newtonsoft.Json; namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class UpdateMemberRequest : IRestRequest + public class ModifyGuildMemberRequest : IRestRequest { string IRestRequest.Method => "PATCH"; string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; @@ -22,7 +22,7 @@ namespace Discord.API.Rest [JsonProperty("channel_id")] public ulong? ChannelId { get; set; } - public UpdateMemberRequest(ulong guildId, ulong userId) + public ModifyGuildMemberRequest(ulong guildId, ulong userId) { GuildId = guildId; UserId = userId; diff --git a/src/Discord.Net/API/Rest/ModifyMessage.cs b/src/Discord.Net/API/Rest/ModifyMessage.cs index 0c99403a6..971c8026e 100644 --- a/src/Discord.Net/API/Rest/ModifyMessage.cs +++ b/src/Discord.Net/API/Rest/ModifyMessage.cs @@ -4,7 +4,7 @@ using Newtonsoft.Json; namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class UpdateMessageRequest : IRestRequest + public class ModifyMessageRequest : IRestRequest { string IRestRequest.Method => "PATCH"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}"; @@ -16,7 +16,7 @@ namespace Discord.API.Rest [JsonProperty("content")] public string Content { get; set; } = ""; - public UpdateMessageRequest(ulong channelId, ulong messageId) + public ModifyMessageRequest(ulong channelId, ulong messageId) { ChannelId = channelId; MessageId = messageId; diff --git a/src/Discord.Net/Discord.Net.Net45.csproj b/src/Discord.Net/Discord.Net.Net45.csproj index f5d12fb3f..20f2dcee0 100644 --- a/src/Discord.Net/Discord.Net.Net45.csproj +++ b/src/Discord.Net/Discord.Net.Net45.csproj @@ -212,15 +212,13 @@ - - - - + - + + + - diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index d59f7fec1..2409a76d2 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -49,7 +49,7 @@ namespace Discord _connectionLock = new SemaphoreSlim(1, 1); _restClientProvider = config.RestClientProvider; - UserAgent = GetUserAgent(config.AppName, config.AppVersion, config.AppUrl); + UserAgent = $"DiscordBot ({DiscordConfig.LibUrl}, v{DiscordConfig.LibVersion})"; _logManager = new LogManager(config.LogLevel); _logManager.Message += (s, e) => Log(this, e); @@ -165,18 +165,18 @@ namespace Discord result[i] = CreateGuild(response[i]); return result.ToImmutable(); } - public virtual async Task GetUser(ulong id) + public virtual async Task GetUser(ulong id) { var response = await RestClient.Send(new GetUserRequest(id)); - var user = CreatePublicUser(response); + var user = CreateGlobalUser(response); return user; } - public virtual async Task GetUser(string username, ushort discriminator) + public virtual async Task GetUser(string username, ushort discriminator) { var response = await RestClient.Send(new QueryUserRequest() { Query = $"{username}#{discriminator}", Limit = 1 }); if (response.Length > 0) { - var user = CreatePublicUser(response[0]); + var user = CreateGlobalUser(response[0]); return user; } return null; @@ -265,7 +265,7 @@ namespace Discord guild.Update(model); return guild; } - internal virtual Message CreateMessage(IMessageChannel channel, User user, API.Message model) + internal virtual Message CreateMessage(IMessageChannel channel, IUser user, API.Message model) { var msg = new Message(model.Id, channel, user); msg.Update(model); @@ -277,33 +277,33 @@ namespace Discord role.Update(model); return role; } - internal virtual GuildUser CreateBannedUser(Guild guild, API.User model) + internal virtual DMUser CreateDMUser(DMChannel channel, API.User model) { - var user = new GuildUser(model.Id, guild, null, null); + var user = new DMUser(CreateGlobalUser(model), channel); user.Update(model); return user; } - internal virtual DMUser CreateDMUser(DMChannel channel, API.User model) + internal virtual GuildUser CreateGuildUser(Guild guild, API.GuildMember model) { - var user = new DMUser(model.Id, channel); + var user = new GuildUser(CreateGlobalUser(model.User), guild); user.Update(model); return user; } - internal virtual GuildUser CreateGuildUser(Guild guild, GuildPresence presence, VoiceState voiceState, API.GuildMember model) + internal virtual GuildUser CreateBannedUser(Guild guild, API.User model) { - var user = new GuildUser(model.User.Id, guild, presence, voiceState); - user.Update(model); + var user = new GuildUser(CreateGlobalUser(model), guild); + //user.Update(model); return user; } - internal virtual PublicUser CreatePublicUser(API.User model) + internal virtual SelfUser CreateSelfUser(API.User model) { - var user = new PublicUser(model.Id, this); + var user = new SelfUser(model.Id, this); user.Update(model); return user; } - internal virtual SelfUser CreateSelfUser(API.User model) + internal virtual GlobalUser CreateGlobalUser(API.User model) { - var user = new SelfUser(model.Id, this); + var user = new GlobalUser(model.Id, this); user.Update(model); return user; } @@ -314,6 +314,8 @@ namespace Discord return region; } + internal virtual void RemoveUser(GlobalUser user) { } + protected virtual void Dispose(bool disposing) { if (!_isDisposed) @@ -329,22 +331,6 @@ namespace Discord } public void Dispose() => Dispose(true); - private static string GetUserAgent(string appName, string appVersion, string appUrl) - { - var sb = new StringBuilder(); - if (!string.IsNullOrEmpty(appName)) - { - sb.Append(appName); - if (!string.IsNullOrEmpty(appVersion)) - sb.Append($"/{appVersion}"); - if (!string.IsNullOrEmpty(appUrl)) - sb.Append($" ({appUrl})"); - sb.Append(' '); - } - sb.Append($"DiscordBot ({DiscordConfig.LibUrl}, v{DiscordConfig.LibVersion})"); - return sb.ToString(); - } - protected void RaiseEvent(EventHandler eventHandler) => eventHandler?.Invoke(this, EventArgs.Empty); protected void RaiseEvent(EventHandler eventHandler, T eventArgs) where T : EventArgs diff --git a/src/Discord.Net/DiscordConfig.cs b/src/Discord.Net/DiscordConfig.cs index b23bc3204..8598b9f27 100644 --- a/src/Discord.Net/DiscordConfig.cs +++ b/src/Discord.Net/DiscordConfig.cs @@ -21,13 +21,6 @@ namespace Discord internal const int MessageQueueInterval = 100; internal const int WebSocketQueueInterval = 100; - /// Gets or sets name of your application, used in the user agent. - public string AppName { get; set; } = null; - /// Gets or sets url to your application, used in the user agent. - public string AppUrl { get; set; } = null; - /// Gets or sets the version of your application, used in the user agent. - public string AppVersion { get; set; } = null; - /// Gets or sets the minimum log level severity that will be sent to the LogMessage event. public LogSeverity LogLevel { get; set; } = LogSeverity.Info; diff --git a/src/Discord.Net/Entities/Channels/DMChannel.cs b/src/Discord.Net/Entities/Channels/DMChannel.cs index f8ce92dfa..c176b9dc0 100644 --- a/src/Discord.Net/Entities/Channels/DMChannel.cs +++ b/src/Discord.Net/Entities/Channels/DMChannel.cs @@ -22,11 +22,9 @@ namespace Discord /// public string Name => $"@{Recipient.Username}#{Recipient.Discriminator}"; /// - public IEnumerable Users => ImmutableArray.Create(Discord.CurrentUser, Recipient); + public IEnumerable Users => ImmutableArray.Create(Discord.CurrentUser, Recipient); /// ChannelType IChannel.Type => ChannelType.DM; - /// - IEnumerable IChannel.Users => Users; private readonly MessageManager _messages; @@ -45,7 +43,7 @@ namespace Discord } /// - public User GetUser(ulong id) + public IUser GetUser(ulong id) { if (id == Recipient.Id) return Recipient; diff --git a/src/Discord.Net/Entities/Channels/GuildChannel.cs b/src/Discord.Net/Entities/Channels/GuildChannel.cs index 862c91671..aea8c86c0 100644 --- a/src/Discord.Net/Entities/Channels/GuildChannel.cs +++ b/src/Discord.Net/Entities/Channels/GuildChannel.cs @@ -27,9 +27,9 @@ namespace Discord /// public DiscordClient Discord => Guild.Discord; /// Gets a collection of all users in this channel. - public IEnumerable Users => _permissions.GetUsers(); + public IEnumerable Users => _permissions.GetMembers(); /// - IEnumerable IChannel.Users => _permissions.GetUsers(); + IEnumerable IChannel.Users => _permissions.GetMembers(); /// Gets a collection of permission overwrites for this channel. public IEnumerable PermissionOverwrites => _permissions.Overwrites; @@ -50,13 +50,12 @@ namespace Discord } /// Gets a user in this channel with the given id. - public GuildUser GetUser(ulong id) - => _permissions.GetUser(id); + public GuildUser GetUser(ulong id) => _permissions.GetUser(id); /// - User IChannel.GetUser(ulong id) => GetUser(id); + IUser IChannel.GetUser(ulong id) => GetUser(id); /// Gets the permission overwrite for a specific user, or null if one does not exist. - public OverwritePermissions? GetPermissionOverwrite(GuildUser user) + public OverwritePermissions? GetPermissionOverwrite(IUser user) => _permissions.GetOverwrite(user); /// Gets the permission overwrite for a specific role, or null if one does not exist. public OverwritePermissions? GetPermissionOverwrite(Role role) @@ -74,23 +73,23 @@ namespace Discord } /// Adds or updates the permission overwrite for the given user. - public Task UpdatePermissionOverwrite(GuildUser user, OverwritePermissions permissions) + public Task UpdatePermissionOverwrite(IUser user, OverwritePermissions permissions) => _permissions.AddOrUpdateOverwrite(user, permissions); /// Adds or updates the permission overwrite for the given role. public Task UpdatePermissionOverwrite(Role role, OverwritePermissions permissions) => _permissions.AddOrUpdateOverwrite(role, permissions); /// Removes the permission overwrite for the given user, if one exists. - public Task RemovePermissionOverwrite(GuildUser user) + public Task RemovePermissionOverwrite(IUser user) => _permissions.RemoveOverwrite(user); /// Removes the permission overwrite for the given role, if one exists. public Task RemovePermissionOverwrite(Role role) => _permissions.RemoveOverwrite(role); - internal ChannelPermissions GetPermissions(GuildUser user) + internal ChannelPermissions GetPermissions(IUser user) => _permissions.GetPermissions(user); internal void UpdatePermissions() => _permissions.UpdatePermissions(); - internal void UpdatePermissions(GuildUser user) + internal void UpdatePermissions(IUser user) => _permissions.UpdatePermissions(user); /// Creates a new invite to this channel. diff --git a/src/Discord.Net/Entities/Channels/IChannel.cs b/src/Discord.Net/Entities/Channels/IChannel.cs index 046718f24..53dc60f18 100644 --- a/src/Discord.Net/Entities/Channels/IChannel.cs +++ b/src/Discord.Net/Entities/Channels/IChannel.cs @@ -9,9 +9,9 @@ namespace Discord /// Gets the name of this channel. string Name { get; } /// Gets a collection of all users in this channel. - IEnumerable Users { get; } + IEnumerable Users { get; } /// Gets a user in this channel with the given id. - User GetUser(ulong id); + IUser GetUser(ulong id); } } diff --git a/src/Discord.Net/Entities/Guild.cs b/src/Discord.Net/Entities/Guild.cs index 62172f47d..57ec95071 100644 --- a/src/Discord.Net/Entities/Guild.cs +++ b/src/Discord.Net/Entities/Guild.cs @@ -27,9 +27,9 @@ namespace Discord private ConcurrentDictionary _channels; private ConcurrentDictionary _members; - private ConcurrentDictionary _presences; + //private ConcurrentDictionary _presences; private ConcurrentDictionary _roles; - private ConcurrentDictionary _voiceStates; + //private ConcurrentDictionary _voiceStates; private ulong _ownerId; private ulong? _afkChannelId, _embedChannelId; private int _userCount; @@ -100,9 +100,9 @@ namespace Discord _channels = new ConcurrentDictionary(); _members = new ConcurrentDictionary(); - _presences = new ConcurrentDictionary(); + //_presences = new ConcurrentDictionary(); _roles = new ConcurrentDictionary(); - _voiceStates = new ConcurrentDictionary(); + //_voiceStates = new ConcurrentDictionary(); } internal void Update(Model model) @@ -207,7 +207,7 @@ namespace Discord public GuildUser GetUser(string mention) => GetUser(MentionHelper.GetUserId(mention)); private GuildUser GetUser(ulong? id) => id != null ? GetUser(id.Value) : null; - public async Task> GetBans() + public async Task> GetBans() { var discord = Discord; var response = await Discord.RestClient.Send(new GetGuildBansRequest(Id)).ConfigureAwait(false); @@ -229,7 +229,7 @@ namespace Discord { if (name == null) throw new ArgumentNullException(nameof(name)); - var request = new CreateChannelRequest(Id) { Name = name, Type = ChannelType.Text }; + var request = new CreateGuildChannelRequest(Id) { Name = name, Type = ChannelType.Text }; var response = await Discord.RestClient.Send(request).ConfigureAwait(false); return Discord.CreateTextChannel(this, response); @@ -238,7 +238,7 @@ namespace Discord { if (name == null) throw new ArgumentNullException(nameof(name)); - var request = new CreateChannelRequest(Id) { Name = name, Type = ChannelType.Voice }; + var request = new CreateGuildChannelRequest(Id) { Name = name, Type = ChannelType.Voice }; var response = await Discord.RestClient.Send(request).ConfigureAwait(false); return Discord.CreateVoiceChannel(this, response); @@ -251,7 +251,7 @@ namespace Discord { if (name == null) throw new ArgumentNullException(nameof(name)); - var createRequest = new CreateRoleRequest(Id); + var createRequest = new CreateGuildRoleRequest(Id); var createResponse = await Discord.RestClient.Send(createRequest).ConfigureAwait(false); var role = Discord.CreateRole(this, createResponse); @@ -347,7 +347,7 @@ namespace Discord newPermissions = GuildPermissions.All.RawValue; else { - foreach (var role in user.Presence.Roles) + foreach (var role in user.Roles) newPermissions |= role.Permissions.RawValue; } diff --git a/src/Discord.Net/Entities/Helpers/MentionHelper.cs b/src/Discord.Net/Entities/Helpers/MentionHelper.cs index 78777a518..9555c5391 100644 --- a/src/Discord.Net/Entities/Helpers/MentionHelper.cs +++ b/src/Discord.Net/Entities/Helpers/MentionHelper.cs @@ -11,7 +11,7 @@ namespace Discord private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+)>"); private static readonly Regex _roleRegex = new Regex(@"@everyone"); - internal static string Mention(User user) => $"<@{user.Id}>"; + internal static string Mention(IUser user) => $"<@{user.Id}>"; internal static string Mention(IChannel channel) => $"<#{channel.Id}>"; internal static string Mention(Role role) => role.IsEveryone ? "@everyone" : ""; diff --git a/src/Discord.Net/Entities/Helpers/MessageManager.cs b/src/Discord.Net/Entities/Helpers/MessageManager.cs index 1285093ae..13c4c72ff 100644 --- a/src/Discord.Net/Entities/Helpers/MessageManager.cs +++ b/src/Discord.Net/Entities/Helpers/MessageManager.cs @@ -29,7 +29,7 @@ namespace Discord } } - internal Message Add(Model model, User user) + internal Message Add(Model model, IUser user) => Add(_channel.Discord.CreateMessage(_channel, user, model)); private Message Add(Message message) { diff --git a/src/Discord.Net/Entities/Helpers/PermissionManager.cs b/src/Discord.Net/Entities/Helpers/PermissionManager.cs index a7047bd94..1646f8ea1 100644 --- a/src/Discord.Net/Entities/Helpers/PermissionManager.cs +++ b/src/Discord.Net/Entities/Helpers/PermissionManager.cs @@ -46,7 +46,7 @@ namespace Discord UpdatePermissions(); } - public OverwritePermissions? GetOverwrite(GuildUser user) + public OverwritePermissions? GetOverwrite(IUser user) { if (user == null) throw new ArgumentNullException(nameof(user)); @@ -64,7 +64,7 @@ namespace Discord return rule.Permissions; return null; } - public Task AddOrUpdateOverwrite(GuildUser user, OverwritePermissions permissions) + public Task AddOrUpdateOverwrite(IUser user, OverwritePermissions permissions) { if (user == null) throw new ArgumentNullException(nameof(user)); return AddOrUpdateOverwrite(user.Id, permissions); @@ -83,7 +83,7 @@ namespace Discord }; return _channel.Discord.RestClient.Send(request); } - public Task RemoveOverwrite(GuildUser user) + public Task RemoveOverwrite(IUser user) { if (user == null) throw new ArgumentNullException(nameof(user)); return RemoveOverwrite(user.Id); @@ -99,7 +99,7 @@ namespace Discord catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } } - public ChannelPermissions GetPermissions(GuildUser user) + public ChannelPermissions GetPermissions(IUser user) { if (user == null) throw new ArgumentNullException(nameof(user)); @@ -131,7 +131,7 @@ namespace Discord } } } - public void UpdatePermissions(GuildUser user) + public void UpdatePermissions(IUser user) { if (user == null) throw new ArgumentNullException(nameof(user)); @@ -147,22 +147,37 @@ namespace Discord } } - - public ChannelPermissions ResolvePermissions(GuildUser user) + public ChannelPermissions ResolvePermissions(IUser user) + { + var permissions = new ChannelPermissions(); + ResolvePermissions(user, ref permissions); + return permissions; + } + private ChannelPermissions ResolvePermissions(GuildUser user) { var permissions = new ChannelPermissions(); ResolvePermissions(user, ref permissions); return permissions; } - public bool ResolvePermissions(GuildUser user, ref ChannelPermissions permissions) + public bool ResolvePermissions(IUser user, ref ChannelPermissions permissions) { if (user == null) throw new ArgumentNullException(nameof(user)); + GuildUser guildUser = _channel.GetUser(user.Id); + if (guildUser == null) + { + permissions = ChannelPermissions.None; + return false; + } + else + return ResolvePermissions(user, ref permissions); + } + private bool ResolvePermissions(GuildUser user, ref ChannelPermissions permissions) + { uint newPermissions = 0; - var guild = user.Guild; uint mask = ChannelPermissions.All(_channel.Type).RawValue; - if (user == guild.Owner) + if (user == user.Guild.Owner) newPermissions = mask; //Private messages and owners always have all permissions else { @@ -171,7 +186,7 @@ namespace Discord var rules = _rules; Overwrite entry; - var roles = user.Presence.Roles.ToArray(); + var roles = user.Roles.ToArray(); if (roles.Length > 0) { for (int i = 0; i < roles.Length; i++) @@ -228,13 +243,13 @@ namespace Discord } else if (_channel.Type == ChannelType.Voice) { - if (user.VoiceState?.VoiceChannel == _channel) + if (user.VoiceChannel == _channel) return user; } } return null; } - public IEnumerable GetUsers() + public IEnumerable GetMembers() { if (_users != null) return _users.Select(x => x.Value.User); @@ -247,7 +262,7 @@ namespace Discord return users.Where(x => ResolvePermissions(x, ref perms)); } else if (_channel.Type == ChannelType.Voice) - return users.Where(x => x.VoiceState?.VoiceChannel == _channel); + return users.Where(x => x.VoiceChannel == _channel); } return Enumerable.Empty(); } diff --git a/src/Discord.Net/Entities/Message.cs b/src/Discord.Net/Entities/Message.cs index 7e255ddf7..09c5d57cb 100644 --- a/src/Discord.Net/Entities/Message.cs +++ b/src/Discord.Net/Entities/Message.cs @@ -3,6 +3,7 @@ using Discord.Net; using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Net; using System.Threading.Tasks; using Model = Discord.API.Message; @@ -11,27 +12,28 @@ namespace Discord { public class Message : IEntity { + //TODO: Docstrings + /// public ulong Id { get; } public IMessageChannel Channel { get; } - public User User { get; } + public IUser User { get; } - public bool IsTTS { get; internal set; } - public string RawText { get; internal set; } - public string Text { get; internal set; } - public DateTime Timestamp { get; internal set; } + public bool IsTTS { get; private set; } + public string RawText { get; private set; } + public string Text { get; private set; } + public DateTime Timestamp { get; private set; } public DateTime? EditedTimestamp { get; private set; } public IReadOnlyList Attachments { get; private set; } public IReadOnlyList Embeds { get; private set; } public IReadOnlyList MentionedUsers { get; private set; } public IReadOnlyList MentionedChannels { get; private set; } public IReadOnlyList MentionedRoles { get; private set; } - internal int Nonce { get; set; } public DiscordClient Discord => Channel.Discord; - public bool IsAuthor => false; + public bool IsAuthor => User.Id == Discord.CurrentUser.Id; - internal Message(ulong id, IMessageChannel channel, User user) + internal Message(ulong id, IMessageChannel channel, IUser user) { Id = id; Channel = channel; @@ -102,7 +104,28 @@ namespace Discord Text = text; } - public bool IsMentioningMe(bool includeRoles = false) => false; + /// Returns true if the logged-in user was mentioned. + public bool IsMentioningMe(bool includeRoles = false) + { + var me = Channel.GetCurrentUser() as GuildUser; + if (me != null) + { + if (includeRoles) + return MentionedUsers.Contains(me) || MentionedRoles.Any(x => me.HasRole(x)); + else + return MentionedUsers.Contains(me); + } + return false; + } + + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var req = new ModifyMessageRequest(Channel.Id, Id); + func(req); + await Discord.RestClient.Send(req).ConfigureAwait(false); + } public Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet diff --git a/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs b/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs index 7b37fccd0..076f33230 100644 --- a/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs +++ b/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs @@ -63,8 +63,8 @@ namespace Discord public bool DeafenMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.DeafenMembers); /// If True, a user may move other users between voice channels. public bool MoveMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.MoveMembers); - /// If True, a user may use voice activation rather than push-to-talk. - public bool UseVoiceActivation => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVoiceActivation); + /// If True, a user may use voice-activity-detection rather than push-to-talk. + public bool UseVAD => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVAD); /// Creates a new ChannelPermissions with the provided packed value. public ChannelPermissions(uint rawValue) { RawValue = rawValue; } @@ -93,7 +93,7 @@ namespace Discord PermissionsHelper.SetValue(ref value, muteMembers, PermissionBit.MuteMembers); PermissionsHelper.SetValue(ref value, deafenMembers, PermissionBit.DeafenMembers); PermissionsHelper.SetValue(ref value, moveMembers, PermissionBit.MoveMembers); - PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBit.UseVoiceActivation); + PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBit.UseVAD); RawValue = value; } diff --git a/src/Discord.Net/Entities/Permissions/GuildPermissions.cs b/src/Discord.Net/Entities/Permissions/GuildPermissions.cs index 7be0febe1..081232e25 100644 --- a/src/Discord.Net/Entities/Permissions/GuildPermissions.cs +++ b/src/Discord.Net/Entities/Permissions/GuildPermissions.cs @@ -52,8 +52,8 @@ namespace Discord public bool DeafenMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.DeafenMembers); /// If True, a user may move other users between voice channels. public bool MoveMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.MoveMembers); - /// If True, a user may use voice activation rather than push-to-talk. - public bool UseVoiceActivation => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVoiceActivation); + /// If True, a user may use voice-activity-detection rather than push-to-talk. + public bool UseVAD => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVAD); /// Creates a new GuildPermissions with the provided packed value. public GuildPermissions(uint rawValue) { RawValue = rawValue; } @@ -86,7 +86,7 @@ namespace Discord PermissionsHelper.SetValue(ref value, muteMembers, PermissionBit.MuteMembers); PermissionsHelper.SetValue(ref value, deafenMembers, PermissionBit.DeafenMembers); PermissionsHelper.SetValue(ref value, moveMembers, PermissionBit.MoveMembers); - PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBit.UseVoiceActivation); + PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBit.UseVAD); RawValue = value; } diff --git a/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs b/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs index 0a569c264..dc6512e7b 100644 --- a/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs +++ b/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs @@ -51,8 +51,8 @@ namespace Discord public PermValue DeafenMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.DeafenMembers); /// If True, a user may move other users between voice channels. public PermValue MoveMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.MoveMembers); - /// If True, a user may use voice activation rather than push-to-talk. - public PermValue UseVoiceActivation => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.UseVoiceActivation); + /// If True, a user may use voice-activity-detection rather than push-to-talk. + public PermValue UseVAD => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.UseVAD); /// Creates a new OverwritePermissions with the provided allow and deny packed values. public OverwritePermissions(uint allowValue, uint denyValue) @@ -83,7 +83,7 @@ namespace Discord PermissionsHelper.SetValue(ref allowValue, ref denyValue, muteMembers, PermissionBit.MuteMembers); PermissionsHelper.SetValue(ref allowValue, ref denyValue, deafenMembers, PermissionBit.DeafenMembers); PermissionsHelper.SetValue(ref allowValue, ref denyValue, moveMembers, PermissionBit.MoveMembers); - PermissionsHelper.SetValue(ref allowValue, ref denyValue, useVoiceActivation, PermissionBit.UseVoiceActivation); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, useVoiceActivation, PermissionBit.UseVAD); AllowValue = allowValue; DenyValue = denyValue; diff --git a/src/Discord.Net/Entities/Presences/GuildPresence.cs b/src/Discord.Net/Entities/Presences/GuildPresence.cs deleted file mode 100644 index 142e042e7..000000000 --- a/src/Discord.Net/Entities/Presences/GuildPresence.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Model = Discord.API.MemberPresence; - -namespace Discord -{ - public class GuildPresence : Presence - { - public Guild Guild { get; } - public ulong UserId { get; } - - /// - public IReadOnlyList Roles { get; private set; } - - internal GuildPresence(ulong userId, Guild guild) - { - UserId = userId; - Guild = guild; - } - internal override void Update(Model model) - { - base.Update(model); - Roles = model.Roles.Select(x => Guild.GetRole(x)).ToImmutableArray(); - } - - public bool HasRole(Role role) => false; - - //TODO: Unsure about these - /*public Task AddRoles(params Role[] roles) => xxx; - public Task RemoveRoles(params Role[] roles) => xxx;*/ - } -} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Presences/Presence.cs b/src/Discord.Net/Entities/Presences/Presence.cs deleted file mode 100644 index 671f60966..000000000 --- a/src/Discord.Net/Entities/Presences/Presence.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Model = Discord.API.MemberPresence; - -namespace Discord -{ - public class Presence - { - public string CurrentGame { get; private set; } - public UserStatus Status { get; private set; } - - internal Presence() { } - - internal virtual void Update(Model model) - { - CurrentGame = model.Game?.Name; - Status = model.Status; - } - } -} diff --git a/src/Discord.Net/Entities/Users/DMUser.cs b/src/Discord.Net/Entities/Users/DMUser.cs index ed2c7d541..982f8aea5 100644 --- a/src/Discord.Net/Entities/Users/DMUser.cs +++ b/src/Discord.Net/Entities/Users/DMUser.cs @@ -1,15 +1,42 @@ -namespace Discord +using System; +using System.Threading.Tasks; +using Model = Discord.API.User; + +namespace Discord { - public class DMUser : User + public class DMUser : IUser { - public DMChannel Channel { get; } + private readonly GlobalUser _user; - public override DiscordClient Discord => Channel.Discord; + public DMChannel Channel { get; } + + /// + public DiscordClient Discord => _user.Discord; + /// + public ulong Id => _user.Id; + /// + public string Username => _user.Username; + /// + public ushort Discriminator => _user.Discriminator; + /// + public bool IsBot => _user.IsBot; + /// + public string CurrentGame => _user.CurrentGame; + /// + public UserStatus Status => _user.Status; + /// + public string AvatarUrl => _user.AvatarUrl; + /// + public string Mention => _user.Mention; - internal DMUser(ulong id, DMChannel channel) - : base(id) + internal DMUser(GlobalUser user, DMChannel channel) { + _user = user; Channel = channel; } + + public void Update(Model model) => _user.Update(model); + + public virtual Task Update() { throw new NotSupportedException(); } } } diff --git a/src/Discord.Net/Entities/Users/User.cs b/src/Discord.Net/Entities/Users/GlobalUser.cs similarity index 57% rename from src/Discord.Net/Entities/Users/User.cs rename to src/Discord.Net/Entities/Users/GlobalUser.cs index 92c5a2773..2bb72b18a 100644 --- a/src/Discord.Net/Entities/Users/User.cs +++ b/src/Discord.Net/Entities/Users/GlobalUser.cs @@ -4,25 +4,29 @@ using Model = Discord.API.User; namespace Discord { - public abstract class User : IEntity + public class GlobalUser : IUser, IEntity { private string _avatarId; + private int _refCount; /// public ulong Id { get; } /// - public abstract DiscordClient Discord { get; } + public DiscordClient Discord { get; } public string Username { get; private set; } public ushort Discriminator { get; private set; } public bool IsBot { get; private set; } - + public string CurrentGame { get; private set; } + public UserStatus Status { get; private set; } + public string AvatarUrl => CDN.GetUserAvatarUrl(Id, _avatarId); public string Mention => MentionHelper.Mention(this); - internal User(ulong id) + internal GlobalUser(ulong id, DiscordClient discord) { Id = id; + Discord = discord; } internal virtual void Update(Model model) { @@ -34,6 +38,18 @@ namespace Discord public virtual Task Update() { throw new NotSupportedException(); } - public async Task CreateDMChannel() => await Discord.GetOrCreateDMChannel(Id); //TODO: We dont want both this and .Channel to appear on DMUser + public async Task CreateDMChannel() => await Discord.GetOrCreateDMChannel(Id); + + internal void Attach(IUser user) + { + //Only ever called from the gateway thread + _refCount++; + } + internal void Detach(IUser user) + { + //Only ever called from the gateway thread + if (--_refCount == 0) + Discord.RemoveUser(this); + } } } diff --git a/src/Discord.Net/Entities/Users/GuildUser.cs b/src/Discord.Net/Entities/Users/GuildUser.cs index bc0c8db8c..ba2e4198a 100644 --- a/src/Discord.Net/Entities/Users/GuildUser.cs +++ b/src/Discord.Net/Entities/Users/GuildUser.cs @@ -1,48 +1,81 @@ using Discord.API.Rest; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Model = Discord.API.GuildMember; namespace Discord { - public class GuildUser : User, IMentionable + public class GuildUser : IUser { + private readonly GlobalUser _user; + public Guild Guild { get; } - public GuildPresence Presence { get; } - public VoiceState VoiceState { get; } /// - public DateTime JoinedAt { get; private set; } - public GuildPermissions GuildPermissions { get; internal set; } + public string CurrentGame { get; private set; } + /// + public UserStatus Status { get; private set; } + public VoiceChannel VoiceChannel { get; private set; } - public override DiscordClient Discord => Guild.Discord; - public IEnumerable TextChannels => Guild.TextChannels.Where(x => GetPermissions(x).ReadMessages); + /// + public DiscordClient Discord => _user.Discord; + /// + public ulong Id => _user.Id; + /// + public string Username => _user.Username; + /// + public ushort Discriminator => _user.Discriminator; + /// + public bool IsBot => _user.IsBot; + /// + public string AvatarUrl => _user.AvatarUrl; + /// + public string Mention => _user.Mention; - internal GuildUser(ulong id, Guild guild, GuildPresence presence, VoiceState voiceState) - : base(id) + /// + public IReadOnlyList Roles { get; private set; } + + internal GuildUser(GlobalUser user, Guild guild) { + _user = user; Guild = guild; - Presence = presence; - VoiceState = voiceState; } internal void Update(Model model) { - base.Update(model.User); JoinedAt = model.JoinedAt.Value; + Roles = model.Roles.Select(x => Guild.GetRole(x)).ToImmutableArray(); } + public bool HasRole(Role role) => false; //TODO: Implement + + public Task Kick() => Discord.RestClient.Send(new RemoveGuildMemberRequest(Guild.Id, Id)); + public Task Ban(int pruneDays = 0) => Discord.RestClient.Send(new CreateGuildBanRequest(Guild.Id, Id) { PruneDays = pruneDays }); + public Task Unban() => Discord.RestClient.Send(new RemoveGuildBanRequest(Guild.Id, Id)); + + /// + public DateTime JoinedAt { get; private set; } + public GuildPermissions GuildPermissions { get; internal set; } + public Task CreateDMChannel() => _user.CreateDMChannel(); + + /// + public Task Update() { throw new NotSupportedException(); } //TODO: Not supported + public ChannelPermissions GetPermissions(GuildChannel channel) { if (channel == null) throw new ArgumentNullException(nameof(channel)); return channel.GetPermissions(this); } - /// - public override Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet - public Task Kick() => Discord.RestClient.Send(new RemoveGuildMemberRequest(Guild.Id, Id)); - public Task Ban(int pruneDays = 0) => Discord.RestClient.Send(new CreateGuildBanRequest(Guild.Id, Id) { PruneDays = pruneDays }); - public Task Unban() => Discord.RestClient.Send(new RemoveGuildBanRequest(Guild.Id, Id)); + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var req = new ModifyGuildMemberRequest(Guild.Id, Id); + func(req); + await Discord.RestClient.Send(req).ConfigureAwait(false); + } } } diff --git a/src/Discord.Net/Entities/Users/IUser.cs b/src/Discord.Net/Entities/Users/IUser.cs new file mode 100644 index 000000000..0e6071224 --- /dev/null +++ b/src/Discord.Net/Entities/Users/IUser.cs @@ -0,0 +1,14 @@ +namespace Discord +{ + public interface IUser : IEntity + { + string Username { get; } + ushort Discriminator { get; } + bool IsBot { get; } + + string AvatarUrl { get; } + string Mention { get; } + string CurrentGame { get; } + UserStatus Status { get; } + } +} diff --git a/src/Discord.Net/Entities/Users/PublicUser.cs b/src/Discord.Net/Entities/Users/PublicUser.cs deleted file mode 100644 index 2ab851a25..000000000 --- a/src/Discord.Net/Entities/Users/PublicUser.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Discord -{ - public class PublicUser : User - { - public override DiscordClient Discord { get; } - - internal PublicUser(ulong id, DiscordClient discord) - : base(id) - { - Discord = discord; - } - } -} diff --git a/src/Discord.Net/Entities/Users/SelfUser.cs b/src/Discord.Net/Entities/Users/SelfUser.cs index 4174672cf..8d5bbbafa 100644 --- a/src/Discord.Net/Entities/Users/SelfUser.cs +++ b/src/Discord.Net/Entities/Users/SelfUser.cs @@ -2,17 +2,14 @@ namespace Discord { - public class SelfUser : User + public class SelfUser : GlobalUser { - public override DiscordClient Discord { get; } - public string Email { get; private set; } public bool IsVerified { get; private set; } internal SelfUser(ulong id, DiscordClient discord) - : base(id) + : base(id, discord) { - Discord = discord; } internal override void Update(Model model) diff --git a/src/Discord.Net/Entities/Presences/VoiceState.cs b/src/Discord.Net/Entities/Users/VoiceState.cs similarity index 94% rename from src/Discord.Net/Entities/Presences/VoiceState.cs rename to src/Discord.Net/Entities/Users/VoiceState.cs index f6b56d7b6..740a54bba 100644 --- a/src/Discord.Net/Entities/Presences/VoiceState.cs +++ b/src/Discord.Net/Entities/Users/VoiceState.cs @@ -1,8 +1,4 @@ -using Discord.API.Rest; -using System; -using System.Collections.Immutable; -using System.Linq; -using System.Threading.Tasks; +/*using System; using Model = Discord.API.MemberVoiceState; namespace Discord @@ -63,4 +59,4 @@ namespace Discord _voiceStates &= ~VoiceStates.Suppressed; } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/Discord.Net/Enums/PermissionBits.cs b/src/Discord.Net/Enums/PermissionBits.cs index ac51dfb05..513d7da16 100644 --- a/src/Discord.Net/Enums/PermissionBits.cs +++ b/src/Discord.Net/Enums/PermissionBits.cs @@ -26,6 +26,6 @@ MuteMembers = 22, DeafenMembers = 23, MoveMembers = 24, - UseVoiceActivation = 25 + UseVAD = 25 } } diff --git a/src/Discord.Net/Enums/UserStatus.cs b/src/Discord.Net/Enums/UserStatus.cs index f2fdfda7c..d71ec3173 100644 --- a/src/Discord.Net/Enums/UserStatus.cs +++ b/src/Discord.Net/Enums/UserStatus.cs @@ -2,6 +2,7 @@ { public enum UserStatus { + Unknown, Online, Idle, Offline diff --git a/src/Discord.Net/Events/TypingEventArgs.cs b/src/Discord.Net/Events/TypingEventArgs.cs index 797d0d9d6..02c803b1f 100644 --- a/src/Discord.Net/Events/TypingEventArgs.cs +++ b/src/Discord.Net/Events/TypingEventArgs.cs @@ -5,9 +5,9 @@ namespace Discord public class TypingEventArgs : EventArgs { public IMessageChannel Channel { get; } - public User User { get; } + public IUser User { get; } - public TypingEventArgs(IMessageChannel channel, User user) + public TypingEventArgs(IMessageChannel channel, IUser user) { Channel = channel; User = user; diff --git a/src/Discord.Net/Events/UserEventArgs.cs b/src/Discord.Net/Events/UserEventArgs.cs index 6bbcaef01..a9139c2f8 100644 --- a/src/Discord.Net/Events/UserEventArgs.cs +++ b/src/Discord.Net/Events/UserEventArgs.cs @@ -4,9 +4,9 @@ namespace Discord { public class UserEventArgs : EventArgs { - public User User { get; } + public IUser User { get; } - public UserEventArgs(User user) + public UserEventArgs(IUser user) { User = user; } diff --git a/src/Discord.Net/Events/UserUpdatedEventArgs.cs b/src/Discord.Net/Events/UserUpdatedEventArgs.cs index 35b68bc55..e6c93fc47 100644 --- a/src/Discord.Net/Events/UserUpdatedEventArgs.cs +++ b/src/Discord.Net/Events/UserUpdatedEventArgs.cs @@ -2,10 +2,10 @@ { public class UserUpdatedEventArgs : UserEventArgs { - public User Before { get; } - public User After => User; + public IUser Before { get; } + public IUser After => User; - public UserUpdatedEventArgs(User before, User after) + public UserUpdatedEventArgs(IUser before, IUser after) : base(after) { Before = before; diff --git a/src/Discord.Net/InternalExtensions.cs b/src/Discord.Net/InternalExtensions.cs index 6b8342e57..431eaf144 100644 --- a/src/Discord.Net/InternalExtensions.cs +++ b/src/Discord.Net/InternalExtensions.cs @@ -2,7 +2,7 @@ { internal static class InternalExtensions { - public static User GetCurrentUser(this IChannel channel) + public static IUser GetCurrentUser(this IChannel channel) { switch (channel.Type) { diff --git a/src/Discord.Net/MessageQueue.cs b/src/Discord.Net/MessageQueue.cs index cdbbcc251..804784bc5 100644 --- a/src/Discord.Net/MessageQueue.cs +++ b/src/Discord.Net/MessageQueue.cs @@ -197,7 +197,7 @@ namespace Discord //{ try { - var request = new UpdateMessageRequest(msg.Channel.Id, msg.Id) + var request = new ModifyMessageRequest(msg.Channel.Id, msg.Id) { Content = item.NewText }; diff --git a/test/Discord.Net.Tests/Tests.cs b/test/Discord.Net.Tests/Tests.cs index 6cb0196d5..d8d09cd3d 100644 --- a/test/Discord.Net.Tests/Tests.cs +++ b/test/Discord.Net.Tests/Tests.cs @@ -242,7 +242,7 @@ namespace Discord.Tests "MessageUpdated event never received", async () => await message.Modify(x => { - x.Text = text + " updated"; + x.Content = text + " updated"; }), x => _targetBot.MessageUpdated += x, x => _targetBot.MessageUpdated -= x, @@ -293,7 +293,11 @@ namespace Discord.Tests var user = _testGuild.GetUser(_targetBot.CurrentUser.Id); AssertEvent( "UserUpdated never fired", - async () => await user.Modify(true, true, null, null), + async () => await user.Modify(x => + { + x.Deaf = true; + x.Mute = true; + }), x => _targetBot.UserUpdated += x, x => _targetBot.UserUpdated -= x); } @@ -319,7 +323,7 @@ namespace Discord.Tests x => _observerBot.UserUpdated -= x, (s, e) => e.After.Status == UserStatus.Idle); } - private async Task SetStatus(DiscordClient _client, UserStatus status) + private Task SetStatus(DiscordClient _client, UserStatus status) { throw new NotImplementedException(); /*_client.SetStatus(status); @@ -336,7 +340,7 @@ namespace Discord.Tests (s, e) => _targetBot.CurrentUser.CurrentGame == "test game"); } - private async Task SetGame(DiscordClient _client, string game) + private Task SetGame(DiscordClient _client, string game) { throw new NotImplementedException(); //_client.SetGame(game);