99
1010use OC \AppFramework \Http \Request ;
1111use OC \FilesMetadata \Model \FilesMetadata ;
12+ use OC \Preview \Db \Preview ;
13+ use OC \Preview \PreviewService ;
14+ use OC \Preview \Storage \IPreviewStorage ;
1215use OC \User \NoUserException ;
1316use OCA \DAV \Connector \Sabre \Exception \InvalidPath ;
1417use OCA \Files_Sharing \External \Mount as SharingExternalMount ;
3033use OCP \L10N \IFactory ;
3134use Sabre \DAV \Exception \Forbidden ;
3235use Sabre \DAV \Exception \NotFound ;
36+ use Sabre \DAV \ICollection ;
3337use Sabre \DAV \IFile ;
3438use Sabre \DAV \PropFind ;
3539use Sabre \DAV \PropPatch ;
@@ -61,6 +65,7 @@ class FilesPlugin extends ServerPlugin {
6165 public const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums ' ;
6266 public const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint ' ;
6367 public const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview ' ;
68+ public const PREVIEW_METADATA_PROPERTYNAME = '{http://nextcloud.org/ns}preview-metadata ' ;
6469 public const MOUNT_TYPE_PROPERTYNAME = '{http://nextcloud.org/ns}mount-type ' ;
6570 public const MOUNT_ROOT_PROPERTYNAME = '{http://nextcloud.org/ns}is-mount-root ' ;
6671 public const IS_FEDERATED_PROPERTYNAME = '{http://nextcloud.org/ns}is-federated ' ;
@@ -77,6 +82,8 @@ class FilesPlugin extends ServerPlugin {
7782 /** Reference to main server object */
7883 private ?Server $ server = null ;
7984
85+ private array $ previewMetadataCache = [];
86+
8087 /**
8188 * @param Tree $tree
8289 * @param IConfig $config
@@ -95,6 +102,8 @@ public function __construct(
95102 private IUserSession $ userSession ,
96103 private IFilenameValidator $ validator ,
97104 private IAccountManager $ accountManager ,
105+ private PreviewService $ previewService ,
106+ private IPreviewStorage $ previewStorage ,
98107 private bool $ isPublic = false ,
99108 private bool $ downloadAttachment = true ,
100109 ) {
@@ -127,6 +136,7 @@ public function initialize(Server $server) {
127136 $ server ->protectedProperties [] = self ::CHECKSUMS_PROPERTYNAME ;
128137 $ server ->protectedProperties [] = self ::DATA_FINGERPRINT_PROPERTYNAME ;
129138 $ server ->protectedProperties [] = self ::HAS_PREVIEW_PROPERTYNAME ;
139+ $ server ->protectedProperties [] = self ::PREVIEW_METADATA_PROPERTYNAME ;
130140 $ server ->protectedProperties [] = self ::MOUNT_TYPE_PROPERTYNAME ;
131141 $ server ->protectedProperties [] = self ::IS_FEDERATED_PROPERTYNAME ;
132142 $ server ->protectedProperties [] = self ::SHARE_NOTE ;
@@ -136,6 +146,7 @@ public function initialize(Server $server) {
136146 $ server ->protectedProperties = array_diff ($ server ->protectedProperties , $ allowedProperties );
137147
138148 $ this ->server = $ server ;
149+ $ this ->server ->on ('preloadCollection ' , $ this ->preloadCollection (...));
139150 $ this ->server ->on ('propFind ' , [$ this , 'handleGetProperties ' ]);
140151 $ this ->server ->on ('propPatch ' , [$ this , 'handleUpdateProperties ' ]);
141152 $ this ->server ->on ('afterBind ' , [$ this , 'sendFileIdHeader ' ]);
@@ -152,6 +163,23 @@ public function initialize(Server $server) {
152163 $ this ->server ->on ('beforeCopy ' , [$ this , 'checkCopy ' ]);
153164 }
154165
166+ private function preloadCollection (PropFind $ propFind , ICollection $ collection ): void {
167+ if (!($ collection instanceof Directory)) {
168+ return ;
169+ }
170+
171+ $ requestProperties = $ propFind ->getRequestedProperties ();
172+ if (in_array (self ::PREVIEW_METADATA_PROPERTYNAME , $ requestProperties , true )) {
173+ $ keys = array_map (static fn (Node $ node ) => $ node ->getInternalFileId (), $ collection ->getChildren ());
174+ $ missingKeys = array_diff ($ keys , array_keys ($ this ->previewMetadataCache ));
175+ if (count ($ missingKeys ) > 0 ) {
176+ foreach ($ this ->previewService ->getAvailablePreviews ($ missingKeys ) as $ fileId => $ previews ) {
177+ $ this ->previewMetadataCache [$ fileId ] = $ previews ;
178+ }
179+ }
180+ }
181+ }
182+
155183 /**
156184 * Plugin that checks if a copy can actually be performed.
157185 *
@@ -474,29 +502,34 @@ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node)
474502
475503 if ($ node instanceof File) {
476504 $ requestProperties = $ propFind ->getRequestedProperties ();
477-
478505 if (in_array (self ::DOWNLOADURL_PROPERTYNAME , $ requestProperties , true )
479506 || in_array (self ::DOWNLOADURL_EXPIRATION_PROPERTYNAME , $ requestProperties , true )) {
480507 try {
481508 $ directDownloadUrl = $ node ->getDirectDownload ();
509+ if ($ directDownloadUrl && isset ($ directDownloadUrl ['url ' ])) {
510+ $ propFind ->handle (self ::DOWNLOADURL_PROPERTYNAME , $ directDownloadUrl ['url ' ]);
511+ $ propFind ->handle (self ::DOWNLOADURL_EXPIRATION_PROPERTYNAME , $ directDownloadUrl ['expiration ' ]);
512+ }
482513 } catch (StorageNotAvailableException |ForbiddenException ) {
483- $ directDownloadUrl = null ;
514+ $ propFind ->handle (self ::DOWNLOADURL_PROPERTYNAME , false );
515+ $ propFind ->handle (self ::DOWNLOADURL_EXPIRATION_PROPERTYNAME , false );
484516 }
517+ }
485518
486- $ propFind ->handle (self ::DOWNLOADURL_PROPERTYNAME , function () use ($ node , $ directDownloadUrl ) {
487- if ($ directDownloadUrl && isset ($ directDownloadUrl ['url ' ])) {
488- return $ directDownloadUrl ['url ' ];
519+ $ propFind ->handle (self ::PREVIEW_METADATA_PROPERTYNAME , function () use ($ node ) {
520+ try {
521+ if (isset ($ this ->previewMetadataCache [$ node ->getInternalFileId ()])) {
522+ $ previews = $ this ->previewMetadataCache [$ node ->getInternalFileId ()];
523+ } else {
524+ [$ node ->getInternalFileId () => $ previews ] = $ this ->previewService ->getAvailablePreviews ([$ node ->getInternalFileId ()]);
489525 }
490- return false ;
491- });
492526
493- $ propFind ->handle (self ::DOWNLOADURL_EXPIRATION_PROPERTYNAME , function () use ($ node , $ directDownloadUrl ) {
494- if ($ directDownloadUrl && isset ($ directDownloadUrl ['expiration ' ])) {
495- return $ directDownloadUrl ['expiration ' ];
496- }
497- return false ;
498- });
499- }
527+ $ data = array_map (fn (Preview $ preview ) => Preview::getMetadata ($ preview , $ this ->previewStorage ), $ previews );
528+ return json_encode ($ data , JSON_THROW_ON_ERROR );
529+ } catch (\Exception $ e ) {
530+ }
531+ return false ;
532+ });
500533
501534 $ propFind ->handle (self ::CHECKSUMS_PROPERTYNAME , function () use ($ node ) {
502535 $ checksum = $ node ->getChecksum ();
0 commit comments