Issue #2969678 by seanB, oknate, phenaproxima, Wim Leers: Integrate Media Library with Content Moderation

merge-requests/55/head
effulgentsia 2019-09-26 16:49:58 -07:00
parent ef3544afa6
commit 6749e8de0a
14 changed files with 741 additions and 53 deletions

View File

@ -749,6 +749,45 @@ display:
plugin_id: boolean
entity_type: media
entity_field: status
status_extra:
id: status_extra
table: media_field_data
field: status_extra
relationship: none
group_type: group
admin_label: ''
operator: '='
value: ''
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
operator_limit_selection: false
operator_list: { }
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
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: media
plugin_id: media_status
langcode:
id: langcode
table: media_field_data
@ -833,6 +872,7 @@ display:
- 'languages:language_interface'
- url
- url.query_args
- user
- user.permissions
tags: { }
media_page_list:
@ -860,5 +900,6 @@ display:
- 'languages:language_interface'
- url
- url.query_args
- user
- user.permissions
tags: { }

View File

@ -18,6 +18,7 @@ use Drupal\Core\Url;
use Drupal\field\FieldConfigInterface;
use Drupal\media\Plugin\media\Source\Image;
use Drupal\media\Plugin\media\Source\OEmbedInterface;
use Drupal\views\ViewExecutable;
/**
* Implements hook_help().
@ -539,3 +540,14 @@ function _media_type_add_form_submit(array &$form, FormStateInterface $form_stat
$display->save();
}
/**
* Implements hook_views_query_substitutions().
*/
function media_views_query_substitutions(ViewExecutable $view) {
$account = \Drupal::currentUser();
return [
'***VIEW_OWN_UNPUBLISHED_MEDIA***' => (int) $account->hasPermission('view own unpublished media'),
'***ADMINISTER_MEDIA***' => (int) $account->hasPermission('administer media'),
];
}

View File

@ -5,6 +5,9 @@
* Post update functions for Media.
*/
use Drupal\user\RoleInterface;
use Drupal\views\Views;
/**
* Clear caches due to changes in local tasks and action links.
*/
@ -28,3 +31,69 @@ function media_post_update_enable_standalone_url() {
$config->set('standalone_url', TRUE)->save(TRUE);
}
}
/**
* Add a status extra filter to the media view default display.
*/
function media_post_update_add_status_extra_filter() {
$view = Views::getView('media');
if (!$view) {
return;
}
// Fetch the filters from the default display and add the new 'status_extra'
// filter if it does not yet exist.
$default_display = $view->getDisplay();
$filters = $default_display->getOption('filters');
if (!isset($filters['status_extra'])) {
$filters['status_extra'] = [
'group_info' => [
'widget' => 'select',
'group_items' => [],
'multiple' => FALSE,
'description' => '',
'default_group_multiple' => [],
'default_group' => 'All',
'label' => '',
'identifier' => '',
'optional' => TRUE,
'remember' => FALSE,
],
'group' => 1,
'relationship' => 'none',
'exposed' => FALSE,
'expose' => [
'use_operator' => FALSE,
'remember' => FALSE,
'operator_id' => '',
'multiple' => FALSE,
'description' => '',
'required' => FALSE,
'label' => '',
'operator_limit_selection' => FALSE,
'operator' => '',
'identifier' => '',
'operator_list' => [],
'remember_roles' => [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID],
],
'entity_type' => 'media',
'value' => '',
'field' => 'status_extra',
'is_grouped' => FALSE,
'admin_label' => '',
'operator' => '=',
'table' => 'media_field_data',
'plugin_id' => 'media_status',
'id' => 'status_extra',
'group_type' => 'group',
];
$default_display->setOption('filters', $filters);
$view->save();
return t("The 'Published status or admin user' filter was added to the %label view.", [
'%label' => $view->storage->label(),
]);
}
}

View File

@ -18,6 +18,16 @@ class MediaViewsData extends EntityViewsData {
$data['media_field_data']['table']['wizard_id'] = 'media';
$data['media_field_revision']['table']['wizard_id'] = 'media_revision';
$data['media_field_data']['status_extra'] = [
'title' => $this->t('Published status or admin user'),
'help' => $this->t('Filters out unpublished media if the current user cannot view it.'),
'filter' => [
'field' => 'status',
'id' => 'media_status',
'label' => $this->t('Published status or admin user'),
],
];
return $data;
}

View File

