How to create sub group in D8 version

CommentFileSizeAuthor
#271 port-subgroups-2736233-271.patch117.34 KBandrewsizz
#270 port-subgroups-2736233-270.patch117.33 KBandrewsizz
#261 interdiff-254-261.txt12.4 KBlobsterr
#261 port-subgroups-2736233-261.patch141.16 KBlobsterr
#255 interdiff_253-254.txt3 KBadrianodias
#255 port-subgroups-2736233-254.patch141.73 KBadrianodias
#253 port-subgroups-2736233-253.patch144.51 KBlobsterr
#253 interdiff-252-253.txt1.52 KBlobsterr
#252 interdiff-252-244.txt14.47 KBlobsterr
#252 port-subgroups-2736233-252.patch144.5 KBlobsterr
#244 interdiff-241_244.txt762 byteslobsterr
#244 port-subgroups-2736233-244.patch136.17 KBlobsterr
#241 interdiff-236-241.txt14.02 KBlobsterr
#241 port-subgroups-2736233-241.patch133.57 KBlobsterr
#236 port-subgroups-2736233-236.patch139.02 KBjcmartinez
#225 port-subgroups-2736233-225.patch138.8 KBlobsterr
#225 interdiff-218-225.txt491 byteslobsterr
#218 interdiff-216-218.txt2.6 KBlobsterr
#218 port-subgroups-2736233-218.patch138.81 KBlobsterr
#216 port-subgroups-2736233-216.patch136.57 KBdangur
#215 interdiff-212-215.patch68 bytesdangur
#212 port-subgroups-2736233-212.patch136.57 KBQuicksaver
#208 interdiff-205-208.patch158 bytesdangur
#208 port-subgroups-2736233-208.patch135.31 KBdangur
#205 port-subgroups-2736233-205.patch135.26 KBlukedekker
#203 interdiff_200-203.patch4.41 KBlukedekker
#203 port-subgroups-2736233-203.patch135.26 KBlukedekker
#201 interdiff_189-200.patch16.73 KBlukedekker
#201 port-subgroups-2736233-200.patch135.25 KBlukedekker
#199 interdiff_189-199.patch16.78 KBlukedekker
#199 port-subgroups-2736233-199.patch135.26 KBlukedekker
#189 interdiff_182-189.patch2.8 KBlukedekker
#189 port-subgroups-2736233-189.patch134.43 KBlukedekker
#185 interdiff_182-185.txt983 bytessteveworley
#185 array_replace-2736233-184.patch133.69 KBsteveworley
#182 interdiff_179-182.patch2.31 KBlukedekker
#182 port-subgroups-2736233-182.patch133.51 KBlukedekker
#179 interdiff_174-179.txt2.48 KBlukedekker
#179 port-subgroups-2736233-179.patch133.09 KBlukedekker
#177 interdiff-164-177.txt428 bytesfloydm
#177 2736233-177.patch127.88 KBfloydm
#174 interdiff_170-174.patch8.04 KBlukedekker
#174 port-subgroups-2736233-174.patch133.08 KBlukedekker
#170 interdiff_164-170.patch10.62 KBlukedekker
#170 port-subgroups-2736233-170.patch132.13 KBlukedekker
#165 2736233-164.patch127.83 KBfloydm
#164 interdiff_156-164.txt662 bytesfloydm
#164 2736233-156.patch127.74 KBfloydm
#163 drush_cache_rebuild.png11.73 KBsketman
#162 subgroup_content_does_not_get_deleted.png60.28 KBsketman
#159 interdiff_157_158.txt2.03 KBhlopes
#159 2736233-158.patch132.7 KBhlopes
#157 interdiff.txt742 bytesdylan donkersgoed
#157 2736233-157.patch132.71 KBdylan donkersgoed
#156 interdiff-153-156.txt5.72 KBseanb
#156 2736233-156.patch127.74 KBseanb
#155 Screen Shot 2018-04-17 at 3.13.27 PM.png255.41 KBpaul kim consulting
#153 interdiff-150-153.txt919 bytesseanb
#153 2736233-153.patch127.67 KBseanb
#150 interdiff-149-150.txt31.57 KBseanb
#150 2736233-150.patch127.66 KBseanb
#149 interdiff-141-149.txt723 bytesseanb
#149 2736233-149.patch124.33 KBseanb
#145 interdiff-2736233-141-145.txt2.97 KBryandekker
#145 group-add_subgroups_module-2736233-145.patch126.97 KBryandekker
#141 interdiff-2736233-140-141.txt3.59 KBarosboro
#141 group-add_subgroups_module-2736233-141.patch124.28 KBarosboro
#140 interdiff-2736233-138-140.txt873 bytesarosboro
#140 group-add_subgroups_module-2736233-140.patch123.79 KBarosboro
#3 groups-add_subgroups_module-2736233-3-D8.patch55.61 KBjludwig
#45 groups-add_subgroups_module-2736233-45-D8.patch106.78 KBCalebD
#45 interdiff-2736233-3-45-do-not-test.diff53.45 KBCalebD
#46 groups-add_subgroups_module-2736233-46-D8.patch106.89 KBCalebD
#52 group.zip221.82 KBManmohan
#55 group-add_subgroups_module-2736233-55-D8.patch106.91 KBCalebD
#56 group-add_subgroups_module-2736233-56-D8.patch111.95 KBmitsuroseba
#56 interdiff-2736233-55-56-do-not-test.diff5.03 KBmitsuroseba
#57 group-add_subgroups_module-2736233-57-D8.patch111.09 KBmitsuroseba
#57 interdiff-2736233-55-57-do-not-test.diff4.18 KBmitsuroseba
#59 group-add_subgroups_module-2736233-59.patch112.32 KBmhmhartman
#59 interdiff-57-59.patch4.23 KBmhmhartman
#62 interdiff-57-60.patch4.23 KBmhmhartman
#62 group-add_subgroups_module-2736233-60.patch112.32 KBmhmhartman
#64 group-add_subgroups_module-2736233-64.patch112.14 KBmhmhartman
#64 interdiff-57-64.patch4.06 KBmhmhartman
#67 group_filter.png126.27 KBgaydamaka
#67 sql_query.png161.69 KBgaydamaka
#67 group-add_subgroups_module-2736233-67.patch112.14 KBgaydamaka
#67 interdiff-2736233-64-67.txt667 bytesgaydamaka
#69 group-add_subgroups_module-2736233-68.patch112.16 KBgaydamaka
#69 interdiff-2736233-64-68.txt667 bytesgaydamaka
#70 group-add_subgroups_module-2736233-70.patch112.2 KBgaydamaka
#70 interdiff-2736233-68-70.txt795 bytesgaydamaka
#72 group-add_subgroups_module-2736233-72.patch112.19 KBgaydamaka
#72 interdiff-2736233-68-72.txt770 bytesgaydamaka
#73 group-add_subgroups_module-2736233-73-TEST_ONLY.patch117.52 KBgaydamaka
#73 group-add_subgroups_module-2736233-73.patch117.58 KBgaydamaka
#73 interdiff-2736233-68-73.txt5.39 KBgaydamaka
#76 group-add_subgroups_module-2736233-76.patch117.7 KBgaydamaka
#76 group-add_subgroups_module-2736233-76-TEST_ONLY.patch117.67 KBgaydamaka
#76 interdiff-2736233-68-76.txt5.38 KBgaydamaka
#83 group-add_subgroups_module-2736233-83.patch117.25 KBgaydamaka
#83 interdiff-2736233-76-83.txt917 bytesgaydamaka
#85 group-add_subgroups_module-2736233-85.patch117.4 KBrigoucr
#85 interdiff-2736233-83-85.txt1.01 KBrigoucr
#88 2736233-views-data-compatibility.patch1.05 KBspheresh
#92 group-add_subgroups_module-2736233-92.patch117.73 KBmitsuroseba
#92 interdiff-2736233-85-92.txt639 bytesmitsuroseba
#95 group-add_subgroups_module-2736233-95.patch134.92 KBseanb
#95 interdiff-92-95.txt64.09 KBseanb
#97 group-add_subgroups_module-2736233-97.patch136.36 KBseanb
#97 interdiff-95-97.txt3.12 KBseanb
#98 group-add_subgroups_module-2736233-98.patch138.09 KBseanb
#98 interdiff-97-98.txt15.69 KBseanb
#102 group-add_subgroups_module-2736233-102.patch117.67 KBseanb
#102 interdiff-98-102.txt55.53 KBseanb
#104 group-add_subgroups_module-2736233-104.patch117.67 KBjayelless
#104 interdiff-2736233-102-104.txt752 bytesjayelless
#113 group-add_subgroups_module-2736233-113.patch113.25 KBmgalalm
#114 group-add_subgroups_module-2736233-114.patch117.69 KBmgalalm
#115 group-add_subgroups_module-2736233-115.patch118.6 KBseanb
#115 interdiff-104-114.txt1.06 KBseanb
#115 interdiff-114-115.txt7.78 KBseanb
#118 group-add_subgroups_module-2736233-118.patch118.72 KBseanb
#118 interdiff-115-118.txt1.85 KBseanb
#119 unexpectedproblem.PNG4.42 KBkaizerking
#121 group-add_subgroups_module-2736233-121.patch118.61 KBseanb
#121 interdiff-118-121.txt2.82 KBseanb
#125 group-add_subgroups_module-2736233-125.patch118.66 KBericras
#125 interdiff-2736233-121-125.txt2.57 KBericras
#126 group-add_subgroups_module-2736233-126.patch118.66 KBericras
#126 interdiff-2736233-121-126.txt2.58 KBericras
#127 group-add_subgroups_module-2736233-127.patch119.89 KBseanb
#127 interdiff-2736233-126-127.txt3.1 KBseanb
#128 group-add_subgroups_module-2736233-128.patch122.5 KBjts86
#129 interdiff-2736233-127-128.txt2.6 KBjts86
#129 group-add_subgroups_module-2736233-129.patch123.18 KBjts86
#129 interdiff-2736233-128-129.txt2.48 KBjts86
#130 Selectie_024.png46.07 KBparijke
#133 Screenshot from 2017-09-02 14-16-13.png336.43 KBAnonymous (not verified)
#134 interdiff-129-134.txt991 bytesidebr
#134 group-add_subgroups_module-2736233-134.patch128.1 KBidebr
#135 group-add_subgroups_module-2736233-135.patch124.95 KBnikolabintev
#138 group-add_subgroups_module-2736233-138.patch123.28 KBmitsuroseba
#138 interdiff-134-138.txt1.94 KBmitsuroseba
#139 interdiff-2736233-138-139.txt772 bytesarosboro
#139 group-add_subgroups_module-2736233-139.patch123.69 KBarosboro

Comments

kaizerking created an issue. See original summary.

kristiaanvandeneynde’s picture

Title: How to create sub group » Port Subgroup (ggroup) to the D8 version
Category: Support request » Task
Status: Active » Postponed

Although, this could be easily enabled by writing a small plugin, the Group 7 version of this did a lot more. I.e.: membership inheritance and synchronization. This is on the to-do-list, but only as an addition after a 1.0 release.

jludwig’s picture

Status: Postponed » Needs work
StatusFileSize
new55.61 KB

Attached is a patch to get things rolling here. This will allow you to add existing/new subgroups and view an overview off all the subgroups associated with a group.

Not this much code was needed to actually allow subgrouping functionality (the minimum would be basically just the content enabler plugin), but this was created by basically copying the gnode module and changing it to deal with groups instead of nodes, so implements all of the same functionality that gnode does except... (get this)...

...Access control!

So this is put as needs work, because it needs:

- Stronger access control
- Features from the D7 version (membership inheritance, synchronization, etc)
- It should probably be treated more uniquely. Not everything in the gnode module makes sense in the module and vice-versa.

This is still, however, very usable if all you need to do is add groups to groups.

Cheers!
-Justin

matslats’s picture

This looks more thorough than my contribution at https://www.drupal.org/node/2699287
I'm keen to get this committed because I have a lot to build on top of it.

zerolab’s picture

Related issues: +#2699287: Subgroups
jludwig’s picture

Hey matslats,

I didn't see that base module that you had committed in that other issue. Sorry! that would have been a good place to start from and it looks almost exactly like the plugin I had written before fleshing it out.

kristiaanvandeneynde, make sure to give matslats some credit if this goes in because his contribution is pretty much exactly what we talked about at DrupalCon.

kristiaanvandeneynde’s picture

Right closing the other issue then in favor of this one.

Just to emphasize the instructions I wrote there:

  • Start off with a GroupContentEnabler plugin that does nothing more than allow you to add groups to other groups.
  • Use a deriver, just like the group_node plugin does to create a plugin derivative per group type.
  • In your plugin's configuration form, read the roles from the group type you're on AND from the group type you're targeting.
  • Then build a UI that says "People with role X will receive role Y in child groups", perhaps a list of checkboxes per role or a matrix. (table of checkboxes)
  • When a person's permissions are checked, see if the group has a parent group and try to read the roles from there. Perhaps this should be recursive so that you can inherit from grandparents and other ancestors too.

That would be a good start!

kristiaanvandeneynde’s picture

Adding matslats to the fixed credit receivers.

matslats’s picture

The conventional way to create new entities here and in gnode in a group is to provide a new entity form to create the entity, then redirect to another form which creates the GroupContent.
This is a weird user experience though. What if we made a CreateEntityForm for every contentEntity?
group/{group}/node/add/story
which inherits everything but in the submit method, it just creates the groupContent

alan.upstone’s picture

#9 Gets my vote. My users don't care about the relation. I care a lot as the site builder but they just want to create content. It's me that has divided them into groups.
In the current two-step process, they say "Didn't I just do that?"

matslats’s picture

Well here's how I'm doing it

/**
 * Implements hook_ENTITY_TYPE_create().
 * Take the group from the request and add it as a temp property to the new entity.
 * (Doesn't work for scripted entities e.g. devel_generate)
 */
function hook_myentitytype_create($entity) {
  $params = \Drupal::routeMatch()->getParameters();
  if ($params->has('group')) {
    $entity->group = $params->get('group');
  }
}

/**
 * Implements hook_smallad_insert().
 * read the temp property and create the GroupContent
 */
function hook_myentitytype_insert($entity) {
  if (isset($entity->group)) {
    $props = [
      'type' => $entity->group->getGroupType()-id().'-myentitytype-'.$entity->bundle(),
      'gid' => $entity->group->id(),
      'entity_id' => $entity->id(),
    ];
    GroupContent::create($props)->save();
  }
}
/**
 * Implements hook_smallad_insert().
 * Override the entity's add-form link with a new path which includes the group
 */
function hook_entity_type_alter(&$entity_types) {
  //this new path must be declared in the mymodule.routing.yml
  $entity_types['myentitytype']->setLinkTemplate('add-form', '/group/{group}/myentitytype/add');
}
kristiaanvandeneynde’s picture

The need to hide the relationship form is a strong sentiment I want to cater to. The first iteration of that crashed and burned as I realized we would potentially have a security issue, incomplete data and a performance hit on our hands.

Maybe we should open a ticket to discuss the options regarding the workflow in the Group Node module and then copy the solution we found there into Subgroup?

matslats’s picture

>security issue, incomplete data and a performance hit
Does this apply to my solution in #11?
How does organic groups module do it?

kristiaanvandeneynde’s picture

When I tried a version where you could have the form auto-submit itself, I came to realize that links such as /group/X/join would also auto-submit the form, meaning we are open to click-jacking attacks.

So ideally, there needs to be a setting on the plugin that allows you to choose whether you want to use the wizard (2-step) or just the node creation form (1-step). That way, we do not risk having auto-submitting links that could potentially be click-jacked.

matslats’s picture

I see the problem but you didn't comment on either of my two ideas.
1) Dynamically create a new entityForm for every GroupContent plugin installed with a new path prefix (which informs the route context) then use the submit handler of that extended entityForm to create the GroupContent entity.
2) Create new routes for every GroupContent plugin installed and use the entity create hook to get the group from context, and create the GroupContent with the hook_entity_insert
Both of these approaches involve making a new route with the group in, which means new content can go into a maximum of one group.

matslats’s picture

Still hoping for answers for #15. But this is a question about the new subgroup module.
There is a global group permission (appears in every group) called Access subgroup overview.
Seems to me it should only appear in groups with subgroups, no?
In which case the permission should be declared in
Drupal\ggroup\Plugin\GroupContentEnabler\SubGroup::getPermissions
and referenced in
Drupal\ggroup\Plugin\GroupContentEnabler\SubGroup::getGroupOperations

kristiaanvandeneynde’s picture

I'll have a thorough look at #15 shortly. Probably tomorrow.

kristiaanvandeneynde’s picture

Re #15:
1) I would not like to add or generate individual forms per plugin. I'd prefer to have a solid base for every scenario that other modules could then extend or alter. E.g.: CreateContentInGroupForm and GroupContentCreateWizardForm.

2) We just abandoned the path of generating routes for every single group content type (plugin) because it was too annoying to maintain. I'd prefer to see paths such as:

  • group/1/content/relate/{entity_type_id} to add existing entities
  • group/1/content/add/{entity_type_id} to add new entities to the group

Where the latter path would either use the simple for or the wizard as outlined in my reply to your first suggestion.

The key here is simplicity and reusability. We want solutions that offer good UX in the front end, without sacrificing developer sanity in the process. Having code that's easy to extend or re-use is the key to make the module loved by developers as well.

