Skip to content

Commit

Permalink
Add a listener to update trashed items when parent is renamed
Browse files Browse the repository at this point in the history
Signed-off-by: Côme Chilliet <[email protected]>
  • Loading branch information
come-nc committed Dec 12, 2023
1 parent 96521d0 commit 8f60465
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 3 deletions.
3 changes: 3 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
use OCA\GroupFolders\Folder\FolderManager;
use OCA\GroupFolders\Listeners\CircleDestroyedEventListener;
use OCA\GroupFolders\Listeners\LoadAdditionalScriptsListener;
use OCA\GroupFolders\Listeners\NodeRenamedListener;
use OCA\GroupFolders\Mount\MountProvider;
use OCA\GroupFolders\Trash\TrashBackend;
use OCA\GroupFolders\Trash\TrashManager;
Expand All @@ -55,6 +56,7 @@
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\Events\Node\NodeRenamedEvent;
use OCP\Files\Folder;
use OCP\Files\IMimeTypeLoader;
use OCP\Files\IRootFolder;
Expand Down Expand Up @@ -90,6 +92,7 @@ public function register(IRegistrationContext $context): void {
$context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalScriptsListener::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, LoadAdditionalScriptsListener::class);
$context->registerEventListener(CircleDestroyedEvent::class, CircleDestroyedEventListener::class);
$context->registerEventListener(NodeRenamedEvent::class, NodeRenamedListener::class);

$context->registerService('GroupAppFolder', function (ContainerInterface $c): Folder {
/** @var IRootFolder $rootFolder */
Expand Down
62 changes: 62 additions & 0 deletions lib/Listeners/NodeRenamedListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2023 Côme Chilliet <[email protected]>
*
* @author Côme Chilliet <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\GroupFolders\Listeners;

use OCA\GroupFolders\Mount\GroupFolderStorage;
use OCA\GroupFolders\Trash\TrashManager;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeRenamedEvent;
use OCP\Files\Folder;
use Psr\Log\LoggerInterface;

/**
* @template-implements IEventListener<NodeRenamedEvent>
*/
class NodeRenamedListener implements IEventListener {
public function __construct(
private TrashManager $trashManager,
private LoggerInterface $logger,
) {
}

public function handle(Event $event): void {
$source = $event->getSource();
$target = $event->getTarget();
// Look at the parent because the node itself is not existing anymore
$sourceStorage = $source->getParent()->getStorage();
$targetStorage = $target->getStorage();

if (($target instanceof Folder) &&
$sourceStorage->instanceOfStorage(GroupFolderStorage::class) &&
$targetStorage->instanceOfStorage(GroupFolderStorage::class)) {
$sourcePath = preg_replace('/^'.preg_quote($source->getParent()->getMountPoint()->getMountPoint(), '/').'/', '', $source->getPath());
$targetPath = preg_replace('/^'.preg_quote($target->getMountPoint()->getMountPoint(), '/').'/', '', $target->getPath());
$this->trashManager->updateTrashedChildren($sourceStorage->getFolderId(), $targetStorage->getFolderId(), $sourcePath, $targetPath);
}
}
}
32 changes: 29 additions & 3 deletions lib/Trash/TrashManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
use OCP\IDBConnection;

class TrashManager {
private IDBConnection $connection;

public function __construct(IDBConnection $connection) {
public function __construct(
private IDBConnection $connection,
) {
$this->connection = $connection;
}

Expand Down Expand Up @@ -90,4 +90,30 @@ public function emptyTrashbin(int $folderId): void {
->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT)));
$query->executeStatement();
}

public function updateTrashedChildren(int $fromFolderId, int $toFolderId, string $fromLocation, string $toLocation): void {
// Update deep children
$query = $this->connection->getQueryBuilder();
$fun = $query->func();
$sourceLength = mb_strlen($fromLocation);
$newPathFunction = $fun->concat(
$query->createNamedParameter($toLocation),
$fun->substring('original_location', $query->createNamedParameter($sourceLength + 1, IQueryBuilder::PARAM_INT))// +1 for the leading slash
);
$query->update('group_folders_trash')
->set('folder_id', $query->createNamedParameter($toFolderId, IQueryBuilder::PARAM_INT))
->set('original_location', $newPathFunction)
->where($query->expr()->eq('folder_id', $query->createNamedParameter($fromFolderId, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->like('original_location', $query->createNamedParameter($this->connection->escapeLikeParameter($fromLocation) . '/%')));
$query->executeStatement();

// Update direct children
$query = $this->connection->getQueryBuilder();
$query->update('group_folders_trash')
->set('folder_id', $query->createNamedParameter($toFolderId, IQueryBuilder::PARAM_INT))
->set('original_location', $query->createNamedParameter($toLocation))
->where($query->expr()->eq('folder_id', $query->createNamedParameter($fromFolderId, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('original_location', $query->createNamedParameter($fromLocation, IQueryBuilder::PARAM_STR)));
$query->executeStatement();
}
}

0 comments on commit 8f60465

Please sign in to comment.