Skip to content

Commit

Permalink
Merge pull request #723 from ONLYOFFICE/feature/nc-25
Browse files Browse the repository at this point in the history
Release/7.6.6
  • Loading branch information
LinneyS authored Oct 20, 2022
2 parents b057eed + a785bb7 commit d42086c
Show file tree
Hide file tree
Showing 57 changed files with 1,066 additions and 290 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Change Log

## 7.6.6
## Added
- Dutch translation
- Chinese (Traditional, Taiwan), Basque (Spain) empty file templates

## Changed
- compatible with Nextcloud 25
- generate preview by default
- fix editing with federated share
- fix opening file in new tab
- fix watermark for shared file by link
- fix update application
- Nextcloud v24 is no longer supported

## 7.5.4
## Changed
- fix opening editor in new tab
Expand Down
7 changes: 5 additions & 2 deletions appinfo/application.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
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;
Expand Down Expand Up @@ -199,7 +200,8 @@ public function register(IRegistrationContext $context): void {
$this->crypt,
$c->get("IManager"),
$c->get("Session"),
$c->get(ITagManager::class)
$c->get(ITagManager::class),
$c->get(ILockManager::class)
);
});

Expand All @@ -214,7 +216,8 @@ public function register(IRegistrationContext $context): void {
$c->get("Logger"),
$this->appConfig,
$this->crypt,
$c->get("IManager")
$c->get("IManager"),
$c->get(ILockManager::class)
);
});

