Problem/Motivation
gnode provides the ability to set permissions by node type, e.g. View unpublished content entities.
It would be great to also expose permissions for content moderation transitions for group-related nodes per group role... E.g. Use Publish transition from Foo workflow.
There have been other feature requests for integration with contrib modules (workflow, workbench) but integrating with D8 Core seems like a logical first step.
I am about to start writing a patch, so any pointers or advice from maintainers would be welcome...
Proposed resolution
Development continues in a seperate module. Use this instead of the patch in this issue: https://www.drupal.org/project/gcontent_moderation
Switching an existing site from the patch to the new module (not tested):
- Uninstall module from the patch
- Remove patch
- Require new module
- Enable new module
Remaining tasks
Convert state transition validation to a decorator serviceDecorate the latest version access service
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #95 | interdiff-80-95.patch | 886 bytes | jorgegc |
| #95 | group-content_moderation-2906085-95.patch | 40.62 KB | jorgegc |
| #91 | permissions.png | 84.12 KB | shelane |
| #80 | interdiff-70-80.txt | 2.29 KB | nikitagupta |
| #80 | 2906085-80.patch | 40.62 KB | nikitagupta |
Comments
Comment #2
Chris Gillis commentedComment #3
Chris Gillis commentedComment #4
Chris Gillis commentedInitial patch attached. Works, but no tests written yet and needs some refactoring. Very happy to take advice from maintainers if this is going in the right direction? Not keen to put too much effort in if this feature won't be considered for inclusion.
Comment #5
Chris Gillis commentedUpdated patch also works on node creation form.
Comment #8
Rkhatun commentedUpdated patch for latest Drupal 8.4 Core update
Comment #9
dylan donkersgoed commentedThe last patch fixed the issue I had with 8.4 but didn't apply for me. Here's a fixed version and an interdiff.
Comment #10
socialnicheguru commentedI get a fatal error with this patch on this page, admin/group/types/manage/mygroup-type/permissions:
Error: Call to undefined method Drupal\workflows\Entity\Workflow::getTransitions() in Drupal\group\Plugin\GroupContentEnablerBase->getGroupModerationPermissions() (line 269 of drupal-8.4.0/html/modules/contrib/group/src/Plugin/GroupContentEnablerBase.php
getTransitions() is defined here:
core/modules/workflows/src/State.php:98
core/modules/workflows/src/StateInterface.php:74
core/modules/content_moderation/src/ContentModerationState.php:110
Comment #11
dylan donkersgoed commentedRan into the same issue as SocialNicheGuru above, patch and interdiff attached.
Comment #12
jhedstromAwesome to see this work started! We'll also need to modify how content moderation handles access to the latest version tab.
Some initial thoughts on the patch:
This will make Group incompatible with other modules that need to override this. Instead of hijacking the service, it would be good to utilize a decorator here. See
workflow_participants.services.ymlandStateTransitionValidatefor an example.I'll see how far I can get on these remaining issues.
Comment #13
jhedstromAfter some initial research, I think it will make more sense to split the latest revision access override into a separate issue. I've added #2935786: Content moderation integration: latest revision access override, and re-titled this one.
Comment #14
jhedstromIt isn't actually possible to separate latest version access out from this, so I've closed #2935786: Content moderation integration: latest revision access override out as a duplicate and will try and tackle this issue.
Comment #15
jhedstromThis patch utilizes service decorators to achieve the ability to override content moderation's access checks at the group level. I've also added some tests, including one that verifies compatibility with other modules that might also be decorating these services.
Comment #17
jhedstromOops, clearly needs some work on making these decorations conditional.
Comment #18
jhedstromIt turns out that decorated services cannot be optional, so this changes the approach to utilize
GroupServiceProvider::alter()to decorate the content moderation services when that module is enabled.Comment #19
jhedstromComment #20
jhedstromThe last patch had an unnecessary change to
group.services.ymlcausing it to not cleanly apply to rc1.Comment #21
jhedstromSmall issue with the title arguments not being replaced on the permissions form.
Comment #22
kevin.dutra commentedSince the real decorators were changed to be applied by the
ServiceProviderdue to the conditional troubles, should these test ones also be moved to mimic that same approach?Comment phrasing: The group member should have access, if we're checking for 200s.
Comment #23
jhedstromSince the test module can require
content_moderationI think it's clearer to utilize the service YAML file. The tests also ensure that both decorators are applied, so we know that core's service registration is working either way.This patch fixes the typo mentioned in #22, and caught another one :)
Comment #25
jhedstromWow, for some reason #2927746: Update Symfony components to 3.4.* broke this approach. I'm digging in now to figure out why.
Comment #26
jhedstromThe failures were due to services now defaulting to private in Symfony 3.4. I left a comment on #2927746-93: Update Symfony components to 3.4.*.
Comment #27
kevin.dutra commentedWow, perfect timing. :)
I haven't manually tested this out so I won't mark it RTBC, but I've done a full code review, so from that perspective RTBC+1.
Comment #28
arosboro commentedI'm about to review this, but I could see this as being useful for group_membership group content where there are states and a workflow that ties into whether a member is considered an outsider or not (Pending/Banned) even if they have a membership relationship to the group.
I have essentially re-written https://www.drupal.org/project/group/issues/2752603 with configuration entities similar to roles as states for memberships but Core Drupal 8 content moderation would be favorable IMO, and I am considering abandoning that approach.
Comment #29
jhedstromComment #30
sukanya.ramakrishnan commented@jhedstrom, i found a minor issue in this patch, when a content is created in a group, the StateTransitionValidation is not merging the global permissions with the group level permissions.
Submitting a patch for the same with an interdiff.
Seems the test coverage is missing the usecase with adding a content within a group, will add tests for this shortly.
Thanks
Sukanya
Comment #31
jhedstrom@sukanya.ramakrishnan good find! We'll need to update the tests to catch this, but the fix looks solid.
Comment #32
jimsmith commentedI tested the patch at #30 and it looks solid. It did the job as expected with no noticeable errors.
Thank you!
Comment #34
Jaesin commentedThe tests are no longer passing against with the latest core (8.6.x) so some api's must have changed. Config import for
GroupTypeImportTest::testImportno longer works but that is not related to this issue.The patch in #30 isn't working for me. I still just get the save button without a moderation state selector on
group/1/content/create/group_node:foowhen I enable moderation for a content type and set the permissions for the user in group permissions. I haven't tried to debug it yet. Maybe tomorrow.I was wondering if this functionality should be a sub-module? Maybe
group_content_moderation?Comment #35
Jaesin commentedRe-roll fixes the current set of tests.
Comment #36
dylan donkersgoed commentedThe getPluginId() method of this patch assumes a derivative plugin with bundles but that may not be true. I have a custom entity plugin which is generic to all bundles. My group uses this plugin with moderation states. I'm attaching a patch which looks up the plugin ID with the content enabler manager. It prioritizes a bundle plugin then falls back to a generic one then back to just returning FALSE.
As a side note, this is the first I've seen of Symfony service decorators. I'm sure I'll use this patch as a reference for them in the future.
Comment #37
dylan donkersgoed commentedHere's an updated patch for the 8.6.2 security update. It adds an isTransitionValid() method to StateTransitionValidationInterface which causes the previous patch to crash the site. I added an implementation of that method.
StateTransitionValidationInterface::isTransitionValid() doesn't pass in the current entity so this patch fetches it from the route. Not 100% sure that will work in all cases....
Comment #39
kevin.dutra commentedFYI, I've opened a core issue because of that change.
#3007716: Security update introduces breaking changes to content moderation
Comment #40
kevin.dutra commentedBased on the current direction of the core issue, here is a revised patch. Since this is a different approach from #37, the interdiff is based on #36.
Also there's some test tweaks to fix a problem with the patch applying and minor documentation fixes to the plugin ID changes from #36.
Comment #42
kevin.dutra commentedOops, apparently there was also an implementation in a test.
Comment #43
kevin.dutra commentedOops, that doesn't quite work. Since it is called within the context of entity validation, the entity's moderation state is actually the new one, not the current one, which borks up the list of valid transitions. This version ensures that the current moderation state is actually used.
Comment #44
dame commentedHi, I think this code won't be compatible with php 7.2. You cannot add an argument to an inherited method's signature.As explained in this comment https://www.drupal.org/project/drupal/issues/2927173#comment-12363396 you will get a fatal error in php 7.2
Ok never mind, adding arguments seems to be permitted as long the next class in line to inherit doesn't remove the new argument in it's own signature. I am leaving my comment online so it can be corrected if I'm wrong.
Comment #45
dame commentedSo I hadn't figured out that patch 43 only workded with the patch of Drupal Core in the other issue. I connected the dots in my head and tested #43. It is working nicely!
Thanks for your work ;)
Comment #46
lcube commentedReally nice work and support (BC breaks around content_moderation are really a pain)
Comment #47
elimw commentedI have updated the patch so that for new entities, the default moderation state is used rather than that of the validated entity that is passed into StateTransitionValidation::isTransitionValid() as that will be using the new state.
Comment #48
wim leersPer #3035113: Replace content moderation specific access check in JSON:API with generic revision access check, please make this patch subclass
Drupal\content_moderation\Access\LatestRevisionCheck. That would signal that they provide a customized version of the same behavior and provide the same guarantees.(If you want to know why the JSON:API module is disallowing
AccessInterfaceimplementations and requiring that particular class — or subclasses thereof, see #3035113-3: Replace content moderation specific access check in JSON:API with generic revision access check and #3035113-6: Replace content moderation specific access check in JSON:API with generic revision access check.)Comment #49
dylan donkersgoed commentedWith 8.7.x I've been encountering an issue where nodes are always saved as draft when using this patch. This seems to be happening specifically because of presave validation that traces back to layout_builder_entity_presave(), so it may be layout builder specific.
The issue is that Drupal\group\StateTransitionValidation::isTransitionValid() sets the entity state like this:
but then it never resets it. Previously this was fine (I guess because it never saved the entity) but since it's getting invoked in presave in this case it actually changes the state in the process of checking whether it's valid. I've attached a patch which remembers and resets the state after it has finished the check.
The issue noted by Wim Leers above remains so I'm leaving this at "Needs Work".
Comment #50
rudy.barrett commentedThis is a great patch and almost gets me where I need to go. I would also like to add the ability to View, Edit, Delete group nodes in a specific Workflow State.
ex: Group node (CT) - "Edit" Latest Version in transition state "Draft" workflow.
Essentially making it where a user must be a member of a group, have an editor user role, and the node within the group must be in a specific workflow state in order for that user to make edits. Currently Workflow_Access and Group Permissions appear to override each other.
Has anyone tried this additional level of granular permission control?
Comment #51
jazzfiction commentedComment #52
jazzfiction commentedIn using patch #49, I got the following error when trying to clear the caches with Drush:
PHP Fatal error: Uncaught TypeError: Argument 1 passed to Drupal\jsonapi\Access\EntityAccessChecker::setLatestRevisionCheck() must be an instance of Drupal\content_moderation\Access\LatestRevisionCheck, instance of Drupal\group\Access\LatestRevisionCheck given in /var/www/html/group-dev/htdocs/docroot/core/modules/jsonapi/src/Access/EntityAccessChecker.php:150
Stack trace:
#0 [internal function]: Drupal\jsonapi\Access\EntityAccessChecker->setLatestRevisionCheck(Object(Drupal\group\Access\LatestRevisionCheck))
#1 /var/www/html/group-dev/htdocs/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(329): call_user_func_array(Array, Array)
#2 /var/www/html/group-dev/htdocs/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(502): Drupal\Component\DependencyInjection\Container->createService(Array, 'jsonapi.entity_...')
#3 /var/www/html/group-dev/htdocs/docroot/core/lib/Drupal/Component/DependencyInjection/Container.php(237): Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters in /var/www/html/group-dev/htdocs/docroot/core/modules/jsonapi/src/Access/EntityAccessChecker.php on line 150
[warning] Drush command terminated abnormally. Check for an exit() in your Drupal site.
It looks like Group's instance of LatestRevisionCheck is being passed to those that need it, but it isn't the instance they are expecting, and it is throwing an error.
Comment #53
goldWe've been using the patch at #47 for sometime now and the update to #49 seems to have kept things working also.
We had an issue with workflow transitions though. It turned out that the moderation_state that was used in $this->getValidTransitions() was not working for us. We have a number of transitions and they're not all available to all users. We were finding that the moderation_state that was being used was the value of the state we were transitioning to, rather than the state that was currently there. This resulted in the wrong transitions being returned.
This addition to the patch appears to fix this. In our case we were also working with translations and the node being worked on was actually a translation rather than the original default language. This feels like we should be working with the translated node to me, but that would be the $entity that was passed in, isn't it? With the way this part of the code is being used the $original_entity is only used for lookup purposes and is not returned or passed in by reference.
I'm not 100% on this but it seems to work. More eyeballs on this would be appreciated.
I will leave this in a Needs Work state as it doesn't address the points in note #50.
If I can find the time (and figure out how) I'll add tests for this later.
Additional: I have been unable to replicate the issue at #52
Comment #54
socialnicheguru commented#52 - this patch will help - https://www.drupal.org/project/drupal/issues/3035113#comment-13092187
Comment #55
sergiuteaca commentedI had the same problem with moderated content in groups that is multilingual as @Gold but handled it a little different.
I am not setting anything in the moderation, I just make sure that the right revision with the right language is loaded.
Because here is exactly this problem. In my, and @Gold's case, the $original_entity is loaded with the default language, and in case we are editing a different language in the $original_entity->moderation_state->value we get the value from the default language.
My patch is practically exactly like #49 and #53 with small differences.
Comment #56
jdearie commentedPatch 55 is working for me - in that it allows me to manage content moderation by group rather than a site-wide permission role.
it also gives my users the Latest Revision button to access unpublished drafts... but the Revisions tab that lists all the revisions of a node is missing. it appears that permission to View revisions by content type is still only in site permissions.
I would love to see that permission moved into groups as well.
Comment #57
mxr576With patch #55 I see content moderation related permissions (ex.: XY group content - Use Create New Draft transition from YZ content moderation workflow.) in group level, even if the XY group content is not part of the YZ content moderation workflow.
Comment #58
merauluka commentedThe direction of this patch overrides the
StateTransitionValidationclass provided by core. In so doing it is causing an ajax error with the contributed module Workflow Buttons which is unfortunate.I'm thinking this won't be the only breakage in the moderation space if this particular implementation continues.
Comment #59
merauluka commentedI have rerolled the patch from #55 to reference the original core validation class being overridden in this issue. Additionally I have renamed the group module's version of the validation class to prevent confusion.
Comment #60
strozx commentedI have tested the patch from #59 it seems to work but I'm gonna leave this open if anyone else wants to review it.
RTBC +1
Comment #61
dwkitchen commentedI further reroll against current dev.
Comment #62
ggj commentedCan I request some clarifications on "how to" for this thread, specifically the patch #61.
I applied the patch, did cache rebuild and rebuilt permissions, however, I don't see any new permissions in the group_type/permissions or people/permissions.
It was applied on Group 8.x-1.x-dev, and I already had subgroups core patch applied on it.
I read through the comments and other patches. And also went through the workflow config etc.
Do I need to configure something or am I missing something obvious?
Thanks in advance
EDIT: to clarify, Group Node is enabled and my Group Type has Content Type with a workflow enabled. The group cardinality with the content type is 1.
Comment #63
dwkitchen commented@ggj I have lost some lines in my re-rolling. I have just come back to this.
There have been a lot of changes in Group permissions and this works will be a Group v1 option and will need updating for Group v2
I'll update with a new patch.
Comment #64
dwkitchen commentedSo even adding the permission provider back in the GroupContentProviders have been updated.
It would be possible to add something into GroupContentPermissionProvider that would add workflow permissions for Entities enabled as group content.
However, this would not cover other entities that might have content moderation- e.g. files/images that are referenced on content added to groups.
I'm thinking there may need to be a setting to add a workflow to a group/s so you can see its permissions; which would be better than just adding all workflows to all group if they are relevant or not.
Comment #65
dwkitchen commentedRebuilt as a sub-module
gcontent_moderationwith a Group permission_callbacksContent moderation permissions aren't linked to the Content Plugin directly. So if you add more than one content type to a group and they have the same moderation workflow; the permission will apply across both content types.
Comment #67
dwkitchen commentedFixing tests and coding standards
Also, use GroupRouteContextTrait
Comment #69
dwkitchen commentedFurther fixes to test
Comment #71
dwkitchen commentedTests don't install dependencies so include content_moderation in the list.
Comment #72
dwkitchen commentedTests also need to have the test module enabled
Comment #73
dwkitchen commentedRenamed the decorator services which fixes the issue in the test and made two functions in the service public as I am decorating this service in my module and want to use
$this->inner->allowedTransitions($user, $entity, $groups)Comment #74
azinck commentedThe patch uses getInitialState() incorrectly. The actual entity should be passed, not the workflow. Corrected patch attached.
Comment #76
shelaneOn a brand new site install with Group 1.1 and the patch from 74 installed, I get this error block:
It seems this has already been reported and the core patch does solve it, but wondering if there will be an issue with Drupal 9. I'm on 8.9.2 currently.
Comment #77
deepikakaran commentedWe are currently using this patch on Group RC1 and its works. Though Groups 1.2 available now, is there any patch available for the new release or is it moved already?
Comment #78
oktboy commentedWe installed the latest version of 'Group' and got issues with PATCH #61. What versions does it work with?
We want to create Group permissions for transitions. The user can be in different groups with a different role, so having transition permissions per role at the user level does not work. We want to silo each group where a user can have different roles in different groups.
Comment #79
a_mitch commentedthis patch adds group permissions for using workflow transitions per node type.
Comment #80
nikitagupta commentedcontent_moderation.state_transition_validationis renamed asgcontent_moderation.state_transition_validationComment #81
nikitagupta commentedComment #83
anruether@oktboy What issues exactly do you face? What you describe is exactly what this patch is supposed to do. (I'm still using RC5 and #43 and haven't tested newer group/patch versions yet)
@amitch Isn't this what the patch already did (at least #43 did)? What exactly did you change and why?
Comment #84
anruether@kristiaanvandeneynde Is this something you would want to add to group module or do you think this should live in a seperate module? As per #2984315-56: Media enabler
Comment #85
dwkitchen commented@arosboro & @kristiaanvandeneynde I think this should be part of the core Group module as Content Moderation is part of Core Drupal (and goes with
gnodebeing part of core Group).I would be tempted to use different workflows if they have they have different access requirements - this aligns close with core permissions I think (unless like @amitch's patch it just does it for nodes, I'm using it on my own custom entities)
Comment #86
shelaneHas any of these patches been tested with 1.3?
Comment #87
devkinetic commentedSo I have a question, I've written my own module which models how content moderation works, all using core workflows and the workflows_field module. Would this addition require that I have content moderation installed and in use or does it integrate with core workflow transitions and states?
Right now, I have this all working by giving group roles a matching system role, which gives them access to the transition permissions. Obviously a fragile system, but it fit the bill for a limit use-case.
Comment #88
azinck commented@shelane I'm using it with 1.3 with no apparent ill-effects.
Comment #89
kristiaanvandeneyndeWell, menus are also part of core, yet Group Menu is a separate module :) So is Subgroup even though "Group" is part of Group :D
That said, I'm probably going to reviewing this Soon™ to see whether it needs to go into Group or a a separate module.
Comment #90
kasey_mk commentedDrupal 8.9.10, Group 1.3.0
#80 threw an error when I tried to enable the gcontent_moderation submodule.
#79 seemed to work at first but after enabling some permissions I got this error when trying to clear caches:
PHP Fatal error: Uncaught TypeError: Argument 1 passed to Drupal\jsonapi\Access\EntityAccessChecker::setLatestRevisionCheck() must be an instance of Drupal\content_moderation\Access\LatestRevisionCheck, instance of Drupal\gcontent_moderation\Access\LatestRevisionCheck given in /Users/kasey/Sites/devdesktop/uua-org-d8/web/core/modules/jsonapi/src/Access/EntityAccessChecker.php:150
Comment #91
shelaneI currently have #74 with group 1.3. We previously had #55 with 1.0-rc5. In both cases we discovered that users who should not have permission to a transition (i.e., publish) were still able to see that option in the content moderation selection and apply it. I tested by both the content moderation that displayed on the detail page and on the edit page. So in this screen shot, the role (name is not shown in the image) "Review" should not have access to "Use Publish transition" on either the editorial workflow or the simple workflow. However, they can anyway.
BTW, I also tried with #79 and it was the same.
Comment #92
anruether@shelane: which global permissions do you have set? Do they make a difference?
Comment #93
shelaneYes, globally there is one role for the users. That is why I use groups to manage roles and permissions because it is their role within the group that should determine their ability to create or publish content. So with that, that role globally has permissions for the transition. If that is off, they have no permissions for the transitions.
Comment #94
veperr commented@azinck, I got that you're using 1.3 of groups, but which patch # are you using without issue? Also, which version of Drupal?
@anyone: which version of the patch works with Groups 1.3 & Drupal 9?
Comment #95
jorgegc commentedI have tested #80 with Group 8.x-1.3 and the permissions were correctly enforced. Although, the "Latest version" tab was missing and then I realised that the LatestRevisionCheck class was checking for the wrong permission name.
Uploading new patch and interdiff for review.
Comment #97
pcate commentedSetting back to "Needs Work" because of failed test with latest patch.
Comment #98
lcube commented@veperr For now i'm having a nice experience with group 1.3 drupal 9.1.x and patch #95
I've checked my basic use cases and no trouble for now
I was using before with success drupal 8.9.x, group-rc-1.5 and patch #43
Hope this help for anyone
By the way, this module is awesome and a great inspiration
Thanks
Comment #99
bramtenhove commentedGreat work on this feature! Looks like it's working quite well.
I've been thinking a bit about the question raised in #84 by anruether:
I think this feature should be a standalone module.
Even though this functionality is in Drupal Core, it doesn’t have to be in the Group module for that reason. For example Group Menu is also not in the Group module.
One of the things kristiaanvandeneynde mentioned in the comment is that he likes to keep the Group module lean. And considering this is already proposed as a submodule, wouldn't it just be better to move it into a standalone module?
I assume kristiaanvandeneynde also has only limited time to contribute to this or move it forward. Having this in a separate module might also speed up a release.
Comment #100
jaapjan commentedI also have some additional patches to deliver for this module, including support for a "Moderated content" tab on a Group with all the correct filters and the "View own unpublished entity" permission. I think it might be best to create a contrib project for this module. It might also help with moving additional features forward and keep better track of patches and issues.
Comment #101
dgaspara commentedWorks for me. Thanks!
Comment #102
dgaspara commented* #95 Works for me. Thanks!
Comment #103
anna_elkb commentedI am using Drupal 9.1.4 and Group module 8.x-1.3. When using the group-content_moderation-2906085-95.patch I get the following error after enabling the "Group Content Moderation" module:
Comment #104
ronaldtebrake commentedAfter discussing this on Slack with @kristiaanvandeneynde it seems this is a good candidate to move to a separate contrib module.
As pointed out by Kristiaan: The idea in this case for the plugin handlers is to declare them as a service, and instead of pointing it to a class in the annotation, we can point to a service.
This should allow the plugin handlers of GroupContentEnablers to be decorated as we please and ensure we don't run in to issues where only one instance can decorate them.
Comment #105
bramtenhove commentedCheck, thanks for the clarification @ronaldtebrake.
@jaapjan (#100) made the patch available at https://www.drupal.org/project/gcontent_moderation with some additional fixes.
I think it's important to add credits at the module page for everyone participating in the patch. And anyone that wants to be added as maintainer is obviously more than welcome, I created the issue for that here.
Comment #106
shelaneSo, removing the patch from composer and requiring the new module results in this error (when drush cr runs):
What is a good "update" path? To make this work, I will have to a release that relies on configuration sync and updates.
Comment #107
anruetherYou should definitely uninstall the module from the patch before removing the patch from composer and only then install the new module. The thing is the code is now in another place and drupal has problems with moving modules around.
Apart from that: Any issues with the new module should be reported in the modules issue queue. I propose to close this issue as won't fix.
Comment #108
anruetherI should be a bit more careful proposing this, since I'm not 100% sure if there could be data loss. But from what I understand how the module works, that should not happen.
Comment #109
bramtenhove commentedAgree, I don't think it makes sense to keep this open. Better to continue the work at the module issue queue.
Additional to what anruether mentioned, you may also want to regenerate the Composer autoloader files. You can do that via
composer dump-autoloadafterwards runningdrush cr. Hope that helps.Comment #110
anruether