Skip to content

Commit 90ab895

Browse files
committed
fixup! Switch to OCP proposal
1 parent a4df471 commit 90ab895

5 files changed

Lines changed: 155 additions & 71 deletions

File tree

README.md

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ Administrators can also lock files using the `./occ` command:
3030

3131
If locking is available the app will expose itself through the capabilties endpoint under the files key:
3232
```
33-
curl http://admin:admin@nextcloud.local/ocs/v1.php/cloud/capabilities\?format\=json -H 'OCS-APIRequest: true' \
33+
curl http://admin:admin@nextcloud.local/ocs/v1.php/cloud/capabilities\?format\=json \
34+
-H 'OCS-APIRequest: true' \
3435
| jq .ocs.data.capabilities.files
3536
{
3637
...
@@ -39,16 +40,97 @@ curl http://admin:admin@nextcloud.local/ocs/v1.php/cloud/capabilities\?format\=j
3940
}
4041
```
4142

42-
### Fetching lock details
43+
### WebDAV: Fetching lock details
4344

4445
WebDAV returns the following additional properties if requests through a `PROPFIND`:
4546

4647
- `{http://nextcloud.org/ns}lock`: `true` if the file is locked, otherwise `false`
48+
- `{http://nextcloud.org/ns}lock-owner-type`: User id of the lock owner
49+
- `0` represents a manual lock by a user
50+
- `1` represents a collaboratively locked file, e.g. when being edited through Office or Text
51+
- `2` represents a WebDAV lock identified by a lock token, which will have the other properties set as if it was type 0
4752
- `{http://nextcloud.org/ns}lock-owner`: User id of the lock owner
4853
- `{http://nextcloud.org/ns}lock-owner-displayname`: Display name of the lock owner
4954
- `{http://nextcloud.org/ns}lock-time`: Timestamp of the log creation time
5055

51-
### Locking a file
56+
```bash
57+
curl -X PROPFIND \
58+
--url http://admin:admin@nextcloud.dev.local/remote.php/dav/files/admin/myfile.odt \
59+
--data '<D:propfind xmlns:D="DAV:" xmlns:NC="http://nextcloud.org/ns">
60+
<D:prop>
61+
<NC:lock />
62+
<NC:lock-owner-type />
63+
<NC:lock-owner />
64+
<NC:lock-owner-displayname />
65+
<NC:lock-owner-editor />
66+
<NC:lock-time />
67+
</D:prop>
68+
</D:propfind>'
69+
```
70+
71+
72+
### WebDAV: Manually lock a file
73+
74+
```
75+
curl -X LOCK \
76+
--url http://admin:admin@nextcloud.dev.local/remote.php/dav/files/admin/myfile.odt \
77+
--header 'X-User-Lock: 1'
78+
```
79+
80+
#### Response
81+
82+
The response will give back the updated properties after obtaining the lock with a `200 Success` status code or the existing lock details in case of a `423 Locked` status.
83+
84+
```xml
85+
<?xml version="1.0"?>
86+
<d:prop
87+
xmlns:d="DAV:"
88+
xmlns:s="http://sabredav.org/ns"
89+
xmlns:oc="http://owncloud.org/ns"
90+
xmlns:nc="http://nextcloud.org/ns">
91+
<nc:lock>1</nc:lock>
92+
<nc:lock-owner-type>0</nc:lock-owner-type>
93+
<nc:lock-owner>user1</nc:lock-owner>
94+
<nc:lock-owner-displayname>user1</nc:lock-owner-displayname>
95+
<nc:lock-owner-editor>user1</nc:lock-owner-editor>
96+
<nc:lock-time>1648046707</nc:lock-time>
97+
</d:prop>
98+
```
99+
100+
101+
102+
### WebDAV: Manually unlock a file
103+
104+
```
105+
curl -X UNLOCK \
106+
--url http://admin:admin@nextcloud.dev.local/remote.php/dav/files/admin/myfile.odt \
107+
--header 'X-User-Lock: 1'
108+
```
109+
110+
#### Response
111+
112+
```xml
113+
<?xml version="1.0"?>
114+
<d:prop
115+
xmlns:d="DAV:"
116+
xmlns:s="http://sabredav.org/ns"
117+
xmlns:oc="http://owncloud.org/ns"
118+
xmlns:nc="http://nextcloud.org/ns">
119+
<nc:lock></nc:lock>
120+
<nc:lock-owner-type/>
121+
<nc:lock-owner/>
122+
<nc:lock-owner-displayname/>
123+
<nc:lock-owner-editor/>
124+
<nc:lock-time/>
125+
</d:prop>
126+
127+
```
128+
129+
#### Error types
130+
131+
- 423 Locked
132+
133+
### OCS: Locking a file
52134

53135
`PUT /apps/files_lock/lock/{fileId}`
54136

@@ -86,7 +168,7 @@ curl -X PUT 'http://admin:admin@nextcloud.local/ocs/v2.php/apps/files_lock/lock/
86168
```
87169
88170
89-
### Unlocking a file
171+
### OCS: Unlocking a file
90172
91173
`DELETE /apps/files_lock/lock/{fileId}`
92174

lib/Command/Lock.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
use OC\Core\Command\Base;
3434
use OC\User\NoUserException;
3535
use OCA\FilesLock\Db\LocksRequest;
36-
use OCA\FilesLock\Exceptions\AlreadyLockedException;
3736
use OCA\FilesLock\Exceptions\LockNotFoundException;
3837
use OCA\FilesLock\Exceptions\NotFileException;
3938
use OCA\FilesLock\Exceptions\SuccessException;
@@ -118,7 +117,6 @@ protected function configure() {
118117
* @throws NoUserException
119118
* @throws NotFoundException
120119
* @throws UnauthorizedUnlockException
121-
* @throws AlreadyLockedException
122120
* @throws NotFileException
123121
* @throws InvalidPathException
124122
*/
@@ -178,7 +176,6 @@ private function getStatus(InputInterface $input, OutputInterface $output, int $
178176
* @param int $fileId
179177
* @param string|null $userId
180178
*
181-
* @throws AlreadyLockedException
182179
* @throws InvalidPathException
183180
* @throws NoUserException
184181
* @throws NotFileException

lib/DAV/LockPlugin.php

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,20 @@
66
use OCA\DAV\Connector\Sabre\Node as SabreNode;
77
use OCA\DAV\Connector\Sabre\ObjectTree;
88
use OCA\FilesLock\AppInfo\Application;
9+
use OCA\FilesLock\Exceptions\LockNotFoundException;
10+
use OCA\FilesLock\Exceptions\NotFileException;
11+
use OCA\FilesLock\Exceptions\UnauthorizedUnlockException;
912
use OCA\FilesLock\Model\FileLock;
1013
use OCA\FilesLock\Service\AppLockService;
1114
use OCA\FilesLock\Service\FileService;
1215
use OCA\FilesLock\Service\LockService;
1316
use OCP\DirectEditing\IManager;
1417
use OCP\DirectEditing\RegisterDirectEditorEvent;
1518
use OCP\EventDispatcher\IEventDispatcher;
19+
use OCP\Files\InvalidPathException;
1620
use OCP\Files\Lock\ILock;
21+
use OCP\Files\Lock\OwnerLockedException;
22+
use OCP\Files\NotFoundException;
1723
use OCP\IUserManager;
1824
use OCP\IUserSession;
1925
use Sabre\DAV\INode;
@@ -130,29 +136,72 @@ public function customProperties(PropFind $propFind, INode $node) {
130136
});
131137
}
132138

139+
private function getLockDisplayName(ILock $lock): ?string {
140+
$user = $this->userManager->get($lock->getOwner());
141+
if ($user !== null) {
142+
return $user->getDisplayName();
143+
}
144+
145+
return null;
146+
}
147+
133148
public function httpLock(RequestInterface $request, ResponseInterface $response) {
134149
if ($request->getHeader('X-User-Lock')) {
135-
$file = $this->fileService->getFileFromAbsoluteUri($this->server->getRequestUri());
136-
$this->lockService->lockFileAsUser($file, $this->userSession->getUser());
137150
$response->setHeader('Content-Type', 'application/xml; charset=utf-8');
138-
//$response->setHeader('Lock-Token', '<opaquelocktoken:'.$lockInfo->token.'>');
139-
//$response->setStatus($newFile ? 201 : 200);
140-
//$response->setBody($this->generateLockResponse($lockInfo));
141-
$response->setStatus(200);
151+
152+
try {
153+
$file = $this->fileService->getFileFromAbsoluteUri($this->server->getRequestUri());
154+
$lockInfo = $this->lockService->lockFileAsUser($file, $this->userSession->getUser());
155+
$response->setStatus(200);
156+
$response->setBody($this->server->xml->write('{DAV:}prop', [
157+
Application::DAV_PROPERTY_LOCK => true,
158+
Application::DAV_PROPERTY_LOCK_OWNER_TYPE => $lockInfo->getLockType(),
159+
Application::DAV_PROPERTY_LOCK_OWNER => $lockInfo->getOwner(),
160+
Application::DAV_PROPERTY_LOCK_OWNER_DISPLAYNAME => $this->getLockDisplayName($lockInfo),
161+
Application::DAV_PROPERTY_LOCK_EDITOR => $lockInfo->getOwner(),
162+
Application::DAV_PROPERTY_LOCK_TIME => $lockInfo->getCreatedAt(),
163+
]));
164+
} catch (OwnerLockedException $e) {
165+
$lockInfo = $e->getLock();
166+
$response->setStatus(423);
167+
$response->setBody($this->server->xml->write('{DAV:}prop', [
168+
Application::DAV_PROPERTY_LOCK => true,
169+
Application::DAV_PROPERTY_LOCK_OWNER_TYPE => $lockInfo->getLockType(),
170+
Application::DAV_PROPERTY_LOCK_OWNER => $lockInfo->getOwner(),
171+
Application::DAV_PROPERTY_LOCK_OWNER_DISPLAYNAME => $this->getLockDisplayName($lockInfo),
172+
Application::DAV_PROPERTY_LOCK_EDITOR => $lockInfo->getOwner(),
173+
Application::DAV_PROPERTY_LOCK_TIME => $lockInfo->getCreatedAt(),
174+
]));
175+
}
176+
142177
return false;
143178
}
144179
return parent::httpLock($request, $response);
145180
}
146181

147182
public function httpUnlock(RequestInterface $request, ResponseInterface $response) {
148183
if ($request->getHeader('X-User-Lock')) {
149-
$file = $this->fileService->getFileFromAbsoluteUri($this->server->getRequestUri());
150-
$this->lockService->unlockFile($file->getId(), $this->userSession->getUser()->getUID());
151184
$response->setHeader('Content-Type', 'application/xml; charset=utf-8');
152-
//$response->setHeader('Lock-Token', '<opaquelocktoken:'.$lockInfo->token.'>');
153-
//$response->setStatus($newFile ? 201 : 200);
154-
//$response->setBody($this->generateLockResponse($lockInfo));
155-
$response->setStatus(200);
185+
186+
try {
187+
$file = $this->fileService->getFileFromAbsoluteUri($this->server->getRequestUri());
188+
$lockInfo = $this->lockService->unlockFile($file->getId(), $this->userSession->getUser()->getUID());
189+
$response->setStatus(200);
190+
$response->setBody($this->server->xml->write('{DAV:}prop', [
191+
Application::DAV_PROPERTY_LOCK => false,
192+
Application::DAV_PROPERTY_LOCK_OWNER_TYPE => null,
193+
Application::DAV_PROPERTY_LOCK_OWNER => null,
194+
Application::DAV_PROPERTY_LOCK_OWNER_DISPLAYNAME => null,
195+
Application::DAV_PROPERTY_LOCK_EDITOR => null,
196+
Application::DAV_PROPERTY_LOCK_TIME => null,
197+
]));
198+
} catch (LockNotFoundException $e) {
199+
$response->setStatus(403);
200+
} catch (UnauthorizedUnlockException $e) {
201+
$response->setStatus(403);
202+
} catch (InvalidPathException $e) {
203+
} catch (NotFoundException $e) {
204+
}
156205
return false;
157206
}
158207
return parent::httpLock($request, $response);

lib/Exceptions/AlreadyLockedException.php

Lines changed: 0 additions & 39 deletions
This file was deleted.

lib/Service/LockService.php

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,22 @@
3131

3232

3333
use Exception;
34-
use OCA\DAV\Connector\Sabre\Node as SabreNode;
35-
use OCA\FilesLock\AppInfo\Application;
3634
use OCA\FilesLock\Db\LocksRequest;
37-
use OCA\FilesLock\Exceptions\AlreadyLockedException;
3835
use OCA\FilesLock\Exceptions\LockNotFoundException;
3936
use OCA\FilesLock\Exceptions\NotFileException;
4037
use OCA\FilesLock\Exceptions\UnauthorizedUnlockException;
4138
use OCA\FilesLock\Model\FileLock;
4239
use OCA\FilesLock\Tools\Traits\TLogger;
4340
use OCA\FilesLock\Tools\Traits\TStringTools;
4441
use OCP\App\IAppManager;
45-
use OCP\DirectEditing\IManager;
46-
use OCP\DirectEditing\RegisterDirectEditorEvent;
47-
use OCP\EventDispatcher\IEventDispatcher;
4842
use OCP\Files\InvalidPathException;
43+
use OCP\Files\Lock\OwnerLockedException;
4944
use OCP\Files\Node;
5045
use OCP\Files\NotFoundException;
5146
use OCP\IL10N;
5247
use OCP\IUser;
5348
use OCP\IUserManager;
54-
use OCP\Notification\IApp;
5549
use OCP\PreConditionNotMetException;
56-
use Sabre\DAV\INode;
57-
use Sabre\DAV\PropFind;
5850

5951

6052
/**
@@ -129,16 +121,19 @@ public function getLockForNodeId(int $nodeId) {
129121
/**
130122
* @param FileLock $lock
131123
*
132-
* @throws AlreadyLockedException
124+
* @throws OwnerLockedException
133125
*/
134126
public function lock(FileLock $lock) {
135127
$this->generateToken($lock);
136128
$this->notice('locking file', false, ['fileLock' => $lock]);
137129

138130
try {
139131
$known = $this->getLockFromFileId($lock->getFileId());
140-
141-
throw new AlreadyLockedException('File is already locked by ' . $known->getOwner());
132+
if ($known->getLockType() === $lock->getLockType() && $known->getOwner() === $lock->getOwner()) {
133+
// TODO refresh
134+
return;
135+
}
136+
throw new OwnerLockedException($known);
142137
} catch (LockNotFoundException $e) {
143138
$this->locksRequest->save($lock);
144139
}
@@ -150,10 +145,10 @@ public function lock(FileLock $lock) {
150145
* @param IUser $user
151146
*
152147
* @return FileLock
153-
* @throws AlreadyLockedException
154148
* @throws InvalidPathException
155149
* @throws NotFileException
156150
* @throws NotFoundException
151+
* @throws OwnerLockedException
157152
*/
158153
public function lockFileAsUser(Node $file, IUser $user): FileLock {
159154
if ($file->getType() !== Node::TYPE_FILE) {

0 commit comments

Comments
 (0)