@ -0,0 +1,55 @@
<?php
namespace Drupal\media\Plugin\views\filter;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\filter\FilterPluginBase;
/**
* Filter by published status.
*
* @ingroup views_filter_handlers
*
* @ViewsFilter("media_status")
*/
class Status extends FilterPluginBase {
/**
* {@inheritdoc}
*/
public function adminSummary() {}
/**
* {@inheritdoc}
*/
protected function operatorForm(&$form, FormStateInterface $form_state) {}
/**
* {@inheritdoc}
*/
public function canExpose() {
return FALSE;
}
/**
* {@inheritdoc}
*/
public function query() {
$table = $this->ensureMyTable();
$snippet = "$table.status = 1 OR ($table.uid = ***CURRENT_USER*** AND ***CURRENT_USER*** <> 0 AND ***VIEW_OWN_UNPUBLISHED_MEDIA*** = 1) OR ***ADMINISTER_MEDIA*** = 1";
if ($this->moduleHandler->moduleExists('content_moderation')) {
$snippet .= ' OR ***VIEW_ANY_UNPUBLISHED_NODES*** = 1';
}
$this->query->addWhereExpression($this->options['group'], $snippet);
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
$contexts = parent::getCacheContexts();
$contexts[] = 'user';
return $contexts;
}
}

View File