Re #16, that permission could perhaps be used for a view at group/X/groups. Much like the group node and members view.

matslats’s picture

I can develop this, but I need clearer instructions.
I don't see in your last comment which way you want to avoid a second stage form.

kristiaanvandeneynde’s picture

I would use a plugin config with radio buttons:

When people want to create content in this group they:

  • Are presented with just the content form.
    Warning: If you configured fields on the relationship, these will not be filled out!
  • Are presented with a wizard to both create the content and fill out the relationship's fields.

Then based on that setting, we could fire up the wizard or the single creation form. Relating content to groups can keep using the form we already have. I.e.: With the entity reference field and the relation's configured fields.

Plugins could then choose which option they want to default to and call it a day. They could even choose to lock the setting and not show the radio buttons if it would break when another method is selected; e.g.: group_membership

matslats’s picture

OK that's clear
How will 'my_entity's creation form be built for the second option?
Will the original creation form be altered by the ContentEnabler plugin?
Will it add a submit handler which creates the groupcontent?

kristiaanvandeneynde’s picture

Please see #2796197-24: Group or Group Node generates some massive queries, we will have to remove hook_group_user_roles_alter(). If you want to move this issue ahead, look at the approach in Group 7. It involves saving memberships and linking those back to the parent that allowed them to exist.

This one just got more complicated sadly, but it's to allow us to have consistent cache contexts and performant grants, so it has to be done.

matslats’s picture

I don't see the connection, and I'm not going to get involved in that other issue.
While I'm waiting however, and building my own distro on groups, and my own contentEnabler plugins, any directions you can give about how this issue is going to work out would be appreciated.

kristiaanvandeneynde’s picture

The connection is that the hook we could have used to make Subgroup a really simple and streamlined module, will have to be removed.

CalebD’s picture

I'm interested in contributing some development of the subgroups feature. We need it for a project we're working on. Has anyone made any additional progress toward kristiaanvandeneynde's outlined approach in comment #7 starting with jludwig's module in comment #3? I'd like to start from whatever has the most progress toward the functionality.

jludwig’s picture

I'm interested in contributing some development of the subgroups feature. We need it for a project we're working on. Has anyone made any additional progress toward kristiaanvandeneynde's outlined approach in comment #7 starting with jludwig's module in comment #3? I'd like to start from whatever has the most progress toward the functionality.

The code I added in #3 did the following out of #7:

  • Start off with a GroupContentEnabler plugin that does nothing more than allow you to add groups to other groups.
  • Use a deriver, just like the group_node plugin does to create a plugin derivative per group type.

It does some more, but does not approach these:

  • In your plugin's configuration form, read the roles from the group type you're on AND from the group type you're targeting.
  • Then build a UI that says "People with role X will receive role Y in child groups", perhaps a list of checkboxes per role or a matrix. (table of checkboxes)
  • When a person's permissions are checked, see if the group has a parent group and try to read the roles from there. Perhaps this should be recursive so that you can inherit from grandparents and other ancestors too.
kristiaanvandeneynde’s picture

Great to see other people working on this. Thanks guys!

CalebD’s picture

I just wanted to say that I do plan on starting in on this effort either tomorrow or Monday. We had to focus on getting our Group setup configured first.

CalebD’s picture

Assigned: Unassigned » CalebD
dmiric’s picture

Ggroup module can not be enabled if there are no groups on the site. Basically form installation profile.

It returns:

Exception: No entity type for field type on view subgroups in                                                            [error]
/var/www/dv/docroot/core/modules/views/src/Plugin/views/HandlerBase.php:697
jludwig’s picture

Ggroup module can not be enabled if there are no groups on the site. Basically form installation profile.

It returns:

Exception: No entity type for field type on view subgroups in [error]
/var/www/dv/docroot/core/modules/views/src/Plugin/views/HandlerBase.php:697

Aye. gnode has the same issue if no content types have been defined.

kristiaanvandeneynde’s picture

Has anyone submitted a bug report for that?

CalebD’s picture

Kristiaan, wondering if you have any additional thoughts on how this should work? I wrote some ideas below. Interested in what you agree or disagree with.

Here is a thought experiment concerning groups, subgroups, and user membership. If Group B is added as a subgroup of Group A, then all members of Group B can be said to be indirect members of Group A (agreed?). Should $group_a->getMembers(); return a flattened list of all members of Group A and Group B (and descendant groups, recursively)? What about the other way around? I am thinking $group_b->getMembers(); shouldn't return Group A members because membership is recursive descent? Roles could be recursively mapped into the roles of Group A.

I looked at the Drupal 7 version of ggroup and it seems to have an inheritance concept whereby group_membership entities are created based on inheritance configuration. I'd like to avoid anything like that and make the behaviors of subgroups as seamless and intuitive as possible. There seems to be a lot of fuzziness in how certain things could be handled.

Basically, I can come up with some behaviors based on how we'd like it to work for our use case, but if we're going to contribute back I'd like to build something that the community could use.

jludwig’s picture

@CalebD IMO, that's a tough one. I, for one, would not want the children to inherit the memberships because I would want to know exactly who is in that specific child. No more, no less.

A good example is the university setting. You wouldn't want every single person in a department to be a part of the classrooms associated with that department, right? Otherwise, that department member might be in dozens of groups, receive emails for dozens of groups, etc, and you wouldn't know if they were really a part of that group or a part of the staff overseeing the classroom.

Permissions, on the other hand, make sense. The members of the department, with the right permissions, should be able to see basically anything in any classroom that is associated with the department.

If we cannot comet to an agreement, I would at least argue that this should be configurable. Both functionalities make sense in certain circumstances.

CalebD’s picture

@jludwig, in that scenario if the department is a group and the classes are each a group, and the class groups are part of the department group, then $department->getMembers(); would return a list of everyone directly in the department group as well as all the class members, while $some_class->getMembers(); would return only the members of the class because what I was proposing is that membership is only inherited by descent. Or am I misunderstanding your example? Either way, I do agree that direct inheritance may not be desired, or there needs to be a way to disambiguate between direct and indirect members. Maybe it is a configuration option on the plugin?

My use case is using the gnode to control access to content. We have a lot of different groups of users. To grant access to some content, instead of adding a node to all those groups, we'd prefer to add the node to a "grouping" group, one that has all the user groups added as subgroups. Then in the future if we have another group of users who need access to that content, we just add their group to the grouping group as a subgroup and those users would be given the same node access permissions.

Parent "grouping" group ← node added to this group, permissions grant members view access
    Child subgroup ← users added to this group

Given that you created the initial D8 version of ggroup, what was the use case?

CalebD’s picture

One approach I am thinking about is having ggroup maintain the hierarchy data of the subgroups. GroupMembershipLoader would be modified to fire events when loading memberships giving other modules a chance to react. ggroup would react by looking at the given group, finding the proper content plugin, checking if an "inherit membership" option is enabled, and if so pulling group membership for all descendant groups in the hierarchy to add to the event data.

Group hierarchy would be stored by having ggroup create a text field on the group content type that would store hierarchy data using the "path enumeration" technique (similar to how Drupal stores comment thread structures). Querying against that field should allow for efficient joins to grab the membership of all descendant groups given a starting group.

Interested in feedback. Thanks!

CalebD’s picture

I realized my use case is more complex than I originally realized. Because a group can have any number of child groups and a group can have any number of parent groups, the result is a graph structure. Unfortunately relational databases don't excel at dealing with graphs. I'm currently researching approach ideas.

As an aside, I recognize my use case is probably much more complex than others. We're wanting to build a flexible access control system and groups within groups is a core component of that flexibility. I don't want to derail anyone else's vision of how this could be implemented, so I'm still interested in input from others.

matslats’s picture

I'd appreciate if we could have some code committed here, just to be going on with. I've built a lot on jludwig's patch and I've things to add.
- a block showing subgroups of the current group
- a devel_generate base plugin

kristiaanvandeneynde’s picture

One approach I am thinking about is having ggroup maintain the hierarchy data of the subgroups. GroupMembershipLoader would be modified to fire events when loading memberships giving other modules a chance to react. ggroup would react by looking at the given group, finding the proper content plugin, checking if an "inherit membership" option is enabled, and if so pulling group membership for all descendant groups in the hierarchy to add to the event data.

This would be a good way to deal with things. We should avoid having code in the Group class that knows there may be subgroups. Firing events from within the GroupMembershipLoader would be great.

That said, I do not think we should have an unconfigurable inheritance system. We now have the benefit of configurable plugins, so let's use those to their best abilities. The UI we have in place in D7 could use some UX love, but it's a good start.

Like in D7, synchronizing memberships so that we actually have them in the database is a good solution too. So far, relations have always been top-down but do we also want to cater to bottom-up?

A teacher in a faculty should get privileges in all class rooms there (top-down). But do we also want to let students from those class rooms see a faculty-only message (bottom-up)? In that case, we need to be careful that inherited memberships do not trigger an endless loop.

matslats’s picture

Sound to me like the subgroup Enabler plugin needs to have an option to inherit membership from the parent or to create memberships in the parent or do nothing.
I would be happy to add that feature if you give me the go-ahead.

kristiaanvandeneynde’s picture

Please look at the way the D7 ggroup module does it to get an idea of what that inheritance option may look like. But yeah, feel free to work on something already :)

matslats’s picture

I've installed d7 and looked at it. I see how the roles inherit.
What I was offering to do was create the mechanism for passing members up and down the hierarchy when groups are created, which is what CalebD was talking about.
Shouldn't that be done first, then it can be extended to handle roles other than 'member'?

CalebD’s picture

matslats, I'm not sure if you've started any work on what you mentioned, but I've made progress on my own approach for subgroups. The code needs a bit more work to support basic functionality. I ended up figuring out my own approach based on our needs rather than look at D7 ggroup. I wanted a solution that could quickly determine group membership via a hierarchy without having to synchronize membership content entities into each group. It also needs to prevent circular references in the hierarchy (Group A has Group B has a subgroup, Group B has Group A as a subgroup, and any other extended derivative).

Once I have the rest of the basics working I'll post a patch for others to look at. Either later today or tomorrow.

sriharsha.uppuluri’s picture

@CalebD - Waiting for the patch :) . In our project we need subgroup module.

CalebD’s picture

Here is my work in progress on subgroups. THIS PATCH IS A PROTOTYPE AND IS NOT READY FOR PRODUCTION USE! This patch is built on the work started by jludwig. What follows is an explanation of what it currently does and how.

First I'll explain the functionality I'm solving for in my approach. My need is around group hierarchies and memberships. Members of subgroups should be considered as indirect members of the supergroup (parent group). For example, given group A and group B, such that group B is a subgroup of group A, then all direct members of group B are indirect members of group A. Now extend that relationship and behavior out to arbitrarily complex group hierarchieries, like this one. Upon doing so we realize that such a hierarchy can be described as a graph.

Other things to consider:

  • How can we quickly know a group's hierarchy without walking the graph each time?
  • What if group A has a subgroup of group B and group B also has a subgroup of group A? That's a circular reference that makes it impossible to resolve the hierarchy. So we need to prevent that from happening.

With more thought, we realize that a group hierarchy is a specific type of graph, called a directed acyclic graph (a DAG). To store the group hierarchy effectively, we need to store and traverse a DAG quickly. Unfortunately hierarchieries are not something that relational databases excel at storing and traversing. There are a variety of approaches for storing trees, but a DAG is more complex. Research brought me to this great article, which proposes a way to store the graph structure in a single table and query relationships quickly at the expense of storage. This is because the approach uses the graph structure to create a relationship between every connected entry in the graph, e.g. if group A has subgroup B, which has subgroup C, then a row will be added connecting A to C. Simple queries can be used to answer questions like "What are all the subgroups of this group?" or "What are all the supergroups of this group?". This is good for performance.

In studying the code for the group module, my assesment was that the best way to implement my needed functionality would be to modify the \Drupal\group\GroupMembershipLoader so that memberships could be influenced by other providers. Drupal core uses events in a few areas for this purpose, for example with building and altering routes. The need to "build and alter" group memberships is similar. This approach allows modifying group membership transparently so that other modules, like gnode, do not need any modification.

So, in this patch the ggroup module defines a table, group_graph, that is used to store the group hierarchy graph. This information is in addition to the group_content subgroup entities that are created. When a subgroup entity is inserted, the group_graph table is updated with the group hierarchy. There is a service class, \Drupal\ggroup\Graph\SqlGroupGraphStorage which handles all the database work, and a more general service class, \Drupal\ggroup\GroupHierarchyManager which is a wrapper around the storage class and is what other classes should use to interact with the group hierarchy. A constraint is added to group_content subgroup entity type so that circular group hierarchieries cannot be created.

