From bec641bc666fdb4858be0249dd6e543751fd123a Mon Sep 17 00:00:00 2001 From: Michael Lee <lee.5151@osu.edu> Date: Wed, 31 Jul 2024 12:18:50 -0400 Subject: [PATCH] Upgrading drupal/field_permissions (1.3.0 => 1.4.0) --- composer.json | 2 +- composer.lock | 18 +- vendor/composer/installed.json | 18 +- vendor/composer/installed.php | 10 +- web/modules/field_permissions/.gitlab-ci.yml | 65 +---- .../css/field_permissions.css | 4 +- .../field_permissions.info.yml | 10 +- .../field_permissions.libraries.yml | 7 - .../field_permissions.module | 37 ++- .../field_permissions/js/field_permissions.js | 30 --- .../Controller/FieldPermissionsController.php | 7 +- .../src/FieldPermissionsService.php | 11 +- .../src/FieldPermissionsServiceInterface.php | 10 +- .../src/Plugin/FieldPermissionType/Base.php | 23 +- .../FieldPermissionType/CustomAccess.php | 65 +++-- .../Plugin/FieldPermissionType/Manager.php | 8 +- .../FieldPermissionType/PrivateAccess.php | 2 +- .../process/FieldPermissionSettings.php | 2 +- .../field_permissions_test.info.yml | 6 +- .../Plugin/FieldPermissionType/TestAccess.php | 6 +- .../FieldPermissionsCommentTest.php | 14 +- ...ieldPermissionsFieldConfigEditFormTest.php | 15 +- .../Functional/FieldPermissionsNodeTest.php | 13 +- .../Functional/FieldPermissionsTestBase.php | 13 +- .../Functional/FieldPermissionsUserTest.php | 16 +- .../FieldPermissionType/ManagerTest.php | 4 +- .../src/Unit/FieldPermissionsServiceTest.php | 52 +--- .../FieldPermissionType/CustomAccessTest.php | 250 ++++++++++++------ .../FieldPermissionType/PrivateAccessTest.php | 175 +++++++----- 29 files changed, 479 insertions(+), 414 deletions(-) delete mode 100644 web/modules/field_permissions/js/field_permissions.js diff --git a/composer.json b/composer.json index addc51d4f9..b6e02b22f4 100644 --- a/composer.json +++ b/composer.json @@ -118,7 +118,7 @@ "drupal/exif_orientation": "^1.1", "drupal/externalauth": "2.0.6", "drupal/field_group": "3.4", - "drupal/field_permissions": "1.3", + "drupal/field_permissions": "1.4", "drupal/focal_point": "2.1.1", "drupal/google_analytics": "^4.0", "drupal/google_tag": "1.7", diff --git a/composer.lock b/composer.lock index cec660d2d1..d8d896497a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "55f345f6fb8933d2dd903c5fdb4f1ae7", + "content-hash": "a1c639a661b4ba2bf4b8b9d80c28d2c0", "packages": [ { "name": "algolia/places", @@ -3238,26 +3238,26 @@ }, { "name": "drupal/field_permissions", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/field_permissions.git", - "reference": "8.x-1.3" + "reference": "8.x-1.4" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.3.zip", - "reference": "8.x-1.3", - "shasum": "f3815d21b423c94e800388f3c29237fc1a00189d" + "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.4.zip", + "reference": "8.x-1.4", + "shasum": "bd3f5803d8c195bc136d4a25774346d69f653029" }, "require": { - "drupal/core": ">=8.9 <11" + "drupal/core": "^9.5 || ^10 || ^11" }, "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.3", - "datestamp": "1703264421", + "version": "8.x-1.4", + "datestamp": "1721754779", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index ae4aab800e..350173ffac 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -3398,27 +3398,27 @@ }, { "name": "drupal/field_permissions", - "version": "1.3.0", - "version_normalized": "1.3.0.0", + "version": "1.4.0", + "version_normalized": "1.4.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/field_permissions.git", - "reference": "8.x-1.3" + "reference": "8.x-1.4" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.3.zip", - "reference": "8.x-1.3", - "shasum": "f3815d21b423c94e800388f3c29237fc1a00189d" + "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.4.zip", + "reference": "8.x-1.4", + "shasum": "bd3f5803d8c195bc136d4a25774346d69f653029" }, "require": { - "drupal/core": ">=8.9 <11" + "drupal/core": "^9.5 || ^10 || ^11" }, "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.3", - "datestamp": "1703264421", + "version": "8.x-1.4", + "datestamp": "1721754779", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index fffb9ed751..a8912ad652 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'osu-asc-webservices/d8-upstream', 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => '9e1c5386fceec4bb8e9adeb6a1ccd8141ad3e707', + 'reference' => '0f8a4b1dc19d2189fc93739ab8306807dd1a5ea9', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -656,9 +656,9 @@ 'dev_requirement' => false, ), 'drupal/field_permissions' => array( - 'pretty_version' => '1.3.0', - 'version' => '1.3.0.0', - 'reference' => '8.x-1.3', + 'pretty_version' => '1.4.0', + 'version' => '1.4.0.0', + 'reference' => '8.x-1.4', 'type' => 'drupal-module', 'install_path' => __DIR__ . '/../../web/modules/field_permissions', 'aliases' => array(), @@ -1537,7 +1537,7 @@ 'osu-asc-webservices/d8-upstream' => array( 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => '9e1c5386fceec4bb8e9adeb6a1ccd8141ad3e707', + 'reference' => '0f8a4b1dc19d2189fc93739ab8306807dd1a5ea9', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/web/modules/field_permissions/.gitlab-ci.yml b/web/modules/field_permissions/.gitlab-ci.yml index 94b86d0a8f..142710b905 100644 --- a/web/modules/field_permissions/.gitlab-ci.yml +++ b/web/modules/field_permissions/.gitlab-ci.yml @@ -8,14 +8,6 @@ # * DrupalSpoons ################ -################ -# Guidelines -# -# This template is designed to give any Contrib maintainer everything they need to test, without requiring modification. It is also designed to keep up to date with Core Development automatically through the use of include files that can be centrally maintained. -# -# However, you can modify this template if you have additional needs for your project. -################ - ################ # Includes # @@ -46,52 +38,13 @@ include: # # Docs at https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/includes/include.drupalci.variables.yml ################ -# variables: -# SKIP_ESLINT: '1' - +variables: + _CSPELL_WORDS: + value: 'Ferran, Hedstrom, Jakob, japerry, jhedstrom, mariacha, markus, petrux' + description: 'Personal names and other irregular words to not mark as incorrect.' -################################################################################### -# -# * -# /( -# ((((, -# /((((((( -# ((((((((((* -# ,((((((((((((((( -# ,((((((((((((((((((( -# ((((((((((((((((((((((((* -# *((((((((((((((((((((((((((((( -# ((((((((((((((((((((((((((((((((((* -# *(((((((((((((((((( .(((((((((((((((((( -# ((((((((((((((((((. /(((((((((((((((((* -# /((((((((((((((((( .(((((((((((((((((, -# ,(((((((((((((((((( (((((((((((((((((( -# .(((((((((((((((((((( .((((((((((((((((( -# ((((((((((((((((((((((( ((((((((((((((((/ -# (((((((((((((((((((((((((((/ ,(((((((((((((((* -# .((((((((((((((/ /(((((((((((((. ,((((((((((((((( -# *(((((((((((((( ,(((((((((((((/ *((((((((((((((. -# ((((((((((((((, /(((((((((((((. ((((((((((((((, -# (((((((((((((/ ,(((((((((((((* ,(((((((((((((, -# *((((((((((((( .((((((((((((((( ,((((((((((((( -# ((((((((((((/ /((((((((((((((((((. ,((((((((((((/ -# ((((((((((((( *(((((((((((((((((((((((* *(((((((((((( -# ((((((((((((( ,(((((((((((((..((((((((((((( *(((((((((((( -# ((((((((((((, /((((((((((((* /((((((((((((/ (((((((((((( -# ((((((((((((( /((((((((((((/ (((((((((((((* (((((((((((( -# (((((((((((((/ /(((((((((((( ,((((((((((((, *(((((((((((( -# (((((((((((((( *(((((((((((/ *((((((((((((. ((((((((((((/ -# *((((((((((((((((((((((((((, /((((((((((((((((((((((((( -# ((((((((((((((((((((((((( ((((((((((((((((((((((((, -# .(((((((((((((((((((((((/ ,((((((((((((((((((((((( -# ((((((((((((((((((((((/ ,(((((((((((((((((((((/ -# *((((((((((((((((((((( (((((((((((((((((((((, -# ,(((((((((((((((((((((, ((((((((((((((((((((/ -# ,(((((((((((((((((((((* /(((((((((((((((((((( -# ((((((((((((((((((((((, ,/((((((((((((((((((((, -# ,((((((((((((((((((((((((((((((((((((((((((((((((((( -# .((((((((((((((((((((((((((((((((((((((((((((( -# .((((((((((((((((((((((((((((((((((((,. -# .,(((((((((((((((((((((((((. -# -################################################################################### + OPT_IN_TEST_PREVIOUS_MAJOR: 1 + OPT_IN_TEST_PREVIOUS_MINOR: 1 + OPT_IN_TEST_NEXT_MINOR: 1 + OPT_IN_TEST_NEXT_MAJOR: 1 + OPT_IN_TEST_MAX_PHP: 1 diff --git a/web/modules/field_permissions/css/field_permissions.css b/web/modules/field_permissions/css/field_permissions.css index a9c6ff85e8..b4adb395bf 100644 --- a/web/modules/field_permissions/css/field_permissions.css +++ b/web/modules/field_permissions/css/field_permissions.css @@ -3,13 +3,13 @@ display: inline-block; width: 16px; height: 16px; - background: url(../images/field_permissions.status-on.svg) no-repeat 0 0; text-indent: -9999em; + background: url(../images/field_permissions.status-on.svg) no-repeat 0 0; } .field-permissions-status-off a { display: inline-block; width: 16px; height: 16px; - background: url(../images/field_permissions.status-off.svg) no-repeat 0 0; text-indent: -9999em; + background: url(../images/field_permissions.status-off.svg) no-repeat 0 0; } diff --git a/web/modules/field_permissions/field_permissions.info.yml b/web/modules/field_permissions/field_permissions.info.yml index b279eae366..434e896d52 100644 --- a/web/modules/field_permissions/field_permissions.info.yml +++ b/web/modules/field_permissions/field_permissions.info.yml @@ -3,11 +3,11 @@ type: module description: 'Set field-level permissions to create, update or view fields.' configure: field_permissions.reports package: Fields -core_version_requirement: '>=8.9 <11' +core_version_requirement: '^9.5 || ^10 || ^11' dependencies: - drupal:field - -# Information added by Drupal.org packaging script on 2023-12-22 -version: '8.x-1.3' + +# Information added by Drupal.org packaging script on 2024-07-23 +version: '8.x-1.4' project: 'field_permissions' -datestamp: 1703264423 +datestamp: 1721754782 diff --git a/web/modules/field_permissions/field_permissions.libraries.yml b/web/modules/field_permissions/field_permissions.libraries.yml index f0a72fdb7e..7e07f5545b 100644 --- a/web/modules/field_permissions/field_permissions.libraries.yml +++ b/web/modules/field_permissions/field_permissions.libraries.yml @@ -3,10 +3,3 @@ field_permissions: css: theme: css/field_permissions.css: {} - js: - js/field_permissions.js: {} - dependencies: - - core/jquery - - core/drupal - - core/drupalSettings - - core/drupal.form diff --git a/web/modules/field_permissions/field_permissions.module b/web/modules/field_permissions/field_permissions.module index 84c5e78760..8705697d37 100644 --- a/web/modules/field_permissions/field_permissions.module +++ b/web/modules/field_permissions/field_permissions.module @@ -5,16 +5,16 @@ * Contains field_permissions.module. */ -use Drupal\field\FieldConfigInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; +use Drupal\field\FieldConfigInterface; use Drupal\field_permissions\FieldPermissionsService; -use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; use Drupal\field_permissions\Plugin\AdminFormSettingsInterface; +use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; /** * Implements hook_help(). @@ -47,7 +47,7 @@ function field_permissions_entity_field_access($operation, FieldDefinitionInterf * Implements hook_jsonapi_entity_field_filter_access(). */ function field_permissions_jsonapi_entity_field_filter_access(FieldDefinitionInterface $field_definition, AccountInterface $account) { - if (!$field_definition->isDisplayConfigurable('view')) { + if (!$field_definition->isDisplayConfigurable('view') || !is_a($field_definition->getFieldStorageDefinition(), '\Drupal\field\FieldStorageConfigInterface')) { return AccessResult::neutral(); } @@ -82,8 +82,8 @@ function field_permissions_form_field_config_edit_form_alter(&$form, FormStateIn } $form['fid'] = ['#type' => 'hidden', '#value' => $field->id()]; - $form['field']['field_permissions'] = [ - '#weight' => -10, + $form['field_permissions'] = [ + '#weight' => 50, ]; // Always add the 'not set' option, which isn't implemented as a plugin. @@ -109,7 +109,7 @@ function field_permissions_form_field_config_edit_form_alter(&$form, FormStateIn } } - $form['field']['field_permissions']['type'] = [ + $form['field_permissions']['type'] = [ '#title' => t('Field visibility and permissions'), '#description' => t('<strong>These permissions apply to all instances of this field.</strong>'), '#type' => 'radios', @@ -118,16 +118,25 @@ function field_permissions_form_field_config_edit_form_alter(&$form, FormStateIn ]; // Add in the descriptions. - $form['field']['field_permissions']['type'] += $descriptions; + $form['field_permissions']['type'] += $descriptions; - $form['actions']['submit']['#submit'][] = 'field_permission_field_config_edit_form_submit'; + $form['actions']['submit']['#submit'][] = 'field_permissions_field_config_edit_form_submit'; $form['#entity_builders'][] = 'field_permissions_field_config_edit_form_builder'; $user_role_storage = \Drupal::service('entity_type.manager')->getStorage('user_role'); // Allow each plugin to add to or alter the form. foreach ($plugins as $plugin) { if ($plugin instanceof AdminFormSettingsInterface) { - $plugin->buildAdminForm($form, $form_state, $user_role_storage); + // Allow plugin to add to the form. + $form['field_permissions'][$id] = [ + '#type' => 'container', + '#states' => [ + 'visible' => [ + ':input[name="type"]' => ['value' => $id], + ], + ], + ]; + $plugin->buildAdminForm($form['field_permissions'][$id], $form_state, $user_role_storage); } } } @@ -139,7 +148,13 @@ function field_permissions_form_field_config_edit_form_alter(&$form, FormStateIn */ function field_permissions_field_config_edit_form_builder($entity_type, FieldConfigInterface $field, array &$form, FormStateInterface $form_state) { $storage = $field->getFieldStorageDefinition(); - $storage->setThirdPartySetting('field_permissions', 'permission_type', $form_state->getValue('type')); + if ($form_state->getValue('type') == FieldPermissionTypeInterface::ACCESS_PUBLIC) { + // Avoid undesired noise in the field storage config (and its export). + $storage->unsetThirdPartySetting('field_permissions', 'permission_type'); + } + else { + $storage->setThirdPartySetting('field_permissions', 'permission_type', $form_state->getValue('type')); + } if (version_compare(\Drupal::VERSION, '10.2', '<')) { $storage->save(); } @@ -150,7 +165,7 @@ function field_permissions_field_config_edit_form_builder($entity_type, FieldCon * * @see field_permissions_form_field_config_edit_form_alter() */ -function field_permission_field_config_edit_form_submit(array &$form, FormStateInterface $form_state) { +function field_permissions_field_config_edit_form_submit(array &$form, FormStateInterface $form_state) { /** @var \Drupal\Core\Field\FieldDefinitionInterface $field */ $field = $form_state->getFormObject()->getEntity(); diff --git a/web/modules/field_permissions/js/field_permissions.js b/web/modules/field_permissions/js/field_permissions.js deleted file mode 100644 index 70266caad6..0000000000 --- a/web/modules/field_permissions/js/field_permissions.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file - * Hide the permissions grid for all field permission types except custom. - */ - -(function ($) { - - Drupal.behaviors.fieldPermissions = { - attach: function (context, settings) { - - var PemTable = $(context).find('#permissions'); - var PermDefaultType = $(context).find('#edit-type input:checked'); - var PermInputType = $(context).find('#edit-type input'); - /*init*/ - if (PermDefaultType.val() != 'custom') { - PemTable.hide(); - } - /*change*/ - PermInputType.on('change', function () { - var typeVal = $(this).val(); - if (typeVal != 'custom') { - PemTable.hide(); - } - else { - PemTable.show(); - } - }); - - }}; -})(jQuery); diff --git a/web/modules/field_permissions/src/Controller/FieldPermissionsController.php b/web/modules/field_permissions/src/Controller/FieldPermissionsController.php index 83b76ca331..4d92bf937c 100644 --- a/web/modules/field_permissions/src/Controller/FieldPermissionsController.php +++ b/web/modules/field_permissions/src/Controller/FieldPermissionsController.php @@ -7,9 +7,9 @@ use Drupal\Core\Link; use Drupal\field\FieldStorageConfigInterface; use Drupal\field_permissions\FieldPermissionsServiceInterface; +use Drupal\field_permissions\Plugin\CustomPermissionsInterface; use Drupal\field_permissions\Plugin\FieldPermissionType\Manager; use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; -use Drupal\field_permissions\Plugin\CustomPermissionsInterface; use Drupal\user\RoleInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -169,7 +169,10 @@ protected function buildRow(FieldStorageConfigInterface $field_storage) { } else { // Use the label and description. - $row[4]['data'] = $this->t('@label (@description)', ['@label' => $plugin->getLabel(), '@description' => $plugin->getDescription()]); + $row[4]['data'] = $this->t('@label (@description)', [ + '@label' => $plugin->getLabel(), + '@description' => $plugin->getDescription(), + ]); $row[4]['colspan'] = 5; } } diff --git a/web/modules/field_permissions/src/FieldPermissionsService.php b/web/modules/field_permissions/src/FieldPermissionsService.php index b6aaa7540d..b7bce88411 100644 --- a/web/modules/field_permissions/src/FieldPermissionsService.php +++ b/web/modules/field_permissions/src/FieldPermissionsService.php @@ -6,12 +6,12 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\field\FieldStorageConfigInterface; +use Drupal\field_permissions\Plugin\CustomPermissionsInterface; use Drupal\field_permissions\Plugin\FieldPermissionType\Base; use Drupal\field_permissions\Plugin\FieldPermissionType\Manager; use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; -use Drupal\field_permissions\Plugin\CustomPermissionsInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -135,8 +135,11 @@ public function getAllPermissions() { /** * {@inheritdoc} */ - public function fieldGetPermissionType(FieldStorageConfigInterface $field) { - return $field->getThirdPartySetting('field_permissions', 'permission_type', FieldPermissionTypeInterface::ACCESS_PUBLIC); + public function fieldGetPermissionType(FieldStorageDefinitionInterface $field) { + if (method_exists($field, 'getThirdPartySetting')) { + return $field->getThirdPartySetting('field_permissions', 'permission_type', FieldPermissionTypeInterface::ACCESS_PUBLIC); + } + return FieldPermissionTypeInterface::ACCESS_PUBLIC; } /** diff --git a/web/modules/field_permissions/src/FieldPermissionsServiceInterface.php b/web/modules/field_permissions/src/FieldPermissionsServiceInterface.php index 790f01a5a1..8c08fd5462 100644 --- a/web/modules/field_permissions/src/FieldPermissionsServiceInterface.php +++ b/web/modules/field_permissions/src/FieldPermissionsServiceInterface.php @@ -4,8 +4,8 @@ use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\field\FieldStorageConfigInterface; /** * Implement FieldPermission Interface. @@ -24,7 +24,7 @@ interface FieldPermissionsServiceInterface { * An array keyed by the permission machine name, with label and description * keys. Note that this machine name doesn't include the field name. * - * @todo This is really only releavant to the custom field permission type + * @todo This is really only relevant to the custom field permission type * plugin. However, since it is used in the report page, it would be * difficult to abstract down to the plugin level the way the report * currently works. @@ -53,10 +53,10 @@ public function getAllPermissions(); /** * Get the permission type for a given field. * - * @param \Drupal\field\FieldStorageConfigInterface $field + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $field * The field to return permissions for. */ - public function fieldGetPermissionType(FieldStorageConfigInterface $field); + public function fieldGetPermissionType(FieldStorageDefinitionInterface $field); /** * Field is attached to comment entity. @@ -70,7 +70,7 @@ public function fieldGetPermissionType(FieldStorageConfigInterface $field); public static function isCommentField(FieldDefinitionInterface $field_definition); /** - * Get access for field by operations and account permisisons. + * Get access for field by operations and account permissions. * * @param string $operation * String operation on field. diff --git a/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php b/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php index 77f49b98f5..32534fe28f 100644 --- a/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php +++ b/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php @@ -7,6 +7,7 @@ use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Session\AccountInterface; use Drupal\field\FieldStorageConfigInterface; +use Drupal\field_permissions\FieldPermissionsServiceInterface; use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -22,6 +23,13 @@ abstract class Base extends PluginBase implements FieldPermissionTypeInterface, */ protected $fieldStorage; + /** + * The fields permissions service. + * + * @var \Drupal\field_permissions\FieldPermissionsServiceInterface + */ + protected $fieldPermissionsService; + /** * Constructs the plugin. * @@ -33,10 +41,20 @@ abstract class Base extends PluginBase implements FieldPermissionTypeInterface, * The plugin implementation definition. * @param \Drupal\field\FieldStorageConfigInterface $field_storage * The field storage. + * @param \Drupal\field_permissions\FieldPermissionsServiceInterface|null $field_permissions_service + * Field permissions service. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, FieldStorageConfigInterface $field_storage) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, FieldStorageConfigInterface $field_storage, FieldPermissionsServiceInterface $field_permissions_service = NULL) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->fieldStorage = $field_storage; + if ($field_permissions_service === NULL) { + @trigger_error('Calling ' . __METHOD__ . '() without the $field_permissions_service argument is deprecated in field_permissions:8.x-1.4 and will be required in field_permissions:8.x-2.0. See https://www.drupal.org/node/3359471', E_USER_DEPRECATED); + // @phpstan-ignore-next-line + $this->fieldPermissionsService = \Drupal::service('field_permissions.permissions_service'); + } + else { + $this->fieldPermissionsService = $field_permissions_service; + } } /** @@ -47,7 +65,8 @@ public static function create(ContainerInterface $container, array $configuratio $configuration, $plugin_id, $plugin_definition, - $field_storage + $field_storage, + $container->get('field_permissions.permissions_service') ); } diff --git a/web/modules/field_permissions/src/Plugin/FieldPermissionType/CustomAccess.php b/web/modules/field_permissions/src/Plugin/FieldPermissionType/CustomAccess.php index 239f5e3270..f9b8347785 100644 --- a/web/modules/field_permissions/src/Plugin/FieldPermissionType/CustomAccess.php +++ b/web/modules/field_permissions/src/Plugin/FieldPermissionType/CustomAccess.php @@ -5,7 +5,6 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\field_permissions\FieldPermissionsService; use Drupal\field_permissions\Plugin\AdminFormSettingsInterface; use Drupal\field_permissions\Plugin\CustomPermissionsInterface; use Drupal\user\EntityOwnerInterface; @@ -43,7 +42,7 @@ public function hasFieldAccess($operation, EntityInterface $entity, AccountInter return $entity->id() == $account->id() && $account->hasPermission($operation . ' own ' . $field_name); } elseif ($entity instanceof EntityOwnerInterface) { - return $entity->getOwnerId() == $account->id() && $account->hasPermission($operation . ' own ' . $field_name); + return $entity->getOwnerId() === $account->id() && $account->hasPermission($operation . ' own ' . $field_name); } } @@ -65,36 +64,52 @@ public function hasFieldViewAccessForEveryEntity(AccountInterface $account) { */ public function buildAdminForm(array &$form, FormStateInterface $form_state, RoleStorageInterface $role_storage) { $this->addPermissionsGrid($form, $form_state, $role_storage); - - // Only display the permissions matrix if this type is selected. - $form['#attached']['library'][] = 'field_permissions/field_permissions'; } /** * {@inheritdoc} */ public function submitAdminForm(array &$form, FormStateInterface $form_state, RoleStorageInterface $role_storage) { + $this_plugin_applies = $form_state->getValue('type') === $this->getPluginId(); $custom_permissions = $form_state->getValue('permissions'); - /** @var \Drupal\user\RoleInterface[] $roles */ - $roles = []; - foreach ($custom_permissions as $permission_name => $field_perm) { - foreach ($field_perm as $role_name => $role_permission) { - $roles[$role_name] = $role_storage->load($role_name); - // If using this plugin, set permissions to the value submitted in the - // form. Otherwise remove all permissions as they will no longer exist. - $role_permission = $form_state->getValue('type') === $this->getPluginId() ? $role_permission : FALSE; - if ($role_permission) { - $roles[$role_name]->grantPermission($permission_name); - } - else { - $roles[$role_name]->revokePermission($permission_name); - } + $keys = array_keys($custom_permissions); + $custom_permissions = $this->transposeArray($custom_permissions); + foreach ($role_storage->loadMultiple() as $role) { + $permissions = $role->getPermissions(); + $removed = array_values(array_intersect($permissions, $keys)); + $added = $this_plugin_applies ? array_keys(array_filter($custom_permissions[$role->id()])) : []; + // Permissions in role object are sorted on save. Permissions on form are + // not in same order (the 'any' and 'own' items are flipped) but need to + // be as array equality tests keys and values. So sort the added items. + sort($added); + if ($removed != $added) { + // Rule #1 Do NOT save something that is not changed. + // Like field storage, delete existing items then add current items. + $permissions = array_diff($permissions, $removed); + $permissions = array_merge($permissions, $added); + $role->set('permissions', $permissions); + $role->trustData()->save(); } } - // Save all roles. - foreach ($roles as $role) { - $role->trustData()->save(); + } + + /** + * Transposes a 2-dimensional array. + * + * @param array $original + * The array to transpose. + * + * @return array + * The transposed array. + */ + protected function transposeArray(array $original) { + $transpose = []; + foreach ($original as $row => $columns) { + foreach ($columns as $column => $value) { + $transpose[$column][$row] = $value; + } } + return $transpose; } /** @@ -103,7 +118,7 @@ public function submitAdminForm(array &$form, FormStateInterface $form_state, Ro public function getPermissions() { $permissions = []; $field_name = $this->fieldStorage->getName(); - $permission_list = FieldPermissionsService::getList($field_name); + $permission_list = $this->fieldPermissionsService->getList($field_name); $perms_name = array_keys($permission_list); foreach ($perms_name as $perm_name) { $name = $perm_name . ' ' . $field_name; @@ -142,8 +157,8 @@ protected function addPermissionsGrid(array &$form, FormStateInterface $form_sta 'class' => ['checkbox'], ]; } - // @todo Remove call to global service. - $test = \Drupal::service('field_permissions.permissions_service')->getPermissionsByRole(); + + $test = $this->fieldPermissionsService->getPermissionsByRole(); foreach ($permissions as $provider => $permission) { $form['permissions'][$provider]['description'] = [ '#type' => 'inline_template', diff --git a/web/modules/field_permissions/src/Plugin/FieldPermissionType/Manager.php b/web/modules/field_permissions/src/Plugin/FieldPermissionType/Manager.php index 91b437f22d..d8387cad7b 100644 --- a/web/modules/field_permissions/src/Plugin/FieldPermissionType/Manager.php +++ b/web/modules/field_permissions/src/Plugin/FieldPermissionType/Manager.php @@ -5,9 +5,9 @@ use Drupal\Component\Plugin\Factory\DefaultFactory; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\DefaultPluginManager; -use Drupal\field\FieldStorageConfigInterface; use Drupal\field_permissions\Annotation\FieldPermissionType; use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; @@ -40,19 +40,21 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac * The plugin ID. * @param array $configuration * The plugin configuration. - * @param \Drupal\field\FieldStorageConfigInterface $field_storage + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface|null $field_storage * The field storage. * * @return \Drupal\field_permissions\Plugin\FieldPermissionTypeInterface * The field permission type plugin instance. * * @throws \Drupal\Component\Plugin\Exception\PluginException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public function createInstance($plugin_id, array $configuration = [], FieldStorageConfigInterface $field_storage = NULL) { + public function createInstance($plugin_id, array $configuration = [], FieldStorageDefinitionInterface $field_storage = NULL) { $plugin_definition = $this->getDefinition($plugin_id); $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition); // If the plugin provides a factory method, pass the container to it. if (is_subclass_of($plugin_class, ContainerFactoryPluginInterface::class)) { + // @phpstan-ignore-next-line $plugin = $plugin_class::create(\Drupal::getContainer(), $configuration, $plugin_id, $plugin_definition, $field_storage); } else { diff --git a/web/modules/field_permissions/src/Plugin/FieldPermissionType/PrivateAccess.php b/web/modules/field_permissions/src/Plugin/FieldPermissionType/PrivateAccess.php index 4a8357312b..b671547731 100644 --- a/web/modules/field_permissions/src/Plugin/FieldPermissionType/PrivateAccess.php +++ b/web/modules/field_permissions/src/Plugin/FieldPermissionType/PrivateAccess.php @@ -37,7 +37,7 @@ public function hasFieldAccess($operation, EntityInterface $entity, AccountInter return $entity->id() == $account->id(); } elseif ($entity instanceof EntityOwnerInterface) { - return $entity->getOwnerId() == $account->id(); + return $entity->getOwnerId() === $account->id(); } return TRUE; diff --git a/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php b/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php index 70b43f848f..a4b4d752c0 100644 --- a/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php +++ b/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php @@ -2,10 +2,10 @@ namespace Drupal\field_permissions\Plugin\migrate\process; +use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; use Drupal\migrate\MigrateExecutableInterface; use Drupal\migrate\ProcessPluginBase; use Drupal\migrate\Row; -use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; /** * Migration plugin for field permission settings. diff --git a/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml b/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml index 72d0cd6043..825635bbb1 100644 --- a/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml +++ b/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml @@ -5,7 +5,7 @@ package: Testing dependencies: - field_permissions:field_permissions -# Information added by Drupal.org packaging script on 2023-12-22 -version: '8.x-1.3' +# Information added by Drupal.org packaging script on 2024-07-23 +version: '8.x-1.4' project: 'field_permissions' -datestamp: 1703264423 +datestamp: 1721754782 diff --git a/web/modules/field_permissions/tests/modules/field_permissions_test/src/Plugin/FieldPermissionType/TestAccess.php b/web/modules/field_permissions/tests/modules/field_permissions_test/src/Plugin/FieldPermissionType/TestAccess.php index 5dc22773cd..67c32621cd 100644 --- a/web/modules/field_permissions/tests/modules/field_permissions_test/src/Plugin/FieldPermissionType/TestAccess.php +++ b/web/modules/field_permissions/tests/modules/field_permissions_test/src/Plugin/FieldPermissionType/TestAccess.php @@ -5,8 +5,8 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\field_permissions\Plugin\FieldPermissionType\Base; use Drupal\field_permissions\Plugin\CustomPermissionsInterface; +use Drupal\field_permissions\Plugin\FieldPermissionType\Base; /** * A test field permission type plugin. @@ -26,6 +26,7 @@ class TestAccess extends Base implements CustomPermissionsInterface { public function hasFieldAccess($operation, EntityInterface $entity, AccountInterface $account) { // Flag that this method was called. // @see \Drupal\Tests\field_permissions\Kernel\Plugin\FieldPermissionType\ManagerTest::testAppliesToField() + // @phpstan-ignore-next-line \Drupal::state()->set('field_permissions_test.called_TestAccess::hasFieldAccess', TRUE); if ($operation === 'view') { @@ -57,7 +58,8 @@ public function getPermissions() { */ public function appliesToField(FieldDefinitionInterface $field_definition): bool { // The state variable is used in tests as a switch. - // @see \Drupal\Tests\field_permissions\Functional\FieldPermissionsFieldConfigEditFormTest::testAppiesToField() + // @see \Drupal\Tests\field_permissions\Functional\FieldPermissionsFieldConfigEditFormTest::testAppliesToField() + // @phpstan-ignore-next-line return \Drupal::state()->get('field_permissions_test.applies_to_field', TRUE); } diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php index 7c89433bbe..9128065fa4 100644 --- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php +++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php @@ -213,7 +213,7 @@ protected function checkBaseCommentFieldFunctionality() { $edit[$this->fieldName . '[0][value]'] = 'Limit User comment body'; $this->submitForm($edit, 'Save'); $this->drupalGet('node/' . $this->node->id()); - // Test visibility second comment by limituser.. + // Test visibility of the second comment by the limited user. $this->assertSession()->pageTextContains('Limit User comment subject'); $this->assertSession()->pageTextContains('Limit User comment body'); $this->drupalLogout(); @@ -234,7 +234,7 @@ protected function checkPrivateCommentField() { $this->drupalLogout(); $this->drupalLogin($this->limitedUser); $this->drupalGet('node/' . $this->node->id()); - // Test hide body comment post by Adminuser but display subject.. + // Test hide body comment post by Admin user but display subject. $this->assertSession()->pageTextContains($this->commentSubject); $this->assertSession()->pageTextNotContains($this->fieldText); // Test view your comment. @@ -266,14 +266,14 @@ protected function checkCustomCommentField() { $this->drupalLogout(); $this->drupalLogin($this->limitedUser); - // View your comment but not view field body comment post by admin. + // View your comment but not view field body comment post by Admin. $this->drupalGet('node/' . $this->node->id()); - // Hide body comment post by Adminuser. + // Hide body comment post by Admin user. $this->assertSession()->pageTextNotContains($this->fieldText); $this->assertSession()->pageTextContains($this->commentSubject); $this->assertSession()->pageTextContains('Limit User comment subject'); $this->assertSession()->pageTextContains('Limit User comment body'); - // Edit your comment not accesss to body field. + // Edit your comment not access to body field. $this->drupalGet('comment/2/edit'); $this->assertSession()->pageTextNotContains('Limit User comment body'); $this->drupalLogout(); @@ -296,10 +296,10 @@ protected function checkCustomCommentField() { $perm = ['edit ' . $this->fieldName, 'view ' . $this->fieldName]; $permission = $this->grantCustomPermissions($this->adminUserRole, $perm, $permission); $this->setCommentFieldPermissions(FieldPermissionTypeInterface::ACCESS_CUSTOM, $permission, $path); - // view. + // View. $this->drupalGet('node/' . $this->node->id()); $this->assertSession()->pageTextContains('Limit User comment body'); - // edit. + // Edit. $this->drupalGet('comment/2/edit'); $this->assertSession()->pageTextContains('Limit User comment body'); $this->drupalLogout(); diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsFieldConfigEditFormTest.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsFieldConfigEditFormTest.php index add79464f8..c002dc933c 100644 --- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsFieldConfigEditFormTest.php +++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsFieldConfigEditFormTest.php @@ -2,22 +2,23 @@ namespace Drupal\Tests\field_permissions\Functional; -use Drupal\node\Entity\NodeType; -use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\node\Functional\NodeTestBase; /** * Tests the field config edit form. * * @group field_permissions */ -class FieldPermissionsFieldConfigEditFormTest extends BrowserTestBase { +class FieldPermissionsFieldConfigEditFormTest extends NodeTestBase { /** * {@inheritdoc} */ protected static $modules = [ 'field_permissions_test', + 'field_permissions', 'node', + 'datetime', 'field_ui', ]; @@ -32,18 +33,16 @@ class FieldPermissionsFieldConfigEditFormTest extends BrowserTestBase { * @covers \Drupal\field_permissions\Plugin\FieldPermissionTypeInterface::appliesToField */ public function testAppliesToField(): void { - $node_type = NodeType::create(['type' => 'page']); - $node_type->save(); - node_add_body_field($node_type); + $assert = $this->assertSession(); $this->drupalLogin($this->createUser([ 'administer field permissions', + 'bypass node access', + 'administer content types', 'administer node fields', ])); $this->drupalGet('/admin/structure/types/manage/page/fields/node.page.body'); - $assert = $this->assertSession(); - // All plugins are exposed on the field config edit form. $assert->pageTextContains('Field visibility and permissions'); $assert->fieldExists('Not set'); diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php index 3c9cf1b4a8..8ce4bfb0de 100644 --- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php +++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php @@ -34,7 +34,7 @@ public function testNodeFieldPermissions() { $this->checkPermissionPage(); $this->checkFieldPermissionConfigurationEdit(); $this->checkInitAddNode(); - $this->checkChengeToPrivateField(); + $this->checkChangeToPrivateField(); $this->checkViewOwnField(); $this->checkViewEditOwnField(); $this->checkViewEditAllField(); @@ -169,7 +169,7 @@ protected function checkInitAddNode() { /** * Test PUBLIC - PRIVATE EDIT - VIEW. */ - protected function checkChengeToPrivateField() { + protected function checkChangeToPrivateField() { $this->drupalLogin($this->webUser); $this->assertNodeFieldVisible(); @@ -191,13 +191,13 @@ protected function checkViewOwnField() { $permission = $this->grantCustomPermissions($this->limitUserRole, ['view own body'], $permission); $this->setNodeFieldPermissions(FieldPermissionTypeInterface::ACCESS_CUSTOM, $permission); - // Login width author node. + // Login with author node. $this->drupalLogin($this->limitedUser); $this->assertNodeFieldVisible(); $this->assertNodeFieldEditNoAccess(); $this->drupalLogout(); - // Login webuser. + // Login the web user. $this->drupalLogin($this->webUser); $this->assertNodeFieldHidden(); $this->assertNodeFieldEditNoAccess(); @@ -212,18 +212,17 @@ protected function checkViewEditOwnField() { $permission = $this->grantCustomPermissions($this->limitUserRole, ['view own body', 'edit own body'], $permission); $this->setNodeFieldPermissions(FieldPermissionTypeInterface::ACCESS_CUSTOM, $permission); - // Login width author node. + // Login with author node. $this->drupalLogin($this->limitedUser); $this->assertNodeFieldVisible(); $this->assertNodeFieldEditAccess(); $this->drupalLogout(); - // Login webuser. + // Login the web user. $this->drupalLogin($this->webUser); $this->assertNodeFieldHidden(); $this->assertNodeFieldEditNoAccess(); $this->drupalLogout(); - } /** diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php index 72d083d829..aeb2846b4e 100644 --- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php +++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php @@ -140,12 +140,19 @@ protected function getCustomPermissionGrid($role, array $field_perm = []) { $custom_perm = []; $permission_list = $this->container->get('field_permissions.permissions_service')->getAllPermissions(); $permission_list = array_keys($permission_list); - $permission_role = array_keys(user_roles()); + $prefix = 'user.role'; + $permission_role = ['anonymous', 'authenticated']; + foreach ($this->container->get('config.factory')->listAll($prefix) as $config_name) { + $role_name = substr($config_name, strlen($prefix) + 1); + if (!in_array($role_name, $permission_role)) { + $permission_role[] = $role_name; + } + } // Set all check to false. - foreach ($permission_role as $rname) { + foreach ($permission_role as $role_name) { foreach ($permission_list as $perm) { - $key = 'permissions[' . $perm . '][' . $rname . ']'; + $key = 'permissions[' . $perm . '][' . $role_name . ']'; $custom_perm[$key] = FALSE; } } diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php index a09df886db..c7891dd207 100644 --- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php +++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php @@ -47,11 +47,11 @@ public function setUp():void { public function testUserFieldPermissions() { $this->drupalLogin($this->adminUser); - // Compila il campo per l'utente admin. + // Fill in the field for the admin user. $this->checkUserFieldEdit($this->adminUser); $this->drupalLogout(); - // Controllo che si visibile ad altri utenti. + // Control that it is visible to other users. $this->drupalLogin($this->limitedUser); $this->assertUserFieldAccess($this->adminUser); $this->drupalLogout(); @@ -186,7 +186,7 @@ private function setUserFieldPermission($perm, array $custom_permission = []) { */ protected function checkUserViewEditOwnField() { $permission = []; - // AGGIUNGE I PERMESSI DI VIEW_OWN. all'utente limitato. + // Adds 'view own' permission to the limited user. $this->drupalLogin($this->webUser); $perm = ['view own ' . $this->fieldName]; $permission = $this->grantCustomPermissions($this->limitUserRole, $perm, $permission); @@ -208,7 +208,7 @@ protected function checkUserViewEditOwnField() { $this->assertUserEditFieldNoAccess($this->limitedUser); $this->drupalLogout(); - // AGGIUNGE I PERMESSI DI EDIT_OWN to limitUserRole. + // Add 'edit own' permission to limitUserRole. $this->drupalLogin($this->webUser); $permission = $this->grantCustomPermissions($this->limitUserRole, ['edit own ' . $this->fieldName], $permission); $this->setUserFieldPermission(FieldPermissionTypeInterface::ACCESS_CUSTOM, $permission); @@ -231,7 +231,7 @@ protected function checkUserViewEditOwnField() { protected function checkUserViewEditField() { $permission = []; - // AGGIUNGE I PERMESSI DI VIEW_OWN. all'utente limitato. + // Adds VIEW_OWN permission to the restricted user. $this->drupalLogin($this->webUser); $perm = ['view ' . $this->fieldName]; $permission = $this->grantCustomPermissions($this->webUserRole, $perm, $permission); @@ -255,11 +255,11 @@ protected function checkPrivateField() { $this->drupalLogout(); $this->drupalLogin($this->limitedUser); - // Controlla il perofilo dell'utente admin e non deve vedere il campo. + // Check the admin user's profile and should not see the field. $this->assertUserFieldNoAccess($this->adminUser); - // Compila il campo per l'utente Limited. + // Fill in the field for Limited user. $this->checkUserFieldEdit($this->limitedUser); - // Controlla che sia visibile. + // Check that it is visible. $this->assertUserFieldAccess($this->limitedUser); $this->drupalLogout(); diff --git a/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php b/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php index 02f9932278..094e528c73 100644 --- a/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php +++ b/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php @@ -28,6 +28,7 @@ class ManagerTest extends KernelTestBase { 'field_permissions', 'field_permissions_test', 'system', + 'text', 'user', ]; @@ -51,7 +52,6 @@ class ManagerTest extends KernelTestBase { public function setUp():void { parent::setUp(); - $this->installSchema('system', ['sequences']); $this->installEntitySchema('user'); $this->installEntitySchema('entity_test'); @@ -70,7 +70,7 @@ public function testCreateInstance() { $entity = EntityTest::create(); $field_storage = FieldStorageConfig::create([ 'field_name' => 'test_foo', - 'type' => 'text', + 'type' => 'string', 'entity_type' => 'entity_test', ]); $plugin = $this->fieldPermissionTypeManager->createInstance('test_access', [], $field_storage); diff --git a/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php b/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php index a978698df6..0b3ef5441c 100644 --- a/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php +++ b/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php @@ -2,7 +2,6 @@ namespace Drupal\Tests\field_permissions\Unit; -use Prophecy\PhpUnit\ProphecyTrait; use Drupal\comment\CommentManagerInterface; use Drupal\Core\DependencyInjection\Container; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -15,6 +14,7 @@ use Drupal\field_permissions\Plugin\FieldPermissionTypeInterface; use Drupal\Tests\UnitTestCase; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; /** * Tests the field permissions service. @@ -69,49 +69,25 @@ public function setUp():void { * * @dataProvider providerTestGetFieldAccess */ - public function testGetFieldAccess($operation, FieldItemListInterface $items, AccountInterface $account, FieldDefinitionInterface $field_definition, $expected_access) { - $this->assertEquals($expected_access, $this->fieldPermissionsService->getFieldAccess($operation, $items, $account, $field_definition)); - } - - /** - * Data provider for ::testGetFieldAccess. - */ - public function providerTestGetFieldAccess() { - $cases = []; - + public function testGetFieldAccess($operation, $roles, $permission, $expected_access) { $field_item_list = $this->prophesize(FieldItemListInterface::class)->reveal(); - // Administrator role. - $account = $this->prophesize(AccountInterface::class); - $account->getRoles()->willReturn(['administrator']); - $field_definition = $this->prophesize(FieldDefinitionInterface::class); - $storage = $this->prophesize(FieldStorageConfigInterface::class); - $storage->getThirdPartySetting('field_permissions', 'permission_type', FieldPermissionTypeInterface::ACCESS_PUBLIC)->willReturn('foo'); - $field_definition->getFieldStorageDefinition()->willReturn($storage->reveal()); - $cases[] = [ - 'view', - $field_item_list, - $account->reveal(), - $field_definition->reveal(), - TRUE, - ]; - - // No admin roles, but public access. $account = $this->prophesize(AccountInterface::class); - $account->getRoles()->willReturn(['blah']); + $account->getRoles()->willReturn($roles); $field_definition = $this->prophesize(FieldDefinitionInterface::class); $storage = $this->prophesize(FieldStorageConfigInterface::class); - $storage->getThirdPartySetting('field_permissions', 'permission_type', FieldPermissionTypeInterface::ACCESS_PUBLIC)->willReturn(FieldPermissionTypeInterface::ACCESS_PUBLIC); + $storage->getThirdPartySetting('field_permissions', 'permission_type', FieldPermissionTypeInterface::ACCESS_PUBLIC)->willReturn($permission); $field_definition->getFieldStorageDefinition()->willReturn($storage->reveal()); - $cases[] = [ - 'view', - $field_item_list, - $account->reveal(), - $field_definition->reveal(), - TRUE, - ]; - - return $cases; + + $this->assertEquals($expected_access, $this->fieldPermissionsService->getFieldAccess($operation, $field_item_list, $account->reveal(), $field_definition->reveal())); + } + + /** + * Data provider for ::testGetFieldAccess. + */ + public static function providerTestGetFieldAccess(): \Generator { + yield 'Administrator access' => ['view', ['administrator'], 'foo', TRUE]; + yield 'No Admin roles, public access' => ['view', ['blah'], FieldPermissionTypeInterface::ACCESS_PUBLIC, TRUE]; } /** diff --git a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php index 993ad1635c..20a917d980 100644 --- a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php +++ b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php @@ -2,14 +2,15 @@ namespace Drupal\Tests\field_permissions\Unit\Plugin\FieldPermissionType; -use Prophecy\PhpUnit\ProphecyTrait; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Session\AccountInterface; use Drupal\field\FieldStorageConfigInterface; +use Drupal\field_permissions\FieldPermissionsService; use Drupal\field_permissions\Plugin\FieldPermissionType\CustomAccess; use Drupal\Tests\UnitTestCase; use Drupal\user\EntityOwnerInterface; use Drupal\user\UserInterface; +use Prophecy\PhpUnit\ProphecyTrait; /** * Tests for the custom access permission type plugin. @@ -33,11 +34,11 @@ class CustomAccessTest extends UnitTestCase { */ public function setUp():void { parent::setUp(); - + $field_permissions = $this->prophesize(FieldPermissionsService::class); $storage = $this->prophesize(FieldStorageConfigInterface::class); $storage->getName()->willReturn('foo_field'); - $this->plugin = new CustomAccess([], 'custom', [], $storage->reveal()); + $this->plugin = new CustomAccess([], 'custom', [], $storage->reveal(), $field_permissions->reveal()); } /** @@ -47,7 +48,20 @@ public function setUp():void { * * @dataProvider providerTestHasFieldAccess */ - public function testHasFieldAccess($operation, EntityInterface $entity, AccountInterface $account, $access) { + + /** + * Helper function to assert hasFieldAccess tests. + * + * @param string $operation + * The Permission operation. + * @param \Drupal\Core\Entity\EntityInterface $entity + * Entity the permission is acting on. + * @param \Drupal\Core\Session\AccountInterface $account + * Account the permission is valid for. + * @param bool $access + * The expected access result. + */ + private function hasFieldAccess($operation, EntityInterface $entity, AccountInterface $account, $access) { $this->assertEquals($access, $this->plugin->hasFieldAccess($operation, $entity, $account)); } @@ -65,103 +79,167 @@ public function testInvalidOperation() { } /** - * Data provider for ::testHasFieldAccess. + * Tests for create access allowed. + * + * @covers ::hasFieldAccess */ - public function providerTestHasFieldAccess() { - $cases = []; - - // Create access allowed. + public function testCreateAccessAllowed() { $account = $this->prophesize(AccountInterface::class); $account->hasPermission('create foo_field')->willReturn(TRUE); $entity = $this->prophesize(EntityInterface::class); $entity->isNew()->willReturn(TRUE); - $cases[] = ['edit', $entity->reveal(), $account->reveal(), TRUE]; + $this->hasFieldAccess('edit', $entity->reveal(), $account->reveal(), TRUE); + } - // Create access denied. + /** + * Tests for create access denied. + * + * @covers ::hasFieldAccess + */ + public function testCreateAccessDenied() { $account = $this->prophesize(AccountInterface::class); $account->hasPermission('create foo_field')->willReturn(FALSE); - $cases[] = ['edit', $entity->reveal(), $account->reveal(), FALSE]; - - // Add edit and view. - foreach (['edit', 'view'] as $operation) { - // Edit|view access allowed. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(TRUE); - $entity = $this->prophesize(EntityInterface::class); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), TRUE]; - - // Edit|view access denied. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(FALSE); - $entity = $this->prophesize(EntityInterface::class); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), FALSE]; - - // User entity, edit|view own allowed. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(FALSE); - $account->hasPermission($operation . ' own foo_field')->willReturn(TRUE); - $account->id()->willReturn(42); - $entity = $this->prophesize(UserInterface::class); - $entity->id()->willReturn(42); - $entity->isNew()->willReturn(FALSE); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), TRUE]; - - // User entity, edit|view own denied. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(FALSE); - $account->hasPermission($operation . ' own foo_field')->willReturn(FALSE); - $account->id()->willReturn(42); - $entity = $this->prophesize(UserInterface::class); - $entity->id()->willReturn(42); - $entity->isNew()->willReturn(FALSE); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), FALSE]; - - // User entity, edit|view own allowed, non-matching entity. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(FALSE); - $account->hasPermission($operation . ' own foo_field')->willReturn(TRUE); - $account->id()->willReturn(42); - $entity = $this->prophesize(UserInterface::class); - $entity->id()->willReturn(27); - $entity->isNew()->willReturn(FALSE); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), FALSE]; + $entity = $this->prophesize(EntityInterface::class); + $entity->isNew()->willReturn(TRUE); + $this->hasFieldAccess('edit', $entity->reveal(), $account->reveal(), FALSE); + } - // Entity implementing EntityOwnerInterface, edit|view own allowed. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(FALSE); - $account->hasPermission($operation . ' own foo_field')->willReturn(TRUE); - $account->id()->willReturn(42); - $entity = $this->prophesize(EntityInterface::class); - $entity->willImplement(EntityOwnerInterface::class); - $entity->getOwnerId()->willReturn(42); - $entity->isNew()->willReturn(FALSE); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), TRUE]; + /** + * Tests view/edit operations for access granted/denied. + * + * @param string $operation + * Operation to test against. + * @param bool $access + * Permission and associated Result (they should be the same). + * + * @covers ::hasFieldAccess + * @dataProvider providerTestHasFieldAccess + */ + public function testEditViewAccess($operation, $access) { + $account = $this->prophesize(AccountInterface::class); + $account->hasPermission($operation . ' foo_field')->willReturn($access); + $entity = $this->prophesize(EntityInterface::class); + $this->hasFieldAccess($operation, $entity->reveal(), $account->reveal(), $access); + } - // Entity implementing EntityOwnerInterface, edit|view own denied. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(FALSE); - $account->hasPermission($operation . ' own foo_field')->willReturn(FALSE); - $account->id()->willReturn(42); - $entity = $this->prophesize(EntityInterface::class); - $entity->willImplement(EntityOwnerInterface::class); - $entity->getOwnerId()->willReturn(42); - $entity->isNew()->willReturn(FALSE); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), FALSE]; + /** + * Matrix of view/edit grant and deny on global permissions. + * + * Data provider for ::testEditViewAccess. + * + * @return \Generator + * The data. + */ + public static function providerTestHasFieldAccess(): \Generator { + yield 'Edit field allowed.' => ['edit', TRUE]; + yield 'View field allowed.' => ['view', TRUE]; + yield 'Edit field denied.' => ['edit', FALSE]; + yield 'View field denied.' => ['view', FALSE]; + } - // Entity implementing EntityOwnerInterface, edit|view own allowed, but - // non-matching entity owner. + /** + * Matrix of tests for Edit/View own permissions. + * + * @param string $entity_type + * The entity type to check permissions against. + * @param int $entity_id + * The mocked entity ID. + * @param int $account_id + * The mocked user id. + * @param int $owner_id + * The id of the over of the entity. + * @param bool $perm_access + * The site access permission check. + * @param bool $own_access + * The owner access permission check. + * @param bool $access + * The expected access result. + * + * @covers ::hasFieldAccess + * @dataProvider providerEditViewOwnAccess + */ + public function testEditViewOwnAccess($entity_type, $entity_id, $account_id, $owner_id, $perm_access, $own_access, $access) { + foreach (['edit', 'view'] as $operation) { $account = $this->prophesize(AccountInterface::class); - $account->hasPermission($operation . ' foo_field')->willReturn(FALSE); - $account->hasPermission($operation . ' own foo_field')->willReturn(TRUE); - $account->id()->willReturn(27); - $entity = $this->prophesize(EntityInterface::class); - $entity->willImplement(EntityOwnerInterface::class); - $entity->getOwnerId()->willReturn(42); + $account->hasPermission($operation . ' foo_field') + ->willReturn($perm_access); + $account->hasPermission($operation . ' own foo_field') + ->willReturn($own_access); + $account->id()->willReturn($account_id); + $entity = $this->prophesize($entity_type); + if ($entity_type === EntityInterface::class) { + $entity->willImplement(EntityOwnerInterface::class); + $entity->getOwnerId()->willReturn($owner_id); + } + $entity->id()->willReturn($entity_id); $entity->isNew()->willReturn(FALSE); - $cases[] = [$operation, $entity->reveal(), $account->reveal(), FALSE]; + $this->hasFieldAccess($operation, $entity->reveal(), $account->reveal(), $access); } + } - return $cases; + /** + * Matrix of view/edit grant and deny data. + * + * Data provider for ::testEditViewOwnAccess. + * + * @return \Generator + * The data. + */ + public static function providerEditViewOwnAccess(): \Generator { + yield 'User entity, edit|view own allowed.' => [ + UserInterface::class, + 42, + 42, + 42, + FALSE, + TRUE, + TRUE, + ]; + yield 'User entity, edit|view own denied.' => [ + UserInterface::class, + 42, + 42, + 42, + FALSE, + FALSE, + FALSE, + ]; + yield 'User entity, edit|view own allowed, non-matching entity.' => [ + UserInterface::class, + 27, + 42, + 27, + FALSE, + TRUE, + FALSE, + ]; + yield 'Entity implementing EntityOwnerInterface, edit|view own allowed.' => [ + EntityInterface::class, + 27, + 42, + 42, + FALSE, + TRUE, + TRUE, + ]; + yield 'Entity implementing EntityOwnerInterface, edit|view own denied.' => [ + EntityInterface::class, + 27, + 42, + 42, + FALSE, + FALSE, + FALSE, + ]; + yield 'Entity implementing EntityOwnerInterface, edit|view own allowed, but non-matching entity owner.' => [ + EntityInterface::class, + 27, + 42, + 27, + FALSE, + TRUE, + FALSE, + ]; } } diff --git a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php index 5eaf1a97e4..c290e0ec36 100644 --- a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php +++ b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php @@ -2,14 +2,15 @@ namespace Drupal\Tests\field_permissions\Unit\Plugin\FieldPermissionType; -use Prophecy\PhpUnit\ProphecyTrait; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Session\AccountInterface; use Drupal\field\FieldStorageConfigInterface; +use Drupal\field_permissions\FieldPermissionsService; use Drupal\field_permissions\Plugin\FieldPermissionType\PrivateAccess; use Drupal\Tests\UnitTestCase; use Drupal\user\EntityOwnerInterface; use Drupal\user\UserInterface; +use Prophecy\PhpUnit\ProphecyTrait; /** * Tests the private access plugin. @@ -21,6 +22,7 @@ class PrivateAccessTest extends UnitTestCase { use ProphecyTrait; + /** * The private access plugin. * @@ -31,12 +33,13 @@ class PrivateAccessTest extends UnitTestCase { /** * {@inheritdoc} */ - public function setUp():void { + public function setUp(): void { parent::setUp(); $storage = $this->prophesize(FieldStorageConfigInterface::class); + $field_permissions_service = $this->prophesize(FieldPermissionsService::class); - $this->plugin = new PrivateAccess([], 'private', [], $storage->reveal()); + $this->plugin = new PrivateAccess([], 'private', [], $storage->reveal(), $field_permissions_service->reveal()); } /** @@ -46,80 +49,108 @@ public function setUp():void { * * @dataProvider providerTestHasFieldAccess */ - public function testHasFieldAccess($operation, EntityInterface $entity, AccountInterface $account, $access) { - $this->assertEquals($access, $this->plugin->hasFieldAccess($operation, $entity, $account)); + public function testHasFieldAccess($operation, $entity_type, $entity_id, $account_id, $owner_id, $perm_access, $is_new, $expected_access) { + $account = $this->prophesize(AccountInterface::class); + $entity = $this->prophesize($entity_type); + if ($account_id !== NULL) { + $account->id()->willReturn($account_id); + } + if ($perm_access !== NULL) { + $account->hasPermission('access private fields') + ->willReturn($perm_access); + } + if ($owner_id !== NULL) { + $entity = $this->prophesize(EntityInterface::class) + ->willImplement(EntityOwnerInterface::class); + $entity->getOwnerId()->willReturn($owner_id); + } + if ($is_new !== NULL) { + $entity->isNew()->willReturn($is_new); + } + if ($entity_id !== NULL) { + $entity->id()->willReturn($entity_id); + } + $this->assertEquals($expected_access, $this->plugin->hasFieldAccess($operation, $entity->reveal(), $account->reveal())); } /** * Data provider for ::testHasFieldAccess. */ - public function providerTestHasFieldAccess() { - $cases = []; - - // Has 'access private fields' permission. - $account = $this->prophesize(AccountInterface::class); - $account->hasPermission('access private fields')->willReturn(TRUE); - $entity = $this->prophesize(EntityInterface::class)->reveal(); - $cases[] = ['view', $entity, $account->reveal(), TRUE]; - $cases[] = ['edit', $entity, $account->reveal(), TRUE]; - - // New entities always grant permission. - $account = $this->prophesize(AccountInterface::class)->reveal(); - $entity = $this->prophesize(EntityInterface::class); - $entity->isNew()->willReturn(TRUE); - $cases[] = ['view', $entity->reveal(), $account, TRUE]; - $cases[] = ['edit', $entity->reveal(), $account, TRUE]; - - // Special handling for user entities. - // Account same as user entity. - $account = $this->prophesize(AccountInterface::class); - $account->id()->willReturn(42); - $account->hasPermission('access private fields')->willReturn(FALSE); - $entity = $this->prophesize(UserInterface::class); - $entity->id()->willReturn(42); - $entity->isNew()->willReturn(FALSE); - $cases[] = ['view', $entity->reveal(), $account->reveal(), TRUE]; - $cases[] = ['edit', $entity->reveal(), $account->reveal(), TRUE]; - - // Different user than account will deny access. - $account = $this->prophesize(AccountInterface::class); - $account->id()->willReturn(27); - $account->hasPermission('access private fields')->willReturn(FALSE); - $entity = $this->prophesize(UserInterface::class); - $entity->id()->willReturn(42); - $entity->isNew()->willReturn(FALSE); - $cases[] = ['view', $entity->reveal(), $account->reveal(), FALSE]; - $cases[] = ['edit', $entity->reveal(), $account->reveal(), FALSE]; - - // EntityOwnerInterface entities with access. - $account = $this->prophesize(AccountInterface::class); - $account->id()->willReturn(42); - $account->hasPermission('access private fields')->willReturn(FALSE); - $entity = $this->prophesize(EntityInterface::class) - ->willImplement(EntityOwnerInterface::class); - $entity->getOwnerId()->willReturn(42); - $entity->isNew()->willReturn(FALSE); - $cases[] = ['view', $entity->reveal(), $account->reveal(), TRUE]; - $cases[] = ['edit', $entity->reveal(), $account->reveal(), TRUE]; - - // EntityOwnerInterface entities without access. - $account = $this->prophesize(AccountInterface::class); - $account->id()->willReturn(42); - $account->hasPermission('access private fields')->willReturn(FALSE); - $entity = $this->prophesize(EntityInterface::class) - ->willImplement(EntityOwnerInterface::class); - $entity->getOwnerId()->willReturn(27); - $entity->isNew()->willReturn(FALSE); - $cases[] = ['view', $entity->reveal(), $account->reveal(), FALSE]; - $cases[] = ['edit', $entity->reveal(), $account->reveal(), FALSE]; - - // Non-user, or none owner interface entity should always have access. - $account = $this->prophesize(AccountInterface::class)->reveal(); - $entity = $this->prophesize(EntityInterface::class)->reveal(); - $cases[] = ['view', $entity, $account, TRUE]; - $cases[] = ['edit', $entity, $account, TRUE]; - - return $cases; + public static function providerTestHasFieldAccess(): \Generator { + yield "Has 'access private fields' permission." => [ + 'operation' => ['view', 'edit'], + 'entity_type' => EntityInterface::class, + 'entity_id' => NULL, + 'account_id' => NULL, + 'owner_id' => NULL, + 'perm_access' => TRUE, + 'is_new' => NULL, + 'expected_access' => TRUE, + ]; + yield "New entities always grant permission." => [ + 'operation' => ['view', 'edit'], + 'entity_type' => EntityInterface::class, + 'entity_id' => NULL, + 'account_id' => NULL, + 'owner_id' => NULL, + 'perm_access' => NULL, + 'is_new' => TRUE, + 'expected_access' => TRUE, + ]; + + yield "User Entity: Account same as user entity." => [ + 'operation' => ['view', 'edit'], + 'entity_type' => UserInterface::class, + 'entity_id' => 42, + 'account_id' => 42, + 'owner_id' => NULL, + 'perm_access' => FALSE, + 'is_new' => FALSE, + 'expected_access' => TRUE, + ]; + yield "User Entity: Account not same as user entity." => [ + 'operation' => ['view', 'edit'], + 'entity_type' => UserInterface::class, + 'entity_id' => 42, + 'account_id' => 27, + 'owner_id' => NULL, + 'perm_access' => FALSE, + 'is_new' => FALSE, + 'expected_access' => FALSE, + ]; + + yield "EntityOwnerInterface entities with access." => [ + 'operation' => ['view', 'edit'], + 'entity_type' => EntityInterface::class, + 'entity_id' => NULL, + 'account_id' => 42, + 'owner_id' => 42, + 'perm_access' => FALSE, + 'is_new' => FALSE, + 'expected_access' => TRUE, + ]; + + yield "EntityOwnerInterface entities without access." => [ + 'operation' => ['view', 'edit'], + 'entity_type' => EntityInterface::class, + 'entity_id' => NULL, + 'account_id' => 42, + 'owner_id' => 27, + 'perm_access' => FALSE, + 'is_new' => FALSE, + 'expected_access' => FALSE, + ]; + + yield "Non-user or none owner interface entity should always have access." => [ + 'operation' => ['view', 'edit'], + 'entity_type' => EntityInterface::class, + 'entity_id' => NULL, + 'account_id' => NULL, + 'owner_id' => NULL, + 'perm_access' => NULL, + 'is_new' => NULL, + 'expected_access' => TRUE, + ]; } } -- GitLab