Skip to content

Commit

Permalink
fix: make rest api endpoints work with multisite uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
carlalexander committed Aug 10, 2020
1 parent 6c404ca commit f4332cf
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 20 deletions.
11 changes: 10 additions & 1 deletion src/RestApi/CreateAttachmentEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,16 @@ public function getMethods(): array
public function respond(\WP_REST_Request $request)
{
$path = ltrim($request->get_param('path'), '/');
$details = $this->cloudStorageClient->getObjectDetails('uploads/'.$path);
$matches = [];

// Need to extract the "sites/{blog_id}" for multisite
preg_match('/(uploads.*)/', $this->uploadsDirectory, $matches);

if (empty($matches[1])) {
throw new \RuntimeException('Unable to parse uploads directory');
}

$details = $this->cloudStorageClient->getObjectDetails(trim($matches[1], '/').'/'.$path);
$url = $this->uploadsUrl.'/'.$path;

$attachment = [
Expand Down
10 changes: 9 additions & 1 deletion src/RestApi/GetFileDetailsEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,19 @@ public function respond(\WP_REST_Request $request)
{
$filename = wp_unique_filename($this->uploadsPath, urlencode(wp_basename(sanitize_file_name(htmlspecialchars_decode($request->get_param('filename'), ENT_QUOTES)))));
$path = $this->uploadsSubdirectory.$filename;
$matches = [];

// Need to extract the "sites/{blog_id}" for multisite
preg_match('/(uploads.*)/', substr($this->uploadsPath, 0, -strlen($this->uploadsSubdirectory)), $matches);

if (empty($matches[1])) {
throw new \RuntimeException('Unable to parse uploads path');
}

return [
'filename' => $filename,
'path' => $path,
'upload_url' => $this->client->createPutObjectRequest('uploads/'.$path),
'upload_url' => $this->client->createPutObjectRequest(trim($matches[1], '/').'/'.$path),
];
}

Expand Down
65 changes: 53 additions & 12 deletions tests/Unit/RestApi/CreateAttachmentEndpointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function testRespondReturnsAsyncResponseForLargeImage()
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
$cloudStorageClient->expects($this->once())
->method('getObjectDetails')
->with('uploads/filename.jpg')
->with('uploads/2020/08/filename.jpg')
->willReturn(['size' => 16, 'type' => 'image/jpeg']);

$consoleClient = $this->getConsoleClientInterfaceMock();
Expand All @@ -71,7 +71,7 @@ public function testRespondReturnsAsyncResponseForLargeImage()
$request->expects($this->once())
->method('get_param')
->with($this->identicalTo('path'))
->willReturn('/filename.jpg');
->willReturn('2020/08/filename.jpg');

$sanitize_text_field = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'sanitize_text_field');
$sanitize_text_field->expects($this->once())
Expand All @@ -85,7 +85,7 @@ public function testRespondReturnsAsyncResponseForLargeImage()

$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
$wp_insert_attachment->expects($this->once())
->with($this->identicalTo(['guid' => 'uploads_url/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'image/jpeg', 'post_title' => 'filename']), $this->identicalTo('filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'image/jpeg', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
->willReturn('attachment_id');

$wp_prepare_attachment_for_js = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_prepare_attachment_for_js');
Expand All @@ -95,17 +95,17 @@ public function testRespondReturnsAsyncResponseForLargeImage()

$wp_update_attachment_metadata = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_update_attachment_metadata');
$wp_update_attachment_metadata->expects($this->once())
->with($this->identicalTo('attachment_id'), $this->identicalTo(['file' => 'filename.jpg']));
->with($this->identicalTo('attachment_id'), $this->identicalTo(['file' => '2020/08/filename.jpg']));

$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'uploads_dir', 'uploads_url'))->respond($request));
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads', 'https://d1mbwobeuvop7i.cloudfront.net/uploads'))->respond($request));
}

public function testRespondReturnsError()
{
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
$cloudStorageClient->expects($this->once())
->method('getObjectDetails')
->with('uploads/filename.txt')
->with('uploads_dir/2020/08/filename.jpg')
->willReturn(['type' => 'text/plain']);

$error = $this->getWPErrorMock();
Expand All @@ -118,7 +118,7 @@ public function testRespondReturnsError()
$request->expects($this->once())
->method('get_param')
->with($this->identicalTo('path'))
->willReturn('/filename.txt');
->willReturn('2020/08/filename.jpg');

$sanitize_text_field = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'sanitize_text_field');
$sanitize_text_field->expects($this->once())
Expand All @@ -127,7 +127,7 @@ public function testRespondReturnsError()

