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:
-rw-r--r--appinfo/application.php4
-rw-r--r--appinfo/routes.php2
-rw-r--r--controller/callbackcontroller.php112
-rw-r--r--controller/editorcontroller.php282
-rw-r--r--js/editor.js98
-rw-r--r--js/listener.js10
-rw-r--r--js/main.js51
-rw-r--r--lib/directeditor.php1
-rw-r--r--lib/fileutility.php17
-rw-r--r--lib/fileversions.php338
-rw-r--r--lib/hooks.php152
-rw-r--r--templates/editor.php1
12 files changed, 1034 insertions, 34 deletions
diff --git a/appinfo/application.php b/appinfo/application.php
index 0e06449..e83a0e9 100644
--- a/appinfo/application.php
+++ b/appinfo/application.php
@@ -42,6 +42,7 @@ use OCA\Onlyoffice\Controller\EditorController;
use OCA\Onlyoffice\Controller\SettingsController;
use OCA\Onlyoffice\Crypt;
use OCA\Onlyoffice\DirectEditor;
+use OCA\Onlyoffice\Hooks;
class Application extends App {
@@ -216,5 +217,8 @@ class Application extends App {
$c->query("IManager")
);
});
+
+
+ Hooks::connectHooks();
}
}
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 3497183..ab5d6df 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -40,6 +40,8 @@ return [
["name" => "editor#convert", "url" => "/ajax/convert", "verb" => "POST"],
["name" => "editor#save", "url" => "/ajax/save", "verb" => "POST"],
["name" => "editor#url", "url" => "/ajax/url", "verb" => "GET"],
+ ["name" => "editor#history", "url" => "/ajax/history", "verb" => "GET"],
+ ["name" => "editor#version", "url" => "/ajax/version", "verb" => "GET"],
["name" => "settings#save_address", "url" => "/ajax/settings/address", "verb" => "PUT"],
["name" => "settings#save_common", "url" => "/ajax/settings/common", "verb" => "PUT"],
["name" => "settings#save_watermark", "url" => "/ajax/settings/watermark", "verb" => "PUT"],
diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php
index 7037c9f..18c6ec1 100644
--- a/controller/callbackcontroller.php
+++ b/controller/callbackcontroller.php
@@ -47,9 +47,12 @@ use OCP\Lock\LockedException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
+use OCA\Files_Versions\Versions\IVersionManager;
+
use OCA\Onlyoffice\AppConfig;
use OCA\Onlyoffice\Crypt;
use OCA\Onlyoffice\DocumentService;
+use OCA\Onlyoffice\FileVersions;
/**
* Callback handler for the document server.
@@ -115,6 +118,13 @@ class CallbackController extends Controller {
private $shareManager;
/**
+ * File version manager
+ *
+ * @var IVersionManager
+ */
+ private $versionManager;
+
+ /**
* Status of the document
*
* @var Array
@@ -160,6 +170,14 @@ class CallbackController extends Controller {
$this->config = $config;
$this->crypt = $crypt;
$this->shareManager = $shareManager;
+
+ if (\OC::$server->getAppManager()->isInstalled("files_versions")) {
+ try {
+ $this->versionManager = \OC::$server->query(IVersionManager::class);
+ } catch (QueryException $e) {
+ $this->logger->logException($e, ["message" => "VersionManager init error", "app" => $this->appName]);
+ }
+ }
}
@@ -188,9 +206,12 @@ class CallbackController extends Controller {
}
$fileId = $hashData->fileId;
- $this->logger->debug("Download: $fileId", ["app" => $this->appName]);
+ $version = isset($hashData->version) ? $hashData->version : null;
+ $changes = isset($hashData->changes) ? $hashData->changes : false;
+ $this->logger->debug("Download: $fileId ($version)" . ($changes ? " changes" : ""), ["app" => $this->appName]);
- if (!$this->userSession->isLoggedIn()) {
+ if (!$this->userSession->isLoggedIn()
+ && !$changes) {
if (!empty($this->config->GetDocumentServerSecret())) {
$header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader());
if (empty($header)) {
@@ -224,7 +245,7 @@ class CallbackController extends Controller {
}
$shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null;
- list ($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId) : $this->getFileByToken($fileId, $shareToken);
+ list ($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, null, $changes ? null : $version) : $this->getFileByToken($fileId, $shareToken, $changes ? null : $version);
if (isset($error)) {
return $error;
@@ -235,10 +256,42 @@ class CallbackController extends Controller {
return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN);
}
+ if ($changes) {
+ if ($this->versionManager === null) {
+ $this->logger->error("Download changes: versionManager is null", ["app" => $this->appName]);
+ return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST);
+ }
+
+ $owner = $file->getFileInfo()->getOwner();
+ if ($owner === null) {
+ $this->logger->error("Download: changes owner of $fileId was not found", ["app" => $this->appName]);
+ return new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND);
+ }
+
+ $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo()));
+
+ $versionId = null;
+ if ($version > count($versions)) {
+ $versionId = $file->getFileInfo()->getMtime();
+ } else {
+ $fileVersion = array_values($versions)[$version - 1];
+
+ $versionId = $fileVersion->getRevisionId();
+ }
+
+ $changesFile = FileVersions::getChangesFile($owner->getUID(), $fileId, $versionId);
+ if ($changesFile === null) {
+ $this->logger->error("Download: changes $fileId ($version) was not found", ["app" => $this->appName]);
+ return new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND);
+ }
+
+ $file = $changesFile;
+ }
+
try {
return new DataDownloadResponse($file->getContent(), $file->getName(), $file->getMimeType());
} catch (NotPermittedException $e) {
- $this->logger->logException($e, ["message" => "Download Not permitted: $fileId", "app" => $this->appName]);
+ $this->logger->logException($e, ["message" => "Download Not permitted: $fileId ($version)", "app" => $this->appName]);
return new JSONResponse(["message" => $this->trans->t("Not permitted")], Http::STATUS_FORBIDDEN);
}
return new JSONResponse(["message" => $this->trans->t("Download failed")], Http::STATUS_INTERNAL_SERVER_ERROR);
@@ -312,6 +365,8 @@ class CallbackController extends Controller {
* @param integer $status - the edited status
* @param string $url - the link to the edited document to be saved
* @param string $token - request signature
+ * @param array $history - file history
+ * @param string $changesurl - link to file changes
*
* @return array
*
@@ -320,7 +375,7 @@ class CallbackController extends Controller {
* @PublicPage
* @CORS
*/
- public function track($doc, $users, $key, $status, $url, $token) {
+ public function track($doc, $users, $key, $status, $url, $token, $history, $changesurl) {
list ($hashData, $error) = $this->crypt->ReadHash($doc);
if ($hashData === null) {
@@ -424,6 +479,7 @@ class CallbackController extends Controller {
$url = $this->config->ReplaceDocumentServerUrlToInternal($url);
+ $prevVersion = $file->getFileInfo()->getMtime();
$fileName = $file->getName();
$curExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$downloadExt = strtolower(pathinfo($url, PATHINFO_EXTENSION));
@@ -448,9 +504,18 @@ class CallbackController extends Controller {
return $file->putContent($newData);
});
+ if ($this->versionManager !== null) {
+ $changes = null;
+ if (!empty($changesurl)) {
+ $changesurl = $this->config->ReplaceDocumentServerUrlToInternal($changesurl);
+ $changes = $documentService->Request($changesurl);
+ }
+ FileVersions::saveHistory($file->getFileInfo(), $history, $changes, $prevVersion);
+ }
+
$result = 0;
} catch (\Exception $e) {
- $this->logger->logException($e, ["message" => "Track $trackerStatus error", "app" => $this->appName]);
+ $this->logger->logException($e, ["message" => "Track: $fileId status $trackerStatus error", "app" => $this->appName]);
}
break;
@@ -472,10 +537,11 @@ class CallbackController extends Controller {
* @param string $userId - user identifier
* @param integer $fileId - file identifier
* @param string $filePath - file path
+ * @param integer $version - file version
*
* @return array
*/
- private function getFile($userId, $fileId, $filePath = null) {
+ private function getFile($userId, $fileId, $filePath = null, $version = 0) {
if (empty($fileId)) {
return [null, new JSONResponse(["message" => $this->trans->t("FileId is empty")], Http::STATUS_BAD_REQUEST)];
}
@@ -509,6 +575,25 @@ class CallbackController extends Controller {
return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)];
}
+ if ($version > 0 && $this->versionManager !== null) {
+ $owner = $file->getFileInfo()->getOwner();
+
+ if ($owner->getUID() !== $userId) {
+ list ($file, $error) = $this->getFile($owner->getUID(), $file->getId());
+
+ if (isset($error)) {
+ return [null, $error];
+ }
+ }
+
+ $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo()));
+
+ if ($version <= count($versions)) {
+ $fileVersion = array_values($versions)[$version - 1];
+ $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId());
+ }
+ }
+
return [$file, null];
}
@@ -517,10 +602,11 @@ class CallbackController extends Controller {
*
* @param integer $fileId - file identifier
* @param string $shareToken - access token
+ * @param integer $version - file version
*
* @return array
*/
- private function getFileByToken($fileId, $shareToken) {
+ private function getFileByToken($fileId, $shareToken, $version = 0) {
list ($share, $error) = $this->getShare($shareToken);
if (isset($error)) {
@@ -550,6 +636,16 @@ class CallbackController extends Controller {
$file = $node;
}
+ if ($version > 0 && $this->versionManager !== null) {
+ $owner = $file->getFileInfo()->getOwner();
+ $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo()));
+
+ if ($version <= count($versions)) {
+ $fileVersion = array_values($versions)[$version - 1];
+ $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId());
+ }
+ }
+
return [$file, null];
}
diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php
index 01e6db4..13c342a 100644
--- a/controller/editorcontroller.php
+++ b/controller/editorcontroller.php
@@ -49,12 +49,14 @@ use OCP\IUserSession;
use OCP\Share\IManager;
use OCA\Files\Helper;
+use OCA\Files_Versions\Versions\IVersionManager;
use OCA\Onlyoffice\AppConfig;
use OCA\Onlyoffice\Crypt;
use OCA\Onlyoffice\DocumentService;
use OCA\Onlyoffice\FileUtility;
use OCA\Onlyoffice\TemplateManager;
+use OCA\Onlyoffice\FileVersions;
/**
* Controller with the main functions
@@ -125,6 +127,13 @@ class EditorController extends Controller {
private $fileUtility;
/**
+ * File version manager
+ *
+ * @var IVersionManager
+ */
+ private $versionManager;
+
+ /**
* 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";
@@ -167,6 +176,14 @@ class EditorController extends Controller {
$this->config = $config;
$this->crypt = $crypt;
+ if (\OC::$server->getAppManager()->isInstalled("files_versions")) {
+ try {
+ $this->versionManager = \OC::$server->query(IVersionManager::class);
+ } catch (QueryException $e) {
+ $this->logger->logException($e, ["message" => "VersionManager init error", "app" => $this->appName]);
+ }
+ }
+
$this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session);
}
@@ -408,6 +425,204 @@ class EditorController extends Controller {
}
/**
+ * Get versions history for file
+ *
+ * @param integer $fileId - file identifier
+ * @param string $shareToken - access token
+ *
+ * @return array
+ *
+ * @NoAdminRequired
+ * @PublicPage
+ */
+ public function history($fileId, $shareToken = null) {
+ $this->logger->debug("Request history for: $fileId", ["app" => $this->appName]);
+
+ $history = [];
+
+ $user = $this->userSession->getUser();
+ $userId = null;
+ if (!empty($user)) {
+ $userId = $user->getUID();
+ }
+
+ list ($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId) : $this->fileUtility->getFileByToken($fileId, $shareToken);
+
+ if (isset($error)) {
+ $this->logger->error("History: $fileId $error", ["app" => $this->appName]);
+ return ["error" => $error];
+ }
+
+ if ($fileId === 0) {
+ $fileId = $file->getId();
+ }
+
+ $owner = null;
+ $ownerId = null;
+ $versions = array();
+ if ($this->versionManager !== null) {
+ $owner = $file->getFileInfo()->getOwner();
+ if ($owner !== null) {
+ $ownerId = $owner->getUID();
+ $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo()));
+ }
+ }
+
+ $prevVersion = "";
+ $versionNum = 0;
+ foreach ($versions as $version) {
+ $versionNum = $versionNum + 1;
+
+ $key = $this->fileUtility->getVersionKey($version);
+ $key = DocumentService::GenerateRevisionId($key);
+
+ $historyItem = [
+ "created" => $this->trans->l("datetime", $version->getTimestamp(), ["width" => "short"]),
+ "key" => $key,
+ "user" => [
+ "id" => $this->buildUserId($ownerId),
+ "name" => $owner->getDisplayName()
+ ],
+ "version" => $versionNum
+ ];
+
+ $versionId = $version->getRevisionId();
+ $historyData = FileVersions::getHistoryData($ownerId, $fileId, $versionId, $prevVersion);
+ if ($historyData !== null) {
+ $historyItem["changes"] = $historyData["changes"];
+ $historyItem["serverVersion"] = $historyData["serverVersion"];
+ }
+
+ $prevVersion = $versionId;
+
+ array_push($history, $historyItem);
+ }
+
+ $key = $this->fileUtility->getKey($file, true);
+ $key = DocumentService::GenerateRevisionId($key);
+
+ $historyItem = [
+ "created" => $this->trans->l("datetime", $file->getMTime(), ["width" => "short"]),
+ "key" => $key,
+ "version" => $versionNum + 1
+ ];
+
+ if ($owner !== null) {
+ $historyItem["user"] = [
+ "id" => $this->buildUserId($owner->getUID()),
+ "name" => $owner->getDisplayName()
+ ];
+ }
+
+ $versionId = $file->getFileInfo()->getMtime();
+ $historyData = FileVersions::getHistoryData($ownerId, $fileId, $versionId, $prevVersion);
+ if ($historyData !== null) {
+ $historyItem["changes"] = $historyData["changes"];
+ $historyItem["serverVersion"] = $historyData["serverVersion"];
+ }
+
+ array_push($history, $historyItem);
+
+ return $history;
+ }
+
+ /**
+ * Get file attributes of specific version
+ *
+ * @param integer $fileId - file identifier
+ * @param integer $version - file version
+ * @param string $shareToken - access token
+ *
+ * @return array
+ *
+ * @NoAdminRequired
+ * @PublicPage
+ */
+ public function version($fileId, $version, $shareToken = null) {
+ $this->logger->debug("Request version for: $fileId ($version)", ["app" => $this->appName]);
+
+ $version = empty($version) ? null : $version;
+
+ $user = $this->userSession->getUser();
+ $userId = null;
+ if (!empty($user)) {
+ $userId = $user->getUID();
+ }
+
+ list ($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId) : $this->fileUtility->getFileByToken($fileId, $shareToken);
+
+ if (isset($error)) {
+ $this->logger->error("History: $fileId $error", ["app" => $this->appName]);
+ return ["error" => $error];
+ }
+
+ if ($fileId === 0) {
+ $fileId = $file->getId();
+ }
+
+ $owner = null;
+ $ownerId = null;
+ $versions = array();
+ if ($this->versionManager !== null) {
+ $owner = $file->getFileInfo()->getOwner();
+ if ($owner !== null) {
+ $ownerId = $owner->getUID();
+ $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo()));
+ }
+ }
+
+ $key = null;
+ $fileUrl = null;
+ $versionId = null;
+ if ($version > count($versions)) {
+ $key = $this->fileUtility->getKey($file, true);
+ $versionId = $file->getFileInfo()->getMtime();
+
+ $fileUrl = $this->getUrl($file, $user, $shareToken);
+ } else {
+ $fileVersion = array_values($versions)[$version - 1];
+
+ $key = $this->fileUtility->getVersionKey($fileVersion);
+ $versionId = $fileVersion->getRevisionId();
+
+ $fileUrl = $this->getUrl($file, $user, $shareToken, $version);
+ }
+ $key = DocumentService::GenerateRevisionId($key);
+
+ $result = [
+ "url" => $fileUrl,
+ "version" => $version,
+ "key" => $key
+ ];
+
+ if ($version > 1
+ && count($versions) >= $version - 1
+ && FileVersions::hasChanges($ownerId, $fileId, $versionId)) {
+
+ $changesUrl = $this->getUrl($file, $user, $shareToken, $version, true);
+ $result["changesUrl"] = $changesUrl;
+
+ $prevVersion = array_values($versions)[$version - 2];
+ $prevVersionKey = $this->fileUtility->getVersionKey($prevVersion);
+ $prevVersionKey = DocumentService::GenerateRevisionId($prevVersionKey);
+
+ $prevVersionUrl = $this->getUrl($file, $user, $shareToken, $version - 1);
+
+ $result["previous"] = [
+ "key" => $prevVersionKey,
+ "url" => $prevVersionUrl
+ ];
+ }
+
+ if (!empty($this->config->GetDocumentServerSecret())) {
+ $token = \Firebase\JWT\JWT::encode($result, $this->config->GetDocumentServerSecret());
+ $result["token"] = $token;
+ }
+
+ return $result;
+ }
+
+ /**
* Get presigned url to file
*
* @param string $filePath - file path
@@ -461,6 +676,7 @@ class EditorController extends Controller {
* @param integer $fileId - file identifier
* @param string $filePath - file path
* @param string $shareToken - access token
+ * @param integer $version - file version
* @param bool $inframe - open in frame
*
* @return TemplateResponse|RedirectResponse
@@ -468,8 +684,8 @@ class EditorController extends Controller {
* @NoAdminRequired
* @NoCSRFRequired
*/
- public function index($fileId, $filePath = null, $shareToken = null, $inframe = false) {
- $this->logger->debug("Open: $fileId $filePath", ["app" => $this->appName]);
+ public function index($fileId, $filePath = null, $shareToken = null, $version = 0, $inframe = false) {
+ $this->logger->debug("Open: $fileId ($version) $filePath ", ["app" => $this->appName]);
$isLoggedIn = $this->userSession->isLoggedIn();
if (empty($shareToken) && !$isLoggedIn) {
@@ -496,6 +712,7 @@ class EditorController extends Controller {
"filePath" => $filePath,
"shareToken" => $shareToken,
"directToken" => null,
+ "version" => $version,
"inframe" => false
];
@@ -535,6 +752,7 @@ class EditorController extends Controller {
*
* @param integer $fileId - file identifier
* @param string $shareToken - access token
+ * @param integer $version - file version
* @param bool $inframe - open in frame
*
* @return TemplateResponse
@@ -543,8 +761,8 @@ class EditorController extends Controller {
* @NoCSRFRequired
* @PublicPage
*/
- public function PublicPage($fileId, $shareToken, $inframe = false) {
- return $this->index($fileId, null, $shareToken, $inframe);
+ public function PublicPage($fileId, $shareToken, $version = 0, $inframe = false) {
+ return $this->index($fileId, null, $shareToken, $version, $inframe);
}
/**
@@ -567,6 +785,7 @@ class EditorController extends Controller {
* @param string $filePath - file path
* @param string $shareToken - access token
* @param string $directToken - direct token
+ * @param integer $version - file version
* @param integer $inframe - open in frame. 0 - no, 1 - yes, 2 - without goback for old editor (5.4)
* @param bool $desktop - desktop label
*
@@ -575,7 +794,7 @@ class EditorController extends Controller {
* @NoAdminRequired
* @PublicPage
*/
- public function config($fileId, $filePath = null, $shareToken = null, $directToken = null, $inframe = 0, $desktop = false) {
+ public function config($fileId, $filePath = null, $shareToken = null, $directToken = null, $version = 0, $inframe = 0, $desktop = false) {
if (!empty($directToken)) {
list ($directData, $error) = $this->crypt->ReadHash($directToken);
@@ -628,8 +847,25 @@ class EditorController extends Controller {
return ["error" => $this->trans->t("Format is not supported")];
}
- $fileUrl = $this->getUrl($file, $user, $shareToken);
- $key = $this->fileUtility->getKey($file, true);
+ $fileUrl = $this->getUrl($file, $user, $shareToken, $version);
+
+ $key = null;
+ if ($version > 0
+ && $this->versionManager !== null) {
+ $owner = $file->getFileInfo()->getOwner();
+ if ($owner !== null) {
+ $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo()));
+
+ if ($version <= count($versions)) {
+ $fileVersion = array_values($versions)[$version - 1];
+
+ $key = $this->fileUtility->getVersionKey($fileVersion);
+ }
+ }
+ }
+ if ($key === null) {
+ $key = $this->fileUtility->getKey($file, true);
+ }
$key = DocumentService::GenerateRevisionId($key);
$params = [
@@ -653,7 +889,8 @@ class EditorController extends Controller {
}
$canEdit = isset($format["edit"]) && $format["edit"];
- $editable = $file->isUpdateable()
+ $editable = $version < 1
+ && $file->isUpdateable()
&& (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE);
$params["document"]["permissions"]["edit"] = $editable;
if ($editable && $canEdit) {
@@ -746,7 +983,7 @@ class EditorController extends Controller {
$params["token"] = $token;
}
- $this->logger->debug("Config is generated for: $fileId with key $key", ["app" => $this->appName]);
+ $this->logger->debug("Config is generated for: $fileId ($version) with key $key", ["app" => $this->appName]);
return $params;
}
@@ -799,23 +1036,42 @@ class EditorController extends Controller {
/**
* Generate secure link to download document
*
- * @param integer $file - file
+ * @param File $file - file
* @param IUser $user - user with access
* @param string $shareToken - access token
+ * @param integer $version - file version
+ * @param bool $changes - is required url to file changes
*
* @return string
*/
- private function getUrl($file, $user = null, $shareToken = null) {
+ private function getUrl($file, $user = null, $shareToken = null, $version = 0, $changes = false) {
+
+ $data = [
+ "action" => "download",
+ "fileId" => $file->getId()
+ ];
+
$userId = null;
if (!empty($user)) {
$userId = $user->getUID();
+ $data["userId"] = $userId;
+ }
+ if (!empty($shareToken)) {
+ $data["shareToken"] = $shareToken;
+ }
+ if ($version > 0) {
+ $data["version"] = $version;
+ }
+ if ($changes) {
+ $data["changes"] = true;
}
- $hashUrl = $this->crypt->GetHash(["fileId" => $file->getId(), "userId" => $userId, "shareToken" => $shareToken, "action" => "download"]);
+ $hashUrl = $this->crypt->GetHash($data);
$fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]);
- if (!empty($this->config->GetStorageUrl())) {
+ if (!empty($this->config->GetStorageUrl())
+ && !$changes) {
$fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl);
}
diff --git a/js/editor.js b/js/editor.js
index 284fe67..d8ac41b 100644
--- a/js/editor.js
+++ b/js/editor.js
@@ -30,7 +30,9 @@
OCA.Onlyoffice = _.extend({
AppName: "onlyoffice",
- inframe: false
+ inframe: false,
+ fileId: null,
+ shareToken: null
}, OCA.Onlyoffice);
OCA.Onlyoffice.InitEditor = function () {
@@ -40,11 +42,12 @@
});
};
- var fileId = $("#iframeEditor").data("id");
- var shareToken = $("#iframeEditor").data("sharetoken");
+ OCA.Onlyoffice.fileId = $("#iframeEditor").data("id");
+ OCA.Onlyoffice.shareToken = $("#iframeEditor").data("sharetoken");
+ OCA.Onlyoffice.version = $("#iframeEditor").data("version");
var directToken = $("#iframeEditor").data("directtoken");
OCA.Onlyoffice.inframe = !!$("#iframeEditor").data("inframe");
- if (!fileId && !shareToken && !directToken) {
+ if (!OCA.Onlyoffice.fileId && !OCA.Onlyoffice.shareToken && !directToken) {
displayError(t(OCA.Onlyoffice.AppName, "FileId is empty"));
return;
}
@@ -56,7 +59,7 @@
var configUrl = OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/config/{fileId}",
{
- fileId: fileId || 0
+ fileId: OCA.Onlyoffice.fileId || 0
});
var params = [];
@@ -64,13 +67,16 @@
if (filePath) {
params.push("filePath=" + encodeURIComponent(filePath));
}
- if (shareToken) {
- params.push("shareToken=" + encodeURIComponent(shareToken));
+ if (OCA.Onlyoffice.shareToken) {
+ params.push("shareToken=" + encodeURIComponent(OCA.Onlyoffice.shareToken));
}
if (directToken) {
$("html").addClass("onlyoffice-full-page");
params.push("directToken=" + encodeURIComponent(directToken));
}
+ if (OCA.Onlyoffice.version > 0) {
+ params.push("version=" + OCA.Onlyoffice.version);
+ }
if (OCA.Onlyoffice.inframe || directToken) {
var dsVersion = DocsAPI.DocEditor.version();
@@ -133,15 +139,22 @@
config.events = {
"onDocumentStateChange": setPageTitle,
+ "onRequestHistory": OCA.Onlyoffice.onRequestHistory,
+ "onRequestHistoryData": OCA.Onlyoffice.onRequestHistoryData,
+ "onDocumentReady": OCA.Onlyoffice.onDocumentReady,
};
+ if (!OCA.Onlyoffice.version) {
+ config.events.onRequestHistoryClose = OCA.Onlyoffice.onRequestHistoryClose;
+ }
+
if (config.editorConfig.tenant) {
config.events.onAppReady = function () {
OCA.Onlyoffice.docEditor.showMessage(t(OCA.Onlyoffice.AppName, "You are using public demo ONLYOFFICE Document Server. Please do not store private sensitive data."));
};
}
- if (OCA.Onlyoffice.inframe && !shareToken
+ if (OCA.Onlyoffice.inframe && !OCA.Onlyoffice.shareToken
|| OC.currentUser) {
config.events.onRequestSaveAs = OCA.Onlyoffice.onRequestSaveAs;
config.events.onRequestInsertImage = OCA.Onlyoffice.onRequestInsertImage;
@@ -154,7 +167,7 @@
}
if (OCA.Onlyoffice.inframe
- && config._files_sharing && !shareToken
+ && config._files_sharing && !OCA.Onlyoffice.shareToken
&& window.parent.OCA.Onlyoffice.context) {
config.events.onRequestSharingSettings = OCA.Onlyoffice.onRequestSharingSettings;
}
@@ -174,6 +187,73 @@
});
};
+ OCA.Onlyoffice.onRequestHistory = function (version) {
+ $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/history?fileId={fileId}&shareToken={shareToken}",
+ {
+ fileId: OCA.Onlyoffice.fileId || 0,
+ shareToken: OCA.Onlyoffice.shareToken || "",
+ }),
+ function onSuccess(response) {
+ if (response.error) {
+ var data = {error: response.error};
+ } else {
+ var currentVersion = 0;
+ $.each(response, function (i, fileVersion) {
+ if (fileVersion.version >= currentVersion) {
+ currentVersion = fileVersion.version;
+ }
+ });
+
+ if (version) {
+ currentVersion = Math.min(currentVersion, version);
+ }
+
+ data = {
+ currentVersion: currentVersion,
+ history: response,
+ };
+ }
+ OCA.Onlyoffice.docEditor.refreshHistory(data);
+ });
+ };
+
+ OCA.Onlyoffice.onRequestHistoryData = function (event) {
+ var version = event.data;
+
+ $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/version?fileId={fileId}&version={version}&shareToken={shareToken}",
+ {
+ fileId: OCA.Onlyoffice.fileId || 0,
+ version: version,
+ shareToken: OCA.Onlyoffice.shareToken || "",
+ }),
+ function onSuccess(response) {
+ if (response.error) {
+ response = {
+ error: response.error,
+ version: version,
+ };
+ }
+ OCA.Onlyoffice.docEditor.setHistoryData(response);
+ });
+ };
+
+ OCA.Onlyoffice.onRequestHistoryClose = function () {
+ location.reload(true);
+ };
+
+ OCA.Onlyoffice.onDocumentReady = function() {
+ if (OCA.Onlyoffice.inframe) {
+ window.parent.postMessage({
+ method: "onDocumentReady"
+ },
+ "*");
+ }
+
+ if (OCA.Onlyoffice.version > 0) {
+ OCA.Onlyoffice.onRequestHistory(OCA.Onlyoffice.version);
+ }
+ };
+
OCA.Onlyoffice.onRequestSaveAs = function (event) {
var saveData = {
name: event.data.title,
diff --git a/js/listener.js b/js/listener.js
index 3a25edb..f571010 100644
--- a/js/listener.js
+++ b/js/listener.js
@@ -36,6 +36,7 @@
OCA.Onlyoffice.onRequestClose = function () {
$(OCA.Onlyoffice.frameSelector).remove();
+ OCA.Onlyoffice.frameSelector = null;
if (OCA.Viewer && OCA.Viewer.close) {
OCA.Viewer.close();
@@ -77,6 +78,12 @@
revisedMimes);
};
+ OCA.Onlyoffice.onDocumentReady = function () {
+ if (OCA.Onlyoffice.bindVersionClick) {
+ OCA.Onlyoffice.bindVersionClick();
+ }
+ };
+
window.addEventListener("message", function (event) {
if ($(OCA.Onlyoffice.frameSelector)[0].contentWindow !== event.source
|| !event.data["method"]) {
@@ -108,6 +115,9 @@
case "editorRequestCompareFile":
OCA.Onlyoffice.onRequestCompareFile(event.data.param);
break;
+ case "onDocumentReady":
+ OCA.Onlyoffice.onDocumentReady();
+ break;
}
}, false);
diff --git a/js/main.js b/js/main.js
index a880116..9eda2df 100644
--- a/js/main.js
+++ b/js/main.js
@@ -66,7 +66,7 @@
}
fileList.add(response, { animate: true });
- OCA.Onlyoffice.OpenEditor(response.id, dir, response.name, winEditor);
+ OCA.Onlyoffice.OpenEditor(response.id, dir, response.name, 0, winEditor);
OCA.Onlyoffice.context = { fileList: fileList };
OCA.Onlyoffice.context.fileName = response.name;
@@ -76,8 +76,11 @@
);
};
- OCA.Onlyoffice.OpenEditor = function (fileId, fileDir, fileName, winEditor) {
- var filePath = fileDir.replace(new RegExp("\/$"), "") + "/" + fileName;
+ OCA.Onlyoffice.OpenEditor = function (fileId, fileDir, fileName, version, winEditor) {
+ var filePath = "";
+ if (fileName) {
+ filePath = fileDir.replace(new RegExp("\/$"), "") + "/" + fileName;
+ }
var url = OC.generateUrl("/apps/" + OCA.Onlyoffice.AppName + "/{fileId}?filePath={filePath}",
{
fileId: fileId,
@@ -92,6 +95,10 @@
});
}
+ if (version > 0) {
+ url += "&version=" + version;
+ }
+
if (winEditor && winEditor.location) {
winEditor.location.href = url;
} else if (!OCA.Onlyoffice.setting.sameTab || OCA.Onlyoffice.Desktop) {
@@ -305,6 +312,40 @@
return extension;
}
+ OCA.Onlyoffice.openVersion = function (fileId, version) {
+ if (OCA.Onlyoffice.frameSelector) {
+ $(OCA.Onlyoffice.frameSelector)[0].contentWindow.OCA.Onlyoffice.onRequestHistory(version);
+ return;
+ }
+
+ OCA.Onlyoffice.OpenEditor(fileId, "", "", version)
+ };
+
+ OCA.Onlyoffice.bindVersionClick = function () {
+ unbindVersionClick();
+ $(document).on("click.onlyoffice-version", "#versionsTabView .downloadVersion", function() {
+ var versionNodes = $("#versionsTabView ul.versions>li");
+ var versionNode = $(this).closest("#versionsTabView ul.versions>li")[0];
+
+ var href = $(this).attr("href");
+ var search = new RegExp("\/versions\/\\w+\/versions\/(\\d+)\/\\d+");
+ var result = search.exec(href);
+ if (result && result.length > 1) {
+ var fileId = result[1];
+ }
+
+ var versionNum = versionNodes.length - $.inArray(versionNode, versionNodes);
+
+ OCA.Onlyoffice.openVersion(fileId || "", versionNum);
+
+ return false;
+ });
+ };
+
+ var unbindVersionClick = function() {
+ $(document).off("click.onlyoffice-version", "#versionsTabView .downloadVersion");
+ }
+
var initPage = function () {
if ($("#isPublic").val() === "1" && !$("#filestable").length) {
var fileName = $("#filename").val();
@@ -334,6 +375,10 @@
} else {
OC.Plugins.register("OCA.Files.FileList", OCA.Onlyoffice.FileList);
OC.Plugins.register("OCA.Files.NewFileMenu", OCA.Onlyoffice.NewFileMenu);
+
+ if (OCA.Versions) {
+ OCA.Onlyoffice.bindVersionClick();
+ }
}
};
diff --git a/lib/directeditor.php b/lib/directeditor.php
index aa8cabe..aebe56f 100644
--- a/lib/directeditor.php
+++ b/lib/directeditor.php
@@ -244,6 +244,7 @@ class DirectEditor implements IEditor {
"filePath" => $filePath,
"shareToken" => null,
"directToken" => $directToken,
+ "version" => 0,
"inframe" => false
];
diff --git a/lib/fileutility.php b/lib/fileutility.php
index dd0edbc..bfba9ec 100644
--- a/lib/fileutility.php
+++ b/lib/fileutility.php
@@ -129,7 +129,7 @@ class FileUtility {
}
if ($node instanceof Folder) {
- if ($fileId !== null) {
+ if ($fileId !== null && $fileId !== 0) {
try {
$files = $node->getById($fileId);
} catch (\Exception $e) {
@@ -282,4 +282,19 @@ class FileUtility {
return $key;
}
+
+ /**
+ * Generate unique file version key
+ *
+ * @param OCA\Files_Versions\Versions\IVersion $version - file version
+ *
+ * @return string
+ */
+ public function getVersionKey($version) {
+ $instanceId = $this->config->GetSystemValue("instanceid", true);
+
+ $key = $instanceId . "_" . $version->getSourceFile()->getEtag() . "_" . $version->getRevisionId();
+
+ return $key;
+ }
}
diff --git a/lib/fileversions.php b/lib/fileversions.php
new file mode 100644
index 0000000..32f65ce
--- /dev/null
+++ b/lib/fileversions.php
@@ -0,0 +1,338 @@
+<?php
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2020
+ *
+ * This program is a free software product.
+ * You can redistribute it and/or modify it under the terms of the GNU Affero General Public License
+ * (AGPL) version 3 as published by the Free Software Foundation.
+ * In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
+ * that Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * For details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha street, Riga, Latvia, EU, LV-1050.
+ *
+ * The interactive user interfaces in modified source and object code versions of the Program
+ * must display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
+ *
+ * Pursuant to Section 7(b) of the License you must retain the original Product logo when distributing the program.
+ * Pursuant to Section 7(e) we decline to grant you any rights under trademark law for use of our trademarks.
+ *
+ * All the Product's GUI elements, including illustrations and icon sets, as well as technical
+ * writing content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International.
+ * See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+ *
+ */
+
+namespace OCA\Onlyoffice;
+
+use OC\Files\Node\File;
+use OC\Files\View;
+
+/**
+ * File versions
+ *
+ * @package OCA\Onlyoffice
+ */
+class FileVersions {
+
+ /**
+ * Application name
+ *
+ * @var string
+ */
+ private static $appName = "onlyoffice";
+
+ /**
+ * Changes file extension
+ *
+ * @var string
+ */
+ private static $changesExt = ".zip";
+
+ /**
+ * History file extension
+ *
+ * @var string
+ */
+ private static $historyExt = ".json";
+
+ /**
+ * Split file path and version id
+ *
+ * @param string $pathVersion - version path
+ *
+ * @return array
+ */
+ public static function splitPathVersion($pathVersion) {
+ $pos = strrpos($pathVersion, ".v");
+ if ($pos === false) {
+ return false;
+ }
+ $filePath = substr($pathVersion, 0, $pos);
+ $versionId = substr($pathVersion, 2 + $pos - strlen($pathVersion));
+ return [$filePath, $versionId];
+ }
+
+ /**
+ * Check if folder is not exist
+ *
+ * @param string $userId - user id
+ * @param string $path - folder path
+ * @param bool $createIfNotExist - create folder if not exist
+ *
+ * @return bool
+ */
+ private static function checkFolderExist($view, $path, $createIfNotExist = false) {
+ if ($view->is_dir($path)) {
+ return true;
+ }
+ if (!$createIfNotExist) {
+ return false;
+ }
+ $view->mkdir($path);
+ return true;
+ }
+
+ /**
+ * Get view and path for changes
+ *
+ * @param string $user - user id
+ * @param string $fileId - file id
+ * @param bool $createIfNotExist - create folder if not exist
+ *
+ * @return array
+ */
+ private static function getView($userId, $fileId, $createIfNotExist = false) {
+ $view = new View("/" . $userId);
+
+ $path = self::$appName;
+ if (!self::checkFolderExist($view, $path, $createIfNotExist)) {
+ return [null, null];
+ }
+
+ if ($fileId === null) {
+ return [$view, $path];
+ }
+
+ $path = $path . "/" . $fileId;
+ if (!self::checkFolderExist($view, $path, $createIfNotExist)) {
+ return [null, null];
+ }
+
+ return [$view, $path];
+ }
+
+ /**
+ * Get changes from stored to history object
+ *
+ * @param string $ownerId - file owner id
+ * @param string $fileId - file id
+ * @param string $versionId - file version
+ * @param string $prevVersion - previous version for check
+ *
+ * @return array
+ */
+ public static function getHistoryData($ownerId, $fileId, $versionId, $prevVersion) {
+ $logger = \OC::$server->getLogger();
+
+ if ($ownerId === null || $fileId === null) {
+ return null;
+ }
+
+ list ($view, $path) = self::getView($ownerId, $fileId);
+ if ($view === null) {
+ return null;
+ }
+
+ $historyPath = $path . "/" . $versionId . self::$historyExt;
+ if (!$view->file_exists($historyPath)) {
+ return null;
+ }
+
+ $historyDataString = $view->file_get_contents($historyPath);
+
+ try {
+ $historyData = json_decode($historyDataString, true);
+
+ if ($historyData["prev"] !== $prevVersion) {
+ $logger->debug("getHistoryData: previous $prevVersion != " . $historyData["prev"], ["app" => self::$appName]);
+
+ $view->unlink($historyPath);
+ $logger->debug("getHistoryData: delete $historyPath", ["app" => self::$appName]);
+
+ $changesPath = $path . "/" . $versionId . self::$changesExt;
+ if ($view->file_exists($changesPath)) {
+ $view->unlink($changesPath);
+ $logger->debug("getHistoryData: delete $changesPath", ["app" => self::$appName]);
+ }
+ return null;
+ }
+
+ return $historyData;
+ } catch (\Exception $e) {
+ $logger->logException($e, ["message" => "getHistoryData: $fileId $versionId", "app" => self::$appName]);
+ return null;
+ }
+ }
+
+ /**
+ * Check if changes is stored
+ *
+ * @param string $ownerId - file owner id
+ * @param string $fileId - file id
+ * @param string $versionId - file version
+ *
+ * @return bool
+ */
+ public static function hasChanges($ownerId, $fileId, $versionId) {
+ if ($ownerId === null || $fileId === null) {
+ return false;
+ }
+
+ list ($view, $path) = self::getView($ownerId, $fileId);
+ if ($view === null) {
+ return false;
+ }
+
+ $changesPath = $path . "/" . $versionId . self::$changesExt;
+ return $view->file_exists($changesPath);
+ }
+
+ /**
+ * Get changes file
+ *
+ * @param string $ownerId - file owner id
+ * @param string $fileId - file id
+ * @param string $versionId - file version
+ *
+ * @return File
+ */
+ public static function getChangesFile($ownerId, $fileId, $versionId) {
+ if ($ownerId === null || $fileId === null) {
+ return null;
+ }
+
+ list ($view, $path) = self::getView($ownerId, $fileId);
+ if ($view === null) {
+ return null;
+ }
+
+ $changesPath = $path . "/" . $versionId . self::$changesExt;
+ if (!$view->file_exists($changesPath)) {
+ return null;
+ }
+
+ $changesInfo = $view->getFileInfo($changesPath);
+ $changes = new File($view->getRoot(), $view, $changesPath, $changesInfo);
+
+ \OC::$server->getLogger()->debug("getChangesFile: $fileId for $ownerId get changes $changesPath", ["app" => self::$appName]);
+
+ return $changes;
+ }
+
+ /**
+ * Save history to storage
+ *
+ * @param OCP\Files\FileInfo $fileInfo - file info
+ * @param array $history - file history
+ * @param string $changes - file changes
+ * @param string $prevVersion - previous version for check
+ */
+ public static function saveHistory($fileInfo, $history, $changes, $prevVersion) {
+ $logger = \OC::$server->getLogger();
+
+ $owner = $fileInfo->getOwner();
+
+ if ($owner === null) {
+ return;
+ }
+ if (empty($history) || empty($changes)) {
+ return;
+ }
+
+ $ownerId = $owner->getUID();
+ $fileId = $fileInfo->getId();
+ $versionId = $fileInfo->getMtime();
+
+ list ($view, $path) = self::getView($ownerId, $fileId, true);
+
+ try {
+ $changesPath = $path . "/" . $versionId . self::$changesExt;
+ $view->touch($changesPath);
+ $view->file_put_contents($changesPath, $changes);
+
+ $history["prev"] = $prevVersion;
+ $historyPath = $path . "/" . $versionId . self::$historyExt;
+ $view->touch($historyPath);
+ $view->file_put_contents($historyPath, json_encode($history));
+
+ $logger->debug("saveHistory: $fileId for $ownerId stored changes $changesPath history $historyPath", ["app" => self::$appName]);
+ } catch (\Exception $e) {
+ $logger->logException($e, ["message" => "saveHistory: save $fileId history error", "app" => self::$appName]);
+ }
+ }
+
+ /**
+ * Delete all versions of file
+ *
+ * @param string $ownerId - file owner id
+ * @param string $fileId - file id
+ */
+ public static function deleteAllVersions($ownerId, $fileId = null) {
+ $logger = \OC::$server->getLogger();
+
+ $logger->debug("deleteAllVersions $ownerId $fileId", ["app" => self::$appName]);
+
+ if ($ownerId === null) {
+ return;
+ }
+
+ list ($view, $path) = self::getView($ownerId, $fileId);
+ if ($view === null) {
+ return;
+ }
+
+ $view->unlink($path);
+ }
+
+ /**
+ * Delete changes and history
+ *
+ * @param string $ownerId - file owner id
+ * @param string $fileId - file id
+ * @param string $versionId - file version
+ */
+ public static function deleteVersion($ownerId, $fileId, $versionId) {
+ $logger = \OC::$server->getLogger();
+
+ $logger->debug("deleteVersion $fileId ($versionId)", ["app" => self::$appName]);
+
+ if ($ownerId === null) {
+ return;
+ }
+ if ($fileId === null || empty($versionId)) {
+ return;
+ }
+
+ list ($view, $path) = self::getView($ownerId, $fileId);
+ if ($view === null) {
+ return null;
+ }
+
+ $historyPath = $path . "/" . $versionId . self::$historyExt;
+ if ($view->file_exists($historyPath)) {
+ $view->unlink($historyPath);
+ $logger->debug("deleteVersion $historyPath", ["app" => self::$appName]);
+ }
+
+ $changesPath = $path . "/" . $versionId . self::$changesExt;
+ if ($view->file_exists($changesPath)) {
+ $view->unlink($changesPath);
+ $logger->debug("deleteVersion $changesPath", ["app" => self::$appName]);
+ }
+ }
+}
diff --git a/lib/hooks.php b/lib/hooks.php
new file mode 100644
index 0000000..d8d89d1
--- /dev/null
+++ b/lib/hooks.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2020
+ *
+ * This program is a free software product.
+ * You can redistribute it and/or modify it under the terms of the GNU Affero General Public License
+ * (AGPL) version 3 as published by the Free Software Foundation.
+ * In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
+ * that Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * For details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha street, Riga, Latvia, EU, LV-1050.
+ *
+ * The interactive user interfaces in modified source and object code versions of the Program
+ * must display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
+ *
+ * Pursuant to Section 7(b) of the License you must retain the original Product logo when distributing the program.
+ * Pursuant to Section 7(e) we decline to grant you any rights under trademark law for use of our trademarks.
+ *
+ * All the Product's GUI elements, including illustrations and icon sets, as well as technical
+ * writing content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International.
+ * See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+ *
+ */
+
+namespace OCA\Onlyoffice;
+
+use OC\Files\Filesystem;
+
+use OCP\Util;
+
+use OCA\Onlyoffice\FileVersions;
+
+/**
+ * The class to handle the filesystem hooks
+ *
+ * @package OCA\Onlyoffice
+ */
+class Hooks {
+
+ /**
+ * Application name
+ *
+ * @var string
+ */
+ private static $appName = "onlyoffice";
+
+ public static function connectHooks() {
+ // Listen user deletion
+ Util::connectHook("OC_User", "pre_deleteUser", Hooks::class, "userDelete");
+
+ // Listen file deletion
+ Util::connectHook("OC_Filesystem", "delete", Hooks::class, "fileDelete");
+
+ // Listen file version deletion
+ Util::connectHook("\OCP\Versions", "preDelete", Hooks::class, "fileVersionDelete");
+
+ // Listen file version restore
+ Util::connectHook("\OCP\Versions", "rollback", Hooks::class, "fileVersionRestore");
+ }
+
+ /**
+ * Erase user file versions
+ *
+ * @param array $params - hook params
+ */
+ public static function userDelete($params) {
+ $userId = $params["uid"];
+
+ FileVersions::deleteAllVersions($userId);
+ }
+
+ /**
+ * Erase versions of deleted file
+ *
+ * @param array $params - hook params
+ */
+ public static function fileDelete($params) {
+ $filePath = $params[Filesystem::signal_param_path];
+ if (empty($filePath)) {
+ return;
+ }
+
+ try {
+ $ownerId = Filesystem::getOwner($filePath);
+
+ $fileInfo = Filesystem::getFileInfo($filePath);
+ $fileId = $fileInfo->getId();
+
+ FileVersions::deleteAllVersions($ownerId, $fileId);
+ } catch (\Exception $e) {
+ \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileDelete " . json_encode($params), "app" => self::$appName]);
+ }
+ }
+
+ /**
+ * Erase versions of deleted version of file
+ *
+ * @param array $params - hook param
+ */
+ public static function fileVersionDelete($params) {
+ $pathVersion = $params["path"];
+ if (empty($pathVersion)) {
+ return;
+ }
+
+ try {
+ list ($filePath, $versionId) = FileVersions::splitPathVersion($pathVersion);
+ if (empty($filePath)) {
+ return;
+ }
+
+ $ownerId = Filesystem::getOwner($filePath);
+
+ $fileInfo = Filesystem::getFileInfo($filePath);
+ $fileId = $fileInfo->getId();
+
+ FileVersions::deleteVersion($ownerId, $fileId, $versionId);
+ } catch (\Exception $e) {
+ \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileVersionDelete " . json_encode($params), "app" => self::$appName]);
+ }
+ }
+
+ /**
+ * Erase versions of restored version of file
+ *
+ * @param array $params - hook param
+ */
+ public static function fileVersionRestore($params) {
+ $filePath = $params["path"];
+ if (empty($filePath)) {
+ return;
+ }
+
+ $versionId = $params["revision"];
+
+ try {
+ $ownerId = Filesystem::getOwner($filePath);
+
+ $fileInfo = Filesystem::getFileInfo($filePath);
+ $fileId = $fileInfo->getId();
+
+ FileVersions::deleteVersion($ownerId, $fileId, $versionId);
+ } catch (\Exception $e) {
+ \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileVersionRestore " . json_encode($params), "app" => self::$appName]);
+ }
+ }
+}
diff --git a/templates/editor.php b/templates/editor.php
index 381c316..c6d17af 100644
--- a/templates/editor.php
+++ b/templates/editor.php
@@ -42,6 +42,7 @@
data-path="<?php p($_["filePath"]) ?>"
data-sharetoken="<?php p($_["shareToken"]) ?>"
data-directtoken="<?php p($_["directToken"]) ?>"
+ data-version="<?php p($_["version"]) ?>"
data-inframe="<?php p($_["inframe"]) ?>"></div>
<?php if (!empty($_["documentServerUrl"])) { ?>