uprtcl / js-uprtcl-server

Uprtcl JS web-server service provider

Home Page:http://uprtcl.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Review permissions implementation and endpoints

pepoospina opened this issue · comments

commented
  • Review the finDelegateTo property so that it always points to the element whose permissions are the effective permissions of an element, including when delegate = false, in which case finDelegateTo should be the same elementId. Once this is done, remove all logic of the type if (delegate) { ... } that is not needed (for example here, here, and here ). Make sure current tests pass.

  • Add new tests to uprtcl.test.ts that changes the delegate property of an element. Consider all possible cases:

    • delegate of perspective A passes from false to true and new delegateTo is perspective C who has delegate = false. Perspectve B has delegate = true and delegateTo = perspective A.
    • delegate of perspective A passes from false to true and new delegateTo is perspective C who has delegate = true and delegateTo = perspective D. Perspectve B has delegate = true and delegateTo = perspective A.
    • delegate of perspective A passes from true to false and delegateTo was perspective C. Perspectve B has delegate = true and delegateTo = perspective A.
  • Review the endpoints related to permissions and remove the generic ones

  • path: "/uprtcl/1/accessConfig/:elementId"

  • path: "/uprtcl/1/permissions/:elementId"

    Replace them with task-specific endpoints as follows:

    path: "/uprtcl/1/accessConfig/:elementId/delegate?delegate=value&delegateTo=value"

    Which will receive two query parameters delegate and delegateTo. The endpoint will set delegate property of the accessConfig of elementId to true or false. If true, the delegateTo query parameter is checked and used to set or update the delegateTo property.

commented
  • check why cascade is needed and cant filter by delegateTo Got error: Attribute delegateTo is not valid scalar type while running: (forum credentials).
  • why adding ~delegateTo to the "C" level, hides C2 and shows C1 and D1? it seems its because C2 don't have children (no one delegateTo to it). Maybe related to @cascade?
  • How can we use this query as an alias to set all the finDelegatedTo of the elements found by the query? even if not recursive. Using upsert
  • Can we do the @recursive query? (so that all children finDelegateTo are set with one upsert mutation)
  • If we cant, which is probably the case, because of multiple level query. Is it possible to change the data schema so that @recurse can be used? for example, remove the accessConfig node, set accessConfig as Perspective properties directly and use delegateTo pointing to a uid

So, this is the query that I worked around regarding the first point:

delegatingFromAccessConfigs as var(func: eq(xid, "${elementId}")) { accessConfig : ~delegateTo { uid } }

~delegateTo, is not an index, which doesn't allow us to perform a direct search as we do with the xid property. The nature of the ~delegateTo property it is that is referenced at a whole element through its uid, because that's how the design should be. The data type that is specified as uid is not allowed to behave as index, which won't let us have a direct function calling it.

So in order to avoid using @cascade and @filter directives, which would pull from us the opportunity to increase efficiency using a reverse edge, I implemented the following logic:

  • The reverse edge ~delegateTo, is designed to return all accessConfig elements that point to a specific perspective, that explains the use of the alias accessConfig in the previously shown query.

  • Regarding the reverse edge ~accessConfig, it is designed to return all perspectives that are pointing to a specific accessConfig element.

This obfuscates to my understanding, point 2, which indicates recursivity. It would be good to try it out with the new query.

However, I already tried the following query that implements hardcoded recursivity:

{ q(func: eq(xid, "zb2wwycfp1ML7DFZRBv4UhP8iKDmUy5wPNCpyrnx57QTiCGxL")) { accessConfig : ~delegateTo { uid perspectives: ~accessConfig { xid accessConfig: ~delegateTo { uid perspectives: ~accessConfig { xid } } } } } }

commented

It makes sense!

Now that this is solved and after reviewing a little better the dgraph documentation, I think its time to get rid of the AccessControl type, and just put all its properties (delegate, delegateTo, finDelegatedTo and permissions to the Perspective object itself).

Once done I would make sure we get the @recurse query working

Hello there!, working around the dgraph documentation, I finally found how to perform recursivity and it is pretty easy, we should only have in mind one rule:

You can specify only one level of predicates after root. These would be traversed recursively. Both scalar and entity-nodes are treated similarly.

