|
35 | 35 | namespace OCA\DAV\Connector\Sabre; |
36 | 36 |
|
37 | 37 | use OC\AppFramework\Http\Request; |
38 | | -use OC\FilesMetadata\Model\MetadataValueWrapper; |
39 | 38 | use OCP\Constants; |
40 | 39 | use OCP\Files\ForbiddenException; |
41 | 40 | use OCP\Files\StorageNotAvailableException; |
| 41 | +use OCP\FilesMetadata\Exceptions\FilesMetadataException; |
42 | 42 | use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; |
43 | 43 | use OCP\FilesMetadata\IFilesMetadataManager; |
44 | 44 | use OCP\FilesMetadata\Model\IMetadataValueWrapper; |
@@ -530,65 +530,131 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { |
530 | 530 | return true; |
531 | 531 | }); |
532 | 532 |
|
| 533 | + $this->handleUpdatePropertiesMetadata($propPatch, $node); |
533 | 534 |
|
534 | | - /** @var IFilesMetadataManager */ |
535 | | - $filesMetadataManager = \OCP\Server::get(IFilesMetadataManager::class); |
| 535 | + /** |
| 536 | + * Disable modification of the displayname property for files and |
| 537 | + * folders via PROPPATCH. See PROPFIND for more information. |
| 538 | + */ |
| 539 | + $propPatch->handle(self::DISPLAYNAME_PROPERTYNAME, function ($displayName) { |
| 540 | + return 403; |
| 541 | + }); |
| 542 | + } |
| 543 | + |
| 544 | + |
| 545 | + /** |
| 546 | + * handle the update of metadata from PROPPATCH requests |
| 547 | + * |
| 548 | + * @param PropPatch $propPatch |
| 549 | + * @param Node $node |
| 550 | + * |
| 551 | + * @throws FilesMetadataException |
| 552 | + */ |
| 553 | + private function handleUpdatePropertiesMetadata(PropPatch $propPatch, Node $node): void { |
| 554 | + $userId = $this->userSession->getUser()?->getUID(); |
| 555 | + if (null === $userId) { |
| 556 | + return; |
| 557 | + } |
| 558 | + |
| 559 | + $accessRight = $this->getMetadataFileAccessRight($node, $userId); |
| 560 | + $filesMetadataManager = $this->initFilesMetadataManager(); |
536 | 561 | $knownMetadata = $filesMetadataManager->getKnownMetadata(); |
537 | 562 |
|
538 | 563 | foreach ($propPatch->getRemainingMutations() as $mutation) { |
539 | 564 | if (!str_starts_with($mutation, self::FILE_METADATA_PREFIX)) { |
540 | 565 | continue; |
541 | 566 | } |
542 | 567 |
|
543 | | - $propPatch->handle($mutation, function (mixed $value) use ($knownMetadata, $node, $mutation, $filesMetadataManager): bool { |
544 | | - $metadata = $filesMetadataManager->getMetadata((int)$node->getFileId(), true); |
545 | | - $metadataKey = substr($mutation, strlen(self::FILE_METADATA_PREFIX)); |
| 568 | + $propPatch->handle( |
| 569 | + $mutation, |
| 570 | + function (mixed $value) use ($accessRight, $knownMetadata, $node, $mutation, $filesMetadataManager): bool { |
| 571 | + $metadata = $filesMetadataManager->getMetadata((int)$node->getFileId(), true); |
| 572 | + $metadataKey = substr($mutation, strlen(self::FILE_METADATA_PREFIX)); |
546 | 573 |
|
547 | | - // If the metadata is unknown, it defaults to string. |
548 | | - try { |
549 | | - $type = $knownMetadata->getType($metadataKey); |
550 | | - } catch (FilesMetadataNotFoundException) { |
551 | | - $type = IMetadataValueWrapper::TYPE_STRING; |
552 | | - } |
| 574 | + // confirm metadata key is editable via PROPPATCH |
| 575 | + if ($knownMetadata->getEditPermission($metadataKey) < $accessRight) { |
| 576 | + throw new FilesMetadataException('you do not have enough rights to update \'' . $metadataKey . '\' on this node'); |
| 577 | + } |
| 578 | + |
| 579 | + // If the metadata is unknown, it defaults to string. |
| 580 | + try { |
| 581 | + $type = $knownMetadata->getType($metadataKey); |
| 582 | + } catch (FilesMetadataNotFoundException) { |
| 583 | + $type = IMetadataValueWrapper::TYPE_STRING; |
| 584 | + } |
| 585 | + |
| 586 | + switch ($type) { |
| 587 | + case IMetadataValueWrapper::TYPE_STRING: |
| 588 | + $metadata->setString($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
| 589 | + break; |
| 590 | + case IMetadataValueWrapper::TYPE_INT: |
| 591 | + $metadata->setInt($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
| 592 | + break; |
| 593 | + case IMetadataValueWrapper::TYPE_FLOAT: |
| 594 | + $metadata->setFloat($metadataKey, $value); |
| 595 | + break; |
| 596 | + case IMetadataValueWrapper::TYPE_BOOL: |
| 597 | + $metadata->setBool($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
| 598 | + break; |
| 599 | + case IMetadataValueWrapper::TYPE_ARRAY: |
| 600 | + $metadata->setArray($metadataKey, $value); |
| 601 | + break; |
| 602 | + case IMetadataValueWrapper::TYPE_STRING_LIST: |
| 603 | + $metadata->setStringList( |
| 604 | + $metadataKey, $value, $knownMetadata->isIndex($metadataKey) |
| 605 | + ); |
| 606 | + break; |
| 607 | + case IMetadataValueWrapper::TYPE_INT_LIST: |
| 608 | + $metadata->setIntList( |
| 609 | + $metadataKey, $value, $knownMetadata->isIndex($metadataKey) |
| 610 | + ); |
| 611 | + break; |
| 612 | + } |
| 613 | + |
| 614 | + $filesMetadataManager->saveMetadata($metadata); |
553 | 615 |
|
554 | | - switch ($type) { |
555 | | - case IMetadataValueWrapper::TYPE_STRING: |
556 | | - $metadata->setString($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
557 | | - break; |
558 | | - case IMetadataValueWrapper::TYPE_INT: |
559 | | - $metadata->setInt($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
560 | | - break; |
561 | | - case IMetadataValueWrapper::TYPE_FLOAT: |
562 | | - $metadata->setFloat($metadataKey, $value); |
563 | | - break; |
564 | | - case IMetadataValueWrapper::TYPE_BOOL: |
565 | | - $metadata->setBool($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
566 | | - break; |
567 | | - case IMetadataValueWrapper::TYPE_ARRAY: |
568 | | - $metadata->setArray($metadataKey, $value); |
569 | | - break; |
570 | | - case IMetadataValueWrapper::TYPE_STRING_LIST: |
571 | | - $metadata->setStringList($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
572 | | - break; |
573 | | - case IMetadataValueWrapper::TYPE_INT_LIST: |
574 | | - $metadata->setIntList($metadataKey, $value, $knownMetadata->isIndex($metadataKey)); |
575 | | - break; |
| 616 | + return true; |
576 | 617 | } |
| 618 | + ); |
| 619 | + } |
| 620 | + } |
577 | 621 |
|
578 | | - $filesMetadataManager->saveMetadata($metadata); |
579 | | - return true; |
580 | | - }); |
| 622 | + /** |
| 623 | + * init default internal metadata |
| 624 | + * |
| 625 | + * @return IFilesMetadataManager |
| 626 | + */ |
| 627 | + private function initFilesMetadataManager(): IFilesMetadataManager { |
| 628 | + /** @var IFilesMetadataManager $manager */ |
| 629 | + $manager = \OCP\Server::get(IFilesMetadataManager::class); |
| 630 | + $manager->initMetadata('files-live-photo', IMetadataValueWrapper::TYPE_STRING, false, IMetadataValueWrapper::EDIT_REQ_OWNERSHIP); |
| 631 | + |
| 632 | + return $manager; |
| 633 | + } |
| 634 | + |
| 635 | + /** |
| 636 | + * based on owner and shares, returns the bottom limit to update related metadata |
| 637 | + * |
| 638 | + * @param Node $node |
| 639 | + * @param string $userId |
| 640 | + * |
| 641 | + * @return int |
| 642 | + */ |
| 643 | + private function getMetadataFileAccessRight(Node $node, string $userId): int { |
| 644 | + if ($node->getOwner()?->getUID() === $userId) { |
| 645 | + return IMetadataValueWrapper::EDIT_REQ_OWNERSHIP; |
| 646 | + } else { |
| 647 | + $filePermissions = $node->getSharePermissions($userId); |
| 648 | + if ($filePermissions & Constants::PERMISSION_UPDATE) { |
| 649 | + return IMetadataValueWrapper::EDIT_REQ_WRITE_PERMISSION; |
| 650 | + } |
581 | 651 | } |
582 | 652 |
|
583 | | - /** |
584 | | - * Disable modification of the displayname property for files and |
585 | | - * folders via PROPPATCH. See PROPFIND for more information. |
586 | | - */ |
587 | | - $propPatch->handle(self::DISPLAYNAME_PROPERTYNAME, function ($displayName) { |
588 | | - return 403; |
589 | | - }); |
| 653 | + return IMetadataValueWrapper::EDIT_REQ_READ_PERMISSION; |
590 | 654 | } |
591 | 655 |
|
| 656 | + |
| 657 | + |
592 | 658 | /** |
593 | 659 | * @param string $filePath |
594 | 660 | * @param \Sabre\DAV\INode $node |
|
0 commit comments