|
|
|
|
@ -35,10 +35,10 @@
|
|
|
|
|
namespace OCA\DAV\Connector\Sabre;
|
|
|
|
|
|
|
|
|
|
use OC\AppFramework\Http\Request;
|
|
|
|
|
use OC\FilesMetadata\Model\MetadataValueWrapper;
|
|
|
|
|
use OCP\Constants;
|
|
|
|
|
use OCP\Files\ForbiddenException;
|
|
|
|
|
use OCP\Files\StorageNotAvailableException;
|
|
|
|
|
use OCP\FilesMetadata\Exceptions\FilesMetadataException;
|
|
|
|
|
use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
|
|
|
|
|
use OCP\FilesMetadata\IFilesMetadataManager;
|
|
|
|
|
use OCP\FilesMetadata\Model\IMetadataValueWrapper;
|
|
|
|
|
@ -530,9 +530,34 @@ class FilesPlugin extends ServerPlugin {
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$this->handleUpdatePropertiesMetadata($propPatch, $node);
|
|
|
|
|
|
|
|
|
|
/** @var IFilesMetadataManager */
|
|
|
|
|
$filesMetadataManager = \OCP\Server::get(IFilesMetadataManager::class);
|
|
|
|
|
/**
|
|
|
|
|
* Disable modification of the displayname property for files and
|
|
|
|
|
* folders via PROPPATCH. See PROPFIND for more information.
|
|
|
|
|
*/
|
|
|
|
|
$propPatch->handle(self::DISPLAYNAME_PROPERTYNAME, function ($displayName) {
|
|
|
|
|
return 403;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* handle the update of metadata from PROPPATCH requests
|
|
|
|
|
*
|
|
|
|
|
* @param PropPatch $propPatch
|
|
|
|
|
* @param Node $node
|
|
|
|
|
*
|
|
|
|
|
* @throws FilesMetadataException
|
|
|
|
|
*/
|
|
|
|
|
private function handleUpdatePropertiesMetadata(PropPatch $propPatch, Node $node): void {
|
|
|
|
|
$userId = $this->userSession->getUser()?->getUID();
|
|
|
|
|
if (null === $userId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$accessRight = $this->getMetadataFileAccessRight($node, $userId);
|
|
|
|
|
$filesMetadataManager = $this->initFilesMetadataManager();
|
|
|
|
|
$knownMetadata = $filesMetadataManager->getKnownMetadata();
|
|
|
|
|
|
|
|
|
|
foreach ($propPatch->getRemainingMutations() as $mutation) {
|
|
|
|
|
@ -540,55 +565,96 @@ class FilesPlugin extends ServerPlugin {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$propPatch->handle($mutation, function (mixed $value) use ($knownMetadata, $node, $mutation, $filesMetadataManager): bool {
|
|
|
|
|
$metadata = $filesMetadataManager->getMetadata((int)$node->getFileId(), true);
|
|
|
|
|
$metadataKey = substr($mutation, strlen(self::FILE_METADATA_PREFIX));
|
|
|
|
|
$propPatch->handle(
|
|
|
|
|
$mutation,
|
|
|
|
|
function (mixed $value) use ($accessRight, $knownMetadata, $node, $mutation, $filesMetadataManager): bool {
|
|
|
|
|
$metadata = $filesMetadataManager->getMetadata((int)$node->getFileId(), true);
|
|
|
|
|
$metadataKey = substr($mutation, strlen(self::FILE_METADATA_PREFIX));
|
|
|
|
|
|
|
|
|
|
// If the metadata is unknown, it defaults to string.
|
|
|
|
|
try {
|
|
|
|
|
$type = $knownMetadata->getType($metadataKey);
|
|
|
|
|
} catch (FilesMetadataNotFoundException) {
|
|
|
|
|
$type = IMetadataValueWrapper::TYPE_STRING;
|
|
|
|
|
}
|
|
|
|
|
// confirm metadata key is editable via PROPPATCH
|
|
|
|
|
if ($knownMetadata->getEditPermission($metadataKey) < $accessRight) {
|
|
|
|
|
throw new FilesMetadataException('you do not have enough rights to update \'' . $metadataKey . '\' on this node');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the metadata is unknown, it defaults to string.
|
|
|
|
|
try {
|
|
|
|
|
$type = $knownMetadata->getType($metadataKey);
|
|
|
|
|
} catch (FilesMetadataNotFoundException) {
|
|
|
|
|
$type = IMetadataValueWrapper::TYPE_STRING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case IMetadataValueWrapper::TYPE_STRING:
|
|
|
|
|
$metadata->setString($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_INT:
|
|
|
|
|
$metadata->setInt($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_FLOAT:
|
|
|
|
|
$metadata->setFloat($metadataKey, $value);
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_BOOL:
|
|
|
|
|
$metadata->setBool($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_ARRAY:
|
|
|
|
|
$metadata->setArray($metadataKey, $value);
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_STRING_LIST:
|
|
|
|
|
$metadata->setStringList(
|
|
|
|
|
$metadataKey, $value, $knownMetadata->isIndex($metadataKey)
|
|
|
|
|
);
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_INT_LIST:
|
|
|
|
|
$metadata->setIntList(
|
|
|
|
|
$metadataKey, $value, $knownMetadata->isIndex($metadataKey)
|
|
|
|
|
);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$filesMetadataManager->saveMetadata($metadata);
|
|
|
|
|
|
|
|
|
|
switch ($type) {
|
|
|
|
|
case IMetadataValueWrapper::TYPE_STRING:
|
|
|
|
|
$metadata->setString($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_INT:
|
|
|
|
|
$metadata->setInt($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_FLOAT:
|
|
|
|
|
$metadata->setFloat($metadataKey, $value);
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_BOOL:
|
|
|
|
|
$metadata->setBool($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_ARRAY:
|
|
|
|
|
$metadata->setArray($metadataKey, $value);
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_STRING_LIST:
|
|
|
|
|
$metadata->setStringList($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
case IMetadataValueWrapper::TYPE_INT_LIST:
|
|
|
|
|
$metadata->setIntList($metadataKey, $value, $knownMetadata->isIndex($metadataKey));
|
|
|
|
|
break;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$filesMetadataManager->saveMetadata($metadata);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
/**
|
|
|
|
|
* init default internal metadata
|
|
|
|
|
*
|
|
|
|
|
* @return IFilesMetadataManager
|
|
|
|
|
*/
|
|
|
|
|
private function initFilesMetadataManager(): IFilesMetadataManager {
|
|
|
|
|
/** @var IFilesMetadataManager $manager */
|
|
|
|
|
$manager = \OCP\Server::get(IFilesMetadataManager::class);
|
|
|
|
|
$manager->initMetadata('files-live-photo', IMetadataValueWrapper::TYPE_STRING, false, IMetadataValueWrapper::EDIT_REQ_OWNERSHIP);
|
|
|
|
|
|
|
|
|
|
return $manager;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* based on owner and shares, returns the bottom limit to update related metadata
|
|
|
|
|
*
|
|
|
|
|
* @param Node $node
|
|
|
|
|
* @param string $userId
|
|
|
|
|
*
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
|
|
|
|
private function getMetadataFileAccessRight(Node $node, string $userId): int {
|
|
|
|
|
if ($node->getOwner()?->getUID() === $userId) {
|
|
|
|
|
return IMetadataValueWrapper::EDIT_REQ_OWNERSHIP;
|
|
|
|
|
} else {
|
|
|
|
|
$filePermissions = $node->getSharePermissions($userId);
|
|
|
|
|
if ($filePermissions & Constants::PERMISSION_UPDATE) {
|
|
|
|
|
return IMetadataValueWrapper::EDIT_REQ_WRITE_PERMISSION;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Disable modification of the displayname property for files and
|
|
|
|
|
* folders via PROPPATCH. See PROPFIND for more information.
|
|
|
|
|
*/
|
|
|
|
|
$propPatch->handle(self::DISPLAYNAME_PROPERTYNAME, function ($displayName) {
|
|
|
|
|
return 403;
|
|
|
|
|
});
|
|
|
|
|
return IMetadataValueWrapper::EDIT_REQ_READ_PERMISSION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $filePath
|
|
|
|
|
* @param \Sabre\DAV\INode $node
|
|
|
|
|
|