Browse Source

Added permission resolving and Channel.Members caching

tags/docs-0.9
RogueException 9 years ago
parent
commit
716e0ee6a4
4 changed files with 78 additions and 35 deletions
  1. +7
    -34
      src/Discord.Net/Models/Channel.cs
  2. +59
    -0
      src/Discord.Net/Models/Member.cs
  3. +3
    -0
      src/Discord.Net/Models/Role.cs
  4. +9
    -1
      src/Discord.Net/Models/Server.cs

+ 7
- 34
src/Discord.Net/Models/Channel.cs View File

@@ -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)
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]); public IEnumerable<Member> Members => UserIds.Select(x => _client.Members[x, ServerId]);


+ 59
- 0
src/Discord.Net/Models/Member.cs View File

@@ -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;
}
} }
} }

+ 3
- 0
src/Discord.Net/Models/Role.cs View File

@@ -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;


+ 9
- 1
src/Discord.Net/Models/Server.cs View File

@@ -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)


Loading…
Cancel
Save