Skip to content

Commit 531815e

Browse files
committed
feat: Implement handling for lock managers who can unlock files
Signed-off-by: Julius Härtl <[email protected]>
1 parent 1b3d345 commit 531815e

File tree

6 files changed

+47
-30
lines changed

6 files changed

+47
-30
lines changed

lib/AppInfo/Application.php

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class Application extends App implements IBootstrap {
6767
public const DAV_PROPERTY_LOCK_TIME = '{http://nextcloud.org/ns}lock-time';
6868
public const DAV_PROPERTY_LOCK_TIMEOUT = '{http://nextcloud.org/ns}lock-timeout';
6969
public const DAV_PROPERTY_LOCK_TOKEN = '{http://nextcloud.org/ns}lock-token';
70+
public const DAV_PROPERTY_LOCK_MANAGER = '{http://nextcloud.org/ns}lock-manager';
7071

7172

7273
/** @var IUserSession */

lib/DAV/LockPlugin.php

+4
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ public function customProperties(PropFind $propFind, INode $node) {
179179

180180
return $lock->getToken();
181181
});
182+
183+
$propFind->handle(Application::DAV_PROPERTY_LOCK_MANAGER, function () use ($node) {
184+
return $this->lockService->isLockManager($this->userSession->getUser(), $node->getNode());
185+
});
182186
}
183187

184188
public function httpLock(RequestInterface $request, ResponseInterface $response) {

lib/Service/LockService.php

+33-30
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,18 @@
3838
use OCA\FilesLock\Model\FileLock;
3939
use OCA\FilesLock\Tools\Traits\TLogger;
4040
use OCA\FilesLock\Tools\Traits\TStringTools;
41+
use OCA\GroupFolders\Mount\GroupMountPoint;
4142
use OCP\App\IAppManager;
4243
use OCP\EventDispatcher\IEventDispatcher;
4344
use OCP\Files\InvalidPathException;
4445
use OCP\Files\Lock\ILock;
4546
use OCP\Files\Lock\LockContext;
4647
use OCP\Files\Lock\OwnerLockedException;
48+
use OCP\Files\Node;
4749
use OCP\Files\NotFoundException;
50+
use OCP\IGroupManager;
4851
use OCP\IL10N;
52+
use OCP\IUser;
4953
use OCP\IUserManager;
5054

5155
/**
@@ -56,47 +60,26 @@
5660
class LockService {
5761
public const PREFIX = 'files_lock';
5862

59-
6063
use TStringTools;
6164
use TLogger;
6265

63-
64-
private ?string $userId;
65-
private IUserManager $userManager;
66-
private IL10N $l10n;
67-
private LocksRequest $locksRequest;
68-
private FileService $fileService;
69-
private ConfigService $configService;
70-
private IAppManager $appManager;
71-
private IEventDispatcher $eventDispatcher;
72-
73-
7466
private array $locks = [];
7567
private bool $lockRetrieved = false;
7668
private array $lockCache = [];
7769
private ?array $directEditors = null;
7870
private bool $allowUserOverride = false;
7971

80-
8172
public function __construct(
82-
$userId,
83-
IL10N $l10n,
84-
IUserManager $userManager,
85-
LocksRequest $locksRequest,
86-
FileService $fileService,
87-
ConfigService $configService,
88-
IAppManager $appManager,
89-
IEventDispatcher $eventDispatcher
73+
private ?string $userId,
74+
private IL10N $l10n,
75+
private IUserManager $userManager,
76+
private IGroupManager $groupManager,
77+
private LocksRequest $locksRequest,
78+
private FileService $fileService,
79+
private ConfigService $configService,
80+
private IAppManager $appManager,
81+
private IEventDispatcher $eventDispatcher
9082
) {
91-
$this->userId = $userId;
92-
$this->l10n = $l10n;
93-
$this->userManager = $userManager;
94-
$this->locksRequest = $locksRequest;
95-
$this->fileService = $fileService;
96-
$this->configService = $configService;
97-
$this->appManager = $appManager;
98-
$this->eventDispatcher = $eventDispatcher;
99-
10083
$this->setup('app', 'files_lock');
10184
}
10285

@@ -402,4 +385,24 @@ private function propagateEtag(LockContext $lockContext): void {
402385
]);
403386
$node->getStorage()->getUpdater()->propagate($node->getInternalPath(), $node->getMTime());
404387
}
388+
389+
public function isLockManager(IUser $user, ?Node $node): bool {
390+
if ($this->groupManager->isAdmin($user->getUID())) {
391+
return true;
392+
}
393+
394+
$lockManagerGroups = explode('|', $this->configService->getAppValue('lock_managers') ?? '');
395+
$userGroups = $this->groupManager->getUserGroupIds($user);
396+
$matchGroups = !empty(array_intersect($lockManagerGroups, $userGroups));
397+
398+
if ($matchGroups) {
399+
return true;
400+
}
401+
402+
if ($node && $node->getOwner()?->getUID() === $user?->getUID() && !$node->getMountPoint() instanceof GroupMountPoint) {
403+
return true;
404+
}
405+
406+
return false;
407+
}
405408
}

src/helper.ts

+7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const getLockStateFromAttributes = (node: Node): LockState => {
3333
lockOwnerType: parseInt(node.attributes['lock-owner-type']),
3434
lockOwnerEditor: node.attributes['lock-owner-editor'],
3535
lockTime: parseInt(node.attributes['lock-time']),
36+
lockManager: !!node.attributes['lock-manager'],
3637
}
3738
}
3839

@@ -53,6 +54,12 @@ export const canUnlock = (node: Node): boolean => {
5354
return false
5455
}
5556

57+
const aclManager = !!node.attributes['acl-can-manage']
58+
59+
if (state.lockManager || aclManager) {
60+
return true
61+
}
62+
5663
if (state.lockOwnerType === LockType.User && state.lockOwner === getCurrentUser()?.uid) {
5764
return true
5865
}

src/init.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ registerDavProperty('nc:lock-owner-displayname', { nc: 'http://nextcloud.org/ns'
1111
registerDavProperty('nc:lock-owner-type', { nc: 'http://nextcloud.org/ns' })
1212
registerDavProperty('nc:lock-owner-editor', { nc: 'http://nextcloud.org/ns' })
1313
registerDavProperty('nc:lock-time', { nc: 'http://nextcloud.org/ns' })
14+
registerDavProperty('nc:lock-manager', { nc: 'http://nextcloud.org/ns' })

src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ export type LockState = {
3030
lockOwnerDisplayName: string,
3131
lockOwnerType: LockType,
3232
lockOwnerEditor: string,
33+
lockManager: boolean,
3334
lockTime: number,
3435
}

0 commit comments

Comments
 (0)