Merge 8.9.19

merge-requests/1298/head
catch 2021-09-24 18:02:17 +01:00
commit 4228606449
21 changed files with 277 additions and 86 deletions

8
composer.lock generated
View File

@ -897,7 +897,11 @@
},
{
"name": "drupal/core-project-message",
<<<<<<< HEAD
"version": "8.9.x-dev",
=======
"version": "8.9.19",
>>>>>>> 8.9.19
"dist": {
"type": "path",
"url": "composer/Plugin/ProjectMessage",
@ -930,7 +934,11 @@
},
{
"name": "drupal/core-vendor-hardening",
<<<<<<< HEAD
"version": "8.9.x-dev",
=======
"version": "8.9.19",
>>>>>>> 8.9.19
"dist": {
"type": "path",
"url": "composer/Plugin/VendorHardening",

View File

@ -82,7 +82,7 @@ class Drupal {
/**
* The current system version.
*/
const VERSION = '8.9.19-dev';
const VERSION = '8.9.20-dev';
/**
* Core API compatibility.

View File

@ -180,6 +180,11 @@ class QuickEditIntegrationTest extends QuickEditTestBase {
// Verify metadata.
$items = $entity->get($this->fieldName);
\Drupal::state()->set('quickedit_test_field_access', 'forbidden');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'neutral');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'allowed');
$metadata = $this->metadataGenerator->generateFieldMetadata($items, 'default');
$expected = [
'access' => TRUE,

View File

@ -255,15 +255,27 @@ class FileUploadResource extends ResourceBase {
$file->setOwnerId($this->currentUser->id());
$file->setFilename($prepared_filename);
$file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename));
$file->setFileUri($file_uri);
$file->setFileUri($temp_file_path);
// Set the size. This is done in File::preSave() but we validate the file
// before it is saved.
$file->setSize(@filesize($temp_file_path));
// Validate the file entity against entity-level validation and field-level
// validators.
$this->validate($file, $validators);
// Validate the file against field-level validators first while the file is
// still a temporary file. Validation is split up in 2 steps to be the same
// as in _file_save_upload_single().
// For backwards compatibility this part is copied from ::validate() to
// leave that method behavior unchanged.
// @todo Improve this with a file uploader service in
// https://www.drupal.org/project/drupal/issues/2940383
$errors = file_validate($file, $validators);
if (!empty($errors)) {
$message = "Unprocessable Entity: file validation failed.\n";
$message .= implode("\n", array_map([PlainTextOutput::class, 'renderFromHtml'], $errors));
throw new UnprocessableEntityHttpException($message);
}
$file->setFileUri($file_uri);
// Move the file to the correct location after validation. Use
// FileSystemInterface::EXISTS_ERROR as the file location has already been
// determined above in FileSystem::getDestinationFilename().
@ -274,6 +286,9 @@ class FileUploadResource extends ResourceBase {
throw new HttpException(500, 'Temporary file could not be moved to file location');
}
// Second step of the validation on the file object itself now.
$this->resourceValidate($file);
$file->save();
$this->lock->release($lock_id);
@ -426,6 +441,11 @@ class FileUploadResource extends ResourceBase {
/**
* Validates the file.
*
* @todo this method is unused in this class because file validation needs to
* be split up in 2 steps in ::post(). Add a deprecation notice as soon as a
* central core file upload service can be used in this class.
* See https://www.drupal.org/project/drupal/issues/2940383
*
* @param \Drupal\file\FileInterface $file
* The file entity to validate.
* @param array $validators

View File

@ -42,9 +42,19 @@ class QuickEditImageTest extends QuickEditJavascriptTestBase {
// Create the Article node type.
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
}
/**
* Tests that quick editor works correctly with images.
*
* @covers ::isCompatible
* @covers ::getAttachments
*
* @dataProvider providerTestImageInPlaceEditor
*/
public function testImageInPlaceEditor($admin_permission = FALSE) {
// Log in as a content author who can use Quick Edit and edit Articles.
$this->contentAuthorUser = $this->drupalCreateUser([
$permissions = [
'access contextual links',
'access toolbar',
'access in-place editing',
@ -52,17 +62,13 @@ class QuickEditImageTest extends QuickEditJavascriptTestBase {
'create article content',
'edit any article content',
'delete any article content',
]);
];
if ($admin_permission) {
$permissions[] = 'administer nodes';
}
$this->contentAuthorUser = $this->drupalCreateUser($permissions);
$this->drupalLogin($this->contentAuthorUser);
}
/**
* Test that quick editor works correctly with images.
*
* @covers ::isCompatible
* @covers ::getAttachments
*/
public function testImageInPlaceEditor() {
// Create a field with a basic filetype restriction.
$field_name = strtolower($this->randomMachineName());
$field_settings = [
@ -127,13 +133,25 @@ class QuickEditImageTest extends QuickEditJavascriptTestBase {
$this->assertEntityInstanceStates([
'node/1[0]' => 'closed',
]);
$admin_inactive = [];
$admin_candidate = [];
if ($admin_permission) {
$admin_inactive = [
'node/1/uid/en/full' => 'inactive',
'node/1/created/en/full' => 'inactive',
];
$admin_candidate = [
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
];
}
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'inactive',
'node/1/uid/en/full' => 'inactive',
'node/1/created/en/full' => 'inactive',
'node/1/body/en/full' => 'inactive',
'node/1/' . $field_name . '/en/full' => 'inactive',
]);
] + $admin_inactive);
// Start in-place editing of the article node.
$this->startQuickEditViaToolbar('node', 1, 0);
@ -143,11 +161,9 @@ class QuickEditImageTest extends QuickEditJavascriptTestBase {
$this->assertQuickEditEntityToolbar((string) $node->label(), NULL);
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'candidate',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/' . $field_name . '/en/full' => 'candidate',
]);
] + $admin_candidate);
// Click the image field.
$this->click($field_selector);
@ -155,21 +171,17 @@ class QuickEditImageTest extends QuickEditJavascriptTestBase {
$this->assertSession()->elementExists('css', $field_selector . ' .quickedit-image-dropzone');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'candidate',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/' . $field_name . '/en/full' => 'active',
]);
] + $admin_candidate);
// Type new 'alt' text.
$this->typeInImageEditorAltTextInput('New text');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'candidate',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/' . $field_name . '/en/full' => 'changed',
]);
] + $admin_candidate);
// Drag and drop an image.
$this->dropImageOnImageEditor($valid_images[1]->uri);
@ -184,11 +196,9 @@ class QuickEditImageTest extends QuickEditJavascriptTestBase {
]);
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'candidate',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/' . $field_name . '/en/full' => 'saving',
]);
] + $admin_candidate);
$this->assertEntityInstanceFieldMarkup('node', 1, 0, [
'node/1/' . $field_name . '/en/full' => '.quickedit-changed',
]);
@ -207,4 +217,17 @@ class QuickEditImageTest extends QuickEditJavascriptTestBase {
$this->assertSession()->elementExists('css', $entity_selector . ' ' . $field_selector . ' ' . $new_image_selector);
}
/**
* Data provider for ::testImageInPlaceEditor().
*
* @return array
* Test cases.
*/
public function providerTestImageInPlaceEditor(): array {
return [
'with permission' => [TRUE],
'without permission' => [FALSE],
];
}
}