@ -178,7 +178,7 @@ class MediaAccessTest extends MediaFunctionalTestBase {
$this->drupalGet('admin/content');
$assert_session->linkByHrefExists('/admin/content/media');
$this->clickLink('Media');
$this->assertCacheContext('user.permissions');
$this->assertCacheContext('user');
$assert_session->statusCodeEquals(200);
$assert_session->elementExists('css', '.view-media');
$assert_session->pageTextContains($this->loggedInUser->getDisplayName());

View File

@ -32,7 +32,7 @@ class MediaOverviewPageTest extends MediaFunctionalTestBase {
$assert_session->statusCodeEquals(403);
$role = Role::load(RoleInterface::AUTHENTICATED_ID);
$this->grantPermissions($role, ['access media overview']);
$this->drupalGet('/admin/content/media');
$this->getSession()->reload();
$assert_session->statusCodeEquals(200);
$assert_session->titleEquals('Media | Drupal');
$assert_session->fieldExists('Media name');
@ -79,55 +79,45 @@ class MediaOverviewPageTest extends MediaFunctionalTestBase {
]);
$media3->save();
// Verify the view is now correctly populated.
// Verify the view is now correctly populated. The non-admin user can only
// view published media.
$this->grantPermissions($role, [
'view media',
'update any media',
'delete any media',
]);
$this->drupalGet('/admin/content/media');
$this->getSession()->reload();
$row1 = $assert_session->elementExists('css', 'table tbody tr:nth-child(1)');
$row2 = $assert_session->elementExists('css', 'table tbody tr:nth-child(2)');
$row3 = $assert_session->elementExists('css', 'table tbody tr:nth-child(3)');
// Media thumbnails.
$assert_session->elementExists('css', 'td.views-field-thumbnail__target-id img', $row1);
$assert_session->elementExists('css', 'td.views-field-thumbnail__target-id img', $row2);
$assert_session->elementExists('css', 'td.views-field-thumbnail__target-id img', $row3);
// Media names.
$name1 = $assert_session->elementExists('css', 'td.views-field-name a', $row1);
$this->assertSame($media1->label(), $name1->getText());
$name2 = $assert_session->elementExists('css', 'td.views-field-name a', $row2);
$this->assertSame($media2->label(), $name2->getText());
$name3 = $assert_session->elementExists('css', 'td.views-field-name a', $row3);
$this->assertSame($media3->label(), $name3->getText());
$this->assertSame($media3->label(), $name2->getText());
$assert_session->linkByHrefExists('/media/' . $media1->id());
$assert_session->linkByHrefExists('/media/' . $media2->id());
$assert_session->linkByHrefExists('/media/' . $media3->id());
// Media types.
$type_element1 = $assert_session->elementExists('css', 'td.views-field-bundle', $row1);
$this->assertSame($media_type1->label(), $type_element1->getText());
$type_element2 = $assert_session->elementExists('css', 'td.views-field-bundle', $row2);
$this->assertSame($media_type2->label(), $type_element2->getText());
$type_element3 = $assert_session->elementExists('css', 'td.views-field-bundle', $row3);
$this->assertSame($media_type1->label(), $type_element3->getText());
$this->assertSame($media_type1->label(), $type_element2->getText());
// Media authors.
$author_element1 = $assert_session->elementExists('css', 'td.views-field-uid', $row1);
$this->assertSame($this->adminUser->getDisplayName(), $author_element1->getText());
$author_element2 = $assert_session->elementExists('css', 'td.views-field-uid', $row2);
$this->assertSame($this->adminUser->getDisplayName(), $author_element2->getText());
$author_element3 = $assert_session->elementExists('css', 'td.views-field-uid', $row3);
$author_element3 = $assert_session->elementExists('css', 'td.views-field-uid', $row2);
$this->assertSame($this->nonAdminUser->getDisplayName(), $author_element3->getText());
// Media publishing status.
$status_element1 = $assert_session->elementExists('css', 'td.views-field-status', $row1);
$this->assertSame('Published', $status_element1->getText());
$status_element2 = $assert_session->elementExists('css', 'td.views-field-status', $row2);
$this->assertSame('Unpublished', $status_element2->getText());
$status_element3 = $assert_session->elementExists('css', 'td.views-field-status', $row3);
$status_element3 = $assert_session->elementExists('css', 'td.views-field-status', $row2);
$this->assertSame('Published', $status_element3->getText());
// Timestamp.
@ -142,6 +132,36 @@ class MediaOverviewPageTest extends MediaFunctionalTestBase {
$delete_link1 = $assert_session->elementExists('css', 'td.views-field-operations li.delete a', $row1);
$this->assertSame('Delete', $delete_link1->getText());
$assert_session->linkByHrefExists('/media/' . $media1->id() . '/delete');
// Make the user the owner of the unpublished media item and assert the
// media item is only visible with the 'view own unpublished media'
// permission.
$media2->setOwner($this->nonAdminUser)->save();
$this->getSession()->reload();
$assert_session->pageTextNotContains($media2->label());
$role->grantPermission('view own unpublished media')->save();
$this->getSession()->reload();
$row = $assert_session->elementExists('css', 'table tbody tr:nth-child(2)');
$name = $assert_session->elementExists('css', 'td.views-field-name a', $row);
$this->assertSame($media2->label(), $name->getText());
$status_element = $assert_session->elementExists('css', 'td.views-field-status', $row);
$this->assertSame('Unpublished', $status_element->getText());
// Assert the admin user can always view all media.
$this->drupalLogin($this->adminUser);
$this->drupalGet('/admin/content/media');
$row1 = $assert_session->elementExists('css', 'table tbody tr:nth-child(1)');
$row2 = $assert_session->elementExists('css', 'table tbody tr:nth-child(2)');
$row3 = $assert_session->elementExists('css', 'table tbody tr:nth-child(3)');
$name1 = $assert_session->elementExists('css', 'td.views-field-name a', $row1);
$this->assertSame($media1->label(), $name1->getText());
$name2 = $assert_session->elementExists('css', 'td.views-field-name a', $row2);
$this->assertSame($media2->label(), $name2->getText());
$name3 = $assert_session->elementExists('css', 'td.views-field-name a', $row3);
$this->assertSame($media3->label(), $name3->getText());
$assert_session->linkByHrefExists('/media/' . $media1->id());
$assert_session->linkByHrefExists('/media/' . $media2->id());
$assert_session->linkByHrefExists('/media/' . $media3->id());
}
}

View File

@ -114,4 +114,25 @@ class MediaUpdateTest extends UpdatePathTestBase {
$this->assertSession()->statusCodeEquals(200);
}
/**
* Tests that the status extra filter is added to the media view.
*
* @see media_post_update_add_status_extra_filter()
*/
public function testMediaViewStatusExtraFilter() {
$config = $this->config('views.view.media');
$this->assertNull($config->get('display.default.display_options.filters.status_extra'));
$this->runUpdates();
$config = $this->config('views.view.media');
$filter = $config->get('display.default.display_options.filters.status_extra');
$this->assertInternalType('array', $filter);
$this->assertSame('status_extra', $filter['field']);
$this->assertSame('media', $filter['entity_type']);
$this->assertSame('media_status', $filter['plugin_id']);
$this->assertSame('status_extra', $filter['id']);
$this->assertFalse($filter['exposed']);
}
}

View File

