1111use OCA \DAV \Connector \Sabre \FilesPlugin ;
1212use OCA \DAV \Connector \Sabre \Node ;
1313use OCP \AppFramework \Http ;
14+ use OCP \Constants ;
15+ use OCP \Files \IRootFolder ;
1416use OCP \IGroupManager ;
1517use OCP \IUser ;
1618use OCP \IUserSession ;
@@ -68,7 +70,8 @@ public function __construct(
6870 protected ISystemTagManager $ tagManager ,
6971 protected IGroupManager $ groupManager ,
7072 protected IUserSession $ userSession ,
71- private ISystemTagObjectMapper $ tagMapper ,
73+ protected IRootFolder $ rootFolder ,
74+ protected ISystemTagObjectMapper $ tagMapper ,
7275 ) {
7376 }
7477
@@ -387,6 +390,11 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
387390 }
388391
389392 if (isset ($ props [self ::OBJECTIDS_PROPERTYNAME ])) {
393+ $ user = $ this ->userSession ->getUser ();
394+ if (!$ user ) {
395+ throw new Forbidden ('You don’t have permissions to update tags ' );
396+ }
397+
390398 $ propValue = $ props [self ::OBJECTIDS_PROPERTYNAME ];
391399 if (!$ propValue instanceof SystemTagsObjectList || count ($ propValue ->getObjects ()) === 0 ) {
392400 throw new BadRequest ('Invalid object-ids property ' );
@@ -399,10 +407,35 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
399407 throw new BadRequest ('Invalid object-ids property. All object types must be of the same type: ' . $ node ->getName ());
400408 }
401409
410+ // Only files are supported at the moment
411+ // Also see SystemTagsRelationsCollection file
412+ if ($ objectTypes [0 ] !== 'files ' ) {
413+ throw new BadRequest ('Invalid object-ids property type. Only files are supported ' );
414+ }
415+
416+ // Get all current tagged objects
417+ $ taggedObjects = $ this ->tagMapper ->getObjectIdsForTags ([$ node ->getSystemTag ()->getId ()], 'files ' );
418+ $ toAddObjects = array_map (fn ($ value ) => (string )$ value , array_keys ($ objects ));
419+
420+ // Compute the tags to add and remove
421+ $ addedObjects = array_values (array_diff ($ toAddObjects , $ taggedObjects ));
422+ $ removedObjects = array_values (array_diff ($ taggedObjects , $ toAddObjects ));
423+
424+ // Check permissions for each object to be freshly tagged or untagged
425+ if (!$ this ->canUpdateTagForFileIds (array_merge ($ addedObjects , $ removedObjects ))) {
426+ throw new Forbidden ('You don’t have permissions to update tags ' );
427+ }
428+
402429 $ this ->tagMapper ->setObjectIdsForTag ($ node ->getSystemTag ()->getId (), $ node ->getName (), array_keys ($ objects ));
403430 }
404431
405432 if ($ props [self ::OBJECTIDS_PROPERTYNAME ] === null ) {
433+ // Check the user have permissions to remove the tag from all currently tagged objects
434+ $ taggedObjects = $ this ->tagMapper ->getObjectIdsForTags ([$ node ->getSystemTag ()->getId ()], 'files ' );
435+ if (!$ this ->canUpdateTagForFileIds ($ taggedObjects )) {
436+ throw new Forbidden ('You don’t have permissions to update tags ' );
437+ }
438+
406439 $ this ->tagMapper ->setObjectIdsForTag ($ node ->getSystemTag ()->getId (), $ node ->getName (), []);
407440 }
408441
@@ -483,4 +516,24 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
483516 return true ;
484517 });
485518 }
519+
520+ /**
521+ * Check if the user can update the tag for the given file ids
522+ *
523+ * @param list<string> $fileIds
524+ * @return bool
525+ */
526+ private function canUpdateTagForFileIds (array $ fileIds ): bool {
527+ $ user = $ this ->userSession ->getUser ();
528+ $ userFolder = $ this ->rootFolder ->getUserFolder ($ user ->getUID ());
529+ foreach ($ fileIds as $ fileId ) {
530+ $ nodes = $ userFolder ->getById ((int )$ fileId );
531+ foreach ($ nodes as $ node ) {
532+ if (($ node ->getPermissions () & Constants::PERMISSION_UPDATE ) === Constants::PERMISSION_UPDATE ) {
533+ return true ;
534+ }
535+ }
536+ }
537+ return false ;
538+ }
486539}
0 commit comments