The patch also modifies GroupMembershipLoader to dispatch events when loading memberships, as mentioned above. The ggroup module implements an event subscriber which uses the GroupHierarchyManager service to pull group hierarchy. The event subscriber creates transient group_content membership entities which are added to the membership collection provided by the events. The transient group_content membership entities represent indirect memberships in a group and are not saved (though they should probably be cached but aren't currently).

With the patch, this is what you can do:

  • Thanks to jludwig, you can enable plugins that allow groups to be added to groups.
  • When a group is added as a subgroup, the group_graph table is updated with the proper hierarchical representation.
  • When requesting group membership, the hierarchy is used to automatically create indirect memberships based on the group hierarchy. This affects anything that looks at group membership, like gnode.
  • A service class, GroupHierarchyManager, can be used to easily query for subgroups and supergroups.

Here is what is missing from this patch:

  • TESTS - I haven't written any additional tests. My testing has been manual so far and focused on the core concept and implementation.
  • Optimization - There isn't any caching of indirect memberships. There could also be various slow blocks of code.
  • Roles - Anything to do with roles and role mapping is not implemented.
  • Probably a bunch of other stuff I'm not thinking of.

Some other thoughts:

  • Need general code cleanup and reivew. There are some places that are straight up copy and paste of code to get something working.
  • GroupMembershipLoader dispatches three different events. I wonder if this could be simplified?
  • I don't like how many of the classes I added are named. For example one of the event classes is GroupMembershipLoaderByUserGroupEvent, which is really long. Any of the names of classes, methods, could and should be changed.
  • I'm not sure of the licensing implications of using the approach outlined in the CodeProject article. The approach in this patch does not use any of the stored procedures but does use the same logic implemented in PHP. The table structure is the same.

I invite others in this thread to take a look and provide feedback. Thanks!

CalebD’s picture

Here is a very small update to my previous patch to fix a bug I noticed with the event subscribers. I haven't had time for further development unfortunately.

kaizerking’s picture

is sub groups module working? has any one tested #46?

matslats’s picture

I'm working with a much earlier version and it is functional.
The module mostly declares group as a groupcontent type.
There's a lot of stuff about inheriting permissions not done yet.

Manmohan’s picture

I installed the latest patch but sub-group not inheriting any content and permission.

Manmohan’s picture

I installed the latest patch but sub-group not inheriting any content and permission.

kaizerking’s picture

@Manmohan can you please share zip? somehow i am not able to make this module

Manmohan’s picture

StatusFileSize
new221.82 KB

@kaizerking PFA complete group module with sub group.

kaizerking’s picture

@Manmohan Thanks, Installed without any glitch how ever I did not understand how to create sub group can you please give steps to create sub group please?

oo0shiny’s picture

I tried the patch in #46, but I'm getting the following error when attempting to add a subgroup to a group:

Recoverable fatal error: Argument 1 passed to Drupal\ggroup\GroupHierarchyManager::groupHasSubgroup() must implement interface Drupal\group\Entity\GroupInterface, null given, called in ../modules/contrib/group/modules/ggroup/src/Plugin/Validation/Constraint/GroupSubgroupConstraintValidator.php on line 71 and defined in Drupal\ggroup\GroupHierarchyManager->groupHasSubgroup() (line 46 of ../modules/contrib/group/modules/ggroup/src/GroupHierarchyManager.php) #0 

As far as I can see, it has to do with $child_group being null when passed to

if ($this->groupHierarchyManager->groupHasSubgroup($child_group, $parent_group)) {
      $this->context->buildViolation($constraint->message)
        ->setParameter('%parent_group_label', $parent_group->label())
        ->setParameter('%child_group_label', $child_group->label())
        ->addViolation();
    }

but I'm still too new at Drupal 8 to figure out if this is supposed to be a valid use case or if I've done something wrong. Things seem to work if I add a check for !is_null($child_group) into the if statement.

CalebD’s picture

StatusFileSize
new106.91 KB

oo0shiny, I'm not sure how you would have triggered that error. Did you install and configure the subgroup group content type by going to the "Set available content" option for your group type(s)? Sounds like there is a bug in here somewhere that will need to be hunted down.

Updated patch to work with 1.x-dev. Still needs tests and general architectural discussion.

mitsuroseba’s picture

Here some draft version of integration ggroup with views.
Added filter to select which content to show in depends of subgroup configuration.
https://www.dropbox.com/s/annnjje56pl8y60/%D0%A1%D0%BA%D1%80%D0%B8%D0%BD...

mitsuroseba’s picture

Anonymous’s picture

@Manmohan Just installed your zip file group module replacement. Seems to be working fine, but I don't understand how to create a sub-group. Are there any instructions?

mhmhartman’s picture

Status: Needs work » Needs review
StatusFileSize
new112.32 KB
new4.23 KB

Added support for inheriting permissions from supergroups. Patch is attached. Also fixed the issues below. Please review!

  1. +++ b/modules/ggroup/src/Form/SubgroupFormStep1.php
    @@ -0,0 +1,102 @@
    +  public function __construct(EntityManagerInterface $entity_manager) {
    +    parent::__construct($entity_manager);
    +    // @todo use proper dependency injection for this.
    +    $temp_store_factory = \Drupal::getContainer()->get('user.private_tempstore');
    +    $this->privateTempStore = $temp_store_factory->get('ggroup_add_temp');
    +  }
    

    Fixed this.

  2. +++ b/modules/ggroup/src/Form/SubgroupFormStep2.php
    @@ -0,0 +1,112 @@
    +    parent::__construct($entity_manager);
    

    The parent constructor needs $temp_store_factory as well. Fixed this.

The last submitted patch, 59: group-add_subgroups_module-2736233-59.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 59: interdiff-57-59.patch, failed testing.

mhmhartman’s picture

Status: Needs work » Needs review
StatusFileSize
new4.23 KB
new112.32 KB

Fixed small mistake.

The last submitted patch, 62: interdiff-57-60.patch, failed testing.

mhmhartman’s picture

StatusFileSize
new112.14 KB
new4.06 KB

Ignore my above patches. Supergroup permission inheritance will now take place in the group entity hasPermission() function.

mitsuroseba’s picture

Also in future we should think about permission propagation.
Like upward/downward/both.

For some cases we need logic to see region content if we have country membership or vice versa if we have region membership see country content.

May be we can have this option in subgroup content enabler plugin.

Any thoughts ?

seanb’s picture

There is a valid case for upward/downward permission propagation. Having this as optional makes sense (in both cases). Not sure yet on the best place to put this, I will need to dive in the code a bit more. When checking access we have a group and a account. We should be able to fetch these settings from a group.

Sidenote: This could make the process of checking where the permissions are coming from pretty complex. It is easier to make a mistake so we should add some kind of warning to make sure people don't activate this without thinking about it.

gaydamaka’s picture

StatusFileSize
new126.27 KB
new161.69 KB
new112.14 KB
new667 bytes

Hi,

I apply patch #64, but plugin GroupIdDepthwrong work.

I set option in filter:
Views filter

But SQL query is wrong:

Sql query

Status: Needs review » Needs work

The last submitted patch, 67: group-add_subgroups_module-2736233-67.patch, failed testing.

gaydamaka’s picture

Status: Needs work » Needs review
StatusFileSize
new112.16 KB
new667 bytes

Fix apply patch

gaydamaka’s picture

If we remove group which is subgroup the relation is not delete. In method removeSubgroup $group_content->getEntity() return null but $group_content->entity_id is not empty.

Status: Needs review » Needs work

The last submitted patch, 70: group-add_subgroups_module-2736233-70.patch, failed testing.

gaydamaka’s picture

Status: Needs work » Needs review
StatusFileSize
new112.19 KB
new770 bytes

Fix apply patch

gaydamaka’s picture

The last submitted patch, 73: group-add_subgroups_module-2736233-73-TEST_ONLY.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 73: group-add_subgroups_module-2736233-73.patch, failed testing.

gaydamaka’s picture

Status: Needs work » Needs review
StatusFileSize
new117.7 KB
new117.67 KB
new5.38 KB

Status: Needs review » Needs work

The last submitted patch, 76: group-add_subgroups_module-2736233-76-TEST_ONLY.patch, failed testing.

gaydamaka’s picture

Status: Needs work » Needs review

The last submitted patch, 55: group-add_subgroups_module-2736233-55-D8.patch, failed testing.

The last submitted patch, 56: group-add_subgroups_module-2736233-56-D8.patch, failed testing.

The last submitted patch, 57: group-add_subgroups_module-2736233-57-D8.patch, failed testing.

gaydamaka’s picture

+++ b/modules/ggroup/config/optional/views.view.subgroups.yml
@@ -0,0 +1,818 @@
+dependencies:

+++ b/modules/ggroup/src/Plugin/GroupContentEnabler/Subgroup.php
@@ -0,0 +1,136 @@
+    $config['info_text']['value'] = '<p>By submitting this form you will add this subgroup to the group.<br />It will then be subject to the access control settings that were configured for the group.<br/>Please fill out any available fields to describe the relation between the subgroup and the group.</p>';

Option info_text was removed in issue.

gaydamaka’s picture

kaizerking’s picture

has anyone tested #83?

rigoucr’s picture

Just a minor fix, ensure user does not belong to a parent group before assigning it.

CalebD’s picture

Assigned: CalebD » Unassigned

I don't have time to focus on this so I am unassigning myself. However, thank you to everyone who has contributed to improve the patch!

Status: Needs review » Needs work

The last submitted patch, 85: group-add_subgroups_module-2736233-85.patch, failed testing.

spheresh’s picture

Issue summary: View changes
StatusFileSize
new1.05 KB
spheresh’s picture

Issue summary: View changes

I decided to take the first step towards compatibility the group_graph table with the views module.

dang42’s picture

Is the latest patch (#85) based on the code (and associated logic) added by CalebD in #45, or something else?

A quick look through the comments makes it look like multiple people were submitting multiple patches based on different starting points.

FYI - I've installed #85 against the latest dev release w/out errors. I'm testing now to see if everything works as it should, but I can't tell exactly what features to expect / test...

Thanks to everyone who has worked on this so far! I'm working on multiple project that could use subgroups and this is all looking very promising.

rigoucr’s picture

Hi @dang42.

Yes, this patch is based on the patch #45, you could verify this following the interdiffs chain.

mitsuroseba’s picture

Status: Needs work » Needs review
StatusFileSize
new117.73 KB
new639 bytes

Merge changes from #85 to our global patch (@spheresh please take a look here https://www.drupal.org/patch).

@dang42 expect/test:
1) CRUD for subgroups like content enabler plugins for other groups.
2) Permission inheritance: Now only from top to bottom.
3) Views integration: contextual argument to show selected levels of subgroup
...

Other contributors feel free to update this list.

seanb’s picture

We currently have a use case where there are different role that you want to propogate:

  • Member: Inherit membership and permissions (up)
  • Admin: Propogate membership and permissions (down)

To fix this we could:

  • When adding a group as a subgroup, we should see a list with all roles defined in the parent. For each role we want to be able to map a role in the parent group to a role in the subgroup and also map roles in the subgroup to roles in the parent group.
  • The membershiploader should recursively check all subgroups/supergroups to check if the membership for that group should be added based on the mapping.
  • In hasPermission() for a group, we should recursively check all subgroups/supergroups to check which roles the user has for each group. If the role is mapped, we should check if the role has the permission we are looking for.

This leads me to believe that when you create enable a group as a subgroup, you should be able to define how to propogate each role down, and how you propogate each role up. As an example:

  • We have a school group type with roles member/admin.
  • We have a cluster group type with roles member/admin.
  • We have a study group type with roles member/admin/teacher.
  • When adding cluster as a subgroup of school:
    • we can make sure the admin role of school is mapped to the admin role in cluster
    • we can make sure the member role of cluster is mapped to the member role in school
  • When adding study as a subgroup of cluster:
    • we can make sure the admin role of cluster is mapped to the admin role in study
    • we can make sure the member role of cluster is mapped to the member role in study
    • we can make sure the member role of study is mapped to the member role in cluster.

This way:

  • When you are added as a member to a study you are automatically a member of the cluster and the school.
  • When you are added as a member to a cluster you are automatically a member of all studies and member of the the school.
  • When you are added as a admin to a cluster you are automatically a admin of all studies.
  • When you are added as a admin to a school you are automatically a admin of all clusters and of all studies.

I will work on this next week.

kristiaanvandeneynde’s picture

Just letting you know that this issue is a goldmine for different points of view. When I get to a 1.0 and want to look into making subgroups part of the main module again, all of this will be really helpful. Thanks all!

seanb’s picture

StatusFileSize
new134.92 KB
new64.09 KB

Just finished implementing inheritance as mentioned in #93. You can now specify inheritance/propagation for each installation of a subgroup. This allows a lot of flexibility (as already mentioned in a bunch of comments).

In doing this also fixed the following:

  • Improved the alters for the membership loader. Since the group roles are now properly inherited, we no longer need to change the hasPermission in \Drupal\group\Entity\Group. Much better!
  • Now using the proper database API's in SqlGroupGraphStorage
  • A whole bunch of code style/documentation fixes.

Things still todo:

  • Fix new line issues in the patch
  • Write tests. The whole graph storage could probably use some. The inheritance needs a bunch of tests. The alter events as well.
  • Fix cache invalidation. When adding/removing subgroups or members, this could change access or other things in parent/children. This probably means we have to add cache tags for all parents/children to a group, and could mean that cache is invalidated a lot.
  • Use inheritance in views. Not sure what the best way is to fix this, since the inherited group membership are not actually stored in the database. Maybe a default argument to provide all group IDs for a user?
  • The new events for the membershiploader are nice, but we probably need a way to fetch only the direct memberships too.

Please test/review, feedback would be very much appreciated :)

*edit: Apparently I missed a bunch of missing new lines in the end of files. Adding this to the list.

seanb’s picture

One important issue comes up: You can't add a user to a group if it already inherits roles for that group. For instance, when a user is an admin, but also a regular intranet user, you want admin permissions on all groups, but member permissions on only some.

As mentioned in my last comment. The new events for the membershiploader are nice, but we probably need a way to fetch only the direct memberships too.

I see several ways to do this, but all have some limits:

  • We add a context to the membershiploader methods and pass this to the event from places where it might be logical to conditionally alter the memberships (for instance in Group::getMember(), Group::getMembers() and GroupRoleStorage::loadByUserAndGroup()). Not sure I'm a fan of this, but it's the best I can come up with for now.
  • We add new events to places like Group::getMember(). It would do the trick, but I'm not sure if we want modules to alter values in all those places.
  • We add a separate method to fetch unaltered memberships. The means for Group::getMember() we decide if the inherited members are included or not, and there is no way to change this. I think we should be a bit more flexible though. We could also provide a setting, but I could imagine situation where you want to influance this.

While the patch is probably easy, it's probably best to discuss what would be the best solution first. If anyone has any other ideas, I'm very open to suggestions.

seanb’s picture

StatusFileSize
new136.36 KB
new3.12 KB

Ok last one. It seems like the inherited memberships could potentially cause issues since they are not in the database. You can't leave a group for example. The membership also can't be removed. This leads me to believe having a separate method to load the unchanged membership is probably best (after looking through the code we probably only need this for Group::getMember()). We could mark it as internal so we don't expand the API and discourage people to use this.

Patch is attached, also fixed the newlines I missed before.

seanb’s picture

StatusFileSize
new138.09 KB
new15.69 KB

After testing this in an application with thousands of groups it was obvious that there were huge performance implications. The main reasons were doing queries for each path/relation. To fix this, I added static caches with the data we need to find the roles we want to inherited. This means a bit more memory is used, but is still a lot faster than all queries (5431 groups and a user being member of all of them, the request time went from 11732ms to 950ms on my local machine).

Getting the group type ID from the group content is now solved in a very hacky way :(. We need this to fetch the implied roles. This should still be fixed. Maybe it's even better to not inherit implied roles at all and remove the code?

jludwig’s picture

Hey all,

I ended up using OG for rather than the Group module because of a specific problem that needed Nodes as the group type.

I still love the Group module, though, and would like to help out when possible.

For this particular problem on the OG side, we are _not_ going to attempt to solve the role inheritance problem in the module itself.

Too many people have too many opinions and there are too many use cases, that it ended up being a better use of time to give an example of how to add some custom business logic to fulfill specific inheritance requirements rather than trying to provide some generic functionality that will 100% satisfy no one's needs.

My suggestion would be:

- Make subgroups only involve posting groups into groups
- Provide some helpful APIs for subgroups
- Create a separate subgroups role inheritance module that is semi-generic; essentially just choose one of the solutions here, knowing it won't solve everyone's use case
- Label that module as an example of how to implement role inheritance, acknowledging that it is a difficult problem and that one may need to develop their own business logic for their specific need

@kristiaanvandeneynde you looked like you were flirting with this conclusion in #94. What do you say?

seanb’s picture

@jludwig The way I currently implemented inheritance is as flexible as it comes. You can specify inheritance for every single relation between group types (up and down). This basically allows people to configure whatever they need.

The added hooks for the membership loader provide extra options to:

  • Add extra memberships for whatever situation might comes up
  • Stop the events we provide for any situation by implementing your own custom event

This leads me to believe that we have very powerful options in the current state of the patch, and enough flexibility to change the current behaviour and/or extend it. Besides that, configuring inheritance is optional.

I do agree that we can't implement every possible use case, but I think basic up/down inheritance and the custom event should cover it.

jludwig’s picture

@seanB

Looking at what you provided, it does seem like the the up/down inheritance is flexible enough to fit most use cases. Great work!

I would still lean towards keeping this separated from the module that simply allows adding groups to groups to allow people wishing to implement their own business logic to do so without needing too much "duct tape" code needed to override certain parts that might be disruptive in some way for their specific use case.

We had a BoF on group role/permission inheritance at DrupalCon Baltimore, and your code looks like it can solve over half of the problems that were in that room, but if it is too closely coupled to the simple ability to add groups to groups, it may make the remaining 40% need re-implement that feature before getting to their own inheritance business logic.

On a side note, I may snag some of your code for the group inheritance stuff that BioRAFT is doing. :)

seanb’s picture

StatusFileSize
new117.67 KB
new55.53 KB

I was using the patch in a application with thousands of groups. And while I managed to fix performance for a lot of cases, there seem to be some cases where this whole membership inheritance is just messed up.

For instance:

  • All groups are created by an administrator, so the admin is a member of lets say 5000 groups
  • We enabled role mapping for related group types (for now a hierarchy with 5 levels)
  • When we do a GroupMembershipLoader::loadByUser() we get 5.000 memberships.
  • In the event to alter the memberships, for each of the 5.000 memberships we now have to check which roles we inherit from 1 or more supergroups or subgroups because there could be some roles missing that we might inherited for each membership.

The solutions seems very nice, and might work very well for small numbers of groups, or if a user is only a member of a small number of groups. You could say that no user actually has to be a member of all group (since we can inherit), but since we can't actually controll that, we are pretty much screwed.

All issues I encountered were caused by messing with the membershiploader. I think if we use the inheritance only for the permissions (an not actual membership) we save us a lot of trouble.

What did I change:

  • Removed loadUnchanged from #97
  • Removed membershiploader eventsubscribers.
  • This also means we can remove all events on the membershiploader, since they are technically now unrelated changes? I do like the groupMembershipCollection though! We should probably create a seperate issue for the events and the membership collection.
  • Add a new event to set a permisison for a user and group. We use this to check for permissions inheritance in subgroups/supergroups.

I think this makes the solution a lot simpler, which might address the feedback from #101

johnwebdev’s picture

Latest patch gives an exception on installing the submodule, but seems to "work" anyway.

Drupal 8.3.2

Exception: No entity type for field type on view subgroups in Drupal\views\Plugin\views\HandlerBase->getEntityType() (line 697 of /home/dcjf1/www/core/modules/views/src/Plugin/views/HandlerBase.php).

jayelless’s picture

I have found an error with group permissions for creating subgroups. The access check in class SubgroupAddAccessCheck builds the permission string using the old permission name structure:
$access = $group->hasPermission('create ' . $group_type->id() . ' subgroup', $account);
but this should be:
$access = $group->hasPermission('create subgroup:' . $group_type->id() . ' content', $account);
to match the current structure of group permission names.

The attached patch fixed the problem.

mpotter’s picture

Playing with the patch in #104. I didn't set up any mapping when enabling the ggroup module. So it's not inheriting any members of my parent space. But I can't see a way to go back and edit those role mappings. Is there a URL path for that? Or not yet implemented in the patch?

seanb’s picture

The roles between groups can be mapped on the page where you install / edit subgroups in a group. For example, when having a parent group type named 'department' and a subgroup type 'team', it's the path admin/group/content/manage/department-subgroup-team.

The patch currently only allows the inheritance of permissions (by mapping roles). Actually inheriting membership is another story and can lead to serious performance issues. See #102.

kaizerking’s picture

#104 applies nicely without any issue thanks for the work
How ever i did not understand how to create subgroup under a group
Can some one write steps to create subgroup please

mpotter’s picture

@seanB thanks, found it finally (Group Types -> select Set Available Content -> Configure for the subgroup).

I have a "Top Level" group and a "Subgroup" group. I have Member permissions in both set to Create Article. I have a "testuser" who is a member of "Top Level". I have the role mapping "MAP GROUP ROLES TO SUBGROUP ROLES" setting Member to Member.

When I log in to "testuser", they can create Articles in the Top Level group, but they cannot create anything in the Subgroup.

Are you saying that I still need to manually add "testuser" to *also* be a Member of the Subgroup? If so, that defeats the purpose of subgroups to me. Trying to implement Atrium-like functionality with Group and the whole idea is to have parent groups and putting content-creation users in the top-level parent so they don't have to be manually added to all 16,000 subgroups (stores) on the site.

I understand the issues you raised in #102, but those are exactly the issues that need to be addressed for proper subgroups. Just handling permissions without handling membership is only half the problem.

In og_subgroups we distinguished between "assigned members" and "inherited members" to deal with this (and yes, still had to fix performance issues, but got it working fine with 16,000 subgroups). I'll have to take a closer look at this patch to see if I can understand your architecture better.

seanb’s picture

@mpotter

Are you saying that I still need to manually add "testuser" to *also* be a Member of the Subgroup?

That shouldn't be needed? I did find I sometimes need to clear the cache? I have the exact same mapping and it seems to work for me?

I understand the issues you raised in #102, but those are exactly the issues that need to be addressed for proper subgroups. Just handling permissions without handling membership is only half the problem.

I totally agree. The issue is complex though since we allow role mapping down/up. You don't just inherit membership but you actually inherit a specific role (or roles). To make it more complex you can not only inherit a role from a parent group, but also from one of your children. If we find a way to solve this I 100% think this should be added.

The biggest problem is that when you are building the list of all the users memberships (inherited or not) you need to check each and every group and fetch the related parent/subgroups for those to see if there are groups to inherit. That is a big problem when you are a member of a lot of groups. If you have some insight on how to deal with this please let me know!

jludwig’s picture

IMO the way it is doing it now is acceptable for going into the core Groups module.

I'd like to reiterate what I said in comment #99, that it may be wise to not provide a specific inheritance implementation because there are so many varying use cases for subgroups, and providing an API flexible enough to deal with even half of them would probably perform terribly.

This is one of the few examples where I think it is better to _not_ provide a complete solution and to allow developers to implement the inheritance business logic needed for their own use case.

If there is a simple example that can be added so that pure sitebuilders at least have _something_, I would suggest that it be a separate submodule and an example of how a developer can implement inheritance.

tdwhite’s picture

Hi everyone, I applied the patch in #104 and while I didn't get any errors I am not able to create any subgroups. I understand this is a work in progress -- so any guidance would be greatly appreciated.

I am able to activate the Subgroups module and then configure my group type as "available content". However, attempting to create a subgroup from the group page I am directed to a page (URL: group/1/subgroup/create/mysubgroup) that simply says: "The website encountered an unexpected error. Please try again later."

The error logged is below, and I have been unable to determine where to start in addressing it:

Recoverable fatal error: Argument 1 passed to Drupal\group\Entity\Form\GroupForm::__construct() must be an instance of Drupal\user\PrivateTempStoreFactory, instance of Drupal\Core\Entity\EntityManager given, called in /home/mysite/mydomain.com/drupal8/modules/group/modules/ggroup/src/Form/SubgroupFormStep1.php on line 33 and defined in Drupal\group\Entity\Form\GroupForm->__construct() (line 33 of /home/mysite/mydomain.com/drupal8/modules/group/src/Entity/Form/GroupForm.php) #0 /home/mysite/mydomain.com/drupal8/core/includes/bootstrap.inc(566): _drupal_error_handler_real(4096, 'Argument 1 pass...', '/home/mysite/de...', 33, Array) #1 /home/mysite/mydomain.com/drupal8/modules/group/src/Entity/Form/GroupForm.php(33): _drupal_error_handler(4096, 'Argument 1 pass...', '/home/mysite/de...', 33, Array) #2 /home/mysite/mydomain.com/drupal8/modules/group/modules/ggroup/src/Form/SubgroupFormStep1.php(33): Drupal\group\Entity\Form\GroupForm->__construct(Object(Drupal\Core\Entity\EntityManager)) #3 /home/mysite/mydomain.com/drupal8/modules/group/modules/ggroup/src/Form/SubgroupFormStep1.php(44): Drupal\ggroup\Form\SubgroupFormStep1->__construct(Object(Drupal\Core\Entity\EntityManager), Object(Drupal\user\PrivateTempStoreFactory)) #4 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/DependencyInjection/ClassResolver.php(28): Drupal\ggroup\Form\SubgroupFormStep1::create(Object(Drupal\Core\DependencyInjection\Container)) #5 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/Entity/EntityTypeManager.php(187): Drupal\Core\DependencyInjection\ClassResolver->getInstanceFromDefinition('Drupal\\ggroup\\F...') #6 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/Entity/EntityManager.php(82): Drupal\Core\Entity\EntityTypeManager->getFormObject('group', 'ggroup-form') #7 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/Entity/EntityFormBuilder.php(44): Drupal\Core\Entity\EntityManager->getFormObject('group', 'ggroup-form') #8 /home/mysite/mydomain.com/drupal8/modules/group/modules/ggroup/src/Controller/SubgroupWizardController.php(131): Drupal\Core\Entity\EntityFormBuilder->getForm(Object(Drupal\group\Entity\Group), 'ggroup-form', Array) #9 [internal function]: Drupal\ggroup\Controller\SubgroupWizardController->addForm(Object(Drupal\group\Entity\Group), Object(Drupal\group\Entity\GroupType)) #10 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array) #11 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/Render/Renderer.php(574): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() #12 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure)) #13 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) #14 [internal function]: Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() #15 /home/mysite/mydomain.com/drupal8/vendor/symfony/http-kernel/HttpKernel.php(144): call_user_func_array(Object(Closure), Array) #16 /home/mysite/mydomain.com/drupal8/vendor/symfony/http-kernel/HttpKernel.php(64): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) #17 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #18 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #19 /home/mysite/mydomain.com/drupal8/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #20 /home/mysite/mydomain.com/drupal8/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true) #21 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #22 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #23 /home/mysite/mydomain.com/drupal8/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #24 /home/mysite/mydomain.com/drupal8/core/lib/Drupal/Core/DrupalKernel.php(656): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #25 /home/mysite/mydomain.com/drupal8/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request)) #26 {main}.

Perhaps I have made a simple mistake? I made sure to install a fresh Drupal, version 8.3.4 and encountered the same issue. I made sure to apply it against 8.x-1.x-dev dated 2017-Jun-06.

Here are my web server details in case relevant: Apache/2.2.32 (Unix) mod_ssl/2.2.32 OpenSSL/1.0.1e-fips mod_bwlimited/1.4 PHP/5.6.30

Thank you

johnwebdev’s picture

Small review:

  1. +++ b/modules/ggroup/config/optional/views.view.subgroups.yml
    @@ -0,0 +1,818 @@
    +  page_1:
    

    Can we have a better machine name rather than page_1?

  2. +++ b/modules/ggroup/ggroup.views.inc
    @@ -0,0 +1,32 @@
    +   $data = array();
    

    Use []

  3. +++ b/modules/ggroup/ggroup.views.inc
    @@ -0,0 +1,32 @@
    +  $data['group_content_field_data']['group_id_depth'] = array(
    

    Use []

  4. +++ b/modules/ggroup/ggroup.views.inc
    @@ -0,0 +1,32 @@
    +    'argument' => array(
    

    Use []

  5. +++ b/modules/ggroup/src/Form/SubgroupFormStep1.php
    @@ -0,0 +1,111 @@
    +  public function __construct(EntityManagerInterface $entity_manager, PrivateTempStoreFactory $temp_store_factory) {
    

    EntityManagerInterface is deprecated.

  6. +++ b/modules/ggroup/src/Form/SubgroupFormStep2.php
    @@ -0,0 +1,112 @@
    +  public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityManagerInterface $entity_manager) {
    

    EntityManagerInterface is deprecated.

  7. +++ b/modules/ggroup/src/Graph/SqlGroupGraphStorage.php
    @@ -0,0 +1,416 @@
    +    while ($id = $results->fetchField()) {
    

    Should be able to just use $result->fetchAll(); here instead?

mgalalm’s picture

StatusFileSize
new113.25 KB

I have the same issue like comment #112, I modified the patch in #104 slightly to fix this issue.

mgalalm’s picture

StatusFileSize
new117.69 KB

Just fixing problem with last patch.

seanb’s picture

#112 Fixed 1, 2, 3, 4 ,5

Added some small performance improvements.

Also added missing interdiff between 104-114 for easier review.

kaizerking’s picture

114 & 115 both patches are breaking the site
PHP Fatal error: Call to a member function get() on null in C:\\Program Files (x86)\\Ampps\\www\\social2\\core\\lib\\Drupal\\Core\\Session\\SessionHandler.php on line 76
PHP Stack trace:
PHP 1. session_write_close() UNKNOWN?:0
PHP 2. Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\SessionHandlerProxy->write() UNKNOWN?:0
PHP 3. Drupal\\Core\\Session\\WriteSafeSessionHandler->write() C:\\Program Files (x86)\\Ampps\\www\\social2\\vendor\\symfony\\http-foundation\\Session\\Storage\\Proxy\\SessionHandlerProxy.php:77
PHP 4. Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\WriteCheckSessionHandler->write() C:\\Program Files (x86)\\Ampps\\www\\social2\\core\\lib\\Drupal\\Core\\Session\\WriteSafeSessionHandler.php:75
PHP 5. Drupal\\Core\\Session\\SessionHandler->write() C:\\Program Files (x86)\\Ampps\\www\\social2\\vendor\\symfony\\http-foundation\\Session\\Storage\\Handler\\WriteCheckSessionHandler.php:89
Uncaught PHP Exception Drupal\\Component\\Serialization\\Exception\\InvalidDataTypeException: "Unable to parse at line 81 (near " arguments: ['@entity_type.manager', '@current_user', '@event_dispatcher']")." at C:\\Program Files (x86)\\Ampps\\www\\social2\\core\\lib\\Drupal\\Component\\Serialization\\YamlSymfony.php line 39, referer: http://localhost/social2/admin/modules

its drupal 8 fresh install

seanb’s picture

Can't reproduce this? The stack trace also doesn't show anything related to group or ggroup modules? Are you sure it's caused by this patch?

seanb’s picture

Did break something else, it is time to start adding a bunch of tests...

kaizerking’s picture

StatusFileSize
new4.42 KB

After applying#118
Enabling gives WSOD with the message : The website encountered an unexpected error. Please try again later.
Server log says:
Uncaught PHP Exception Exception: "No entity type for field type on view subgroups" at C:\\Program Files (x86)\\Ampps\\www\\social2\\core\\modules\\views\\src\\Plugin\\views\\HandlerBase.php line 697, referer: http://localhost/social2/admin/modules

seanb’s picture

I can reproduce the issue with the view. Will try to fix that asap.

seanb’s picture

Status: Needs review » Needs work
StatusFileSize
new118.61 KB
new2.82 KB

Ok fixed the WSOD. There is another issue though. We can't filter the subgroup view to show only subgroup group content. There is no plugin type available. You can add these after you actually create group types and install subgroups for the group types.

I think there should be a filter for plugin type 'subgroup'. So this still needs some work.

kaizerking’s picture

As of now #121 workings goodl..

seanb’s picture

Using migrate to import groups and subgroups, I noticed the graph got messed up after changes in the source data. I'm assuming this is an error on my part, but this got me thinking that the only time the graph is properly created or check is when adding subgroup content. Since the graph is a form of caching for the relations, it would be nice to be able to recalculate the graph.

The code below does exactly this, not sure how to fit it in the module. Maybe a configuration page that adds a button to do this?

$subgroup_types = [];
foreach (\Drupal::entityTypeManager()->getStorage('group_type')->loadMultiple() as $group_type) {
  $plugin_id = 'subgroup:' . $group_type->id();
  /** @var \Drupal\group\Entity\Storage\GroupContentTypeStorageInterface $storage */
  $storage = \Drupal::entityTypeManager()->getStorage('group_content_type');
  $subgroup_content_types = $storage->loadByContentPluginId($plugin_id);
  foreach ($subgroup_content_types as $subgroup_content_type) {
    /** @var \Drupal\group\Entity\GroupContentTypeInterface $subgroup_content_type */
    $subgroup_types[] = $subgroup_content_type->id()
  }
}

$hierarchy_manager = \Drupal::service('ggroup.group_hierarchy_manager');
$group_contents = \Drupal::entityTypeManager()->getStorage('group_content')
  ->loadByProperties([
    'type' => $subgroup_types,
  ]);
foreach($group_contents as $group_content) {
  $hierarchy_manager->addSubgroup($group_content);
}
ericras’s picture

1. On /group/%/subgroups I'm seeing all of the group's content listed - nodes, users, menus. **EDIT: Is this what #121 is referencing?

2a. In src/Plugin/GroupContentEnabler/Subgroup.php all of the permissions should be for "entity" not "content". They should be like $permissions["create $plugin_id entity"]. "entity" is for new creation and "content" is for relating.

2b. Need to set the 'create_mode' flag that distinguishes creating/relating as is done in gnode. (Also see #2881769: group/{group}/node/create uses the permissions of group/{group}/node/add). In SubgroupRouteProvider.php:

    $routes['entity.group_content.subgroup_add_page']
      ->setDefaults([
        '_title' => 'Create subgroup',
        '_controller' => '\Drupal\ggroup\Controller\SubgroupWizardController::addPage',
        'create_mode' => TRUE,  #### This is the addition 
      ])
ericras’s picture

Here's an update that addresses point two in the last comment. (I'll once again point out that permissions specificity relating to creating vs relating is broken per #2881769: group/{group}/node/create uses the permissions of group/{group}/node/add)

ericras’s picture

StatusFileSize
new118.66 KB
new2.58 KB

An update to #125 to fix the Edit permissions machine name: it should be "update" not "edit".

seanb’s picture

#124.1 Yep, that's what 121 is about. Not sure how to fix?

#126 Nice one. Just ran into this myself. Improved the patch a little to fix the ordering and the description of the relations permissions. Also fixed weird references to a create $name group permission that doesn't seem to exist. Not sure why it was there?

jts86’s picture

Added support for parent group tokens for Subgroups. Based in https://www.drupal.org/node/2774827.

jts86’s picture

Unchecking the " 2-step wizard" option in a subgroup content plugin seems to have no effect... the second screen still appears regardless of the value of that option. This patch aims to fix the problem.

parijke’s picture

StatusFileSize
new46.07 KB

Apllied patch #129

While creating subgroups, In the subgroup tab I see myself show up as a subgroup... That I did not expect to happen?

screenshot

Just created a location group type

Activated gnode (article) and ggroup (location) on it

created group Spanje

in group Spanje created subgroup Alicante

idebr’s picture

@parijke in #130

The missing filter on the subgroups pages to display only group content of the type 'subgroup' was identified in #121 and #124.1 as well

parijke’s picture

@idebr you're absolutely right.... punish me for my lazyness (didn't read the whole thread)

Glad it is in vision though

Anonymous’s picture

StatusFileSize
new336.43 KB

Hello,
My config is: Ubuntu 16.04, PostgreSql 9.5, Drupal 8.3.7 Group 8.x-1.0-rc1, Patch #129, with Group an SubGroup modules Installed.
Have Created 2 groups types Country and Region. SQL Error when creating a Region in a Country (see screenshot)
I guess it is because I am using PostgreSql.
All the best,

idebr’s picture

Status: Needs work » Needs review
StatusFileSize
new991 bytes
new128.1 KB

Fixed an issue where inherited group roles from the supergroup were written to the static cache of inherited subgroup roles, causing incorrect permissions.

nikolabintev’s picture

StatusFileSize
new124.95 KB

#129 works fine for me. The only issue I experienced is that no matter if I'm creating new group entity or relating an existing one, the same permissions is used for access check, which doesn't allow us to restrict the user to relate an existing entity in group by using Group permissions table.

Here is a patch that fixes the issue

idebr’s picture

Status: Needs review » Needs work

@nikolabintev #135
Your patch does not include the changes in #134. Can you post a new patch based on #134?

An interdiff would also help for reviewing your changes. You can find info on how to generate an interdiff at https://www.drupal.org/documentation/git/interdiff

nikolabintev’s picture

@idebr I'll remove patch #135 as it is related to another issue: https://www.drupal.org/node/2881769

mitsuroseba’s picture

Fix issue.

Notice: Undefined offset: 363 in Drupal\ggroup\Graph\SqlGroupGraphStorage->getPath() (line 390 of modules/contrib/group/modules/ggroup/src/Graph/SqlGroupGraphStorage.php).
Drupal\ggroup\Graph\SqlGroupGraphStorage->getPath('446', '325') (Line: 238)
Drupal\ggroup\GroupHierarchyManager->getInheritedSupergroupRoleIds(Object, Object) (Line: 199)
Drupal\ggroup\GroupHierarchyManager->getInheritedGroupRoles(Object, Object) (Line: 63)
Drupal\ggroup\EventSubscriber\GroupEventSubscriber->inheritGroupPermission(Object, 'group.permission', Object) (Line: 111)

Method getPath tried get directAncestors from group which doesn't have those.

arosboro’s picture

I've updated Subgroup.php with a patch that fixes a harmless warning about parent_role_mapping and child_role_mapping indexes being undefined for the default values.

arosboro’s picture

I jumped the gun there, it looks like a sanity check is required after submitting the form and going back to the Group Content Types overview.

arosboro’s picture

Regarding #121 and #124.1, I have updated the view to properly display only subgroup content, and fixed the dropbutton links.

arosboro’s picture

Status: Needs work » Needs review

The last submitted patch, 139: group-add_subgroups_module-2736233-139.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

maticb’s picture

Tested patch #141 and quickly came across 2 issues, but they may have already be mentioned, as I might have missed it in all of the comments above :)

- When navigating to the "subgroups" tab on any group it always says "An illegal choice has been detected. Please contact the site administrator.", because the "- Any -" option is selected, but not working.
- When you press "Create subgroup" you cannot select group type you are automatically placed onto an add form, instead of the group type selection form.

Other than that I think it's in good shape, but didn't do much in depth testing yet, as I am currently looking for options in my use case.

EDIT: I have realized now that I have to install content plugin for each group type, to be able to add it as a subgroup.

ryandekker’s picture

Was running into an issue where a user in a parent group could view/edit/delete a subgroup they weren't a member of. Looks like these permissions didn't do anything: "$operation any/own $plugin_id entity" (example: view any subgroup:<subgroup_type> entity).

I basically cloned and tweaked what gnode.module is doing in gnode_node_access(). Tested and this is working for me. (I haven't test the Views work from #141.)

Status: Needs review » Needs work

The last submitted patch, 145: group-add_subgroups_module-2736233-145.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Alumei’s picture

It might be a little late to ask, but:
Might it be actually easier to propagate roles instead of permissions for a first access related solution?

My thinking:
* Create outsider roles for group-types based on configured group-type as content relations in other types
* Go up the group nesting from the corresponding bottom, selecting the first actual membership to be found
* Use that membership to select appropriate outsider permissions in case the use is not a member

Even it does not make sense in this context I would still propose separating the permission-bubbling so something like the above could be used instead.

lukedekker’s picture

Found an issue in this patch. From the subgroups page of a group, the edit and delete operations for each row point at the parent group, not the subgroup.

This means that attempting to delete a child entity from this interface results in the deletion of the parent instead.

seanb’s picture

Status: Needs work » Needs review
StatusFileSize
new124.33 KB
new723 bytes

Added a fix for #2933819: getPermission does not convert plugin label to string properly to the patch.

About #145:

Was running into an issue where a user in a parent group could view/edit/delete a subgroup they weren't a member of. Looks like these permissions didn't do anything: "$operation any/own $plugin_id entity" (example: view any subgroup: entity).

This could be caused by the membership inheritance. If you set your groups up to inherit a role from a parent/child, you could get access to groups you are not actually a member of. This is exactly the point of the current patch and I don't think the ggroup_group_access() should be needed.

seanb’s picture

StatusFileSize
new127.66 KB
new31.57 KB

When using large amounts of subgroups with inheritance we still noticed a significant decrease in performance. This was even worse after upgrading to RC2.
I think I found a way to prevent calculating the inherited roles for groups on every request by building a cache with all possible direct/indirect relations between groups and the roles that are inherited. The cache is invalidated and rebuilt when subgroups are added or removed.

Please let me know if you find any issues.

Status: Needs review » Needs work

The last submitted patch, 150: 2736233-150.patch, failed testing. View results

seanb’s picture

On a sidenote, I also used the patch in #2878389: Add static cache to gnode_node_grants. Without that patch, overview are still a bit slow. The function gnode_node_grants() adds a lot of calls to $group->hasPermission().

Also not sure why PHPLint fails on the splat operator?

seanb’s picture

StatusFileSize
new127.67 KB
new919 bytes

Fixed a PHP warning and corrected small doc error.

arosboro’s picture

ggroup also has the same issue found at #2793621: Upload files when adding content to group don't work well, which can be solved with the same solution as #12 applied in that thread.

paul kim consulting’s picture

StatusFileSize
new255.41 KB

Hi @seanB,

I tried your patch in #150, and have set the role inheritance correctly between group and subgroup, but I'm not seeing the inheritance working correctly.

My group is called "State" and my subgroup is called "District". I have 3 different roles for both groups: Program Manager, Team Member, and Guest. Any role in "State" should have Guest access to the "District".

Here is how my District subgroup content plugin is configured:

none

Whenever I try to access a given permission for a "District" with a user that has "Program Manager" role in the "State", I don't get the permission inheritance as defined by the configs of the content plugin. But if I manually add that role for the "District" to the user, it works fine.

Am I missing something?

seanb’s picture

StatusFileSize
new127.74 KB
new5.72 KB

Added the changes from #2793621-12: Upload files when adding content to group don't work well as suggested in #154.

Also fixed another issue with merging group roles in GroupHierarchyManager::getInheritedGroupRoleIdsByUser().

@ #155 Paul Kim Consulting, it seems you are doing everything right. If you are able to debug the issue and provide some more insight that would be really helpful!

dylan donkersgoed’s picture

StatusFileSize
new132.71 KB
new742 bytes

Same issue as #155 here. Seems like this line in GroupHierarchyManager is the culprit:

$mapped_role_ids[] = array_intersect_key($role_map[$group_id][$membership_gid], array_flip($this->getMembershipRoles($membership)));

the role map and the final result need to be flipped as well.

hlopes’s picture

+  $entity_types['group']->setFormClass('ggroup-form', 'Drupal\ggroup\Form\SubgroupFormStep1');
+  $entity_types['group_content']->setFormClass('ggroup-form', 'Drupal\ggroup\Form\SubgroupFormStep2');
...
+    return $this->entityFormBuilder()->getForm($entity, 'ggroup-form', $extra);

I think there's an issue here, as the ggroup-form messes up the form id, meaning one can't implement hook_form_FORM_ID_alter.

hlopes’s picture

StatusFileSize
new132.7 KB
new2.03 KB

Patch & interdiff attached.

ozvalue’s picture

I have been able to "git apply -v" the .156 patch to the group-8.x-1.x-dev module with only whitespace errors warning. I then package up the new group module as a .tar.gz and use that to install into a clean Drupal 8.5.4 installation.

I then enable (within the administrations 'extend' menu item) the modified group module into a clean Drupal installation which is installed with the latest 64 bit bitnami LAMP stack.

Enabling group and 'group node' causes no problems.

When I try to enable subgroup I get the message:
"The website encountered an unexpected error. Please try again later."
on a White Screen Of Death.

The last lines at: apache2/logs/error_log show
"[Wed Jun 20 13:54:30.453360 2018] [php7:notice] [pid 13439] [client 127.0.0.1:52768] Uncaught PHP Exception Exception: "No entity type for field type on view subgroups" at /opt/lampstack-7.1.18-1/apps/drupal/htdocs/core/modules/views/src/Plugin/views/HandlerBase.php line 711, referer: http://localhost/drupal/admin/modules"
PHP Version:7.1.18 MySQL Version:5.7.22

This appears to be the same error from #119 except that the HandlerBase.php has gone from line 697 to 711. Yet, this was meant to have been fixed at #112

Regardless of the above, when I now check the enabled modules (within the administrations 'extend' menu item) it shows that subgroup has been enabled

I have redone the above
but using group-8.x-1.0-rc2 with the later 157 patch
and group-8.x-1.x-dev with the latest 158 patch
but in each case I got the same result.

Before using this 64 bit computer I tried to implement it on an old 32 bit laptop with older LAMP software but I had the same problems.

Are other people getting the same as this?

Is there anything I can do to not get this?

Many thanks

jordik’s picture

Applied patch from #159, it installed well and I could link groups and subgroups.
The roles and permissions inheritance and propagation though DID NOT work at all.
After debugging, I reverted the changes from #155 (no additional array flips) and voila - the permissions worked!
Why are those additional array flips of the role_map necessary at all?

sketman’s picture

StatusFileSize
new60.28 KB

Bug: when group is deleted, it still remains listed in "Content" tab, as a Subgroup. Hitting the "Install" button next to the deleted group throws error...ofcourse:) Please see atached screenshot.

I have installed a patch #159.

sketman’s picture

StatusFileSize
new11.73 KB

I wanted to unistall the entire Group suite. When uninstalling Group Node and Subgroup modules, I got error:

The website encountered an unexpected error. Please try again later.

Site is now unaccessible. Drush cr does not help, neither restarting Apache.

Apache logs say:

[Sat Sep 22 14:26:14.923769 2018] [php7:notice] [pid 16637] [client 62.197.243.35:49400] Uncaught PHP Exception Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException: "The "subgroup:technicians" plugin does not exist." at /home/bizhub/public_html/web/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryTrait.php line 52

Any thoughts please?

floydm’s picture

StatusFileSize
new127.74 KB
new662 bytes

This is 156 rerolled to pick up the translation of the parent group in the tokens, similar to:

https://www.drupal.org/project/group/issues/2774827#comment-12835463

With this patch applied one can use a path alias like:

[group:group:title]/[group:title]

And get the parent and the child in the same language.

floydm’s picture

StatusFileSize
new127.83 KB

Sorry attached 156 again instead of new patch 164.

martijn de wit’s picture

Status: Needs work » Needs review

Changed status for testing and added a test for #165

The last submitted patch, 153: 2736233-153.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 165: 2736233-164.patch, failed testing. View results

jnicola’s picture

We've got something going like this for our configuration already. Curious how this would compare. It's custom written for a particular set of groups, and menus in groups.

lukedekker’s picture

StatusFileSize
new132.13 KB
new10.62 KB

I've been running the patch from #165 on a project with a large number of groups (about 50K). Our structure is really simple with just groups and subgroups. The method of loading the entire groups_graph structure and using that for role inheritance just doesn't work for a project with our type of structure/size. Operations dealing with groups use a debilitating amount of memory (peaking around 900M) and take an extraordinary amount of time (no duh).

I've created an alternate method for loading group hierarchy that loads only one group at a time. I realize that there are potential issues with other projects with a deeper group structure, but at least for our use case, we've seen a dramatic improvement in performance. I also added caching on the hierarchy mapping, so that we're only hitting the database when we have to and only for the data that we need.

Not saying that this is the way to do this, but I think it's a step in the right direction. The existing solution just doesn't scale well enough for large projects. I haven't dug into the role inheritance logic, but I have a feeling that this issue is really just revealing another performance issue further up the chain.

martinma’s picture

Applying patch #170 worked, but enabling modul I get fatal error and following message in dblog:

Exception: No entity type for field type on view subgroups in Drupal\views\Plugin\views\HandlerBase->getEntityType() (line 712 of /medjxcwh/drupal8test-composer/core/modules/views/src/Plugin/views/HandlerBase.php).

webadpro’s picture

@MartinMa, I had the same issue, until you actually create a group type. I'm testing using Opigno_LMS.

martijn de wit’s picture

Status: Needs work » Needs review

Don't forget to change the issue status when you commit a patch. Otherwise tests will not run :)

Added a test manually.

lukedekker’s picture

StatusFileSize
new133.08 KB
new8.04 KB

@Martijn de Wit Ah thanks for that. Totally forgot.

I've kept working on this and made a similar change to the GroupRoleInheritance service, allowing mapping to be built for one group at a time. Also fixed a few bugs in the last patch.

Again to reiterate: I don't think this is the correct solution. I'm just dipping my toes into the inner workings of ggroups. I'm happy to keep pushing this along, but I would super appreciate some feedback from everyone. I'm basically just hacking ggroups so that it isn't a total memory hog for my use case. :/

The last submitted patch, 174: port-subgroups-2736233-174.patch, failed testing. View results

floydm’s picture

We're building a distro with subgroups using the patch from #165. We have a demo content module that creates a bunch of test groups, then behat tests that verify our group content and relationships.

Testing either the patch from #170 or #174, I'm getting a lot of failures. In particular it appears to be related to the GroupHierarchyManager. Code like

$subgroups = \Drupal::service('ggroup.group_hierarchy_manager')->getGroupSubgroups($group->id());

gets an empty array back when there are valid subgroups.

I've inserted some cache clearing just in case it was a caching issue, but that doesn't appear to make a difference.

For now we're sticking with #165.

floydm’s picture

StatusFileSize
new127.88 KB
new428 bytes

Attached is a reroll of the patch from #164 with a better validation. This is following alex.rutz's suggestion on a similar change on 2774827.

Status: Needs review » Needs work

The last submitted patch, 177: 2736233-177.patch, failed testing. View results

lukedekker’s picture

StatusFileSize
new133.09 KB
new2.48 KB

@floydm Awesome, thanks for the feedback.

Holy cow. I had a huge bug in the loadMap function.

-    if (!empty($this->loaded[$gid])) {
+    if (empty($this->loaded[$gid])) {

This works on the SECOND check of any page request, but not the first.
I also found a bunch of places where I was misspelling descendants (decendants).

Anyways, Fixed both of those issues and now you can load the subgroups on the first try :)

@floydm, would love for you to test this out and see if it fixes things for you.

Also I forgot to reroll with your last patch, so if anyone wants to go for it. Otherwise I'll hit that next go around (as I'm sure there will be one).

lukedekker’s picture

Also, I lied. It doesn't work on the second try. Honestly, I have no idea how this was working for me....

floydm’s picture

@lukedekker My tests are still failing with the patch from #179 but failing differently now. Which is progress. :)

With #177 I am able to see the subgroups and supergroups, but user permissions aren't cascading.

Our scenario has:

Parent group with group content (nodes).

Child group which users are members of.

The members of the child group inherit access to view the content in the parent group by virtue of parent/child group role mapping.

This works on #177 but not #179 (Access Denied).

lukedekker’s picture

StatusFileSize
new133.51 KB
new2.31 KB

Ok. Here is an updated patch (again). I believe that it addresses the issues you were having @floydm.

I also found yet another area where a permissions check was loading every single group_content entity of a specific plugin. (This time it only took up about 600MB, yay.)

Anyways, fixed those, also fixed a caching issue that I found.

Thanks for helping me test this!

floydm’s picture

Hey @lukedekker! I'm on holiday but don't want to keep you hanging, so I applied your latest patch and ran my tests. I went from 4 failing previously down to 2 failing now.

The errors seem to be related to role access inheritance still. For example, when I'm accessing the parent group as a member of the child group, I'm still getting "Access Denied" and a screen full of notices like:

Notice: Undefined offset: 1 in Drupal\ggroup\GroupRoleInheritance->getSubgroupRelationConfig() (line 269 of modules/contrib/group/modules/ggroup/src/GroupRoleInheritance.php).
Drupal\ggroup\GroupRoleInheritance->getSubgroupRelationConfig('1', '3') (Line: 142)
Drupal\ggroup\GroupRoleInheritance->build('1') (Line: 90)
Drupal\ggroup\GroupRoleInheritance->getAllInheritedGroupRoleIds('1') (Line: 186)
Drupal\ggroup\GroupHierarchyManager->getInheritedGroupRoleIdsByUser(Object, Object) (Line: 65)
Drupal\ggroup\EventSubscriber\GroupEventSubscriber->inheritGroupPermission(Object, 'group.permission', Object)
call_user_func(Array, Object, 'group.permission', Object) (Line: 111)

I probably won't have a chance to chase this down in any more detail until after the holidays but I hope this helps you out.

lukedekker’s picture

@Floydm, can you confirm that there is a valid subgroup for your group id 1?

I believe I've run into that issue before when running patch from #164.

Currently, my inclination from past behavior and looking at the logic in place is that we need better handling for this situation, but there is no serious issue in the logic here.

steveworley’s picture

StatusFileSize
new133.69 KB
new983 bytes

Hey @lukedekker I was just testing your latest patch and ran into something that I thought might be worth flagging. I needed to create a hierarchical list of subgroups for navigation. I couldn't find this functionality but started looking through GroupHierarchyManager and SqlGroupGraphStorage and found that the functionality is pretty much there.

One thing I was having trouble with was loading the group mapping from cache- the merge of the mapping data didn't work as I expected, so I just wanted to raise this.

+    // Merge relatives with those already set.
+    $this->descendants += $mapping['descendants'];
+    $this->ancestors += $mapping['ancestors'];
+    $this->directDescendants += $mapping['directDescendants'];
+    $this->directAncestors += $mapping['directAncestors'];

This has issues if you load multiple group mappings in a single request. I'll try and explain; I set up a pretty simple hierarchical structure I had 3 levels of subgroup nesting. If you loaded the first in the hierarchy it would show all leaf nodes correctly. If you stepped down, you would correctly see the remaining subgroups but you wouldn't see siblings.

The output I was looking for was something like:

  • Subgroup 1
    • Subgroup 1A
  • Subgroup 2
  • Subgroup 3

If I was on the Subgroup 1 page - I would see only its children, if I was on Subgroup 1A I would see the full tree similarly to if I was on the parent of Subgroup 1 I would see the full tree as well.

I was loading the ancestors of the current term to get the most senior in the hierarchy which would do an initial load and set the mapping in SqlGroupGraphStorage. When I was to load descendants to build the tree it didn't merge the new mappings as I was expecting. Some pseudo code to show the state:

# gid = 2;
directDescendants => [1 => [2]],
# gid = 1
directDescendants => [1 => [2, 3, 4]]

[1 => [2]] + [1 => [2, 3, 4]]

# Results in
directDescendants = [1 => [2]]
# Expected
directDescendants = [1 => [2, 3, 4]]

Array replace results in the result that I was expecting and it didn't seem to affect other functionality.

lukedekker’s picture

@steveworley you raise a great point. That merging logic is not working the way that we really need it to.

However, I think the fix that you're suggesting will actually cause the same problem you're describing if it is applied in the opposite order.

# gid = 1
directDescendants => [1 => [2, 3, 4]]
# gid = 2;
directDescendants => [1 => [2]],

array_replace([1 => [2, 3, 4]], [1 => [2]]);

# Results in
directDescendants = [1 => [2]]
# Expected
directDescendants = [1 => [2, 3, 4]]

So this works fine if you're loading your projects from child to parent, but causes the same problem in the opposite direction. I can't think of any baked-in methods that will do what we need here, so we may have to create a custom merger to handle this. Any better ideas anyone?

steveworley’s picture

Yeah that's a good point. I think a custom merge function will be required. I looked into NestedArray::deepMergeArray(). Which on the surface looks to work but because the mapping at lower levels has arbitrary keys we run into some potential issues.

# gid = 2
directDescendants = [1 => [2, 4]]
# gid = 1
directDescendants = [1 => [1,2,3]]

NestedArray::deepMergeArray([$a1, $a2], TRUE);
# results in
# directDescendants = [1 => [1, 2, 3]]

When creating the mapping we might be able to create the second array with keys that match the group id? Something like:

$mapping['directAncestors'] = $query->execute()->fetchAll(\PDO::FETCH_COLUMN | \PDO::FETCH_GROUP, 1);
$mapping['directAncestors'] = array_combine($mapping['directAncestors'] , $mapping['directAncestors']);

That would make the merge look more like:

# gid = 2
directDescendants = [1 => [2 => 2, 4 => 4]]
# gid = 1
directDescendants = [1 => [1 => 1, 2 => 2, 3 => 3]]

And then we could level the NestedArray merge functionality.

steveworley’s picture

@lukedekker I also ran into the notice mentioned in #183.

It looks like the role inheritance getSubgroupRelationConfig is called multiple times with different group IDs but the subgroup relation is only cached once for a single group ID.

For example my page calls that method 3 times with: 13, 12, 13.

This block is only evaluated once:

if (!$this->subgroupRelations) {
      // Get all  type between the supergroup and subgroup.
      $group_contents = $this->entityTypeManager->getStorage('group_content')
        ->loadByProperties([
          'type' => array_keys($subgroup_relations_config),
          'gid' => [$group_id],
        ]);
      foreach ($group_contents as $group_content) {
        $this->subgroupRelations[$group_content->gid->target_id][$group_content->entity_id->target_id] = $group_content->bundle();
      }
    }

because we set subgroupRelations on the first call and because the query is restrictive to the first gid that is received. $this->subgroupRelations[$group_id] will only ever be set for the first group_id that method is called with.

lukedekker’s picture

StatusFileSize
new134.43 KB
new2.8 KB

@steveworley great idea to convert those to associative arrays. I like that structure a lot better (I converted $this->mapping[x] to be associative as well).

Also, once you pointed out where the subgroupRelation stuff was failing, it became painfully obvious why that was failing. Once any subgroup relation is fetched, it's statically cached. Meaning that if (!$this->subgroupRelations) { will always be false.

Attached is a patch that adds the custom merge logic we talked about and resolves the subgroup relation config issue.

Huge thanks for the help!

mmjvb’s picture

Status: Needs work » Needs review

Assuming you want your patch tested !

The last submitted patch, 179: port-subgroups-2736233-179.patch, failed testing. View results

The last submitted patch, 189: port-subgroups-2736233-189.patch, failed testing. View results

The last submitted patch, 185: array_replace-2736233-184.patch, failed testing. View results

steveworley’s picture

Awesome! I'll patch and test that out but it looks good from the diff! :D

I just had a quick question about the group role inheritance and was wondering if you might be able to explain the intent and make sure that I'm understanding it correctly. The inheritance is for the permissions configured for each role; if I have a "Content Creator" role its permissions will be shared between each subgroup.

I'm looking to have the membership inherit as well (eg. you can add a user to the most senior group and it will have the same access to all subgroups).

Am I right in assuming it's the roles that are inherited and membership needs to be manually updated?

lukedekker’s picture

Gah, always forget to change the status. Thanks @mmjvb!

@steve it's actually a really clever system if a bit unintuitive. Props to whoever thought it up and implemented it.

By default, there is no permissions inheritance between groups and subgroups. What you need to do is hit the config page for the plugin between the parent type and child group type. That page allows you to map roles between the two. Basically you would configure a relationship between the "Admin" role on the parent group to the "Owner" role on the child. That means that regardless of whether the admin is an owner of the child, they will have the permissions of the Owner. And you can do the same thing in the opposite direction.

The hardest part is finding the page. I stumbled upon it accidentally - lucky for me :). Hope that helps?

steveworley’s picture

Awesome! Thanks so much for that, that's pretty much exactly what I needed.

Was just noticing the tests failing; it's failing because php 5.5 doesn't support splats so php -l thinks theres a syntax error. I think we just might need to rerun the test against a newer version of php; should we add the php version constraint to the modules composer.json to make sure that people know 5.5 isn't supported?

Other than that the latest patch is working just fine!

lukedekker’s picture

Just reran against PHP 7 and passed! There's still a bunch of coding standards warnings that ought to get resolved before we consider this RTBC. (Some of which are definitely from me! :/ )

I'm starting to feel that we may be getting close to a production-ready version.

mmjvb’s picture

Status: Needs review » Needs work

As per 195,196,197 set to Needs work
- Coding standards
- PHP 7 requirement

lukedekker’s picture

Status: Needs work » Needs review
StatusFileSize
new135.26 KB
new16.78 KB

K, Did a bunch of coding standards cleanup and added the PHP 7 dependency. Let's see how this goes.

The last submitted patch, 199: port-subgroups-2736233-199.patch, failed testing. View results

lukedekker’s picture

StatusFileSize
new135.25 KB
new16.73 KB

Aaannnd fixing the issue with my PHP version constraint.

The last submitted patch, 201: port-subgroups-2736233-200.patch, failed testing. View results

lukedekker’s picture

StatusFileSize
new135.26 KB
new4.41 KB

A few last coding standards. and I think we're good to go!

The last submitted patch, 203: port-subgroups-2736233-203.patch, failed testing. View results

lukedekker’s picture

StatusFileSize
new135.26 KB

Accidentally dropped the composer stuff in the last patch...

Andrei Tyuhai’s picture

Got an exception while installing the subgroup module patched with #205:
Exception: No entity type for field type on view subgroups in Drupal\views\Plugin\views\HandlerBase->getEntityType() (line 712 of /app/web/core/modules/views/src/Plugin/views/HandlerBase.php).
Notice: Undefined index: gc__group in Drupal\views\Plugin\views\HandlerBase->getEntityType() (line 702 of core/modules/views/src/Plugin/views/HandlerBase.php).

lukedekker’s picture

Based on my testing, this error only occurs if there are no existing group types when installing the subgroup module. It's triggered by the missing gc__group relationship used in ggroup/config/optional/views.view.group_members.yml which is provided by groups. I'm guessing we just need an extra dependency on that config.

Although I'm wondering if it would be better to force groups to define the gc__group relationship in src/Entity/Views/GroupContentViewsData.php

Any good ideas here?

dangur’s picture

Issue tags: +PostgreSQL compatability
StatusFileSize
new135.31 KB
new158 bytes

Relating nor creating subgroups was working with PostgreSQL. This adds a condition for the parent and child group graph.

The last submitted patch, 208: port-subgroups-2736233-208.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 208: interdiff-205-208.patch, failed testing. View results

jedgar1mx’s picture

Is there a estimated date for this release? or any suggestions on how to achieve sub-grouping like control with the current `group` release.

Thanks

Quicksaver’s picture

StatusFileSize
new136.57 KB

Patch 208 was failing to apply on 8.x-1.x, because of 3028343 and 3026897

Rerolled it as I need it for a project that relies greatly around this functionality, but I'm having trouble creating an interdiff because of the huge amount of changes in the latest commits there. So changes are:

- composer.json and group.services.yml : simple merge conflicts
- moved permission_event logic from src/Entity/Group.php to src/Access/GroupPermissionChecker.php :: please verify if the logic is still valid!!

Looks like it's working so far on my end, although I see some issues that I can't tell if they're due to my patch or if they existed already:

- First going to the subgroups page, I get an "An illegal choice has been detected." on the "Type" filter and no groups appear until I click on Apply to re-filter the groups list.
- "Type" filter in the subgroups page shows all existing group types even though I've only enabled one in a group.
- The autocomplete of the relate (add) subgroup page does not work (I never have any choices).
- When I create a new subgroup, I'm directed to an "Access denied" page (the group page) if that group type is not setup to either add the current user as a member or if external members cannot see it. Maybe directing to the subgroups page you were in before could be safer?

lukedekker’s picture

Awesome! Thanks for the re-roll. It's a huge help :) I'm not surprised that you're running into a few issues with the UI. As far as I can tell, nobody has touched the user-facing issues in about a year!

Your patch applies like a dream, and I'm excited that we're getting closer.

It does look like a few of the tests are failing now, so we'll need to address those, but hopefully, we can get this RTBC once we get the UI and testing issues sorted out.

Quicksaver’s picture

"The autocomplete of the relate (add) subgroup page does not work (I never have any choices)."

Just leaving this here: this looks like a permissions issue, it works if I'm adding the group as the site admin (user 1), but not if it's any user with the appropriate group permissions.

dangur’s picture

Issue tags: -PostgreSQL compatability
StatusFileSize
new68 bytes

With regard to the "An illegal choice has been detected." issue, adding something like this should resolve:

/**
 * Appends ?type=YOUR_GROUP_TYPE to /group/{group_id}/subgroup.
 *
 * Implements hook_form_FORM_ID_alter().
 */
function YOUR_CUSTOM_MODULE_NAME_form_views_exposed_form_alter(&$form) {
  if ($form["#id"] == 'views-exposed-form-subgroups-page') {
    $query = \Drupal::request()->query->get('type');
    if ($query == '') {
      $path = "{$form['#action']}?type=YOUR_GROUP_TYPE_MACHINE_NAME";
      $response = new RedirectResponse($path);
      $response->send();
    }
  }
}

Might be slick one day to automatically detect if there is only one type and if so, select that type.

dangur’s picture

StatusFileSize
new136.57 KB

Re-rolled for Drupal core version bump to 8.6.

dangur’s picture

lobsterr’s picture

Status: Needs work » Needs review
StatusFileSize
new138.81 KB
new2.6 KB

Fixed broken tests

jedgar1mx’s picture

Is the patch working on D8.7 or only 8.8?

martijn de wit’s picture

Added a test so we wil see :)
https://www.drupal.org/pift-ci-job/1250184

jedgar1mx’s picture

Awesome!!!

webadpro’s picture

Things are looking great guys! Awesome work.

Quicksaver’s picture

Just to mention access grants to nodes within a groups hierarchy are not yet fully defined. For example, in my case I had to write a hook_node_grants() that would set the appropriate grants based on a group's subgroups and parent groups.

I haven't added a new patch with it as I wrote it with my single use-case in mind and I don't know if that's the proper way to go for this, it just happened to work for my very specific (and a bit simple) group hierarchy setup.

dan_billingsley’s picture

I'm trying to use this patch as the subgroup functionality is a critical piece for a site I'm looking to build. As soon as I add the patch I start having errors any time I access a group. It seems that the EventDispatcherInterface is not getting injected in the GroupPermissionChecker constructor.

Any ideas where to go from here?

ArgumentCountError: Too few arguments to function Drupal\group\Access\GroupPermissionChecker::__construct(), 1 passed in C:\SoftwareDev\wamp.net\sites\lifestylelinkv2\core\lib\Drupal\Component\DependencyInjection\Container.php on line 269 and exactly 2 expected in Drupal\group\Access\GroupPermissionChecker->__construct() (line 38 of modules\contrib\group\src\Access\GroupPermissionChecker.php).

lobsterr’s picture

StatusFileSize
new491 bytes
new138.8 KB

Small fix for subgroups view to avoid "An illegal choice has been detected. Please contact the site administrator" warning

lobsterr’s picture

@dan_billingsley
We are constantly using this patch in our project and It works correctly.
Can you check your service file group.services.yml? It should contain the next config

  group_permission.checker:
    class: 'Drupal\group\Access\GroupPermissionChecker'
    arguments: ['@group_permission.calculator', '@event_dispatcher']

Maybe a cache issue ?

jcmartinez’s picture

So far, I can create subgroups through the admin pages; however, when I try to create them via migration something is not working right.

I've posted on https://www.drupal.org/project/group/issues/3060352, but I thought that I should mention it here because there may be something missing in the code of this sub-module.

jedgar1mx’s picture

I tried #225 on Drupal 8.7.2 and it errored out.

mmjvb’s picture

No surprise there with a patch for D8.8 !

jedgar1mx’s picture

I tried #218 as well which had 8.7 passing.

mmjvb’s picture

Sorry, meant to say: patch for D8.8 failing !
Wonder why it didn't run for D8.7, the current active version!

jedgar1mx’s picture

Group: 1.0.0-rc3
Drupal 8.7.3

I keep getting this error:

  Could not apply patch! Skipping. The error was: Cannot apply patch https://www.drupal.org/files/issues/2019-03-28/port-subgroups-2736233-218.patch

                                                                                                                                                                  
  [Exception]                                                                                                                                                     
  Cannot apply patch Issue #2736233: Port Subgroup (ggroup) to the D8 version (https://www.drupal.org/files/issues/2019-03-28/port-subgroups-2736233-218.patch)! 
jedgar1mx’s picture

Here is the verbose output:

patch '-p1' --dry-run --no-backup-if-mismatch -f -d 'docroot/modules/contrib/group' < '/tmp/5d010ba7c3709.patch'
checking file composer.json

checking file group.services.yml
Hunk #1 succeeded at 93 (offset -5 lines).
Hunk #2 FAILED at 112.
1 out of 2 hunks FAILED
checking file modules/ggroup/config/optional/views.view.subgroups.yml

checking file modules/ggroup/ggroup.group.permissions.yml

checking file modules/ggroup/ggroup.info.yml

checking file modules/ggroup/ggroup.install

checking file modules/ggroup/ggroup.links.action.yml

checking file modules/ggroup/ggroup.module

checking file modules/ggroup/ggroup.routing.yml

checking file modules/ggroup/ggroup.services.yml

checking file modules/ggroup/ggroup.tokens.inc

checking file modules/ggroup/ggroup.views.inc

checking file modules/ggroup/src/Access/SubgroupAddAccessCheck.php

checking file modules/ggroup/src/Controller/SubgroupController.php

checking file modules/ggroup/src/Controller/SubgroupWizardController.php

checking file modules/ggroup/src/EventSubscriber/GroupEventSubscriber.php

checking file modules/ggroup/src/Form/SubgroupFormStep1.php

checking file modules/ggroup/src/Form/SubgroupFormStep2.php

checking file modules/ggroup/src/Graph/CyclicGraphException.php

checking file modules/ggroup/src/Graph/GroupGraphStorageInterface.php

checking file modules/ggroup/src/Graph/SqlGroupGraphStorage.php

checking file modules/ggroup/src/GroupHierarchyManager.php

checking file modules/ggroup/src/GroupHierarchyManagerInterface.php

checking file modules/ggroup/src/GroupRoleInheritance.php

checking file modules/ggroup/src/GroupRoleInheritanceInterface.php

checking file modules/ggroup/src/Plugin/GroupContentEnabler/Subgroup.php

checking file modules/ggroup/src/Plugin/GroupContentEnabler/SubgroupDeriver.php

checking file modules/ggroup/src/Plugin/Validation/Constraint/GroupSubgroupConstraint.php

checking file modules/ggroup/src/Plugin/Validation/Constraint/GroupSubgroupConstraintValidator.php

checking file modules/ggroup/src/Plugin/views/argument/GroupIdDepth.php

checking file modules/ggroup/src/Routing/SubgroupRouteProvider.php

checking file modules/ggroup/tests/modules/ggroup_test_config/config/install/group.content_type.default-subgroup-subgroup.yml

checking file modules/ggroup/tests/modules/ggroup_test_config/config/install/group.type.subgroup.yml

checking file modules/ggroup/tests/modules/ggroup_test_config/ggroup_test_config.info.yml

checking file modules/ggroup/tests/src/Kernel/SubgroupTest.php

checking file src/Access/GroupPermissionChecker.php

Hunk #2 FAILED at 20.

1 out of 3 hunks FAILED

checking file src/Event/GroupEvents.php

checking file src/Event/GroupPermissionEvent.php

checking file tests/src/Unit/GroupPermissionCheckerTest.php

Hunk #1 succeeded at 9 with fuzz 2.
Hunk #2 FAILED at 30.

1 out of 3 hunks FAILED

patch '-p0' --dry-run --no-backup-if-mismatch -f -d 'docroot/modules/contrib/group' < '/tmp/5d010ba7c3709.patch'
can't find file to patch at input line 5
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/composer.json b/composer.json
|index 66b2367..630ddf4 100644
|--- a/composer.json
|+++ b/composer.json
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 18
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/group.services.yml b/group.services.yml
|index 7e8c517..d7c9b69 100644
|--- a/group.services.yml
|+++ b/group.services.yml
--------------------------
No file to patch.  Skipping patch.

2 out of 2 hunks ignored

checking file b/modules/ggroup/config/optional/views.view.subgroups.yml

checking file b/modules/ggroup/ggroup.group.permissions.yml

checking file b/modules/ggroup/ggroup.info.yml

checking file b/modules/ggroup/ggroup.install

checking file b/modules/ggroup/ggroup.links.action.yml

checking file b/modules/ggroup/ggroup.module

checking file b/modules/ggroup/ggroup.routing.yml

checking file b/modules/ggroup/ggroup.services.yml

checking file b/modules/ggroup/ggroup.tokens.inc

checking file b/modules/ggroup/ggroup.views.inc

checking file b/modules/ggroup/src/Access/SubgroupAddAccessCheck.php

checking file b/modules/ggroup/src/Controller/SubgroupController.php

checking file b/modules/ggroup/src/Controller/SubgroupWizardController.php

checking file b/modules/ggroup/src/EventSubscriber/GroupEventSubscriber.php

checking file b/modules/ggroup/src/Form/SubgroupFormStep1.php

checking file b/modules/ggroup/src/Form/SubgroupFormStep2.php

checking file b/modules/ggroup/src/Graph/CyclicGraphException.php

checking file b/modules/ggroup/src/Graph/GroupGraphStorageInterface.php

checking file b/modules/ggroup/src/Graph/SqlGroupGraphStorage.php

checking file b/modules/ggroup/src/GroupHierarchyManager.php

checking file b/modules/ggroup/src/GroupHierarchyManagerInterface.php

checking file b/modules/ggroup/src/GroupRoleInheritance.php

checking file b/modules/ggroup/src/GroupRoleInheritanceInterface.php

checking file b/modules/ggroup/src/Plugin/GroupContentEnabler/Subgroup.php

checking file b/modules/ggroup/src/Plugin/GroupContentEnabler/SubgroupDeriver.php

checking file b/modules/ggroup/src/Plugin/Validation/Constraint/GroupSubgroupConstraint.php

checking file b/modules/ggroup/src/Plugin/Validation/Constraint/GroupSubgroupConstraintValidator.php

checking file b/modules/ggroup/src/Plugin/views/argument/GroupIdDepth.php

checking file b/modules/ggroup/src/Routing/SubgroupRouteProvider.php

checking file b/modules/ggroup/tests/modules/ggroup_test_config/config/install/group.content_type.default-subgroup-subgroup.yml

checking file b/modules/ggroup/tests/modules/ggroup_test_config/config/install/group.type.subgroup.yml

checking file b/modules/ggroup/tests/modules/ggroup_test_config/ggroup_test_config.info.yml

checking file b/modules/ggroup/tests/src/Kernel/SubgroupTest.php

can't find file to patch at input line 4155
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/src/Access/GroupPermissionChecker.php b/src/Access/GroupPermissionChecker.php
|index 193641a..703b46d 100644
|--- a/src/Access/GroupPermissionChecker.php
|+++ b/src/Access/GroupPermissionChecker.php
--------------------------
No file to patch.  Skipping patch.

3 out of 3 hunks ignored

checking file b/src/Event/GroupEvents.php

checking file b/src/Event/GroupPermissionEvent.php

can't find file to patch at input line 4361
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/tests/src/Unit/GroupPermissionCheckerTest.php b/tests/src/Unit/GroupPermissionCheckerTest.php
|index a99b408..2c675fe 100644
|--- a/tests/src/Unit/GroupPermissionCheckerTest.php
|+++ b/tests/src/Unit/GroupPermissionCheckerTest.php
--------------------------
No file to patch.  Skipping patch.

3 out of 3 hunks ignored

patch '-p2' --dry-run --no-backup-if-mismatch -f -d 'docroot/modules/contrib/group' < '/tmp/5d010ba7c3709.patch'
can't find file to patch at input line 5
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/composer.json b/composer.json
|index 66b2367..630ddf4 100644
|--- a/composer.json
|+++ b/composer.json
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored
can't find file to patch at input line 18
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/group.services.yml b/group.services.yml
|index 7e8c517..d7c9b69 100644
|--- a/group.services.yml
|+++ b/group.services.yml
--------------------------
No file to patch.  Skipping patch.

2 out of 2 hunks ignored

checking file ggroup/config/optional/views.view.subgroups.yml

checking file ggroup/ggroup.group.permissions.yml

checking file ggroup/ggroup.info.yml

checking file ggroup/ggroup.install

checking file ggroup/ggroup.links.action.yml

checking file ggroup/ggroup.module

checking file ggroup/ggroup.routing.yml

checking file ggroup/ggroup.services.yml

checking file ggroup/ggroup.tokens.inc

checking file ggroup/ggroup.views.inc

checking file ggroup/src/Access/SubgroupAddAccessCheck.php

checking file ggroup/src/Controller/SubgroupController.php

checking file ggroup/src/Controller/SubgroupWizardController.php

checking file ggroup/src/EventSubscriber/GroupEventSubscriber.php

checking file ggroup/src/Form/SubgroupFormStep1.php

checking file ggroup/src/Form/SubgroupFormStep2.php

checking file ggroup/src/Graph/CyclicGraphException.php

checking file ggroup/src/Graph/GroupGraphStorageInterface.php

checking file ggroup/src/Graph/SqlGroupGraphStorage.php

checking file ggroup/src/GroupHierarchyManager.php

checking file ggroup/src/GroupHierarchyManagerInterface.php

checking file ggroup/src/GroupRoleInheritance.php

checking file ggroup/src/GroupRoleInheritanceInterface.php

checking file ggroup/src/Plugin/GroupContentEnabler/Subgroup.php

checking file ggroup/src/Plugin/GroupContentEnabler/SubgroupDeriver.php

checking file ggroup/src/Plugin/Validation/Constraint/GroupSubgroupConstraint.php

checking file ggroup/src/Plugin/Validation/Constraint/GroupSubgroupConstraintValidator.php

checking file ggroup/src/Plugin/views/argument/GroupIdDepth.php

checking file ggroup/src/Routing/SubgroupRouteProvider.php

checking file ggroup/tests/modules/ggroup_test_config/config/install/group.content_type.default-subgroup-subgroup.yml

checking file ggroup/tests/modules/ggroup_test_config/config/install/group.type.subgroup.yml

checking file ggroup/tests/modules/ggroup_test_config/ggroup_test_config.info.yml

checking file ggroup/tests/src/Kernel/SubgroupTest.php

can't find file to patch at input line 4155
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/src/Access/GroupPermissionChecker.php b/src/Access/GroupPermissionChecker.php
|index 193641a..703b46d 100644
|--- a/src/Access/GroupPermissionChecker.php
|+++ b/src/Access/GroupPermissionChecker.php
--------------------------
No file to patch.  Skipping patch.

3 out of 3 hunks ignored

checking file Event/GroupEvents.php

checking file Event/GroupPermissionEvent.php

can't find file to patch at input line 4361
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/tests/src/Unit/GroupPermissionCheckerTest.php b/tests/src/Unit/GroupPermissionCheckerTest.php
|index a99b408..2c675fe 100644
|--- a/tests/src/Unit/GroupPermissionCheckerTest.php
|+++ b/tests/src/Unit/GroupPermissionCheckerTest.php
--------------------------
No file to patch.  Skipping patch.

3 out of 3 hunks ignored

patch '-p4' --dry-run --no-backup-if-mismatch -f -d 'docroot/modules/contrib/group' < '/tmp/5d010ba7c3709.patch'
can't find file to patch at input line 5
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/composer.json b/composer.json
|index 66b2367..630ddf4 100644
|--- a/composer.json
|+++ b/composer.json
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored
can't find file to patch at input line 18
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/group.services.yml b/group.services.yml
|index 7e8c517..d7c9b69 100644
|--- a/group.services.yml
|+++ b/group.services.yml
--------------------------
No file to patch.  Skipping patch.
2 out of 2 hunks ignored

checking file optional/views.view.subgroups.yml

can't find file to patch at input line 877
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.group.permissions.yml b/modules/ggroup/ggroup.group.permissions.yml
|new file mode 100644
|index 0000000..687036f
|--- /dev/null
|+++ b/modules/ggroup/ggroup.group.permissions.yml
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 886
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.info.yml b/modules/ggroup/ggroup.info.yml
|new file mode 100644
|index 0000000..c1dc61f
|--- /dev/null
|+++ b/modules/ggroup/ggroup.info.yml
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 899
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.install b/modules/ggroup/ggroup.install
|new file mode 100644
|index 0000000..2243ff7
|--- /dev/null
|+++ b/modules/ggroup/ggroup.install
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 960
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.links.action.yml b/modules/ggroup/ggroup.links.action.yml
|new file mode 100644
|index 0000000..e05bf0f
|--- /dev/null
|+++ b/modules/ggroup/ggroup.links.action.yml
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 977
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.module b/modules/ggroup/ggroup.module
|new file mode 100644
|index 0000000..cc1e7b5
|--- /dev/null
|+++ b/modules/ggroup/ggroup.module
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 1049
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.routing.yml b/modules/ggroup/ggroup.routing.yml
|new file mode 100644
|index 0000000..6978670
|--- /dev/null
|+++ b/modules/ggroup/ggroup.routing.yml
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 1067
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.services.yml b/modules/ggroup/ggroup.services.yml
|new file mode 100644
|index 0000000..6fbe387
|--- /dev/null
|+++ b/modules/ggroup/ggroup.services.yml
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 1092
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.tokens.inc b/modules/ggroup/ggroup.tokens.inc
|new file mode 100644
|index 0000000..288a803
|--- /dev/null
|+++ b/modules/ggroup/ggroup.tokens.inc
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 1189
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/modules/ggroup/ggroup.views.inc b/modules/ggroup/ggroup.views.inc
|new file mode 100644
|index 0000000..e906b09
|--- /dev/null
|+++ b/modules/ggroup/ggroup.views.inc
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

checking file Access/SubgroupAddAccessCheck.php

checking file Controller/SubgroupController.php

checking file Controller/SubgroupWizardController.php

checking file EventSubscriber/GroupEventSubscriber.php

checking file Form/SubgroupFormStep1.php

checking file Form/SubgroupFormStep2.php

checking file Graph/CyclicGraphException.php

checking file Graph/GroupGraphStorageInterface.php

checking file Graph/SqlGroupGraphStorage.php

checking file GroupHierarchyManager.php

checking file GroupHierarchyManagerInterface.php

checking file GroupRoleInheritance.php

checking file GroupRoleInheritanceInterface.php

checking file Plugin/GroupContentEnabler/Subgroup.php

checking file Plugin/GroupContentEnabler/SubgroupDeriver.php

checking file Plugin/Validation/Constraint/GroupSubgroupConstraint.php

checking file Plugin/Validation/Constraint/GroupSubgroupConstraintValidator.php

checking file Plugin/views/argument/GroupIdDepth.php

checking file Routing/SubgroupRouteProvider.php

checking file modules/ggroup_test_config/config/install/group.content_type.default-subgroup-subgroup.yml

checking file modules/ggroup_test_config/config/install/group.type.subgroup.yml

checking file modules/ggroup_test_config/ggroup_test_config.info.yml

checking file src/Kernel/SubgroupTest.php

can't find file to patch at input line 4155
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------

|diff --git a/src/Access/GroupPermissionChecker.php b/src/Access/GroupPermissionChecker.php
|index 193641a..703b46d 100644
|--- a/src/Access/GroupPermissionChecker.php
|+++ b/src/Access/GroupPermissionChecker.php
--------------------------
No file to patch.  Skipping patch.

3 out of 3 hunks ignored

can't find file to patch at input line 4215
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/src/Event/GroupEvents.php b/src/Event/GroupEvents.php
|new file mode 100644
|index 0000000..d0bd02c
|--- /dev/null
|+++ b/src/Event/GroupEvents.php
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored
can't find file to patch at input line 4248
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------

|diff --git a/src/Event/GroupPermissionEvent.php b/src/Event/GroupPermissionEvent.php
|new file mode 100644
|index 0000000..2cc9222
|--- /dev/null
|+++ b/src/Event/GroupPermissionEvent.php
--------------------------
No file to patch.  Skipping patch.

1 out of 1 hunk ignored

can't find file to patch at input line 4361
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/tests/src/Unit/GroupPermissionCheckerTest.php b/tests/src/Unit/GroupPermissionCheckerTest.php
|index a99b408..2c675fe 100644
|--- a/tests/src/Unit/GroupPermissionCheckerTest.php
|+++ b/tests/src/Unit/GroupPermissionCheckerTest.php
--------------------------
No file to patch.  Skipping patch.

3 out of 3 hunks ignored

jedgar1mx’s picture

I checked some of the files just to make sure that the patch didn't get commited to the new release but the changes were not there. 🤔

kristiaanvandeneynde’s picture

Yeah, I basically had two choices here:

  1. Get a release out the door after more than a year, even though it does not contain all I wanted it to contain
  2. Keep trying to please everyone by adding more features and fixing more bugs, delaying a new release even further

I went with option A. I hope you can forgive me ;-)

jcmartinez’s picture

StatusFileSize
new139.02 KB

As being said above, with the release of 8.x-1.0-rc3, the patch #225 broke. I finished applying the code from the patch manually, and so far things are working for me.
Attached is a new version of the #225 patch that includes my manual tweaks to make Subgroups available on 8.x-1.0-rc3.

jedgar1mx’s picture

Thanks @jcmartinez for the update. @kristiaanvandeneynde I undertand the need to get the release out I was just trying to make sure it wasn't just me.

jcmartinez’s picture

If someone could tell me in plain English (or Spanish) what does it mean "Ancillary require failure", I'll be happy to try fixing the #236 patch.
The "Ancillary require failure" feedback from testing sounds a bit cryptic to me; although, it could be just my English.

it-cru’s picture

@jcmartinez: I think this failure message occurs, because in the patch is php 7.0 or higher required and the test currently try to test with PHP 5.6.

[InvalidArgumentException]
Package drupal/group at version dev-ancillary-branch as dev-1.x has a PHP requirement incompatible with your PHP version (5.6.37)

lobsterr’s picture

I have found a few edge cases when subgroup inherits roles from the parent group.
We can't correctly inherit roles for Anonymous and Outsider users.
These two roles should be handled a separate way in GroupHierarchyManager, because users (which don't have any membership) can have Anonymous user and Outsider roles, but they in the same time they don't have any records for membership, but GroupHierarchyManager build the mapping based on membership information.
I'm checking this case, I hope I will find a solution

lobsterr’s picture

StatusFileSize
new133.57 KB
new14.02 KB

I have migrated the permission handling to a new permission layer provided by group module. More information can be found here #3041087: Update the new permission layer to be alterable and #3041094: Group permissions can now be altered.

We don't need an event to handle permissions. I have removed the code related the events. Also there is a new permission calculator InheritGroupPermissionCalculator, which handles subgroup permissions.

jedgar1mx’s picture

#236 works for me now. I'm running PHP 7.2 and Drupal 8.7.4

socialnicheguru’s picture

Status: Needs review » Needs work

patch 241 produces this error

ReflectionException: Class Drupal\ggroup\EventSubscriber\GroupEventSubscriber does not exist in         [error]
drupal874/html/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterEventSubscribersPass.php:30

because of this line which is introduced in the patch:

ggroup.services.yml:7: class: Drupal\ggroup\EventSubscriber\GroupEventSubscriber

Where is the GroupEventSubscriber?

lobsterr’s picture

Status: Needs work » Needs review
StatusFileSize
new136.17 KB
new762 bytes

Missed it

socialnicheguru’s picture

EDIT:

This is not in the rc2 version of group:

 group_permission.checker:
    class: 'Drupal\group\Access\GroupPermissionChecker'
    arguments: ['@group_permission.calculator', '@event_dispatcher']

group_permission.calculator is not there

I am confused about which patch will work with the group r2.

When I apply the patch from https://www.drupal.org/project/group/issues/2736233#comment-13104478

I get this error:

more html/modules/contrib/group/group.services.yml.rej
--- group.services.yml
+++ group.services.yml
@@ -98,7 +98,7 @@ services:
       - { name: 'context_provider' }
   group.membership_loader:
     class: 'Drupal\group\GroupMembershipLoader'
-    arguments: ['@entity_type.manager', '@current_user']
+    arguments: ['@entity_type.manager', '@current_user', '@event_dispatcher']
   # @todo Rename to group_permission.builder in 8.2.0.
   group.permissions:
     class: 'Drupal\group\Access\GroupPermissionHandler'
@@ -112,7 +112,7 @@ services:
     arguments: ['@cache.default', '@cache.static', '@entity_type.manager', '@gr
oup_role.synchronizer', '@group.membership_loader']
   group_permission.checker:
     class: 'Drupal\group\Access\GroupPermissionChecker'
-    arguments: ['@group_permission.calculator']
+    arguments: ['@group_permission.calculator', '@event_dispatcher']
   group.uninstall_validator.group_content:
     class: 'Drupal\group\UninstallValidator\GroupContentUninstallValidator'
     tags:

delete previous comment.

walli’s picture

Hello @LOBsTerr,

Thank you for this useful patch :)

When i apply the patch port-subgroups-2736233-244.patch, and i run drush updb, the hook updates can't be detected, so im always having this error :
The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException</em>: You have requested a non-existent service &quot;cache_context.group_membership.roles.permissions&quot;. Did you mean one of these: &quot;cache_context.group_membership.audience&quot;, &quot;cache_context.group_membership.roles&quot;? in <em class="placeholder">Drupal\Component\DependencyInjection\Container-&gt;get()</em> (line <em class="placeholder">153</em> of <em class="placeholder">core/lib/Drupal/Component/DependencyInjection/Container.php</em>). i had to apply the hook update in a custom module to avoid the error. Would you help me or maybe im missing something ? Thank you

lobsterr’s picture

@walli I have tried to reproduce your case, but unfortunately without success. If you can provide more information about your instance or even specific steps. I will check.
I have tried with a fresh instance + rc4 and dev version of the module.

lobsterr’s picture

I want to open a discussion with all users of this patch, because I want to improve the subgroup permission system.
I have recently spent a lot of time trying to find all user cases and how to make it work with a new permission layer, but currently I need your opinion.

1. Why do we need propagate permissions from subgroup to parent group. Does anybody actually use these settings? It is really confusing and I think we should remove it. (it is second part in the mapping of subgroups)

2. Currently, we can map any parent group roles to any subgroup roles, but in fact the anonymous, outsider and advanced outsider roles are not taken into account, because we get groups from memberships. My question is do we want to map roles only if a user is a member for both parent and subgroup? In this case anonymous, outsider and advanced outsider roles are ignored as it is right now.

3. Should we simplify these settings and just allow or not allow to propagate permissions from parent group to sub groups and get rid off mapping ?

4. Please provide some other examples from your projects

jedgar1mx’s picture

Hey @Lobsterr, I don't think there is any need to propagate the permissions from child to parent. The bi-directional permissions will only complicate things and could be easily achieved by giving users multiple memberships. But that is just my take.

lukedekker’s picture

  1. I don't personally make use of this case, but I do see its benefit. The main use case I see for this functionality is granting a user elevated permissions in a parent group based off of their role in a subgroup. For example a subgroup admin (call them team lead) can post new comments on content belonging to the parent group (executive staff). The same functionality could be accomplished by just maintaining the subgroup admin in both groups, but this can require a lot of custom logic/rules to keep in sync. Personally, I'd rather see a slightly more complex permissions system, than requiring developers/site builders to build logic to keep their groups in sync.
  2. This one I do use. The admin of a parent group is allowed to view and join any subgroup in our project, but have no elevated permissions regarding any other group or subgroup in which they aren't a member. It's possible that this could be achieved with some clever use of advanced outsider permissions (I haven't tried) but this definitely simplifies the flow.
  3. I can definitely see the case for simplifying things. However, I'm not sure that I would recommend it. We already have a (mostly?) functional permissions system that is extremely powerful. I can't currently think of any features I would add that expand the capabilities of this module. I'm more inclined to fix the issues (honestly not sure what confirmed issues remain to be solved) than to rebuild the permissions system so that it can be less powerful, even though such a system would likely be easier to use and a bit more performant.
  4. Don't have anything to add here.

As I mentioned, I haven't been following this issue quite as closely in the last few months. Skimming through things, I don't see any confirmed issues that are needing a resolution. I think it would be beneficial to have a solid roadmap of confirmed issues (and steps to reproduce if possible) that we can start punching through. I believe that is our fastest route to getting this stable and committed.

Quicksaver’s picture

Response to #248

TL;DR I see a definite and useful place for bubbling permissions in subgroups. All of it can be implemented by custom logic per-project though, perhaps even simplifying its implementation depending on each project's individual needs (not our case). This is mostly a report of our specific use-case, I don't have a concrete opinion on whether bubbling permissions should be implemented by subgroups itself, or how comprehensive they should be.

---

In basic terms, in our system an organization (the parent group, call it overseer) works with several other organizations (its subgroups, call them delegates). The delegates contain a stock of products, and a set of actions to be performed on/with that stock, as well as own user management.

1. Each delegate cannot access the stock or members of other delegates, nor act on them. In our case, we absolutely want members of the overseer to also access and perform those actions on its delegates, without members of the delegates to act on the overseer (which also has its own actions, etc). The most direct, and I would venture logical, way to do this is create a set of permissions on the delegate (subgroup) and have it propagate to the overseer (parent group)'s members.

I'll admit your point about them being confusing, it took me a little bit to get my head around it when I first started configuring the subgroups. However, solutions around it for our system without bubbling permissions are undoubtedly more difficult. In fact, we had to implement a custom permissions handler because of a single peculiarity in our system, and ended up just using it also for this permissions bubbling (only because it was more freeing). But as @lukedekker mentioned, I can see a definite place for bubbling permissions in subgroups.

2. To me this is more of a strategy/organization point rather than a technical one. (None of anonymous, outsider and advanced outsider roles are relevant or used in our system, so I will not give an opinion on those directly.)

In our case, users can only belong to a single group, they cannot belong to both the parent and subgroup. Both overseers and delegates are independent companies that manage their own staff, it's much simpler for the editorial/administrative staff to visualize them in the system in that way as well, avoiding situations like "Why is this person listed in my company? I don't even know them."

Again, it's not a technical point, this is of course easily overcome by a custom permissions handler (like the one I mentioned in 1. does a bit already actually), or with a set of views and hooks to automatically add, show, hide and remove certain members from certain groups. I just don't think multiple memberships can, or should, always be the solution.

3. Hmm, tough question. In our particular case, this would not matter much. Right now the overseer basically has admin rights (all permissions) over the delegates. I can still see a case for mapping though, such as a division of the overseer's staff with a certain role being able to perform only stock-related actions on the delegates, but not user membership ones.

lobsterr’s picture

StatusFileSize
new144.5 KB
new14.47 KB

First of all, I want to thank everyone for your feedback.
To sum up
1) This option is not used, but we will keep it for some exceptional cases. It can be remove easily at any moment.
2) Users use mapping of member roles and it is the main feature here.
The only feature is missing from the current implementation is propagation of the rights from anonymous and outsider roles. I did it (check information bellow)
3) Users use this functionality as it is. So, we will not simplify it. We will give the users opportunity to map any role to any role.
4) No, new features are required at this moment.

Information about the current changes
1) Fixed the bug with cache, when we build group inheritance structure
2) Improved the cache for "InheritGroupPermissionCalculator". I added Group Content Type as a dependency. It means every time we save a new role mapping configuration the permissions will recalculated
3) The main improvement, we can propagate and bubble up anonymous, outsider and advanced outsider roles to member roles.

lobsterr’s picture

StatusFileSize
new1.52 KB
new144.51 KB

I have noticed that I choose the wrong context it should be SCOPE_GROUP_TYPE context for InheritGroupPermissionCalculator

remotebox’s picture

I have just tried patch #253 and am getting the following error when trying to view subgroups:
Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "cache_context.group_membership.roles.permissions". Did you mean one of these: "cache_context.group_membership.audience", "cache_context.group_membership.roles"? in Drupal\Component\DependencyInjection\Container->get() (line 155 of /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php).

I am using PHP 7.2, Drupal 8.7.6 and Group 8.x-1.0-rc4.

adrianodias’s picture

StatusFileSize
new141.73 KB
new3 KB

while trying out the new patch I noticed that there was a regression on group.install and gnode.install, committed changes from 6eaa050e39de8369ff6ca9d070992ea8ead363e5 got removed.
here is a new version of the previous patch where the following was addressed:
- fix the regression,
- there was a problem when trying to apply the contextual filter "Has parent group ID (with depth)" (the default value of checkboxes must be a array)

lobsterr’s picture

@remotebox, Do you use the latest version of the group ? This service was removed "Removed the unsafe group_membership.roles.permissions cache context instead of deprecating it." in https://git.drupalcode.org/project/group/commit/b542c0ce2f2186e7c8cea2ae.... It is nothing to do with the patch.

remotebox’s picture

@LOBsTerr, Sorry you are right - I was only using the latest stable release. I updated to the dev release which fixed the issue - thank you.

kkasson’s picture

I'm having some trouble getting this to work. I've created a fresh test installation to eliminate extra variables, and I just can't get this module to do anything. I can't tell if the module isn't working or if I'm doing something wrong. I assume the problem is on my end since it seems to work for everyone else, but I can't at all figure out what I'm missing.

Here's the situation on my test site. This will be a little verbose but I want to describe as exactly as possible to narrow down the problem.

I have a group type called Parent Group with a single group belonging to it called Parent. There's another group type called Child Group with a single group belonging to it called Child. Parent Group has roles of Parent 1 and Parent 2, and Child Group has roles called Child 1 and Child 2.

I'd like for members of Parent Group having the Parent 1 role to have access to the Child Group (and have the role of Child 1).

I installed the subgroup plugin for Child Group on Parent Group and mapped Member to Member, Parent 1 to Child 1, and Parent 2 to Child 2. I set Member, Child 1, and Child 2 to have view access to Child Group. I added Child as group content to Parent, and created a user called testuser.

