* AppRouterController.cs: chore:
* Utils.cs: * RoleTest.cs: * AVQuery.cs: * AVStatus.cs: * AVRelation.cs: * AVFieldNameAttribute.cs: * AVRole.cs: chore: 测试 Role 模块
parent
56bfee1732
commit
9266d6e115
|
@ -34,7 +34,7 @@ namespace LeanCloud.Storage.Internal {
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<AppRouterState> QueryAsync(string appId) {
|
||||
async Task<AppRouterState> QueryAsync(string appId) {
|
||||
Console.WriteLine("QueryAsync");
|
||||
|
||||
string url = string.Format("https://app-router.leancloud.cn/2/route?appId={0}", appId);
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using LeanCloud;
|
||||
|
||||
namespace LeanCloudTests {
|
||||
public class RoleTest {
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
Utils.InitNorthChina(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUsersFromRole() {
|
||||
AVQuery<AVRole> query = new AVQuery<AVRole>();
|
||||
AVRole role = await query.FirstAsync();
|
||||
AVQuery<AVUser> userQuery = role.Users.Query;
|
||||
IEnumerable<AVUser> users = await userQuery.FindAsync();
|
||||
Assert.Greater(users.Count(), 0);
|
||||
TestContext.Out.WriteLine($"count: {users.Count()}");
|
||||
foreach (AVUser user in users) {
|
||||
TestContext.Out.WriteLine($"{user.ObjectId}, {user.Username}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,30 +4,38 @@ using NUnit.Framework;
|
|||
|
||||
namespace LeanCloudTests {
|
||||
public static class Utils {
|
||||
public static void InitNorthChina() {
|
||||
AVClient.Initialize(new AVClient.Configuration {
|
||||
ApplicationId = "BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz",
|
||||
ApplicationKey = "pbf6Nk5seyjilexdpyrPwjSp",
|
||||
ApiServer = "https://avoscloud.com"
|
||||
});
|
||||
AVClient.HttpLog(TestContext.Out.WriteLine);
|
||||
public static void InitNorthChina(bool master = false) {
|
||||
if (master) {
|
||||
Init("BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz", "pbf6Nk5seyjilexdpyrPwjSp", "https://avoscloud.com", "qKH9ryRagHKvXeRRVkiUiHeb");
|
||||
} else {
|
||||
Init("BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz", "pbf6Nk5seyjilexdpyrPwjSp", "https://avoscloud.com");
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitEastChina() {
|
||||
AVClient.Initialize(new AVClient.Configuration {
|
||||
ApplicationId = "4eTwHdYhMaNBUpl1SrTr7GLC-9Nh9j0Va",
|
||||
ApplicationKey = "GSD6DtdgGWlWolivN4qhWtlE",
|
||||
ApiServer = "https://4eTwHdYh.api.lncldapi.com"
|
||||
});
|
||||
AVClient.HttpLog(TestContext.Out.WriteLine);
|
||||
public static void InitEastChina(bool master = false) {
|
||||
if (master) {
|
||||
Init("4eTwHdYhMaNBUpl1SrTr7GLC-9Nh9j0Va", "GSD6DtdgGWlWolivN4qhWtlE", "https://4eTwHdYh.api.lncldapi.com", "eqEp4n89h4zanWFskDDpIwL4");
|
||||
} else {
|
||||
Init("4eTwHdYhMaNBUpl1SrTr7GLC-9Nh9j0Va", "GSD6DtdgGWlWolivN4qhWtlE", "https://4eTwHdYh.api.lncldapi.com");
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitUS() {
|
||||
public static void InitUS(bool master = false) {
|
||||
if (master) {
|
||||
Init("MFAS1GnOyomRLSQYRaxdgdPz-MdYXbMMI", "p42JUxdxb95K5G8187t5ba3l", "https://MFAS1GnO.api.lncldglobal.com", "Ahb1wdFLwMgKwEaEicHRXbCY");
|
||||
} else {
|
||||
Init("MFAS1GnOyomRLSQYRaxdgdPz-MdYXbMMI", "p42JUxdxb95K5G8187t5ba3l", "https://MFAS1GnO.api.lncldglobal.com");
|
||||
}
|
||||
}
|
||||
|
||||
static void Init(string appId, string appKey, string apiServer, string masterKey = null) {
|
||||
AVClient.Initialize(new AVClient.Configuration {
|
||||
ApplicationId = "MFAS1GnOyomRLSQYRaxdgdPz-MdYXbMMI",
|
||||
ApplicationKey = "p42JUxdxb95K5G8187t5ba3l",
|
||||
ApiServer = "https://MFAS1GnO.api.lncldglobal.com"
|
||||
ApplicationId = appId,
|
||||
ApplicationKey = appKey,
|
||||
MasterKey = masterKey,
|
||||
ApiServer = apiServer
|
||||
});
|
||||
AVClient.UseMasterKey = !string.IsNullOrEmpty(masterKey);
|
||||
AVClient.HttpLog(TestContext.Out.WriteLine);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LeanCloud
|
||||
{
|
||||
namespace LeanCloud {
|
||||
/// <summary>
|
||||
/// Specifies a field name for a property on a AVObject subclass.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
|
||||
public sealed class AVFieldNameAttribute : Attribute
|
||||
{
|
||||
public sealed class AVFieldNameAttribute : Attribute {
|
||||
/// <summary>
|
||||
/// Constructs a new AVFieldName attribute.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field on the AVObject that the
|
||||
/// property represents.</param>
|
||||
public AVFieldNameAttribute(string fieldName)
|
||||
{
|
||||
public AVFieldNameAttribute(string fieldName) {
|
||||
FieldName = fieldName;
|
||||
}
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ namespace LeanCloud
|
|||
});
|
||||
}
|
||||
|
||||
public Task<T> FirstAsync(CancellationToken cancellationToken)
|
||||
public Task<T> FirstAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return FirstOrDefaultAsync(cancellationToken).OnSuccess(t =>
|
||||
{
|
||||
|
|
|
@ -8,71 +8,59 @@ using System.Linq.Expressions;
|
|||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace LeanCloud
|
||||
{
|
||||
namespace LeanCloud {
|
||||
/// <summary>
|
||||
/// A common base class for AVRelations.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public abstract class AVRelationBase : IJsonConvertible
|
||||
{
|
||||
public abstract class AVRelationBase : IJsonConvertible {
|
||||
private AVObject parent;
|
||||
private string key;
|
||||
private string targetClassName;
|
||||
|
||||
internal AVRelationBase(AVObject parent, string key)
|
||||
{
|
||||
internal AVRelationBase(AVObject parent, string key) {
|
||||
EnsureParentAndKey(parent, key);
|
||||
}
|
||||
|
||||
internal AVRelationBase(AVObject parent, string key, string targetClassName)
|
||||
: this(parent, key)
|
||||
{
|
||||
: this(parent, key) {
|
||||
this.targetClassName = targetClassName;
|
||||
}
|
||||
|
||||
internal static ObjectSubclassingController SubclassingController
|
||||
{
|
||||
get
|
||||
{
|
||||
internal static ObjectSubclassingController SubclassingController {
|
||||
get {
|
||||
return AVPlugins.Instance.SubclassingController;
|
||||
}
|
||||
}
|
||||
|
||||
internal void EnsureParentAndKey(AVObject parent, string key)
|
||||
{
|
||||
internal void EnsureParentAndKey(AVObject parent, string key) {
|
||||
this.parent = this.parent ?? parent;
|
||||
this.key = this.key ?? key;
|
||||
Debug.Assert(this.parent == parent, "Relation retrieved from two different objects");
|
||||
Debug.Assert(this.key == key, "Relation retrieved from two different keys");
|
||||
}
|
||||
|
||||
internal void Add(AVObject obj)
|
||||
{
|
||||
internal void Add(AVObject obj) {
|
||||
var change = new AVRelationOperation(new[] { obj }, null);
|
||||
parent.PerformOperation(key, change);
|
||||
targetClassName = change.TargetClassName;
|
||||
}
|
||||
|
||||
internal void Remove(AVObject obj)
|
||||
{
|
||||
internal void Remove(AVObject obj) {
|
||||
var change = new AVRelationOperation(null, new[] { obj });
|
||||
parent.PerformOperation(key, change);
|
||||
targetClassName = change.TargetClassName;
|
||||
}
|
||||
|
||||
IDictionary<string, object> IJsonConvertible.ToJSON()
|
||||
{
|
||||
IDictionary<string, object> IJsonConvertible.ToJSON() {
|
||||
return new Dictionary<string, object> {
|
||||
{ "__type", "Relation"},
|
||||
{ "className", targetClassName}
|
||||
};
|
||||
}
|
||||
|
||||
internal AVQuery<T> GetQuery<T>() where T : AVObject
|
||||
{
|
||||
if (targetClassName != null)
|
||||
{
|
||||
internal AVQuery<T> GetQuery<T>() where T : AVObject {
|
||||
if (targetClassName != null) {
|
||||
return new AVQuery<T>(targetClassName)
|
||||
.WhereRelatedTo(parent, key);
|
||||
}
|
||||
|
@ -82,24 +70,19 @@ namespace LeanCloud
|
|||
.WhereRelatedTo(parent, key);
|
||||
}
|
||||
|
||||
internal AVQuery<T> GetReverseQuery<T>(T target) where T : AVObject
|
||||
{
|
||||
if (target.ObjectId == null)
|
||||
{
|
||||
throw new ArgumentNullException("target.ObjectId", "can not query a relation without target ObjectId.");
|
||||
internal AVQuery<T> GetReverseQuery<T>(T target) where T : AVObject {
|
||||
if (target.ObjectId == null) {
|
||||
throw new ArgumentNullException(nameof(target), "can not query a relation without target ObjectId.");
|
||||
}
|
||||
|
||||
return new AVQuery<T>(parent.ClassName).WhereEqualTo(key, target);
|
||||
}
|
||||
|
||||
internal string TargetClassName
|
||||
{
|
||||
get
|
||||
{
|
||||
internal string TargetClassName {
|
||||
get {
|
||||
return targetClassName;
|
||||
}
|
||||
set
|
||||
{
|
||||
set {
|
||||
targetClassName = value;
|
||||
}
|
||||
}
|
||||
|
@ -109,8 +92,7 @@ namespace LeanCloud
|
|||
/// </summary>
|
||||
internal static AVRelationBase CreateRelation(AVObject parent,
|
||||
string key,
|
||||
string targetClassName)
|
||||
{
|
||||
string targetClassName) {
|
||||
var targetType = SubclassingController.GetType(targetClassName) ?? typeof(AVObject);
|
||||
|
||||
Expression<Func<AVRelation<AVObject>>> createRelationExpr =
|
||||
|
@ -124,8 +106,7 @@ namespace LeanCloud
|
|||
}
|
||||
|
||||
private static AVRelation<T> CreateRelation<T>(AVObject parent, string key, string targetClassName)
|
||||
where T : AVObject
|
||||
{
|
||||
where T : AVObject {
|
||||
return new AVRelation<T>(parent, key, targetClassName);
|
||||
}
|
||||
}
|
||||
|
@ -135,8 +116,7 @@ namespace LeanCloud
|
|||
/// AVRelation is associated with a particular parent and key.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the child objects.</typeparam>
|
||||
public sealed class AVRelation<T> : AVRelationBase where T : AVObject
|
||||
{
|
||||
public sealed class AVRelation<T> : AVRelationBase where T : AVObject {
|
||||
|
||||
internal AVRelation(AVObject parent, string key) : base(parent, key) { }
|
||||
|
||||
|
@ -147,8 +127,7 @@ namespace LeanCloud
|
|||
/// Adds an object to this relation. The object must already have been saved.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to add.</param>
|
||||
public void Add(T obj)
|
||||
{
|
||||
public void Add(T obj) {
|
||||
base.Add(obj);
|
||||
}
|
||||
|
||||
|
@ -156,18 +135,15 @@ namespace LeanCloud
|
|||
/// Removes an object from this relation. The object must already have been saved.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to remove.</param>
|
||||
public void Remove(T obj)
|
||||
{
|
||||
public void Remove(T obj) {
|
||||
base.Remove(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a query that can be used to query the objects in this relation.
|
||||
/// </summary>
|
||||
public AVQuery<T> Query
|
||||
{
|
||||
get
|
||||
{
|
||||
public AVQuery<T> Query {
|
||||
get {
|
||||
return base.GetQuery<T>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,18 @@
|
|||
using LeanCloud.Storage.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LeanCloud
|
||||
{
|
||||
namespace LeanCloud {
|
||||
/// <summary>
|
||||
/// Represents a Role on the LeanCloud server. AVRoles represent groupings
|
||||
/// of <see cref="AVUser"/>s for the purposes of granting permissions (e.g.
|
||||
/// specifying a <see cref="AVACL"/> for a <see cref="AVObject"/>. Roles
|
||||
/// are specified by their sets of child users and child roles, all of which are granted
|
||||
/// any permissions that the parent role has.
|
||||
///
|
||||
/// Roles must have a name (that cannot be changed after creation of the role),
|
||||
/// and must specify an ACL.
|
||||
/// 角色类
|
||||
/// </summary>
|
||||
[AVClassName("_Role")]
|
||||
public class AVRole : AVObject
|
||||
{
|
||||
public class AVRole : AVObject {
|
||||
private static readonly Regex namePattern = new Regex("^[0-9a-zA-Z_\\- ]+$");
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new AVRole. You must assign a name and ACL to the role.
|
||||
/// </summary>
|
||||
public AVRole() : base() { }
|
||||
public AVRole() { }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new AVRole with the given name.
|
||||
|
@ -34,8 +20,7 @@ namespace LeanCloud
|
|||
/// <param name="name">The name of the role to create.</param>
|
||||
/// <param name="acl">The ACL for this role. Roles must have an ACL.</param>
|
||||
public AVRole(string name, AVACL acl)
|
||||
: this()
|
||||
{
|
||||
: this() {
|
||||
Name = name;
|
||||
ACL = acl;
|
||||
}
|
||||
|
@ -44,10 +29,13 @@ namespace LeanCloud
|
|||
/// Gets the name of the role.
|
||||
/// </summary>
|
||||
[AVFieldName("name")]
|
||||
public string Name
|
||||
{
|
||||
get { return GetProperty<string>("Name"); }
|
||||
set { SetProperty(value, "Name"); }
|
||||
public string Name {
|
||||
get {
|
||||
return GetProperty<string>("Name");
|
||||
}
|
||||
set {
|
||||
SetProperty(value, "Name");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -57,9 +45,10 @@ namespace LeanCloud
|
|||
/// add or remove child users from the role through this relation.
|
||||
/// </summary>
|
||||
[AVFieldName("users")]
|
||||
public AVRelation<AVUser> Users
|
||||
{
|
||||
get { return GetRelationProperty<AVUser>("Users"); }
|
||||
public AVRelation<AVUser> Users {
|
||||
get {
|
||||
return GetRelationProperty<AVUser>("Users");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -69,30 +58,25 @@ namespace LeanCloud
|
|||
/// add or remove child roles from the role through this relation.
|
||||
/// </summary>
|
||||
[AVFieldName("roles")]
|
||||
public AVRelation<AVRole> Roles
|
||||
{
|
||||
get { return GetRelationProperty<AVRole>("Roles"); }
|
||||
public AVRelation<AVRole> Roles {
|
||||
get {
|
||||
return GetRelationProperty<AVRole>("Roles");
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnSettingValue(ref string key, ref object value)
|
||||
{
|
||||
internal override void OnSettingValue(ref string key, ref object value) {
|
||||
base.OnSettingValue(ref key, ref value);
|
||||
if (key == "name")
|
||||
{
|
||||
if (ObjectId != null)
|
||||
{
|
||||
if (key == "name") {
|
||||
if (ObjectId != null) {
|
||||
throw new InvalidOperationException(
|
||||
"A role's name can only be set before it has been saved.");
|
||||
}
|
||||
if (!(value is string))
|
||||
{
|
||||
throw new ArgumentException("A role's name must be a string.", "value");
|
||||
if (!(value is string)) {
|
||||
throw new ArgumentException("A role's name must be a string.", nameof(value));
|
||||
}
|
||||
if (!namePattern.IsMatch((string)value))
|
||||
{
|
||||
if (!namePattern.IsMatch((string)value)) {
|
||||
throw new ArgumentException(
|
||||
"A role's name can only contain alphanumeric characters, _, -, and spaces.",
|
||||
"value");
|
||||
"A role's name can only contain alphanumeric characters, _, -, and spaces.", nameof(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,10 +84,8 @@ namespace LeanCloud
|
|||
/// <summary>
|
||||
/// Gets a <see cref="AVQuery{AVRole}"/> over the Role collection.
|
||||
/// </summary>
|
||||
public static AVQuery<AVRole> Query
|
||||
{
|
||||
get
|
||||
{
|
||||
public static AVQuery<AVRole> Query {
|
||||
get {
|
||||
return new AVQuery<AVRole>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LeanCloud
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件流系统中的一条状态
|
||||
/// </summary>
|
||||
[AVClassName("_Status")]
|
||||
public class AVStatus : AVObject
|
||||
{
|
||||
private static readonly HashSet<string> readOnlyKeys = new HashSet<string> {
|
||||
"messageId", "inboxType", "data","Source"
|
||||
};
|
||||
|
||||
protected override bool IsKeyMutable(string key)
|
||||
{
|
||||
return !readOnlyKeys.Contains(key);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue