Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use OCP\Files\Cache\CacheEntryInsertedEvent;
use OCP\Files\Cache\CacheEntryRemovedEvent;
use OCP\Files\Cache\CacheEntryUpdatedEvent;
use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Group\Events\UserAddedEvent;
use OCP\Group\Events\UserRemovedEvent;
use OCP\Security\CSP\AddContentSecurityPolicyEvent;
Expand Down Expand Up @@ -71,6 +72,7 @@ public function attachHooks(
$eventDispatcher->addListener(CacheEntryInsertedEvent::class, [$listener, 'cacheListener']);
$eventDispatcher->addListener(CacheEntryUpdatedEvent::class, [$listener, 'cacheListener']);
$eventDispatcher->addListener(CacheEntryRemovedEvent::class, [$listener, 'cacheListener']);
$eventDispatcher->addListener(NodeDeletedEvent::class, [$listener, 'nodeDeletedListener']);

$eventDispatcher->addListener(UserAddedEvent::class, [$listener, 'groupListener']);
$eventDispatcher->addListener(UserRemovedEvent::class, [$listener, 'groupListener']);
Expand Down
48 changes: 32 additions & 16 deletions lib/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
use OCP\Activity\IEvent;
use OCP\EventDispatcher\Event;
use OCP\Files\Cache\ICacheEvent;
use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Files\IHomeStorage;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
use OCP\Group\Events\UserAddedEvent;
use OCP\Group\Events\UserRemovedEvent;
Expand All @@ -35,22 +37,36 @@ public function __construct(IQueue $queue) {

public function cacheListener(Event $event): void {
if ($event instanceof ICacheEvent) {
$path = $event->getPath();

$storage = $event->getStorage();
while ($storage->instanceOfStorage(Jail::class)) {
/** @var Jail $storage */
$path = $storage->getUnjailedPath($path);
$storage = $storage->getUnjailedStorage();
}

if ($this->shouldNotifyPath($event->getStorage(), $path)) {
$this->queue->push('notify_storage_update', [
'storage' => $event->getStorageId(),
'path' => $path,
'file_id' => $event->getFileId(),
]);
}
$this->pushStorageUpdate($event->getStorage(), $event->getStorageId(), $event->getPath(), $event->getFileId());
}
}

/**
* Moving a file to the trash bin only updates its cache entry to the path in the trash bin,
* which users don't see. Notify the path it was deleted from as well.
*/
public function nodeDeletedListener(NodeDeletedEvent $event): void {
$node = $event->getNode();
try {
$storage = $node->getStorage();
$this->pushStorageUpdate($storage, $storage->getCache()->getNumericStorageId(), $node->getInternalPath(), $node->getId());
} catch (NotFoundException) {
}
}

private function pushStorageUpdate(IStorage $storage, int $storageId, string $path, int $fileId): void {
while ($storage->instanceOfStorage(Jail::class)) {
/** @var Jail $storage */
$path = $storage->getUnjailedPath($path);
$storage = $storage->getUnjailedStorage();
}

if ($this->shouldNotifyPath($storage, $path)) {
$this->queue->push('notify_storage_update', [
'storage' => $storageId,
'path' => $path,
'file_id' => $fileId,
]);
}
}

Expand Down
50 changes: 50 additions & 0 deletions tests/lib/ListenerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
use OCA\NotifyPush\Listener;
use OCA\NotifyPush\Queue\IQueue;
use OCP\Files\Cache\CacheEntryInsertedEvent;
use OCP\Files\Cache\CacheEntryUpdatedEvent;
use OCP\Files\Cache\ICache;
use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Files\File;
use OCP\Files\IHomeStorage;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
use OCP\Group\Events\UserAddedEvent;
use OCP\Group\Events\UserRemovedEvent;
Expand Down Expand Up @@ -56,6 +62,50 @@ public function testCacheEvents() {
], $events);
}

private function getHomeStorage(): IStorage {
$cache = $this->createMock(ICache::class);
$cache->method('getNumericStorageId')->willReturn(1);
$storage = $this->createMock(IStorage::class);
$storage->method('getCache')->willReturn($cache);
$storage->method('instanceOfStorage')->willReturnCallback(static fn (string $class): bool => $class === IHomeStorage::class);
return $storage;
}

public function testFileMovedToTheTrashBin() {
$events = [];
$listener = new Listener($this->getQueue($events));
$storage = $this->getHomeStorage();

// The cache entry moves to the trash bin, users don't see that path
$listener->cacheListener(new CacheEntryUpdatedEvent($storage, 'files_trashbin/files/report.md.d1760000000', 12, 1));
$this->assertEquals([], $events);

$node = $this->createMock(File::class);
$node->method('getStorage')->willReturn($storage);
$node->method('getInternalPath')->willReturn('files/Documents/report.md');
$node->method('getId')->willReturn(12);
$listener->nodeDeletedListener(new NodeDeletedEvent($node));

$this->assertEquals([
'notify_storage_update' => [
['storage' => 1, 'path' => 'files/Documents/report.md', 'file_id' => 12],
],
], $events);
}

public function testDeletedNodeWithoutInfo() {
$events = [];
$listener = new Listener($this->getQueue($events));

$node = $this->createMock(File::class);
$node->method('getStorage')->willReturn($this->getHomeStorage());
$node->method('getInternalPath')->willReturn('files/report.md');
$node->method('getId')->willThrowException(new NotFoundException());
$listener->nodeDeletedListener(new NodeDeletedEvent($node));

$this->assertEquals([], $events);
}

public function testGroupEvents() {
$events = [];
$queue = $this->getQueue($events);
Expand Down
Loading