I added testuser as a member of Parent, and gave him the role of Parent 1. testuser does not have a membership on the Child Group. testuser is unable to view Child. I then tried removing view access for Members and adding testuser as a group member on the Child Group. My hope here was that he would inherit the Child 1 role (since he has Parent 1, which is mapped to Child 1), and therefore have view access. He is still unable to view the group. I also tried reversing everything and mapping the child roles to the parent roles. I gave testuser the role of Child 1, and took away the role of Parent 1. testuser is then able to view the child group, but unable to view the parent group.

Is there some step I'm missing to get it to work? I've tried to debug the code and find what's happening but I'm not sure how's it supposed to work to know what I'm looking for. I did find a couple things that might be relevant:

GroupHierarchyManager->getInheritedGroupRoleIdsByUser loops through the group memberships that belong to the user. It appears that this completely prevents my first case from working, when the user has a membership to the Parent group but does not have a membership on the child group. Is that correct?

When I added the membership to the child group, it did appear that the above method returns the mapped Child 1 role correctly. However this doesn't seem to have any effect, as the user is still not able to view the group even though the Child 1 role has view permission.

lobsterr’s picture

@kkasson, Thank you for your detailed report. I found the issue, I will present a new patch soon

lobsterr’s picture

So, far I have found the next issues and we need to address them

1) When we map the roles parent -> subgroup, the user receive the roles of subgroup, but should get parent's roles. The same problem when we use bubbling of the roles from subgroup -> parent
2) When we do the mapping, we don't check that user actually has these roles in parent or subgroup.
3) When we have more then two levels the mapping of the roles is incorrect.
Parent group (type 1)
-> Child group (type 2)
---> Child child group (type 2)

"Child child group" and "Parent group" gets roles mapping from "Child group" and "Child child group"

lobsterr’s picture

StatusFileSize
new141.16 KB
new12.4 KB

I have fixed two first points. The third point a too complicated. I need more time.
Please, test it and report back

jayelless’s picture

Hey Guys. Just a heads up here.

While I really appreciate all the effort that is going into getting sub-groups and this patch working correctly, I think that it is now getting overly complex, which I believe is preventing progress in having the patch ready to be committed.

My use cases require only stable sub-groups without any aspect of role inheritance, so can I suggest that the effort is split, so that the the basic sub-group functionality is in the ggroup module, with all the complex role inheritance moved into a separate sub-module or even an new contrib module. I think that the porting of sub-groups could then be completed and accepted more quickly, while the complex use cases for role inheritance are discussed separately.

Is there any support for this approach?

kkasson’s picture

@LOBsTerr, thanks for the updated patch! It helped but I found some more issues.

1) The conditions in getInheritedGroupRoleIdsByMembership never apply to my configuration. I have a group A and a child group B. Member of A is mapped to member of B. My test user is a member of A and not of B. The role should inherit from parent A to child B and the test user should be a member of B.

$role_map correctly returns that mapping. However, since the method loops through group memberships, $group_id and $membership_gid both point to group A. Therefore $role_map[$group_id][$membership_gid] is always empty.

I made some changes and got this working in my case - I'll post the code below. I don't want to add it as a new patch because I don't know if it actually works, but hopefully someone here might be able to look at it and make any needed changes. It seems that the group graph is being used to generate the role map, but we also need to loop over the graph to find the inherited groups, since the user doesn't necessarily have group memberships in the other groups. The getGroupSubgroups/getGroupSupergroups methods weren't being used at all before. I've only tested this with a single group of each type, so I don't know if my changes might cause problems in other cases.

2) The graph doesn't seem to always work, or at least there are cases that it isn't designed to handle. It seems to correctly trace the path from parents to children, or children to parents, but it breaks when there are both types of inheritance at once. Here's my test case for this. Each letter is a different group type, and I have one group of each group type:

Group A has a child Group B. Group B has a child Group C. Group C has a child Group D. Another group type, Group L, also has Group D as a child.

A member (parent) is mapped to B member (child). B member (parent) is mapped to C member (child). C member (parent) is mapped to D member (child).

D member (child) is mapped to L member (parent), using the subgroup to parent group mapping.

Group B correctly picks up the role from A, and C picks up A through B. D also picks up A, through C and through B. The test user is a member of A, and therefore inherits the member role in B, C, and D. He's correctly able to view D.

Since he is now a member of D (through the inheritance), his role should inherit from the child group D to the parent group L, from the subgroup to parent group mapping. However this doesn't get picked up in the graph, and there's no path in the graph from L to C, B, or A. I tried to quickly add some SQL to add the rest of these path, but I couldn't get it to work without adding thousands of extra paths from looping back and forth over each other. I don't know if it's even supposed to have these paths, but they're needed with the way I'm inheriting the group permissions below.

3) The caches don't seem to always be working for me. I added a hook on group_content_update to rebuild the role inheritance, in addition to the insert and delete hooks. If you update the role mapping from a parent group to a subgroup, it wasn't updating the cached role inheritance. Even with that I was still getting the wrong inheritance cached sometimes. There's probably still somewhere else that things need to be invalidated, but I haven't narrowed down when exactly it's happening.

Here is the code I changed for 1). This seems to work for most cases, except those described in 2).

In GroupHierarchyManager.php, change the end of getInheritedGroupRoleIdsByMembership to the following:

    $mapped_role_ids = [[]];
    foreach ($this->userMemberships[$account_id] as $membership) {
      $membership_gid = $membership->getGroup()->id();

      $subgroup_ids = $this->getGroupSupergroupIds($membership_gid) + $this->getGroupSubgroupIds($membership_gid);;
      foreach ($subgroup_ids as $subgroup_id) {
        if (!empty($role_map[$subgroup_id][$group_id])) {
          $mapped_role_ids[$subgroup_id] = array_merge(isset($mapped_role_ids[$subgroup_id]) ? $mapped_role_ids[$subgroup_id] : [], array_intersect_key($role_map[$subgroup_id][$group_id], array_flip($roles)));
        }
      }

    }

    foreach ($mapped_role_ids as $group_id => $role_ids) {
      if (!empty(array_unique($role_ids))) {
        $this->mappedRoles[$account_id][$group_id] = array_merge(isset($this->mappedRoles[$account_id][$group_id]) ? $this->mappedRoles[$account_id][$group_id] : [], $this->entityTypeManager->getStorage('group_role')->loadMultiple(array_unique($role_ids)));
      }
    }

    return $this->mappedRoles[$account_id];

In InheritGroupPermissionCalculator.php, change the end of calculateMemberPermissions to the following:

      $group_role_array = $this->hierarchyManager->getInheritedGroupRoleIdsByMembership($group_membership, $account);

      foreach ($group_role_array as $group_id => $group_roles) {
        $permission_sets = [];
        foreach ($group_roles as $group_role) {
          $permission_sets[] = $group_role->getPermissions();
          $calculated_permissions->addCacheableDependency($group_role);
        }
        $permissions = $permission_sets ? array_merge(...$permission_sets) : [];

        $item = new CalculatedGroupPermissionsItem(
          CalculatedGroupPermissionsItemInterface::SCOPE_GROUP,
          (string) $group_id,
          $permissions
        );

        $calculated_permissions->addItem($item);
        $calculated_permissions->addCacheableDependency($this->entityTypeManager->getStorage('group')->load($group_id));

      }
kkasson’s picture

A couple more notes to the above:

1) This line in GroupHierarchyManager.php is definitely broken with my other changes. This could perhaps be the source of my caching problems.

    if (isset($this->mappedRoles[$account_id][$group_id])) {
      return $this->mappedRoles[$account_id][$group_id];
    }

2) I was also noticing some major performance problems coming from calculateAuthenticatedPermissions in the main Group module's ChainGroupPermissionCalculator. It was calling the merge function thousands of times. I added some quick static caching that solved the problem for me, at least as a workaround. The other methods in that file were being cached correctly, but it was still having to merge those cached results. I'm not sure if that's actually an issue with that method itself or if it indicates a problem further down the line in these subgroup permissions.

lobsterr’s picture

@jlscott I like the idea, I think we should do it. I started to work on it.
1) I propose to create a separate ticket for subgroup code only;
2) This issue we will keep for a new module. I propose the name ggroup_role_mapper, because this ticket keeps the most of the discussions related to the group role mapping

@kkasson I will investigate the cases provide by you after the split of the modules.

lobsterr’s picture

Finally, I have done the split. I decided to create two separate tickets. So, it would much easier to handle it and for newcomers easier to contribute. In this issue there are too many comments.

1) Subgroups core module #3084140: Subgroups core module
2) Subgroups role mapper module #3084153: Subgroup role mapper

catch’s picture

Status: Needs review » Closed (duplicate)

Let's mark this as duplicate of the two issue in #266 and continue in those.

catch’s picture

Status: Closed (duplicate) » Needs review

Er except the patch didn't make it to #3084140: Subgroups core module.

catch’s picture

Status: Needs review » Closed (duplicate)

Both patches are uploaded to the spin-off issues, marking as duplicate now.

andrewsizz’s picture

StatusFileSize
new117.33 KB

Delete view subgroup, as this view have references to field gc__group which already not exists

andrewsizz’s picture

StatusFileSize
new117.34 KB

updated patch for latest version

dbielke1986’s picture

@AndrewsizZ

Why did you post something in an closed item.
This issue have been splitted up to two seperate items:

#3084153: Subgroup role mapper,
#3084140: Subgroups core module

I think we should not update this issue right here...