Skip to content

Commit 52db34b

Browse files
committed
fix: catch ManuallyLockedException and use app context
The files_lock app may throw ManuallyLockedExceptions when attempting to revert a file that is currently opened. This would prevent the user from rolling back a opened file. Text and Richdocuments handle changes of the file while editing. Allow reverting files even when they are locked by these apps and let the apps handle the conflict. Signed-off-by: Max <[email protected]>
1 parent b21c5c8 commit 52db34b

File tree

1 file changed

+47
-1
lines changed

1 file changed

+47
-1
lines changed

apps/files_versions/lib/Versions/VersionManager.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@
2727

2828
use OCP\Files\File;
2929
use OCP\Files\FileInfo;
30+
use OCP\Files\IRootFolder;
31+
use OCP\Files\Lock\ILock;
32+
use OCP\Files\Lock\ILockManager;
33+
use OCP\Files\Lock\LockContext;
3034
use OCP\Files\Storage\IStorage;
3135
use OCP\IUser;
36+
use OCP\Lock\ManuallyLockedException;
3237

3338
class VersionManager implements IVersionManager, INameableVersionBackend, IDeletableVersionBackend {
3439
/** @var (IVersionBackend[])[] */
@@ -94,7 +99,7 @@ public function createVersion(IUser $user, FileInfo $file) {
9499

95100
public function rollback(IVersion $version) {
96101
$backend = $version->getBackend();
97-
$result = $backend->rollback($version);
102+
$result = self::handleAppLocks(fn(): ?bool => $backend->rollback($version));
98103
// rollback doesn't have a return type yet and some implementations don't return anything
99104
if ($result === null || $result === true) {
100105
\OC_Hook::emit('\OCP\Versions', 'rollback', [
@@ -133,4 +138,45 @@ public function deleteVersion(IVersion $version): void {
133138
$backend->deleteVersion($version);
134139
}
135140
}
141+
142+
/**
143+
* Catch ManuallyLockedException and retry in app context if possible.
144+
*
145+
* The files_lock app may throw ManuallyLockedExceptions
146+
* when attempting to revert a file that is currently opened.
147+
* This would prevent the user from rolling back a opened file.
148+
*
149+
* Text and Richdocuments handle changes of the file while editing.
150+
* Allow reverting files even when they are locked by these apps
151+
* and let the apps handle the conflict.
152+
*
153+
* @param callable $callback function to run with app locks handled
154+
* @return bool|null
155+
* @throws ManuallyLockedException
156+
*
157+
*/
158+
private static function handleAppLocks(callable $callback): ?bool {
159+
try {
160+
return $callback();
161+
} catch (ManuallyLockedException $e) {
162+
$owner = (string) $e->getOwner();
163+
$appsThatHandleUpdates = array("text", "richdocuments");
164+
if (!in_array($owner, $appsThatHandleUpdates)) {
165+
throw $e;
166+
}
167+
// The LockWrapper in the files_lock app only compares the lock type and owner
168+
// when checking the lock against the current scope.
169+
// So we do not need to get the actual node here
170+
// and use the root node instead.
171+
$root = \OC::$server->get(IRootFolder::class);
172+
$lockContext = new LockContext($root, ILock::TYPE_APP, $owner());
173+
$lockManager = \OC::$server->get(ILockManager::class);
174+
$result = null;
175+
$lockManager->runInScope($lockContext, function() use ($callback, &$result) {
176+
$result = $callback();
177+
});
178+
return $result;
179+
}
180+
}
181+
136182
}

0 commit comments

Comments
 (0)