Expand Down
5 changes: 3 additions & 2 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<description>ONLYOFFICE connector allows you to view, edit and collaborate on text documents, spreadsheets and presentations within Nextcloud using ONLYOFFICE Docs. This will create a new Edit in ONLYOFFICE action within the document library for Office documents. This allows multiple users to co-author documents in real time from the familiar web interface and save the changes back to your file storage.</description>
<licence>apache</licence>
<author mail="dev@onlyoffice.com" homepage="https://www.onlyoffice.com/">Ascensio System SIA</author>
<version>7.5.4</version>
<version>7.6.6</version>
<namespace>Onlyoffice</namespace>
<types>
<prevent_group_restriction/>
Expand All @@ -28,8 +28,9 @@
<screenshot>https://raw.githubusercontent.com/ONLYOFFICE/onlyoffice-nextcloud/master/screenshots/settings.png</screenshot>
<screenshot>https://raw.githubusercontent.com/ONLYOFFICE/onlyoffice-nextcloud/master/screenshots/new.png</screenshot>
<screenshot>https://raw.githubusercontent.com/ONLYOFFICE/onlyoffice-nextcloud/master/screenshots/open.png</screenshot>
<screenshot>https://raw.githubusercontent.com/ONLYOFFICE/onlyoffice-nextcloud/master/screenshots/open_form.png</screenshot>
<dependencies>
<nextcloud min-version="24" max-version="24"/>
<nextcloud min-version="25" max-version="25"/>
</dependencies>
<settings>
<admin>OCA\Onlyoffice\AdminSettings</admin>
Expand Down
1 change: 1 addition & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"ocs" => [
["name" => "federation#key", "url" => "/api/v1/key", "verb" => "POST"],
["name" => "federation#keylock", "url" => "/api/v1/keylock", "verb" => "POST"],
["name" => "federation#healthcheck", "url" => "/api/v1/healthcheck", "verb" => "GET"],
["name" => "editorapi#config", "url" => "/api/v1/config/{fileId}", "verb" => "GET"],
["name" => "sharingapi#get_shares", "url" => "/api/v1/shares/{fileId}", "verb" => "GET"],
["name" => "sharingapi#set_shares", "url" => "/api/v1/shares", "verb" => "PUT"]
Expand Down
2 changes: 1 addition & 1 deletion assets
Submodule assets updated 78 files
+ az-Latn-AZ/new.docx
+ az-Latn-AZ/new.docxf
+ az-Latn-AZ/new.pptx
+ az-Latn-AZ/new.xlsx
+ bg-BG/new.pptx
+ bg-BG/new.xlsx
+ de-DE/new.pptx
+ de-DE/new.xlsx
+ el-GR/new.pptx
+ el-GR/new.xlsx
+ en-GB/new.pptx
+ en-GB/new.xlsx
+ en-US/new.pptx
+ en-US/new.xlsx
+ es-ES/new.docxf
+ es-ES/new.pptx
+ es-ES/new.xlsx
+ eu-ES/new.docx
+ eu-ES/new.docxf
+ eu-ES/new.pptx
+ eu-ES/new.xlsx
+ fr-FR/new.pptx
+ fr-FR/new.xlsx
+ gl-ES/new.pptx
+ gl-ES/new.xlsx
+ hy-AM/new.docx
+ hy-AM/new.docxf
+ hy-AM/new.pptx
+ hy-AM/new.xlsx
+ it-IT/new.pptx
+ it-IT/new.xlsx
+ ja-JP/new.docx
+ ja-JP/new.docxf
+ ja-JP/new.pptx
+ ja-JP/new.xlsx
+ ko-KR/new.pptx
+ ko-KR/new.xlsx
+ lv-LV/new.pptx
+ lv-LV/new.xlsx
+ ms-MY/new.docx
+ ms-MY/new.docxf
+ ms-MY/new.pptx
+ ms-MY/new.xlsx
+ nl-NL/new.pptx
+ nl-NL/new.xlsx
+ pl-PL/new.pptx
+ pl-PL/new.xlsx
+ pt-BR/new.docx
+ pt-BR/new.docxf
+ pt-BR/new.pptx
+ pt-BR/new.xlsx
+ pt-PT/new.docx
+ pt-PT/new.docxf
+ pt-PT/new.pptx
+ pt-PT/new.xlsx
+ ru-RU/new.pptx
+ ru-RU/new.xlsx
+ sk-SK/new.docx
+ sk-SK/new.docxf
+ sk-SK/new.pptx
+ sk-SK/new.xlsx
+ sv-SE/new.docx
+ sv-SE/new.docxf
+ sv-SE/new.pptx
+ sv-SE/new.xlsx
+ tr-TR/new.docxf
+ tr-TR/new.pptx
+ tr-TR/new.xlsx
+ uk-UA/new.pptx
+ uk-UA/new.xlsx
+ vi-VN/new.pptx
+ vi-VN/new.xlsx
+ zh-CN/new.pptx
+ zh-CN/new.xlsx
+ zh-TW/new.docx
+ zh-TW/new.docxf
+ zh-TW/new.pptx
+ zh-TW/new.xlsx
213 changes: 148 additions & 65 deletions controller/callbackcontroller.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
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;
Expand All @@ -39,14 +45,14 @@
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;

use OCA\Files_Sharing\External\Storage as SharingExternalStorage;
use OCA\Files_Versions\Versions\IVersionManager;

use OCA\Onlyoffice\AppConfig;
use OCA\Onlyoffice\Crypt;
use OCA\Onlyoffice\DocumentService;
use OCA\Onlyoffice\FileVersions;
use OCA\Onlyoffice\KeyManager;
use OCA\Onlyoffice\RemoteInstance;
use OCA\Onlyoffice\TemplateManager;

/**
Expand Down Expand Up @@ -119,6 +125,13 @@ class CallbackController extends Controller {
*/
private $versionManager;

/**
* Lock manager
*
* @var ILockManager
*/
private $lockManager;

/**
* Status of the document
*/
Expand All @@ -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,
Expand All @@ -150,7 +164,8 @@ public function __construct($AppName,
ILogger $logger,
AppConfig $config,
Crypt $crypt,
IManager $shareManager
IManager $shareManager,
ILockManager $lockManager
) {
parent::__construct($AppName, $request);

Expand All @@ -162,6 +177,7 @@ public function __construct($AppName,
$this->config = $config;
$this->crypt = $crypt;
$this->shareManager = $shareManager;
$this->lockManager = $lockManager;

if (\OC::$server->getAppManager()->isInstalled("files_versions")) {
try {
Expand Down Expand Up @@ -434,77 +450,84 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan
$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)
&& $status !== self::TrackerStatus_Editing) {
// 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();
Expand All @@ -529,8 +552,8 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan

$prevIsForcesave = KeyManager::wasForcesave($fileId);

if ($file->getStorage()->instanceOfStorage(SharingExternalStorage::class)) {
$isLock = KeyManager::lockFederatedKey($file, $isForcesave, null);
if (RemoteInstance::isRemoteFile($file)) {
$isLock = RemoteInstance::lockRemoteKey($file, $isForcesave, null);
if ($isForcesave && !$isLock) {
break;
}
Expand All @@ -539,13 +562,27 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan
}

$this->logger->debug("Track put content " . $file->getPath(), ["app" => $this->appName]);
$this->retryOperation(function () use ($file, $newData) {
return $file->putContent($newData);
});

if ($file->getStorage()->instanceOfStorage(SharingExternalStorage::class)) {
$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);
} catch (NoLockProviderException $e) {
$retryOperation();
}

if (!$isForcesave) {
$this->unlock($file);
}

if (RemoteInstance::isRemoteFile($file)) {
if ($isForcesave) {
KeyManager::lockFederatedKey($file, false, $isForcesave);
RemoteInstance::lockRemoteKey($file, false, $isForcesave);
}
} else {
KeyManager::lock($fileId, false);
Expand Down Expand Up @@ -575,7 +612,13 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan
break;

case self::TrackerStatus_Editing:
$this->lock($file);

$result = 0;
break;
case self::TrackerStatus_Closed:
$this->unlock($file);

$result = 0;
break;
}
Expand Down Expand Up @@ -756,6 +799,46 @@ private function parseUserId($userId) {
return $userId;
}

/**
* Lock file by lock provider if exists
*
* @param File $file - file
*/
private function lock($file) {
if (!$this->lockManager->isLockProviderAvailable()) {
return;
}

$fileId = $file->getId();

try {
if (empty($this->lockManager->getLocks($fileId))) {
$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) {}
}

/**
* Unlock file by lock provider if exists
*
* @param File $file - file
*/
private function unlock($file) {
if (!$this->lockManager->isLockProviderAvailable()) {
return;
}

$fileId = $file->getId();

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) {}
}

/**
* Retry operation if a LockedException occurred
* Other exceptions will still be thrown
Expand Down
Loading

0 comments on commit d42086c

Please sign in to comment.