Problem/Motivation
#2934995: Add a "Manage permissions" tab for each bundle that has associated permissions applied to all entity types that have bundles and set field_ui_base_route in the entity annotation. That issue was originally fixed in 9.3.x, then reverted because it conflicted with existing admin paths for at least one contrib module.
#2934995 was not reverted in the 9.4.x branch. One option is to leave it as is and warn contrib module maintainers to update their modules to be compatible. This issue is to implement another option: only add the new Permissions form if a module adds certain annotations to its entity classes.
Proposed resolution
- Replace the route subscriber with a route provider.
- Register a new link type.
- Add annotations to core classes to use the new link type and route provider.
Remaining tasks
- Update the change record Add "Manage permissions" tab after "Manage display"
User interface changes
None
API changes
Replace Drupal\user\Routing\RouteSubscriber, which was added in #2934995: Add a "Manage permissions" tab for each bundle that has associated permissions, with Drupal\user\Entity\UserPermissionsRouteProvider.
Data model changes
None
Release notes snippet
Modules that define entity types can easily add Permissions forms for their entity types. See the change record https://www.drupal.org/node/3242827 for more information.
| Comment | File | Size | Author |
|---|---|---|---|
| #30 | entity-permissions-empty.png | 60.42 KB | benjifisher |
Issue fork drupal-3253955
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
benjifisherI created a MR for this issue, so I am setting it to NR.
The failing tests in #2934995-124: Add a "Manage permissions" tab for each bundle that has associated permissions are because the new link type was not declared. I fixed that by adding
user.link_relation_types.yml. But then the same tests failed a few lines later. I tracked this down toDrupal\rest\Plugin\rest\resource\EntityResource::addLinkHeaders(). It seems that these link templates have to be added to the bundle entity type (such as NodeType, not Node).I think we should improve the documentation for link templates. If there is any documentation explaining the points I just mentioned, I could not find it.
Since #2934995 adds the bundle-specific Permissions form to any entity that has bundles and sets
field_ui_base_routein its annotations, I enabled the form for the following entity types:I am pretty sure we want the Permissions form for the last three. Maybe we also want it for the first three. Even if the module defining an entity type does not define bundle-specific permissions, other modules may. In particular, the core Configuration Translation and Layout Builder modules create permissions for any configured bundle types. The access checker added in #2934995 makes sure not to show the page unless there are some permissions to manage.
Comment #4
benjifisherIn the commits I just added, I dropped the check for
field_ui_base_routewhen defining the route. I kept that check when defining the local task.If
field_ui_base_routeis not defined, should we still create a local task? If so, should the base route be the edit form for the bundle?Comment #5
benjifisherI am adding related issues. I think the issues for the Group module can be closed (outdated) if this issue is fixed.
Comment #6
benjifisherHere is a shortened version of @Berdir's review from #2934995-126: Add a "Manage permissions" tab for each bundle that has associated permissions:
I don't think you need to worry about this case, bundle is always defined, even for entity types that don't have bundles.
Hm. I think I missed how the url/route access is called through this, makes sense that we tried to optimize it then. This is quite slow. not only do we need to go through route upcasting, the access check then loads the bundle entity and does the permission check.
Do we really still need that? ...
My replies:
According to @danflanagan's testing (see the MR for #2934995) the slowest part of the access check is not the overhead of
$url->access()and it is not calculating the permissions. The slowest part is computing the config dependencies.Comment #7
kristiaanvandeneyndeCode looks good to me, this will allow me to not have the new form enabled for my entity types and therefore remove any chance of a conflict. Thanks!
Comment #8
benjifisherI just added #3254866: Update the deprecation notices related to "Manage Permissions" pages.
Comment #9
kristiaanvandeneynde@benjifisher Code looks good, just some naming concerns and berdir's comments are on point too. From a code point of view it's already RTBC as far as I am concerned, just need to polish it a bit more as per the comments we left.
Comment #10
benjifisher@Berdir, @kristiaanvandeneynde:
Thanks for the reviews. I updated the MR with your recommendations. I am afraid I made the testbot work a bit, but I hope the latest commit will pass tests.
Comment #11
benjifisherOne more fix for
core/modules/system/tests/src/Functional/Menu/LocalTasksTest.php.There is another failing test, but that is because of #3255749: Composer v2.2 prompts to authorize plugins.
Update: the failing test is caused by #3255836: Test fails due to Composer 2.2.
Comment #12
kristiaanvandeneyndeLGTM
Comment #13
alexpottWe need to update the draft CR to be correct before we commit this.
We also need to update the issue summary - there's the release note section and a to be determined.
Comment #14
benjifisherI updated the CR https://www.drupal.org/node/3242827.
No one replied to my comment in #3 about the core entity types, so the current MR does what I said there: it enables the Permissions form for every core entity type that was affected by #2934995: Add a "Manage permissions" tab for each bundle that has associated permissions. That means that this issue does not create any user interface changes.
Or should I consider contrib modules as well? A contrib module might get a Permissions form after #2934995, and it will be removed by this issue unless the module is updated to "opt in".
I added a release-notes snippet.
I am removing the tags for CR/IS updates. Since there are no changes to the MR, I am moving the status back to RTBC.
Comment #15
alexpott@benjifisher as this feature has not been released
is not an issue as far as I can see. We need to ensure the CR for #2934995 details how to opt in as a contrib module.
Comment #16
alexpott@benjifisher the current change record look really good. Nice work.
Comment #17
aaronmchaleThis is really good, thank you for all the effort here!
I really like
bundle-permissions-form.Have added a couple of minor comments to the MR.
Comment #18
kristiaanvandeneyndeStill RTBC from my end, those nitpicks don't change that :) So AFAIC, once you address those small bits, feel free to set right back to RTBC
Comment #19
benjifisherThanks to all for the attention to this issue.
I am happy to have the status set back to NW.
While revising the CR, I looked at the code again and realized how little it has to do with bundles. Originally, this feature had a lot to do with bundles. We start with a content entity, like Node, then look for the bundle entity, like NodeType.
In the current version, we start with the bundle type and look for the related (content) entity type. But that is only used in a few places:
field_ui_base_routemay be set. The deriver for local tasks (tabs) needs this to decide where (if anywhere) to add local tasks.permission_granularitymay be set to "bundle". If so, then the access checker skips the dependency calculation and grants access.Of these, (1) makes a lot of sense, but it is independent of the rest of the feature.
In order to support (2), the route provider checks whether the current entity type is a bundle type. If not, it exits early. If so, then it adds an extra default to the route to save a few steps for the access checker.
Instead of (2), we could provide an "opt in" strategy for the access checker. The Node module creates permissions based on each NodeType entity (content type). It can opt out of the access check. The Block Content module does not create permissions for each BlockContentType entity (custom block type), but other modules (Layout Builder, Configuration Translation) can. So Block Content should opt in to the access check.
The mechanism would be to provide two route providers. One would extend the other and provide the access checker.
What do you think? Should I make the changes requested in #17 and open a follow-up issue for this suggestion? Or if everyone thinks this is a good idea, then I can implement it as part of this issue.
Comment #20
benjifisher@AaronMcHale:
I disagree on both points: see my replies on the MR (or the MR comments should appear just above this).
As I said in #19, I am thinking of making further changes anyway, but for now I am setting the status back to NR with no code changes.
Comment #21
aaronmchale1 thread can now be resolved, commented on the other.
GitLab and me are about to fall out, the UI it kept jumping around, and the "resolve thread" button apparently isn't actually doing anything for me.
Comment #22
benjifisherRight, only the person who opens the MR, and maybe core committers, can resolve a thread. I think the person who opens a thread should decide when it can be closed, so thanks for being explicit about that.
I marked one thread as resolved, and I replied on the other.
Comment #23
benjifisherThe commits I just added implement part of what I suggested in #19.
When I wrote #19, I forgot one crucial use of the "related (content) entity type". We need it in order to use EntityBundleRouteEnhancer (formerly FieldUiRouteEnhancer). The job of that route enhancer is to provide a
(string) $bundleparameter to the form builder, even though the original parameter is something like$node_type.Getting around that seems out of scope for this issue. I may work on a follow-up issue to do it. Then again, that may be a solution without a problem.
I did make several changes with the idea that we might later remove the reliance on EntityBundleRouteEnhancer:
entity.$entity_type_id.bundle_permissions_formtoentity.$entity_type_id.entity_permissions_form.bundle-permissions-formtoentity-permissions-form.I also gave into temptation and fixed a couple of code comments. (See the commit messages starting with "Fix".)
If any of that seems out of scope for this issue, I can revert those commits.
The substantive changes to implement the opt-in strategy for the access checker are
entity_permissions_formroute.Change Bundle to Entity in method names, variable names, and comments.
Comment #24
benjifisherI think the test failures are not related to this issue/MR. See #2829040-143: [meta] Known intermittent, random, and environment-specific test failures.
Comment #25
aaronmchaleTo summarise Benji and I's discussion about whether we need
_admin_route(since we had a parallel Slack thread going). We seem to have settled on letting a Core committer break the tie on whether it should be included or not.That aside, I've had a look over the recent changes, which benji detailed in #23, overall I think those are sensible
entity-permissions-form/entity_permissions_form, can we simplify that topermissions-form/ermissions_form, or does that come too close to causing the same issues with the group module, as the word "entity" seems redundant there?For those implementing this in custom/contrib entities, we need to be really clear about when it's appropriate to use
UserPermissionsRouteProviderWithCheckvsUserPermissionsRouteProvider, we could add more info to the docblocks in addition to the change record and also on the entity API docs pages.Do we need to prefix those classes with
User, seems redundant and possibly confusing, implying that they are specifically for user permissions?Comment #26
benjifisherI do think the shorter version runs the risk of conflicts. The longer version will be consistent with the proposed changes (see below) for the class names.
I will add something to the doc blocks.
I am reluctant to refer to Object-oriented code > Naming conventions. The recommendations there confuse me.
Let's look at what core modules have so far:
I wish the namespaces were more consistent: Routing, Entity, and Entity\Routing are all used.
Both NodeRouteProvider and UserRouteProvider are used only in the modules that define them. I did not check the others.
So I think the question, and the implicit suggestion, are on point. There is no need to start the class names with User.
@AaronMcHale, will you be disappointed if I change the class names to EntityPermissionsRouteProvider and EntityPermissionsRouteProviderWithCheck?
While I am at it, maybe I will change UserPermissionsEntityForm to EntityPermissionsForm.
Comment #27
alexpottAfter discussing this with @catch we decided to revert #2934995: Add a "Manage permissions" tab for each bundle that has associated permissions from 9.4.x to give us a chance to land this in 9.5.x. Hopefully we can land this soon. Thanks @benjifisher for all the efforts to get this done - unfortunately 9.4.0 is about to reach alpha. Maybe if we land this very very soon we'll revert the revert and get this in the 9.4.0 alpha too.
Comment #28
benjifisherI rebased on the 9.5.x branch because of #27. I made the changes I promised in #26:
Comment #29
aaronmchaleRe #26:
Sounds good.
Thank you!
+1 to that!
That is definitely clearer, thank you!
I do wonder though, should we add the word
FormafterEntityPermissions, or would be too verbose of a class name, so for exampleEntityPermissionsFormRouteProvider. Just a suggestion,EntityPermissionsRouteProvideris still fine so either way happy to leave it at that.+1 to that!
Comment #30
benjifisher@AaronMcHale:
See #28: I already made the changes that I proposed in #26.
I do not really like ReallyLongClassNames, so I think I prefer not to add "Form" as in
EntityPermissionsFormRouteProviderandEntityPermissionsFormRouteProviderWithCheck. Since you listed that as a suggestion, are you willing to call this issue RTBC?One other thought: now that we make it possible to opt in or out of the access check, it is possible to get an empty form. I hacked
BlockContentTypeto generate this screenshot:I think we should avoid the do-nothing form, but maybe we can leave that for a follow-up issue.
Comment #31
aaronmchaleYes I agree that does look a bit on the ReallyLongClassName side of things 😀 So yeah let's go with what's there.
That sound like the kind of edge-case that could be delt with in a follow-up, particularly if there's still a chance of getting this into 9.4 :)
Speaking of which, looking at the MR there's nothing else that comes to mind and if you're happy to create that follow-up issue @benji then I'm happy marking as RTBC!
Comment #32
benjifisherI am converting this issue to a child of #2934995: Add a "Manage permissions" tab for each bundle that has associated permissions.
I added a sibling issue: #3279355: Do not show an empty table when there are no entity-specific permissions.
I updated the change record Add "Manage permissions" tab after "Manage display".
We missed the deadline for 9.4.0-alpha1. I do not know if this feature is eligible for the beta release. For now, I did not change the version mentioned in the deprecation notices and the change record. If this issue is not eligible for a back-port to 9.4.x, then we will have to do that.
Comment #33
kristiaanvandeneyndeI certainly hope it is or Group will crash and burn again with the release of 9.4.0
Comment #34
alexpottCommitted and pushed aef1006122 to 10.0.x and 05b4b09193 to 9.5.x. Thanks!
Leaving at rtbc whilst we decide whether to revert the reverts of the prior issues on 9.4.x and commit this one there.
Comment #37
kristiaanvandeneyndeRe #34 I'd have to double-check but judging by the comments, the parent issue's code only got reverted on 9.3.x and is still in 9.4.x. So not sure what you mean by reverting the revert.
Comment #39
alexpottDiscussed with @catch. We decided to revert the 9.4.x reverts and cherry pick this one there. So the new bundle permission functionality is live in 9.4.0 - yay!
Comment #40
alexpott@kristiaanvandeneynde I reverted #3254866: Update the deprecation notices related to "Manage Permissions" pages and #2934995: Add a "Manage permissions" tab for each bundle that has associated permissions from 9.4.x prior to the alpha in-case this one did not land. So in order to apply this to 9.4.x I had to revert those reverts.
Comment #41
benjifisher@kristiaanvandeneynde:
I think you missed #27 on this issue:
So the parent issue was reverted on 9.4.x, although there are no new comment on that issue. That revert is now reverted, and this issue is committed.
@alexpott:
+1 to "yay!"
I was prepared to wait another 6 months for 9.5 and 10.0, but now I can look forward to the beta release of 9.4. :)
Comment #42
benjifisherI removed "[PP-1]" from the title of the follow-up #3279355: Do not show an empty table when there are no entity-specific permissions. (I forgot to set the status to Postponed when I created the issue.)
I see you already published the change record. +1
Comment #43
kristiaanvandeneyndeRe #41 Oh yeah I missed that, thanks for clarifying!
Also great job @benjifisher, truly amazing work.
Comment #44
aaronmchaleAwesome! Thanks @alexpott and @catch for committing this!
Tagging for release highlights, this feels like a pretty notable improvement from a UX perspective!
Comment #45
berdir#2934995: Add a "Manage permissions" tab for each bundle that has associated permissions is/was the UX improvement, this is a purely technical refactoring IMHO.
Comment #46
alexpott@AaronMcHale I agree. I made #2934995: Add a "Manage permissions" tab for each bundle that has associated permissions a release highlight as I think that that provides the highlightable functionality. I think this one is release note worthy as it changes how custom entity types can leverage this functionality and therefore is way more developer focussed.
Comment #48
xjmDeveloper-facing highlights are still highlights; the release notes are only for when we break people's stuff somehow. :) This is more of an un-break than a break, so I think the highlights is the right place for this.