Which means that we should avoid wrapping when specifying the data that we need, and these requires us to provide a pattern, which is the one that is going to repeat and form the tree.

Here is a an example of how a hardcoded recursive query would be:

  • The query is based on a parent perspective, "PerspectiveA", which has a lot of children and it is the final delegated of all the related nodes.

image

This query gives us the following result:

image

image

It can be easily noticed that the result returned four (4) UIDs, which are the children of the perspective of reference (note the green nodes in the graph above). If we do the same implementing recursivity, we can notice that we match the same result, but instead we will also receive more perspectives, which are the ones that point to the accessConfig we needed to get, being this a result of the pattern specified in the recursive query.

The following is an example following the recursive practice:

image

Notice that the depth parameter is set to a crazy number "100". According to the documentation, the parameter won't throw any error through the number specification, it will only throw an error if the depth limit is exceeded by the results, which I still can't figure it out in the docs.

This query gives us the following result:
Screenshot from 2020-08-21 20-11-30

We can easily notice in the above picture our four (4) accessConfig, the same received in the hardcoded query.

image

We can also notice it in the graph result.

So if we want to make an upsert, in which we take only the UIDs coming from our accessConfig, we will only need to identify something like this:

a as ~accessConfig: ~delegateTo .

But first, I would like to be sure about this recursive query, in order to follow up the pattern and achieve to properly identify the accessConfig variables and have them ready to perform the perfect mutation!.

commented

I closed the issue by mistake, thanks for reopening it. Your summary is super useful and clear @sotous.

It's interesting that you can use @recurse and ask for properties that will be available in some nodes, and not in others and vice-versa. The problem, as you say, is that you get the uids of the access configs and of the perspectives.

It seems that removing the distinction between the AccessConfig and the Perspective types and combining them into a single Perspective type that includes the access confgi properties should result in the recursive query only having one ~delegateTo and getting the uids of the child perspectives which can then be used to set their finDelegateTo.

I closed the issue by mistake, thanks for reopening it. Your summary is super useful and clear @sotous.

It's interesting that you can use @recurse and ask for properties that will be available in some nodes, and not in others and vice-versa. The problem, as you say, is that you get the uids of the access configs and of the perspectives.

It seems that removing the distinction between the AccessConfig and the Perspective types and combining them into a single Perspective type that includes the access confgi properties should result in the recursive query only having one ~delegateTo and getting the uids of the child perspectives which can then be used to set their finDelegateTo.

Well, regarding your comment it seems like I achieved to make the mutation, I am working on tests to completely proof that is working out.

image

This one seems to be our winner. Here what I am performing is to set delegate to false in PerspectiveB, that's why both XIDs are the same in the upsert query.

Before this upsert was done, all the child nodes pointing to the PerspectiveB had as a finDelegatedTo the PerspectiveA.

After running this upsert, since now PerspectiveB don't have any delegateTo, all child nodes have as a finDelegatedTo the PerspectiveB.

Here you can notice the difference:

  • Before the upsert

image

  • After the upsert

image

The logic that I am understanding is that when you set a variable for an attribute of the @recurse operation, the function will save the result into it, without caring about the type, which in this case can be an array or just a single element.

The upsert use the variable identifier a, applied later in the mutation. So, depending on what is inside a, the mutation will run n times:

uid(result1) <finDelegatedTo> uid(finDelegatedTo) .
uid(result2) <finDelegatedTo> uid(finDelegatedTo) .
uid(result3) <finDelegatedTo> uid(finDelegatedTo) .

Being each result an element inside the variable a, the loop will perform automatically.

Having this in mind, now I am working on tests to try out all the different scenarios and make sure that our practice is good enough. :)

commented

Ok, perfect @sotous . It seems the case when delegate passes from true to false is ready then.

Now we can focus on the case when it passes from false to true.

In that case:

  • the delegate property must be set to true,
  • the delegateTo property must be set to the delegateTo element id provided as input.
  • the finDelegateTo property must be set to the finDelegateTo of the delegateTo element.
  • the finDelegateTo of all the elements that have finDelegateTo to the current element must be changed to the new finDelegateTo too. Looks like the job for a ~finDelegateTo query and upsert.