$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
$wp_insert_attachment->expects($this->once())
->with($this->identicalTo(['guid' => 'uploads_url/filename.txt', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('filename.txt'), $this->identicalTo(0), $this->identicalTo(true))
->with($this->identicalTo(['guid' => 'uploads_url/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
->willReturn($error);

$this->assertSame($error, (new CreateAttachmentEndpoint($cloudStorageClient, $this->getConsoleClientInterfaceMock(), 'uploads_dir', 'uploads_url'))->respond($request));
Expand All @@ -138,7 +138,7 @@ public function testRespondReturnsResponse()
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
$cloudStorageClient->expects($this->once())
->method('getObjectDetails')
->with('uploads/filename.txt')
->with('uploads/2020/08/filename.jpg')
->willReturn(['type' => 'text/plain']);

$consoleClient = $this->getConsoleClientInterfaceMock();
Expand All @@ -154,7 +154,7 @@ public function testRespondReturnsResponse()
$request->expects($this->once())
->method('get_param')
->with($this->identicalTo('path'))
->willReturn('/filename.txt');
->willReturn('2020/08/filename.jpg');

$sanitize_text_field = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'sanitize_text_field');
$sanitize_text_field->expects($this->once())
Expand All @@ -163,14 +163,55 @@ public function testRespondReturnsResponse()

$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
$wp_insert_attachment->expects($this->once())
->with($this->identicalTo(['guid' => 'uploads_url/filename.txt', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('filename.txt'), $this->identicalTo(0), $this->identicalTo(true))
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
->willReturn('attachment_id');

$wp_prepare_attachment_for_js = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_prepare_attachment_for_js');
$wp_prepare_attachment_for_js->expects($this->once())
->with($this->identicalTo('attachment_id'))
->willReturn([]);

$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'uploads_dir', 'uploads_url'))->respond($request));
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads', 'https://d1mbwobeuvop7i.cloudfront.net/uploads'))->respond($request));
}

public function testRespondReturnsResponseForMultisite()
{
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
$cloudStorageClient->expects($this->once())
->method('getObjectDetails')
->with('uploads/sites/2/2020/08/filename.jpg')
->willReturn(['type' => 'text/plain']);

$consoleClient = $this->getConsoleClientInterfaceMock();
$consoleClient->expects($this->once())
->method('createAttachmentMetadata')
->with($this->identicalTo('attachment_id'), $this->identicalTo(false));

$get_current_user_id = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'get_current_user_id');
$get_current_user_id->expects($this->once())
->willReturn('user_id');

$request = $this->getWPRESTRequestMock();
$request->expects($this->once())
->method('get_param')
->with($this->identicalTo('path'))
->willReturn('2020/08/filename.jpg');

$sanitize_text_field = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'sanitize_text_field');
$sanitize_text_field->expects($this->once())
->with($this->identicalTo('filename'))
->willReturn('filename');

$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
$wp_insert_attachment->expects($this->once())
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/sites/2/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
->willReturn('attachment_id');

$wp_prepare_attachment_for_js = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_prepare_attachment_for_js');
$wp_prepare_attachment_for_js->expects($this->once())
->with($this->identicalTo('attachment_id'))
->willReturn([]);

$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads/sites/2', 'https://d1mbwobeuvop7i.cloudfront.net/uploads/sites/2'))->respond($request));
}
}
48 changes: 42 additions & 6 deletions tests/Unit/RestApi/GetFileDetailsEndpointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function testRespondWithEncodedCharacters()
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
$cloudStorageClient->expects($this->once())
->method('createPutObjectRequest')
->with($this->identicalTo('uploads/uploads_subdir/uploads_path/Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf'))
->with($this->identicalTo('uploads/2020/08/Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf'))
->willReturn('cloudstorage_put_request_url');

$request = $this->getWPRESTRequestMock();
Expand All @@ -72,14 +72,50 @@ public function testRespondWithEncodedCharacters()

$wp_unique_filename = $this->getFunctionMock($this->getNamespace(GetFileDetailsEndpoint::class), 'wp_unique_filename');
$wp_unique_filename->expects($this->once())
->with($this->identicalTo('uploads_path'), $this->identicalTo('Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf'))
->willReturn('uploads_path/Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf');
->with($this->identicalTo('cloudstorage:///uploads/2020/08'), $this->identicalTo('Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf'))
->willReturn('Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf');

$this->assertSame([
'filename' => 'uploads_path/Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf',
'path' => 'uploads_subdir/uploads_path/Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf',
'filename' => 'Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf',
'path' => '2020/08/Revenu+Qu%C3%A9bec+-+Inscription+d%27une+entreprise+en+d%C3%A9marrage.pdf',
'upload_url' => 'cloudstorage_put_request_url',
], (new GetFileDetailsEndpoint($cloudStorageClient, 'uploads_path', 'uploads_subdir'))->respond($request));
], (new GetFileDetailsEndpoint($cloudStorageClient, 'cloudstorage:///uploads/2020/08', '/2020/08'))->respond($request));
}

public function testRespondWithMultisiteUploadsPath()
{
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
$cloudStorageClient->expects($this->once())
->method('createPutObjectRequest')
->with($this->identicalTo('uploads/sites/2/2020/08/test.txt'))
->willReturn('cloudstorage_put_request_url');

$request = $this->getWPRESTRequestMock();
$request->expects($this->once())
->method('get_param')
->with($this->identicalTo('filename'))
->willReturn('test.txt');

$sanitize_file_name = $this->getFunctionMock($this->getNamespace(GetFileDetailsEndpoint::class), 'sanitize_file_name');
$sanitize_file_name->expects($this->once())
->with($this->identicalTo('test.txt'))
->willReturn('test.txt');

$wp_basename = $this->getFunctionMock($this->getNamespace(GetFileDetailsEndpoint::class), 'wp_basename');
$wp_basename->expects($this->once())
->with($this->identicalTo('test.txt'))
->willReturn('test.txt');

$wp_unique_filename = $this->getFunctionMock($this->getNamespace(GetFileDetailsEndpoint::class), 'wp_unique_filename');
$wp_unique_filename->expects($this->once())
->with($this->identicalTo('cloudstorage:///uploads/sites/2/2020/08'), $this->identicalTo('test.txt'))
->willReturn('test.txt');

$this->assertSame([
'filename' => 'test.txt',
'path' => '2020/08/test.txt',
'upload_url' => 'cloudstorage_put_request_url',
], (new GetFileDetailsEndpoint($cloudStorageClient, 'cloudstorage:///uploads/sites/2/2020/08', '/2020/08'))->respond($request));
}

public function testValidateRequest()
Expand Down

0 comments on commit f4332cf

Please sign in to comment.