@@ -17,6 +17,7 @@ namespace Discord | |||
private readonly DiscordClient _client; | |||
private ConcurrentDictionary<string, bool> _messages; | |||
internal bool _areMembersStale; | |||
/// <summary> Returns the unique identifier for this channel. </summary> | |||
public string Id { get; } | |||
@@ -46,45 +47,17 @@ namespace Discord | |||
[JsonIgnore] | |||
public User Recipient => _client.Users[RecipientId]; | |||
private string[] userIds; | |||
public IEnumerable<string> UserIds | |||
{ | |||
get | |||
{ | |||
if (IsPrivate) | |||
return new string[] { RecipientId }; | |||
var server = Server; | |||
string everyoneId = server.EveryoneRoleId; | |||
//Is this channel Opt-In or Opt-Out? | |||
IEnumerable<PermissionOverwrite> everyones = PermissionOverwrites.Where(x => x.Type == PermissionTarget.Role && x.Id == server.EveryoneRoleId); | |||
bool isOptIn = everyones.Any(x => x.Deny.Text_ReadMessages) && !everyones.Any(x => x.Allow.Text_ReadMessages); | |||
if (!_areMembersStale) | |||
return userIds; | |||
var denyMembers = PermissionOverwrites | |||
.Where(x => x.Deny.Text_ReadMessages && x.Type == PermissionTarget.Member) | |||
.Select(x => x.Id); | |||
var allowRoles = PermissionOverwrites | |||
.Where(x => x.Allow.Text_ReadMessages && x.Type == PermissionTarget.Role && x.Id != server.EveryoneRoleId) | |||
.SelectMany(x => _client.Roles[x.Id].MemberIds); | |||
var allowMembers = PermissionOverwrites | |||
.Where(x => x.Allow.Text_ReadMessages && x.Type == PermissionTarget.Member) | |||
.Select(x => x.Id); | |||
if (isOptIn) | |||
{ | |||
//AllowRole -> DenyMember -> AllowMember -> AllowOwner | |||
return allowRoles.Except(denyMembers).Concat(allowMembers).Concat(new string[] { server.OwnerId }).Distinct(); | |||
} | |||
else | |||
{ | |||
var denyRoles = PermissionOverwrites | |||
.Where(x => x.Deny.Text_ReadMessages && x.Type == PermissionTarget.Role && x.Id != server.EveryoneRoleId) | |||
.SelectMany(x => _client.Roles[x.Id].MemberIds); | |||
//DenyRole -> AllowRole -> DenyMember -> AllowMember -> AllowOwner | |||
var optOut = denyRoles.Except(allowRoles).Concat(denyMembers).Except(allowMembers).Except(new string[] { server.OwnerId }); | |||
return Server.UserIds.Except(optOut); | |||
} | |||
_areMembersStale = false; | |||
userIds = Members.Where(x => x.Permissions.Text_ReadMessages).Select(x => x.UserId).ToArray(); | |||
return userIds; | |||
} | |||
} | |||
public IEnumerable<Member> Members => UserIds.Select(x => _client.Members[x, ServerId]); | |||
@@ -1,5 +1,6 @@ | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -8,6 +9,7 @@ namespace Discord | |||
public class Member | |||
{ | |||
private readonly DiscordClient _client; | |||
private ConcurrentDictionary<string, PackedPermissions> _permissions; | |||
/// <summary> Returns the name of this user on this server. </summary> | |||
public string Name { get; internal set; } | |||
@@ -29,6 +31,7 @@ namespace Discord | |||
public string SessionId { get; internal set; } | |||
public string Token { get; internal set; } | |||
public PackedPermissions Permissions { get; internal set; } | |||
/// <summary> Returns the id for the game this user is currently playing. </summary> | |||
public string GameId { get; internal set; } | |||
@@ -65,6 +68,7 @@ namespace Discord | |||
UserId = userId; | |||
ServerId = serverId; | |||
Status = UserStatus.Offline; | |||
_permissions = new ConcurrentDictionary<string, PackedPermissions>(); | |||
} | |||
public override string ToString() => UserId; | |||
@@ -91,6 +95,8 @@ namespace Discord | |||
for (int i = 0; i < model.Roles.Length; i++) | |||
newRoles[i + 1] = model.Roles[i]; | |||
RoleIds = newRoles; | |||
UpdatePermissions(); | |||
} | |||
internal void Update(API.ExtendedMemberInfo model) | |||
{ | |||
@@ -129,5 +135,58 @@ namespace Discord | |||
if (LastActivityAt == null || activity > LastActivityAt.Value) | |||
LastActivityAt = activity ?? DateTime.UtcNow; | |||
} | |||
internal void AddChannel(string channelId) | |||
{ | |||
_permissions.TryAdd(channelId, new PackedPermissions()); | |||
UpdatePermissions(channelId); | |||
} | |||
internal bool RemoveChannel(string channelId) | |||
{ | |||
PackedPermissions ignored; | |||
return _permissions.TryRemove(channelId, out ignored); | |||
} | |||
internal void UpdatePermissions() | |||
{ | |||
foreach (var channel in _permissions) | |||
UpdatePermissions(channel.Key); | |||
} | |||
internal void UpdatePermissions(string channelId) | |||
{ | |||
var server = Server; | |||
if (server == null) return; | |||
var channel = _client.Channels[channelId]; | |||
if (channel == null) return; | |||
var serverOverwrites = channel.PermissionOverwrites; | |||
var channelOverwrites = channel.PermissionOverwrites; | |||
PackedPermissions permissions; | |||
if (!_permissions.TryGetValue(channelId, out permissions)) return; | |||
uint newPermissions = 0x0; | |||
foreach (var serverRole in Roles) | |||
newPermissions |= serverRole.Permissions.RawValue; | |||
foreach (var denyRole in channelOverwrites.Where(x => x.Type == PermissionTarget.Role && x.Deny.RawValue != 0 && RoleIds.Contains(x.Id))) | |||
newPermissions &= ~denyRole.Deny.RawValue; | |||
foreach (var allowRole in channelOverwrites.Where(x => x.Type == PermissionTarget.Role && x.Allow.RawValue != 0 && RoleIds.Contains(x.Id))) | |||
newPermissions |= allowRole.Allow.RawValue; | |||
foreach (var denyMembers in channelOverwrites.Where(x => x.Type == PermissionTarget.Member && x.Id == UserId && x.Deny.RawValue != 0)) | |||
newPermissions &= ~denyMembers.Deny.RawValue; | |||
foreach (var allowMembers in channelOverwrites.Where(x => x.Type == PermissionTarget.Member && x.Id == UserId && x.Allow.RawValue != 0)) | |||
newPermissions |= allowMembers.Allow.RawValue; | |||
if (permissions.RawValue != newPermissions) | |||
{ | |||
permissions.RawValue = newPermissions; | |||
channel._areMembersStale = true; | |||
} | |||
} | |||
public PackedPermissions GetPermissions(string channelId) | |||
{ | |||
PackedPermissions perms; | |||
if (_permissions.TryGetValue(channelId, out perms)) | |||
return perms; | |||
return null; | |||
} | |||
} | |||
} |
@@ -42,6 +42,9 @@ namespace Discord | |||
{ | |||
Name = model.Name; | |||
Permissions.RawValue = (uint)model.Permissions; | |||
foreach (var member in Members) | |||
member.UpdatePermissions(); | |||
} | |||
public override string ToString() => Name; | |||
@@ -173,10 +173,14 @@ namespace Discord | |||
internal void AddChannel(string channelId) | |||
{ | |||
_channels.TryAdd(channelId, true); | |||
foreach (var member in Members) | |||
member.AddChannel(channelId); | |||
} | |||
internal bool RemoveChannel(string channelId) | |||
{ | |||
bool ignored; | |||
foreach (var member in Members) | |||
member.RemoveChannel(channelId); | |||
return _channels.TryRemove(channelId, out ignored); | |||
} | |||
@@ -193,10 +197,14 @@ namespace Discord | |||
internal void AddMember(string userId) | |||
{ | |||
_members.TryAdd(userId, true); | |||
} | |||
foreach (var channel in Channels) | |||
channel._areMembersStale = true; | |||
} | |||
internal bool RemoveMember(string userId) | |||
{ | |||
bool ignored; | |||
foreach (var channel in Channels) | |||
channel._areMembersStale = true; | |||
return _members.TryRemove(userId, out ignored); | |||
} | |||
internal bool HasMember(string userId) | |||