3 namespace Drupal\Tests\media\Functional\Rest;
5 use Drupal\Component\Utility\NestedArray;
7 use Drupal\file\Entity\File;
8 use Drupal\media\Entity\Media;
9 use Drupal\media\Entity\MediaType;
10 use Drupal\rest\RestResourceConfigInterface;
11 use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
12 use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
13 use Drupal\user\Entity\Role;
14 use Drupal\user\Entity\User;
15 use Drupal\user\RoleInterface;
16 use GuzzleHttp\RequestOptions;
18 abstract class MediaResourceTestBase extends EntityResourceTestBase {
20 use BcTimestampNormalizerUnixTestTrait;
25 public static $modules = ['media'];
30 protected static $entityTypeId = 'media';
33 * @var \Drupal\media\MediaInterface
40 protected static $patchProtectedFieldNames = [
47 protected function setUpAuthorization($method) {
50 $this->grantPermissionsToTestedRole(['view media']);
54 $this->grantPermissionsToTestedRole(['create camelids media', 'access content']);
58 $this->grantPermissionsToTestedRole(['edit any camelids media']);
59 // @todo Remove this in https://www.drupal.org/node/2824851.
60 $this->grantPermissionsToTestedRole(['access content']);
64 $this->grantPermissionsToTestedRole(['delete any camelids media']);
72 protected function createEntity() {
73 if (!MediaType::load('camelids')) {
74 // Create a "Camelids" media type.
75 $media_type = MediaType::create([
78 'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
82 // Create the source field.
83 $source_field = $media_type->getSource()->createSourceField($media_type);
84 $source_field->getFieldStorageDefinition()->save();
85 $source_field->save();
87 ->set('source_configuration', [
88 'source_field' => $source_field->getName(),
93 // Create a file to upload.
94 $file = File::create([
95 'uri' => 'public://llama.txt',
97 $file->setPermanent();
100 // Create a "Llama" media item.
101 $media = Media::create([
102 'bundle' => 'camelids',
103 'field_media_file' => [
104 'target_id' => $file->id(),
110 ->setCreatedTime(123456789)
111 ->setOwnerId(static::$auth ? $this->account->id() : 0)
112 ->setRevisionUserId(static::$auth ? $this->account->id() : 0)
121 protected function getExpectedNormalizedEntity() {
122 $file = File::load(1);
123 $thumbnail = File::load(2);
124 $author = User::load($this->entity->getOwnerId());
133 'value' => $this->entity->uuid(),
148 'target_id' => 'camelids',
149 'target_type' => 'media_type',
150 'target_uuid' => MediaType::load('camelids')->uuid(),
158 'field_media_file' => [
160 'description' => NULL,
162 'target_id' => (int) $file->id(),
163 'target_type' => 'file',
164 'target_uuid' => $file->uuid(),
165 'url' => $file->url(),
173 'target_id' => (int) $thumbnail->id(),
174 'target_type' => 'file',
175 'target_uuid' => $thumbnail->uuid(),
177 'url' => $thumbnail->url(),
186 $this->formatExpectedTimestampItemValues(123456789),
189 $this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
191 'revision_created' => [
192 $this->formatExpectedTimestampItemValues((int) $this->entity->getRevisionCreationTime()),
194 'default_langcode' => [
201 'target_id' => (int) $author->id(),
202 'target_type' => 'user',
203 'target_uuid' => $author->uuid(),
204 'url' => base_path() . 'user/' . $author->id(),
209 'target_id' => (int) $author->id(),
210 'target_type' => 'user',
211 'target_uuid' => $author->uuid(),
212 'url' => base_path() . 'user/' . $author->id(),
215 'revision_log_message' => [],
216 'revision_translation_affected' => [
227 protected function getNormalizedPostEntity() {
231 'target_id' => 'camelids',
236 'value' => 'Dramallama',
239 'field_media_file' => [
241 'description' => NULL,
252 protected function getNormalizedPatchEntity() {
253 return array_diff_key($this->getNormalizedPostEntity(), ['field_media_file' => TRUE]);
259 protected function getExpectedUnauthorizedAccessMessage($method) {
260 if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
261 return parent::getExpectedUnauthorizedAccessMessage($method);
266 return "The 'view media' permission is required and the media item must be published.";
269 return "The following permissions are required: 'administer media' OR 'create media' OR 'create camelids media'.";
272 return "The following permissions are required: 'update any media' OR 'update own media' OR 'camelids: edit any media' OR 'camelids: edit own media'.";
275 return "The following permissions are required: 'delete any media' OR 'delete own media' OR 'camelids: delete any media' OR 'camelids: delete own media'.";
278 return parent::getExpectedUnauthorizedAccessMessage($method);
285 public function testPost() {
286 $file_storage = $this->container->get('entity_type.manager')->getStorage('file');
288 // Step 1: upload file, results in File entity marked temporary.
290 $file = $file_storage->loadUnchanged(3);
291 $this->assertTrue($file->isTemporary());
292 $this->assertFalse($file->isPermanent());
294 // Step 2: create Media entity using the File, makes File entity permanent.
296 $file = $file_storage->loadUnchanged(3);
297 $this->assertFalse($file->isTemporary());
298 $this->assertTrue($file->isPermanent());
302 * This duplicates some of the 'file_upload' REST resource plugin test
303 * coverage, to be able to test it on a concrete use case.
305 protected function uploadFile() {
306 // Enable the 'file_upload' REST resource for the current format + auth.
307 $this->resourceConfigStorage->create([
308 'id' => 'file.upload',
309 'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
311 'methods' => ['POST'],
312 'formats' => [static::$format],
313 'authentication' => isset(static::$auth) ? [static::$auth] : [],
317 $this->refreshTestStateAfterRestConfigChange();
319 $this->initAuthentication();
321 // POST to create a File entity.
322 $url = Url::fromUri('base:file/upload/media/camelids/field_media_file');
323 $url->setOption('query', ['_format' => static::$format]);
324 $request_options = [];
325 $request_options[RequestOptions::HEADERS] = [
326 // Set the required (and only accepted) content type for the request.
327 'Content-Type' => 'application/octet-stream',
328 // Set the required Content-Disposition header for the file name.
329 'Content-Disposition' => 'file; filename="drupal rocks 🤘.txt"',
331 $request_options[RequestOptions::BODY] = 'Drupal is the best!';
332 $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('POST'));
333 $response = $this->request('POST', $url, $request_options);
334 $this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
336 // Grant necessary permission, retry.
337 $this->grantPermissionsToTestedRole(['create camelids media']);
338 $response = $this->request('POST', $url, $request_options);
339 $this->assertSame(201, $response->getStatusCode());
340 $expected = $this->getExpectedNormalizedFileEntity();
341 static::recursiveKSort($expected);
342 $actual = $this->serializer->decode((string) $response->getBody(), static::$format);
343 static::recursiveKSort($actual);
344 $this->assertSame($expected, $actual);
346 // To still run the complete test coverage for POSTing a Media entity, we
347 // must revoke the additional permissions that we granted.
348 $role = Role::load(static::$auth ? RoleInterface::AUTHENTICATED_ID : RoleInterface::AUTHENTICATED_ID);
349 $role->revokePermission('create camelids media');
350 $role->trustData()->save();
354 * Gets the expected file entity.
357 * The expected normalized data array.
359 protected function getExpectedNormalizedFileEntity() {
360 $file = File::load(3);
361 $owner = static::$auth ? $this->account : User::load(0);
371 'value' => $file->uuid(),
381 'target_id' => (int) $owner->id(),
382 'target_type' => 'user',
383 'target_uuid' => $owner->uuid(),
384 'url' => base_path() . 'user/' . $owner->id(),
389 'value' => 'drupal rocks 🤘.txt',
394 'value' => 'public://' . date('Y-m') . '/drupal rocks 🤘.txt',
395 'url' => base_path() . $this->siteDirectory . '/files/' . date('Y-m') . '/drupal%20rocks%20%F0%9F%A4%98.txt',
400 'value' => 'text/plain',
414 $this->formatExpectedTimestampItemValues($file->getCreatedTime()),
417 $this->formatExpectedTimestampItemValues($file->getChangedTime()),
425 protected function getExpectedUnauthorizedAccessCacheability() {
426 // @see \Drupal\media\MediaAccessControlHandler::checkAccess()
427 return parent::getExpectedUnauthorizedAccessCacheability()
428 ->addCacheTags(['media:1']);