@ -325,6 +325,45 @@ display:
entity_type: media
entity_field: bundle
plugin_id: bundle
status_extra:
id: status_extra
table: media_field_data
field: status_extra
relationship: none
group_type: group
admin_label: ''
operator: '='
value: ''
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
operator_limit_selection: false
operator_list: { }
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
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: media
plugin_id: media_status
sorts:
created:
id: created
@ -395,6 +434,7 @@ display:
- url
- url.query_args
- 'url.query_args:sort_by'
- user
- user.permissions
tags: { }
page:
@ -700,6 +740,7 @@ display:
- url
- url.query_args
- 'url.query_args:sort_by'
- user
- user.permissions
tags: { }
# @todo Lock down access in https://www.drupal.org/node/2983179

View File

@ -9,6 +9,7 @@ use Drupal\Core\Entity\Entity\EntityFormMode;
use Drupal\Core\Entity\Entity\EntityViewMode;
use Drupal\image\Entity\ImageStyle;
use Drupal\media\Entity\MediaType;
use Drupal\user\RoleInterface;
use Drupal\views\Views;
/**
@ -240,3 +241,69 @@ function media_library_post_update_add_media_library_image_style() {
return t('The %label image style has been created successfully.', ['%label' => 'Media Library (220x220)']);
}
/**
* Add a status extra filter to the media library view default display.
*/
function media_library_post_update_add_status_extra_filter() {
$view = Views::getView('media_library');
if (!$view) {
return t('The media_library view could not be updated because it has been deleted. The Media Library module needs this view in order to work properly. Uninstall and reinstall the module so the view will be re-created.');
}
// Fetch the filters from the default display and add the new 'status_extra'
// filter if it does not yet exist.
$default_display = $view->getDisplay();
$filters = $default_display->getOption('filters');
if (!isset($filters['status_extra'])) {
$filters['status_extra'] = [
'group_info' => [
'widget' => 'select',
'group_items' => [],
'multiple' => FALSE,
'description' => '',
'default_group_multiple' => [],
'default_group' => 'All',
'label' => '',
'identifier' => '',
'optional' => TRUE,
'remember' => FALSE,
],
'group' => 1,
'relationship' => 'none',
'exposed' => FALSE,
'expose' => [
'use_operator' => FALSE,
'remember' => FALSE,
'operator_id' => '',
'multiple' => FALSE,
'description' => '',
'required' => FALSE,
'label' => '',
'operator_limit_selection' => FALSE,
'operator' => '',
'identifier' => '',
'operator_list' => [],
'remember_roles' => [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID],
],
'entity_type' => 'media',
'value' => '',
'field' => 'status_extra',
'is_grouped' => FALSE,
'admin_label' => '',
'operator' => '=',
'table' => 'media_field_data',
'plugin_id' => 'media_status',
'id' => 'status_extra',
'group_type' => 'group',
];
$default_display->setOption('filters', $filters);
$view->save();
return t("The 'Published status or admin user' filter was added to the %label view.", [
'%label' => $view->storage->label(),
]);
}
}

View File

