Skip to content

Commit 39946fd

Browse files
authored
Merge pull request #300 from nextcloud/feature/noid/better-preview-api
Add the mimetype to the preview arrays
2 parents 56b8311 + 190f6c8 commit 39946fd

File tree

3 files changed

+76
-71
lines changed

3 files changed

+76
-71
lines changed

docs/endpoint-v2.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ Field name | Type | Value description
9898
---------- | ---- | -----------------
9999
`source` | string | Full URL of the image to be displayed
100100
`link` | string | Full URL the preview should be wrapped in
101+
`mimeType` | string | The mime type of the file (not the preview)
102+
`fileId` | int | The if of the actual file
103+
`view` | string | The view where the file can be found (either `files` or `trashbin`)
101104
`isMimeTypeIcon` | bool | True if `source` points to a mime type icon instead of a real preview
102105

103106
In case the endpoint returns more fields, they should be ignored and are deprecated (only for backwards compatibility usage) or internal.
@@ -112,15 +115,15 @@ In case the endpoint returns more fields, they should be ignored and are depreca
112115
"type": "file_created",
113116
"user": "test1",
114117
"affecteduser": "admin",
115-
"subject": "test1 created hello.jpg",
118+
"subject": "test1 created hello.txt",
116119
"subject_rich": {
117120
"0": "test1 created {file1}",
118121
"1": {
119122
"file1": {
120123
"type": "file",
121124
"id": 23,
122-
"name": "hello.jpg",
123-
"path": "\/test\/hello.jpg"
125+
"name": "hello.txt",
126+
"path": "\/test\/hello.txt"
124127
}
125128
}
126129
},
@@ -133,12 +136,15 @@ In case the endpoint returns more fields, they should be ignored and are depreca
133136
"link": "",
134137
"object_type": "files",
135138
"object_id": 23,
136-
"object_name": "\/test\/hello.jpg",
139+
"object_name": "\/test\/hello.txt",
137140
"previews": [
138141
{
139-
"link": "https:\/\/localhost\/index.php\/apps\/files\/?dir=\/test&scrollto=hello.jpg",
140-
"source": "https:\/\/localhost\/index.php\/core\/preview.png?file=\/hello.jpg&x=150&y=150",
141-
"isMimeTypeIcon": false
142+
"link": "https:\/\/localhost\/index.php\/apps\/files\/?dir=\/test&scrollto=hello.txt",
143+
"source": "https:\/\/localhost\/index.php\/core\/preview.png?file=\/hello.txt&x=150&y=150",
144+
"mimeType": "text/plain",
145+
"view": "files",
146+
"fileId": 23,
147+
"isMimeTypeIcon": false
142148
}
143149
]
144150
}

