diff --git a/core/modules/media/src/MediaAccessControlHandler.php b/core/modules/media/src/MediaAccessControlHandler.php index f753e7f..15ba505 100644 --- a/core/modules/media/src/MediaAccessControlHandler.php +++ b/core/modules/media/src/MediaAccessControlHandler.php @@ -3,9 +3,12 @@ namespace Drupal\media; use Drupal\Core\Access\AccessResult; +use Drupal\field\Entity\FieldConfig; +use Drupal\file\Entity\File; use Drupal\Core\Entity\EntityAccessControlHandler; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Session\AccountInterface; +use Drupal\node\Entity\Node; /** * Defines an access control handler for the media entity. @@ -23,10 +26,68 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter $is_owner = ($account->id() && $account->id() === $entity->getOwnerId()); switch ($operation) { case 'view': - return AccessResult::allowedIf($account->hasPermission('view media') && $entity->isPublished()) - ->cachePerPermissions() - ->addCacheableDependency($entity); + /** + * @TODO: make this more generic for other than default reference + * and other entities that reference media + */ + if (isset($entity->field_media_image->target_id)) { + $file = File::load($entity->field_media_image->target_id); + /** + * Core File class lacks a public function to get file storage; there's only protected File::$isPublic flag + */ + if (substr($file->getFileUri(), 0, 10) === "private://") { + /** + * get file usage + * @todo: find a way to replace deprecated db_select; maybe in Drupal 9? + */ + $query = db_select('file_usage', 'fu') + ->fields('fu', ['id']) + ->condition('fu.fid', $file->id()); + $ids = $query->execute()->fetchCol(); + + /** + * by default set access forbidden for private files + */ + $result = AccessResult::forbidden(); + /** + * get all possible reference field for media + **/ + $bundle_fields = []; + $contentTypes = \Drupal::service('entity.manager')->getStorage('node_type')->loadMultiple(); + foreach ($contentTypes as $contentType) { + $bundle_fields[$contentType->id()] = \Drupal::getContainer()->get('entity_field.manager')->getFieldDefinitions('node', $contentType->id()); + } + $media_fields = []; + foreach ($bundle_fields as $bundle => $field) { + foreach ($field as $config) { + if ( $config->getSetting('target_type') === 'media' ) { + $media_fields[] = $config->getName(); + } + } + } + + // loop through nodes from reference field and set access allowed if any node is allowed + foreach ($media_fields as $media_field) { + foreach ($ids as $idx => $id) { + $query = \Drupal::entityQuery('node') + ->condition($media_field, $id); + $nodes = $query->execute(); + $checknodes = Node::loadMultiple($nodes); + + foreach ($checknodes as $checknode) { + $result = parent::access($checknode, $operation, $account, TRUE); + } + } + } + return $result; + } + else { + return AccessResult::allowedIf($account->hasPermission('view media') && $entity->isPublished()) + ->cachePerPermissions() + ->addCacheableDependency($entity); + } + } case 'update': if ($account->hasPermission('update any media')) { return AccessResult::allowed()->cachePerPermissions();