I'm sure all 3 of these topics warrant their own separate issue but since I don't see issues about any of them I figured I would start one to get a general feel for if this functionality is in the pipeline and what kind of shape it will have when it does appear.

CommentFileSizeAuthor
#3 Subgroup inheritance.png58.88 KBkristiaanvandeneynde
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kristiaanvandeneynde’s picture

I've been thinking about this one for a while but haven't touched it so far until I get a good idea. Below are some roadblocks I've encountered so far.

If subgroups inherit permissions, how will they do so? Global group roles are always present on any group type, so they could be inherited. Same goes for group roles when the subgroup is of the same type as the parent. But what if the subgroup is of a different group type? Both groups could have group roles that are not present on the other.

Currently, any group type can be a subgroup of any group type. I like the flexibility this offers, but this makes the code base very agnostic. If we were to tie a subgroup type to a group type, we'd know which roles are susceptible to inheritance.

In such a scenario, wouldn't it perhaps be better to have a configurable inheritance scheme? For instance: "If Group type B becomes a subgroup of Group type A, give everyone with role A-X the permissions that are tied to role B-Y." That way, we wouldn't have to synch users over, but could check the scheme for access.

Perhaps you have any ideas to add to this concept?

ctrlADel’s picture

I gave this some thought and I think I've come up with a setup you may like. I'm not sure how easy it will be to implement but if its possible I think it would work quite well.

For content inheritance each group type should be configurable to inherit content from above/below/both maybe even be able to specify what type of content should be inherited. If I've interpreted how the module works right all this would do is not deny access to inherited content. Access to view/edit the content would still be dependent on the permissions of a user.

For user inheritance I went with a broader approach then you where you just specify inherit users from above/below/both and choose which roles should be applied to users based on if they are coming from above or below.

This broader approach though opens up a need for permission inheritance because you may not want to give all low level users being inherited the permissions that a high level user being inherited should have. So in the same vein as above allow each group type to specify inherit permissions from above/below/both. Ideally this would add permissions to a user by going up/down the groups and checking what permissions they have based on their roles until it reaches a group that is not configured to inherit permissions.

I don't think this will be an issue but I just want to make sure. If something like this was implemented whenever you created a group type it would get all the default settings but after creation you would be able to change the settings for a specific group right?

kristiaanvandeneynde’s picture

FileSize
58.88 KB

I've given this some thought and came up with the following statements:

  • If you create a Group Type with the purpose of it becoming a subgroup, chances are it will always be a subgroup
  • If we do live inheritance checks, the module will become a database nightmare
  • As a result, we are best of synchronizing memberships
  • Syncing should be done on the following events: create, update, delete membership
  • Syncing should be possible both top-down as bottom-up

So I came up with this:

Subgroup inheritance

Basically, what the happens is that you configure the subgroup details on a group type. I have yet to figure out whether I want that configuration on the parent or the child. While configuring this, you can specify what action to take on the following events:

  • Creation/Update in parent
  • Creation/Update in child
  • Delete in parent
  • Delete in child

Because node access is defined by permissions, this would automatically allow you to 'inherit' content from a subgroup or parent group.

We would probably require one more checkbox, though: "Re-synchronize existing memberships upon saving configuration". This button would loop over all existing memberships and adjust them accordingly when you changed the synchronization settings. Although I need to figure out how exactly we would go about that.

For instance:

  • Admin A used to synch into Admin B
  • This was a mistake and we now want sync Admin A into Member B
  • What to do with existing Admin B?
    • Keep them and risk having people as Admin B that shouldn't be?
    • Update all Admin B to Member B and risk demoting people that were manually set to Admin B?

Edit: We could perhaps keep track of a membership with a flag 'is_synchronized', much as Entity API has a flag for ENTITY_IN_CODE, ENTITY_CUSTOM and ENTITY_OVERRIDDEN. We could then re-sync only those memberships that were 'clean' synchronizations, leave manual memberships alone and run a diff on 'dirty' memberships.

ctrlADel’s picture

I can see how live checks could become a nightmare. Since I need subgroup functionality to move forward on my project I sat down yesterday started work on hard coding pretty much what you described for my use case so I want to thank you for the clear documentation and plentiful functions. It has made interacting with the groups and figuring out what I need to do fairly straightforward.

On topic though I think your solution would work it would just be rather clunky and perhaps confusing to setup. Instead of 'is_synchronized' perhaps 'inherited' might be a bit more clear that it's flagging memberships as inherited. Either way that type of flag would allow for treating inherited members differently like displaying them as inherited and not allowing a group admin to change the roles of an inherited user or remove an inherited user from the group.

kristiaanvandeneynde’s picture

Category: Feature request » Task

I'm glad you can find your way through the code, I was actually aiming for a developer friendly module :)

I totally agree on naming the property 'inherited' instead. About preventing the change of inherited memberships: I can see this go both ways, so perhaps it should become a toggle. As I said in my previous comment, we could easily track down which inherited memberships have become 'dirty'. We could even track if a membership was manually deleted.

Any way, seeing as I can appreciate the addition of this feature to ggroup, let's set this to Task.

ctrlADel’s picture

I was thinking about treating inherited users separately a little bit and I think that there really needs to be quite a bit behind it. I'm trying to imagine multiple use cases but I can't come up with one where somebody would want a bottom/middle level group administrator to be able to break an inheritance chain which is what could happen if inherited memberships were treated as normal memberships. The most common use cases I keep coming back to are inherited users will be treated as submembers with limited roles, inherited users will be treated as administrators/supermembers with more roles then most group members, and in some cases an inherited member may need to be promoted/demoted to the level of a normal group member without changing their membership in the root group.

