Problem/Motivation
Mapillary already depends on Entity API (entity:entity in mapillary.info.yml), but none of its handlers are used. All Mapillary entity types rely on core handlers only, which makes access all-or-nothing.
- The five content entity types (
mapillary_image,mapillary_sequence,mapillary_organization,mapillary_map_feature,mapillary_detection) use the coreEntityAccessControlHandlerwith anadmin_permission. Every operation, includingview, requiresadminister mapillary_*, which is a "restrict access" permission. There is no way to let an editor, or an anonymous visitor, view Mapillary entities without granting full administration. - There are no bundle-level permissions, although four of the five types are bundleable (image, sequence, map feature, detection).
- Permissions for the admin listings are inconsistent. The list builder collection routes (
/admin/content/mapillary/image, ...) require the per-typeadminister mapillary_*permission, while the Views listings (/admin/content/mapillary/images, ...) require the globaladminister mapillarypermission. - Entity pages (canonical, edit, delete) have no View/Edit/Delete local tasks. The existing
*.links.task.ymlfiles only cover the settings pages.
Entity API provides exactly these pieces, and the module already requires it.
Steps to reproduce
- Create a role without any
administer mapillary_*permission and give it to a user. - As that user, open an imported Mapillary image at
/admin/content/mapillary/image/{id}: access denied. - On
/admin/people/permissions, look for a permission to view Mapillary images or a single bundle of them: there is none.
Proposed resolution
1. Content entity types
Add or replace these handlers on the five content entity types:
permission_provider:Drupal\entity\EntityPermissionProvider. Generates per-type and per-bundle permissions.access:Drupal\entity\EntityAccessControlHandler. Checks{operation} {entity_type}or{operation} {bundle} {entity_type}; the admin permission still allows everything. Requires the permission provider above.query_access:Drupal\entity\QueryAccess\QueryAccessHandler. Filters access-checked entity queries and Views on Mapillary base tables to the bundles the user may view.route_provider.html:Drupal\entity\Routing\AdminHtmlRouteProvider. The collection route acceptsaccess {entity_type} overviewin addition to the admin permission.local_task_provider.default:Drupal\entity\Menu\DefaultEntityLocalTaskProvider. Adds View/Edit/Delete tabs on entity pages.
Set permission_granularity to 'bundle' on the four bundleable types and keep the default ('entity_type') on mapillary_organization.
Mapillary entities have no owner (EntityOwnerInterface) and no published status (EntityPublishedInterface), so the generated permissions are plain view/update/delete, without "own/any" or "unpublished" variants:
administer {entity_type}: all types, existing name.access {entity_type} overview: all types.view {entity_type}: all types.view {bundle} {entity_type},update {bundle} {entity_type},delete {bundle} {entity_type}: bundleable types.update {entity_type},delete {entity_type}:mapillary_organization.create {bundle} {entity_type}/create {entity_type}: generated, but without effect (see below).
The provider builds the admin permission name from admin_permission, so administer mapillary_image and the other four keep their names and their providing module. The five administer mapillary_* entries can be removed from the *.permissions.yml files, and existing role assignments keep working without an update.
The entity types define no add-form or add-page link templates (entities are imported from the Mapillary API, not created in the UI), so the generated create permissions do not open any route.
2. Bundle config entity types
Use Drupal\entity\BundleEntityAccessControlHandler as the access handler for mapillary_image_type, mapillary_sequence_type, mapillary_map_feature_type and mapillary_detection_type. Users who may view any bundle of the content type get view label access on the bundle entity (exposed bundle filters, bundle labels in listings).
3. Admin Views listings
Change the access setting of the five admin Views (mapillary_images, mapillary_sequences, mapillary_organizations, mapillary_map_features, mapillary_detections) from administer mapillary to the matching access {entity_type} overview permission. Rows are then filtered by query access, so a user sees only the bundles they may view.
Existing sites need a post-update hook for this, because the views are installed from config/install. It should only touch views whose access setting still has the shipped value.
Behaviour changes to decide on
- Today, a role with only the global
administer mapillarypermission sees every row in the five Views listings. After this change, Views rows are filtered by query access, so that role would see no rows unless it also has the per-type admin or view permissions. Proposal: the post-update hook grantsaccess {entity_type} overviewandview {entity_type}to roles that haveadminister mapillary, so current visibility is preserved. Feedback welcome, since this grants permissions automatically. - Mapillary's own data access is not affected. The importers use
load()andloadByProperties(), which do not check access. The explicit entity queries (detection cascade queuer, computed image count field, install/update hooks) all useaccessCheck(FALSE). - No database schema change; only entity type handler definitions change. A cache rebuild (as run by
drush updb) is enough.
Out of scope
EntityCollectionLocalActionProvider: there are no add forms to link to.- Bundle plugins, entity and bundle duplication, revision UI, delete-multiple forms: they do not match how Mapillary data is created (imported, not authored).
- Field formatters:
mapillary_street_level_viewer,mapillary_sequence_id,mapillary_map_feature_summaryandmapillary_leaflet_split_viewerrender the referenced entity without aviewaccess check. Whether they should respect the newviewpermissions is a question for a follow-up issue. - JSON:API filtering: Entity API's
hook_jsonapi_entity_filter_access()only maps owner and published conditions, so bundle-based conditions do not open JSON:API filtering. Nothing changes there for Mapillary entities.
Remaining tasks
- Add the handlers and
permission_granularityto the five content entity types. - Add
BundleEntityAccessControlHandlerto the four bundle config entity types. - Remove the
administer mapillary_*entries from the*.permissions.ymlfiles. - Update the access setting of the five admin Views in
config/install. - Post-update hook: update the views access setting and, if agreed, grant the overview and view permissions to roles with
administer mapillary. - Kernel tests: generated permission list per type and bundle; access matrix (anonymous, bundle view only, per-type admin) for view/update/delete; access-checked entity query filtered by bundle; existing role assignments unchanged.
- Functional tests: collection route reachable with the overview permission; Views listing rows filtered by bundle permission; View/Edit/Delete tabs present.
- Update path test for the post-update hook.
- README and CHANGELOG.
User interface changes
- New permissions on
/admin/people/permissionsfor every Mapillary content entity type and bundle. - View/Edit/Delete tabs on Mapillary entity pages.
- Admin listings show only the rows the user may view.
API changes
- Entity type handler definitions change for nine entity types.
- The
administer mapillary_*permissions move from YAML to the Entity API permission provider. Names and providing modules stay the same.
Data model changes
None.
Issue fork mapillary-3627415
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 #2
orkutmuratyilmazComment #4
orkutmuratyilmazThe
3627415-use-entity-apibranch implements the proposed resolution. Three points differ from the issue summary, all found while testing against the Entity API code.Views access for the admin listings
The summary proposes the core
permaccess plugin withaccess {entity_type} overview. That plugin checks one permission only, so a role withadminister mapillary_detectionbut without the overview permission got a 403 on/admin/content/mapillary/detections, while the entity list route fromAdminHtmlRouteProvideraccepts either permission (administer {entity_type}+access {entity_type} overview).The branch adds a Views access plugin,
mapillary_entity_overview(Drupal\mapillary\Plugin\views\access\EntityOverviewAccess). It grants access with the admin or the overview permission of the configured entity type, and the five admin Views use it. It lives in the base module becausemapillary_organizationdoes not depend onmapillary_entity.Local tasks
Entity pages get View and Edit tabs from
DefaultEntityLocalTaskProvider. There is no Delete tab: like core, Entity API leaves it out on purpose (#1834002: Configuration delete operations are all over the place). Deleting still works through thedelete-formroute (/admin/content/mapillary/image/{id}/delete), linked from the Delete link at the bottom of the edit form and from the Operations column of the list builder and the admin Views. Both are shown only with delete access.Bundle labels
view labelis the access operation for showing only the label of an entity. For the bundle entities (mapillary_image_typeand the others) it decides who sees a bundle name, for example in a bundle column or an exposed bundle filter added to a view. WithBundleEntityAccessControlHandler, a user without the admin permission sees a bundle name only if they may view entities of that bundle:view default mapillary_imageshows the name of thedefaultimage type but not of the other image types,view mapillary_imageshows all of them. The admin Views shipped by Mapillary have no bundle column or filter, so they look the same.Post-update hooks
mapillary_entity,mapillary_map_feature,mapillary_detectionandmapillary_organizationeach get two post-update hooks, sharingDrupal\mapillary\Update\EntityAccessUpdater:*_post_update_entity_api_views_access()switches the view displays whose access setting is still the shippedperm/administer mapillaryto the new plugin. Customised displays are left alone.*_post_update_entity_api_grant_overview_permissions()grantsaccess {entity_type} overviewandview {entity_type}to roles withadminister mapillary, except admin roles and except for the entity types whose admin permission the role already has.The grant is a separate function, so it can be dropped if automatic grants are not wanted (the open question in the summary).
Checked
administer mapillary_*keep their names, providing modules andrestrict access.add-formoradd-pageroute is generated, so thecreatepermissions open nothing.config/installare installed as trusted data, so theirdependenciesare written by hand; a kernel test compares them with the calculated dependencies.Tests
administer mapillary), bundle-filtered entity queries, bundleview label, Organization access, both post-update hooks and the shipped view dependencies.MapillaryAdminViewsTestandMapillaryOrganizationsAdminViewTestlogged in withadminister mapillaryonly. They now use the overview permissions and assert thatadminister mapillaryalone gets a 403, which is the intended behaviour change.The module test suite passes (178 tests), PHPCS reports no new errors and PHPStan (level 6) no new errors.
Comment #6
orkutmuratyilmaz