lib/Controller/APIv2.php

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
declare(strict_types=1);
23
/**
34
* @copyright Copyright (c) 2016, ownCloud, Inc.
45
*
@@ -151,16 +152,16 @@ public function __construct($appName,
151152
* @throws \OutOfBoundsException when no user is given
152153
*/
153154
protected function validateParameters($filter, $since, $limit, $previews, $objectType, $objectId, $sort) {
154-
$this->filter = is_string($filter) ? $filter : 'all';
155+
$this->filter = \is_string($filter) ? $filter : 'all';
155156
if ($this->filter !== $this->data->validateFilter($this->filter)) {
156-
throw new InvalidFilterException();
157+
throw new InvalidFilterException('Invalid filter');
157158
}
158159
$this->since = (int) $since;
159160
$this->limit = (int) $limit;
160161
$this->loadPreviews = (bool) $previews;
161162
$this->objectType = (string) $objectType;
162163
$this->objectId = (int) $objectId;
163-
$this->sort = in_array($sort, ['asc', 'desc'], true) ? $sort : 'desc';
164+
$this->sort = \in_array($sort, ['asc', 'desc'], true) ? $sort : 'desc';
164165

165166
if (($this->objectType !== '' && $this->objectId === 0) || ($this->objectType === '' && $this->objectId !== 0)) {
166167
// Only allowed together
@@ -173,7 +174,7 @@ protected function validateParameters($filter, $since, $limit, $previews, $objec
173174
$this->user = $user->getUID();
174175
} else {
175176
// No user logged in
176-
throw new \OutOfBoundsException();
177+
throw new \OutOfBoundsException('Not logged in');
177178
}
178179
}
179180

@@ -188,7 +189,7 @@ protected function validateParameters($filter, $since, $limit, $previews, $objec
188189
* @param string $sort
189190
* @return DataResponse
190191
*/
191-
public function getDefault($since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc') {
192+
public function getDefault($since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc'): DataResponse {
192193
return $this->get('all', $since, $limit, $previews, $object_type, $object_id, $sort);
193194
}
194195

@@ -204,7 +205,7 @@ public function getDefault($since = 0, $limit = 50, $previews = false, $object_t
204205
* @param string $sort
205206
* @return DataResponse
206207
*/
207-
public function getFilter($filter, $since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc') {
208+
public function getFilter($filter, $since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc'): DataResponse {
208209
return $this->get($filter, $since, $limit, $previews, $object_type, $object_id, $sort);
209210
}
210211

@@ -213,7 +214,7 @@ public function getFilter($filter, $since = 0, $limit = 50, $previews = false, $
213214
*
214215
* @return DataResponse
215216
*/
216-
public function listFilters() {
217+
public function listFilters(): DataResponse {
217218
$filters = $this->activityManager->getFilters();
218219

219220
$filters = array_map(function(IFilter $filter) {
@@ -247,7 +248,7 @@ public function listFilters() {
247248
* @param string $sort
248249
* @return DataResponse
249250
*/
250-
protected function get($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort) {
251+
protected function get($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort): DataResponse {
251252
try {
252253
$this->validateParameters($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort);
253254
} catch (InvalidFilterException $e) {
@@ -293,7 +294,7 @@ protected function get($filter, $since, $limit, $previews, $filterObjectType, $f
293294
if ($this->loadPreviews) {
294295
$activity['previews'] = [];
295296
if ($activity['object_type'] === 'files') {
296-
if (!empty($activity['objects']) && is_array($activity['objects'])) {
297+
if (!empty($activity['objects']) && \is_array($activity['objects'])) {
297298
foreach ($activity['objects'] as $objectId => $objectName) {
298299
if (((int) $objectId) === 0 || $objectName === '') {
299300
// No file, no preview
@@ -315,13 +316,7 @@ protected function get($filter, $since, $limit, $previews, $filterObjectType, $f
315316
return new DataResponse($preparedActivities, Http::STATUS_OK, $headers);
316317
}
317318

318-
/**
319-
* @param array $headers
320-
* @param bool $hasMoreActivities
321-
* @param array $data
322-
* @return array
323-
*/
324-
protected function generateHeaders(array $headers, $hasMoreActivities, array $data) {
319+
protected function generateHeaders(array $headers, bool $hasMoreActivities, array $data): array {
325320
if ($hasMoreActivities && isset($headers['X-Activity-Last-Given'])) {
326321
// Set the "Link" header for the next page
327322
$nextPageParameters = [
@@ -354,71 +349,62 @@ protected function generateHeaders(array $headers, $hasMoreActivities, array $da
354349
return $headers;
355350
}
356351

357-
/**
358-
* @param string $owner
359-
* @param int $fileId
360-
* @param string $filePath
361-
* @return array
362-
*/
363-
protected function getPreview($owner, $fileId, $filePath) {
352+
protected function getPreview(string $owner, int $fileId, string $filePath): array {
364353
$info = $this->infoCache->getInfoById($owner, $fileId, $filePath);
365354

366355
if (!$info['exists'] || $info['view'] !== '') {
367-
return $this->getPreviewFromPath($filePath, $info);
356+
return $this->getPreviewFromPath($fileId, $filePath, $info);
368357
}
369358

370359
$preview = [
371360
'link' => $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
372361
'source' => '',
362+
'mimeType' => 'application/octet-stream',
373363
'isMimeTypeIcon' => true,
364+
'fileId' => $fileId,
365+
'view' => $info['view'] ?: 'files',
374366
];
375367

376368
// show a preview image if the file still exists
377369
if ($info['is_dir']) {
378370
$preview['source'] = $this->getPreviewPathFromMimeType('dir');
371+
$preview['mimeType'] = 'dir';
379372
} else {
380373
$this->view->chroot('/' . $owner . '/files');
381374
$fileInfo = $this->view->getFileInfo($info['path']);
382-
if (!($fileInfo instanceof FileInfo)) {
383-
$pathPreview = $this->getPreviewFromPath($filePath, $info);
384-
$preview['source'] = $pathPreview['source'];
375+
if (!$fileInfo instanceof FileInfo) {
376+
$preview = $this->getPreviewFromPath($fileId, $filePath, $info);
385377
} else if ($this->preview->isAvailable($fileInfo)) {
386-
$preview['isMimeTypeIcon'] = false;
387378
$preview['source'] = $this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreview', [
388379
'file' => $info['path'],
389380
'c' => $this->view->getETag($info['path']),
390381
'x' => 150,
391382
'y' => 150,
392383
]);
384+
$preview['mimeType'] = $fileInfo->getMimetype();
385+
$preview['isMimeTypeIcon'] = false;
393386
} else {
394387
$preview['source'] = $this->getPreviewPathFromMimeType($fileInfo->getMimetype());
388+
$preview['mimeType'] = $fileInfo->getMimetype();
395389
}
396390
}
397391

398392
return $preview;
399393
}
400394

401-
/**
402-
* @param string $filePath
403-
* @param array $info
404-
* @return array
405-
*/
406-
protected function getPreviewFromPath($filePath, $info) {
395+
protected function getPreviewFromPath(int $fileId, string $filePath, array $info): array {
407396
$mimeType = $info['is_dir'] ? 'dir' : $this->mimeTypeDetector->detectPath($filePath);
408-
$preview = [
397+
return [
409398
'link' => $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
410399
'source' => $this->getPreviewPathFromMimeType($mimeType),
400+
'mimeType' => $mimeType,
411401
'isMimeTypeIcon' => true,
402+
'fileId' => $fileId,
403+
'view' => $info['view'] ?: 'files',
412404
];
413-
414-
return $preview;
415405
}
416406

417-
/**
418-
* @param string $mimeType
419-
* @return string
420-
*/
421-
protected function getPreviewPathFromMimeType($mimeType) {
407+
protected function getPreviewPathFromMimeType(string $mimeType): string {
422408
$mimeTypeIcon = $this->mimeTypeDetector->mimeTypeIcon($mimeType);
423409
if (substr($mimeTypeIcon, -4) === '.png') {
424410
$mimeTypeIcon = substr($mimeTypeIcon, 0, -4) . '.svg';
@@ -427,18 +413,12 @@ protected function getPreviewPathFromMimeType($mimeType) {
427413
return $this->urlGenerator->getAbsoluteURL($mimeTypeIcon);
428414
}
429415

430-
/**
431-
* @param string $path
432-
* @param bool $isDir
433-
* @param string $view
434-
* @return string
435-
*/
436-
protected function getPreviewLink($path, $isDir, $view) {
416+
protected function getPreviewLink(string $path, bool $isDir, string $view): string {
437417
$params = [
438418
'dir' => $path,
439419
];
440420
if (!$isDir) {
441-
$params['dir'] = (substr_count($path, '/') === 1) ? '/' : dirname($path);
421+
$params['dir'] = (substr_count($path, '/') === 1) ? '/' : \dirname($path);
442422
$params['scrollto'] = basename($path);
443423
}
444424
if ($view !== '') {

tests/Controller/APIv2Test.php

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -651,18 +651,18 @@ public function testGetPreviewInvalidPaths($author, $fileId, $path, $returnedPat
651651
]);
652652
$controller->expects($this->any())
653653
->method('getPreviewFromPath')
654-
->with($path)
654+
->with($fileId, $path)
655655
->willReturn(['getPreviewFromPath']);
656656

657657
$this->assertSame(['getPreviewFromPath'], self::invokePrivate($controller, 'getPreview', [$author, $fileId, $path]));
658658
}
659659

660660
public function dataGetPreview() {
661661
return [
662-
['author', 42, '/path', '/currentPath', true, true, false, '/preview/dir', true],
663-
['author', 42, '/file.txt', '/currentFile.txt', false, true, false, '/preview/mpeg', true],
664-
['author', 42, '/file.txt', '/currentFile.txt', false, true, true, '/preview/currentFile.txt', false],
665-
['author', 42, '/file.txt', '/currentFile.txt', false, false, true, 'source::getPreviewFromPath', true],
662+
['author', 42, '/path', '/currentPath', true, true, false, '/preview/dir', true, 'dir'],
663+
['author', 42, '/file.txt', '/currentFile.txt', false, true, false, '/preview/mpeg', true, 'audio/mp3'],
664+
['author', 42, '/file.txt', '/currentFile.txt', false, true, true, '/preview/currentFile.txt', false, 'text/plain'],
665+
['author', 42, '/file.txt', '/currentFile.txt', false, false, true, 'source::getPreviewFromPath', true, 'text/plain'],
666666
];
667667
}
668668

@@ -678,8 +678,9 @@ public function dataGetPreview() {
678678
* @param bool $isMimeSup
679679
* @param string $source
680680
* @param bool $isMimeTypeIcon
681+
* @param string $mimeType
681682
*/
682-
public function testGetPreview($author, $fileId, $path, $returnedPath, $isDir, $validFileInfo, $isMimeSup, $source, $isMimeTypeIcon) {
683+
public function testGetPreview($author, $fileId, $path, $returnedPath, $isDir, $validFileInfo, $isMimeSup, $source, $isMimeTypeIcon, $mimeType) {
683684

684685
$controller = $this->getController([
685686
'getPreviewLink',
@@ -726,7 +727,7 @@ public function testGetPreview($author, $fileId, $path, $returnedPath, $isDir, $
726727
->willReturn($isMimeSup);
727728

728729
if (!$isMimeSup) {
729-
$fileInfo->expects($this->once())
730+
$fileInfo->expects($this->atLeastOnce())
730731
->method('getMimetype')
731732
->willReturn('audio/mp3');
732733

@@ -735,6 +736,10 @@ public function testGetPreview($author, $fileId, $path, $returnedPath, $isDir, $
735736
->with('audio/mp3')
736737
->willReturn('/preview/mpeg');
737738
} else {
739+
$fileInfo->expects($this->atLeastOnce())
740+
->method('getMimetype')
741+
->willReturn('text/plain');
742+
738743
$this->urlGenerator->expects($this->once())
739744
->method('linkToRouteAbsolute')
740745
->with('core.Preview.getPreview', $this->anything())
@@ -753,33 +758,44 @@ public function testGetPreview($author, $fileId, $path, $returnedPath, $isDir, $
753758

754759
$controller->expects($this->once())
755760
->method('getPreviewFromPath')
756-
->with($path, $this->anything())
757-
->willReturn(['source' => 'source::getPreviewFromPath']);
761+
->with($fileId, $path, $this->anything())
762+
->willReturn([
763+
'link' => '/preview' . $returnedPath,
764+
'source' => 'source::getPreviewFromPath',
765+
'mimeType' => $mimeType,
766+
'isMimeTypeIcon' => $isMimeTypeIcon,
767+
'fileId' => $fileId,
768+
'view' => 'files',
769+
]);
758770
}
759771

760772
$this->assertSame([
761773
'link' => '/preview' . $returnedPath,
762774
'source' => $source,
775+
'mimeType' => $mimeType,
763776
'isMimeTypeIcon' => $isMimeTypeIcon,
777+
'fileId' => $fileId,
778+
'view' => 'files',
764779
], self::invokePrivate($controller, 'getPreview', [$author, $fileId, $path]));
765780
}
766781

767782
public function dataGetPreviewFromPath() {
768783
return [
769-
['dir', 'dir', true, ''],
770-
['test.txt', 'text/plain', false, 'trashbin'],
771-
['test.mp3', 'audio/mpeg', false, ''],
784+
[23, 'dir', 'dir', true, ''],
785+
[42, 'test.txt', 'text/plain', false, 'trashbin'],
786+
[128, 'test.mp3', 'audio/mpeg', false, ''],
772787
];
773788
}
774789

775790
/**
776791
* @dataProvider dataGetPreviewFromPath
792+
* @param int $fileId
777793
* @param string $filePath
778794
* @param string $mimeType
779795
* @param bool $isDir
780796
* @param string $view
781797
*/
782-
public function testGetPreviewFromPath($filePath, $mimeType, $isDir, $view) {
798+
public function testGetPreviewFromPath($fileId, $filePath, $mimeType, $isDir, $view) {
783799
$controller = $this->getController([
784800
'getPreviewPathFromMimeType',
785801
'getPreviewLink',
@@ -801,9 +817,12 @@ public function testGetPreviewFromPath($filePath, $mimeType, $isDir, $view) {
801817
[
802818
'link' => 'target-link',
803819
'source' => 'mime-type-icon',
820+
'mimeType' => $mimeType,
804821
'isMimeTypeIcon' => true,
822+
'fileId' => $fileId,
823+
'view' => $view ?: 'files',
805824
],
806-
self::invokePrivate($controller, 'getPreviewFromPath', [$filePath, ['path' => $filePath, 'is_dir' => $isDir, 'view' => $view]])
825+
self::invokePrivate($controller, 'getPreviewFromPath', [$fileId, $filePath, ['path' => $filePath, 'is_dir' => $isDir, 'view' => $view]])
807826
);
808827
}
809828

0 commit comments

Comments
 (0)