Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
File diff suppressed because one or more lines are too long
804
web/core/modules/content_moderation/tests/fixtures/update/drupal-8.default-cms-entity-id-2941736.php
vendored
Normal file
804
web/core/modules/content_moderation/tests/fixtures/update/drupal-8.default-cms-entity-id-2941736.php
vendored
Normal file
|
|
@ -0,0 +1,804 @@
|
|||
<?php
|
||||
// @codingStandardsIgnoreFile
|
||||
/**
|
||||
* @file
|
||||
* Content for the update path test in #2941736.
|
||||
*
|
||||
* @see \Drupal\Tests\content_moderation\Functional\DefaultContentModerationStateRevisionUpdateTest.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
$connection->insert('block_content')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'type',
|
||||
'uuid',
|
||||
'langcode',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '1',
|
||||
'type' => 'test_block_content',
|
||||
'uuid' => '811fac6c-8184-4de5-99eb-9e70d28709f4',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'type' => 'test_block_content',
|
||||
'uuid' => 'b89f025c-0538-4075-bd8e-96acf74211c9',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'type' => 'test_block_content',
|
||||
'uuid' => '62e428e1-88a6-478c-a8c6-a554ca2332ae',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('block_content_field_data')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'type',
|
||||
'langcode',
|
||||
'info',
|
||||
'changed',
|
||||
'default_langcode',
|
||||
'revision_translation_affected',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '1',
|
||||
'type' => 'test_block_content',
|
||||
'langcode' => 'en',
|
||||
'info' => 'draft pending revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'type' => 'test_block_content',
|
||||
'langcode' => 'en',
|
||||
'info' => 'published default revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'type' => 'test_block_content',
|
||||
'langcode' => 'en',
|
||||
'info' => 'archived default revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('block_content_field_revision')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'langcode',
|
||||
'info',
|
||||
'changed',
|
||||
'default_langcode',
|
||||
'revision_translation_affected',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '1',
|
||||
'langcode' => 'en',
|
||||
'info' => 'draft pending revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '2',
|
||||
'langcode' => 'en',
|
||||
'info' => 'draft pending revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'langcode' => 'en',
|
||||
'info' => 'published default revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '4',
|
||||
'langcode' => 'en',
|
||||
'info' => 'archived default revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'langcode' => 'en',
|
||||
'info' => 'archived default revision',
|
||||
'changed' => '1517725800',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('block_content_revision')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'langcode',
|
||||
'revision_user',
|
||||
'revision_created',
|
||||
'revision_log',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '1',
|
||||
'langcode' => 'en',
|
||||
'revision_user' => NULL,
|
||||
'revision_created' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '2',
|
||||
'langcode' => 'en',
|
||||
'revision_user' => NULL,
|
||||
'revision_created' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'langcode' => 'en',
|
||||
'revision_user' => NULL,
|
||||
'revision_created' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '4',
|
||||
'langcode' => 'en',
|
||||
'revision_user' => NULL,
|
||||
'revision_created' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'langcode' => 'en',
|
||||
'revision_user' => NULL,
|
||||
'revision_created' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->delete('config')
|
||||
->condition('name', ['workflows.workflow.editorial'], 'IN')
|
||||
->execute();
|
||||
|
||||
$connection->insert('config')
|
||||
->fields(array(
|
||||
'collection',
|
||||
'name',
|
||||
'data',
|
||||
))
|
||||
->values(array(
|
||||
'collection' => '',
|
||||
'name' => 'block_content.type.test_block_content',
|
||||
'data' => 'a:8:{s:4:"uuid";s:36:"966baba6-525e-48fe-b8c5-a5f131b1857f";s:8:"langcode";s:2:"en";s:6:"status";b:1;s:12:"dependencies";a:0:{}s:2:"id";s:18:"test_block_content";s:5:"label";s:18:"Test Block Content";s:8:"revision";N;s:11:"description";N;}',
|
||||
))
|
||||
->values(array(
|
||||
'collection' => '',
|
||||
'name' => 'workflows.workflow.editorial',
|
||||
'data' => 'a:9:{s:4:"uuid";s:36:"08b548c7-ff59-468b-9347-7d697680d035";s:8:"langcode";s:2:"en";s:6:"status";b:1;s:12:"dependencies";a:2:{s:6:"config";a:2:{i:0;s:37:"block_content.type.test_block_content";i:1;s:17:"node.type.article";}s:6:"module";a:1:{i:0;s:18:"content_moderation";}}s:5:"_core";a:1:{s:19:"default_config_hash";s:43:"T_JxNjYlfoRBi7Bj1zs5Xv9xv1btuBkKp5C1tNrjMhI";}s:2:"id";s:9:"editorial";s:5:"label";s:9:"Editorial";s:4:"type";s:18:"content_moderation";s:13:"type_settings";a:3:{s:6:"states";a:3:{s:8:"archived";a:4:{s:5:"label";s:8:"Archived";s:6:"weight";i:5;s:9:"published";b:0;s:16:"default_revision";b:1;}s:5:"draft";a:4:{s:5:"label";s:5:"Draft";s:9:"published";b:0;s:16:"default_revision";b:0;s:6:"weight";i:-5;}s:9:"published";a:4:{s:5:"label";s:9:"Published";s:9:"published";b:1;s:16:"default_revision";b:1;s:6:"weight";i:0;}}s:11:"transitions";a:5:{s:7:"archive";a:4:{s:5:"label";s:7:"Archive";s:4:"from";a:1:{i:0;s:9:"published";}s:2:"to";s:8:"archived";s:6:"weight";i:2;}s:14:"archived_draft";a:4:{s:5:"label";s:16:"Restore to Draft";s:4:"from";a:1:{i:0;s:8:"archived";}s:2:"to";s:5:"draft";s:6:"weight";i:3;}s:18:"archived_published";a:4:{s:5:"label";s:7:"Restore";s:4:"from";a:1:{i:0;s:8:"archived";}s:2:"to";s:9:"published";s:6:"weight";i:4;}s:16:"create_new_draft";a:4:{s:5:"label";s:16:"Create New Draft";s:2:"to";s:5:"draft";s:6:"weight";i:0;s:4:"from";a:2:{i:0;s:5:"draft";i:1;s:9:"published";}}s:7:"publish";a:4:{s:5:"label";s:7:"Publish";s:2:"to";s:9:"published";s:6:"weight";i:1;s:4:"from";a:2:{i:0;s:5:"draft";i:1;s:9:"published";}}}s:12:"entity_types";a:2:{s:13:"block_content";a:1:{i:0;s:18:"test_block_content";}s:4:"node";a:1:{i:0;s:7:"article";}}}}',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('content_moderation_state')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'uuid',
|
||||
'langcode',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '2',
|
||||
'uuid' => '3ce04732-f65f-4937-aa49-821f5842ae06',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'uuid' => 'a6507b55-3001-4748-8d32-f4fa47319754',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'uuid' => '112d2bd2-552b-4e2f-9a6d-526740ba1b38',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '4',
|
||||
'revision_id' => '7',
|
||||
'uuid' => 'a85d0d06-e046-4509-b9b4-75d78dcdd91e',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '5',
|
||||
'revision_id' => '8',
|
||||
'uuid' => '3797f5de-116b-4d75-b7e3-5206e6f97c41',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '6',
|
||||
'revision_id' => '10',
|
||||
'uuid' => '8d9b11c1-8ddf-4c61-bb8d-9ac724e28d9e',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('content_moderation_state_field_data')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'langcode',
|
||||
'uid',
|
||||
'workflow',
|
||||
'moderation_state',
|
||||
'content_entity_type_id',
|
||||
'content_entity_id',
|
||||
'content_entity_revision_id',
|
||||
'default_langcode',
|
||||
'revision_translation_affected',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '2',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'draft',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '1',
|
||||
'content_entity_revision_id' => '2',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '2',
|
||||
'content_entity_revision_id' => '3',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'archived',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '3',
|
||||
'content_entity_revision_id' => '5',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '4',
|
||||
'revision_id' => '7',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'draft',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '1',
|
||||
'content_entity_revision_id' => '2',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '5',
|
||||
'revision_id' => '8',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '2',
|
||||
'content_entity_revision_id' => '3',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '6',
|
||||
'revision_id' => '10',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'archived',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '3',
|
||||
'content_entity_revision_id' => '5',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('content_moderation_state_field_revision')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'langcode',
|
||||
'uid',
|
||||
'workflow',
|
||||
'moderation_state',
|
||||
'content_entity_type_id',
|
||||
'content_entity_id',
|
||||
'content_entity_revision_id',
|
||||
'default_langcode',
|
||||
'revision_translation_affected',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '1',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '1',
|
||||
'content_entity_revision_id' => '1',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '2',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'draft',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '1',
|
||||
'content_entity_revision_id' => '2',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '2',
|
||||
'content_entity_revision_id' => '3',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '4',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '3',
|
||||
'content_entity_revision_id' => '4',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'archived',
|
||||
'content_entity_type_id' => 'node',
|
||||
'content_entity_id' => '3',
|
||||
'content_entity_revision_id' => '5',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '4',
|
||||
'revision_id' => '6',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '1',
|
||||
'content_entity_revision_id' => '1',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '4',
|
||||
'revision_id' => '7',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'draft',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '1',
|
||||
'content_entity_revision_id' => '2',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '5',
|
||||
'revision_id' => '8',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '2',
|
||||
'content_entity_revision_id' => '3',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '6',
|
||||
'revision_id' => '9',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'published',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '3',
|
||||
'content_entity_revision_id' => '4',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '6',
|
||||
'revision_id' => '10',
|
||||
'langcode' => 'en',
|
||||
'uid' => '0',
|
||||
'workflow' => 'editorial',
|
||||
'moderation_state' => 'archived',
|
||||
'content_entity_type_id' => 'block_content',
|
||||
'content_entity_id' => '3',
|
||||
'content_entity_revision_id' => '5',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('content_moderation_state_revision')
|
||||
->fields(array(
|
||||
'id',
|
||||
'revision_id',
|
||||
'langcode',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '1',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '1',
|
||||
'revision_id' => '2',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '2',
|
||||
'revision_id' => '3',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '4',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '3',
|
||||
'revision_id' => '5',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '4',
|
||||
'revision_id' => '6',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '4',
|
||||
'revision_id' => '7',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '5',
|
||||
'revision_id' => '8',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '6',
|
||||
'revision_id' => '9',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'id' => '6',
|
||||
'revision_id' => '10',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('key_value')
|
||||
->fields(array(
|
||||
'collection',
|
||||
'name',
|
||||
'value',
|
||||
))
|
||||
->values(array(
|
||||
'collection' => 'config.entity.key_store.block_content_type',
|
||||
'name' => 'uuid:966baba6-525e-48fe-b8c5-a5f131b1857f',
|
||||
'value' => 'a:1:{i:0;s:37:"block_content.type.test_block_content";}',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('node')
|
||||
->fields(array(
|
||||
'nid',
|
||||
'vid',
|
||||
'type',
|
||||
'uuid',
|
||||
'langcode',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'type' => 'article',
|
||||
'uuid' => '11143847-fe18-4808-a797-8b15966adf4c',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '2',
|
||||
'vid' => '3',
|
||||
'type' => 'article',
|
||||
'uuid' => '336e6941-9340-419e-a763-65d4c11ea031',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '3',
|
||||
'vid' => '5',
|
||||
'type' => 'article',
|
||||
'uuid' => '3eebe337-f977-4a32-94d2-4095947f125d',
|
||||
'langcode' => 'en',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('node_field_data')
|
||||
->fields(array(
|
||||
'nid',
|
||||
'vid',
|
||||
'type',
|
||||
'langcode',
|
||||
'status',
|
||||
'title',
|
||||
'uid',
|
||||
'created',
|
||||
'changed',
|
||||
'promote',
|
||||
'sticky',
|
||||
'default_langcode',
|
||||
'revision_translation_affected',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'type' => 'article',
|
||||
'langcode' => 'en',
|
||||
'status' => '1',
|
||||
'title' => 'draft pending revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '2',
|
||||
'vid' => '3',
|
||||
'type' => 'article',
|
||||
'langcode' => 'en',
|
||||
'status' => '1',
|
||||
'title' => 'published default revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '3',
|
||||
'vid' => '5',
|
||||
'type' => 'article',
|
||||
'langcode' => 'en',
|
||||
'status' => '0',
|
||||
'title' => 'archived default revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('node_field_revision')
|
||||
->fields(array(
|
||||
'nid',
|
||||
'vid',
|
||||
'langcode',
|
||||
'status',
|
||||
'title',
|
||||
'uid',
|
||||
'created',
|
||||
'changed',
|
||||
'promote',
|
||||
'sticky',
|
||||
'default_langcode',
|
||||
'revision_translation_affected',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'langcode' => 'en',
|
||||
'status' => '1',
|
||||
'title' => 'draft pending revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '1',
|
||||
'vid' => '2',
|
||||
'langcode' => 'en',
|
||||
'status' => '0',
|
||||
'title' => 'draft pending revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '2',
|
||||
'vid' => '3',
|
||||
'langcode' => 'en',
|
||||
'status' => '1',
|
||||
'title' => 'published default revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '3',
|
||||
'vid' => '4',
|
||||
'langcode' => 'en',
|
||||
'status' => '1',
|
||||
'title' => 'archived default revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '3',
|
||||
'vid' => '5',
|
||||
'langcode' => 'en',
|
||||
'status' => '0',
|
||||
'title' => 'archived default revision',
|
||||
'uid' => '0',
|
||||
'created' => '1517725800',
|
||||
'changed' => '1517725800',
|
||||
'promote' => '1',
|
||||
'sticky' => '0',
|
||||
'default_langcode' => '1',
|
||||
'revision_translation_affected' => '1',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$connection->insert('node_revision')
|
||||
->fields(array(
|
||||
'nid',
|
||||
'vid',
|
||||
'langcode',
|
||||
'revision_uid',
|
||||
'revision_timestamp',
|
||||
'revision_log',
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'langcode' => 'en',
|
||||
'revision_uid' => '0',
|
||||
'revision_timestamp' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '1',
|
||||
'vid' => '2',
|
||||
'langcode' => 'en',
|
||||
'revision_uid' => '0',
|
||||
'revision_timestamp' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '2',
|
||||
'vid' => '3',
|
||||
'langcode' => 'en',
|
||||
'revision_uid' => '0',
|
||||
'revision_timestamp' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '3',
|
||||
'vid' => '4',
|
||||
'langcode' => 'en',
|
||||
'revision_uid' => '0',
|
||||
'revision_timestamp' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->values(array(
|
||||
'nid' => '3',
|
||||
'vid' => '5',
|
||||
'langcode' => 'en',
|
||||
'revision_uid' => '0',
|
||||
'revision_timestamp' => '1517725800',
|
||||
'revision_log' => NULL,
|
||||
))
|
||||
->execute();
|
||||
|
|
@ -5,5 +5,5 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- content_moderation
|
||||
- node
|
||||
- drupal:content_moderation
|
||||
- drupal:node
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- content_moderation
|
||||
- node
|
||||
- user
|
||||
id: test_content_moderation_field_state_test
|
||||
label: test_content_moderation_field_state_test
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
default_field_elements: true
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
settings:
|
||||
link_to_entity: true
|
||||
plugin_id: field
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: string
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
moderation_state:
|
||||
id: moderation_state
|
||||
table: node_field_data
|
||||
field: moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: content_moderation_state
|
||||
settings: { }
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
plugin_id: field
|
||||
filters: { }
|
||||
sorts: { }
|
||||
title: test_content_moderation_field_state_test
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: test-content-moderation-field-state-test
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
|
|
@ -1,447 +0,0 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_content_moderation_latest_revision
|
||||
label: test_content_moderation_latest_revision
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: mini
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: ‹‹
|
||||
next: ››
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_data
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: number_integer
|
||||
settings:
|
||||
thousand_separator: ''
|
||||
prefix_suffix: true
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: field
|
||||
revision_id:
|
||||
id: revision_id
|
||||
table: content_revision_tracker
|
||||
field: revision_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
plugin_id: standard
|
||||
title:
|
||||
id: title
|
||||
table: node_field_revision
|
||||
field: title
|
||||
relationship: latest_revision__node
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: string
|
||||
settings:
|
||||
link_to_entity: false
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
plugin_id: field
|
||||
moderation_state:
|
||||
id: moderation_state
|
||||
table: content_moderation_state_field_revision
|
||||
field: moderation_state
|
||||
relationship: moderation_state
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: target_id
|
||||
type: string
|
||||
settings: { }
|
||||
group_column: target_id
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: content_moderation_state
|
||||
entity_field: moderation_state
|
||||
plugin_id: field
|
||||
moderation_state_1:
|
||||
id: moderation_state_1
|
||||
table: content_moderation_state_field_revision
|
||||
field: moderation_state
|
||||
relationship: moderation_state_1
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: target_id
|
||||
type: string
|
||||
settings: { }
|
||||
group_column: target_id
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: content_moderation_state
|
||||
entity_field: moderation_state
|
||||
plugin_id: field
|
||||
filters: { }
|
||||
sorts:
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_data
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: standard
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships:
|
||||
latest_revision__node:
|
||||
id: latest_revision__node
|
||||
table: content_revision_tracker
|
||||
field: latest_revision__node
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: 'Content latest revision'
|
||||
required: false
|
||||
plugin_id: standard
|
||||
moderation_state_1:
|
||||
id: moderation_state_1
|
||||
table: node_field_revision
|
||||
field: moderation_state
|
||||
relationship: latest_revision__node
|
||||
group_type: group
|
||||
admin_label: 'Content moderation state (latest revision)'
|
||||
required: false
|
||||
entity_type: node
|
||||
plugin_id: standard
|
||||
moderation_state:
|
||||
id: moderation_state
|
||||
table: node_field_revision
|
||||
field: moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: 'Content moderation state'
|
||||
required: false
|
||||
entity_type: node
|
||||
plugin_id: standard
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
rendering_language: '***LANGUAGE_entity_default***'
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- content_moderation
|
||||
- node
|
||||
- user
|
||||
id: test_content_moderation_state_filter_base_table
|
||||
label: test_content_moderation_state_filter_base_table
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_data
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: number_integer
|
||||
settings:
|
||||
thousand_separator: ''
|
||||
prefix_suffix: false
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: field
|
||||
filters:
|
||||
moderation_state:
|
||||
id: moderation_state
|
||||
table: node_field_data
|
||||
field: moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: moderation_state_op
|
||||
label: 'Default Revision State'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: moderation_state_op
|
||||
identifier: default_revision_state
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
entity_type: node
|
||||
plugin_id: moderation_state_filter
|
||||
moderation_state_1:
|
||||
id: moderation_state_1
|
||||
table: node_field_data
|
||||
field: moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: 'not empty'
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
entity_type: node
|
||||
plugin_id: moderation_state_filter
|
||||
sorts:
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_data
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: standard
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags:
|
||||
- 'config:workflow_list'
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: filter-test-path
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags:
|
||||
- 'config:workflow_list'
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- content_moderation
|
||||
- node
|
||||
- user
|
||||
id: test_content_moderation_state_filter_base_table_filter_on_revision
|
||||
label: test_content_moderation_state_filter_base_table_filter_on_revision
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_data
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: number_integer
|
||||
settings:
|
||||
thousand_separator: ''
|
||||
prefix_suffix: false
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: field
|
||||
filters:
|
||||
moderation_state:
|
||||
id: moderation_state
|
||||
table: node_field_revision
|
||||
field: moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: moderation_state_op
|
||||
label: 'Moderation state'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: moderation_state_op
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
entity_type: node
|
||||
plugin_id: moderation_state_filter
|
||||
sorts:
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_data
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: standard
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags:
|
||||
- 'config:workflow_list'
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: filter-on-revision-test-path
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags:
|
||||
- 'config:workflow_list'
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- content_moderation
|
||||
- entity_test
|
||||
id: test_content_moderation_state_filter_entity_test
|
||||
label: test_content_moderation_state_filter_entity_test
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: entity_test_no_bundle
|
||||
base_field: id
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
options: { }
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
entity_id:
|
||||
id: entity_id
|
||||
table: content_revision_tracker
|
||||
field: entity_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
plugin_id: standard
|
||||
filters:
|
||||
moderation_state:
|
||||
id: moderation_state
|
||||
table: entity_test_no_bundle
|
||||
field: moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: moderation_state_op
|
||||
label: 'Moderation state'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: moderation_state_op
|
||||
identifier: moderation_state
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
entity_type: entity_test_no_bundle
|
||||
plugin_id: moderation_state_filter
|
||||
sorts: { }
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
tags: { }
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- content_moderation
|
||||
- user
|
||||
id: test_content_moderation_state_filter_revision_table
|
||||
label: test_content_moderation_state_filter_revision_table
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_revision
|
||||
base_field: vid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'view all revisions'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: mini
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: ‹‹
|
||||
next: ››
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_revision
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: number_integer
|
||||
settings:
|
||||
thousand_separator: ''
|
||||
prefix_suffix: true
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: field
|
||||
filters:
|
||||
moderation_state:
|
||||
id: moderation_state
|
||||
table: node_field_revision
|
||||
field: moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: moderation_state_op
|
||||
label: 'Moderation state'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: moderation_state_op
|
||||
identifier: moderation_state
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
entity_type: node
|
||||
plugin_id: moderation_state_filter
|
||||
sorts:
|
||||
vid:
|
||||
id: vid
|
||||
table: node_field_revision
|
||||
field: vid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
entity_type: node
|
||||
entity_field: vid
|
||||
plugin_id: standard
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- url.query_args
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
|
|
@ -5,6 +5,7 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- content_moderation
|
||||
- node
|
||||
- views
|
||||
- drupal:content_moderation
|
||||
- drupal:node
|
||||
- drupal:views
|
||||
- drupal:entity_test
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class ContentModerationWorkflowTypeTest extends BrowserTestBase {
|
|||
public static $modules = [
|
||||
'content_moderation',
|
||||
'node',
|
||||
'entity_test',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -36,19 +37,27 @@ class ContentModerationWorkflowTypeTest extends BrowserTestBase {
|
|||
* Test creating a new workflow using the content moderation plugin.
|
||||
*/
|
||||
public function testNewWorkflow() {
|
||||
$types[] = $this->createContentType();
|
||||
$types[] = $this->createContentType();
|
||||
$types[] = $this->createContentType();
|
||||
|
||||
$entity_bundle_info = \Drupal::service('entity_type.bundle.info');
|
||||
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/add', [
|
||||
'label' => 'Test Workflow',
|
||||
'id' => 'test_workflow',
|
||||
'label' => 'Test',
|
||||
'id' => 'test',
|
||||
'workflow_type' => 'content_moderation',
|
||||
], 'Save');
|
||||
|
||||
$session = $this->assertSession();
|
||||
// Make sure the test workflow includes the default states and transitions.
|
||||
$this->assertSession()->pageTextContains('Draft');
|
||||
$this->assertSession()->pageTextContains('Published');
|
||||
$this->assertSession()->pageTextContains('Create New Draft');
|
||||
$this->assertSession()->pageTextContains('Publish');
|
||||
$session->pageTextContains('Draft');
|
||||
$session->pageTextContains('Published');
|
||||
$session->pageTextContains('Create New Draft');
|
||||
$session->pageTextContains('Publish');
|
||||
|
||||
$session->linkByHrefNotExists('/admin/config/workflow/workflows/manage/test/state/draft/delete');
|
||||
$session->linkByHrefNotExists('/admin/config/workflow/workflows/manage/test/state/published/delete');
|
||||
|
||||
// Ensure after a workflow is created, the bundle information can be
|
||||
// refreshed.
|
||||
|
|
@ -59,20 +68,40 @@ class ContentModerationWorkflowTypeTest extends BrowserTestBase {
|
|||
$this->submitForm([
|
||||
'label' => 'Test State',
|
||||
'id' => 'test_state',
|
||||
'type_settings[content_moderation][published]' => TRUE,
|
||||
'type_settings[content_moderation][default_revision]' => FALSE,
|
||||
'type_settings[published]' => TRUE,
|
||||
'type_settings[default_revision]' => FALSE,
|
||||
], 'Save');
|
||||
$this->assertSession()->pageTextContains('Created Test State state.');
|
||||
$session->pageTextContains('Created Test State state.');
|
||||
$session->linkByHrefExists('/admin/config/workflow/workflows/manage/test/state/test_state/delete');
|
||||
|
||||
// Check there is a link to delete a default transition.
|
||||
$session->linkByHrefExists('/admin/config/workflow/workflows/manage/test/transition/publish/delete');
|
||||
// Delete the transition.
|
||||
$this->drupalGet('/admin/config/workflow/workflows/manage/test/transition/publish/delete');
|
||||
$this->submitForm([], 'Delete');
|
||||
// The link to delete the transition should now be gone.
|
||||
$session->linkByHrefNotExists('/admin/config/workflow/workflows/manage/test/transition/publish/delete');
|
||||
|
||||
// Ensure that the published settings cannot be changed.
|
||||
$this->drupalGet('admin/config/workflow/workflows/manage/test_workflow/state/published');
|
||||
$this->assertSession()->fieldDisabled('type_settings[content_moderation][published]');
|
||||
$this->assertSession()->fieldDisabled('type_settings[content_moderation][default_revision]');
|
||||
$this->drupalGet('admin/config/workflow/workflows/manage/test/state/published');
|
||||
$session->fieldDisabled('type_settings[published]');
|
||||
$session->fieldDisabled('type_settings[default_revision]');
|
||||
|
||||
// Ensure that the draft settings cannot be changed.
|
||||
$this->drupalGet('admin/config/workflow/workflows/manage/test_workflow/state/draft');
|
||||
$this->assertSession()->fieldDisabled('type_settings[content_moderation][published]');
|
||||
$this->assertSession()->fieldDisabled('type_settings[content_moderation][default_revision]');
|
||||
$this->drupalGet('admin/config/workflow/workflows/manage/test/state/draft');
|
||||
$session->fieldDisabled('type_settings[published]');
|
||||
$session->fieldDisabled('type_settings[default_revision]');
|
||||
|
||||
$this->drupalGet('admin/config/workflow/workflows/manage/test/type/node');
|
||||
$session->pageTextContains('Select the content types for the Test workflow');
|
||||
foreach ($types as $type) {
|
||||
$session->pageTextContains($type->label());
|
||||
$session->elementContains('css', sprintf('.form-item-bundles-%s label', $type->id()), sprintf('Update %s', $type->label()));
|
||||
}
|
||||
|
||||
// Ensure warning message are displayed for unsupported features.
|
||||
$this->drupalGet('admin/config/workflow/workflows/manage/test/type/entity_test_rev');
|
||||
$this->assertSession()->pageTextContains('Test entity - revisions entities do not support publishing statuses. For example, even after transitioning from a published workflow state to an unpublished workflow state they will still be visible to site visitors.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Test updating the ContentModerationState entity default revisions.
|
||||
*
|
||||
* @group Update
|
||||
* @group legacy
|
||||
* @see content_moderation_post_update_update_cms_default_revisions
|
||||
*/
|
||||
class DefaultContentModerationStateRevisionUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
|
||||
__DIR__ . '/../../fixtures/update/drupal-8.4.0-content_moderation_installed.php',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updating the default revision.
|
||||
*/
|
||||
public function testUpdateDefaultRevision() {
|
||||
// Include the database fixture required to test updating the default
|
||||
// revision. This is excluded from ::setDatabaseDumpFiles so that we can
|
||||
// test the same post_update hook with no test content enabled.
|
||||
require __DIR__ . '/../../fixtures/update/drupal-8.default-cms-entity-id-2941736.php';
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
foreach (['node', 'block_content'] as $entity_type_id) {
|
||||
$draft_pending_revision = $this->getEntityByLabel($entity_type_id, 'draft pending revision');
|
||||
$this->assertFalse($draft_pending_revision->isLatestRevision());
|
||||
$this->assertCompositeEntityMatchesDefaultRevisionId($draft_pending_revision);
|
||||
|
||||
$published_default_revision = $this->getEntityByLabel($entity_type_id, 'published default revision');
|
||||
$this->assertTrue($published_default_revision->isLatestRevision());
|
||||
$this->assertCompositeEntityMatchesDefaultRevisionId($published_default_revision);
|
||||
|
||||
$archived_default_revision = $this->getEntityByLabel($entity_type_id, 'archived default revision');
|
||||
$this->assertTrue($archived_default_revision->isLatestRevision());
|
||||
$this->assertCompositeEntityMatchesDefaultRevisionId($archived_default_revision);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the post_update hook when no entity types are being moderated.
|
||||
*/
|
||||
public function testNoEntitiesUnderModeration() {
|
||||
// If any errors occur during the post_update hook, the test case will fail.
|
||||
$this->runUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert for the given entity, the default revision ID matches.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The entity to use for the assertion.
|
||||
*/
|
||||
protected function assertCompositeEntityMatchesDefaultRevisionId(ContentEntityInterface $entity) {
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$entity_list = $entity_type_manager->getStorage('content_moderation_state')
|
||||
->loadByProperties([
|
||||
'content_entity_type_id' => $entity->getEntityTypeId(),
|
||||
'content_entity_id' => $entity->id(),
|
||||
]);
|
||||
$content_moderation_state_entity = array_shift($entity_list);
|
||||
$this->assertEquals($entity->getLoadedRevisionId(), $content_moderation_state_entity->content_entity_revision_id->value);
|
||||
|
||||
// Check that the data table records were updated correctly.
|
||||
/** @var \Drupal\Core\Database\Connection $database */
|
||||
$database = $this->container->get('database');
|
||||
$query = 'SELECT * FROM {content_moderation_state_field_data} WHERE id = :id';
|
||||
$records = $database->query($query, [':id' => $content_moderation_state_entity->id()])
|
||||
->fetchAllAssoc('langcode');
|
||||
foreach ($records as $langcode => $record) {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $translation */
|
||||
$translation = $content_moderation_state_entity->getTranslation($langcode);
|
||||
foreach ((array) $record as $field_name => $value) {
|
||||
if ($translation->hasField($field_name)) {
|
||||
$items = $translation->get($field_name)->getValue();
|
||||
$this->assertEquals(current($items[0]), $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an entity by label.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
* @param string $label
|
||||
* The label of the entity to load.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||
* The loaded entity.
|
||||
*/
|
||||
protected function getEntityByLabel($entity_type_id, $label) {
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$label_field = $entity_type_manager->getDefinition($entity_type_id)->getKey('label');
|
||||
$entity_list = $entity_type_manager->getStorage($entity_type_id)
|
||||
->loadByProperties([$label_field => $label]);
|
||||
return array_shift($entity_list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* Tests the "Latest Revision" views filter.
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class LatestRevisionViewsFilterTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_moderation_test_views',
|
||||
'content_moderation',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests view shows the correct node IDs.
|
||||
*/
|
||||
public function testViewShowsCorrectNids() {
|
||||
$this->createNodeType('Test', 'test');
|
||||
|
||||
$permissions = [
|
||||
'access content',
|
||||
'view all revisions',
|
||||
];
|
||||
$editor1 = $this->drupalCreateUser($permissions);
|
||||
|
||||
$this->drupalLogin($editor1);
|
||||
|
||||
// Make a pre-moderation node.
|
||||
/** @var Node $node_0 */
|
||||
$node_0 = Node::create([
|
||||
'type' => 'test',
|
||||
'title' => 'Node 0 - Rev 1',
|
||||
'uid' => $editor1->id(),
|
||||
]);
|
||||
$node_0->save();
|
||||
|
||||
// Now enable moderation for subsequent nodes.
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'test');
|
||||
$workflow->save();
|
||||
|
||||
// Make a node that is only ever in Draft.
|
||||
/** @var Node $node_1 */
|
||||
$node_1 = Node::create([
|
||||
'type' => 'test',
|
||||
'title' => 'Node 1 - Rev 1',
|
||||
'uid' => $editor1->id(),
|
||||
]);
|
||||
$node_1->moderation_state->value = 'draft';
|
||||
$node_1->save();
|
||||
|
||||
// Make a node that is in Draft, then Published.
|
||||
/** @var Node $node_2 */
|
||||
$node_2 = Node::create([
|
||||
'type' => 'test',
|
||||
'title' => 'Node 2 - Rev 1',
|
||||
'uid' => $editor1->id(),
|
||||
]);
|
||||
$node_2->moderation_state->value = 'draft';
|
||||
$node_2->save();
|
||||
|
||||
$node_2->setTitle('Node 2 - Rev 2');
|
||||
$node_2->moderation_state->value = 'published';
|
||||
$node_2->save();
|
||||
|
||||
// Make a node that is in Draft, then Published, then Draft.
|
||||
/** @var Node $node_3 */
|
||||
$node_3 = Node::create([
|
||||
'type' => 'test',
|
||||
'title' => 'Node 3 - Rev 1',
|
||||
'uid' => $editor1->id(),
|
||||
]);
|
||||
$node_3->moderation_state->value = 'draft';
|
||||
$node_3->save();
|
||||
|
||||
$node_3->setTitle('Node 3 - Rev 2');
|
||||
$node_3->moderation_state->value = 'published';
|
||||
$node_3->save();
|
||||
|
||||
$node_3->setTitle('Node 3 - Rev 3');
|
||||
$node_3->moderation_state->value = 'draft';
|
||||
$node_3->save();
|
||||
|
||||
// Now show the View, and confirm that only the correct titles are showing.
|
||||
$this->drupalGet('/latest');
|
||||
$page = $this->getSession()->getPage();
|
||||
$this->assertEquals(200, $this->getSession()->getStatusCode());
|
||||
$this->assertTrue($page->hasContent('Node 1 - Rev 1'));
|
||||
$this->assertTrue($page->hasContent('Node 2 - Rev 2'));
|
||||
$this->assertTrue($page->hasContent('Node 3 - Rev 3'));
|
||||
$this->assertFalse($page->hasContent('Node 2 - Rev 1'));
|
||||
$this->assertFalse($page->hasContent('Node 3 - Rev 1'));
|
||||
$this->assertFalse($page->hasContent('Node 3 - Rev 2'));
|
||||
$this->assertFalse($page->hasContent('Node 0 - Rev 1'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node type.
|
||||
*
|
||||
* @param string $label
|
||||
* The human-readable label of the type to create.
|
||||
* @param string $machine_name
|
||||
* The machine name of the type to create.
|
||||
*
|
||||
* @return NodeType
|
||||
* The node type just created.
|
||||
*/
|
||||
protected function createNodeType($label, $machine_name) {
|
||||
/** @var NodeType $node_type */
|
||||
$node_type = NodeType::create([
|
||||
'type' => $machine_name,
|
||||
'label' => $label,
|
||||
]);
|
||||
$node_type->save();
|
||||
|
||||
return $node_type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Tests moderated content administration page functionality.
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ModeratedContentViewTest extends BrowserTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* A user with permission to bypass access content.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['content_moderation', 'node', 'views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page'])->save();
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article'])->save();
|
||||
$this->drupalCreateContentType(['type' => 'unmoderated_type', 'name' => 'Unmoderated type'])->save();
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'article');
|
||||
$workflow->save();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(['access administration pages', 'view any unpublished content', 'administer nodes', 'bypass node access']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the moderated content page.
|
||||
*/
|
||||
public function testModeratedContentPage() {
|
||||
$assert_sesison = $this->assertSession();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Use an explicit changed time to ensure the expected order in the content
|
||||
// admin listing. We want these to appear in the table in the same order as
|
||||
// they appear in the following code, and the 'moderated_content' view has a
|
||||
// table style configuration with a default sort on the 'changed' field
|
||||
// descending.
|
||||
$time = \Drupal::time()->getRequestTime();
|
||||
$excluded_nodes['published_page'] = $this->drupalCreateNode(['type' => 'page', 'changed' => $time--, 'moderation_state' => 'published']);
|
||||
$excluded_nodes['published_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'published']);
|
||||
|
||||
$excluded_nodes['unmoderated_type'] = $this->drupalCreateNode(['type' => 'unmoderated_type', 'changed' => $time--]);
|
||||
$excluded_nodes['unmoderated_type']->setNewRevision(TRUE);
|
||||
$excluded_nodes['unmoderated_type']->isDefaultRevision(FALSE);
|
||||
$excluded_nodes['unmoderated_type']->changed->value = $time--;
|
||||
$excluded_nodes['unmoderated_type']->save();
|
||||
|
||||
$nodes['published_then_draft_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'published', 'title' => 'first article - published']);
|
||||
$nodes['published_then_draft_article']->setNewRevision(TRUE);
|
||||
$nodes['published_then_draft_article']->setTitle('first article - draft');
|
||||
$nodes['published_then_draft_article']->moderation_state->value = 'draft';
|
||||
$nodes['published_then_draft_article']->changed->value = $time--;
|
||||
$nodes['published_then_draft_article']->save();
|
||||
|
||||
$nodes['published_then_archived_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'published']);
|
||||
$nodes['published_then_archived_article']->setNewRevision(TRUE);
|
||||
$nodes['published_then_archived_article']->moderation_state->value = 'archived';
|
||||
$nodes['published_then_archived_article']->changed->value = $time--;
|
||||
$nodes['published_then_archived_article']->save();
|
||||
|
||||
$nodes['draft_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'draft']);
|
||||
$nodes['draft_page_1'] = $this->drupalCreateNode(['type' => 'page', 'changed' => $time--, 'moderation_state' => 'draft']);
|
||||
$nodes['draft_page_2'] = $this->drupalCreateNode(['type' => 'page', 'changed' => $time, 'moderation_state' => 'draft']);
|
||||
|
||||
// Verify view, edit, and delete links for any content.
|
||||
$this->drupalGet('admin/content/moderated');
|
||||
$assert_sesison->statusCodeEquals(200);
|
||||
|
||||
// Check that nodes with pending revisions appear in the view.
|
||||
$node_type_labels = $this->xpath('//td[contains(@class, "views-field-type")]');
|
||||
$delta = 0;
|
||||
foreach ($nodes as $node) {
|
||||
$assert_sesison->linkByHrefExists('node/' . $node->id());
|
||||
$assert_sesison->linkByHrefExists('node/' . $node->id() . '/edit');
|
||||
$assert_sesison->linkByHrefExists('node/' . $node->id() . '/delete');
|
||||
// Verify that we can see the content type label.
|
||||
$this->assertEquals($node->type->entity->label(), trim($node_type_labels[$delta]->getText()));
|
||||
$delta++;
|
||||
}
|
||||
|
||||
// Check that nodes that are not moderated or do not have a pending revision
|
||||
// do not appear in the view.
|
||||
foreach ($excluded_nodes as $node) {
|
||||
$assert_sesison->linkByHrefNotExists('node/' . $node->id());
|
||||
}
|
||||
|
||||
// Check that the latest revision is displayed.
|
||||
$assert_sesison->pageTextContains('first article - draft');
|
||||
$assert_sesison->pageTextNotContains('first article - published');
|
||||
|
||||
// Verify filtering by moderation state.
|
||||
$this->drupalGet('admin/content/moderated', ['query' => ['moderation_state' => 'editorial-draft']]);
|
||||
|
||||
$assert_sesison->linkByHrefExists('node/' . $nodes['published_then_draft_article']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefExists('node/' . $nodes['draft_article']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_1']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_1']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefNotExists('node/' . $nodes['published_then_archived_article']->id() . '/edit');
|
||||
|
||||
// Verify filtering by moderation state and content type.
|
||||
$this->drupalGet('admin/content/moderated', ['query' => ['moderation_state' => 'editorial-draft', 'type' => 'page']]);
|
||||
|
||||
$assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_1']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_2']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefNotExists('node/' . $nodes['published_then_draft_article']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefNotExists('node/' . $nodes['published_then_archived_article']->id() . '/edit');
|
||||
$assert_sesison->linkByHrefNotExists('node/' . $nodes['draft_article']->id() . '/edit');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ namespace Drupal\Tests\content_moderation\Functional;
|
|||
use Drupal\node\Entity\Node;
|
||||
use Drupal\simpletest\ContentTypeCreationTrait;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Test the content moderation actions.
|
||||
|
|
@ -15,6 +15,7 @@ use Drupal\workflows\Entity\Workflow;
|
|||
class ModerationActionsTest extends BrowserTestBase {
|
||||
|
||||
use ContentTypeCreationTrait;
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
|
@ -38,7 +39,7 @@ class ModerationActionsTest extends BrowserTestBase {
|
|||
$standard_bundle = $this->createContentType(['type' => 'standard_bundle']);
|
||||
$standard_bundle->save();
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated_bundle');
|
||||
$workflow->save();
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Tests the moderation form, specifically on nodes.
|
||||
|
|
@ -11,6 +12,18 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class ModerationFormTest extends ModerationStateTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'node',
|
||||
'content_moderation',
|
||||
'locale',
|
||||
'content_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -24,9 +37,7 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
/**
|
||||
* Tests the moderation form that shows on the latest version page.
|
||||
*
|
||||
* The latest version page only shows if there is a forward revision. There
|
||||
* is only a forward revision if a draft revision is created on a node where
|
||||
* the default revision is not a published moderation state.
|
||||
* The latest version page only shows if there is a pending revision.
|
||||
*
|
||||
* @see \Drupal\content_moderation\EntityOperations
|
||||
* @see \Drupal\Tests\content_moderation\Functional\ModerationStateBlockTest::testCustomBlockModeration
|
||||
|
|
@ -36,7 +47,8 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Some moderated content',
|
||||
'body[0][value]' => 'First version of the content.',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Some moderated content');
|
||||
$canonical_path = sprintf('node/%d', $node->id());
|
||||
|
|
@ -51,7 +63,7 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->assertResponse(200);
|
||||
$this->assertField('edit-new-state', 'The node view page has a moderation form.');
|
||||
|
||||
// The latest version page should not show, because there is no forward
|
||||
// The latest version page should not show, because there is no pending
|
||||
// revision.
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertResponse(403);
|
||||
|
|
@ -59,7 +71,8 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
// Update the draft.
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'body[0][value]' => 'Second version of the content.',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
|
||||
// The canonical view should have a moderation form, because it is not the
|
||||
// live revision.
|
||||
|
|
@ -67,15 +80,35 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->assertResponse(200);
|
||||
$this->assertField('edit-new-state', 'The node view page has a moderation form.');
|
||||
|
||||
// Preview the draft.
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'body[0][value]' => 'Second version of the content.',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Preview'));
|
||||
|
||||
// The preview view should not have a moderation form.
|
||||
$preview_url = Url::fromRoute('entity.node.preview', [
|
||||
'node_preview' => $node->uuid(),
|
||||
'view_mode_id' => 'full',
|
||||
]);
|
||||
$this->assertResponse(200);
|
||||
$this->assertUrl($preview_url);
|
||||
$this->assertNoField('edit-new-state', 'The node preview page has no moderation form.');
|
||||
|
||||
// The latest version page should not show, because there is still no
|
||||
// forward revision.
|
||||
// pending revision.
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Publish the draft.
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'body[0][value]' => 'Third version of the content.',
|
||||
], t('Save and Publish'));
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save'));
|
||||
|
||||
// Check widget default value.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertFieldByName('moderation_state[0][state]', 'published', 'The moderation default value is set correctly.');
|
||||
|
||||
// The published view should not have a moderation form, because it is the
|
||||
// live revision.
|
||||
|
|
@ -84,14 +117,15 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->assertNoField('edit-new-state', 'The node view page has no moderation form.');
|
||||
|
||||
// The latest version page should not show, because there is still no
|
||||
// forward revision.
|
||||
// pending revision.
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Make a forward revision.
|
||||
// Make a pending revision.
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'body[0][value]' => 'Fourth version of the content.',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
|
||||
// The published view should not have a moderation form, because it is the
|
||||
// live revision.
|
||||
|
|
@ -100,7 +134,7 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->assertNoField('edit-new-state', 'The node view page has no moderation form.');
|
||||
|
||||
// The latest version page should show the moderation form and have "Draft"
|
||||
// status, because the forward revision is in "Draft".
|
||||
// status, because the pending revision is in "Draft".
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertResponse(200);
|
||||
$this->assertField('edit-new-state', 'The latest-version page has a moderation form.');
|
||||
|
|
@ -112,7 +146,7 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
], t('Apply'));
|
||||
|
||||
// The latest version page should not show, because there is no
|
||||
// forward revision.
|
||||
// pending revision.
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertResponse(403);
|
||||
}
|
||||
|
|
@ -122,28 +156,27 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
*/
|
||||
public function testNonBundleModerationForm() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_mulrevpub', 'entity_test_mulrevpub');
|
||||
$workflow->save();
|
||||
$this->workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_mulrevpub', 'entity_test_mulrevpub');
|
||||
$this->workflow->save();
|
||||
|
||||
// Create new moderated content in draft.
|
||||
$this->drupalPostForm('entity_test_mulrevpub/add', [], t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('entity_test_mulrevpub/add', ['moderation_state[0][state]' => 'draft'], t('Save'));
|
||||
|
||||
// The latest version page should not show, because there is no forward
|
||||
// The latest version page should not show, because there is no pending
|
||||
// revision.
|
||||
$this->drupalGet('/entity_test_mulrevpub/manage/1/latest');
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Update the draft.
|
||||
$this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', [], t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', ['moderation_state[0][state]' => 'draft'], t('Save'));
|
||||
|
||||
// The latest version page should not show, because there is still no
|
||||
// forward revision.
|
||||
// pending revision.
|
||||
$this->drupalGet('/entity_test_mulrevpub/manage/1/latest');
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Publish the draft.
|
||||
$this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', [], t('Save and Publish'));
|
||||
$this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', ['moderation_state[0][state]' => 'published'], t('Save'));
|
||||
|
||||
// The published view should not have a moderation form, because it is the
|
||||
// default revision.
|
||||
|
|
@ -152,12 +185,12 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->assertNoText('Status', 'The node view page has no moderation form.');
|
||||
|
||||
// The latest version page should not show, because there is still no
|
||||
// forward revision.
|
||||
// pending revision.
|
||||
$this->drupalGet('entity_test_mulrevpub/manage/1/latest');
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Make a forward revision.
|
||||
$this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', [], t('Save and Create New Draft'));
|
||||
// Make a pending revision.
|
||||
$this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', ['moderation_state[0][state]' => 'draft'], t('Save'));
|
||||
|
||||
// The published view should not have a moderation form, because it is the
|
||||
// default revision.
|
||||
|
|
@ -166,10 +199,10 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->assertNoText('Status', 'The node view page has no moderation form.');
|
||||
|
||||
// The latest version page should show the moderation form and have "Draft"
|
||||
// status, because the forward revision is in "Draft".
|
||||
// status, because the pending revision is in "Draft".
|
||||
$this->drupalGet('entity_test_mulrevpub/manage/1/latest');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('Status', 'Form text found on the latest-version page.');
|
||||
$this->assertText('Moderation state', 'Form text found on the latest-version page.');
|
||||
$this->assertText('Draft', 'Correct status found on the latest-version page.');
|
||||
|
||||
// Submit the moderation form to change status to published.
|
||||
|
|
@ -178,7 +211,7 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
], t('Apply'));
|
||||
|
||||
// The latest version page should not show, because there is no
|
||||
// forward revision.
|
||||
// pending revision.
|
||||
$this->drupalGet('entity_test_mulrevpub/manage/1/latest');
|
||||
$this->assertResponse(403);
|
||||
}
|
||||
|
|
@ -189,9 +222,10 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
public function testModerationFormSetsRevisionAuthor() {
|
||||
// Create new moderated content in published.
|
||||
$node = $this->createNode(['type' => 'moderated_content', 'moderation_state' => 'published']);
|
||||
// Make a forward revision.
|
||||
// Make a pending revision.
|
||||
$node->title = $this->randomMachineName();
|
||||
$node->moderation_state->value = 'draft';
|
||||
$node->setRevisionCreationTime(12345);
|
||||
$node->save();
|
||||
|
||||
$another_user = $this->drupalCreateUser($this->permissions);
|
||||
|
|
@ -203,6 +237,287 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
|
||||
$this->drupalGet(sprintf('node/%d/revisions', $node->id()));
|
||||
$this->assertText('by ' . $another_user->getAccountName());
|
||||
|
||||
// Verify the revision creation time has been updated.
|
||||
$node = $node->load($node->id());
|
||||
$this->assertGreaterThan(12345, $node->getRevisionCreationTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translated and moderated nodes.
|
||||
*/
|
||||
public function testContentTranslationNodeForm() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Add French language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
// Enable content translation on articles.
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][moderated_content][translatable]' => TRUE,
|
||||
'settings[node][moderated_content][settings][language][language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
|
||||
// Adding languages requires a container rebuild in the test running
|
||||
// environment so that multilingual services are used.
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Create new moderated content in draft (revision 1).
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Some moderated content',
|
||||
'body[0][value]' => 'First version of the content.',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
$this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Some moderated content');
|
||||
$this->assertTrue($node->language(), 'en');
|
||||
$edit_path = sprintf('node/%d/edit', $node->id());
|
||||
$translate_path = sprintf('node/%d/translations/add/en/fr', $node->id());
|
||||
$latest_version_path = sprintf('node/%d/latest', $node->id());
|
||||
$french = \Drupal::languageManager()->getLanguage('fr');
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertSession()->statusCodeEquals('403');
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Add french translation (revision 2).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Second version of the content.',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertSession()->statusCodeEquals('403');
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Add french pending revision (revision 3).
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Third version of the content.',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
$this->drupalGet($edit_path);
|
||||
$this->clickLink('Delete');
|
||||
$this->assertSession()->buttonExists('Delete');
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Publish the french pending revision (revision 4).
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Fifth version of the content.',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Publish the English pending revision (revision 5).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Sixth version of the content.',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Make sure we are allowed to create a pending French revision.
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
|
||||
|
||||
// Add an English pending revision (revision 6).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Seventh version of the content.',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Publish the English pending revision (revision 7)
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Eighth version of the content.',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Make sure we are allowed to create a pending French revision.
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
|
||||
|
||||
// Make sure we are allowed to create a pending English revision.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
|
||||
|
||||
// Create new moderated content (revision 1).
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Third moderated content',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Third moderated content');
|
||||
$this->assertTrue($node->language(), 'en');
|
||||
$edit_path = sprintf('node/%d/edit', $node->id());
|
||||
$translate_path = sprintf('node/%d/translations/add/en/fr', $node->id());
|
||||
|
||||
// Translate it, without updating data (revision 2).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
// Add another draft for the translation (revision 3).
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
// Updating and publishing the french translation is still possible.
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
|
||||
// Now the french translation is published, an english draft can be added.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save (this translation)'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the moderation_state field when an alternative widget is set.
|
||||
*/
|
||||
public function testAlternativeModerationStateWidget() {
|
||||
$entity_form_display = EntityFormDisplay::load('node.moderated_content.default');
|
||||
$entity_form_display->setComponent('moderation_state', [
|
||||
'type' => 'string_textfield',
|
||||
'region' => 'content',
|
||||
]);
|
||||
$entity_form_display->save();
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Test content',
|
||||
'moderation_state[0][value]' => 'published',
|
||||
], 'Save');
|
||||
$this->assertSession()->pageTextContains('Moderated content Test content has been created.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that workflows and states can not be deleted if they are in use.
|
||||
*
|
||||
* @covers \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::workflowHasData
|
||||
* @covers \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::workflowStateHasData
|
||||
*/
|
||||
public function testWorkflowInUse() {
|
||||
$user = $this->createUser([
|
||||
'administer workflows',
|
||||
'create moderated_content content',
|
||||
'edit own moderated_content content',
|
||||
'use editorial transition create_new_draft',
|
||||
'use editorial transition publish',
|
||||
'use editorial transition archive',
|
||||
]);
|
||||
$this->drupalLogin($user);
|
||||
$paths = [
|
||||
'archived_state' => 'admin/config/workflow/workflows/manage/editorial/state/archived/delete',
|
||||
'editorial_workflow' => 'admin/config/workflow/workflows/manage/editorial/delete',
|
||||
];
|
||||
$messages = [
|
||||
'archived_state' => 'This workflow state is in use. You cannot remove this workflow state until you have removed all content using it.',
|
||||
'editorial_workflow' => 'This workflow is in use. You cannot remove this workflow until you have removed all content using it.',
|
||||
];
|
||||
foreach ($paths as $path) {
|
||||
$this->drupalGet($path);
|
||||
$this->assertSession()->buttonExists('Delete');
|
||||
}
|
||||
// Create new moderated content in draft.
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Some moderated content',
|
||||
'body[0][value]' => 'First version of the content.',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], 'Save');
|
||||
|
||||
// The archived state is not used yet, so can still be deleted.
|
||||
$this->drupalGet($paths['archived_state']);
|
||||
$this->assertSession()->buttonExists('Delete');
|
||||
|
||||
// The workflow is being used, so can't be deleted.
|
||||
$this->drupalGet($paths['editorial_workflow']);
|
||||
$this->assertSession()->buttonNotExists('Delete');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains($messages['editorial_workflow']);
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Some moderated content');
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], 'Save');
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'archived',
|
||||
], 'Save');
|
||||
|
||||
// Now the archived state is being used so it can not be deleted either.
|
||||
foreach ($paths as $type => $path) {
|
||||
$this->drupalGet($path);
|
||||
$this->assertSession()->buttonNotExists('Delete');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains($messages[$type]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
/**
|
||||
* Test content_moderation functionality with localization and translation.
|
||||
*
|
||||
|
|
@ -22,19 +24,23 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
];
|
||||
|
||||
/**
|
||||
* Tests article translations can be moderated separately.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testTranslateModeratedContent() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Enable moderation on Article node type.
|
||||
$this->createContentTypeFromUi('Article', 'article', TRUE);
|
||||
|
||||
// Add French language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
// Add French and Italian languages.
|
||||
foreach (['fr', 'it'] as $langcode) {
|
||||
$edit = [
|
||||
'predefined_langcode' => $langcode,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
}
|
||||
|
||||
// Enable content translation on articles.
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
|
|
@ -48,13 +54,19 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
// Adding languages requires a container rebuild in the test running
|
||||
// environment so that multilingual services are used.
|
||||
$this->rebuildContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests article translations can be moderated separately.
|
||||
*/
|
||||
public function testTranslateModeratedContent() {
|
||||
// Create a published article in English.
|
||||
$edit = [
|
||||
'title[0][value]' => 'Published English node',
|
||||
'langcode[0][value]' => 'en',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and Publish'));
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save'));
|
||||
$this->assertText(t('Article Published English node has been created.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Published English node');
|
||||
|
||||
|
|
@ -63,8 +75,9 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->clickLink(t('Add'));
|
||||
$edit = [
|
||||
'title[0][value]' => 'French node Draft',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save and Create New Draft (this translation)'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
// Here the error has occurred "The website encountered an unexpected error.
|
||||
// Please try again later."
|
||||
// If the translation has got lost.
|
||||
|
|
@ -74,8 +87,9 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$edit = [
|
||||
'title[0][value]' => 'English node',
|
||||
'langcode[0][value]' => 'en',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save'));
|
||||
$this->assertText(t('Article English node has been created.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('English node');
|
||||
|
||||
|
|
@ -84,14 +98,17 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->clickLink(t('Add'));
|
||||
$edit = [
|
||||
'title[0][value]' => 'French node',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save and Create New Draft (this translation)'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$this->assertText(t('Article French node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('English node', TRUE);
|
||||
|
||||
// Publish the English article and check that the translation stays
|
||||
// unpublished.
|
||||
$this->drupalPostForm('node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
|
||||
$this->drupalPostForm('node/' . $english_node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
$this->assertText(t('Article English node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('English node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
|
|
@ -106,8 +123,9 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
// the translation first.
|
||||
$edit = [
|
||||
'title[0][value]' => 'Another node',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save'));
|
||||
$this->assertText(t('Article Another node has been created.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node');
|
||||
|
||||
|
|
@ -116,14 +134,17 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->clickLink(t('Add'));
|
||||
$edit = [
|
||||
'title[0][value]' => 'Translated node',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save and Create New Draft (this translation)'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$this->assertText(t('Article Translated node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
|
||||
|
||||
// Publish the translation and check that the source language version stays
|
||||
// unpublished.
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
$this->assertText(t('Article Translated node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
|
|
@ -135,8 +156,9 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
// Now check that we can create a new draft of the translation.
|
||||
$edit = [
|
||||
'title[0][value]' => 'New draft of translated node',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', $edit, t('Save and Create New Draft (this translation)'));
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', $edit, t('Save (this translation)'));
|
||||
$this->assertText(t('Article New draft of translated node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
|
|
@ -144,12 +166,11 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertEqual($french_node->getTitle(), 'Translated node', 'The default revision of the published translation remains the same.');
|
||||
|
||||
// Publish the draft.
|
||||
$edit = [
|
||||
'new_state' => 'published',
|
||||
];
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/latest', $edit, t('Apply'));
|
||||
$this->assertText(t('The moderation state has been updated.'));
|
||||
// Publish the French article before testing the archive transition.
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
$this->assertText(t('Article New draft of translated node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertEqual($french_node->moderation_state->value, 'published');
|
||||
|
|
@ -157,15 +178,21 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->assertEqual($french_node->getTitle(), 'New draft of translated node', 'The draft has replaced the published revision.');
|
||||
|
||||
// Publish the English article before testing the archive transition.
|
||||
$this->drupalPostForm('node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
|
||||
$this->drupalPostForm('node/' . $english_node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save (this translation)'));
|
||||
$this->assertText(t('Article Another node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
|
||||
$this->assertEqual($english_node->moderation_state->value, 'published');
|
||||
|
||||
// Archive the node and its translation.
|
||||
$this->drupalPostForm('node/' . $english_node->id() . '/edit', [], t('Save and Archive (this translation)'));
|
||||
$this->drupalPostForm('node/' . $english_node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'archived',
|
||||
], t('Save (this translation)'));
|
||||
$this->assertText(t('Article Another node has been updated.'));
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Archive (this translation)'));
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [
|
||||
'moderation_state[0][state]' => 'archived',
|
||||
], t('Save (this translation)'));
|
||||
$this->assertText(t('Article New draft of translated node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
|
|
@ -173,43 +200,363 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->assertFalse($english_node->isPublished());
|
||||
$this->assertEqual($french_node->moderation_state->value, 'archived');
|
||||
$this->assertFalse($french_node->isPublished());
|
||||
}
|
||||
|
||||
// Create another article with its translation. This time publishing english
|
||||
// after creating a forward french revision.
|
||||
$edit = [
|
||||
'title[0][value]' => 'An english node',
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and Create New Draft'));
|
||||
$this->assertText(t('Article An english node has been created.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node');
|
||||
$this->assertFalse($english_node->isPublished());
|
||||
/**
|
||||
* Tests that individual translations can be moderated independently.
|
||||
*/
|
||||
public function testLanguageIndependentContentModeration() {
|
||||
// Create a published article in English (revision 1).
|
||||
$this->drupalGet('node/add/article');
|
||||
$node = $this->submitNodeForm('Test 1.1 EN', 'published');
|
||||
$this->assertNotLatestVersionPage($node);
|
||||
|
||||
// Add a French translation.
|
||||
$this->drupalGet('node/' . $english_node->id() . '/translations');
|
||||
$edit_path = $node->toUrl('edit-form');
|
||||
$translate_path = $node->toUrl('drupal:content-translation-overview');
|
||||
|
||||
// Create a new English draft (revision 2).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->submitNodeForm('Test 1.2 EN', 'draft', TRUE);
|
||||
$this->assertLatestVersionPage($node);
|
||||
|
||||
// Add a French translation draft (revision 3).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Add'));
|
||||
$this->submitNodeForm('Test 1.3 FR', 'draft');
|
||||
$fr_node = $this->loadTranslation($node, 'fr');
|
||||
$this->assertLatestVersionPage($fr_node);
|
||||
$this->assertModerationForm($node);
|
||||
|
||||
// Add an Italian translation draft (revision 4).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Add'));
|
||||
$this->submitNodeForm('Test 1.4 IT', 'draft');
|
||||
$it_node = $this->loadTranslation($node, 'it');
|
||||
$this->assertLatestVersionPage($it_node);
|
||||
$this->assertModerationForm($node);
|
||||
$this->assertModerationForm($fr_node);
|
||||
|
||||
// Publish the English draft (revision 5).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->submitNodeForm('Test 1.5 EN', 'published', TRUE);
|
||||
$this->assertNotLatestVersionPage($node);
|
||||
$this->assertModerationForm($fr_node);
|
||||
$this->assertModerationForm($it_node);
|
||||
|
||||
// Publish the Italian draft (revision 6).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 2);
|
||||
$this->submitNodeForm('Test 1.6 IT', 'published');
|
||||
$this->assertNotLatestVersionPage($it_node);
|
||||
$this->assertNoModerationForm($node);
|
||||
$this->assertModerationForm($fr_node);
|
||||
|
||||
// Publish the French draft (revision 7).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 1);
|
||||
$this->submitNodeForm('Test 1.7 FR', 'published');
|
||||
$this->assertNotLatestVersionPage($fr_node);
|
||||
$this->assertNoModerationForm($node);
|
||||
$this->assertNoModerationForm($it_node);
|
||||
|
||||
// Create an Italian draft (revision 8).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 2);
|
||||
$this->submitNodeForm('Test 1.8 IT', 'draft');
|
||||
$this->assertLatestVersionPage($it_node);
|
||||
$this->assertNoModerationForm($node);
|
||||
$this->assertNoModerationForm($fr_node);
|
||||
|
||||
// Create a French draft (revision 9).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 1);
|
||||
$this->submitNodeForm('Test 1.9 FR', 'draft');
|
||||
$this->assertLatestVersionPage($fr_node);
|
||||
$this->assertNoModerationForm($node);
|
||||
$this->assertModerationForm($it_node);
|
||||
|
||||
// Create an English draft (revision 10).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->submitNodeForm('Test 1.10 EN', 'draft');
|
||||
$this->assertLatestVersionPage($node);
|
||||
$this->assertModerationForm($fr_node);
|
||||
$this->assertModerationForm($it_node);
|
||||
|
||||
// Now start from a draft article in English (revision 1).
|
||||
$this->drupalGet('node/add/article');
|
||||
$node2 = $this->submitNodeForm('Test 2.1 EN', 'draft', TRUE);
|
||||
$this->assertNotLatestVersionPage($node2, TRUE);
|
||||
|
||||
$edit_path = $node2->toUrl('edit-form');
|
||||
$translate_path = $node2->toUrl('drupal:content-translation-overview');
|
||||
|
||||
// Add a French translation (revision 2).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Add'));
|
||||
$this->submitNodeForm('Test 2.2 FR', 'draft');
|
||||
$fr_node2 = $this->loadTranslation($node2, 'fr');
|
||||
$this->assertNotLatestVersionPage($fr_node2, TRUE);
|
||||
$this->assertModerationForm($node2, FALSE);
|
||||
|
||||
// Add an Italian translation (revision 3).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Add'));
|
||||
$this->submitNodeForm('Test 2.3 IT', 'draft');
|
||||
$it_node2 = $this->loadTranslation($node2, 'it');
|
||||
$this->assertNotLatestVersionPage($it_node2, TRUE);
|
||||
$this->assertModerationForm($node2, FALSE);
|
||||
$this->assertModerationForm($fr_node2, FALSE);
|
||||
|
||||
// Publish the English draft (revision 4).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->submitNodeForm('Test 2.4 EN', 'published', TRUE);
|
||||
$this->assertNotLatestVersionPage($node2);
|
||||
$this->assertModerationForm($fr_node2, FALSE);
|
||||
$this->assertModerationForm($it_node2, FALSE);
|
||||
|
||||
// Publish the Italian draft (revision 5).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 2);
|
||||
$this->submitNodeForm('Test 2.5 IT', 'published');
|
||||
$this->assertNotLatestVersionPage($it_node2);
|
||||
$this->assertNoModerationForm($node2);
|
||||
$this->assertModerationForm($fr_node2, FALSE);
|
||||
|
||||
// Publish the French draft (revision 6).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 1);
|
||||
$this->submitNodeForm('Test 2.6 FR', 'published');
|
||||
$this->assertNotLatestVersionPage($fr_node2);
|
||||
$this->assertNoModerationForm($node2);
|
||||
$this->assertNoModerationForm($it_node2);
|
||||
|
||||
// Now that all revision translations are published, verify that the
|
||||
// moderation form is never displayed on revision pages.
|
||||
/** @var \Drupal\node\NodeStorageInterface $storage */
|
||||
$storage = $this->container->get('entity_type.manager')->getStorage('node');
|
||||
foreach (range(11, 16) as $revision_id) {
|
||||
/** @var \Drupal\node\NodeInterface $revision */
|
||||
$revision = $storage->loadRevision($revision_id);
|
||||
foreach ($revision->getTranslationLanguages() as $langcode => $language) {
|
||||
if ($revision->isRevisionTranslationAffected()) {
|
||||
$this->drupalGet($revision->toUrl('revision'));
|
||||
$this->assertFalse($this->hasModerationForm(), 'Moderation form is not displayed correctly for revision ' . $revision_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create an Italian draft (revision 7).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 2);
|
||||
$this->submitNodeForm('Test 2.7 IT', 'draft');
|
||||
$this->assertLatestVersionPage($it_node2);
|
||||
$this->assertNoModerationForm($node2);
|
||||
$this->assertNoModerationForm($fr_node2);
|
||||
|
||||
// Create a French draft (revision 8).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 1);
|
||||
$this->submitNodeForm('Test 2.8 FR', 'draft');
|
||||
$this->assertLatestVersionPage($fr_node2);
|
||||
$this->assertNoModerationForm($node2);
|
||||
$this->assertModerationForm($it_node2);
|
||||
|
||||
// Create an English draft (revision 9).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->submitNodeForm('Test 2.9 EN', 'draft', TRUE);
|
||||
$this->assertLatestVersionPage($node2);
|
||||
$this->assertModerationForm($fr_node2);
|
||||
$this->assertModerationForm($it_node2);
|
||||
|
||||
// Now publish a draft in another language first and verify that the
|
||||
// moderation form is not displayed on the English node view page.
|
||||
$this->drupalGet('node/add/article');
|
||||
$node3 = $this->submitNodeForm('Test 3.1 EN', 'published');
|
||||
$this->assertNotLatestVersionPage($node3);
|
||||
|
||||
$edit_path = $node3->toUrl('edit-form');
|
||||
$translate_path = $node3->toUrl('drupal:content-translation-overview');
|
||||
|
||||
// Create an English draft (revision 2).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->submitNodeForm('Test 3.2 EN', 'draft', TRUE);
|
||||
$this->assertLatestVersionPage($node3);
|
||||
|
||||
// Add a French translation (revision 3).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Add'));
|
||||
$this->submitNodeForm('Test 3.3 FR', 'draft');
|
||||
$fr_node3 = $this->loadTranslation($node3, 'fr');
|
||||
$this->assertLatestVersionPage($fr_node3);
|
||||
$this->assertModerationForm($node3);
|
||||
|
||||
// Publish the French draft (revision 4).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->clickLink(t('Edit'), 1);
|
||||
$this->submitNodeForm('Test 3.4 FR', 'published');
|
||||
$this->assertNotLatestVersionPage($fr_node3);
|
||||
$this->assertModerationForm($node3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that new translation values are populated properly.
|
||||
*/
|
||||
public function testNewTranslationSourceValues() {
|
||||
// Create a published article in Italian (revision 1).
|
||||
$this->drupalGet('node/add/article');
|
||||
$node = $this->submitNodeForm('Test 1.1 IT', 'published', TRUE, 'it');
|
||||
$this->assertNotLatestVersionPage($node);
|
||||
|
||||
// Create a new draft (revision 2).
|
||||
$this->drupalGet($node->toUrl('edit-form'));
|
||||
$this->submitNodeForm('Test 1.2 IT', 'draft', TRUE);
|
||||
$this->assertLatestVersionPage($node);
|
||||
|
||||
// Create an English draft (revision 3) and verify that the Italian draft
|
||||
// values are used as source values.
|
||||
$url = $node->toUrl('drupal:content-translation-add');
|
||||
$url->setRouteParameter('source', 'it');
|
||||
$url->setRouteParameter('target', 'en');
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains('Test 1.2 IT');
|
||||
$this->submitNodeForm('Test 1.3 EN', 'draft');
|
||||
$this->assertLatestVersionPage($node);
|
||||
|
||||
// Create a French draft (without saving) and verify that the Italian draft
|
||||
// values are used as source values.
|
||||
$url->setRouteParameter('target', 'fr');
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains('Test 1.2 IT');
|
||||
|
||||
// Now switch source language and verify that the English draft values are
|
||||
// used as source values.
|
||||
$url->setRouteParameter('source', 'en');
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains('Test 1.3 EN');
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the node form at the current URL with the specified values.
|
||||
*
|
||||
* @param string $title
|
||||
* The node title.
|
||||
* @param string $moderation_state
|
||||
* The moderation state.
|
||||
* @param bool $default_translation
|
||||
* (optional) Whether we are editing the default translation.
|
||||
* @param string|null $langcode
|
||||
* (optional) The node language. Defaults to English.
|
||||
*
|
||||
* @return \Drupal\node\NodeInterface|null
|
||||
* A node object if a new one is being created, NULL otherwise.
|
||||
*/
|
||||
protected function submitNodeForm($title, $moderation_state, $default_translation = FALSE, $langcode = 'en') {
|
||||
$is_new = strpos($this->getSession()->getCurrentUrl(), '/node/add/') !== FALSE;
|
||||
$edit = [
|
||||
'title[0][value]' => 'A french node',
|
||||
'title[0][value]' => $title,
|
||||
'moderation_state[0][state]' => $moderation_state,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save and Publish (this translation)'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertFalse($english_node->isPublished());
|
||||
if ($is_new) {
|
||||
$default_translation = TRUE;
|
||||
$edit['langcode[0][value]'] = $langcode;
|
||||
}
|
||||
$submit = $default_translation ? t('Save') : t('Save (this translation)');
|
||||
$this->drupalPostForm(NULL, $edit, $submit);
|
||||
$message = $is_new ? "Article $title has been created." : "Article $title has been updated.";
|
||||
$this->assertSession()->pageTextContains($message);
|
||||
return $is_new ? $this->drupalGetNodeByTitle($title) : NULL;
|
||||
}
|
||||
|
||||
// Create a forward revision
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Create New Draft (this translation)'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertFalse($english_node->isPublished());
|
||||
/**
|
||||
* Loads the node translation for the specified language.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface $node
|
||||
* A node object.
|
||||
* @param string $langcode
|
||||
* The translation language code.
|
||||
*
|
||||
* @return \Drupal\node\NodeInterface
|
||||
* The node translation object.
|
||||
*/
|
||||
protected function loadTranslation(NodeInterface $node, $langcode) {
|
||||
/** @var \Drupal\node\NodeStorageInterface $storage */
|
||||
$storage = $this->container->get('entity_type.manager')->getStorage('node');
|
||||
// Explicitly invalidate the cache for that node, as the call below is
|
||||
// statically cached.
|
||||
$storage->resetCache([$node->id()]);
|
||||
/** @var \Drupal\node\NodeInterface $node */
|
||||
$node = $storage->loadRevision($storage->getLatestRevisionId($node->id()));
|
||||
return $node->getTranslation($langcode);
|
||||
}
|
||||
|
||||
// Publish the english node and the default french node not the latest
|
||||
// french node should be used.
|
||||
$this->drupalPostForm('/node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertTrue($english_node->isPublished());
|
||||
/**
|
||||
* Asserts that this is the "latest version" page for the specified node.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface $node
|
||||
* A node object.
|
||||
*/
|
||||
public function assertLatestVersionPage(NodeInterface $node) {
|
||||
$this->assertEquals($node->toUrl('latest-version')->setAbsolute()->toString(), $this->getSession()->getCurrentUrl());
|
||||
$this->assertModerationForm($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that this is not the "latest version" page for the specified node.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface $node
|
||||
* A node object.
|
||||
* @param bool $moderation_form
|
||||
* (optional) Whether the page should contain the moderation form. Defaults
|
||||
* to FALSE.
|
||||
*/
|
||||
public function assertNotLatestVersionPage(NodeInterface $node, $moderation_form = FALSE) {
|
||||
$this->assertNotEquals($node->toUrl('latest-version')->setAbsolute()->toString(), $this->getSession()->getCurrentUrl());
|
||||
if ($moderation_form) {
|
||||
$this->assertModerationForm($node, FALSE);
|
||||
}
|
||||
else {
|
||||
$this->assertNoModerationForm($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the moderation form is displayed for the specified node.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface $node
|
||||
* A node object.
|
||||
* @param bool $latest_tab
|
||||
* (optional) Whether the node form is expected to be displayed on the
|
||||
* latest version page or on the node view page. Defaults to the former.
|
||||
*/
|
||||
public function assertModerationForm(NodeInterface $node, $latest_tab = TRUE) {
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertEquals(!$latest_tab, $this->hasModerationForm());
|
||||
$this->drupalGet($node->toUrl('latest-version'));
|
||||
$this->assertEquals($latest_tab, $this->hasModerationForm());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the moderation form is not displayed for the specified node.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface $node
|
||||
* A node object.
|
||||
*/
|
||||
public function assertNoModerationForm(NodeInterface $node) {
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertFalse($this->hasModerationForm());
|
||||
$this->drupalGet($node->toUrl('latest-version'));
|
||||
$this->assertEquals(403, $this->getSession()->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the page contains the moderation form.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the moderation form could be find in the page, FALSE otherwise.
|
||||
*/
|
||||
public function hasModerationForm() {
|
||||
return (bool) $this->xpath('//ul[@class="entity-moderation-form"]');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace Drupal\Tests\content_moderation\Functional;
|
|||
|
||||
use Drupal\simpletest\ContentTypeCreationTrait;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Test revision revert.
|
||||
|
|
@ -14,6 +14,7 @@ use Drupal\workflows\Entity\Workflow;
|
|||
class ModerationRevisionRevertTest extends BrowserTestBase {
|
||||
|
||||
use ContentTypeCreationTrait;
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
|
@ -34,16 +35,19 @@ class ModerationRevisionRevertTest extends BrowserTestBase {
|
|||
$moderated_bundle = $this->createContentType(['type' => 'moderated_bundle']);
|
||||
$moderated_bundle->save();
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated_bundle');
|
||||
$workflow->save();
|
||||
|
||||
/** @var \Drupal\Core\Routing\RouteBuilderInterface $router_builder */
|
||||
$router_builder = $this->container->get('router.builder');
|
||||
$router_builder->rebuildIfNeeded();
|
||||
|
||||
$admin = $this->drupalCreateUser([
|
||||
'access content overview',
|
||||
'administer nodes',
|
||||
'bypass node access',
|
||||
'view all revisions',
|
||||
'view content moderation',
|
||||
'use editorial transition create_new_draft',
|
||||
'use editorial transition publish',
|
||||
]);
|
||||
|
|
@ -55,10 +59,16 @@ class ModerationRevisionRevertTest extends BrowserTestBase {
|
|||
*/
|
||||
public function testEditingAfterRevertRevision() {
|
||||
// Create a draft.
|
||||
$this->drupalPostForm('node/add/moderated_bundle', ['title[0][value]' => 'First draft node'], t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('node/add/moderated_bundle', [
|
||||
'title[0][value]' => 'First draft node',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
|
||||
// Now make it published.
|
||||
$this->drupalPostForm('node/1/edit', ['title[0][value]' => 'Published node'], t('Save and Publish'));
|
||||
$this->drupalPostForm('node/1/edit', [
|
||||
'title[0][value]' => 'Published node',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save'));
|
||||
|
||||
// Check the editing form that show the published title.
|
||||
$this->drupalGet('node/1/edit');
|
||||
|
|
@ -76,7 +86,9 @@ class ModerationRevisionRevertTest extends BrowserTestBase {
|
|||
$this->assertSession()
|
||||
->pageTextContains('First draft node');
|
||||
// Try to save the node.
|
||||
$this->click('.moderation-state-draft > input');
|
||||
$this->drupalPostForm('node/1/edit', [
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
|
||||
// Check if the submission passed the EntityChangedConstraintValidator.
|
||||
$this->assertSession()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Drupal\Tests\content_moderation\Functional;
|
|||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the view access control handler for moderation state entities.
|
||||
|
|
@ -14,6 +14,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class ModerationStateAccessTest extends BrowserTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -32,7 +34,6 @@ class ModerationStateAccessTest extends BrowserTestBase {
|
|||
$permissions = [
|
||||
'access content',
|
||||
'view all revisions',
|
||||
'view content moderation',
|
||||
];
|
||||
$editor1 = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($editor1);
|
||||
|
|
@ -69,7 +70,6 @@ class ModerationStateAccessTest extends BrowserTestBase {
|
|||
$permissions = [
|
||||
'access content',
|
||||
'view all revisions',
|
||||
'administer content moderation',
|
||||
];
|
||||
$admin1 = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($admin1);
|
||||
|
|
@ -90,18 +90,18 @@ class ModerationStateAccessTest extends BrowserTestBase {
|
|||
* @param string $machine_name
|
||||
* The machine name of the type to create.
|
||||
*
|
||||
* @return NodeType
|
||||
* @return \Drupal\node\Entity\NodeType
|
||||
* The node type just created.
|
||||
*/
|
||||
protected function createNodeType($label, $machine_name) {
|
||||
/** @var NodeType $node_type */
|
||||
/** @var \Drupal\node\Entity\NodeType $node_type */
|
||||
$node_type = NodeType::create([
|
||||
'type' => $machine_name,
|
||||
'label' => $label,
|
||||
]);
|
||||
$node_type->save();
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', $machine_name);
|
||||
$workflow->save();
|
||||
return $node_type;
|
||||
|
|
|
|||
|
|
@ -51,25 +51,18 @@ class ModerationStateBlockTest extends ModerationStateTestBase {
|
|||
public function testCustomBlockModeration() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$this->drupalGet('admin/structure/block/block-content/types');
|
||||
$this->assertLinkByHref('admin/structure/block/block-content/manage/basic/moderation');
|
||||
$this->drupalGet('admin/structure/block/block-content/manage/basic');
|
||||
$this->assertLinkByHref('admin/structure/block/block-content/manage/basic/moderation');
|
||||
$this->drupalGet('admin/structure/block/block-content/manage/basic/moderation');
|
||||
|
||||
// Enable moderation for custom blocks at
|
||||
// admin/structure/block/block-content/manage/basic/moderation.
|
||||
$edit = ['workflow' => 'editorial'];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertText(t('Your settings have been saved.'));
|
||||
// Enable moderation for custom blocks.
|
||||
$edit['bundles[basic]'] = TRUE;
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/block_content', $edit, t('Save'));
|
||||
|
||||
// Create a custom block at block/add and save it as draft.
|
||||
$body = 'Body of moderated block';
|
||||
$edit = [
|
||||
'info[0][value]' => 'Moderated block',
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
'body[0][value]' => $body,
|
||||
];
|
||||
$this->drupalPostForm('block/add', $edit, t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('block/add', $edit, t('Save'));
|
||||
$this->assertText(t('basic Moderated block has been created.'));
|
||||
|
||||
// Place the block in the Sidebar First region.
|
||||
|
|
@ -91,8 +84,9 @@ class ModerationStateBlockTest extends ModerationStateTestBase {
|
|||
$updated_body = 'This is the new body value';
|
||||
$edit = [
|
||||
'body[0][value]' => $updated_body,
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm('block/' . $block->id(), $edit, t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('block/' . $block->id(), $edit, t('Save'));
|
||||
$this->assertText(t('basic Moderated block has been updated.'));
|
||||
|
||||
// Navigate to the home page and check that the block shows the updated
|
||||
|
|
@ -101,18 +95,21 @@ class ModerationStateBlockTest extends ModerationStateTestBase {
|
|||
$this->drupalGet('');
|
||||
$this->assertText($updated_body);
|
||||
|
||||
// Publish the block so we can create a forward revision.
|
||||
$this->drupalPostForm('block/' . $block->id(), [], t('Save and Publish'));
|
||||
// Publish the block so we can create a pending revision.
|
||||
$this->drupalPostForm('block/' . $block->id(), [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save'));
|
||||
|
||||
// Create a forward revision.
|
||||
$forward_revision_body = 'This is the forward revision body value';
|
||||
// Create a pending revision.
|
||||
$pending_revision_body = 'This is the pending revision body value';
|
||||
$edit = [
|
||||
'body[0][value]' => $forward_revision_body,
|
||||
'body[0][value]' => $pending_revision_body,
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm('block/' . $block->id(), $edit, t('Save and Create New Draft'));
|
||||
$this->drupalPostForm('block/' . $block->id(), $edit, t('Save'));
|
||||
$this->assertText(t('basic Moderated block has been updated.'));
|
||||
|
||||
// Navigate to home page and check that the forward revision doesn't show,
|
||||
// Navigate to home page and check that the pending revision doesn't show,
|
||||
// since it should not be set as the default revision.
|
||||
$this->drupalGet('');
|
||||
$this->assertText($updated_body);
|
||||
|
|
@ -124,10 +121,17 @@ class ModerationStateBlockTest extends ModerationStateTestBase {
|
|||
$this->drupalPostForm('block/' . $block->id() . '/latest', $edit, t('Apply'));
|
||||
$this->assertText(t('The moderation state has been updated.'));
|
||||
|
||||
// Navigate to home page and check that the forward revision is now the
|
||||
// Navigate to home page and check that the pending revision is now the
|
||||
// default revision and therefore visible.
|
||||
$this->drupalGet('');
|
||||
$this->assertText($forward_revision_body);
|
||||
$this->assertText($pending_revision_body);
|
||||
|
||||
// Check that revision is checked by default when content moderation is
|
||||
// enabled.
|
||||
$this->drupalGet('/block/' . $block->id());
|
||||
$this->assertSession()->checkboxChecked('revision');
|
||||
$this->assertText('Revisions must be required when moderation is enabled.');
|
||||
$this->assertSession()->fieldDisabled('revision');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
public function testCreatingContent() {
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'moderated content',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
$node = $this->getNodeByTitle('moderated content');
|
||||
if (!$node) {
|
||||
$this->fail('Test node was not saved correctly.');
|
||||
|
|
@ -37,7 +38,9 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
|
||||
$path = 'node/' . $node->id() . '/edit';
|
||||
// Set up published revision.
|
||||
$this->drupalPostForm($path, [], t('Save and Publish'));
|
||||
$this->drupalPostForm($path, [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save'));
|
||||
\Drupal::entityTypeManager()->getStorage('node')->resetCache([$node->id()]);
|
||||
/* @var \Drupal\node\NodeInterface $node */
|
||||
$node = \Drupal::entityTypeManager()->getStorage('node')->load($node->id());
|
||||
|
|
@ -52,9 +55,8 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
$this->assertText(t('The Moderated content moderated content has been deleted.'));
|
||||
|
||||
// Disable content moderation.
|
||||
$this->drupalPostForm('admin/structure/types/manage/moderated_content/moderation', ['workflow' => ''], t('Save'));
|
||||
$this->drupalGet('admin/structure/types/manage/moderated_content/moderation');
|
||||
$this->assertOptionSelected('edit-workflow', '');
|
||||
$edit['bundles[moderated_content]'] = FALSE;
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', $edit, t('Save'));;
|
||||
// Ensure the parent environment is up-to-date.
|
||||
// @see content_moderation_workflow_insert()
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
|
|
@ -63,7 +65,7 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
// Create a new node.
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'non-moderated content',
|
||||
], t('Save and publish'));
|
||||
], t('Save'));
|
||||
|
||||
$node = $this->getNodeByTitle('non-moderated content');
|
||||
if (!$node) {
|
||||
|
|
@ -80,7 +82,8 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Some moderated content',
|
||||
'body[0][value]' => 'First version of the content.',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Some moderated content');
|
||||
$edit_path = sprintf('node/%d/edit', $node->id());
|
||||
|
|
@ -94,7 +97,8 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
// URL, but viewing the second revision.
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'body[0][value]' => 'Second version of the content.',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
$this->assertUrl(Url::fromRoute('entity.node.canonical', ['node' => $node->id()]));
|
||||
$this->assertText('Second version of the content.');
|
||||
|
||||
|
|
@ -102,15 +106,17 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
// canonical URL.
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'body[0][value]' => 'Third version of the content.',
|
||||
], t('Save and Publish'));
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save'));
|
||||
$this->assertUrl(Url::fromRoute('entity.node.canonical', ['node' => $node->id()]));
|
||||
$this->assertText('Third version of the content.');
|
||||
|
||||
// Make a new forward revision; after saving, we should be on the "Latest
|
||||
// Make a new pending revision; after saving, we should be on the "Latest
|
||||
// version" tab.
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'body[0][value]' => 'Fourth version of the content.',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
$this->assertUrl(Url::fromRoute('entity.node.latest_version', ['node' => $node->id()]));
|
||||
$this->assertText('Fourth version of the content.');
|
||||
}
|
||||
|
|
@ -138,4 +144,29 @@ class ModerationStateNodeTest extends ModerationStateTestBase {
|
|||
$this->assertEqual(0, $query['page']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the workflow when a user has no Content Moderation permissions.
|
||||
*/
|
||||
public function testNoContentModerationPermissions() {
|
||||
$session_assert = $this->assertSession();
|
||||
|
||||
// Create a user with quite advanced node permissions but no content
|
||||
// moderation permissions.
|
||||
$limited_user = $this->createUser([
|
||||
'administer nodes',
|
||||
'bypass node access',
|
||||
]);
|
||||
$this->drupalLogin($limited_user);
|
||||
|
||||
// Check the user can see the content entity form, but can't see the
|
||||
// moderation state select or save the entity form.
|
||||
$this->drupalGet('node/add/moderated_content');
|
||||
$session_assert->statusCodeEquals(200);
|
||||
$session_assert->fieldNotExists('moderation_state[0][state]');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'title[0][value]' => 'moderated content',
|
||||
], 'Save');
|
||||
$session_assert->pageTextContains('You do not have access to transition from Draft to Draft');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ class ModerationStateNodeTypeTest extends ModerationStateTestBase {
|
|||
|
||||
/**
|
||||
* A node type without moderation state disabled.
|
||||
*
|
||||
* @covers \Drupal\content_moderation\EntityTypeInfo::formAlter
|
||||
* @covers \Drupal\content_moderation\Entity\Handler\NodeModerationHandler::enforceRevisionsBundleFormAlter
|
||||
*/
|
||||
public function testNotModerated() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
|
@ -18,19 +21,22 @@ class ModerationStateNodeTypeTest extends ModerationStateTestBase {
|
|||
$this->assertText('The content type Not moderated has been added.');
|
||||
$this->grantUserPermissionToCreateContentOfType($this->adminUser, 'not_moderated');
|
||||
$this->drupalGet('node/add/not_moderated');
|
||||
$this->assertRaw('Save as unpublished');
|
||||
$this->assertRaw('Save');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'title[0][value]' => 'Test',
|
||||
], t('Save and publish'));
|
||||
], t('Save'));
|
||||
$this->assertText('Not moderated Test has been created.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests enabling moderation on an existing node-type, with content.
|
||||
*
|
||||
* @covers \Drupal\content_moderation\EntityTypeInfo::formAlter
|
||||
* @covers \Drupal\content_moderation\Entity\Handler\NodeModerationHandler::enforceRevisionsBundleFormAlter
|
||||
*/
|
||||
public function testEnablingOnExistingContent() {
|
||||
$editor_permissions = [
|
||||
'administer content moderation',
|
||||
'administer workflows',
|
||||
'access administration pages',
|
||||
'administer content types',
|
||||
'administer nodes',
|
||||
|
|
@ -53,20 +59,11 @@ class ModerationStateNodeTypeTest extends ModerationStateTestBase {
|
|||
$this->drupalGet('node/add/not_moderated');
|
||||
$this->drupalPostForm(NULL, [
|
||||
'title[0][value]' => 'Test',
|
||||
], t('Save and publish'));
|
||||
], t('Save'));
|
||||
$this->assertText('Not moderated Test has been created.');
|
||||
|
||||
// Now enable moderation state, ensuring all the expected links and tabs are
|
||||
// present.
|
||||
$this->drupalGet('admin/structure/types');
|
||||
$this->assertLinkByHref('admin/structure/types/manage/not_moderated/moderation');
|
||||
$this->drupalGet('admin/structure/types/manage/not_moderated');
|
||||
$this->assertLinkByHref('admin/structure/types/manage/not_moderated/moderation');
|
||||
$this->drupalGet('admin/structure/types/manage/not_moderated/moderation');
|
||||
$this->assertOptionSelected('edit-workflow', '');
|
||||
$this->assertNoLink('Delete');
|
||||
$edit['workflow'] = 'editorial';
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
// Now enable moderation state.
|
||||
$this->enableModerationThroughUi('not_moderated');
|
||||
|
||||
// And make sure it works.
|
||||
$nodes = \Drupal::entityTypeManager()->getStorage('node')
|
||||
|
|
@ -81,14 +78,14 @@ class ModerationStateNodeTypeTest extends ModerationStateTestBase {
|
|||
$this->assertLinkByHref('node/' . $node->id() . '/edit');
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Save and Create New Draft');
|
||||
$this->assertNoRaw('Save and Publish');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionNotExists('moderation_state[0][state]', 'published');
|
||||
|
||||
$this->drupalLogin($editor_with_publish);
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Save and Create New Draft');
|
||||
$this->assertRaw('Save and Publish');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
|
||||
$this->assertSession()->optionExists('moderation_state[0][state]', 'published');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\user\Entity\Role;
|
||||
|
||||
/**
|
||||
|
|
@ -11,8 +13,12 @@ use Drupal\user\Entity\Role;
|
|||
*/
|
||||
abstract class ModerationStateTestBase extends BrowserTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Profile to use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'testing';
|
||||
|
||||
|
|
@ -29,7 +35,7 @@ abstract class ModerationStateTestBase extends BrowserTestBase {
|
|||
* @var array
|
||||
*/
|
||||
protected $permissions = [
|
||||
'administer content moderation',
|
||||
'administer workflows',
|
||||
'access administration pages',
|
||||
'administer content types',
|
||||
'administer nodes',
|
||||
|
|
@ -38,8 +44,18 @@ abstract class ModerationStateTestBase extends BrowserTestBase {
|
|||
'access content overview',
|
||||
'use editorial transition create_new_draft',
|
||||
'use editorial transition publish',
|
||||
'use editorial transition archive',
|
||||
'use editorial transition archived_draft',
|
||||
'use editorial transition archived_published',
|
||||
];
|
||||
|
||||
/**
|
||||
* The editorial workflow entity.
|
||||
*
|
||||
* @var \Drupal\workflows\Entity\Workflow
|
||||
*/
|
||||
protected $workflow;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
|
|
@ -58,6 +74,7 @@ abstract class ModerationStateTestBase extends BrowserTestBase {
|
|||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->workflow = $this->createEditorialWorkflow();
|
||||
$this->adminUser = $this->drupalCreateUser($this->permissions);
|
||||
$this->drupalPlaceBlock('local_tasks_block', ['id' => 'tabs_block']);
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
|
@ -94,12 +111,20 @@ abstract class ModerationStateTestBase extends BrowserTestBase {
|
|||
protected function createContentTypeFromUi($content_type_name, $content_type_id, $moderated = FALSE, $workflow_id = 'editorial') {
|
||||
$this->drupalGet('admin/structure/types');
|
||||
$this->clickLink('Add content type');
|
||||
|
||||
// Check that the 'Create new revision' checkbox is checked and disabled.
|
||||
$this->assertSession()->checkboxChecked('options[revision]');
|
||||
$this->assertSession()->fieldDisabled('options[revision]');
|
||||
|
||||
$edit = [
|
||||
'name' => $content_type_name,
|
||||
'type' => $content_type_id,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save content type'));
|
||||
|
||||
// Check the content type has been set to create new revisions.
|
||||
$this->assertTrue(NodeType::load($content_type_id)->isNewRevision());
|
||||
|
||||
if ($moderated) {
|
||||
$this->enableModerationThroughUi($content_type_id, $workflow_id);
|
||||
}
|
||||
|
|
@ -113,13 +138,18 @@ abstract class ModerationStateTestBase extends BrowserTestBase {
|
|||
* @param string $workflow_id
|
||||
* The workflow to attach to the bundle.
|
||||
*/
|
||||
protected function enableModerationThroughUi($content_type_id, $workflow_id = 'editorial') {
|
||||
$edit['workflow'] = $workflow_id;
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $content_type_id . '/moderation', $edit, t('Save'));
|
||||
public function enableModerationThroughUi($content_type_id, $workflow_id = 'editorial') {
|
||||
$this->drupalGet('/admin/config/workflow/workflows');
|
||||
$this->assertLinkByHref('admin/config/workflow/workflows/manage/' . $workflow_id);
|
||||
$edit['bundles[' . $content_type_id . ']'] = TRUE;
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/' . $workflow_id . '/type/node', $edit, t('Save'));
|
||||
// Ensure the parent environment is up-to-date.
|
||||
// @see content_moderation_workflow_insert()
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
||||
/** @var \Drupal\Core\Routing\RouteBuilderInterface $router_builder */
|
||||
$router_builder = $this->container->get('router.builder');
|
||||
$router_builder->rebuildIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\node\Entity\NodeType;
|
||||
|
||||
/**
|
||||
* Tests permission access control around nodes.
|
||||
*
|
||||
|
|
@ -19,7 +21,7 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
'block',
|
||||
'block_content',
|
||||
'node',
|
||||
'node_access_test_empty',
|
||||
'node_access_test',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -28,7 +30,7 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
* @var array
|
||||
*/
|
||||
protected $permissions = [
|
||||
'administer content moderation',
|
||||
'administer workflows',
|
||||
'access administration pages',
|
||||
'administer content types',
|
||||
'administer nodes',
|
||||
|
|
@ -46,9 +48,12 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->createContentTypeFromUi('Moderated content', 'moderated_content', TRUE);
|
||||
$this->createContentTypeFromUi('Moderated content', 'moderated_content', FALSE);
|
||||
$this->grantUserPermissionToCreateContentOfType($this->adminUser, 'moderated_content');
|
||||
|
||||
// Add the private field to the node type.
|
||||
node_access_test_add_field(NodeType::load('moderated_content'));
|
||||
|
||||
// Rebuild permissions because hook_node_grants() is implemented by the
|
||||
// node_access_test_empty module.
|
||||
node_access_rebuild();
|
||||
|
|
@ -58,12 +63,29 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
* Verifies that a non-admin user can still access the appropriate pages.
|
||||
*/
|
||||
public function testPageAccess() {
|
||||
// Initially disable access grant records in
|
||||
// node_access_test_node_access_records().
|
||||
\Drupal::state()->set('node_access_test.private', TRUE);
|
||||
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Access the node form before moderation is enabled, the publication state
|
||||
// should now be visible.
|
||||
$this->drupalGet('node/add/moderated_content');
|
||||
$this->assertSession()->fieldExists('Published');
|
||||
|
||||
// Now enable the workflow.
|
||||
$this->enableModerationThroughUi('moderated_content', 'editorial');
|
||||
|
||||
// Access that the status field is no longer visible.
|
||||
$this->drupalGet('node/add/moderated_content');
|
||||
$this->assertSession()->fieldNotExists('Published');
|
||||
|
||||
// Create a node to test with.
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
$this->drupalPostForm(NULL, [
|
||||
'title[0][value]' => 'moderated content',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
$node = $this->getNodeByTitle('moderated content');
|
||||
if (!$node) {
|
||||
$this->fail('Test node was not saved correctly.');
|
||||
|
|
@ -91,7 +113,9 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
|
||||
// Publish the node.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalPostForm($edit_path, [], t('Save and Publish'));
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'moderation_state[0][state]' => 'published',
|
||||
], t('Save'));
|
||||
|
||||
// Ensure access works correctly for anonymous users.
|
||||
$this->drupalLogout();
|
||||
|
|
@ -104,11 +128,12 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
$this->drupalGet($view_path);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Create a forward revision for the 'Latest revision' tab.
|
||||
// Create a pending revision for the 'Latest revision' tab.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalPostForm($edit_path, [
|
||||
'title[0][value]' => 'moderated content revised',
|
||||
], t('Save and Create New Draft'));
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
], t('Save'));
|
||||
|
||||
$this->drupalLogin($user);
|
||||
|
||||
|
|
@ -120,7 +145,7 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
$this->drupalGet($view_path);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Now make another user, who should not be able to see forward revisions.
|
||||
// Now make another user, who should not be able to see pending revisions.
|
||||
$user = $this->createUser([
|
||||
'use editorial transition create_new_draft',
|
||||
]);
|
||||
|
|
@ -133,6 +158,30 @@ class NodeAccessTest extends ModerationStateTestBase {
|
|||
$this->assertResponse(403);
|
||||
$this->drupalGet($view_path);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Now create a private node that the user is not granted access to by the
|
||||
// node grants, but is granted access via hook_node_access().
|
||||
// @see node_access_test_node_access
|
||||
$node = $this->createNode([
|
||||
'type' => 'moderated_content',
|
||||
'private' => TRUE,
|
||||
'uid' => $this->adminUser->id(),
|
||||
]);
|
||||
$user = $this->createUser([
|
||||
'use editorial transition publish',
|
||||
]);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Grant access to the node via node_access_test_node_access().
|
||||
\Drupal::state()->set('node_access_test.allow_uid', $user->id());
|
||||
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Verify the moderation form is in place by publishing the node.
|
||||
$this->drupalPostForm(NULL, [], t('Apply'));
|
||||
$node = \Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($node->id());
|
||||
$this->assertEquals('published', $node->moderation_state->value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,315 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Functional;
|
||||
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* Tests the views 'moderation_state_filter' filter plugin.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\content_moderation\Plugin\views\filter\ModerationStateFilter
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ViewsModerationStateFilterTest extends ViewTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_moderation_test_views',
|
||||
'node',
|
||||
'content_moderation',
|
||||
'workflows',
|
||||
'workflow_type_test',
|
||||
'entity_test',
|
||||
'language',
|
||||
'content_translation',
|
||||
'views_ui',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp(FALSE);
|
||||
|
||||
NodeType::create([
|
||||
'type' => 'example_a',
|
||||
])->save();
|
||||
NodeType::create([
|
||||
'type' => 'example_b',
|
||||
])->save();
|
||||
|
||||
$this->createEditorialWorkflow();
|
||||
|
||||
$new_workflow = Workflow::create([
|
||||
'type' => 'content_moderation',
|
||||
'id' => 'new_workflow',
|
||||
'label' => 'New workflow',
|
||||
]);
|
||||
$new_workflow->getTypePlugin()->addState('bar', 'Bar');
|
||||
$new_workflow->save();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer workflows', 'administer views']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the dependency handling of the moderation state filter.
|
||||
*
|
||||
* @covers ::calculateDependencies
|
||||
* @covers ::onDependencyRemoval
|
||||
*/
|
||||
public function testModerationStateFilterDependencyHandling() {
|
||||
// First, check that the view doesn't have any config dependency when there
|
||||
// are no states configured in the filter.
|
||||
$view_id = 'test_content_moderation_state_filter_base_table';
|
||||
$view = Views::getView($view_id);
|
||||
|
||||
$this->assertWorkflowDependencies([], $view);
|
||||
$this->assertTrue($view->storage->status());
|
||||
|
||||
// Configure the Editorial workflow for a node bundle, set the filter value
|
||||
// to use one of its states and check that the workflow is now a dependency
|
||||
// of the view.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||
'bundles[example_a]' => TRUE,
|
||||
], 'Save');
|
||||
|
||||
$edit['options[value][]'] = ['editorial-published'];
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
|
||||
$view = Views::getView($view_id);
|
||||
$this->assertWorkflowDependencies(['editorial'], $view);
|
||||
$this->assertTrue($view->storage->status());
|
||||
|
||||
// Create another workflow and repeat the checks above.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/add', [
|
||||
'label' => 'Translation',
|
||||
'id' => 'translation',
|
||||
'workflow_type' => 'content_moderation',
|
||||
], 'Save');
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/translation/add_state', [
|
||||
'label' => 'Needs Review',
|
||||
'id' => 'needs_review',
|
||||
], 'Save');
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/translation/type/node', [
|
||||
'bundles[example_b]' => TRUE,
|
||||
], 'Save');
|
||||
|
||||
$edit['options[value][]'] = ['editorial-published', 'translation-needs_review'];
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
|
||||
$view = Views::getView($view_id);
|
||||
$this->assertWorkflowDependencies(['editorial', 'translation'], $view);
|
||||
$this->assertTrue(isset($view->storage->getDisplay('default')['display_options']['filters']['moderation_state']));
|
||||
$this->assertTrue($view->storage->status());
|
||||
|
||||
// Remove the 'Translation' workflow.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/translation/delete', [], 'Delete');
|
||||
|
||||
// Check that the view has been disabled, the filter has been deleted, the
|
||||
// view can be saved and there are no more config dependencies.
|
||||
$view = Views::getView($view_id);
|
||||
$this->assertFalse($view->storage->status());
|
||||
$this->assertFalse(isset($view->storage->getDisplay('default')['display_options']['filters']['moderation_state']));
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
$this->assertWorkflowDependencies([], $view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the moderation state filter when the configured workflow is changed.
|
||||
*
|
||||
* @dataProvider providerTestWorkflowChanges
|
||||
*/
|
||||
public function testWorkflowChanges($view_id, $filter_name) {
|
||||
// Update the view and make the default filter not exposed anymore,
|
||||
// otherwise all results will be shown when there are no more moderated
|
||||
// bundles left.
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", [], 'Hide filter');
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
|
||||
// First, apply the Editorial workflow to both of our content types.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||
'bundles[example_a]' => TRUE,
|
||||
'bundles[example_b]' => TRUE,
|
||||
], 'Save');
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
|
||||
// Add a few nodes in various moderation states.
|
||||
$this->createNode(['type' => 'example_a', 'moderation_state' => 'published']);
|
||||
$this->createNode(['type' => 'example_b', 'moderation_state' => 'published']);
|
||||
$archived_node_a = $this->createNode(['type' => 'example_a', 'moderation_state' => 'archived']);
|
||||
$archived_node_b = $this->createNode(['type' => 'example_b', 'moderation_state' => 'archived']);
|
||||
|
||||
// Configure the view to only show nodes in the 'archived' moderation state.
|
||||
$edit['options[value][]'] = ['editorial-archived'];
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
|
||||
// Check that only the archived nodes from both bundles are displayed by the
|
||||
// view.
|
||||
$view = Views::getView($view_id);
|
||||
$this->executeView($view);
|
||||
$this->assertIdenticalResultset($view, [['nid' => $archived_node_a->id()], ['nid' => $archived_node_b->id()]], ['nid' => 'nid']);
|
||||
|
||||
// Remove the Editorial workflow from one of the bundles.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||
'bundles[example_a]' => TRUE,
|
||||
'bundles[example_b]' => FALSE,
|
||||
], 'Save');
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
|
||||
$view = Views::getView($view_id);
|
||||
$this->executeView($view);
|
||||
$this->assertIdenticalResultset($view, [['nid' => $archived_node_a->id()]], ['nid' => 'nid']);
|
||||
|
||||
// Check that the view can still be edited and saved without any
|
||||
// intervention.
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
|
||||
// Remove the Editorial workflow from both bundles.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||
'bundles[example_a]' => FALSE,
|
||||
'bundles[example_b]' => FALSE,
|
||||
], 'Save');
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
|
||||
$view = Views::getView($view_id);
|
||||
$this->executeView($view);
|
||||
|
||||
// Check that the view doesn't return any result.
|
||||
$this->assertEmpty($view->result);
|
||||
|
||||
// Check that the view can not be edited without any intervention anymore
|
||||
// because the user needs to fix the filter.
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
$this->assertSession()->pageTextContains("No valid values found on filter: $filter_name.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testWorkflowChanges.
|
||||
*
|
||||
* @return string[]
|
||||
* An array of view IDs.
|
||||
*/
|
||||
public function providerTestWorkflowChanges() {
|
||||
return [
|
||||
'view on base table, filter on base table' => [
|
||||
'test_content_moderation_state_filter_base_table',
|
||||
'Content: Moderation state',
|
||||
],
|
||||
'view on base table, filter on revision table' => [
|
||||
'test_content_moderation_state_filter_base_table_filter_on_revision',
|
||||
'Content revision: Moderation state',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the content moderation state filter caching is correct.
|
||||
*/
|
||||
public function testFilterRenderCache() {
|
||||
// Initially all states of the workflow are displayed.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||
'bundles[example_a]' => TRUE,
|
||||
], 'Save');
|
||||
$this->assertFilterStates(['All', 'editorial-draft', 'editorial-published', 'editorial-archived']);
|
||||
|
||||
// Adding a new state to the editorial workflow will display that state in
|
||||
// the list of filters.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/add_state', [
|
||||
'label' => 'Foo',
|
||||
'id' => 'foo',
|
||||
], 'Save');
|
||||
$this->assertFilterStates(['All', 'editorial-draft', 'editorial-published', 'editorial-archived', 'editorial-foo']);
|
||||
|
||||
// Adding a second workflow to nodes will also show new states.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/new_workflow/type/node', [
|
||||
'bundles[example_b]' => TRUE,
|
||||
], 'Save');
|
||||
$this->assertFilterStates(['All', 'editorial-draft', 'editorial-published', 'editorial-archived', 'editorial-foo', 'new_workflow-draft', 'new_workflow-published', 'new_workflow-bar']);
|
||||
|
||||
// Add a few more states and change the exposed filter to allow multiple
|
||||
// selections so we can check that the size of the select element does not
|
||||
// exceed 8 options.
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/add_state', [
|
||||
'label' => 'Foo 2',
|
||||
'id' => 'foo2',
|
||||
], 'Save');
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/add_state', [
|
||||
'label' => 'Foo 3',
|
||||
'id' => 'foo3',
|
||||
], 'Save');
|
||||
|
||||
$view_id = 'test_content_moderation_state_filter_base_table';
|
||||
$edit['options[expose][multiple]'] = TRUE;
|
||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||
|
||||
$this->assertFilterStates(['editorial-draft', 'editorial-published', 'editorial-archived', 'editorial-foo', 'editorial-foo2', 'editorial-foo3', 'new_workflow-draft', 'new_workflow-published', 'new_workflow-bar'], TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert the states which appear in the filter.
|
||||
*
|
||||
* @param array $states
|
||||
* The states which should appear in the filter.
|
||||
* @param bool $check_size
|
||||
* (optional) Whether to check that size of the select element is not
|
||||
* greater than 8. Defaults to FALSE.
|
||||
*/
|
||||
protected function assertFilterStates($states, $check_size = FALSE) {
|
||||
$this->drupalGet('/filter-test-path');
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
// Check that the select contains the correct number of options.
|
||||
$assert_session->elementsCount('css', '#edit-default-revision-state option', count($states));
|
||||
|
||||
// Check that the size of the select element does not exceed 8 options.
|
||||
if ($check_size) {
|
||||
$this->assertGreaterThan(8, count($states));
|
||||
$assert_session->elementAttributeContains('css', '#edit-default-revision-state', 'size', 8);
|
||||
}
|
||||
|
||||
// Check that an option exists for each of the expected states.
|
||||
foreach ($states as $state) {
|
||||
$assert_session->optionExists('Default Revision State', $state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the views dependencies on workflow config entities.
|
||||
*
|
||||
* @param string[] $workflow_ids
|
||||
* An array of workflow IDs to check.
|
||||
* @param \Drupal\views\ViewExecutable $view
|
||||
* An executable View object.
|
||||
*/
|
||||
protected function assertWorkflowDependencies(array $workflow_ids, ViewExecutable $view) {
|
||||
$dependencies = $view->getDependencies();
|
||||
|
||||
$expected = [];
|
||||
foreach (Workflow::loadMultiple($workflow_ids) as $workflow) {
|
||||
$expected[] = $workflow->getConfigDependencyName();
|
||||
}
|
||||
|
||||
if ($expected) {
|
||||
$this->assertSame($expected, $dependencies['config']);
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(!isset($dependencies['config']));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -55,37 +55,13 @@ class ContentModerationPermissionsTest extends KernelTestBase {
|
|||
'id' => 'simple_workflow',
|
||||
'label' => 'Simple Workflow',
|
||||
'type' => 'content_moderation',
|
||||
'transitions' => [
|
||||
'publish' => [
|
||||
'label' => 'Publish',
|
||||
'from' => ['draft'],
|
||||
'to' => 'published',
|
||||
'weight' => 0,
|
||||
],
|
||||
'unpublish' => [
|
||||
'label' => 'Unpublish',
|
||||
'from' => ['published'],
|
||||
'to' => 'draft',
|
||||
'weight' => 0,
|
||||
],
|
||||
],
|
||||
'states' => [
|
||||
'draft' => [
|
||||
'label' => 'Draft',
|
||||
'weight' => -5,
|
||||
],
|
||||
'published' => [
|
||||
'label' => 'Published',
|
||||
'weight' => 0,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'use simple_workflow transition publish' => [
|
||||
'title' => 'Use <em class="placeholder">Publish</em> transition from <em class="placeholder">Simple Workflow</em> workflow.',
|
||||
'title' => '<em class="placeholder">Simple Workflow</em> workflow: Use <em class="placeholder">Publish</em> transition.',
|
||||
],
|
||||
'use simple_workflow transition unpublish' => [
|
||||
'title' => 'Use <em class="placeholder">Unpublish</em> transition from <em class="placeholder">Simple Workflow</em> workflow.',
|
||||
'use simple_workflow transition create_new_draft' => [
|
||||
'title' => '<em class="placeholder">Simple Workflow</em> workflow: Use <em class="placeholder">Create New Draft</em> transition.',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
|
@ -113,7 +89,7 @@ class ContentModerationPermissionsTest extends KernelTestBase {
|
|||
],
|
||||
],
|
||||
],
|
||||
[]
|
||||
[],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\rest\Entity\RestResourceConfig;
|
||||
use Drupal\rest\RestResourceConfigInterface;
|
||||
|
||||
/**
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ContentModerationStateResourceTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['serialization', 'rest', 'content_moderation'];
|
||||
|
||||
/**
|
||||
* @see \Drupal\content_moderation\Entity\ContentModerationState
|
||||
*/
|
||||
public function testCreateContentModerationStateResource() {
|
||||
$this->setExpectedException(PluginNotFoundException::class, 'The "entity:content_moderation_state" plugin does not exist.');
|
||||
RestResourceConfig::create([
|
||||
'id' => 'entity.content_moderation_state',
|
||||
'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
|
||||
'configuration' => [
|
||||
'methods' => ['GET'],
|
||||
'formats' => ['json'],
|
||||
'authentication' => ['cookie'],
|
||||
],
|
||||
])
|
||||
->enable()
|
||||
->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ use Drupal\content_moderation\Entity\ContentModerationState;
|
|||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Test the ContentModerationState storage schema.
|
||||
|
|
@ -16,6 +16,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class ContentModerationStateStorageSchemaTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -45,7 +47,7 @@ class ContentModerationStateStorageSchemaTest extends KernelTestBase {
|
|||
NodeType::create([
|
||||
'type' => 'example',
|
||||
])->save();
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,16 @@
|
|||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\content_moderation\Entity\ContentModerationState;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
use Drupal\entity_test\Entity\EntityTestBundle;
|
||||
use Drupal\entity_test\Entity\EntityTestWithBundle;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\entity_test\Entity\EntityTestRev;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
|
|
@ -21,13 +22,21 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class ContentModerationStateTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'entity_test',
|
||||
'node',
|
||||
'block',
|
||||
'block_content',
|
||||
'media',
|
||||
'media_test_source',
|
||||
'image',
|
||||
'file',
|
||||
'field',
|
||||
'content_moderation',
|
||||
'user',
|
||||
'system',
|
||||
|
|
@ -51,13 +60,16 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
$this->installSchema('node', 'node_access');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('entity_test_with_bundle');
|
||||
$this->installEntitySchema('entity_test_rev');
|
||||
$this->installEntitySchema('entity_test_no_bundle');
|
||||
$this->installEntitySchema('entity_test_mulrevpub');
|
||||
$this->installEntitySchema('block_content');
|
||||
$this->installEntitySchema('media');
|
||||
$this->installEntitySchema('file');
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installConfig('content_moderation');
|
||||
$this->installSchema('file', 'file_usage');
|
||||
$this->installConfig(['field', 'system', 'image', 'file', 'media']);
|
||||
|
||||
$this->entityTypeManager = $this->container->get('entity_type.manager');
|
||||
}
|
||||
|
|
@ -68,33 +80,7 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
* @dataProvider basicModerationTestCases
|
||||
*/
|
||||
public function testBasicModeration($entity_type_id) {
|
||||
// Make the 'entity_test_with_bundle' entity type revisionable.
|
||||
if ($entity_type_id == 'entity_test_with_bundle') {
|
||||
$this->setEntityTestWithBundleKeys(['revision' => 'revision_id']);
|
||||
}
|
||||
|
||||
$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||
$bundle_id = $entity_type_id;
|
||||
$bundle_entity_type_id = $this->entityTypeManager->getDefinition($entity_type_id)->getBundleEntityType();
|
||||
if ($bundle_entity_type_id) {
|
||||
$bundle_entity_type_definition = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
|
||||
$entity_type_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
|
||||
|
||||
$entity_type = $entity_type_storage->create([
|
||||
$bundle_entity_type_definition->getKey('id') => 'example',
|
||||
]);
|
||||
$entity_type->save();
|
||||
$bundle_id = $entity_type->id();
|
||||
}
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
|
||||
$workflow->save();
|
||||
|
||||
$entity = $entity_storage->create([
|
||||
'title' => 'Test title',
|
||||
$this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
|
||||
]);
|
||||
$entity = $this->createEntity($entity_type_id);
|
||||
if ($entity instanceof EntityPublishedInterface) {
|
||||
$entity->setUnpublished();
|
||||
}
|
||||
|
|
@ -145,6 +131,7 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
$entity->save();
|
||||
|
||||
// Revert to the previous (published) revision.
|
||||
$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||
$previous_revision = $entity_storage->loadRevision(4);
|
||||
$previous_revision->isDefaultRevision(TRUE);
|
||||
$previous_revision->setNewRevision(TRUE);
|
||||
|
|
@ -174,8 +161,8 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
'Block content' => [
|
||||
'block_content',
|
||||
],
|
||||
'Test Entity with Bundle' => [
|
||||
'entity_test_with_bundle',
|
||||
'Media' => [
|
||||
'media',
|
||||
],
|
||||
'Test entity - revisions, data table, and published interface' => [
|
||||
'entity_test_mulrevpub',
|
||||
|
|
@ -189,6 +176,97 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests removal of content moderation state entity.
|
||||
*
|
||||
* @dataProvider basicModerationTestCases
|
||||
*/
|
||||
public function testContentModerationStateDataRemoval($entity_type_id) {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->createEntity($entity_type_id);
|
||||
$entity->save();
|
||||
$entity = $this->reloadEntity($entity);
|
||||
$entity->delete();
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
|
||||
$this->assertFalse($content_moderation_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests removal of content moderation state entity revisions.
|
||||
*
|
||||
* @dataProvider basicModerationTestCases
|
||||
*/
|
||||
public function testContentModerationStateRevisionDataRemoval($entity_type_id) {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->createEntity($entity_type_id);
|
||||
$entity->save();
|
||||
$revision = clone $entity;
|
||||
$revision->isDefaultRevision(FALSE);
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
|
||||
$this->assertTrue($content_moderation_state);
|
||||
$entity = $this->reloadEntity($entity);
|
||||
$entity->setNewRevision(TRUE);
|
||||
$entity->save();
|
||||
$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||
$entity_storage->deleteRevision($revision->getRevisionId());
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
|
||||
$this->assertFalse($content_moderation_state);
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
|
||||
$this->assertTrue($content_moderation_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests removal of content moderation state pending entity revisions.
|
||||
*
|
||||
* @dataProvider basicModerationTestCases
|
||||
*/
|
||||
public function testContentModerationStatePendingRevisionDataRemoval($entity_type_id) {
|
||||
$entity = $this->createEntity($entity_type_id);
|
||||
$entity->moderation_state = 'published';
|
||||
$entity->save();
|
||||
$entity->setNewRevision(TRUE);
|
||||
$entity->moderation_state = 'draft';
|
||||
$entity->save();
|
||||
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
|
||||
$this->assertTrue($content_moderation_state);
|
||||
|
||||
$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||
$entity_storage->deleteRevision($entity->getRevisionId());
|
||||
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
|
||||
$this->assertFalse($content_moderation_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests removal of content moderation state translations.
|
||||
*
|
||||
* @dataProvider basicModerationTestCases
|
||||
*/
|
||||
public function testContentModerationStateTranslationDataRemoval($entity_type_id) {
|
||||
// Test content moderation state translation deletion.
|
||||
if ($this->entityTypeManager->getDefinition($entity_type_id)->isTranslatable()) {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->createEntity($entity_type_id);
|
||||
$langcode = 'it';
|
||||
ConfigurableLanguage::createFromLangcode($langcode)
|
||||
->save();
|
||||
$entity->save();
|
||||
$translation = $entity->addTranslation($langcode, ['title' => 'Titolo test']);
|
||||
// Make sure we add values for all of the required fields.
|
||||
if ($entity_type_id == 'block_content') {
|
||||
$translation->info = $this->randomString();
|
||||
}
|
||||
$translation->save();
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
|
||||
$this->assertTrue($content_moderation_state->hasTranslation($langcode));
|
||||
$entity->removeTranslation($langcode);
|
||||
$entity->save();
|
||||
$content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
|
||||
$this->assertFalse($content_moderation_state->hasTranslation($langcode));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests basic multilingual content moderation through the API.
|
||||
*/
|
||||
|
|
@ -200,7 +278,7 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
]);
|
||||
$node_type->save();
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
|
|
@ -305,38 +383,79 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
$this->assertEquals(6, $english_node->getRevisionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests moderation when the moderation_state field has a config override.
|
||||
*/
|
||||
public function testModerationWithFieldConfigOverride() {
|
||||
NodeType::create([
|
||||
'type' => 'test_type',
|
||||
])->save();
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'test_type');
|
||||
$workflow->save();
|
||||
|
||||
$fields = $this->container->get('entity_field.manager')->getFieldDefinitions('node', 'test_type');
|
||||
$field_config = $fields['moderation_state']->getConfig('test_type');
|
||||
$field_config->setLabel('Field Override!');
|
||||
$field_config->save();
|
||||
|
||||
$node = Node::create([
|
||||
'title' => 'Test node',
|
||||
'type' => 'test_type',
|
||||
]);
|
||||
$node->save();
|
||||
$this->assertFalse($node->isPublished());
|
||||
$this->assertEquals('draft', $node->moderation_state->value);
|
||||
|
||||
$node->moderation_state = 'published';
|
||||
$node->save();
|
||||
$this->assertTrue($node->isPublished());
|
||||
$this->assertEquals('published', $node->moderation_state->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that entities with special languages can be moderated.
|
||||
*/
|
||||
public function testModerationWithSpecialLanguages() {
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
|
||||
$workflow->save();
|
||||
|
||||
// Create a test entity.
|
||||
$entity = EntityTestRev::create([
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
]);
|
||||
$entity->save();
|
||||
$this->assertEquals('draft', $entity->moderation_state->value);
|
||||
|
||||
$entity->moderation_state->value = 'published';
|
||||
$entity->save();
|
||||
|
||||
$this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a non-translatable entity type with a langcode can be moderated.
|
||||
*/
|
||||
public function testNonTranslatableEntityTypeModeration() {
|
||||
// Make the 'entity_test_with_bundle' entity type revisionable.
|
||||
$this->setEntityTestWithBundleKeys(['revision' => 'revision_id']);
|
||||
|
||||
// Create a test bundle.
|
||||
$entity_test_bundle = EntityTestBundle::create([
|
||||
'id' => 'example',
|
||||
]);
|
||||
$entity_test_bundle->save();
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_with_bundle', 'example');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
|
||||
$workflow->save();
|
||||
|
||||
// Check that the tested entity type is not translatable.
|
||||
$entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_with_bundle');
|
||||
$entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
|
||||
$this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
|
||||
|
||||
// Create a test entity.
|
||||
$entity_test_with_bundle = EntityTestWithBundle::create([
|
||||
'type' => 'example'
|
||||
]);
|
||||
$entity_test_with_bundle->save();
|
||||
$this->assertEquals('draft', $entity_test_with_bundle->moderation_state->value);
|
||||
$entity = EntityTestRev::create();
|
||||
$entity->save();
|
||||
$this->assertEquals('draft', $entity->moderation_state->value);
|
||||
|
||||
$entity_test_with_bundle->moderation_state->value = 'published';
|
||||
$entity_test_with_bundle->save();
|
||||
$entity->moderation_state->value = 'published';
|
||||
$entity->save();
|
||||
|
||||
$this->assertEquals('published', EntityTestWithBundle::load($entity_test_with_bundle->id())->moderation_state->value);
|
||||
$this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -344,54 +463,35 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
* moderated.
|
||||
*/
|
||||
public function testNonLangcodeEntityTypeModeration() {
|
||||
// Make the 'entity_test_with_bundle' entity type revisionable and unset
|
||||
// the langcode entity key.
|
||||
$this->setEntityTestWithBundleKeys(['revision' => 'revision_id'], ['langcode']);
|
||||
// Unset the langcode entity key for 'entity_test_rev'.
|
||||
$entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
|
||||
$keys = $entity_type->getKeys();
|
||||
unset($keys['langcode']);
|
||||
$entity_type->set('entity_keys', $keys);
|
||||
\Drupal::state()->set('entity_test_rev.entity_type', $entity_type);
|
||||
|
||||
// Create a test bundle.
|
||||
$entity_test_bundle = EntityTestBundle::create([
|
||||
'id' => 'example',
|
||||
]);
|
||||
$entity_test_bundle->save();
|
||||
// Update the entity type in order to remove the 'langcode' field.
|
||||
\Drupal::entityDefinitionUpdateManager()->applyUpdates();
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_with_bundle', 'example');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
|
||||
$workflow->save();
|
||||
|
||||
// Check that the tested entity type is not translatable.
|
||||
$entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_with_bundle');
|
||||
// Check that the tested entity type is not translatable and does not have a
|
||||
// 'langcode' entity key.
|
||||
$entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
|
||||
$this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
|
||||
$this->assertFalse($entity_type->getKey('langcode'), "The test entity type does not have a 'langcode' entity key.");
|
||||
|
||||
// Create a test entity.
|
||||
$entity_test_with_bundle = EntityTestWithBundle::create([
|
||||
'type' => 'example'
|
||||
]);
|
||||
$entity_test_with_bundle->save();
|
||||
$this->assertEquals('draft', $entity_test_with_bundle->moderation_state->value);
|
||||
$entity = EntityTestRev::create();
|
||||
$entity->save();
|
||||
$this->assertEquals('draft', $entity->moderation_state->value);
|
||||
|
||||
$entity_test_with_bundle->moderation_state->value = 'published';
|
||||
$entity_test_with_bundle->save();
|
||||
$entity->moderation_state->value = 'published';
|
||||
$entity->save();
|
||||
|
||||
$this->assertEquals('published', EntityTestWithBundle::load($entity_test_with_bundle->id())->moderation_state->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the keys on the test entity type.
|
||||
*
|
||||
* @param array $keys
|
||||
* The entity keys to override
|
||||
* @param array $remove_keys
|
||||
* Keys to remove.
|
||||
*/
|
||||
protected function setEntityTestWithBundleKeys($keys, $remove_keys = []) {
|
||||
$entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_with_bundle');
|
||||
$original_keys = $entity_type->getKeys();
|
||||
foreach ($remove_keys as $remove_key) {
|
||||
unset($original_keys[$remove_key]);
|
||||
}
|
||||
$entity_type->set('entity_keys', $keys + $original_keys);
|
||||
\Drupal::state()->set('entity_test_with_bundle.entity_type', $entity_type);
|
||||
\Drupal::entityDefinitionUpdateManager()->applyUpdates();
|
||||
$this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -403,7 +503,7 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
]);
|
||||
$node_type->save();
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
// Test both a config and non-config based bundle and entity type.
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
|
||||
|
|
@ -423,7 +523,7 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
$this->assertEquals([
|
||||
'entity_test_no_bundle',
|
||||
'entity_test_rev',
|
||||
'node'
|
||||
'node',
|
||||
], $workflow->getTypePlugin()->getEntityTypes());
|
||||
|
||||
// Delete the node type and ensure it is removed from the workflow.
|
||||
|
|
@ -439,6 +539,140 @@ class ContentModerationStateTest extends KernelTestBase {
|
|||
$this->assertEquals([], $entity_types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the content moderation workflow dependencies for non-config bundles.
|
||||
*/
|
||||
public function testWorkflowNonConfigBundleDependencies() {
|
||||
// Create a bundle not based on any particular configuration.
|
||||
entity_test_create_bundle('test_bundle');
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test', 'test_bundle');
|
||||
$workflow->save();
|
||||
|
||||
// Ensure the bundle is correctly added to the workflow.
|
||||
$this->assertEquals([
|
||||
'module' => [
|
||||
'content_moderation',
|
||||
'entity_test',
|
||||
],
|
||||
], $workflow->getDependencies());
|
||||
$this->assertEquals([
|
||||
'test_bundle',
|
||||
], $workflow->getTypePlugin()->getBundlesForEntityType('entity_test'));
|
||||
|
||||
// Delete the test bundle to ensure the workflow entity responds
|
||||
// appropriately.
|
||||
entity_test_delete_bundle('test_bundle');
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$this->assertEquals([], $workflow->getTypePlugin()->getBundlesForEntityType('entity_test'));
|
||||
$this->assertEquals([
|
||||
'module' => [
|
||||
'content_moderation',
|
||||
],
|
||||
], $workflow->getDependencies());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the revision default state of the moderation state entity revisions.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The ID of entity type to be tested.
|
||||
*
|
||||
* @dataProvider basicModerationTestCases
|
||||
*/
|
||||
public function testRevisionDefaultState($entity_type_id) {
|
||||
// Check that the revision default state of the moderated entity and the
|
||||
// content moderation state entity always match.
|
||||
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
|
||||
$storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $cms_storage */
|
||||
$cms_storage = $this->entityTypeManager->getStorage('content_moderation_state');
|
||||
|
||||
$entity = $this->createEntity($entity_type_id);
|
||||
$entity->get('moderation_state')->value = 'published';
|
||||
$storage->save($entity);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
|
||||
$cms_entity = $cms_storage->loadUnchanged(1);
|
||||
$this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
|
||||
|
||||
$entity->get('moderation_state')->value = 'published';
|
||||
$storage->save($entity);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
|
||||
$cms_entity = $cms_storage->loadUnchanged(1);
|
||||
$this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
|
||||
|
||||
$entity->get('moderation_state')->value = 'draft';
|
||||
$storage->save($entity);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
|
||||
$cms_entity = $cms_storage->loadUnchanged(1);
|
||||
$this->assertEquals($entity->getLoadedRevisionId() - 1, $cms_entity->get('content_entity_revision_id')->value);
|
||||
|
||||
$entity->get('moderation_state')->value = 'published';
|
||||
$storage->save($entity);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
|
||||
$cms_entity = $cms_storage->loadUnchanged(1);
|
||||
$this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity.
|
||||
*
|
||||
* The entity will have required fields populated and the corresponding bundle
|
||||
* will be enabled for content moderation.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||
* The created entity.
|
||||
*/
|
||||
protected function createEntity($entity_type_id) {
|
||||
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
|
||||
|
||||
$bundle_id = $entity_type_id;
|
||||
// Set up a bundle entity type for the specified entity type, if needed.
|
||||
if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) {
|
||||
$bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
|
||||
$bundle_entity_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
|
||||
|
||||
$bundle_id = 'example';
|
||||
if (!$bundle_entity_storage->load($bundle_id)) {
|
||||
$bundle_entity = $bundle_entity_storage->create([
|
||||
$bundle_entity_type->getKey('id') => 'example',
|
||||
]);
|
||||
if ($entity_type_id == 'media') {
|
||||
$bundle_entity->set('source', 'test');
|
||||
$bundle_entity->save();
|
||||
$source_field = $bundle_entity->getSource()->createSourceField($bundle_entity);
|
||||
$source_field->getFieldStorageDefinition()->save();
|
||||
$source_field->save();
|
||||
$bundle_entity->set('source_configuration', [
|
||||
'source_field' => $source_field->getName(),
|
||||
]);
|
||||
}
|
||||
$bundle_entity->save();
|
||||
}
|
||||
}
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
|
||||
$workflow->save();
|
||||
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||
$entity = $entity_storage->create([
|
||||
$entity_type->getKey('label') => 'Test title',
|
||||
$entity_type->getKey('bundle') => $bundle_id,
|
||||
]);
|
||||
// Make sure we add values for all of the required fields.
|
||||
if ($entity_type_id == 'block_content') {
|
||||
$entity->info = $this->randomString();
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the entity after clearing the static cache.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\Core\Config\ConfigImporterException;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Tests how Content Moderation handles workflow config changes.
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ContentModerationWorkflowConfigTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'node',
|
||||
'content_moderation',
|
||||
'user',
|
||||
'system',
|
||||
'text',
|
||||
'workflows',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityTypeManager
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* @var \Drupal\workflows\Entity\Workflow
|
||||
*/
|
||||
protected $workflow;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Config\Entity\ConfigEntityStorage
|
||||
*/
|
||||
protected $workflowStorage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installSchema('node', 'node_access');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installConfig(['system', 'content_moderation']);
|
||||
|
||||
NodeType::create([
|
||||
'type' => 'example',
|
||||
])->save();
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()
|
||||
->addState('test1', 'Test one')
|
||||
->addState('test2', 'Test two')
|
||||
->addState('test3', 'Test three')
|
||||
->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
$this->workflow = $workflow;
|
||||
|
||||
$this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleting a state via config import.
|
||||
*/
|
||||
public function testDeletingStateViaConfiguration() {
|
||||
$config_sync = \Drupal::service('config.storage.sync');
|
||||
|
||||
// Alter the workflow data.
|
||||
$config_data = $this->config('workflows.workflow.editorial')->get();
|
||||
unset($config_data['type_settings']['states']['test1']);
|
||||
$config_sync->write('workflows.workflow.editorial', $config_data);
|
||||
|
||||
// Alter the data of another entity type.
|
||||
$config_data = $this->config('node.type.example')->get();
|
||||
$config_data['description'] = 'A new description';
|
||||
$config_sync->write('node.type.example', $config_data);
|
||||
|
||||
// Alter the values of simple config.
|
||||
$config_data = $this->config('core.extension')->get();
|
||||
$config_data['module']['node'] = 1;
|
||||
$config_sync->write('core.extension', $config_data);
|
||||
|
||||
// There are no Nodes with the moderation state test1, so this should run
|
||||
// with no errors.
|
||||
$this->configImporter()->reset()->import();
|
||||
|
||||
$node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Test title',
|
||||
'moderation_state' => 'test2',
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
$config_data = $this->config('workflows.workflow.editorial')->get();
|
||||
unset($config_data['type_settings']['states']['test2']);
|
||||
unset($config_data['type_settings']['states']['test3']);
|
||||
\Drupal::service('config.storage.sync')->write('workflows.workflow.editorial', $config_data);
|
||||
|
||||
// Now there is a Node with the moderation state test2, this will fail.
|
||||
try {
|
||||
$this->configImporter()->reset()->import();
|
||||
$this->fail('ConfigImporterException not thrown, invalid import was not stopped due to deleted state.');
|
||||
}
|
||||
catch (ConfigImporterException $e) {
|
||||
$this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.' . PHP_EOL . 'The moderation state Test two is being used, but is not in the source storage.');
|
||||
$error_log = $this->configImporter->getErrors();
|
||||
$expected = ['The moderation state Test two is being used, but is not in the source storage.'];
|
||||
$this->assertEqual($expected, $error_log);
|
||||
}
|
||||
|
||||
\Drupal::service('config.storage.sync')->delete('workflows.workflow.editorial');
|
||||
|
||||
// An error should be thrown when trying to delete an in use workflow.
|
||||
try {
|
||||
$this->configImporter()->reset()->import();
|
||||
$this->fail('ConfigImporterException not thrown, invalid import was not stopped due to deleted workflow.');
|
||||
}
|
||||
catch (ConfigImporterException $e) {
|
||||
$this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.' . PHP_EOL . 'The moderation state Test two is being used, but is not in the source storage.' . PHP_EOL . 'The workflow Editorial is being used, and cannot be deleted.');
|
||||
$error_log = $this->configImporter->getErrors();
|
||||
$expected = [
|
||||
'The moderation state Test two is being used, but is not in the source storage.',
|
||||
'The workflow Editorial is being used, and cannot be deleted.',
|
||||
];
|
||||
$this->assertEqual($expected, $error_log);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ class ContentModerationWorkflowTypeApiTest extends KernelTestBase {
|
|||
/**
|
||||
* A workflow for testing.
|
||||
*
|
||||
* @var \Drupal\workflows\Entity\Workflow;
|
||||
* @var \Drupal\workflows\Entity\Workflow
|
||||
*/
|
||||
protected $workflow;
|
||||
|
||||
|
|
@ -37,9 +37,6 @@ class ContentModerationWorkflowTypeApiTest extends KernelTestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->workflow = Workflow::create(['id' => 'test', 'type' => 'content_moderation']);
|
||||
$this->workflow
|
||||
->addState('draft', 'Draft')
|
||||
->addState('published', 'Published');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -101,4 +98,26 @@ class ContentModerationWorkflowTypeApiTest extends KernelTestBase {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::addEntityTypeAndBundle
|
||||
* @covers ::removeEntityTypeAndBundle
|
||||
*/
|
||||
public function testRemoveEntityTypeAndBundle() {
|
||||
/** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration $workflow_plugin */
|
||||
$workflow_plugin = $this->workflow->getTypePlugin();
|
||||
|
||||
// There should be no bundles for fake_node to start with.
|
||||
$this->assertEquals([], $workflow_plugin->getBundlesForEntityType('fake_node'));
|
||||
// Removing a bundle which is not set on the workflow should not throw an
|
||||
// error and should still result in none being returned.
|
||||
$workflow_plugin->removeEntityTypeAndBundle('fake_node', 'fake_page');
|
||||
$this->assertEquals([], $workflow_plugin->getBundlesForEntityType('fake_node'));
|
||||
// Adding a bundle for fake_node should result it in being returned, but
|
||||
// then removing it will return no bundles for fake_node.
|
||||
$workflow_plugin->addEntityTypeAndBundle('fake_node', 'fake_page');
|
||||
$this->assertEquals(['fake_page'], $workflow_plugin->getBundlesForEntityType('fake_node'));
|
||||
$workflow_plugin->removeEntityTypeAndBundle('fake_node', 'fake_page');
|
||||
$this->assertEquals([], $workflow_plugin->getBundlesForEntityType('fake_node'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use Drupal\KernelTests\KernelTestBase;
|
|||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the correct default revision is set.
|
||||
|
|
@ -15,6 +15,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class DefaultRevisionStateTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -68,7 +70,7 @@ class DefaultRevisionStateTest extends KernelTestBase {
|
|||
|
||||
$this->container->get('content_translation.manager')->setEnabled('node', 'example', TRUE);
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
|
|
@ -83,6 +85,7 @@ class DefaultRevisionStateTest extends KernelTestBase {
|
|||
$this->assertEquals('draft', $english_node->moderation_state->value);
|
||||
$this->assertFalse($english_node->isPublished());
|
||||
$this->assertTrue($english_node->isDefaultRevision());
|
||||
$this->assertModerationState($english_node->getRevisionId(), $english_node->language()->getId(), 'draft');
|
||||
|
||||
// Revision 2 (fr)
|
||||
$french_node = $english_node->addTranslation('fr', ['title' => 'French title']);
|
||||
|
|
@ -90,6 +93,7 @@ class DefaultRevisionStateTest extends KernelTestBase {
|
|||
$french_node->save();
|
||||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertTrue($french_node->isDefaultRevision());
|
||||
$this->assertModerationState($french_node->getRevisionId(), $french_node->language()->getId(), 'published');
|
||||
|
||||
// Revision 3 (fr)
|
||||
$node = Node::load($english_node->id())->getTranslation('fr');
|
||||
|
|
@ -97,6 +101,7 @@ class DefaultRevisionStateTest extends KernelTestBase {
|
|||
$node->save();
|
||||
$this->assertFalse($node->isPublished());
|
||||
$this->assertFalse($node->isDefaultRevision());
|
||||
$this->assertModerationState($node->getRevisionId(), $node->language()->getId(), 'draft');
|
||||
|
||||
// Revision 4 (en)
|
||||
$latest_revision = $this->entityTypeManager->getStorage('node')->loadRevision(3);
|
||||
|
|
@ -104,6 +109,36 @@ class DefaultRevisionStateTest extends KernelTestBase {
|
|||
$latest_revision->save();
|
||||
$this->assertFalse($latest_revision->isPublished());
|
||||
$this->assertFalse($latest_revision->isDefaultRevision());
|
||||
$this->assertModerationState($latest_revision->getRevisionId(), $latest_revision->language()->getId(), 'draft');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the expected moderation state revision exists.
|
||||
*
|
||||
* @param int $revision_id
|
||||
* The revision ID of the host entity.
|
||||
* @param string $langcode
|
||||
* The language code of the host entity to check.
|
||||
* @param string $expected_state
|
||||
* The state the content moderation state revision should be in.
|
||||
* @param string $expected_workflow
|
||||
* The workflow the content moderation state revision should be using.
|
||||
*/
|
||||
protected function assertModerationState($revision_id, $langcode, $expected_state, $expected_workflow = 'editorial') {
|
||||
$moderation_state_storage = $this->entityTypeManager->getStorage('content_moderation_state');
|
||||
|
||||
$query = $moderation_state_storage->getQuery();
|
||||
$results = $query->allRevisions()
|
||||
->condition('content_entity_revision_id', $revision_id)
|
||||
->condition('langcode', $langcode)
|
||||
->execute();
|
||||
$this->assertCount(1, $results);
|
||||
|
||||
$moderation_state = $moderation_state_storage
|
||||
->loadRevision(key($results))
|
||||
->getTranslation($langcode);
|
||||
$this->assertEquals($expected_state, $moderation_state->get('moderation_state')->value);
|
||||
$this->assertEquals($expected_workflow, $moderation_state->get('workflow')->target_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\EntityOperations
|
||||
|
|
@ -15,6 +14,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class EntityOperationsTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -49,15 +50,15 @@ class EntityOperationsTest extends KernelTestBase {
|
|||
'label' => 'Page',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
|
||||
$workflow->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the process of saving forward-revisions works as expected.
|
||||
* Verifies that the process of saving pending revisions works as expected.
|
||||
*/
|
||||
public function testForwardRevisions() {
|
||||
public function testPendingRevisions() {
|
||||
// Create a new node in draft.
|
||||
$page = Node::create([
|
||||
'type' => 'page',
|
||||
|
|
@ -68,9 +69,9 @@ class EntityOperationsTest extends KernelTestBase {
|
|||
|
||||
$id = $page->id();
|
||||
|
||||
// Verify the entity saved correctly, and that the presence of forward
|
||||
// Verify the entity saved correctly, and that the presence of pending
|
||||
// revisions doesn't affect the default node load.
|
||||
/** @var Node $page */
|
||||
/** @var \Drupal\node\Entity\Node $page */
|
||||
$page = Node::load($id);
|
||||
$this->assertEquals('A', $page->getTitle());
|
||||
$this->assertTrue($page->isDefaultRevision());
|
||||
|
|
@ -87,7 +88,7 @@ class EntityOperationsTest extends KernelTestBase {
|
|||
$this->assertTrue($page->isDefaultRevision());
|
||||
$this->assertTrue($page->isPublished());
|
||||
|
||||
// Make a new forward-revision in Draft.
|
||||
// Make a new pending revision in Draft.
|
||||
$page->setTitle('C');
|
||||
$page->moderation_state->value = 'draft';
|
||||
$page->save();
|
||||
|
|
@ -96,7 +97,7 @@ class EntityOperationsTest extends KernelTestBase {
|
|||
$page = Node::load($id);
|
||||
$this->assertEquals('B', $page->getTitle());
|
||||
|
||||
// Verify we can load the forward revision, even if the mechanism is kind
|
||||
// Verify we can load the pending revision, even if the mechanism is kind
|
||||
// of gross. Note: revisionIds() is only available on NodeStorageInterface,
|
||||
// so this won't work for non-nodes. We'd need to use entity queries. This
|
||||
// is a core bug that should get fixed.
|
||||
|
|
@ -143,7 +144,7 @@ class EntityOperationsTest extends KernelTestBase {
|
|||
$id = $page->id();
|
||||
|
||||
// Verify the entity saved correctly.
|
||||
/** @var Node $page */
|
||||
/** @var \Drupal\node\Entity\Node $page */
|
||||
$page = Node::load($id);
|
||||
$this->assertEquals('A', $page->getTitle());
|
||||
$this->assertTrue($page->isDefaultRevision());
|
||||
|
|
|
|||
|
|
@ -2,21 +2,22 @@
|
|||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\ParamConverter\EntityRevisionConverter
|
||||
* @group content_moderation
|
||||
* @group legacy
|
||||
*/
|
||||
class EntityRevisionConverterTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'user',
|
||||
'entity_test',
|
||||
'system',
|
||||
'content_moderation',
|
||||
'node',
|
||||
|
|
@ -28,74 +29,36 @@ class EntityRevisionConverterTest extends KernelTestBase {
|
|||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('entity_test');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installSchema('system', 'router');
|
||||
$this->installSchema('system', 'sequences');
|
||||
$this->installSchema('node', 'node_access');
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::convert
|
||||
* @expectedDeprecationMessage The load_pending_revision flag has been deprecated. You should use load_latest_revision instead.
|
||||
*/
|
||||
public function testConvertNonRevisionableEntityType() {
|
||||
$entity_test = EntityTest::create([
|
||||
'name' => 'test',
|
||||
]);
|
||||
|
||||
$entity_test->save();
|
||||
|
||||
/** @var \Symfony\Component\Routing\RouterInterface $router */
|
||||
$router = \Drupal::service('router.no_access_checks');
|
||||
$result = $router->match('/entity_test/' . $entity_test->id());
|
||||
|
||||
$this->assertInstanceOf(EntityTest::class, $result['entity_test']);
|
||||
$this->assertEquals($entity_test->getRevisionId(), $result['entity_test']->getRevisionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::convert
|
||||
*/
|
||||
public function testConvertWithRevisionableEntityType() {
|
||||
$this->installConfig(['content_moderation']);
|
||||
$node_type = NodeType::create([
|
||||
public function testDeprecatedLoadPendingRevisionFlag() {
|
||||
NodeType::create([
|
||||
'type' => 'article',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'article');
|
||||
$workflow->save();
|
||||
])->save();
|
||||
|
||||
$revision_ids = [];
|
||||
$node = Node::create([
|
||||
'title' => 'test',
|
||||
'type' => 'article',
|
||||
]);
|
||||
$node->moderation_state->value = 'published';
|
||||
$node->save();
|
||||
|
||||
$revision_ids[] = $node->getRevisionId();
|
||||
|
||||
$node->isDefaultRevision(FALSE);
|
||||
$node->setNewRevision(TRUE);
|
||||
$node->save();
|
||||
$revision_ids[] = $node->getRevisionId();
|
||||
|
||||
$node->setNewRevision(TRUE);
|
||||
$node->moderation_state->value = 'draft';
|
||||
$node->save();
|
||||
$revision_ids[] = $node->getRevisionId();
|
||||
|
||||
/** @var \Symfony\Component\Routing\RouterInterface $router */
|
||||
$router = \Drupal::service('router.no_access_checks');
|
||||
$result = $router->match('/node/' . $node->id() . '/edit');
|
||||
|
||||
$this->assertInstanceOf(Node::class, $result['node']);
|
||||
$this->assertEquals($revision_ids[2], $result['node']->getRevisionId());
|
||||
$this->assertFalse($result['node']->isDefaultRevision());
|
||||
$converted = $this->container->get('paramconverter.latest_revision')->convert($node->id(), [
|
||||
'load_pending_revision' => TRUE,
|
||||
'type' => 'entity:node',
|
||||
], 'node', []);
|
||||
$this->assertEquals($converted->getLoadedRevisionId(), $node->getLoadedRevisionId());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ use Drupal\KernelTests\KernelTestBase;
|
|||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\Tests\user\Traits\UserCreationTrait;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\Plugin\Validation\Constraint\ModerationStateConstraintValidator
|
||||
|
|
@ -14,6 +15,9 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class EntityStateChangeValidationTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
use UserCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -27,6 +31,13 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
'workflows',
|
||||
];
|
||||
|
||||
/**
|
||||
* An admin user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -38,6 +49,9 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installConfig('content_moderation');
|
||||
$this->installSchema('system', ['sequences']);
|
||||
|
||||
$this->adminUser = $this->createUser(array_keys($this->container->get('user.permissions')->getPermissions()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,11 +60,13 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
* @covers ::validate
|
||||
*/
|
||||
public function testValidTransition() {
|
||||
$this->setCurrentUser($this->adminUser);
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
|
|
@ -74,11 +90,13 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
* @covers ::validate
|
||||
*/
|
||||
public function testInvalidTransition() {
|
||||
$this->setCurrentUser($this->adminUser);
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
|
|
@ -96,10 +114,140 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
$this->assertEquals('Invalid state transition from <em class="placeholder">Draft</em> to <em class="placeholder">Archived</em>', $violations->get(0)->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation with an invalid state.
|
||||
*/
|
||||
public function testInvalidState() {
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
$node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Test title',
|
||||
]);
|
||||
$node->moderation_state->value = 'invalid_state';
|
||||
$violations = $node->validate();
|
||||
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals('State <em class="placeholder">invalid_state</em> does not exist on <em class="placeholder">Editorial</em> workflow', $violations->get(0)->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation with content that has no initial state or an invalid state.
|
||||
*/
|
||||
public function testInvalidStateWithoutExisting() {
|
||||
$this->setCurrentUser($this->adminUser);
|
||||
// Create content without moderation enabled for the content type.
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
$node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Test title',
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
// Enable moderation to test validation on existing content, with no
|
||||
// explicit state.
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addState('deleted_state', 'Deleted state');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
// Validate the invalid state.
|
||||
$node->moderation_state->value = 'invalid_state';
|
||||
$violations = $node->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
|
||||
// Assign the node to a state we're going to delete.
|
||||
$node->moderation_state->value = 'deleted_state';
|
||||
$node->save();
|
||||
|
||||
// Delete the state so $node->original contains an invalid state when
|
||||
// validating.
|
||||
$workflow->getTypePlugin()->deleteState('deleted_state');
|
||||
$workflow->save();
|
||||
|
||||
// When there is an invalid state, the content will revert to "draft". This
|
||||
// will allow a draft to draft transition.
|
||||
$node->moderation_state->value = 'draft';
|
||||
$violations = $node->validate();
|
||||
$this->assertCount(0, $violations);
|
||||
// This will disallow a draft to archived transition.
|
||||
$node->moderation_state->value = 'archived';
|
||||
$violations = $node->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test state transition validation with multiple languages.
|
||||
*/
|
||||
public function testInvalidStateMultilingual() {
|
||||
$this->setCurrentUser($this->adminUser);
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
$node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'English Published Node',
|
||||
'langcode' => 'en',
|
||||
'moderation_state' => 'published',
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
$node_fr = $node->addTranslation('fr', $node->toArray());
|
||||
$node_fr->setTitle('French Published Node');
|
||||
$node_fr->save();
|
||||
$this->assertEquals('published', $node_fr->moderation_state->value);
|
||||
|
||||
// Create a pending revision of the original node.
|
||||
$node->moderation_state = 'draft';
|
||||
$node->setNewRevision(TRUE);
|
||||
$node->isDefaultRevision(FALSE);
|
||||
$node->save();
|
||||
|
||||
// For the pending english revision, there should be a violation from draft
|
||||
// to archived.
|
||||
$node->moderation_state = 'archived';
|
||||
$violations = $node->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals('Invalid state transition from <em class="placeholder">Draft</em> to <em class="placeholder">Archived</em>', $violations->get(0)->getMessage());
|
||||
|
||||
// From the default french published revision, there should be none.
|
||||
$node_fr = Node::load($node->id())->getTranslation('fr');
|
||||
$this->assertEquals('published', $node_fr->moderation_state->value);
|
||||
$node_fr->moderation_state = 'archived';
|
||||
$violations = $node_fr->validate();
|
||||
$this->assertCount(0, $violations);
|
||||
|
||||
// From the latest french revision, there should also be no violation.
|
||||
$node_fr = Node::load($node->id())->getTranslation('fr');
|
||||
$this->assertEquals('published', $node_fr->moderation_state->value);
|
||||
$node_fr->moderation_state = 'archived';
|
||||
$violations = $node_fr->validate();
|
||||
$this->assertCount(0, $violations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that content without prior moderation information can be moderated.
|
||||
*/
|
||||
public function testLegacyContent() {
|
||||
public function testExistingContentWithNoModeration() {
|
||||
$this->setCurrentUser($this->adminUser);
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
|
|
@ -114,7 +262,7 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
$nid = $node->id();
|
||||
|
||||
// Enable moderation for our node type.
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
|
|
@ -133,7 +281,9 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
/**
|
||||
* Tests that content without prior moderation information can be translated.
|
||||
*/
|
||||
public function testLegacyMultilingualContent() {
|
||||
public function testExistingMultilingualContentWithNoModeration() {
|
||||
$this->setCurrentUser($this->adminUser);
|
||||
|
||||
// Enable French.
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
|
||||
|
|
@ -160,7 +310,7 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
$node_fr->save();
|
||||
|
||||
// Enable moderation for our node type.
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
|
|
@ -173,4 +323,81 @@ class EntityStateChangeValidationTest extends KernelTestBase {
|
|||
$node_fr->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider transitionAccessValidationTestCases
|
||||
*/
|
||||
public function testTransitionAccessValidation($permissions, $target_state, $messages) {
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addState('foo', 'Foo');
|
||||
$workflow->getTypePlugin()->addTransition('draft_to_foo', 'Draft to foo', ['draft'], 'foo');
|
||||
$workflow->getTypePlugin()->addTransition('foo_to_foo', 'Foo to foo', ['foo'], 'foo');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
$this->setCurrentUser($this->createUser($permissions));
|
||||
|
||||
$node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Test content',
|
||||
'moderation_state' => $target_state,
|
||||
]);
|
||||
$this->assertTrue($node->isNew());
|
||||
$violations = $node->validate();
|
||||
$this->assertCount(count($messages), $violations);
|
||||
foreach ($messages as $i => $message) {
|
||||
$this->assertEquals($message, $violations->get($i)->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cases for ::testTransitionAccessValidation.
|
||||
*/
|
||||
public function transitionAccessValidationTestCases() {
|
||||
return [
|
||||
'Invalid transition, no permissions validated' => [
|
||||
[],
|
||||
'archived',
|
||||
['Invalid state transition from <em class="placeholder">Draft</em> to <em class="placeholder">Archived</em>'],
|
||||
],
|
||||
'Valid transition, missing permission' => [
|
||||
[],
|
||||
'published',
|
||||
['You do not have access to transition from <em class="placeholder">Draft</em> to <em class="placeholder">Published</em>'],
|
||||
],
|
||||
'Valid transition, granted published permission' => [
|
||||
['use editorial transition publish'],
|
||||
'published',
|
||||
[],
|
||||
],
|
||||
'Valid transition, granted draft permission' => [
|
||||
['use editorial transition create_new_draft'],
|
||||
'draft',
|
||||
[],
|
||||
],
|
||||
'Valid transition, incorrect permission granted' => [
|
||||
['use editorial transition create_new_draft'],
|
||||
'published',
|
||||
['You do not have access to transition from <em class="placeholder">Draft</em> to <em class="placeholder">Published</em>'],
|
||||
],
|
||||
// Test with an additional state and set of transitions, since the
|
||||
// "published" transition can start from either "draft" or "published", it
|
||||
// does not capture bugs that fail to correctly distinguish the initial
|
||||
// workflow state from the set state of a new entity.
|
||||
'Valid transition, granted foo permission' => [
|
||||
['use editorial transition draft_to_foo'],
|
||||
'foo',
|
||||
[],
|
||||
],
|
||||
'Valid transition, incorrect foo permission granted' => [
|
||||
['use editorial transition foo_to_foo'],
|
||||
'foo',
|
||||
['You do not have access to transition from <em class="placeholder">Draft</em> to <em class="placeholder">Foo</em>'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ class EntityTypeInfoTest extends KernelTestBase {
|
|||
*/
|
||||
public static $modules = [
|
||||
'content_moderation',
|
||||
'workflows',
|
||||
'entity_test',
|
||||
];
|
||||
|
||||
|
|
@ -60,4 +61,34 @@ class EntityTypeInfoTest extends KernelTestBase {
|
|||
$this->assertTrue($base_fields['moderation_state']->isTranslatable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the correct entity types have moderation added.
|
||||
*
|
||||
* @covers ::entityTypeAlter
|
||||
*
|
||||
* @dataProvider providerTestEntityTypeAlter
|
||||
*/
|
||||
public function testEntityTypeAlter($entity_type_id, $moderatable) {
|
||||
$entity_types = $this->entityTypeManager->getDefinitions();
|
||||
$this->assertSame($moderatable, $entity_types[$entity_type_id]->hasHandlerClass('moderation'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for testEntityTypeAlter().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases, where each test case is an array with the
|
||||
* following values:
|
||||
* - An entity type ID.
|
||||
* - Whether the entity type is moderatable or not.
|
||||
*/
|
||||
public function providerTestEntityTypeAlter() {
|
||||
$tests = [];
|
||||
$tests['non_internal_non_revisionable'] = ['entity_test', FALSE];
|
||||
$tests['non_internal_revisionable'] = ['entity_test_rev', TRUE];
|
||||
$tests['internal_non_revisionable'] = ['entity_test_no_label', FALSE];
|
||||
$tests['internal_revisionable'] = ['content_moderation_state', FALSE];
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use Drupal\entity_test\Entity\EntityTestRev;
|
|||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the correct initial states are set on install.
|
||||
|
|
@ -15,6 +15,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class InitialStateTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -66,7 +68,7 @@ class InitialStateTest extends KernelTestBase {
|
|||
$entity_test->save();
|
||||
|
||||
\Drupal::service('module_installer')->install(['content_moderation'], TRUE);
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
|
||||
$workflow->save();
|
||||
|
|
@ -77,6 +79,12 @@ class InitialStateTest extends KernelTestBase {
|
|||
$this->assertEquals('draft', $loaded_unpublished_node->moderation_state->value);
|
||||
$this->assertEquals('published', $loaded_published_node->moderation_state->value);
|
||||
$this->assertEquals('draft', $loaded_entity_test->moderation_state->value);
|
||||
|
||||
$presave_node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Presave node',
|
||||
]);
|
||||
$this->assertEquals('draft', $presave_node->moderation_state->value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestMulRevPub;
|
||||
use Drupal\entity_test\Entity\EntityTestRev;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\ModerationInformation
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ModerationInformationTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_moderation',
|
||||
'entity_test',
|
||||
'user',
|
||||
'workflows',
|
||||
'language',
|
||||
'content_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* The moderation information service.
|
||||
*
|
||||
* @var \Drupal\content_moderation\ModerationInformationInterface
|
||||
*/
|
||||
protected $moderationInformation;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('entity_test_rev');
|
||||
$this->installEntitySchema('entity_test_mulrevpub');
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installConfig(['content_moderation']);
|
||||
|
||||
$this->moderationInformation = $this->container->get('content_moderation.moderation_information');
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('de')->save();
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_mulrevpub', 'entity_test_mulrevpub');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
|
||||
$workflow->save();
|
||||
|
||||
$this->container->get('content_translation.manager')->setEnabled('entity_test_mulrevpub', 'entity_test_mulrevpub', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getDefaultRevisionId
|
||||
* @covers ::getLatestRevisionId
|
||||
*/
|
||||
public function testDefaultAndLatestRevisionId() {
|
||||
$entity_test_rev = EntityTestRev::create([
|
||||
'name' => 'Default Revision',
|
||||
'moderation_state' => 'published',
|
||||
]);
|
||||
$entity_test_rev->save();
|
||||
|
||||
$entity_test_rev->name = 'Pending revision';
|
||||
$entity_test_rev->moderation_state = 'draft';
|
||||
$entity_test_rev->save();
|
||||
|
||||
// Check that moderation information service returns the correct default
|
||||
// revision ID.
|
||||
$default_revision_id = $this->moderationInformation->getDefaultRevisionId('entity_test_rev', $entity_test_rev->id());
|
||||
$this->assertSame(1, $default_revision_id);
|
||||
|
||||
// Check that moderation information service returns the correct latest
|
||||
// revision ID.
|
||||
$latest_revision_id = $this->moderationInformation->getLatestRevisionId('entity_test_rev', $entity_test_rev->id());
|
||||
$this->assertSame(2, $latest_revision_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isDefaultRevisionPublished
|
||||
* @dataProvider isDefaultRevisionPublishedTestCases
|
||||
*/
|
||||
public function testIsDefaultRevisionPublished($initial_state, $final_state, $initial_is_default_published, $final_is_default_published) {
|
||||
$entity = EntityTestMulRevPub::create([
|
||||
'moderation_state' => $initial_state,
|
||||
]);
|
||||
$entity->save();
|
||||
$this->assertEquals($initial_is_default_published, $this->moderationInformation->isDefaultRevisionPublished($entity));
|
||||
|
||||
$entity->moderation_state = $final_state;
|
||||
$entity->save();
|
||||
$this->assertEquals($final_is_default_published, $this->moderationInformation->isDefaultRevisionPublished($entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cases for ::testIsDefaultRevisionPublished.
|
||||
*/
|
||||
public function isDefaultRevisionPublishedTestCases() {
|
||||
return [
|
||||
'Draft to draft' => [
|
||||
'draft',
|
||||
'draft',
|
||||
FALSE,
|
||||
FALSE,
|
||||
],
|
||||
'Draft to published' => [
|
||||
'draft',
|
||||
'published',
|
||||
FALSE,
|
||||
TRUE,
|
||||
],
|
||||
'Published to published' => [
|
||||
'published',
|
||||
'published',
|
||||
TRUE,
|
||||
TRUE,
|
||||
],
|
||||
'Published to draft' => [
|
||||
'published',
|
||||
'draft',
|
||||
TRUE,
|
||||
TRUE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isDefaultRevisionPublished
|
||||
*/
|
||||
public function testIsDefaultRevisionPublishedMultilingual() {
|
||||
$entity = EntityTestMulRevPub::create([
|
||||
'moderation_state' => 'draft',
|
||||
]);
|
||||
$entity->save();
|
||||
$this->assertEquals('draft', $entity->moderation_state->value);
|
||||
|
||||
$translated = $entity->addTranslation('de');
|
||||
$translated->moderation_state = 'published';
|
||||
$translated->save();
|
||||
$this->assertEquals('published', $translated->moderation_state->value);
|
||||
|
||||
// Test a scenario where the default revision exists with the default
|
||||
// language in a draft state and a non-default language in a published
|
||||
// state. The method returns TRUE if any of the languages for the default
|
||||
// revision are in a published state.
|
||||
$this->assertEquals(TRUE, $this->moderationInformation->isDefaultRevisionPublished($entity));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ namespace Drupal\Tests\content_moderation\Kernel;
|
|||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\Plugin\Field\ModerationStateFieldItemList
|
||||
|
|
@ -14,6 +14,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class ModerationStateFieldItemListTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -43,11 +45,15 @@ class ModerationStateFieldItemListTest extends KernelTestBase {
|
|||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installConfig('content_moderation');
|
||||
|
||||
NodeType::create([
|
||||
'type' => 'unmoderated',
|
||||
])->save();
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
|
||||
|
|
@ -64,7 +70,8 @@ class ModerationStateFieldItemListTest extends KernelTestBase {
|
|||
* Test the field item list when accessing an index.
|
||||
*/
|
||||
public function testArrayIndex() {
|
||||
$this->assertEquals('published', $this->testNode->moderation_state[0]->value);
|
||||
$this->assertFalse($this->testNode->isPublished());
|
||||
$this->assertEquals('draft', $this->testNode->moderation_state[0]->value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -75,7 +82,254 @@ class ModerationStateFieldItemListTest extends KernelTestBase {
|
|||
foreach ($this->testNode->moderation_state as $item) {
|
||||
$states[] = $item->value;
|
||||
}
|
||||
$this->assertEquals(['published'], $states);
|
||||
$this->assertEquals(['draft'], $states);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getValue
|
||||
*/
|
||||
public function testGetValue() {
|
||||
$this->assertEquals([['value' => 'draft']], $this->testNode->moderation_state->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::get
|
||||
*/
|
||||
public function testGet() {
|
||||
$this->assertEquals('draft', $this->testNode->moderation_state->get(0)->value);
|
||||
$this->setExpectedException(\InvalidArgumentException::class);
|
||||
$this->testNode->moderation_state->get(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the item list when it is emptied and appended to.
|
||||
*/
|
||||
public function testEmptyStateAndAppend() {
|
||||
// This test case mimics the lifecycle of an entity that is being patched in
|
||||
// a rest resource.
|
||||
$this->testNode->moderation_state->setValue([]);
|
||||
$this->assertTrue($this->testNode->moderation_state->isEmpty());
|
||||
$this->assertEmptiedModerationFieldItemList();
|
||||
|
||||
$this->testNode->moderation_state->appendItem();
|
||||
$this->assertEquals(1, $this->testNode->moderation_state->count());
|
||||
$this->assertEquals(NULL, $this->testNode->moderation_state->value);
|
||||
$this->assertEmptiedModerationFieldItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test an empty value assigned to the field item.
|
||||
*/
|
||||
public function testEmptyFieldItem() {
|
||||
$this->testNode->moderation_state->value = '';
|
||||
$this->assertEquals('', $this->testNode->moderation_state->value);
|
||||
$this->assertEmptiedModerationFieldItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test an empty value assigned to the field item list.
|
||||
*/
|
||||
public function testEmptyFieldItemList() {
|
||||
$this->testNode->moderation_state = '';
|
||||
$this->assertEquals('', $this->testNode->moderation_state->value);
|
||||
$this->assertEmptiedModerationFieldItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the field item when it is unset.
|
||||
*/
|
||||
public function testUnsetItemList() {
|
||||
unset($this->testNode->moderation_state);
|
||||
$this->assertEquals(NULL, $this->testNode->moderation_state->value);
|
||||
$this->assertEmptiedModerationFieldItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the field item when it is assigned NULL.
|
||||
*/
|
||||
public function testAssignNullItemList() {
|
||||
$this->testNode->moderation_state = NULL;
|
||||
$this->assertEquals(NULL, $this->testNode->moderation_state->value);
|
||||
$this->assertEmptiedModerationFieldItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert the set of expectations when the moderation state field is emptied.
|
||||
*/
|
||||
protected function assertEmptiedModerationFieldItemList() {
|
||||
$this->assertTrue($this->testNode->moderation_state->isEmpty());
|
||||
// Test the empty value causes a violation in the entity.
|
||||
$violations = $this->testNode->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals('This value should not be null.', $violations->get(0)->getMessage());
|
||||
// Test that incorrectly saving the entity regardless will not produce a
|
||||
// change in the moderation state.
|
||||
$this->testNode->save();
|
||||
$this->assertEquals('draft', Node::load($this->testNode->id())->moderation_state->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the list class with a non moderated entity.
|
||||
*/
|
||||
public function testNonModeratedEntity() {
|
||||
$unmoderated_node = Node::create([
|
||||
'type' => 'unmoderated',
|
||||
'title' => 'Test title',
|
||||
]);
|
||||
$unmoderated_node->save();
|
||||
$this->assertEquals(0, $unmoderated_node->moderation_state->count());
|
||||
|
||||
$unmoderated_node->moderation_state = NULL;
|
||||
$this->assertEquals(0, $unmoderated_node->moderation_state->count());
|
||||
$this->assertCount(0, $unmoderated_node->validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that moderation state changes also change the related entity state.
|
||||
*
|
||||
* @dataProvider moderationStateChangesTestCases
|
||||
*/
|
||||
public function testModerationStateChanges($initial_state, $final_state, $first_published, $first_is_default, $second_published, $second_is_default) {
|
||||
$this->testNode->moderation_state->value = $initial_state;
|
||||
$this->assertEquals($first_published, $this->testNode->isPublished());
|
||||
$this->assertEquals($first_is_default, $this->testNode->isDefaultRevision());
|
||||
$this->testNode->save();
|
||||
|
||||
$this->testNode->moderation_state->value = $final_state;
|
||||
$this->assertEquals($second_published, $this->testNode->isPublished());
|
||||
$this->assertEquals($second_is_default, $this->testNode->isDefaultRevision());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::testModerationStateChanges
|
||||
*/
|
||||
public function moderationStateChangesTestCases() {
|
||||
return [
|
||||
'Draft to draft' => [
|
||||
'draft',
|
||||
'draft',
|
||||
FALSE,
|
||||
TRUE,
|
||||
FALSE,
|
||||
TRUE,
|
||||
],
|
||||
'Draft to published' => [
|
||||
'draft',
|
||||
'published',
|
||||
FALSE,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE,
|
||||
],
|
||||
'Published to published' => [
|
||||
'published',
|
||||
'published',
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE,
|
||||
],
|
||||
'Published to draft' => [
|
||||
'published',
|
||||
'draft',
|
||||
TRUE,
|
||||
TRUE,
|
||||
FALSE,
|
||||
FALSE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updating the state for an entity without a workflow.
|
||||
*/
|
||||
public function testEntityWithNoWorkflow() {
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example_no_workflow',
|
||||
]);
|
||||
$node_type->save();
|
||||
$test_node = Node::create([
|
||||
'type' => 'example_no_workflow',
|
||||
'title' => 'Test node with no workflow',
|
||||
]);
|
||||
$test_node->save();
|
||||
|
||||
/** @var \Drupal\content_moderation\ModerationInformationInterface $content_moderation_info */
|
||||
$content_moderation_info = \Drupal::service('content_moderation.moderation_information');
|
||||
$workflow = $content_moderation_info->getWorkflowForEntity($test_node);
|
||||
$this->assertNull($workflow);
|
||||
|
||||
$this->assertTrue($test_node->isPublished());
|
||||
$test_node->moderation_state->setValue('draft');
|
||||
// The entity is still published because there is not a workflow.
|
||||
$this->assertTrue($test_node->isPublished());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the moderation_state field after an entity has been serialized.
|
||||
*
|
||||
* @dataProvider entityUnserializeTestCases
|
||||
*/
|
||||
public function testEntityUnserialize($state, $default, $published) {
|
||||
$this->testNode->moderation_state->value = $state;
|
||||
|
||||
$this->assertEquals($state, $this->testNode->moderation_state->value);
|
||||
$this->assertEquals($default, $this->testNode->isDefaultRevision());
|
||||
$this->assertEquals($published, $this->testNode->isPublished());
|
||||
|
||||
$unserialized = unserialize(serialize($this->testNode));
|
||||
|
||||
$this->assertEquals($state, $unserialized->moderation_state->value);
|
||||
$this->assertEquals($default, $unserialized->isDefaultRevision());
|
||||
$this->assertEquals($published, $unserialized->isPublished());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cases for ::testEntityUnserialize.
|
||||
*/
|
||||
public function entityUnserializeTestCases() {
|
||||
return [
|
||||
'Default draft state' => [
|
||||
'draft',
|
||||
TRUE,
|
||||
FALSE,
|
||||
],
|
||||
'Non-default published state' => [
|
||||
'published',
|
||||
TRUE,
|
||||
TRUE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test saving a moderated node with an existing ID.
|
||||
*
|
||||
* @dataProvider moderatedEntityWithExistingIdTestCases
|
||||
*/
|
||||
public function testModeratedEntityWithExistingId($state) {
|
||||
$node = Node::create([
|
||||
'title' => 'Test title',
|
||||
'type' => 'example',
|
||||
'nid' => 999,
|
||||
'moderation_state' => $state,
|
||||
]);
|
||||
$node->save();
|
||||
$this->assertEquals($state, $node->moderation_state->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cases for ::testModeratedEntityWithExistingId.
|
||||
*/
|
||||
public function moderatedEntityWithExistingIdTestCases() {
|
||||
return [
|
||||
'Draft non-default state' => [
|
||||
'draft',
|
||||
],
|
||||
'Published default state' => [
|
||||
'published',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\content_moderation\Plugin\Field\FieldWidget\ModerationStateWidget;
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\Plugin\Field\FieldWidget\ModerationStateWidget
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ModerationStateWidgetTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'system',
|
||||
'user',
|
||||
'workflows',
|
||||
'content_moderation',
|
||||
'node',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installEntitySchema('user');
|
||||
$this->installConfig(['content_moderation', 'system']);
|
||||
|
||||
NodeType::create([
|
||||
'type' => 'moderated',
|
||||
])->save();
|
||||
NodeType::create([
|
||||
'type' => 'unmoderated',
|
||||
])->save();
|
||||
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated');
|
||||
$workflow->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the widget does not impact a non-moderated entity.
|
||||
*/
|
||||
public function testWidgetNonModeratedEntity() {
|
||||
// Create an unmoderated entity and build a form display which will include
|
||||
// the ModerationStateWidget plugin, in a hidden state.
|
||||
$entity = Node::create([
|
||||
'type' => 'unmoderated',
|
||||
]);
|
||||
$entity_form_display = EntityFormDisplay::create([
|
||||
'targetEntityType' => 'node',
|
||||
'bundle' => 'unmoderated',
|
||||
'mode' => 'default',
|
||||
'status' => TRUE,
|
||||
]);
|
||||
$form = [];
|
||||
$form_state = new FormState();
|
||||
$entity_form_display->buildForm($entity, $form, $form_state);
|
||||
|
||||
// The moderation_state field should have no values for an entity that isn't
|
||||
// being moderated.
|
||||
$entity_form_display->extractFormValues($entity, $form, $form_state);
|
||||
$this->assertEquals(0, $entity->moderation_state->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isApplicable
|
||||
*/
|
||||
public function testIsApplicable() {
|
||||
// The moderation_state field definition should be applicable to our widget.
|
||||
$fields = $this->container->get('entity_field.manager')->getFieldDefinitions('node', 'test_type');
|
||||
$this->assertTrue(ModerationStateWidget::isApplicable($fields['moderation_state']));
|
||||
$this->assertFalse(ModerationStateWidget::isApplicable($fields['status']));
|
||||
// A config override should still be applicable.
|
||||
$field_config = $fields['moderation_state']->getConfig('moderated');
|
||||
$this->assertTrue(ModerationStateWidget::isApplicable($field_config));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\Tests\node\Traits\NodeCreationTrait;
|
||||
use Drupal\Tests\user\Traits\UserCreationTrait;
|
||||
|
||||
/**
|
||||
* Tests with node access enabled.
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class NodeAccessTest extends KernelTestBase {
|
||||
|
||||
use NodeCreationTrait;
|
||||
use UserCreationTrait;
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* The moderation information service.
|
||||
*
|
||||
* @var \Drupal\content_moderation\ModerationInformationInterface
|
||||
*/
|
||||
protected $moderationInformation;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_moderation',
|
||||
'filter',
|
||||
'node',
|
||||
'node_access_test',
|
||||
'system',
|
||||
'user',
|
||||
'workflows',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('workflow');
|
||||
$this->installConfig(['content_moderation', 'filter']);
|
||||
$this->installSchema('system', ['sequences']);
|
||||
$this->installSchema('node', ['node_access']);
|
||||
|
||||
// Add a moderated node type.
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'page',
|
||||
'label' => 'Page',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
|
||||
$workflow->save();
|
||||
|
||||
$this->moderationInformation = \Drupal::service('content_moderation.moderation_information');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for moderation information methods with node access.
|
||||
*/
|
||||
public function testModerationInformation() {
|
||||
// Create an admin user.
|
||||
$user = $this->createUser([], NULL, TRUE);
|
||||
\Drupal::currentUser()->setAccount($user);
|
||||
|
||||
// Create a node.
|
||||
$node = $this->createNode(['type' => 'page']);
|
||||
$this->assertEquals($node->getRevisionId(), $this->moderationInformation->getDefaultRevisionId('node', $node->id()));
|
||||
$this->assertEquals($node->getRevisionId(), $this->moderationInformation->getLatestRevisionId('node', $node->id()));
|
||||
|
||||
// Create a non-admin user.
|
||||
$user = $this->createUser();
|
||||
\Drupal::currentUser()->setAccount($user);
|
||||
$this->assertEquals($node->getRevisionId(), $this->moderationInformation->getDefaultRevisionId('node', $node->id()));
|
||||
$this->assertEquals($node->getRevisionId(), $this->moderationInformation->getLatestRevisionId('node', $node->id()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ namespace Drupal\Tests\content_moderation\Kernel;
|
|||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\entity_test\Entity\EntityTestRev;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Test the state field formatter.
|
||||
|
|
@ -14,6 +14,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class StateFormatterTest extends KernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
|
|
@ -36,7 +38,7 @@ class StateFormatterTest extends KernelTestBase {
|
|||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installConfig('content_moderation');
|
||||
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
|
||||
$workflow->save();
|
||||
}
|
||||
|
|
@ -52,7 +54,7 @@ class StateFormatterTest extends KernelTestBase {
|
|||
]);
|
||||
$entity->save();
|
||||
|
||||
$field_output = $this->container->get('renderer')->executeInRenderContext(new RenderContext(), function() use ($entity, $formatter_settings) {
|
||||
$field_output = $this->container->get('renderer')->executeInRenderContext(new RenderContext(), function () use ($entity, $formatter_settings) {
|
||||
return $entity->moderation_state->view($formatter_settings);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestMulRevPub;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* Tests the views integration of content_moderation.
|
||||
|
|
@ -16,6 +15,8 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class ViewsDataIntegrationTest extends ViewsKernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -45,60 +46,12 @@ class ViewsDataIntegrationTest extends ViewsKernelTestBase {
|
|||
'type' => 'page',
|
||||
]);
|
||||
$node_type->save();
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_mulrevpub', 'entity_test_mulrevpub');
|
||||
$workflow->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests content_moderation_views_data().
|
||||
*
|
||||
* @see content_moderation_views_data()
|
||||
*/
|
||||
public function testViewsData() {
|
||||
$node = Node::create([
|
||||
'type' => 'page',
|
||||
'title' => 'Test title first revision',
|
||||
]);
|
||||
$node->moderation_state->value = 'published';
|
||||
$node->save();
|
||||
|
||||
// Create a totally unrelated entity to ensure the extra join information
|
||||
// joins by the correct entity type.
|
||||
$unrelated_entity = EntityTestMulRevPub::create([
|
||||
'id' => $node->id(),
|
||||
]);
|
||||
$unrelated_entity->save();
|
||||
|
||||
$this->assertEquals($unrelated_entity->id(), $node->id());
|
||||
|
||||
$revision = clone $node;
|
||||
$revision->setNewRevision(TRUE);
|
||||
$revision->isDefaultRevision(FALSE);
|
||||
$revision->title->value = 'Test title second revision';
|
||||
$revision->moderation_state->value = 'draft';
|
||||
$revision->save();
|
||||
|
||||
$view = Views::getView('test_content_moderation_latest_revision');
|
||||
$view->execute();
|
||||
|
||||
// Ensure that the content_revision_tracker contains the right latest
|
||||
// revision ID.
|
||||
// Also ensure that the relationship back to the revision table contains the
|
||||
// right latest revision.
|
||||
$expected_result = [
|
||||
[
|
||||
'nid' => $node->id(),
|
||||
'revision_id' => $revision->getRevisionId(),
|
||||
'title' => $revision->label(),
|
||||
'moderation_state_1' => 'draft',
|
||||
'moderation_state' => 'published',
|
||||
],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, ['nid' => 'nid', 'content_revision_tracker_revision_id' => 'revision_id', 'moderation_state' => 'moderation_state', 'moderation_state_1' => 'moderation_state_1']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the join from the revision data table to the moderation state table.
|
||||
*/
|
||||
|
|
@ -157,14 +110,12 @@ class ViewsDataIntegrationTest extends ViewsKernelTestBase {
|
|||
$expected_result = [
|
||||
[
|
||||
'nid' => $node->id(),
|
||||
// @todo I would have expected that the content_moderation_state default
|
||||
// revision is the same one as in the node, but it isn't.
|
||||
// Joins from the base table to the default revision of the
|
||||
// content_moderation.
|
||||
'moderation_state' => 'draft',
|
||||
'moderation_state' => 'published',
|
||||
// Joins from the revision table to the default revision of the
|
||||
// content_moderation.
|
||||
'moderation_state_1' => 'draft',
|
||||
'moderation_state_1' => 'published',
|
||||
// Joins from the revision table to the revision of the
|
||||
// content_moderation.
|
||||
'moderation_state_2' => 'published',
|
||||
|
|
@ -173,4 +124,27 @@ class ViewsDataIntegrationTest extends ViewsKernelTestBase {
|
|||
$this->assertIdenticalResultset($view, $expected_result, ['nid' => 'nid', 'moderation_state' => 'moderation_state', 'moderation_state_1' => 'moderation_state_1', 'moderation_state_2' => 'moderation_state_2']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the content moderation state views field.
|
||||
*/
|
||||
public function testContentModerationStateField() {
|
||||
$node = Node::create([
|
||||
'type' => 'page',
|
||||
'title' => 'Test title',
|
||||
]);
|
||||
$node->moderation_state->value = 'published';
|
||||
$node->save();
|
||||
|
||||
$view = Views::getView('test_content_moderation_field_state_test');
|
||||
$view->execute();
|
||||
|
||||
$expected_result = [
|
||||
[
|
||||
'title' => 'Test title',
|
||||
'moderation_state' => 'published',
|
||||
],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected_result, ['title' => 'title', 'moderation_state' => 'moderation_state']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,301 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestNoBundle;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* Tests the views 'moderation_state_filter' filter plugin.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\content_moderation\Plugin\views\filter\ModerationStateFilter
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ViewsModerationStateFilterTest extends ViewsKernelTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_moderation_test_views',
|
||||
'node',
|
||||
'content_moderation',
|
||||
'workflows',
|
||||
'workflow_type_test',
|
||||
'entity_test',
|
||||
'language',
|
||||
'content_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp(FALSE);
|
||||
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('content_moderation_state');
|
||||
$this->installEntitySchema('entity_test_no_bundle');
|
||||
$this->installSchema('node', 'node_access');
|
||||
$this->installConfig('content_moderation_test_views');
|
||||
$this->installConfig('content_moderation');
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example',
|
||||
]);
|
||||
$node_type->save();
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'another_example',
|
||||
]);
|
||||
$node_type->save();
|
||||
|
||||
$node_type = NodeType::create([
|
||||
'type' => 'example_non_moderated',
|
||||
]);
|
||||
$node_type->save();
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the content moderation state filter.
|
||||
*/
|
||||
public function testStateFilterViewsRelationship() {
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->getTypePlugin()->addState('translated_draft', 'Bar');
|
||||
$configuration = $workflow->getTypePlugin()->getConfiguration();
|
||||
$configuration['states']['translated_draft'] += [
|
||||
'published' => FALSE,
|
||||
'default_revision' => FALSE,
|
||||
];
|
||||
$workflow->getTypePlugin()->setConfiguration($configuration);
|
||||
$workflow->save();
|
||||
|
||||
// Create a published default revision and one forward draft revision.
|
||||
$node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Test Node',
|
||||
'moderation_state' => 'published',
|
||||
]);
|
||||
$node->save();
|
||||
$node->setNewRevision();
|
||||
$node->moderation_state = 'draft';
|
||||
$node->save();
|
||||
|
||||
// Create a draft default revision.
|
||||
$second_node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Second Node',
|
||||
'moderation_state' => 'draft',
|
||||
]);
|
||||
$second_node->save();
|
||||
|
||||
// Create a published default revision.
|
||||
$third_node = Node::create([
|
||||
'type' => 'example',
|
||||
'title' => 'Third node',
|
||||
'moderation_state' => 'published',
|
||||
]);
|
||||
$third_node->save();
|
||||
|
||||
// Add a non-moderated node.
|
||||
$fourth_node = Node::create([
|
||||
'type' => 'example_non_moderated',
|
||||
'title' => 'Fourth node',
|
||||
]);
|
||||
$fourth_node->save();
|
||||
|
||||
// Create a translated published revision.
|
||||
$translated_forward_revision = $third_node->addTranslation('fr');
|
||||
$translated_forward_revision->title = 'Translated Node';
|
||||
$translated_forward_revision->setNewRevision(TRUE);
|
||||
$translated_forward_revision->moderation_state = 'translated_draft';
|
||||
$translated_forward_revision->save();
|
||||
|
||||
// The three default revisions are listed when no filter is specified.
|
||||
$this->assertNodesWithFilters([$node, $second_node, $third_node], []);
|
||||
|
||||
// The default revision of node one and three are published.
|
||||
$this->assertNodesWithFilters([$node, $third_node], [
|
||||
'default_revision_state' => 'editorial-published',
|
||||
]);
|
||||
|
||||
// The default revision of node two is draft.
|
||||
$this->assertNodesWithFilters([$second_node], [
|
||||
'default_revision_state' => 'editorial-draft',
|
||||
]);
|
||||
|
||||
// Test the same three revisions on a view displaying content revisions.
|
||||
// Both nodes have one draft revision.
|
||||
$this->assertNodesWithFilters([$node, $second_node], [
|
||||
'moderation_state' => 'editorial-draft',
|
||||
], 'test_content_moderation_state_filter_revision_table');
|
||||
// Creating a new forward revision of node three, creates a second published
|
||||
// revision of of the original language, hence there are two published
|
||||
// revisions of node three.
|
||||
$this->assertNodesWithFilters([$node, $third_node, $third_node], [
|
||||
'moderation_state' => 'editorial-published',
|
||||
], 'test_content_moderation_state_filter_revision_table');
|
||||
// There is a single forward translated revision with a new state, which is
|
||||
// also filterable.
|
||||
$this->assertNodesWithFilters([$translated_forward_revision], [
|
||||
'moderation_state' => 'editorial-translated_draft',
|
||||
], 'test_content_moderation_state_filter_revision_table');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the moderation filter with a non-translatable entity type.
|
||||
*/
|
||||
public function testNonTranslatableEntityType() {
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_no_bundle', 'entity_test_no_bundle');
|
||||
$workflow->save();
|
||||
|
||||
$test_entity = EntityTestNoBundle::create([
|
||||
'moderation_state' => 'draft',
|
||||
]);
|
||||
$test_entity->save();
|
||||
|
||||
$view = Views::getView('test_content_moderation_state_filter_entity_test');
|
||||
$view->setExposedInput([
|
||||
'moderation_state' => 'editorial-draft',
|
||||
]);
|
||||
$view->execute();
|
||||
$this->assertIdenticalResultset($view, [['id' => $test_entity->id()]], ['id' => 'id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the list of states in the filter plugin.
|
||||
*/
|
||||
public function testStateFilterStatesList() {
|
||||
// By default a view of nodes will not have states to filter.
|
||||
$this->assertPluginStates([]);
|
||||
|
||||
// Adding a content type to the editorial workflow will enable all of the
|
||||
// editorial states.
|
||||
$workflow = $this->createEditorialWorkflow();
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
$this->assertPluginStates([
|
||||
'Editorial' => [
|
||||
'editorial-draft' => 'Draft',
|
||||
'editorial-published' => 'Published',
|
||||
'editorial-archived' => 'Archived',
|
||||
],
|
||||
]);
|
||||
|
||||
// Adding a workflow which is not content moderation will not add any
|
||||
// additional states to the views filter.
|
||||
$workflow = Workflow::create(['id' => 'test', 'type' => 'workflow_type_complex_test']);
|
||||
$workflow->getTypePlugin()->addState('draft', 'Draft');
|
||||
$workflow->save();
|
||||
$this->assertPluginStates([
|
||||
'Editorial' => [
|
||||
'editorial-draft' => 'Draft',
|
||||
'editorial-published' => 'Published',
|
||||
'editorial-archived' => 'Archived',
|
||||
],
|
||||
]);
|
||||
|
||||
// Adding a new content moderation workflow will add additional states to
|
||||
// filter.
|
||||
$workflow = Workflow::create(['id' => 'moderation_test', 'type' => 'content_moderation', 'label' => 'Moderation test']);
|
||||
$workflow->getTypePlugin()->addState('foo', 'Foo State');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||
$workflow->save();
|
||||
$this->assertPluginStates([
|
||||
'Editorial' => [
|
||||
'editorial-draft' => 'Draft',
|
||||
'editorial-published' => 'Published',
|
||||
'editorial-archived' => 'Archived',
|
||||
],
|
||||
'Moderation test' => [
|
||||
'moderation_test-foo' => 'Foo State',
|
||||
'moderation_test-draft' => 'Draft',
|
||||
'moderation_test-published' => 'Published',
|
||||
],
|
||||
]);
|
||||
|
||||
// Deleting a workflow will remove the states from the filter.
|
||||
$workflow = Workflow::load('moderation_test');
|
||||
$workflow->delete();
|
||||
$this->assertPluginStates([
|
||||
'Editorial' => [
|
||||
'editorial-draft' => 'Draft',
|
||||
'editorial-published' => 'Published',
|
||||
'editorial-archived' => 'Archived',
|
||||
],
|
||||
]);
|
||||
|
||||
// Deleting a state from a workflow will remove the state from the filter.
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->deleteState('archived');
|
||||
$workflow->save();
|
||||
$this->assertPluginStates([
|
||||
'Editorial' => [
|
||||
'editorial-draft' => 'Draft',
|
||||
'editorial-published' => 'Published',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert the plugin states.
|
||||
*
|
||||
* @param string[] $states
|
||||
* The states which should appear in the filter.
|
||||
*/
|
||||
protected function assertPluginStates($states) {
|
||||
$plugin = Views::pluginManager('filter')->createInstance('moderation_state_filter', []);
|
||||
$view = Views::getView('test_content_moderation_state_filter_base_table');
|
||||
$plugin->init($view, $view->getDisplay());
|
||||
$this->assertEquals($states, $plugin->getValueOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert the nodes appear when the test view is executed.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface[] $nodes
|
||||
* Nodes to assert are in the views result.
|
||||
* @param array $filters
|
||||
* An array of filters to apply to the view.
|
||||
* @param string $view_id
|
||||
* The view to execute for the results.
|
||||
*/
|
||||
protected function assertNodesWithFilters(array $nodes, array $filters, $view_id = 'test_content_moderation_state_filter_base_table') {
|
||||
$view = Views::getView($view_id);
|
||||
$view->setExposedInput($filters);
|
||||
$view->execute();
|
||||
|
||||
// Verify the join configuration.
|
||||
$query = $view->getQuery();
|
||||
$join = $query->getTableInfo('content_moderation_state')['join'];
|
||||
$configuration = $join->configuration;
|
||||
$this->assertEquals('content_moderation_state_field_revision', $configuration['table']);
|
||||
$this->assertEquals('content_entity_revision_id', $configuration['field']);
|
||||
$this->assertEquals('vid', $configuration['left_field']);
|
||||
$this->assertEquals('content_entity_type_id', $configuration['extra'][0]['field']);
|
||||
$this->assertEquals('node', $configuration['extra'][0]['value']);
|
||||
$this->assertEquals('langcode', $configuration['extra'][1]['field']);
|
||||
$this->assertEquals('langcode', $configuration['extra'][1]['left_field']);
|
||||
|
||||
$expected_result = [];
|
||||
foreach ($nodes as $node) {
|
||||
$expected_result[] = ['nid' => $node->id()];
|
||||
}
|
||||
$this->assertIdenticalResultset($view, $expected_result, ['nid' => 'nid']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Traits;
|
||||
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* Trait ContentModerationTestTraint.
|
||||
*/
|
||||
trait ContentModerationTestTrait {
|
||||
|
||||
/**
|
||||
* Creates the editorial workflow.
|
||||
*
|
||||
* @return \Drupal\workflows\Entity\Workflow
|
||||
* The editorial workflow entity.
|
||||
*/
|
||||
protected function createEditorialWorkflow() {
|
||||
$workflow = Workflow::create([
|
||||
'type' => 'content_moderation',
|
||||
'id' => 'editorial',
|
||||
'label' => 'Editorial',
|
||||
'type_settings' => [
|
||||
'states' => [
|
||||
'archived' => [
|
||||
'label' => 'Archived',
|
||||
'weight' => 5,
|
||||
'published' => FALSE,
|
||||
'default_revision' => TRUE,
|
||||
],
|
||||
'draft' => [
|
||||
'label' => 'Draft',
|
||||
'published' => FALSE,
|
||||
'default_revision' => FALSE,
|
||||
'weight' => -5,
|
||||
],
|
||||
'published' => [
|
||||
'label' => 'Published',
|
||||
'published' => TRUE,
|
||||
'default_revision' => TRUE,
|
||||
'weight' => 0,
|
||||
],
|
||||
],
|
||||
'transitions' => [
|
||||
'archive' => [
|
||||
'label' => 'Archive',
|
||||
'from' => ['published'],
|
||||
'to' => 'archived',
|
||||
'weight' => 2,
|
||||
],
|
||||
'archived_draft' => [
|
||||
'label' => 'Restore to Draft',
|
||||
'from' => ['archived'],
|
||||
'to' => 'draft',
|
||||
'weight' => 3,
|
||||
],
|
||||
'archived_published' => [
|
||||
'label' => 'Restore',
|
||||
'from' => ['archived'],
|
||||
'to' => 'published',
|
||||
'weight' => 4,
|
||||
],
|
||||
'create_new_draft' => [
|
||||
'label' => 'Create New Draft',
|
||||
'to' => 'draft',
|
||||
'weight' => 0,
|
||||
'from' => [
|
||||
'draft',
|
||||
'published',
|
||||
],
|
||||
],
|
||||
'publish' => [
|
||||
'label' => 'Publish',
|
||||
'to' => 'published',
|
||||
'weight' => 1,
|
||||
'from' => [
|
||||
'draft',
|
||||
'published',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$workflow->save();
|
||||
return $workflow;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_moderation\Unit;
|
||||
|
||||
use Drupal\content_moderation\Routing\ContentModerationRouteSubscriber;
|
||||
use Drupal\Core\Entity\Entity;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Routing\RouteBuildEvent;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\Routing\ContentModerationRouteSubscriber
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ContentModerationRouteSubscriberTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The test content moderation route subscriber.
|
||||
*
|
||||
* @var \Drupal\content_moderation\Routing\ContentModerationRouteSubscriber
|
||||
*/
|
||||
protected $routeSubscriber;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
|
||||
$entity_type_manager = $this->createMock(EntityTypeManagerInterface::class);
|
||||
$this->routeSubscriber = new ContentModerationRouteSubscriber($entity_type_manager);
|
||||
$this->setupEntityTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity manager mock returning entity type objects.
|
||||
*/
|
||||
protected function setupEntityTypes() {
|
||||
$definition = $this->createMock(EntityTypeInterface::class);
|
||||
$definition->expects($this->any())
|
||||
->method('getClass')
|
||||
->will($this->returnValue(SimpleTestEntity::class));
|
||||
$definition->expects($this->any())
|
||||
->method('isRevisionable')
|
||||
->willReturn(FALSE);
|
||||
$revisionable_definition = $this->createMock(EntityTypeInterface::class);
|
||||
$revisionable_definition->expects($this->any())
|
||||
->method('getClass')
|
||||
->will($this->returnValue(SimpleTestEntity::class));
|
||||
$revisionable_definition->expects($this->any())
|
||||
->method('isRevisionable')
|
||||
->willReturn(TRUE);
|
||||
$entity_types = [
|
||||
'entity_test' => $definition,
|
||||
'entity_test_rev' => $revisionable_definition,
|
||||
];
|
||||
|
||||
$reflector = new \ReflectionProperty($this->routeSubscriber, 'moderatedEntityTypes');
|
||||
$reflector->setAccessible(TRUE);
|
||||
$reflector->setValue($this->routeSubscriber, $entity_types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::testSetLatestRevisionFlag.
|
||||
*/
|
||||
public function setLatestRevisionFlagTestCases() {
|
||||
return [
|
||||
'Entity parameter not on an entity form' => [
|
||||
[],
|
||||
[
|
||||
'entity_test' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Entity parameter on an entity form' => [
|
||||
[
|
||||
'_entity_form' => 'entity_test_rev.edit',
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
],
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
'load_latest_revision' => TRUE,
|
||||
],
|
||||
],
|
||||
],
|
||||
'Entity form with no operation' => [
|
||||
[
|
||||
'_entity_form' => 'entity_test_rev',
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
],
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
'load_latest_revision' => TRUE,
|
||||
],
|
||||
],
|
||||
],
|
||||
'Non-moderated entity form' => [
|
||||
[
|
||||
'_entity_form' => 'entity_test_mulrev',
|
||||
],
|
||||
[
|
||||
'entity_test_mulrev' => [
|
||||
'type' => 'entity:entity_test_mulrev',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Multiple entity parameters on an entity form' => [
|
||||
[
|
||||
'_entity_form' => 'entity_test_rev.edit',
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
],
|
||||
'node' => [
|
||||
'type' => 'entity:node',
|
||||
],
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
'load_latest_revision' => TRUE,
|
||||
],
|
||||
'node' => [
|
||||
'type' => 'entity:node',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Overridden load_latest_revision flag does not change' => [
|
||||
[
|
||||
'_entity_form' => 'entity_test_rev.edit',
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
'load_latest_revision' => FALSE,
|
||||
],
|
||||
],
|
||||
],
|
||||
'Non-revisionable entity type will not change' => [
|
||||
[
|
||||
'_entity_form' => 'entity_test.edit',
|
||||
],
|
||||
[
|
||||
'entity_test' => [
|
||||
'type' => 'entity:entity_test',
|
||||
],
|
||||
],
|
||||
FALSE,
|
||||
FALSE,
|
||||
],
|
||||
'Overridden load_latest_revision flag does not change with multiple parameters' => [
|
||||
[
|
||||
'_entity_form' => 'entity_test_rev.edit',
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
],
|
||||
'node' => [
|
||||
'type' => 'entity:node',
|
||||
'load_latest_revision' => FALSE,
|
||||
],
|
||||
],
|
||||
[
|
||||
'entity_test_rev' => [
|
||||
'type' => 'entity:entity_test_rev',
|
||||
'load_latest_revision' => TRUE,
|
||||
],
|
||||
'node' => [
|
||||
'type' => 'entity:node',
|
||||
'load_latest_revision' => FALSE,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the "load_latest_revision" flag is handled correctly.
|
||||
*
|
||||
* @param array $defaults
|
||||
* The route defaults.
|
||||
* @param array $parameters
|
||||
* The route parameters.
|
||||
* @param array|bool $expected_parameters
|
||||
* (optional) The expected route parameters. Defaults to FALSE.
|
||||
*
|
||||
* @covers ::setLatestRevisionFlag
|
||||
*
|
||||
* @dataProvider setLatestRevisionFlagTestCases
|
||||
*/
|
||||
public function testSetLatestRevisionFlag($defaults, $parameters, $expected_parameters = FALSE) {
|
||||
$route = new Route('/foo/{entity_test}', $defaults, [], [
|
||||
'parameters' => $parameters,
|
||||
]);
|
||||
|
||||
$route_collection = new RouteCollection();
|
||||
$route_collection->add('test', $route);
|
||||
$event = new RouteBuildEvent($route_collection);
|
||||
$this->routeSubscriber->onAlterRoutes($event);
|
||||
|
||||
// If expected parameters have not been provided, assert they are unchanged.
|
||||
$this->assertEquals($expected_parameters ?: $parameters, $route->getOption('parameters'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete entity.
|
||||
*/
|
||||
class SimpleTestEntity extends Entity {
|
||||
}
|
||||
|
|
@ -5,13 +5,14 @@ namespace Drupal\Tests\content_moderation\Unit;
|
|||
use Drupal\content_moderation\ContentPreprocess;
|
||||
use Drupal\Core\Routing\CurrentRouteMatch;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\ContentPreprocess
|
||||
*
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ContentPreprocessTest extends \PHPUnit_Framework_TestCase {
|
||||
class ContentPreprocessTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::isLatestVersionPage
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use Drupal\Core\Session\AccountInterface;
|
|||
use Drupal\node\Entity\Node;
|
||||
use Drupal\content_moderation\Access\LatestRevisionCheck;
|
||||
use Drupal\content_moderation\ModerationInformation;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
use Prophecy\Argument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
|
@ -21,7 +22,7 @@ use Symfony\Component\Routing\Route;
|
|||
* @coversDefaultClass \Drupal\content_moderation\Access\LatestRevisionCheck
|
||||
* @group content_moderation
|
||||
*/
|
||||
class LatestRevisionCheckTest extends \PHPUnit_Framework_TestCase {
|
||||
class LatestRevisionCheckTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
|
@ -44,8 +45,8 @@ class LatestRevisionCheckTest extends \PHPUnit_Framework_TestCase {
|
|||
* The class of the entity to mock.
|
||||
* @param string $entity_type
|
||||
* The machine name of the entity to mock.
|
||||
* @param bool $has_forward
|
||||
* Whether this entity should have a forward revision in the system.
|
||||
* @param bool $has_pending_revision
|
||||
* Whether this entity should have a pending revision in the system.
|
||||
* @param array $account_permissions
|
||||
* An array of permissions the account has.
|
||||
* @param bool $is_owner
|
||||
|
|
@ -56,7 +57,7 @@ class LatestRevisionCheckTest extends \PHPUnit_Framework_TestCase {
|
|||
*
|
||||
* @dataProvider accessSituationProvider
|
||||
*/
|
||||
public function testLatestAccessPermissions($entity_class, $entity_type, $has_forward, array $account_permissions, $is_owner, $result_class) {
|
||||
public function testLatestAccessPermissions($entity_class, $entity_type, $has_pending_revision, array $account_permissions, $is_owner, $result_class) {
|
||||
|
||||
/** @var \Drupal\Core\Session\AccountInterface $account */
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
|
|
@ -81,7 +82,7 @@ class LatestRevisionCheckTest extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
/** @var \Drupal\content_moderation\ModerationInformation $mod_info */
|
||||
$mod_info = $this->prophesize(ModerationInformation::class);
|
||||
$mod_info->hasForwardRevision($entity->reveal())->willReturn($has_forward);
|
||||
$mod_info->hasPendingRevision($entity->reveal())->willReturn($has_pending_revision);
|
||||
|
||||
$route = $this->prophesize(Route::class);
|
||||
|
||||
|
|
@ -118,13 +119,13 @@ class LatestRevisionCheckTest extends \PHPUnit_Framework_TestCase {
|
|||
// Node with own content permissions and no latest version, but no perms
|
||||
// to view latest version.
|
||||
[Node::class, 'node', TRUE, ['view own unpublished content'], FALSE, AccessResultNeutral::class],
|
||||
// Block with forward revision, and permissions to view any.
|
||||
// Block with pending revision, and permissions to view any.
|
||||
[BlockContent::class, 'block_content', TRUE, ['view latest version', 'view any unpublished content'], FALSE, AccessResultAllowed::class],
|
||||
// Block with no forward revision.
|
||||
// Block with no pending revision.
|
||||
[BlockContent::class, 'block_content', FALSE, ['view latest version', 'view any unpublished content'], FALSE, AccessResultForbidden::class],
|
||||
// Block with forward revision, but no permission to view any.
|
||||
// Block with pending revision, but no permission to view any.
|
||||
[BlockContent::class, 'block_content', TRUE, ['view latest version', 'view own unpublished content'], FALSE, AccessResultNeutral::class],
|
||||
// Block with no forward revision.
|
||||
// Block with no pending revision.
|
||||
[BlockContent::class, 'block_content', FALSE, ['view latest version', 'view own unpublished content'], FALSE, AccessResultForbidden::class],
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,19 @@ use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
|||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\content_moderation\ModerationInformation;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\workflows\WorkflowInterface;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\content_moderation\ModerationInformation
|
||||
* @group content_moderation
|
||||
*/
|
||||
class ModerationInformationTest extends \PHPUnit_Framework_TestCase {
|
||||
class ModerationInformationTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Builds a mock user.
|
||||
*
|
||||
* @return AccountInterface
|
||||
* @return \Drupal\Core\Session\AccountInterface
|
||||
* The mocked user.
|
||||
*/
|
||||
protected function getUser() {
|
||||
|
|
@ -31,7 +32,7 @@ class ModerationInformationTest extends \PHPUnit_Framework_TestCase {
|
|||
/**
|
||||
* Returns a mock Entity Type Manager.
|
||||
*
|
||||
* @return EntityTypeManagerInterface
|
||||
* @return \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
* The mocked entity type manager.
|
||||
*/
|
||||
protected function getEntityTypeManager() {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ use Drupal\Core\DependencyInjection\ContainerBuilder;
|
|||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\content_moderation\StateTransitionValidation;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\workflow_type_test\Plugin\WorkflowType\TestType;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
use Drupal\workflows\WorkflowTypeInterface;
|
||||
use Drupal\workflows\WorkflowTypeManager;
|
||||
use Prophecy\Argument;
|
||||
|
||||
|
|
@ -16,7 +17,7 @@ use Prophecy\Argument;
|
|||
* @coversDefaultClass \Drupal\content_moderation\StateTransitionValidation
|
||||
* @group content_moderation
|
||||
*/
|
||||
class StateTransitionValidationTest extends \PHPUnit_Framework_TestCase {
|
||||
class StateTransitionValidationTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Verifies user-aware transition validation.
|
||||
|
|
@ -61,16 +62,14 @@ class StateTransitionValidationTest extends \PHPUnit_Framework_TestCase {
|
|||
// Create a container so that the plugin manager and workflow type can be
|
||||
// mocked.
|
||||
$container = new ContainerBuilder();
|
||||
$workflow_type = $this->prophesize(WorkflowTypeInterface::class);
|
||||
$workflow_type->decorateState(Argument::any())->willReturnArgument(0);
|
||||
$workflow_type->decorateTransition(Argument::any())->willReturnArgument(0);
|
||||
$workflow_manager = $this->prophesize(WorkflowTypeManager::class);
|
||||
$workflow_manager->createInstance('content_moderation', Argument::any())->willReturn($workflow_type->reveal());
|
||||
$workflow_manager->createInstance('content_moderation', Argument::any())->willReturn(new TestType([], '', []));
|
||||
$container->set('plugin.manager.workflows.type', $workflow_manager->reveal());
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
$workflow = new Workflow(['id' => 'process', 'type' => 'content_moderation'], 'workflow');
|
||||
$workflow
|
||||
->getTypePlugin()
|
||||
->addState('draft', 'draft')
|
||||
->addState('needs_review', 'needs_review')
|
||||
->addState('published', 'published')
|
||||
|
|
|
|||
Reference in a new issue