using System;
using System.Collections.Generic;
using System.Linq;
using LeanCloud.Storage.Internal;
namespace LeanCloud {
///
/// A AVACL is used to control which users and roles can access or modify a particular object. Each
/// can have its own AVACL. You can grant read and write permissions
/// separately to specific users, to groups of users that belong to roles, or you can grant permissions
/// to "the public" so that, for example, any user could read a particular object but only a particular
/// set of users could write to that object.
///
public class AVACL : IJsonConvertible {
private enum AccessKind {
Read,
Write
}
private const string publicName = "*";
private readonly ICollection readers = new HashSet();
private readonly ICollection writers = new HashSet();
internal AVACL(IDictionary jsonObject) {
readers = new HashSet(from pair in jsonObject
where ((IDictionary)pair.Value).ContainsKey("read")
select pair.Key);
writers = new HashSet(from pair in jsonObject
where ((IDictionary)pair.Value).ContainsKey("write")
select pair.Key);
}
///
/// Creates an ACL with no permissions granted.
///
public AVACL() {
}
///
/// Creates an ACL where only the provided user has access.
///
/// The only user that can read or write objects governed by this ACL.
public AVACL(AVUser owner) {
SetReadAccess(owner, true);
SetWriteAccess(owner, true);
}
IDictionary IJsonConvertible.ToJSON() {
var result = new Dictionary();
foreach (var user in readers.Union(writers)) {
var userPermissions = new Dictionary();
if (readers.Contains(user)) {
userPermissions["read"] = true;
}
if (writers.Contains(user)) {
userPermissions["write"] = true;
}
result[user] = userPermissions;
}
return result;
}
private void SetAccess(AccessKind kind, string userId, bool allowed) {
if (userId == null) {
throw new ArgumentException("Cannot set access for an unsaved user or role.");
}
ICollection target = null;
switch (kind) {
case AccessKind.Read:
target = readers;
break;
case AccessKind.Write:
target = writers;
break;
default:
throw new NotImplementedException("Unknown AccessKind");
}
if (allowed) {
target.Add(userId);
} else {
target.Remove(userId);
}
}
private bool GetAccess(AccessKind kind, string userId) {
if (userId == null) {
throw new ArgumentException("Cannot get access for an unsaved user or role.");
}
switch (kind) {
case AccessKind.Read:
return readers.Contains(userId);
case AccessKind.Write:
return writers.Contains(userId);
default:
throw new NotImplementedException("Unknown AccessKind");
}
}
///
/// Gets or sets whether the public is allowed to read this object.
///
public bool PublicReadAccess {
get {
return GetAccess(AccessKind.Read, publicName);
}
set {
SetAccess(AccessKind.Read, publicName, value);
}
}
///
/// Gets or sets whether the public is allowed to write this object.
///
public bool PublicWriteAccess {
get {
return GetAccess(AccessKind.Write, publicName);
}
set {
SetAccess(AccessKind.Write, publicName, value);
}
}
///
/// Sets whether the given user id is allowed to read this object.
///
/// The objectId of the user.
/// Whether the user has permission.
public void SetReadAccess(string userId, bool allowed) {
SetAccess(AccessKind.Read, userId, allowed);
}
///
/// Sets whether the given user is allowed to read this object.
///
/// The user.
/// Whether the user has permission.
public void SetReadAccess(AVUser user, bool allowed) {
SetReadAccess(user.ObjectId, allowed);
}
///
/// Sets whether the given user id is allowed to write this object.
///
/// The objectId of the user.
/// Whether the user has permission.
public void SetWriteAccess(string userId, bool allowed) {
SetAccess(AccessKind.Write, userId, allowed);
}
///
/// Sets whether the given user is allowed to write this object.
///
/// The user.
/// Whether the user has permission.
public void SetWriteAccess(AVUser user, bool allowed) {
SetWriteAccess(user.ObjectId, allowed);
}
///
/// Gets whether the given user id is *explicitly* allowed to read this object.
/// Even if this returns false, the user may still be able to read it if
/// PublicReadAccess is true or a role that the user belongs to has read access.
///
/// The user objectId to check.
/// Whether the user has access.
public bool GetReadAccess(string userId) {
return GetAccess(AccessKind.Read, userId);
}
///
/// Gets whether the given user is *explicitly* allowed to read this object.
/// Even if this returns false, the user may still be able to read it if
/// PublicReadAccess is true or a role that the user belongs to has read access.
///
/// The user to check.
/// Whether the user has access.
public bool GetReadAccess(AVUser user) {
return GetReadAccess(user.ObjectId);
}
///
/// Gets whether the given user id is *explicitly* allowed to write this object.
/// Even if this returns false, the user may still be able to write it if
/// PublicReadAccess is true or a role that the user belongs to has write access.
///
/// The user objectId to check.
/// Whether the user has access.
public bool GetWriteAccess(string userId) {
return GetAccess(AccessKind.Write, userId);
}
///
/// Gets whether the given user is *explicitly* allowed to write this object.
/// Even if this returns false, the user may still be able to write it if
/// PublicReadAccess is true or a role that the user belongs to has write access.
///
/// The user to check.
/// Whether the user has access.
public bool GetWriteAccess(AVUser user) {
return GetWriteAccess(user.ObjectId);
}
///
/// Sets whether users belonging to the role with the given
/// are allowed to read this object.
///
/// The name of the role.
/// Whether the role has access.
public void SetRoleReadAccess(string roleName, bool allowed) {
SetAccess(AccessKind.Read, "role:" + roleName, allowed);
}
///
/// Sets whether users belonging to the given role are allowed to read this object.
///
/// The role.
/// Whether the role has access.
public void SetRoleReadAccess(AVRole role, bool allowed) {
SetRoleReadAccess(role.Name, allowed);
}
///
/// Gets whether users belonging to the role with the given
/// are allowed to read this object. Even if this returns false, the role may still be
/// able to read it if a parent role has read access.
///
/// The name of the role.
/// Whether the role has access.
public bool GetRoleReadAccess(string roleName) {
return GetAccess(AccessKind.Read, "role:" + roleName);
}
///
/// Gets whether users belonging to the role are allowed to read this object.
/// Even if this returns false, the role may still be able to read it if a
/// parent role has read access.
///
/// The name of the role.
/// Whether the role has access.
public bool GetRoleReadAccess(AVRole role) {
return GetRoleReadAccess(role.Name);
}
///
/// Sets whether users belonging to the role with the given
/// are allowed to write this object.
///
/// The name of the role.
/// Whether the role has access.
public void SetRoleWriteAccess(string roleName, bool allowed) {
SetAccess(AccessKind.Write, "role:" + roleName, allowed);
}
///
/// Sets whether users belonging to the given role are allowed to write this object.
///
/// The role.
/// Whether the role has access.
public void SetRoleWriteAccess(AVRole role, bool allowed) {
SetRoleWriteAccess(role.Name, allowed);
}
///
/// Gets whether users belonging to the role with the given
/// are allowed to write this object. Even if this returns false, the role may still be
/// able to write it if a parent role has write access.
///
/// The name of the role.
/// Whether the role has access.
public bool GetRoleWriteAccess(string roleName) {
return GetAccess(AccessKind.Write, "role:" + roleName);
}
///
/// Gets whether users belonging to the role are allowed to write this object.
/// Even if this returns false, the role may still be able to write it if a
/// parent role has write access.
///
/// The name of the role.
/// Whether the role has access.
public bool GetRoleWriteAccess(AVRole role) {
return GetRoleWriteAccess(role.Name);
}
}
}