Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ONLYOFFICE/onlyoffice-nextcloud.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Linnik <sergey.linnik@onlyoffice.com>2022-10-03 17:33:32 +0300
committerGitHub <noreply@github.com>2022-10-03 17:33:32 +0300
commit1bb8444594c7d5ff6af19d7238915fe7bcb210dd (patch)
tree15c876f9c10019fa5c1bc47720fe331fbb5e04d6
parent442263d24d69ebad02054fc9fc78307f7b09000b (diff)
parent5cf475c7c480f9c9c027f7e6494c7985942e011d (diff)
Merge pull request #711 from ONLYOFFICE/feature/lock-nc24
Feature/lock nc24
-rw-r--r--appinfo/application.php7
-rw-r--r--controller/callbackcontroller.php169
-rw-r--r--controller/editorapicontroller.php44
3 files changed, 141 insertions, 79 deletions
diff --git a/appinfo/application.php b/appinfo/application.php
index bbf013a..25487b8 100644
--- a/appinfo/application.php
+++ b/appinfo/application.php
@@ -32,6 +32,7 @@ use OCP\Files\Template\ITemplateManager;
use OCP\Files\Template\TemplateFileCreator;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCP\Files\IMimeTypeDetector;
+use OCP\Files\Lock\ILockManager;
use OCP\IL10N;
use OCP\IPreview;
use OCP\ITagManager;
@@ -199,7 +200,8 @@ class Application extends App implements IBootstrap {
$this->crypt,
$c->get("IManager"),
$c->get("Session"),
- $c->get(ITagManager::class)
+ $c->get(ITagManager::class),
+ $c->get(ILockManager::class)
);
});
@@ -214,7 +216,8 @@ class Application extends App implements IBootstrap {
$c->get("Logger"),
$this->appConfig,
$this->crypt,
- $c->get("IManager")
+ $c->get("IManager"),
+ $c->get(ILockManager::class)
);
});
diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php
index 9270794..a83edfa 100644
--- a/controller/callbackcontroller.php
+++ b/controller/callbackcontroller.php
@@ -30,6 +30,12 @@ use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
+use OCP\Files\Lock\ILock;
+use OCP\Files\Lock\ILockManager;
+use OCP\Files\Lock\LockContext;
+use OCP\Files\Lock\NoLockProviderException;
+use OCP\Files\Lock\OwnerLockedException;
+use OCP\PreConditionNotMetException;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IRequest;
@@ -120,6 +126,13 @@ class CallbackController extends Controller {
private $versionManager;
/**
+ * Lock manager
+ *
+ * @var ILockManager
+ */
+ private $lockManager;
+
+ /**
* Status of the document
*/
private const TrackerStatus_Editing = 1;
@@ -140,6 +153,7 @@ class CallbackController extends Controller {
* @param AppConfig $config - application configuration
* @param Crypt $crypt - hash generator
* @param IManager $shareManager - Share manager
+ * @param ILockManager $lockManager - Lock manager
*/
public function __construct($AppName,
IRequest $request,
@@ -150,7 +164,8 @@ class CallbackController extends Controller {
ILogger $logger,
AppConfig $config,
Crypt $crypt,
- IManager $shareManager
+ IManager $shareManager,
+ ILockManager $lockManager
) {
parent::__construct($AppName, $request);
@@ -162,6 +177,7 @@ class CallbackController extends Controller {
$this->config = $config;
$this->crypt = $crypt;
$this->shareManager = $shareManager;
+ $this->lockManager = $lockManager;
if (\OC::$server->getAppManager()->isInstalled("files_versions")) {
try {
@@ -434,77 +450,83 @@ class CallbackController extends Controller {
$url = isset($payload->url) ? $payload->url : null;
}
- $result = 1;
- switch ($status) {
- case self::TrackerStatus_MustSave:
- case self::TrackerStatus_Corrupted:
- case self::TrackerStatus_ForceSave:
- case self::TrackerStatus_CorruptedForceSave:
- if (empty($url)) {
- $this->logger->error("Track without url: $fileId status $status", ["app" => $this->appName]);
- return new JSONResponse(["message" => "Url not found"], Http::STATUS_BAD_REQUEST);
- }
+ $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null;
+ $filePath = null;
- try {
- $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null;
- $filePath = null;
+ \OC_Util::tearDownFS();
- \OC_Util::tearDownFS();
+ $isForcesave = $status === self::TrackerStatus_ForceSave || $status === self::TrackerStatus_CorruptedForceSave;
- $isForcesave = $status === self::TrackerStatus_ForceSave || $status === self::TrackerStatus_CorruptedForceSave;
+ $callbackUserId = $hashData->userId;
- // author of the latest changes
- $userId = $this->parseUserId($users[0]);
+ $userId = null;
+ if (!empty($users)) {
+ // author of the latest changes
+ $userId = $this->parseUserId($users[0]);
+ } else {
+ $userId = $callbackUserId;
+ }
- if ($isForcesave
- && $forcesavetype === 1
- && !empty($actions)) {
- // the user who clicked Save
- $userId = $this->parseUserId($actions[0]["userid"]);
- }
+ if ($isForcesave
+ && $forcesavetype === 1
+ && !empty($actions)) {
+ // the user who clicked Save
+ $userId = $this->parseUserId($actions[0]["userid"]);
+ }
- $user = $this->userManager->get($userId);
- if (!empty($user)) {
- \OC_User::setUserId($userId);
- } else {
- if (empty($shareToken)) {
- $this->logger->error("Track without token: $fileId status $status", ["app" => $this->appName]);
- return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN);
- }
+ $user = $this->userManager->get($userId);
+ if (!empty($user)) {
+ \OC_User::setUserId($userId);
+ } else {
+ if (empty($shareToken)) {
+ $this->logger->error("Track without token: $fileId status $status", ["app" => $this->appName]);
+ return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN);
+ }
- $this->logger->debug("Track $fileId by token for $userId", ["app" => $this->appName]);
- }
+ $this->logger->debug("Track $fileId by token for $userId", ["app" => $this->appName]);
+ }
- // owner of file from the callback link
- $ownerId = $hashData->ownerId;
- $owner = $this->userManager->get($ownerId);
+ // owner of file from the callback link
+ $ownerId = $hashData->ownerId;
+ $owner = $this->userManager->get($ownerId);
- if (!empty($owner)) {
- $userId = $ownerId;
- } else {
- $callbackUserId = $hashData->userId;
- $callbackUser = $this->userManager->get($callbackUserId);
+ if (!empty($owner)) {
+ $userId = $ownerId;
+ } else {
+ $callbackUser = $this->userManager->get($callbackUserId);
- if (!empty($callbackUser)) {
- // author of the callback link
- $userId = $callbackUserId;
+ if (!empty($callbackUser)) {
+ // author of the callback link
+ $userId = $callbackUserId;
- // path for author of the callback link
- $filePath = $hashData->filePath;
- }
- }
+ // path for author of the callback link
+ $filePath = $hashData->filePath;
+ }
+ }
- if (!empty($userId)) {
- \OC_Util::setupFS($userId);
- }
+ if (!empty($userId)) {
+ \OC_Util::setupFS($userId);
+ }
- list ($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken);
+ list ($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken);
- if (isset($error)) {
- $this->logger->error("track error $fileId " . json_encode($error->getData()), ["app" => $this->appName]);
- return $error;
- }
+ if (isset($error)) {
+ $this->logger->error("track error $fileId " . json_encode($error->getData()), ["app" => $this->appName]);
+ return $error;
+ }
+ $result = 1;
+ switch ($status) {
+ case self::TrackerStatus_MustSave:
+ case self::TrackerStatus_Corrupted:
+ case self::TrackerStatus_ForceSave:
+ case self::TrackerStatus_CorruptedForceSave:
+ if (empty($url)) {
+ $this->logger->error("Track without url: $fileId status $status", ["app" => $this->appName]);
+ return new JSONResponse(["message" => "Url not found"], Http::STATUS_BAD_REQUEST);
+ }
+
+ try {
$url = $this->config->ReplaceDocumentServerUrlToInternal($url);
$prevVersion = $file->getFileInfo()->getMtime();
@@ -539,9 +561,22 @@ class CallbackController extends Controller {
}
$this->logger->debug("Track put content " . $file->getPath(), ["app" => $this->appName]);
- $this->retryOperation(function () use ($file, $newData) {
- return $file->putContent($newData);
- });
+
+ $retryOperation = function () use ($file, $newData) {
+ $this->retryOperation(function () use ($file, $newData) {
+ return $file->putContent($newData);
+ });
+ };
+
+ try {
+ $lockContext = new LockContext($file, ILock::TYPE_APP, $this->appName);
+ $this->lockManager->runInScope($lockContext, $retryOperation);
+ $this->lockManager->unlock($lockContext);
+
+ $this->logger->debug("$this->appName has unlocked file $fileId", ["app" => $this->appName]);
+ } catch (NoLockProviderException $e) {
+ $retryOperation();
+ } catch (PreConditionNotMetException $e) {}
if (RemoteInstance::isRemoteFile($file)) {
if ($isForcesave) {
@@ -575,7 +610,21 @@ class CallbackController extends Controller {
break;
case self::TrackerStatus_Editing:
+ try {
+ $this->lockManager->lock(new LockContext($file, ILock::TYPE_APP, $this->appName));
+
+ $this->logger->debug("$this->appName has locked file $fileId", ["app" => $this->appName]);
+ } catch (PreConditionNotMetException | OwnerLockedException | NoLockProviderException $e) {}
+
+ $result = 0;
+ break;
case self::TrackerStatus_Closed:
+ try {
+ $this->lockManager->unlock(new LockContext($file, ILock::TYPE_APP, $this->appName));
+
+ $this->logger->debug("$this->appName has unlocked file $fileId", ["app" => $this->appName]);
+ } catch (PreConditionNotMetException | NoLockProviderException $e) {}
+
$result = 0;
break;
}
diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php
index b8c2c7f..713b865 100644
--- a/controller/editorapicontroller.php
+++ b/controller/editorapicontroller.php
@@ -26,6 +26,11 @@ use OCP\Constants;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
+use OCP\Files\Lock\ILock;
+use OCP\Files\Lock\ILockManager;
+use OCP\Files\Lock\NoLockProviderException;
+use OCP\Files\Lock\OwnerLockedException;
+use OCP\PreConditionNotMetException;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IRequest;
@@ -40,8 +45,6 @@ use OCP\Share\IManager;
use OCP\Share\IShare;
use OCA\Files_Versions\Versions\IVersionManager;
-use OCA\FilesLock\Service\LockService;
-use OCA\FilesLock\Exceptions\LockNotFoundException;
use OCA\Onlyoffice\AppConfig;
use OCA\Onlyoffice\Crypt;
@@ -140,6 +143,13 @@ class EditorApiController extends OCSController {
private $extraPermissions;
/**
+ * Lock manager
+ *
+ * @var ILockManager
+ */
+ private $lockManager;
+
+ /**
* Mobile regex from https://github.com/ONLYOFFICE/CommunityServer/blob/v9.1.1/web/studio/ASC.Web.Studio/web.appsettings.config#L35
*/
const USER_AGENT_MOBILE = "/android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i";
@@ -158,6 +168,7 @@ class EditorApiController extends OCSController {
* @param IManager $shareManager - Share manager
* @param ISession $ISession - Session
* @param ITagManager $tagManager - Tag manager
+ * @param ILockManager $lockManager - Lock manager
*/
public function __construct($AppName,
IRequest $request,
@@ -171,7 +182,8 @@ class EditorApiController extends OCSController {
Crypt $crypt,
IManager $shareManager,
ISession $session,
- ITagManager $tagManager
+ ITagManager $tagManager,
+ ILockManager $lockManager
) {
parent::__construct($AppName, $request);
@@ -184,6 +196,7 @@ class EditorApiController extends OCSController {
$this->config = $config;
$this->crypt = $crypt;
$this->tagManager = $tagManager;
+ $this->lockManager = $lockManager;
if (\OC::$server->getAppManager()->isInstalled("files_versions")) {
try {
@@ -372,24 +385,21 @@ class EditorApiController extends OCSController {
$isTempLock = false;
if ($version < 1
- && \OC::$server->getAppManager()->isInstalled("files_lock")) {
+ && $this->lockManager->isLockProviderAvailable()) {
try {
- $lockService = \OC::$server->get(LockService::class);
- $lock = $lockService->getLockFromFileId($file->getId());
+ $locks = $this->lockManager->getLocks($file->getId());
+ $lock = !empty($locks) ? $locks[0] : null;
- $lockOwner = null;
- if (method_exists($lock, "getUserId")) {
- $lockOwner = $lock->getUserId();
- }
- else if(method_exists($lock, "getOwner")) {
+ if ($lock !== null) {
+ $lockType = $lock->getType();
$lockOwner = $lock->getOwner();
+ if (($lockType === ILock::TYPE_APP) && $lockOwner !== $this->appName
+ || ($lockType === ILock::TYPE_USER || $lockType === ILock::TYPE_TOKEN) && $lockOwner !== $userId) {
+ $isTempLock = true;
+ $this->logger->debug("File" . $file->getId() . "is locked by $lockOwner", ["app" => $this->appName]);
+ }
}
-
- if ($userId !== $lockOwner) {
- $isTempLock = true;
- $this->logger->debug("File" . $file->getId() . "is locked by $lockOwner", ["app" => $this->appName]);
- }
- } catch (LockNotFoundException $e) {}
+ } catch (PreConditionNotMetException | NoLockProviderException $e) {}
}
$canEdit = isset($format["edit"]) && $format["edit"];