I think this could all be addressed with a new permission 'Add inherited users to group' or something similar. It would allow users with that permission to change the status of inherited memberships from inherited to active. Then the memberships could be treated the same as normal memberships but still retain their inherited state. It does get kind of hairy when you talk about deleting memberships and changing roles though. I'll try to explain my thoughts below and you can find the holes I'm sure are there.

I'm working on the assumption that a membership will have a property 'inherited' that will identify if it was inherited rather then manually added to a group and that 'Inherited' and 'Inherited-Blocked' states can be added to a memberships status. With the addition of the 'Inherited' status it makes it possible to differentiate between inherited memberships that have been changed to normal memberships and inherited memberships that are still inherited.

For deleting memberships I think it should look something like this

  • If a root membership is canceled all the connected inherited memberships above/below should be deleted.
  • If an inherited membership has been changed to a normal membership and the root membership from above/below is deleted the membership should not be deleted but it should be changed to show it is no longer an inherited membership.(Set the 'inherited' flag to show it is not inherited. Also maybe a toggle on the root memberships deletion confirmation page to override this)
  • If an inherited membership has been changed to a normal membership and the membership is then canceled it should be reset to inherited.

For roles maybe something like this

  • If a root membership role is changed or the relation is changed for group->subgroup then that change should propagate to all the inherited memberships.
  • When an inherited membership is changed to a normal membership it should retain all the roles it had from being inherited.
  • If an inherited membership has been changed to a normal membership that membership's roles should not change if the root membership's roles change but any inherited memberships above/below should still change as if it was still inherited.
  • If an inherited membership has been changed to a normal membership and the roles have been changed and then the normal membership is canceled and the membership is set back to inherited it should be granted all the roles it should have as an inherited member.
  • If an inherited membership has been changed to a normal membership and its roles have been changed it should not affect inherited memberships above/below it.(That's the tricky part I think)

And finally for membership status

  • If an inherited membership is changed from inherited to normal the status should change from 'Inherited' to 'Active'
  • If an inherited membership has been changed to a normal membership and the normal membership is then canceled the membership status should be set back to 'Inherited'
  • If an inherited membership has been changed to a normal membership and the normal membership is set to 'blocked' nothing above/below should change.
  • If a root membership is set to blocked then all inherited memberships should also be set to blocked. If it is inherited still set it to 'inherited-blocked' if it is a normal membership set it to 'blocked'

Now that I've written it all down it sounds like it might be overly but I guess that comes with the territory when trying to address multiple levels of subgroups and membership states.

kristiaanvandeneynde’s picture

Most of what you've written down makes sense.

I'm also starting to think you're right on a bottoms-up scenario being hard to pull off:

  • User "John" joins group "Retailer A" as "Customer", making him "Customer" in group "Corporation"
  • User "John" joins group "Retailer B" as "Manager", making him "Staff" in group "Corporation"

We could merge both of John's roles on the Corporation level, and we could even rebuild the inherited roles when one of his Retailer memberships is deleted. But as soon as his Corporation membership becomes 'dirty' (modified), it's a whole different ball game. For example: There is no way to make sure we didn't intend John to be a Staff member no matter what. So if he leaves Retailer B, what then?

Detecting changes can only work well if we limit the inheritance source to one, ergo: top-down. And even then we need some sort of 'Break inheritance' button to allow us to keep certain members should a resync delete all others. Example:

  • School X has several Janitor memberships, granting them the "Cleaning crew" role in all Class groups
  • Only janitor "Heisenberg" has the degree to clean up the Lab Class, so he needs to be fixed to Lab Class (breaking the inheritance)
  • School X decides to reassign the Janitor role to drop cleaning duties, and grants the cleaning duties to the role "Cleaning lady" instead
  • Because we broke the inheritance for Heisenberg in Lab Class, he retains his cleaning abilities
  • Ideally, you'd kick the cleaning lady out of the lab too :)

Perhaps we need to use the already existing membership status functionality:

  • Inherited: The membership is inherited from above and can be automatically deleted from above.
  • Inherited (overridden): The membership is inherited from above but has since been changed. Any synchronization from above will still take place, after which the manual changes will be reapplied. This can go both ways: granting extra roles or revoking some roles.
  • Active: A regular membership, this status is also granted after fully breaking inheritance on a membership
kristiaanvandeneynde’s picture

I've done quite some work on this already, next task is to check of all the "when ... then ..." scenarios from #6. Make sure to run update.php after pulling the latest code.

ctrlADel’s picture

I'm back again! Got distracted by some other parts of my site but it's nice to see you have made some progress.

After playing around with it a bit I noticed that members that were added to parent groups were not being inherited down is that how it is supposed to work?

Also it took me far to long to figure out that the member who makes the subgroup does not also get assigned the roles they would normally inherit. I assumed that was how it would work and think it would make sense for the members roles to be inherited by default.

Other then those 2 things it looks like it is coming a long nicely.

Soul88’s picture

Status: Active » Closed (outdated)

We thank everyone for their collaboration on this issue, but as the D7 version is no longer supported, we will now close all D7 issues to keep the issue queue a bit tidier. This information won't go anywhere, it just won't show up on the list of open issues anymore.

Please see: https://www.drupal.org/project/group/issues/3163655 and https://www.drupal.org/project/group/issues/3203863#comment-14100281 for more details.