Added permission resolving and Channel.Members caching
This commit is contained in:
@@ -17,6 +17,7 @@ namespace Discord
|
|||||||
|
|
||||||
private readonly DiscordClient _client;
|
private readonly DiscordClient _client;
|
||||||
private ConcurrentDictionary<string, bool> _messages;
|
private ConcurrentDictionary<string, bool> _messages;
|
||||||
|
internal bool _areMembersStale;
|
||||||
|
|
||||||
/// <summary> Returns the unique identifier for this channel. </summary>
|
/// <summary> Returns the unique identifier for this channel. </summary>
|
||||||
public string Id { get; }
|
public string Id { get; }
|
||||||
@@ -46,45 +47,17 @@ namespace Discord
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public User Recipient => _client.Users[RecipientId];
|
public User Recipient => _client.Users[RecipientId];
|
||||||
|
|
||||||
|
private string[] userIds;
|
||||||
public IEnumerable<string> UserIds
|
public IEnumerable<string> UserIds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (IsPrivate)
|
if (!_areMembersStale)
|
||||||
return new string[] { RecipientId };
|
return userIds;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
var denyMembers = PermissionOverwrites
|
_areMembersStale = false;
|
||||||
.Where(x => x.Deny.Text_ReadMessages && x.Type == PermissionTarget.Member)
|
userIds = Members.Where(x => x.Permissions.Text_ReadMessages).Select(x => x.UserId).ToArray();
|
||||||
.Select(x => x.Id);
|
return userIds;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public IEnumerable<Member> Members => UserIds.Select(x => _client.Members[x, ServerId]);
|
public IEnumerable<Member> Members => UserIds.Select(x => _client.Members[x, ServerId]);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -8,6 +9,7 @@ namespace Discord
|
|||||||
public class Member
|
public class Member
|
||||||
{
|
{
|
||||||
private readonly DiscordClient _client;
|
private readonly DiscordClient _client;
|
||||||
|
private ConcurrentDictionary<string, PackedPermissions> _permissions;
|
||||||
|
|
||||||
/// <summary> Returns the name of this user on this server. </summary>
|
/// <summary> Returns the name of this user on this server. </summary>
|
||||||
public string Name { get; internal set; }
|
public string Name { get; internal set; }
|
||||||
@@ -29,6 +31,7 @@ namespace Discord
|
|||||||
|
|
||||||
public string SessionId { get; internal set; }
|
public string SessionId { get; internal set; }
|
||||||
public string Token { 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>
|
/// <summary> Returns the id for the game this user is currently playing. </summary>
|
||||||
public string GameId { get; internal set; }
|
public string GameId { get; internal set; }
|
||||||
@@ -65,6 +68,7 @@ namespace Discord
|
|||||||
UserId = userId;
|
UserId = userId;
|
||||||
ServerId = serverId;
|
ServerId = serverId;
|
||||||
Status = UserStatus.Offline;
|
Status = UserStatus.Offline;
|
||||||
|
_permissions = new ConcurrentDictionary<string, PackedPermissions>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => UserId;
|
public override string ToString() => UserId;
|
||||||
@@ -91,6 +95,8 @@ namespace Discord
|
|||||||
for (int i = 0; i < model.Roles.Length; i++)
|
for (int i = 0; i < model.Roles.Length; i++)
|
||||||
newRoles[i + 1] = model.Roles[i];
|
newRoles[i + 1] = model.Roles[i];
|
||||||
RoleIds = newRoles;
|
RoleIds = newRoles;
|
||||||
|
|
||||||
|
UpdatePermissions();
|
||||||
}
|
}
|
||||||
internal void Update(API.ExtendedMemberInfo model)
|
internal void Update(API.ExtendedMemberInfo model)
|
||||||
{
|
{
|
||||||
@@ -129,5 +135,58 @@ namespace Discord
|
|||||||
if (LastActivityAt == null || activity > LastActivityAt.Value)
|
if (LastActivityAt == null || activity > LastActivityAt.Value)
|
||||||
LastActivityAt = activity ?? DateTime.UtcNow;
|
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;
|
Name = model.Name;
|
||||||
Permissions.RawValue = (uint)model.Permissions;
|
Permissions.RawValue = (uint)model.Permissions;
|
||||||
|
|
||||||
|
foreach (var member in Members)
|
||||||
|
member.UpdatePermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
|
|||||||
@@ -173,10 +173,14 @@ namespace Discord
|
|||||||
internal void AddChannel(string channelId)
|
internal void AddChannel(string channelId)
|
||||||
{
|
{
|
||||||
_channels.TryAdd(channelId, true);
|
_channels.TryAdd(channelId, true);
|
||||||
|
foreach (var member in Members)
|
||||||
|
member.AddChannel(channelId);
|
||||||
}
|
}
|
||||||
internal bool RemoveChannel(string channelId)
|
internal bool RemoveChannel(string channelId)
|
||||||
{
|
{
|
||||||
bool ignored;
|
bool ignored;
|
||||||
|
foreach (var member in Members)
|
||||||
|
member.RemoveChannel(channelId);
|
||||||
return _channels.TryRemove(channelId, out ignored);
|
return _channels.TryRemove(channelId, out ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,10 +197,14 @@ namespace Discord
|
|||||||
internal void AddMember(string userId)
|
internal void AddMember(string userId)
|
||||||
{
|
{
|
||||||
_members.TryAdd(userId, true);
|
_members.TryAdd(userId, true);
|
||||||
}
|
foreach (var channel in Channels)
|
||||||
|
channel._areMembersStale = true;
|
||||||
|
}
|
||||||
internal bool RemoveMember(string userId)
|
internal bool RemoveMember(string userId)
|
||||||
{
|
{
|
||||||
bool ignored;
|
bool ignored;
|
||||||
|
foreach (var channel in Channels)
|
||||||
|
channel._areMembersStale = true;
|
||||||
return _members.TryRemove(userId, out ignored);
|
return _members.TryRemove(userId, out ignored);
|
||||||
}
|
}
|
||||||
internal bool HasMember(string userId)
|
internal bool HasMember(string userId)
|
||||||
|
|||||||
Reference in New Issue
Block a user