From c1937c051b510c1d115da096a5c3afe1df7be1d3 Mon Sep 17 00:00:00 2001 From: dannylamb Date: Wed, 7 Mar 2018 15:46:39 -0400 Subject: [PATCH] Add binary to node (#76) * First pass at adding media directly to nodes as binaries * Tests. Coding standards * Refined access checking and updated tests * README update --- README.md | 12 + islandora.routing.yml | 10 + islandora.services.yml | 3 +- src/Controller/MediaSourceController.php | 139 +++++++++-- src/MediaSource/MediaSourceService.php | 217 ++++++++++++----- tests/src/Functional/AddMediaToNodeTest.php | 223 ++++++++++++++++++ ...llerTest.php => MediaSourceUpdateTest.php} | 10 +- 7 files changed, 528 insertions(+), 86 deletions(-) create mode 100644 tests/src/Functional/AddMediaToNodeTest.php rename tests/src/Functional/{MediaSourceControllerTest.php => MediaSourceUpdateTest.php} (92%) diff --git a/README.md b/README.md index 6758cb5c..bb50b47d 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,18 @@ Example usage: curl -u admin:islandora -v -X PUT -H 'Content-Type: image/png' -H 'Content-Disposition: attachment; filename="my_image.png"' --data-binary @my_image.png localhost:8000/media/1/source ``` +### /node/{node}/media/{field}/add/{bundle} + +You can POST content to the `/node/{node}/media/{field}/add/{bundle}` endpoint to create a new Media of the specified bundle +using the POST body. It will be associated with the specified Node using the field from the route. The `Content-Type` +header is expected, as well as a `Content-Disposition` header of the form `attachment; filename="your_filename"` to indicate +the name to give the file. Requests with empty bodies or no `Content-Length` header will be rejected. + +Example usage: +``` +curl -v -u admin:islandora -H "Content-Type: image/jpeg" -H "Content-Disposition: attachment; filename=\"test.jpeg\"" --data-binary @test.jpeg http://localhost:8000/node/1/media/my_media_field/add/my_media_bundle +``` + ## Maintainers Current maintainers: diff --git a/islandora.routing.yml b/islandora.routing.yml index 52c089b8..615232ac 100644 --- a/islandora.routing.yml +++ b/islandora.routing.yml @@ -33,3 +33,13 @@ islandora.media_source_update: _permission: 'update media' options: _auth: ['basic_auth', 'cookie', 'jwt_auth'] + +islandora.media_source_add_to_node: + path: '/node/{node}/media/{field}/add/{bundle}' + defaults: + _controller: '\Drupal\islandora\Controller\MediaSourceController::addToNode' + methods: [POST] + requirements: + _custom_access: '\Drupal\islandora\Controller\MediaSourceController::addToNodeAccess' + options: + _auth: ['basic_auth', 'cookie', 'jwt_auth'] diff --git a/islandora.services.yml b/islandora.services.yml index 53f02e03..df4ce606 100644 --- a/islandora.services.yml +++ b/islandora.services.yml @@ -41,5 +41,4 @@ services: - { name: 'context_provider' } islandora.media_source_service: class: Drupal\islandora\MediaSource\MediaSourceService - factory: ['Drupal\islandora\MediaSource\MediaSourceService', create] - arguments: ['@entity_type.manager', '@stream_wrapper_manager'] + arguments: ['@entity_type.manager', '@current_user', '@stream_wrapper_manager', '@token'] diff --git a/src/Controller/MediaSourceController.php b/src/Controller/MediaSourceController.php index fc677ab4..83f6be01 100644 --- a/src/Controller/MediaSourceController.php +++ b/src/Controller/MediaSourceController.php @@ -2,9 +2,13 @@ namespace Drupal\islandora\Controller; +use Drupal\Core\Access\AccessResult; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Database\Connection; +use Drupal\Core\Routing\RouteMatch; +use Drupal\Core\Session\AccountInterface; use Drupal\media_entity\MediaInterface; +use Drupal\node\NodeInterface; use Drupal\islandora\MediaSource\MediaSourceService; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -79,33 +83,34 @@ class MediaSourceController extends ControllerBase { * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function put(MediaInterface $media, Request $request) { - // Since we update both the Media and its File, do this in a transaction. - $transaction = $this->database->startTransaction(); + $content_type = $request->headers->get('Content-Type', ""); - try { - $content_type = $request->headers->get('Content-Type', ""); + if (empty($content_type)) { + throw new BadRequestHttpException("Missing Content-Type header"); + } - if (empty($content_type)) { - throw new BadRequestHttpException("Missing Content-Type header"); - } + $content_length = $request->headers->get('Content-Length', 0); - $content_length = $request->headers->get('Content-Length', 0); + if ($content_length <= 0) { + throw new BadRequestHttpException("Missing Content-Length"); + } - if ($content_length <= 0) { - throw new BadRequestHttpException("Missing Content-Length"); - } + $content_disposition = $request->headers->get('Content-Disposition', ""); - $content_disposition = $request->headers->get('Content-Disposition', ""); + if (empty($content_disposition)) { + throw new BadRequestHttpException("Missing Content-Disposition header"); + } - if (empty($content_disposition)) { - throw new BadRequestHttpException("Missing Content-Disposition header"); - } + $matches = []; + if (!preg_match('/attachment; filename="(.*)"/', $content_disposition, $matches)) { + throw new BadRequestHttpException("Malformed Content-Disposition header"); + } + $filename = $matches[1]; - $matches = []; - if (!preg_match('/attachment; filename="(.*)"/', $content_disposition, $matches)) { - throw new BadRequestHttpException("Malformed Content-Disposition header"); - } - $filename = $matches[1]; + // Since we update both the Media and its File, do this in a transaction. + $transaction = $this->database->startTransaction(); + + try { $this->service->updateSourceField( $media, @@ -127,4 +132,98 @@ class MediaSourceController extends ControllerBase { } } + /** + * Adds a Media to a Node using the specified field. + * + * @param \Drupal\node\NodeInterface $node + * The Node to which you want to add a Media. + * @param string $field + * Name of field on Node to reference Media. + * @param string $bundle + * Name of bundle for Media to create. + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * + * @return \Symfony\Component\HttpFoundation\Response + * 201 on success with a Location link header. + * + * @throws \Symfony\Component\HttpKernel\Exception\HttpException + */ + public function addToNode( + NodeInterface $node, + $field, + $bundle, + Request $request + ) { + $content_type = $request->headers->get('Content-Type', ""); + + if (empty($content_type)) { + throw new BadRequestHttpException("Missing Content-Type header"); + } + + $content_length = $request->headers->get('Content-Length', 0); + + if ($content_length <= 0) { + throw new BadRequestHttpException("Missing Content-Length"); + } + + $content_disposition = $request->headers->get('Content-Disposition', ""); + + if (empty($content_disposition)) { + throw new BadRequestHttpException("Missing Content-Disposition header"); + } + + $matches = []; + if (!preg_match('/attachment; filename="(.*)"/', $content_disposition, $matches)) { + throw new BadRequestHttpException("Malformed Content-Disposition header"); + } + $filename = $matches[1]; + + // Since we create both a Media and its File, AND update a node, + // start a transaction. + $transaction = $this->database->startTransaction(); + + try { + $media = $this->service->addToNode( + $node, + $field, + $bundle, + $request->getContent(TRUE), + $content_type, + $content_length, + $filename + ); + + $response = new Response("", 201); + $response->headers->set("Location", $media->url('canonical', ['absolute' => TRUE])); + return $response; + } + catch (HttpException $e) { + $transaction->rollBack(); + throw $e; + } + catch (\Exception $e) { + $transaction->rollBack(); + throw new HttpException(500, $e->getMessage()); + } + } + + /** + * Checks for permissions to update a node and create media. + * + * @param \Drupal\Core\Session\AccountInterface $account + * Account for user making the request. + * @param \Drupal\Core\Routing\RouteMatch $route_match + * Route match to get Node from url params. + * + * @return \Drupal\Core\Access\AccessResultInterface + * Access result. + */ + public function addToNodeAccess(AccountInterface $account, RouteMatch $route_match) { + // We'd have 404'd already if node didn't exist, so no need to check. + // Just hack it out of the route match. + $node = $route_match->getParameter('node'); + return AccessResult::allowedIf($node->access('update', $account) && $account->hasPermission('create media')); + } + } diff --git a/src/MediaSource/MediaSourceService.php b/src/MediaSource/MediaSourceService.php index 4e830a3c..885e6bea 100644 --- a/src/MediaSource/MediaSourceService.php +++ b/src/MediaSource/MediaSourceService.php @@ -2,11 +2,15 @@ namespace Drupal\islandora\MediaSource; -use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Component\Render\PlainTextOutput; use Drupal\Core\Entity\EntityTypeManager; +use Drupal\Core\Session\AccountInterface; use Drupal\Core\StreamWrapper\StreamWrapperManager; +use Drupal\Core\Utility\Token; use Drupal\media_entity\MediaInterface; +use Drupal\node\NodeInterface; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\ConflictHttpException; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -16,18 +20,18 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class MediaSourceService { /** - * Media bundle storage. + * The entity type manager. * - * @var \Drupal\Core\Entity\EntityStorageInterface + * @var \Drupal\Core\Entity\EntityTypeManager */ - protected $mediaBundleStorage; + protected $entityTypeManager; /** - * Field config storage. + * Current user. * - * @var \Drupal\Core\Entity\EntityStorageInterface + * @var \Drupal\Core\Session\AccountInterface */ - protected $fieldConfigStorage; + protected $account; /** * Stream wrapper manager. @@ -37,45 +41,34 @@ class MediaSourceService { protected $streamWrapperManager; /** - * Constructor. + * Token service. * - * @param \Drupal\Core\Entity\EntityStorageInterface $media_bundle_storage - * Media bundle storage. - * @param \Drupal\Core\Entity\EntityStorageInterface $field_config_storage - * Field config storage. - * @param \Drupal\Core\StreamWrapper\StreamWrapperManager $stream_wrapper_manager - * Stream wrapper manager. + * @var \Drupal\Core\Utility\Token */ - public function __construct( - EntityStorageInterface $media_bundle_storage, - EntityStorageInterface $field_config_storage, - StreamWrapperManager $stream_wrapper_manager - ) { - $this->mediaBundleStorage = $media_bundle_storage; - $this->fieldConfigStorage = $field_config_storage; - $this->streamWrapperManager = $stream_wrapper_manager; - } + protected $token; /** - * Factory. + * Constructor. * * @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager * The entity type manager. + * @param \Drupal\Core\Session\AccountInterface $account + * The current user. * @param \Drupal\Core\StreamWrapper\StreamWrapperManager $stream_wrapper_manager * Stream wrapper manager. - * - * @return \Drupal\islandora\MediaSource\MediaSourceService - * MediaSourceService instance. + * @param \Drupal\Core\Utility\Token $token + * Token service. */ - public static function create( + public function __construct( EntityTypeManager $entity_type_manager, - StreamWrapperManager $stream_wrapper_manager + AccountInterface $account, + StreamWrapperManager $stream_wrapper_manager, + Token $token ) { - return new static( - $entity_type_manager->getStorage('media_bundle'), - $entity_type_manager->getStorage('field_config'), - $stream_wrapper_manager - ); + $this->entityTypeManager = $entity_type_manager; + $this->account = $account; + $this->streamWrapperManager = $stream_wrapper_manager; + $this->token = $token; } /** @@ -88,9 +81,12 @@ class MediaSourceService { * Field name if it exists in configuration, else NULL. */ public function getSourceFieldName($media_bundle) { - $bundle = $this->mediaBundleStorage->load($media_bundle); - $type_configuration = $bundle->getTypeConfiguration(); + $bundle = $this->entityTypeManager->getStorage('media_bundle')->load($media_bundle); + if (!$bundle) { + throw new NotFoundHttpException("Bundle $media_bundle does not exist"); + } + $type_configuration = $bundle->getTypeConfiguration(); if (!isset($type_configuration['source_field'])) { return NULL; } @@ -98,27 +94,6 @@ class MediaSourceService { return $type_configuration['source_field']; } - /** - * Gets a list of valid file extensions for a field. - * - * @param string $entity_type - * Entity type (node, media, etc...). - * @param string $bundle - * Bundle the field belongs to. - * @param string $field - * The field whose valid extensions you're looking for. - * - * @return string - * Space delimited string containing valid extensions. - */ - public function getFileFieldExtensions($entity_type, $bundle, $field) { - $field_config = $this->fieldConfigStorage->load("$entity_type.$bundle.$field"); - if (!$field_config) { - return ""; - } - return $field_config->getSetting('file_extensions'); - } - /** * Updates a media's source field with the supplied resource. * @@ -159,9 +134,9 @@ class MediaSourceService { $file->setSize($content_length); // Validate file extension. - $entity_type = $media->getEntityTypeId(); $bundle = $media->bundle(); - $valid_extensions = $this->getFileFieldExtensions($entity_type, $bundle, $source_field); + $source_field_config = $this->entityTypeManager->getStorage('field_config')->load("media.$bundle.$source_field"); + $valid_extensions = $source_field_config->getSetting('file_extensions'); $errors = file_validate_extensions($file, $valid_extensions); if (!empty($errors)) { @@ -193,4 +168,128 @@ class MediaSourceService { $media->save(); } + /** + * Creates a new Media using the provided resource, adding it to a Node. + * + * @param \Drupal\node\NodeInterface $node + * The node to reference the newly created Media. + * @param string $field + * Name of field on the Node to reference the Media. + * @param string $bundle + * Bundle of Media to create. + * @param resource $resource + * New file contents as a resource. + * @param string $mimetype + * New mimetype of contents. + * @param string $content_length + * New size of contents. + * @param string $filename + * New filename for contents. + * + * @throws HttpException + */ + public function addToNode( + NodeInterface $node, + $field, + $bundle, + $resource, + $mimetype, + $content_length, + $filename + ) { + if (!$node->hasField($field)) { + throw new NotFoundHttpException(); + } + + if (!$node->get($field)->isEmpty()) { + throw new ConflictHttpException(); + } + + // Get the source field for the media type. + $source_field = $this->getSourceFieldName($bundle); + if (empty($source_field)) { + throw new NotFoundHttpException("Source field not set for {$media->bundle()} media"); + } + + // Load its config to get file extensions and upload path. + $source_field_config = $this->entityTypeManager->getStorage('field_config')->load("media.$bundle.$source_field"); + + // Construct the destination uri. + $directory = $source_field_config->getSetting('file_directory'); + $directory = trim($directory, '/'); + $directory = PlainTextOutput::renderFromHtml($this->token->replace($directory, ['node' => $node])); + $scheme = file_default_scheme(); + $destination_directory = "$scheme://$directory"; + $destination = "$destination_directory/$filename"; + + // Construct the File. + $file = $this->entityTypeManager->getStorage('file')->create([ + 'uid' => $this->account->id(), + 'uri' => $destination, + 'filename' => $filename, + 'filemime' => $mimetype, + 'filesize' => $content_length, + 'status' => FILE_STATUS_PERMANENT, + ]); + + // Validate file extension. + $source_field_config = $this->entityTypeManager->getStorage('field_config')->load("media.$bundle.$source_field"); + $valid_extensions = $source_field_config->getSetting('file_extensions'); + $errors = file_validate_extensions($file, $valid_extensions); + + if (!empty($errors)) { + throw new BadRequestHttpException("Invalid file extension. Valid types are $valid_extensions"); + } + + if (!file_prepare_directory($destination_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { + throw new HttpException(500, "The destination directory does not exist, could not be created, or is not writable"); + } + + // Copy the contents over using streams. + $uri = $file->getFileUri(); + $file_stream_wrapper = $this->streamWrapperManager->getViaUri($uri); + $path = ""; + $file_stream_wrapper->stream_open($uri, 'w', STREAM_REPORT_ERRORS, $path); + $file_stream = $file_stream_wrapper->stream_cast(STREAM_CAST_AS_STREAM); + if (stream_copy_to_stream($resource, $file_stream) === FALSE) { + throw new HttpException(500, "The file could not be copied into $uri"); + } + + $file->save(); + + // Construct the Media. + $media_struct = [ + 'bundle' => $bundle, + 'uid' => $this->account->id(), + 'name' => $filename, + "$source_field" => [ + 'target_id' => $file->id(), + ], + ]; + if ($source_field_config->getSetting('alt_field') && $source_field_config->getSetting('alt_field_required')) { + $media_struct[$source_field]['alt'] = $filename; + } + $media = $this->entityTypeManager->getStorage('media')->create($media_struct); + + // Set fields provided by type plugin and mapped in bundle configuration + // for the media. + foreach ($media->bundle->entity->field_map as $source => $destination) { + if ($media->hasField($destination) && $value = $media->getType()->getField($media, $source)) { + $media->set($destination, $value); + } + } + + // Flush the image cache for the image so thumbnails get regenerated. + image_path_flush($uri); + + $media->save(); + + // Update the Node. + $node->get($field)->appendItem($media); + $node->save(); + + // Return the created media. + return $media; + } + } diff --git a/tests/src/Functional/AddMediaToNodeTest.php b/tests/src/Functional/AddMediaToNodeTest.php new file mode 100644 index 00000000..08aa3568 --- /dev/null +++ b/tests/src/Functional/AddMediaToNodeTest.php @@ -0,0 +1,223 @@ +container->get('entity_type.manager')->getStorage('node_type')->create([ + 'type' => 'test_type_with_reference', + 'label' => 'Test Type With Reference', + ]); + $test_type_with_reference->save(); + + // Add two entity reference fields. + // One for nodes and one for media. + $this->createEntityReferenceField('node', 'test_type_with_reference', 'field_media', 'Media Entity', 'media', 'default', [], 2); + + $this->referencer = $this->container->get('entity_type.manager')->getStorage('node')->create([ + 'type' => 'test_type_with_reference', + 'title' => 'Referencer', + ]); + $this->referencer->save(); + } + + /** + * @covers \Drupal\islandora\Controller\MediaSourceController::addToNode + */ + public function testAddMediaToNode() { + // Hack out the guzzle client. + $client = $this->getSession()->getDriver()->getClient()->getClient(); + + $add_to_node_url = Url::fromRoute( + 'islandora.media_source_add_to_node', + [ + 'node' => $this->referencer->id(), + 'field' => 'field_media', + 'bundle' => 'tn', + ] + ) + ->setAbsolute() + ->toString(); + + $bad_node_url = Url::fromRoute( + 'islandora.media_source_add_to_node', + [ + 'node' => 123456, + 'field' => 'field_media', + 'bundle' => 'tn', + ] + ) + ->setAbsolute() + ->toString(); + + $image = file_get_contents(__DIR__ . '/../../static/test.jpeg'); + + // Test different permissions scenarios. + $options = [ + 'http_errors' => FALSE, + 'headers' => [ + 'Content-Type' => 'image/jpeg', + 'Content-Disposition' => 'attachment; filename="test.jpeg"', + ], + 'body' => $image, + ]; + + // 403 if you don't have permissions to update the node. + $account = $this->drupalCreateUser([ + 'access content', + 'create media', + ]); + $this->drupalLogin($account); + $options['auth'] = [$account->getUsername(), $account->pass_raw]; + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 403, "Expected 403, received {$response->getStatusCode()}"); + + // Bad node URL should return 404, regardless of permissions. + // Just making sure our custom access function doesn't obfuscate responses. + $response = $client->request('POST', $bad_node_url, $options); + $this->assertTrue($response->getStatusCode() == 404, "Expected 404, received {$response->getStatusCode()}"); + + // 403 if you don't have permissions to create Media. + $account = $this->drupalCreateUser([ + 'bypass node access', + ]); + $this->drupalLogin($account); + $options['auth'] = [$account->getUsername(), $account->pass_raw]; + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 403, "Expected 403, received {$response->getStatusCode()}"); + + // Now with proper credentials, test responses given to malformed requests. + $account = $this->drupalCreateUser([ + 'bypass node access', + 'create media', + ]); + $this->drupalLogin($account); + + // Request without Content-Type header should fail with 400. + $options = [ + 'auth' => [$account->getUsername(), $account->pass_raw], + 'http_errors' => FALSE, + 'headers' => [ + 'Content-Disposition' => 'attachment; filename="test.jpeg"', + ], + 'body' => $image, + ]; + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 400, "Expected 400, received {$response->getStatusCode()}"); + + // Request without Content-Disposition header should fail with 400. + $options = [ + 'auth' => [$account->getUsername(), $account->pass_raw], + 'http_errors' => FALSE, + 'headers' => [ + 'Content-Type' => 'image/jpeg', + ], + 'body' => $image, + ]; + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 400, "Expected 400, received {$response->getStatusCode()}"); + + // Request with malformed Content-Disposition header should fail with 400. + $options = [ + 'auth' => [$account->getUsername(), $account->pass_raw], + 'http_errors' => FALSE, + 'headers' => [ + 'Content-Type' => 'image/jpeg', + 'Content-Disposition' => 'garbage; filename="test.jpeg"', + ], + 'body' => $image, + ]; + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 400, "Expected 400, received {$response->getStatusCode()}"); + + // Request without body should fail with 400. + $options = [ + 'auth' => [$account->getUsername(), $account->pass_raw], + 'http_errors' => FALSE, + 'headers' => [ + 'Content-Type' => 'image/jpeg', + 'Content-Disposition' => 'attachment; filename="test.jpeg"', + ], + ]; + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 400, "Expected 400, received {$response->getStatusCode()}"); + + // Test properly formed requests with bad parameters in the route. + $options = [ + 'auth' => [$account->getUsername(), $account->pass_raw], + 'http_errors' => FALSE, + 'headers' => [ + 'Content-Type' => 'image/jpeg', + 'Content-Disposition' => 'attachment; filename="test.jpeg"', + ], + 'body' => $image, + ]; + + // Bad node id should return 404 even with proper permissions. + $response = $client->request('POST', $bad_node_url, $options); + $this->assertTrue($response->getStatusCode() == 404, "Expected 404, received {$response->getStatusCode()}"); + + // Bad field name in url should return 404. + $bad_field_url = Url::fromRoute( + 'islandora.media_source_add_to_node', + [ + 'node' => $this->referencer->id(), + 'field' => 'field_garbage', + 'bundle' => 'tn', + ] + ) + ->setAbsolute() + ->toString(); + $response = $client->request('POST', $bad_field_url, $options); + $this->assertTrue($response->getStatusCode() == 404, "Expected 404, received {$response->getStatusCode()}"); + + // Bad bundle name in url should return 404. + $bad_bundle_url = Url::fromRoute( + 'islandora.media_source_add_to_node', + [ + 'node' => $this->referencer->id(), + 'field' => 'field_media', + 'bundle' => 'garbage', + ] + ) + ->setAbsolute() + ->toString(); + $response = $client->request('POST', $bad_bundle_url, $options); + $this->assertTrue($response->getStatusCode() == 404, "Expected 404, received {$response->getStatusCode()}"); + + // Should be successful with proper url, options, and permissions. + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 201, "Expected 201, received {$response->getStatusCode()}"); + $this->assertTrue(!empty($response->getHeader("Location")), "Response must include Location header"); + + // Should fail with 409 if Node already references a media using the field + // (i.e. the previous call was successful). + $response = $client->request('POST', $add_to_node_url, $options); + $this->assertTrue($response->getStatusCode() == 409, "Expected 409, received {$response->getStatusCode()}"); + } + +} diff --git a/tests/src/Functional/MediaSourceControllerTest.php b/tests/src/Functional/MediaSourceUpdateTest.php similarity index 92% rename from tests/src/Functional/MediaSourceControllerTest.php rename to tests/src/Functional/MediaSourceUpdateTest.php index c44701df..99d93e75 100644 --- a/tests/src/Functional/MediaSourceControllerTest.php +++ b/tests/src/Functional/MediaSourceUpdateTest.php @@ -9,7 +9,7 @@ use Drupal\Core\Url; * * @group islandora */ -class MediaSourceControllerTest extends IslandoraFunctionalTestBase { +class MediaSourceUpdateTest extends IslandoraFunctionalTestBase { /** * {@inheritdoc} @@ -99,7 +99,7 @@ class MediaSourceControllerTest extends IslandoraFunctionalTestBase { 'http_errors' => FALSE, 'headers' => [ 'Content-Type' => 'image/jpeg', - 'Content-Disposition' => 'attachment; garbage="test.jpeg"', + 'Content-Disposition' => 'garbage; filename="test.jpeg"', ], 'body' => $image, ]; @@ -145,9 +145,9 @@ class MediaSourceControllerTest extends IslandoraFunctionalTestBase { $updated_image = file_get_contents($updated['field_image'][0]['url']); $this->assertTrue($original_mimetype != $updated_mimetype, "Mimetypes should be updated with media source update"); - $this->assertTrue($original_width != $updated_width, "Height should be updated with media source update"); - $this->assertTrue($original_height != $updated_height, "Width should be updated with media source update"); - $this->assertTrue($original_image != $updated_image, "Width should be updated with media source update"); + $this->assertTrue($original_width != $updated_width, "Width should be updated with media source update"); + $this->assertTrue($original_height != $updated_height, "Height should be updated with media source update"); + $this->assertTrue($original_image != $updated_image, "Image should be updated with media source update"); $this->assertTrue($updated_mimetype == "image/jpeg", "Invalid mimetype. Expected image/jpeg, received $updated_mimetype"); $this->assertTrue($updated_width == 295, "Invalid width. Expected 295, received $updated_width");