Skip to content

Commit 2e84a3f

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.
1 parent b21c5c8 commit 2e84a3f

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(): ?boolean => $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 boolean|null
155+
* @throws ManuallyLockedException
156+
*
157+
*/
158+
private static function handleAppLocks(callable $callback): ?boolean {
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)