View File

@ -18,6 +18,7 @@ use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Utility\Token;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Core\Entity\EntityConstraintViolationList;
use Drupal\file\Entity\File;
use Drupal\file\Plugin\Field\FieldType\FileFieldItemList;
use Psr\Log\LoggerInterface;
@ -174,18 +175,37 @@ class TemporaryJsonapiFileFieldUploader {
$file->setOwnerId($owner->id());
$file->setFilename($prepared_filename);
$file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename));
$file->setFileUri($file_uri);
$file->setFileUri($temp_file_path);
// Set the size. This is done in File::preSave() but we validate the file
// before it is saved.
$file->setSize(@filesize($temp_file_path));
// Validate the file entity against entity-level validation and field-level
// validators.
$violations = $this->validate($file, $validators);
if ($violations->count() > 0) {
// Validate the file against field-level validators first while the file is
// still a temporary file. Validation is split up in 2 steps to be the same
// as in _file_save_upload_single().
// For backwards compatibility this part is copied from ::validate() to
// leave that method behavior unchanged.
// @todo Improve this with a file uploader service in
// https://www.drupal.org/project/drupal/issues/2940383
$errors = file_validate($file, $validators);
if (!empty($errors)) {
$violations = new EntityConstraintViolationList($file);
$translator = new DrupalTranslator();
$entity = EntityAdapter::createFromEntity($file);
foreach ($errors as $error) {
$violation = new ConstraintViolation($translator->trans($error),
$error,
[],
$entity,
'',
NULL
);
$violations->add($violation);
}
return $violations;
}
$file->setFileUri($file_uri);
// Move the file to the correct location after validation. Use
// FileSystemInterface::EXISTS_ERROR as the file location has already been
// determined above in FileSystem::getDestinationFilename().
@ -196,6 +216,16 @@ class TemporaryJsonapiFileFieldUploader {
throw new HttpException(500, 'Temporary file could not be moved to file location');
}
// Second step of the validation on the file object itself now.
$violations = $file->validate();
// Remove violations of inaccessible fields as they cannot stem from our
// changes.
$violations->filterByFieldAccess();
if ($violations->count() > 0) {
return $violations;
}
$file->save();
$this->lock->release($lock_id);
@ -334,6 +364,11 @@ class TemporaryJsonapiFileFieldUploader {
/**
* Validates the file.
*
* @todo this method is unused in this class because file validation needs to
* be split up in 2 steps in ::handleFileUploadForField(). Add a deprecation
* notice as soon as a central core file upload service can be used in this
* class. See https://www.drupal.org/project/drupal/issues/2940383
*
* @param \Drupal\file\FileInterface $file
* The file entity to validate.
* @param array $validators

View File

@ -400,7 +400,7 @@ class ResourceType {
$this->relatableResourceTypesByField = array_reduce(array_map(function (ResourceTypeRelationship $field) {
return [$field->getPublicName() => $field->getRelatableResourceTypes()];
}, array_filter($this->fields, function (ResourceTypeField $field) {
return $field instanceof ResourceTypeRelationship;
return $field instanceof ResourceTypeRelationship && $field->isFieldEnabled();
})), 'array_merge', []);
}
return $this->relatableResourceTypesByField;
@ -418,7 +418,7 @@ class ResourceType {
* @see self::getRelatableResourceTypes()
*/
public function getRelatableResourceTypesByField($field_name) {
return ($field = $this->getFieldByPublicName($field_name)) && $field instanceof ResourceTypeRelationship
return ($field = $this->getFieldByPublicName($field_name)) && $field instanceof ResourceTypeRelationship && $field->isFieldEnabled()
? $field->getRelatableResourceTypes()
: [];
}

View File

@ -113,6 +113,14 @@ class LayoutBuilderQuickEditTest extends QuickEditJavascriptTestBase {
$this->drupalLogin($this->contentAuthorUser);
$this->usingLayoutBuilder = TRUE;
$this->assertQuickEditInit(['title']);
$this->drupalLogin($this->drupalCreateUser([
'access contextual links',
'access in-place editing',
'access content',
'edit any article content',
'administer nodes',
]));
$this->assertQuickEditInit(['title', 'uid', 'created']);
}
@ -124,7 +132,7 @@ class LayoutBuilderQuickEditTest extends QuickEditJavascriptTestBase {
*
* @dataProvider providerEnableDisableLayoutBuilder
*/
public function testEnableDisableLayoutBuilder($use_revisions) {
public function testEnableDisableLayoutBuilder($use_revisions, $admin_permission = FALSE) {
if (!$use_revisions) {
$content_type = NodeType::load('article');
$content_type->setNewRevision(FALSE);
@ -132,10 +140,18 @@ class LayoutBuilderQuickEditTest extends QuickEditJavascriptTestBase {
}
$fields = [
'title',
'uid',
'created',
'body',
];
if ($admin_permission) {
$fields = array_merge($fields, ['uid', 'created']);
$this->drupalLogin($this->drupalCreateUser([
'access contextual links',
'access in-place editing',
'access content',
'edit any article content',
'administer nodes',
]));
}
// Test article with Layout Builder disabled.
$this->assertQuickEditInit($fields);
@ -169,8 +185,10 @@ class LayoutBuilderQuickEditTest extends QuickEditJavascriptTestBase {
*/
public function providerEnableDisableLayoutBuilder() {
return [
'use revisions' => [TRUE],
'do not use revisions' => [FALSE],
'use revisions, not admin' => [TRUE],
'do not use revisions, not admin' => [FALSE],
'use revisions, admin' => [TRUE, TRUE],
'do not use revisions, admin' => [FALSE, TRUE],
];
}

View File

@ -472,6 +472,10 @@
uuid: this.data.attributes['data-entity-uuid'],
},
dataType: 'html',
headers: {
'X-Drupal-MediaPreview-CSRF-Token':
editor.config.drupalMedia_previewCsrfToken,
},
success: (previewHtml, textStatus, jqXhr) => {
this.element.setHtml(previewHtml);
this.setData(

View File

@ -314,6 +314,9 @@
uuid: this.data.attributes['data-entity-uuid']
},
dataType: 'html',
headers: {
'X-Drupal-MediaPreview-CSRF-Token': editor.config.drupalMedia_previewCsrfToken
},
success: function success(previewHtml, textStatus, jqXhr) {
_this3.element.setHtml(previewHtml);
_this3.setData('label', jqXhr.getResponseHeader('Drupal-Media-Label'));

View File

@ -7,10 +7,12 @@ use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\ContentEntityStorageInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\filter\FilterFormatInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
@ -93,6 +95,8 @@ class MediaFilterController implements ContainerInjectionInterface {
* @see \Drupal\editor\EditorController::getUntransformedText
*/
public function preview(Request $request, FilterFormatInterface $filter_format) {
self::checkCsrf($request, \Drupal::currentUser());
$text = $request->query->get('text');
$uuid = $request->query->get('uuid');
if ($text == '' || $uuid == '') {
@ -140,4 +144,30 @@ class MediaFilterController implements ContainerInjectionInterface {
->addCacheableDependency($filter_format);
}
/**
* Throws an AccessDeniedHttpException if the request fails CSRF validation.
*
* This is used instead of \Drupal\Core\Access\CsrfAccessCheck, in order to
* allow access for anonymous users.
*
* @todo Refactor this to an access checker.
*/
private static function checkCsrf(Request $request, AccountInterface $account) {
$header = 'X-Drupal-MediaPreview-CSRF-Token';
if (!$request->headers->has($header)) {
throw new AccessDeniedHttpException();
}
if ($account->isAnonymous()) {
// For anonymous users, just the presence of the custom header is
// sufficient protection.
return;
}
// For authenticated users, validate the token value.
$token = $request->headers->get($header);
if (!\Drupal::csrfToken()->validate($token, $header)) {
throw new AccessDeniedHttpException();
}
}
}

View File

@ -98,7 +98,9 @@ class DrupalMedia extends PluginBase implements ContainerFactoryPluginInterface,
* {@inheritdoc}
*/
public function getConfig(Editor $editor) {
return [];
return [
'drupalMedia_previewCsrfToken' => \Drupal::csrfToken()->get('X-Drupal-MediaPreview-CSRF-Token'),
];
}
/**

View File

@ -3,7 +3,6 @@
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\Component\Utility\Html;
use Drupal\Core\Url;
use Drupal\editor\Entity\Editor;
use Drupal\field\Entity\FieldConfig;
use Drupal\file\Entity\File;
@ -1027,14 +1026,13 @@ class CKEditorIntegrationTest extends WebDriverTestBase {
* @dataProvider previewAccessProvider
*/
public function testEmbedPreviewAccess($media_embed_enabled, $can_use_format) {
$format = FilterFormat::create([
'format' => $this->randomMachineName(),
'name' => $this->randomString(),
'filters' => [
'filter_align' => ['status' => TRUE],
'filter_caption' => ['status' => TRUE],
'media_embed' => ['status' => $media_embed_enabled],
],
// Reconfigure the host entity's text format to suit our needs.
/** @var \Drupal\filter\FilterFormatInterface $format */
$format = FilterFormat::load($this->host->body->format);
$format->set('filters', [
'filter_align' => ['status' => TRUE],
'filter_caption' => ['status' => TRUE],
'media_embed' => ['status' => $media_embed_enabled],
]);
$format->save();
@ -1045,24 +1043,23 @@ class CKEditorIntegrationTest extends WebDriverTestBase {
$permissions[] = $format->getPermissionName();
}
$this->drupalLogin($this->drupalCreateUser($permissions));
$text = '<drupal-media data-caption="baz" data-entity-type="media" data-entity-uuid="' . $this->media->uuid() . '"></drupal-media>';
$route_parameters = ['filter_format' => $format->id()];
$options = [
'query' => [
'text' => $text,
'uuid' => $this->media->uuid(),
],
];
$this->drupalGet(Url::fromRoute('media.filter.preview', $route_parameters, $options));
$this->drupalGet($this->host->toUrl('edit-form'));
$assert_session = $this->assertSession();
if ($media_embed_enabled && $can_use_format) {
$assert_session->elementExists('css', 'img');
$assert_session->responseContains('baz');
if ($can_use_format) {
$this->waitForEditor();
$this->assignNameToCkeditorIframe();
$this->getSession()->switchToIFrame('ckeditor');
if ($media_embed_enabled) {
$this->assertNotEmpty($assert_session->waitForElementVisible('css', 'article.media'));
}
else {
$assert_session->assertWaitOnAjaxRequest();
$assert_session->elementNotExists('css', 'article.media');
}
}
else {
$assert_session->responseContains('You are not authorized to access this page.');
$assert_session->pageTextContains('This field has been disabled because you do not have sufficient permissions to edit it.');
}
}

View File

@ -526,6 +526,9 @@
options.success.call(entityModel);
}
};
entitySaverAjax.options.headers = entitySaverAjax.options.headers || {};
entitySaverAjax.options.headers['X-Drupal-Quickedit-CSRF-Token'] =
drupalSettings.quickedit.csrf_token;
// Trigger the AJAX request, which will will return the
// quickeditEntitySaved AJAX command to which we then react.
entitySaverAjax.execute();

View File

@ -243,6 +243,8 @@
options.success.call(entityModel);
}
};
entitySaverAjax.options.headers = entitySaverAjax.options.headers || {};
entitySaverAjax.options.headers['X-Drupal-Quickedit-CSRF-Token'] = drupalSettings.quickedit.csrf_token;
entitySaverAjax.execute();
},

View File

@ -53,6 +53,7 @@ function quickedit_page_attachments(array &$page) {
return;
}
$page['#attached']['drupalSettings']['quickedit']['csrf_token'] = \Drupal::csrfToken()->get('X-Drupal-Quickedit-CSRF-Token');
$page['#attached']['library'][] = 'quickedit/quickedit';
}

View File

@ -68,7 +68,7 @@ class MetadataGenerator implements MetadataGeneratorInterface {
// Early-return if user does not have access.
$access = $this->accessChecker->accessEditEntityField($entity, $field_name);
if (!$access) {
if (!$access->isAllowed()) {
return ['access' => FALSE];
}

View File

@ -6,10 +6,12 @@ use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Entity\EntityInterface;
@ -165,6 +167,32 @@ class QuickEditController extends ControllerBase {
return new JsonResponse($metadata);
}
/**
* Throws an AccessDeniedHttpException if the request fails CSRF validation.
*
* This is used instead of \Drupal\Core\Access\CsrfAccessCheck, in order to
* allow access for anonymous users.
*
* @todo Refactor this to an access checker.
*/
private static function checkCsrf(Request $request, AccountInterface $account) {
$header = 'X-Drupal-Quickedit-CSRF-Token';
if (!$request->headers->has($header)) {
throw new AccessDeniedHttpException();
}
if ($account->isAnonymous()) {
// For anonymous users, just the presence of the custom header is
// sufficient protection.
return;
}
// For authenticated users, validate the token value.
$token = $request->headers->get($header);
if (!\Drupal::csrfToken()->validate($token, $header)) {
throw new AccessDeniedHttpException();
}
}
/**
* Returns AJAX commands to load in-place editors' attachments.
*
@ -315,6 +343,8 @@ class QuickEditController extends ControllerBase {
* The Ajax response.
*/
public function entitySave(EntityInterface $entity) {
self::checkCsrf(\Drupal::request(), \Drupal::currentUser());
// Take the entity from PrivateTempStore and save in entity storage.
// fieldForm() ensures that the PrivateTempStore copy exists ahead.
$tempstore = $this->tempStoreFactory->get('quickedit');

View File

@ -2,6 +2,7 @@
namespace Drupal\quickedit_test;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\quickedit\Access\QuickEditEntityFieldAccessCheckInterface;
@ -14,7 +15,19 @@ class MockQuickEditEntityFieldAccessCheck implements QuickEditEntityFieldAccessC
* {@inheritdoc}
*/
public function accessEditEntityField(EntityInterface $entity, $field_name) {
return TRUE;
switch (\Drupal::state()->get('quickedit_test_field_access')) {
case 'allowed':
return AccessResult::allowed();
case 'neutral':
return AccessResult::neutral();
case 'forbidden':
return AccessResult::forbidden();
default:
throw new \OutOfRangeException("The state for the 'quickedit_test_field_access' key must be either 'allowed', 'neutral' or 'forbidden'.");
}
}
}

View File

@ -146,8 +146,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
]);
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'inactive',
'node/1/uid/en/full' => 'inactive',
'node/1/created/en/full' => 'inactive',
'node/1/body/en/full' => 'inactive',
'node/1/field_tags/en/full' => 'inactive',
]);
@ -160,8 +158,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
$this->assertQuickEditEntityToolbar((string) $node->label(), NULL);
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'candidate',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/field_tags/en/full' => 'candidate',
]);
@ -174,8 +170,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
$this->assertQuickEditEntityToolbar((string) $node->label(), 'Title');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'active',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/field_tags/en/full' => 'candidate',
]);
@ -188,8 +182,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
$this->awaitEntityInstanceFieldState('node', 1, 0, 'title', 'en', 'changed');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'changed',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/field_tags/en/full' => 'candidate',
]);
@ -201,8 +193,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
$this->assertQuickEditEntityToolbar((string) $node->label(), 'Body');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/title/en/full' => 'saving',
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'active',
'node/1/field_tags/en/full' => 'candidate',
]);
@ -225,8 +215,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
$assert_session->waitForElement('css', '.quickedit-toolbar-field div[id*="tags"]');
$this->assertQuickEditEntityToolbar((string) $node->label(), 'Tags');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/field_tags/en/full' => 'activating',
'node/1/title/en/full' => 'candidate',
@ -241,8 +229,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
// Wait for the form to load.
$this->assertJsCondition('document.querySelector(\'.quickedit-form-container > .quickedit-form[role="dialog"] > .placeholder\') === null');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/field_tags/en/full' => 'active',
'node/1/title/en/full' => 'candidate',
@ -252,8 +238,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
$this->typeInFormEditorTextInputField('field_tags[target_id]', 'foo, bar');
$this->awaitEntityInstanceFieldState('node', 1, 0, 'field_tags', 'en', 'changed');
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/field_tags/en/full' => 'changed',
'node/1/title/en/full' => 'candidate',
@ -266,8 +250,6 @@ class QuickEditIntegrationTest extends QuickEditJavascriptTestBase {
'node/1[0]' => 'committing',
]);
$this->assertEntityInstanceFieldStates('node', 1, 0, [
'node/1/uid/en/full' => 'candidate',
'node/1/created/en/full' => 'candidate',
'node/1/body/en/full' => 'candidate',
'node/1/field_tags/en/full' => 'saving',
'node/1/title/en/full' => 'candidate',

View File

@ -97,6 +97,11 @@ class MetadataGeneratorTest extends QuickEditTestBase {
// Verify metadata for field 1.
$items_1 = $entity->get($field_1_name);
\Drupal::state()->set('quickedit_test_field_access', 'forbidden');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items_1, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'neutral');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items_1, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'allowed');
$metadata_1 = $this->metadataGenerator->generateFieldMetadata($items_1, 'default');
$expected_1 = [
'access' => TRUE,
@ -107,6 +112,11 @@ class MetadataGeneratorTest extends QuickEditTestBase {
// Verify metadata for field 2.
$items_2 = $entity->get($field_2_name);
\Drupal::state()->set('quickedit_test_field_access', 'forbidden');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items_2, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'neutral');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items_2, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'allowed');
$metadata_2 = $this->metadataGenerator->generateFieldMetadata($items_2, 'default');
$expected_2 = [
'access' => TRUE,
@ -163,6 +173,11 @@ class MetadataGeneratorTest extends QuickEditTestBase {
// Verify metadata.
$items = $entity->get($field_name);
\Drupal::state()->set('quickedit_test_field_access', 'forbidden');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'neutral');
$this->assertSame(['access' => FALSE], $this->metadataGenerator->generateFieldMetadata($items, 'default'));
\Drupal::state()->set('quickedit_test_field_access', 'allowed');
$metadata = $this->metadataGenerator->generateFieldMetadata($items, 'default');
$expected = [
'access' => TRUE,