mirror of
https://github.com/nextcloud/server.git
synced 2026-05-22 01:55:56 -04:00
fix: handle share moves
Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
parent
adb8ed914f
commit
e7fcb6c7f5
10 changed files with 106 additions and 6 deletions
|
|
@ -57,6 +57,7 @@ use OCP\IDBConnection;
|
|||
use OCP\IGroup;
|
||||
use OCP\Share\Events\BeforeShareDeletedEvent;
|
||||
use OCP\Share\Events\ShareCreatedEvent;
|
||||
use OCP\Share\Events\ShareMovedEvent;
|
||||
use OCP\Share\Events\ShareTransferredEvent;
|
||||
use OCP\User\Events\UserChangedEvent;
|
||||
use OCP\User\Events\UserDeletedEvent;
|
||||
|
|
@ -125,6 +126,7 @@ class Application extends App implements IBootstrap {
|
|||
$context->registerEventListener(BeforeGroupDeletedEvent::class, SharesUpdatedListener::class);
|
||||
$context->registerEventListener(GroupDeletedEvent::class, SharesUpdatedListener::class);
|
||||
$context->registerEventListener(UserShareAccessUpdatedEvent::class, SharesUpdatedListener::class);
|
||||
$context->registerEventListener(ShareMovedEvent::class, SharesUpdatedListener::class);
|
||||
$context->registerEventListener(UserHomeSetupEvent::class, UserHomeSetupListener::class);
|
||||
|
||||
$context->registerConfigLexicon(ConfigLexicon::class);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use OCP\IAppConfig;
|
|||
use OCP\IUser;
|
||||
use OCP\Share\Events\BeforeShareDeletedEvent;
|
||||
use OCP\Share\Events\ShareCreatedEvent;
|
||||
use OCP\Share\Events\ShareMovedEvent;
|
||||
use OCP\Share\Events\ShareTransferredEvent;
|
||||
use OCP\Share\IManager;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
|
@ -31,7 +32,7 @@ use Psr\Clock\ClockInterface;
|
|||
* Listen to various events that can change what shares a user has access to
|
||||
*
|
||||
* @psalm-type GroupEvents = UserAddedEvent|UserRemovedEvent|GroupDeletedEvent|BeforeGroupDeletedEvent
|
||||
* @template-implements IEventListener<GroupEvents|ShareCreatedEvent|ShareTransferredEvent|BeforeShareDeletedEvent|UserShareAccessUpdatedEvent>
|
||||
* @template-implements IEventListener<GroupEvents|ShareCreatedEvent|ShareTransferredEvent|BeforeShareDeletedEvent|UserShareAccessUpdatedEvent|ShareMovedEvent>
|
||||
*/
|
||||
class SharesUpdatedListener implements IEventListener {
|
||||
/**
|
||||
|
|
@ -88,6 +89,14 @@ class SharesUpdatedListener implements IEventListener {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ($event instanceof ShareMovedEvent) {
|
||||
$share = $event->getShare();
|
||||
foreach ($this->shareManager->getUsersForShare($share) as $user) {
|
||||
$this->markOrRun($user, function () use ($user, $share) {
|
||||
$this->shareUpdater->updateForMovedShare($user, $share);
|
||||
});
|
||||
}
|
||||
}
|
||||
if ($event instanceof BeforeShareDeletedEvent) {
|
||||
$share = $event->getShare();
|
||||
foreach ($this->shareManager->getUsersForShare($share) as $user) {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class ShareRecipientUpdater {
|
|||
$mountsChanged = count($shares) !== count($shareMounts);
|
||||
foreach ($shares as $share) {
|
||||
[$parentShare, $groupedShares] = $share;
|
||||
$mountPoint = '/' . $user->getUID() . '/files/' . trim($parentShare->getTarget(), '/') . '/';
|
||||
$mountPoint = $this->getMountPointFromTarget($user, $parentShare->getTarget());
|
||||
$mountKey = $parentShare->getNodeId() . '::' . $mountPoint;
|
||||
if (!isset($cachedMounts[$mountKey])) {
|
||||
$mountsChanged = true;
|
||||
|
|
@ -72,17 +72,34 @@ class ShareRecipientUpdater {
|
|||
$mountsByPath = array_combine($mountPoints, $cachedMounts);
|
||||
|
||||
$target = $this->shareTargetValidator->verifyMountPoint($user, $share, $mountsByPath, [$share]);
|
||||
$mountPoint = '/' . $user->getUID() . '/files/' . trim($target, '/') . '/';
|
||||
$mountPoint = $this->getMountPointFromTarget($user, $target);
|
||||
|
||||
$this->userMountCache->addMount($user, $mountPoint, $share->getNode()->getData(), MountProvider::class);
|
||||
}
|
||||
|
||||
private function getMountPointFromTarget(IUser $user, string $target): string {
|
||||
return '/' . $user->getUID() . '/files/' . trim($target, '/') . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single deleted share for a user
|
||||
*/
|
||||
public function updateForDeletedShare(IUser $user, IShare $share): void {
|
||||
$mountPoint = '/' . $user->getUID() . '/files/' . trim($share->getTarget(), '/') . '/';
|
||||
$this->userMountCache->removeMount($this->getMountPointFromTarget($user, $share->getTarget()));
|
||||
}
|
||||
|
||||
$this->userMountCache->removeMount($mountPoint);
|
||||
/**
|
||||
* Process a single moved share for a user
|
||||
*/
|
||||
public function updateForMovedShare(IUser $user, IShare $share): void {
|
||||
$originalTarget = $share->getOriginalTarget();
|
||||
if ($originalTarget != null) {
|
||||
$newMountPoint = $this->getMountPointFromTarget($user, $share->getTarget());
|
||||
$oldMountPoint = $this->getMountPointFromTarget($user, $originalTarget);
|
||||
$this->userMountCache->removeMount($oldMountPoint);
|
||||
$this->userMountCache->addMount($user, $newMountPoint, $share->getNode()->getData(), MountProvider::class);
|
||||
} else {
|
||||
$this->updateForUser($user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -414,3 +414,15 @@ Scenario: User added/removed to group share with marking
|
|||
| /user0/files/textfile0 (2).txt/ |
|
||||
When Connecting to dav endpoint
|
||||
Then Share mounts for "user0" are empty
|
||||
|
||||
Scenario: Share moved without marking
|
||||
Given As an "admin"
|
||||
And user "user0" exists
|
||||
And user "user1" exists
|
||||
And file "textfile0.txt" of user "user1" is shared with user "user0"
|
||||
And As an "user0"
|
||||
Then Share mounts for "user0" match
|
||||
| /user0/files/textfile0 (2).txt/ |
|
||||
When User "user0" moves file "/textfile0 (2).txt" to "/target.txt"
|
||||
Then Share mounts for "user0" match
|
||||
| /user0/files/target.txt/ |
|
||||
|
|
|
|||
|
|
@ -850,6 +850,7 @@ return array(
|
|||
'OCP\\Share\\Events\\ShareCreatedEvent' => $baseDir . '/lib/public/Share/Events/ShareCreatedEvent.php',
|
||||
'OCP\\Share\\Events\\ShareDeletedEvent' => $baseDir . '/lib/public/Share/Events/ShareDeletedEvent.php',
|
||||
'OCP\\Share\\Events\\ShareDeletedFromSelfEvent' => $baseDir . '/lib/public/Share/Events/ShareDeletedFromSelfEvent.php',
|
||||
'OCP\\Share\\Events\\ShareMovedEvent' => $baseDir . '/lib/public/Share/Events/ShareMovedEvent.php',
|
||||
'OCP\\Share\\Events\\ShareTransferredEvent' => $baseDir . '/lib/public/Share/Events/ShareTransferredEvent.php',
|
||||
'OCP\\Share\\Events\\VerifyMountPointEvent' => $baseDir . '/lib/public/Share/Events/VerifyMountPointEvent.php',
|
||||
'OCP\\Share\\Exceptions\\AlreadySharedException' => $baseDir . '/lib/public/Share/Exceptions/AlreadySharedException.php',
|
||||
|
|
|
|||
|
|
@ -891,6 +891,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OCP\\Share\\Events\\ShareCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareCreatedEvent.php',
|
||||
'OCP\\Share\\Events\\ShareDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareDeletedEvent.php',
|
||||
'OCP\\Share\\Events\\ShareDeletedFromSelfEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareDeletedFromSelfEvent.php',
|
||||
'OCP\\Share\\Events\\ShareMovedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareMovedEvent.php',
|
||||
'OCP\\Share\\Events\\ShareTransferredEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareTransferredEvent.php',
|
||||
'OCP\\Share\\Events\\VerifyMountPointEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/VerifyMountPointEvent.php',
|
||||
'OCP\\Share\\Exceptions\\AlreadySharedException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/AlreadySharedException.php',
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ use OCP\Share\Events\ShareAcceptedEvent;
|
|||
use OCP\Share\Events\ShareCreatedEvent;
|
||||
use OCP\Share\Events\ShareDeletedEvent;
|
||||
use OCP\Share\Events\ShareDeletedFromSelfEvent;
|
||||
use OCP\Share\Events\ShareMovedEvent;
|
||||
use OCP\Share\Exceptions\AlreadySharedException;
|
||||
use OCP\Share\Exceptions\GenericShareException;
|
||||
use OCP\Share\Exceptions\ShareNotFound;
|
||||
|
|
@ -1200,7 +1201,11 @@ class Manager implements IManager {
|
|||
[$providerId,] = $this->splitFullId($share->getFullId());
|
||||
$provider = $this->factory->getProvider($providerId);
|
||||
|
||||
return $provider->move($share, $recipientId);
|
||||
$result = $provider->move($share, $recipientId);
|
||||
|
||||
$this->dispatchEvent(new ShareMovedEvent($share), 'share moved');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ class Share implements IShare {
|
|||
private ?int $parent = null;
|
||||
/** @var string */
|
||||
private $target;
|
||||
/** @var string */
|
||||
private ?string $originalTarget = null;
|
||||
/** @var \DateTime */
|
||||
private $shareTime;
|
||||
/** @var bool */
|
||||
|
|
@ -514,10 +516,21 @@ class Share implements IShare {
|
|||
* @inheritdoc
|
||||
*/
|
||||
public function setTarget($target) {
|
||||
// if the target is changed, save the original target
|
||||
if ($this->target && !$this->originalTarget) {
|
||||
$this->originalTarget = $this->target;
|
||||
}
|
||||
$this->target = $target;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the original target, if this share was moved
|
||||
*/
|
||||
public function getOriginalTarget(): ?string {
|
||||
return $this->originalTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
|||
33
lib/public/Share/Events/ShareMovedEvent.php
Normal file
33
lib/public/Share/Events/ShareMovedEvent.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\Share\Events;
|
||||
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\Share\IShare;
|
||||
|
||||
/**
|
||||
* @since 33.0.0
|
||||
*/
|
||||
class ShareMovedEvent extends Event {
|
||||
/**
|
||||
* @since 33.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly IShare $share,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 33.0.0
|
||||
*/
|
||||
public function getShare(): IShare {
|
||||
return $this->share;
|
||||
}
|
||||
}
|
||||
|
|
@ -545,6 +545,13 @@ interface IShare {
|
|||
*/
|
||||
public function setTarget($target);
|
||||
|
||||
/**
|
||||
* Return the original target, if this share was moved
|
||||
*
|
||||
* @since 33.0.0
|
||||
*/
|
||||
public function getOriginalTarget(): ?string;
|
||||
|
||||
/**
|
||||
* Get the target path of this share relative to the recipients user folder.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue