diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 97cefa71..4aa4df76 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -21,6 +21,7 @@ use OCP\Files\Events\Node\NodeDeletedEvent; use OCP\Files\Events\Node\NodeRenamedEvent; use OCP\Files\Events\NodeRemovedFromCache; +use OCP\Files\IRootFolder; use OCP\Share\Events\ShareCreatedEvent; use OCP\Share\Events\ShareDeletedEvent; @@ -42,6 +43,11 @@ public function __construct() { $dispatcher->addServiceListener(ShareDeletedEvent::class, FileListener::class); $dispatcher->addServiceListener(CacheEntryInsertedEvent::class, FileListener::class); $dispatcher->addServiceListener(NodeRemovedFromCache::class, FileListener::class); + $rootFolder = $this->getContainer()->get(IRootFolder::class); + $rootFolder->listen('\OC\Files', 'postRename', function($source, $target) { + $fileListener = $this->getContainer()->get(FileListener::class); + $fileListener->postRename($source, $target); + }); } public function register(IRegistrationContext $context): void { diff --git a/lib/Hooks/FileListener.php b/lib/Hooks/FileListener.php index a46b7e63..3601f84a 100644 --- a/lib/Hooks/FileListener.php +++ b/lib/Hooks/FileListener.php @@ -38,6 +38,9 @@ use OCP\Share\IManager; use Psr\Log\LoggerInterface; +/** + * @template-implements IEventListener + */ class FileListener implements IEventListener { private FaceDetectionMapper $faceDetectionMapper; private LoggerInterface $logger; @@ -70,7 +73,7 @@ public function handle(Event $event): void { $node = $share->getNode(); $accessList = $this->shareManager->getAccessList($node, true, true); - $userIds = array_map(fn ($id) => (string)$id, array_keys($accessList['users'])); + $userIds = array_map(fn ($id) => strval($id), array_keys($accessList['users'])); if ($node->getType() === FileInfo::TYPE_FOLDER) { $mount = $node->getMountPoint(); @@ -312,6 +315,86 @@ public function postInsert(Node $node, bool $recurse = true): void { } } + function preRename(Node $source, Node $target): void { + $sourceAccessList = $this->shareManager->getAccessList($source, true, true); + $sourceUserIds = array_map(fn ($id) => strval($id), array_keys($sourceAccessList['users'])); + $targetAccessList = $this->shareManager->getAccessList($target, true, true); + $targetUserIds = array_map(fn ($id) => strval($id), array_keys($targetAccessList['users'])); + + $usersToRemove = array_diff($sourceUserIds, $targetUserIds); + + if ($target->getType() === FileInfo::TYPE_FOLDER) { + $mount = $target->getMountPoint(); + if ($mount->getNumericStorageId() === null) { + return; + } + $files = $this->storageService->getFilesInMount($mount->getNumericStorageId(), $source->getId(), [ClusteringFaceClassifier::MODEL_NAME], 0, 0); + foreach ($files as $fileInfo) { + $this->faceDetectionMapper->removeDetectionsForFileFromUsersNotInList($fileInfo['fileid'], $usersToRemove); + } + } else { + $this->faceDetectionMapper->removeDetectionsForFileFromUsersNotInList($source->getId(), $usersToRemove); + } + } + + function postRename(Node $source, Node $target): void { + if (in_array($source->getName(), [...Constants::IGNORE_MARKERS_ALL, ...Constants::IGNORE_MARKERS_IMAGE, ...Constants::IGNORE_MARKERS_AUDIO, ...Constants::IGNORE_MARKERS_VIDEO], true) && + !in_array($target->getName(), [...Constants::IGNORE_MARKERS_ALL, ...Constants::IGNORE_MARKERS_IMAGE, ...Constants::IGNORE_MARKERS_AUDIO, ...Constants::IGNORE_MARKERS_VIDEO], true)) { + $this->resetIgnoreCache($source); + $this->postInsert($target->getParent()); + return; + } + + if (!in_array($source->getName(), [...Constants::IGNORE_MARKERS_ALL, ...Constants::IGNORE_MARKERS_IMAGE, ...Constants::IGNORE_MARKERS_AUDIO, ...Constants::IGNORE_MARKERS_VIDEO], true) && + in_array($target->getName(), [...Constants::IGNORE_MARKERS_ALL, ...Constants::IGNORE_MARKERS_IMAGE, ...Constants::IGNORE_MARKERS_AUDIO, ...Constants::IGNORE_MARKERS_VIDEO], true)) { + $this->resetIgnoreCache($target); + $this->postDelete($target->getParent()); + return; + } + + if ($this->isIgnored($target)) { + $this->postDelete($target); + return; + } + if ($this->isIgnored($source) && !$this->isIgnored($target)) { + $this->postInsert($target); + return; + } + + $sourceAccessList = $this->shareManager->getAccessList($source, true, true); + $sourceUserIds = array_map(fn ($id) => strval($id), array_keys($sourceAccessList['users'])); + $targetAccessList = $this->shareManager->getAccessList($target, true, true); + $targetUserIds = array_map(fn ($id) => strval($id), array_keys($targetAccessList['users'])); + + $usersToAdd = array_diff($targetUserIds, $sourceUserIds); + $existingUsers = array_diff($targetUserIds, $usersToAdd); + // *handwaving* I know this is a stretch but it's good enough + $ownerId = $existingUsers[0]; + + if ($target->getType() === FileInfo::TYPE_FOLDER) { + $mount = $target->getMountPoint(); + if ($mount->getNumericStorageId() === null) { + return; + } + $files = $this->storageService->getFilesInMount($mount->getNumericStorageId(), $target->getId(), [ClusteringFaceClassifier::MODEL_NAME], 0, 0); + foreach ($files as $fileInfo) { + foreach ($usersToAdd as $userId) { + if (count($this->faceDetectionMapper->findByFileIdAndUser($target->getId(), $userId)) > 0) { + continue; + } + $this->faceDetectionMapper->copyDetectionsForFileFromUserToUser($fileInfo['fileid'], $ownerId, $userId); + } + } + } else { + foreach ($usersToAdd as $userId) { + if (count($this->faceDetectionMapper->findByFileIdAndUser($target->getId(), $userId)) > 0) { + continue; + } + $this->faceDetectionMapper->copyDetectionsForFileFromUserToUser($target->getId(), $ownerId, $userId); + } + } + } + /** * @param \OCP\Files\Node $node * @return bool