@ -38,10 +38,17 @@ class MediaLibraryFieldWidgetOpener implements MediaLibraryOpenerInterface {
public function checkAccess(MediaLibraryState $state, AccountInterface $account) {
$parameters = $state->getOpenerParameters() + ['entity_id' => NULL];
$process_result = function ($result) {
if ($result instanceof RefinableCacheableDependencyInterface) {
$result->addCacheContexts(['url.query_args']);
}
return $result;
};
// Forbid access if any of the required parameters are missing.
foreach (['entity_type_id', 'bundle', 'field_name'] as $key) {
if (empty($parameters[$key])) {
return AccessResult::forbidden("$key parameter is missing.")->addCacheableDependency($state);
return $process_result(AccessResult::forbidden("$key parameter is missing."));
}
}
@ -69,10 +76,7 @@ class MediaLibraryFieldWidgetOpener implements MediaLibraryOpenerInterface {
// If entity-level access is denied, there's no point in continuing.
if (!$entity_access->isAllowed()) {
if ($entity_access instanceof RefinableCacheableDependencyInterface) {
$entity_access->addCacheableDependency($state);
}
return $entity_access;
return $process_result($entity_access);
}
// If the entity has not been loaded, create it in memory now.
@ -96,11 +100,7 @@ class MediaLibraryFieldWidgetOpener implements MediaLibraryOpenerInterface {
}
$field_access = $access_handler->fieldAccess('edit', $field_definition, $account, $items, TRUE);
$access = $entity_access->andIf($field_access);
if ($access instanceof RefinableCacheableDependencyInterface) {
$access->addCacheableDependency($state);
}
return $access;
return $process_result($entity_access->andIf($field_access));
}
/**

View File

@ -3,8 +3,6 @@
namespace Drupal\media_library;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Site\Settings;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
@ -44,7 +42,7 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
* subject to change in minor releases. External code should not instantiate
* or extend this class.
*/
class MediaLibraryState extends ParameterBag implements CacheableDependencyInterface {
class MediaLibraryState extends ParameterBag {
/**
* {@inheritdoc}
@ -276,25 +274,4 @@ class MediaLibraryState extends ParameterBag implements CacheableDependencyInter
return $this->get('media_library_opener_parameters', []);
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return ['url.query_args'];
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return Cache::PERMANENT;
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return [];
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Drupal\Tests\media_library\Functional\Update;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
/**
* Tests the media library module updates for the view page display links.
*
* @group media_library
* @group legacy
*/
class MediaLibraryUpdateViewStatusExtraFilterTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
__DIR__ . '/../../../../../media/tests/fixtures/update/drupal-8.4.0-media_installed.php',
__DIR__ . '/../../../fixtures/update/drupal-8.7.2-media_library_installed.php',
];
}
/**
* Tests that the status extra filter is added to the media library view.
*
* @see media_library_post_update_add_status_extra_filter()
*/
public function testMediaLibraryViewStatusExtraFilter() {
$config = $this->config('views.view.media_library');
$this->assertNull($config->get('display.default.display_options.filters.status_extra'));
$this->runUpdates();
$config = $this->config('views.view.media_library');
$filter = $config->get('display.default.display_options.filters.status_extra');
$this->assertInternalType('array', $filter);
$this->assertSame('status_extra', $filter['field']);
$this->assertSame('media', $filter['entity_type']);
$this->assertSame('media_status', $filter['plugin_id']);
$this->assertSame('status_extra', $filter['id']);
$this->assertFalse($filter['exposed']);
}
}

View File

@ -0,0 +1,328 @@
<?php
namespace Drupal\Tests\media_library\FunctionalJavascript;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\file\Entity\File;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\media\Entity\Media;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
use Drupal\Tests\TestFileCreationTrait;
/**
* Tests media library integration with content moderation.
*
* @group media_library
*/
class ContentModerationTest extends WebDriverTestBase {
use ContentModerationTestTrait;
use EntityReferenceTestTrait;
use MediaTypeCreationTrait;
use TestFileCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'content_moderation',
'field',
'media',
'media_library',
'node',
'views',
];
/**
* User with the 'administer media' permission.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $userAdmin;
/**
* User with the 'view media' permission.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $userViewer;
/**
* User with the 'view media' and 'view own unpublished media' permissions.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $userViewOwnUnpublished;
/**
* User with the 'view media' and 'view any unpublished content' permissions.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $userViewAnyUnpublished;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create an image media type and article node type.
$this->createMediaType('image', ['id' => 'image']);
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
// Create a media reference field on articles.
$this->createEntityReferenceField(
'node',
'article',
'field_media',
'Media',
'media',
'default',
['target_bundles' => ['image']],
FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
);
// Add the media field to the form display.
$form_display = \Drupal::service('entity_display.repository')->getFormDisplay('node', 'article', 'default');
$form_display->setComponent('field_media', [
'type' => 'media_library_widget',
])->save();
// Configure the "Editorial" workflow to apply to image media.
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('media', 'image');
$workflow->save();
$image = File::create([
'uri' => $this->getTestFiles('image')[0]->uri,
]);
$image->setPermanent();
$image->save();
// Create a draft, published and archived media item.
$draft_media = Media::create([
'name' => 'Hoglet',
'bundle' => 'image',
'field_media_image' => $image,
'moderation_state' => 'draft',
]);
$draft_media->save();
$published_media = Media::create([
'name' => 'Panda',
'bundle' => 'image',
'field_media_image' => $image,
'moderation_state' => 'published',
]);
$published_media->save();
$archived_media = Media::create([
'name' => 'Mammoth',
'bundle' => 'image',
'field_media_image' => $image,
'moderation_state' => 'archived',
]);
$archived_media->save();
// Create some users for our tests. We want to check with user 1, a media
// administrator with 'administer media' permissions, a user that has the
// 'view media' permissions, a user that can 'view media' and 'view own
// unpublished media', and a user that has 'view media' and 'view any
// unpublished content' permissions.
$this->userAdmin = $this->drupalCreateUser([
'access administration pages',
'access content',
'access media overview',
'edit own article content',
'create article content',
'administer media',
]);
$this->userViewer = $this->drupalCreateUser([
'access administration pages',
'access content',
'access media overview',
'edit own article content',
'create article content',
'view media',
'create media',
]);
$this->userViewOwnUnpublished = $this->drupalCreateUser([
'access administration pages',
'access content',
'access media overview',
'edit own article content',
'create article content',
'view media',
'view own unpublished media',
'create media',
]);
$this->userViewAnyUnpublished = $this->drupalCreateUser([
'access administration pages',
'access content',
'access media overview',
'edit own article content',
'create article content',
'view media',
'create media',
'view any unpublished content',
]);
}
/**
* Tests the media library widget only shows published media.
*/
public function testAdministrationPage() {
// User 1 should be able to see all media items.
$this->drupalLogin($this->rootUser);
$this->drupalGet('admin/content/media');
$this->assertAllMedia();
// The media admin user should be able to see all media items.
$this->drupalLogin($this->userAdmin);
$this->drupalGet('admin/content/media');
$this->assertAllMedia();
// The media viewer user should be able to see only published media items.
$this->drupalLogin($this->userViewer);
$this->drupalGet('admin/content/media');
$this->assertOnlyPublishedMedia();
// The media viewer user that can also view its own unpublished media should
// also be able to see only published media items since it is not the owner
// of the created media items.
$this->drupalLogin($this->userViewOwnUnpublished);
$this->drupalGet('admin/content/media');
$this->assertOnlyPublishedMedia();
// When content moderation is enabled, a media viewer that can view any
// unpublished content should be able to see all media.
// @see content_moderation_entity_access()
$this->drupalLogin($this->userViewAnyUnpublished);
$this->drupalGet('admin/content/media');
$this->assertAllMedia();
// Assign all media to the user with the 'view own unpublished media'
// permission.
foreach (Media::loadMultiple() as $media) {
$media->setOwner($this->userViewOwnUnpublished);
$media->save();
}
// User 1 should still be able to see all media items.
$this->drupalLogin($this->rootUser);
$this->drupalGet('admin/content/media');
$this->assertAllMedia();
// The media admin user should still be able to see all media items.
$this->drupalLogin($this->userAdmin);
$this->drupalGet('admin/content/media');
$this->assertAllMedia();
// The media viewer user should still be able to see only published media
// items.
$this->drupalLogin($this->userViewer);
$this->drupalGet('admin/content/media');
$this->assertOnlyPublishedMedia();
// The media viewer user that can also view its own unpublished media
// should now be able to see all media items since it is the owner of the
// created media items.
$this->drupalLogin($this->userViewOwnUnpublished);
$this->drupalGet('admin/content/media');
$this->assertAllMedia();
// The media viewer that can view any unpublished content should still be
// able to see all media.
$this->drupalLogin($this->userViewAnyUnpublished);
$this->drupalGet('admin/content/media');
$this->assertAllMedia();
}
/**
* Tests the media library widget only shows published media.
*/
public function testWidget() {
$assert_session = $this->assertSession();
// All users should only be able to see published media items.
$this->drupalLogin($this->rootUser);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userAdmin);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userViewer);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userViewOwnUnpublished);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userViewAnyUnpublished);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
// After we change the owner to the user with 'view own unpublished media'
// permission, all users should still only be able to see published media.
foreach (Media::loadMultiple() as $media) {
$media->setOwner($this->userViewOwnUnpublished);
$media->save();
}
$this->drupalLogin($this->rootUser);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userAdmin);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userViewer);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userViewOwnUnpublished);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
$this->drupalLogin($this->userViewAnyUnpublished);
$this->drupalGet('node/add/article');
$assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click();
$assert_session->assertWaitOnAjaxRequest();
$this->assertOnlyPublishedMedia();
}
/**
* Asserts all media items are visible.
*/
protected function assertAllMedia() {
$assert_session = $this->assertSession();
$assert_session->pageTextContains('Hoglet');
$assert_session->pageTextContains('Panda');
$assert_session->pageTextContains('Mammoth');
}
/**
* Asserts only published media items are visible.
*/
protected function assertOnlyPublishedMedia() {
$assert_session = $this->assertSession();
$assert_session->pageTextNotContains('Hoglet');
$assert_session->pageTextContains('Panda');
$assert_session->pageTextNotContains('Mammoth');
}
}