Multiple access levels: How to get there

The plugins Quasi Access and Granular Access provide a couple ways to associate multiple ACLs with content. I have an internal plugin that does something similar (manages an ACL binding zero or more users and ACLs) and a design for how I think Elgg core would provide this flexibility.

My knowledge of Granular Access is limited. My reading of Quasi Access is that it builds a new "quasi" ACL (and object) for every possible combination of ACL and doesn't actually populate those ACL members. When it's time to build an access query, it looks up all the ACLs the current user should see and stuffs them into the existing list going into the SQL. This certainly seems better than giving each content its own ACL and linking all the right users to it (which requires rebuilding that list each time a user leaves/joins one of the groups, etc).

I'd like to know the longer-term scaling challenges with these approaches; where we think we'll hit pain and what we could do at that point.

I'm also wondering if there's a path for slowly integrating my preferred schema into the current system. What if Elgg wrote to both storage schemas, but required a switch to read from the new one?

Part of me thinks that getting from here to there is hopeless without fully rebuilding Elgg, in which case we should just endorse some plugin and pour all effort into optimizing it. Or what if we could add a table or two to hack this in in a way that was as fast as possible?

Where do we go from here?

  • Let's say we want to add a new ACL level of ACCESS_FRIENDS_OF to core, to allow sharing context with people that have friended the poster. 

    Now imagine how that blows up our current access system. 

    Whenever I have to implement a generic solution with Elgg relationships, I take "friends of" as the base for my thinking. It usually complicates things so much that I find an alternative solution.

  • We could provide a simple way to automatically track the inverse relationship under a different relationship name. Then if you add a relationship, Elgg would also add the inverse automatically. same if you delete.

    So the inverse of "members" might be "memberships". If you add a user 345 to /123/members, Elgg transparently also adds 123 to /345/memberships.

    Now both are available and you can use whatever "direction" makes sense but without having to really think about direction (I always found "inverse" hard to wrap my head around).

    "friends" inverse could be "friended_by". ("Friends of" I also find ambiguous...)

    Adding 123 to 345/friends would therefore add 345 to 123/friended_by. Now there's two lists and two acls to use whichever way makes sense and the name makes it clear what we mean by the relationship.

  • So, what happens when you want to create a system where all friend relationships are bilateral? Do you have 4 different records to mean the same thing?

  • You could set the inverse of the relationship to be the same relationship, so it's even easier to get automatically.

    If the inverse of "friends" is "friends", then you're golden.

  • Ok, current schema allows us to retrieve second level relationships:

    Category 1.1.1 is 'child_of' Category 1.1 that is a 'child_of' Category 1. I can use an SQL query to find all second level children of Category 1. The new API would make that a nightmare.

    My point is that I really like how the current relationship schema allows you to write wonderful SQLs to get exactly what you need. I am afraid Lists schema would negate that possibility.

  • @Ismayil In the system @Evan described, yes i think so.

    In practice I think Ismayil's suggestion would be simple enough. An ACL is just a pointer to a set of relationships with an indication of which is GUID1.

    You then get either ACL without duplicating all the data. It does mean that the query has to include both directions, probably not a deal breaker.

  • Just think about how powerful a relationship is. Two table rows (1, friend, 2) and (2, friend, 3) in their simplest form allow us to use SQL to:

    - Get all users who friended 2
    - Get all users who were friended by 2
    - Get all users who have common friends but are not friends yet
    - Get all users who have at least one friend in common
    ... use your imagination

  • I do like the idea of requiring relationships to have two words, one for each direction, and the system reserves both. No duplication of data, and you don't chose a "direction" but instead the word you want.

    E.g. let's say you register the name pair: ("member_of", "has_member")

    Now (123, member_of, 234) would be equivalent to (234, has_member, 123).

    In a query to list members: "relationship" => "member_of", "relationship_guid" => 234.

    In a query to see what groups I'm in: "relationship" => "has_member", "relationship_guid" => (me)

  • More examples:

    ("friended", "friended_by")
    ("subscriber", "has_subscriber")
    ("role:moderates", "role:has_moderator")

    This would basically register the 2nd word as an alias for the first in the opposite direction (we wouldn't need to alter the schema).

  • I don't know about you, but after all these years, when I see an Elgg relationship, that's exactly how I read it. 

    1 "member" 2

    1 is member of 2 (inverse = false)

    2 has a member 1 (inverse = true)

    IMHO, inverse relationships are easier to understand. Now imagine you use ege_from_relationship(), and you want to get all the blogs that have a subscriber whose guid is x. I think I have more trouble figuring out who a user is a to a blog if there are two relationship names that symbolize the same thing in opposites direction.

Feedback and Planning

Feedback and Planning

Discussions about the past, present, and future of Elgg and this community site.