Chris@0: 'filtered_html', Chris@0: 'name' => 'Filtered HTML', Chris@0: 'weight' => 0, Chris@0: 'filters' => [], Chris@0: ]); Chris@0: $filtered_html_format->save(); Chris@0: Chris@0: // Create a node type. Chris@0: $this->drupalCreateContentType([ Chris@0: 'type' => 'article', Chris@0: 'name' => 'Article', Chris@0: ]); Chris@0: Chris@0: // Set the node type to initially not have revisions. Chris@0: // Testing with revisions will be done later. Chris@0: $node_type = NodeType::load('article'); Chris@0: $node_type->setNewRevision(FALSE); Chris@0: $node_type->save(); Chris@0: Chris@0: // Create one node of the above node type using the above text format. Chris@0: $this->testNode = $this->drupalCreateNode([ Chris@0: 'type' => 'article', Chris@0: 'body' => [ Chris@0: 0 => [ Chris@0: 'value' => '
How are you?
', Chris@0: 'format' => 'filtered_html', Chris@0: ] Chris@0: ], Chris@0: 'revision_log' => $this->randomString(), Chris@0: ]); Chris@0: Chris@0: // Create 2 users, the only difference being the ability to use in-place Chris@0: // editing Chris@0: $basic_permissions = ['access content', 'create article content', 'edit any article content', 'use text format filtered_html', 'access contextual links']; Chris@0: $this->authorUser = $this->drupalCreateUser($basic_permissions); Chris@0: $this->editorUser = $this->drupalCreateUser(array_merge($basic_permissions, ['access in-place editing'])); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Test the loading of Quick Edit when a user doesn't have access to it. Chris@0: */ Chris@0: public function testUserWithoutPermission() { Chris@0: $this->drupalLogin($this->authorUser); Chris@0: $this->drupalGet('node/1'); Chris@0: Chris@0: // Library and in-place editors. Chris@0: $this->assertNoRaw('core/modules/quickedit/js/quickedit.js', 'Quick Edit library not loaded.'); Chris@0: $this->assertNoRaw('core/modules/quickedit/js/editors/formEditor.js', "'form' in-place editor not loaded."); Chris@0: Chris@0: // HTML annotation and title class does not exist for users without Chris@0: // permission to in-place edit. Chris@0: $this->assertNoRaw('data-quickedit-entity-id="node/1"'); Chris@0: $this->assertNoRaw('data-quickedit-field-id="node/1/body/en/full"'); Chris@0: $this->assertNoFieldByXPath('//h1[contains(@class, "js-quickedit-page-title")]'); Chris@0: Chris@0: // Retrieving the metadata should result in an empty 403 response. Chris@0: $post = ['fields[0]' => 'node/1/body/en/full']; Chris@0: $response = $this->drupalPostWithFormat(Url::fromRoute('quickedit.metadata'), 'json', $post); Chris@0: $this->assertIdentical(Json::encode(['message' => "The 'access in-place editing' permission is required."]), $response); Chris@0: $this->assertResponse(403); Chris@0: Chris@0: // Quick Edit's JavaScript would never hit these endpoints if the metadata Chris@0: // was empty as above, but we need to make sure that malicious users aren't Chris@0: // able to use any of the other endpoints either. Chris@0: $post = ['editors[0]' => 'form'] + $this->getAjaxPageStatePostData(); Chris@0: $response = $this->drupalPost('quickedit/attachments', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); Chris@0: $message = Json::encode(['message' => "The 'access in-place editing' permission is required."]); Chris@0: $this->assertIdentical($message, $response); Chris@0: $this->assertResponse(403); Chris@0: $post = ['nocssjs' => 'true'] + $this->getAjaxPageStatePostData(); Chris@0: $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); Chris@0: $this->assertIdentical($message, $response); Chris@0: $this->assertResponse(403); Chris@0: $edit = []; Chris@0: $edit['form_id'] = 'quickedit_field_form'; Chris@0: $edit['form_token'] = 'xIOzMjuc-PULKsRn_KxFn7xzNk5Bx7XKXLfQfw1qOnA'; Chris@0: $edit['form_build_id'] = 'form-kVmovBpyX-SJfTT5kY0pjTV35TV-znor--a64dEnMR8'; Chris@0: $edit['body[0][summary]'] = ''; Chris@0: $edit['body[0][value]'] = 'Malicious content.
'; Chris@0: $edit['body[0][format]'] = 'filtered_html'; Chris@0: $edit['op'] = t('Save'); Chris@0: $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', '', $edit, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); Chris@0: $this->assertIdentical($message, $response); Chris@0: $this->assertResponse(403); Chris@0: $post = ['nocssjs' => 'true']; Chris@0: $response = $this->drupalPostWithFormat('quickedit/entity/' . 'node/1', 'json', $post); Chris@0: $this->assertIdentical(Json::encode(['message' => "The 'access in-place editing' permission is required."]), $response); Chris@0: $this->assertResponse(403); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the loading of Quick Edit when a user does have access to it. Chris@0: * Chris@0: * Also ensures lazy loading of in-place editors works. Chris@0: */ Chris@0: public function testUserWithPermission() { Chris@0: $this->drupalLogin($this->editorUser); Chris@0: $this->drupalGet('node/1'); Chris@0: Chris@0: // Library and in-place editors. Chris@0: $settings = $this->getDrupalSettings(); Chris@0: $libraries = explode(',', $settings['ajaxPageState']['libraries']); Chris@0: $this->assertTrue(in_array('quickedit/quickedit', $libraries), 'Quick Edit library loaded.'); Chris@0: $this->assertFalse(in_array('quickedit/quickedit.inPlaceEditor.form', $libraries), "'form' in-place editor not loaded."); Chris@0: Chris@0: // HTML annotation and title class must always exist (to not break the Chris@0: // render cache). Chris@0: $this->assertRaw('data-quickedit-entity-id="node/1"'); Chris@0: $this->assertRaw('data-quickedit-field-id="node/1/body/en/full"'); Chris@0: $this->assertFieldByXPath('//h1[contains(@class, "js-quickedit-page-title")]'); Chris@0: Chris@0: // There should be only one revision so far. Chris@0: $node = Node::load(1); Chris@0: $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node); Chris@0: $this->assertIdentical(1, count($vids), 'The node has only one revision.'); Chris@0: $original_log = $node->revision_log->value; Chris@0: Chris@0: // Retrieving the metadata should result in a 200 JSON response. Chris@0: $htmlPageDrupalSettings = $this->drupalSettings; Chris@0: $post = ['fields[0]' => 'node/1/body/en/full']; Chris@0: $response = $this->drupalPostWithFormat('quickedit/metadata', 'json', $post); Chris@0: $this->assertResponse(200); Chris@0: $expected = [ Chris@0: 'node/1/body/en/full' => [ Chris@0: 'label' => 'Body', Chris@0: 'access' => TRUE, Chris@0: 'editor' => 'form', Chris@0: ] Chris@0: ]; Chris@0: $this->assertIdentical(Json::decode($response), $expected, 'The metadata HTTP request answers with the correct JSON response.'); Chris@0: // Restore drupalSettings to build the next requests; simpletest wipes them Chris@0: // after a JSON response. Chris@0: $this->drupalSettings = $htmlPageDrupalSettings; Chris@0: Chris@0: // Retrieving the attachments should result in a 200 response, containing: Chris@0: // 1. a settings command with useless metadata: AjaxController is dumb Chris@0: // 2. an insert command that loads the required in-place editors Chris@0: $post = ['editors[0]' => 'form'] + $this->getAjaxPageStatePostData(); Chris@0: $response = $this->drupalPost('quickedit/attachments', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); Chris@0: $ajax_commands = Json::decode($response); Chris@0: $this->assertIdentical(2, count($ajax_commands), 'The attachments HTTP request results in two AJAX commands.'); Chris@0: // First command: settings. Chris@0: $this->assertIdentical('settings', $ajax_commands[0]['command'], 'The first AJAX command is a settings command.'); Chris@0: // Second command: insert libraries into DOM. Chris@0: $this->assertIdentical('insert', $ajax_commands[1]['command'], 'The second AJAX command is an append command.'); Chris@0: $this->assertTrue(in_array('quickedit/quickedit.inPlaceEditor.form', explode(',', $ajax_commands[0]['settings']['ajaxPageState']['libraries'])), 'The quickedit.inPlaceEditor.form library is loaded.'); Chris@0: Chris@0: // Retrieving the form for this field should result in a 200 response, Chris@0: // containing only a quickeditFieldForm command. Chris@0: $post = ['nocssjs' => 'true', 'reset' => 'true'] + $this->getAjaxPageStatePostData(); Chris@0: $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); Chris@0: $this->assertResponse(200); Chris@0: $ajax_commands = Json::decode($response); Chris@0: $this->assertIdentical(1, count($ajax_commands), 'The field form HTTP request results in one AJAX command.'); Chris@0: $this->assertIdentical('quickeditFieldForm', $ajax_commands[0]['command'], 'The first AJAX command is a quickeditFieldForm command.'); Chris@0: $this->assertIdentical('