diff options
author | Julius Härtl <jus@bitgrid.net> | 2019-05-23 17:02:31 +0300 |
---|---|---|
committer | Julius Härtl <jus@bitgrid.net> | 2019-12-18 11:54:06 +0300 |
commit | edb200299d513184b6bf6bd84936b951c288cb89 (patch) | |
tree | 7e1057f8b2ab9ec1fb30a3f19fd60c5b16604aac /lib | |
parent | 6ecc8499f9d0ebc20c15125f4bde959d2d658e12 (diff) |
Start with new template creation mechanism
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Capabilities.php | 3 | ||||
-rw-r--r-- | lib/Controller/DirectViewController.php | 9 | ||||
-rw-r--r-- | lib/Controller/DocumentController.php | 9 | ||||
-rw-r--r-- | lib/Controller/WopiController.php | 66 | ||||
-rw-r--r-- | lib/Db/Direct.php | 6 | ||||
-rw-r--r-- | lib/Db/Wopi.php | 10 | ||||
-rw-r--r-- | lib/Db/WopiMapper.php | 5 | ||||
-rw-r--r-- | lib/Preview/Office.php | 2 | ||||
-rw-r--r-- | lib/Service/CapabilitiesService.php | 31 | ||||
-rw-r--r-- | lib/TokenManager.php | 46 |
10 files changed, 156 insertions, 31 deletions
diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 90094269..43eb427b 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -105,13 +105,14 @@ class Capabilities implements ICapability { 'mimetypesNoDefaultOpen' => self::MIMETYPES_OPTIONAL, 'collabora' => $collaboraCapabilities, 'direct_editing' => isset($collaboraCapabilities['hasMobileSupport']) ? : false, - 'templates' => isset($collaboraCapabilities['hasTemplateSaveAs']) ? : false, + 'templates' => isset($collaboraCapabilities['hasTemplateSaveAs']) || isset($collaboraCapabilities['hasTemplateSource']) ? : false, 'productName' => isset($collaboraCapabilities['productName']) ? $collaboraCapabilities['productName'] : $this->l10n->t('Collabora Online'), ], ]; } /** + * TODO: use CapabilitiesService * @return array * @throws \OCP\Files\NotPermittedException */ diff --git a/lib/Controller/DirectViewController.php b/lib/Controller/DirectViewController.php index b392fa8e..62dec909 100644 --- a/lib/Controller/DirectViewController.php +++ b/lib/Controller/DirectViewController.php @@ -114,7 +114,8 @@ class DirectViewController extends Controller { } try { - list($urlSrc, $token) = $this->tokenManager->getTokenForTemplate($item, $direct->getUid(), $direct->getTemplateDestination(), true); + + list($urlSrc, $wopi) = $this->tokenManager->getTokenForTemplate($item, $direct->getUid(), $direct->getTemplateDestination(), true); } catch (\Exception $e) { return new JSONResponse([], Http::STATUS_BAD_REQUEST); } @@ -136,7 +137,7 @@ class DirectViewController extends Controller { return $response; } - list($urlSrc, $token) = $this->tokenManager->getToken($item->getId(), null, $direct->getUid(), true); + list($urlSrc, $token, $wopi) = $this->tokenManager->getToken($item->getId(), null, $direct->getUid(), true); } catch (\Exception $e) { $params = [ 'errors' => [['error' => $e->getMessage()]] @@ -151,8 +152,8 @@ class DirectViewController extends Controller { $params = [ 'permissions' => $item->getPermissions(), 'title' => $item->getName(), - 'fileId' => $item->getId() . '_' . $this->config->getSystemValue('instanceid'), - 'token' => $token, + 'fileId' => $wopi->getFileid() . '_' . $this->config->getSystemValue('instanceid'), + 'token' => $wopi->getToken(), 'urlsrc' => $urlSrc, 'path' => $relativePath, 'instanceId' => $this->config->getSystemValue('instanceid'), diff --git a/lib/Controller/DocumentController.php b/lib/Controller/DocumentController.php index dd6db804..ca6eb0fd 100644 --- a/lib/Controller/DocumentController.php +++ b/lib/Controller/DocumentController.php @@ -306,13 +306,16 @@ class DocumentController extends Controller { $file = $folder->newFile($fileName); $template = $this->templateManager->get($templateId); - list($urlSrc, $token) = $this->tokenManager->getTokenForTemplate($template, $this->uid, $file->getId()); + list($urlSrc, $wopi) = $this->tokenManager->getTokenForTemplate($template, $this->uid, $file->getId()); + + $wopiFileId = $template->getId() . '-' . $file->getId() . '_' . $this->settings->getSystemValue('instanceid'); + $wopiFileId = $wopi->getFileid() . '_' . $this->settings->getSystemValue('instanceid'); $params = [ 'permissions' => $template->getPermissions(), 'title' => $fileName, - 'fileId' => $template->getId() . '-' . $file->getId() . '_' . $this->settings->getSystemValue('instanceid'), - 'token' => $token, + 'fileId' => $wopiFileId, + 'token' => $wopi->getToken(), 'urlsrc' => $urlSrc, 'path' => $userFolder->getRelativePath($file->getPath()), 'instanceId' => $this->settings->getSystemValue('instanceid'), diff --git a/lib/Controller/WopiController.php b/lib/Controller/WopiController.php index e32eea51..d0ffc771 100644 --- a/lib/Controller/WopiController.php +++ b/lib/Controller/WopiController.php @@ -202,12 +202,21 @@ class WopiController extends Controller { ]; $watermarkTemplate = $this->appConfig->getAppValue('watermark_text'); - $response['WatermarkText'] = preg_replace_callback('/{(.+?)}/', function($matches) use ($replacements) - { + $response['WatermarkText'] = preg_replace_callback('/{(.+?)}/', function ($matches) use ($replacements) { return $replacements[$matches[1]]; }, $watermarkTemplate); } + /** + * New approach for generating files from templates by creating an empty file + * and providing an URL which returns the actual templyte + */ + if ($wopi->hasTemplateId()) { + $templateUrl = 'index.php/apps/richdocuments/wopi/template/' . $wopi->getTemplateId() . '?access_token=' . $wopi->getToken(); + $templateUrl = $this->urlGenerator->getAbsoluteURL($templateUrl); + $response['TemplateSource'] = $templateUrl; + } + $user = $this->userManager->get($wopi->getEditorUid()); if($user !== null && $user->getAvatarImage(32) !== null) { $response['UserExtraInfo']['avatar'] = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $wopi->getEditorUid(), 'size' => 32]); @@ -387,8 +396,11 @@ class WopiController extends Controller { if ($isPutRelative) { // the new file needs to be installed in the current user dir $userFolder = $this->rootFolder->getUserFolder($wopi->getEditorUid()); - $file = $userFolder->getById($fileId)[0]; - + $file = $userFolder->getById($fileId); + if (count($file) === 0) { + return new JSONResponse([], Http::STATUS_NOT_FOUND); + } + $file = $file[0]; $suggested = $this->request->getHeader('X-WOPI-SuggestedTarget'); $suggested = iconv('utf-7', 'utf-8', $suggested); @@ -421,10 +433,11 @@ class WopiController extends Controller { } else { $file = $this->getFileForWopiToken($wopi); $wopiHeaderTime = $this->request->getHeader('X-LOOL-WOPI-Timestamp'); - if ($wopiHeaderTime !== null && $wopiHeaderTime !== Helper::toISO8601($file->getMTime())) { + + if ($wopiHeaderTime !== null && $wopiHeaderTime !== Helper::toISO8601($file->getMTime() ?? 0)) { $this->logger->debug('Document timestamp mismatch ! WOPI client says mtime {headerTime} but storage says {storageTime}', [ 'headerTime' => $wopiHeaderTime, - 'storageTime' => Helper::toISO8601($file->getMTime()) + 'storageTime' => Helper::toISO8601($file->getMTime() ?? 0) ]); // Tell WOPI client about this conflict. return new JSONResponse(['LOOLStatusCode' => self::LOOL_STATUS_DOC_CHANGED], Http::STATUS_CONFLICT); @@ -538,7 +551,11 @@ class WopiController extends Controller { $path = $this->rootFolder->getNonExistingName($path); $file = $file->move($path); } else { - $file = $userFolder->getById($fileId)[0]; + $file = $userFolder->getById($fileId); + if (count($file) === 0) { + return new JSONResponse([], Http::STATUS_NOT_FOUND); + } + $file = $file[0]; $suggested = $this->request->getHeader('X-WOPI-SuggestedTarget'); $suggested = iconv('utf-7', 'utf-8', $suggested); @@ -658,4 +675,39 @@ class WopiController extends Controller { } return $file; } + + /** + * Endpoint to return the template file that is requested by collabora to create a new document + * + * @PublicPage + * @NoCSRFRequired + * + * @param $fileId + * @param $access_token + * @return JSONResponse|StreamResponse + */ + public function getTemplate($fileId, $access_token) { + try { + $wopi = $this->wopiMapper->getPathForToken($access_token); + } catch (DoesNotExistException $e) { + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + + if ((int)$fileId !== $wopi->getTemplateId()) { + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + + try { + $this->templateManager->setUserId($wopi->getOwnerUid()); + $file = $this->templateManager->get($wopi->getTemplateId()); + $response = new StreamResponse($file->fopen('rb')); + $response->addHeader('Content-Disposition', 'attachment'); + $response->addHeader('Content-Type', 'application/octet-stream'); + return $response; + } catch (\Exception $e) { + $this->logger->logException($e, ['level' => ILogger::ERROR, 'app' => 'richdocuments', 'message' => 'getTemplate failed']); + return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + } diff --git a/lib/Db/Direct.php b/lib/Db/Direct.php index 437df370..92dcbe05 100644 --- a/lib/Db/Direct.php +++ b/lib/Db/Direct.php @@ -36,6 +36,8 @@ use OCP\AppFramework\Db\Entity; * @method int getTimestamp() * @method void setTemplateDestination(int $fileId) * @method int getTemplateDestination() + * @method void setTemplateId(int $fileId) + * @method int getTemplateId() */ class Direct extends Entity { /** @var string */ @@ -53,11 +55,15 @@ class Direct extends Entity { /** @var int */ protected $templateDestination; + /** @var int */ + protected $templateId; + public function __construct() { $this->addType('token', 'string'); $this->addType('uid', 'string'); $this->addType('fileid', 'int'); $this->addType('timestamp', 'int'); $this->addType('template_destination', 'int'); + $this->addType('template_id', 'int'); } } diff --git a/lib/Db/Wopi.php b/lib/Db/Wopi.php index f8d8143b..fab36964 100644 --- a/lib/Db/Wopi.php +++ b/lib/Db/Wopi.php @@ -49,6 +49,8 @@ use OCP\AppFramework\Db\Entity; * @method string getGuestDisplayname() * @method void setTemplateDestination(int $fileId) * @method int getTemplateDestination() + * @method void setTemplateId(int $fileId) + * @method int getTemplateId() */ class Wopi extends Entity { /** @var string */ @@ -81,6 +83,9 @@ class Wopi extends Entity { /** @var int */ protected $templateDestination; + /** @var int */ + protected $templateId; + /** @var bool */ protected $hideDownload; @@ -107,6 +112,7 @@ class Wopi extends Entity { $this->addType('expiry', 'int'); $this->addType('guest_displayname', 'string'); $this->addType('templateDestination', 'int'); + $this->addType('templateId', 'int'); $this->addType('hide_download', 'bool'); $this->addType('direct', 'bool'); @@ -116,4 +122,8 @@ class Wopi extends Entity { return $this->getTemplateDestination() !== 0 && $this->getTemplateDestination() !== null; } + public function hasTemplateId() { + return $this->getTemplateId() !== 0 && $this->getTemplateId() !== null; + } + } diff --git a/lib/Db/WopiMapper.php b/lib/Db/WopiMapper.php index e9056730..e5cf8665 100644 --- a/lib/Db/WopiMapper.php +++ b/lib/Db/WopiMapper.php @@ -64,7 +64,7 @@ class WopiMapper extends Mapper { * @param int $templateDestination * @return Wopi */ - public function generateFileToken($fileId, $owner, $editor, $version, $updatable, $serverHost, $guestDisplayname, $templateDestination = 0, $hideDownload = false, $direct = false, $isRemoteToken = false) { + public function generateFileToken($fileId, $owner, $editor, $version, $updatable, $serverHost, $guestDisplayname, $templateDestination = 0, $hideDownload = false, $direct = false, $isRemoteToken = false, $templateId = 0) { $token = $this->random->generate(32, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS); $wopi = Wopi::fromParams([ @@ -80,7 +80,8 @@ class WopiMapper extends Mapper { 'templateDestination' => $templateDestination, 'hideDownload' => $hideDownload, 'direct' => $direct, - 'isRemoteToken' => $isRemoteToken + 'isRemoteToken' => $isRemoteToken, + 'templateId' => $templateId, ]); /** @var Wopi $wopi */ diff --git a/lib/Preview/Office.php b/lib/Preview/Office.php index 6b43c045..f3f8af01 100644 --- a/lib/Preview/Office.php +++ b/lib/Preview/Office.php @@ -21,6 +21,8 @@ */ namespace OCA\Richdocuments\Preview; +use GuzzleHttp\Psr7\LimitStream; +use function GuzzleHttp\Psr7\stream_for; use OC\Preview\Provider; use OCA\Richdocuments\Capabilities; use OCP\Http\Client\IClientService; diff --git a/lib/Service/CapabilitiesService.php b/lib/Service/CapabilitiesService.php index 82202ce4..fb8856c4 100644 --- a/lib/Service/CapabilitiesService.php +++ b/lib/Service/CapabilitiesService.php @@ -38,6 +38,8 @@ class CapabilitiesService { private $clientService; /** @var ISimpleFolder */ private $appData; + /** @var array */ + private $capabilities; public function __construct(IConfig $config, IClientService $clientService, IAppData $appData) { $this->config = $config; @@ -49,6 +51,34 @@ class CapabilitiesService { } } + + public function getCapabilities() { + if ($this->capabilities) { + return $this->capabilities; + } + try { + $file = $this->appData->getFile('capabilities.json'); + $decodedFile = \json_decode($file->getContent(), true); + } catch (NotFoundException $e) { + return []; + } + + if (!is_array($decodedFile)) { + return []; + } + $this->capabilities = $decodedFile; + + return $this->capabilities; + } + + public function hasTemplateSaveAs() { + return $this->getCapabilities()['hasTemplateSaveAs'] ?? false; + } + + public function hasTemplateSource() { + return $this->getCapabilities()['hasTemplateSource'] ?? false; + } + private function getFile() { try { $file = $this->appData->getFile('capabilities.json'); @@ -103,4 +133,5 @@ class CapabilitiesService { return $ret; } + } diff --git a/lib/TokenManager.php b/lib/TokenManager.php index 33233ddb..bb0b4f6a 100644 --- a/lib/TokenManager.php +++ b/lib/TokenManager.php @@ -25,6 +25,7 @@ use OC\Share\Constants; use OCA\Richdocuments\Db\WopiMapper; use OCA\Richdocuments\Helper; use OCA\Richdocuments\Db\Wopi; +use OCA\Richdocuments\Service\CapabilitiesService; use OCA\Richdocuments\WOPI\Parser; use OCP\Files\File; use OCP\Files\IRootFolder; @@ -58,6 +59,8 @@ class TokenManager { private $userManager; /** @var IGroupManager */ private $groupManager; + /** @var CapabilitiesService */ + private $capabilitiesService; /** * @param IRootFolder $rootFolder @@ -73,6 +76,7 @@ class TokenManager { IManager $shareManager, IURLGenerator $urlGenerator, Parser $wopiParser, + CapabilitiesService $capabilitiesService, AppConfig $appConfig, $UserId, WopiMapper $wopiMapper, @@ -83,6 +87,7 @@ class TokenManager { $this->shareManager = $shareManager; $this->urlGenerator = $urlGenerator; $this->wopiParser = $wopiParser; + $this->capabilitiesService = $capabilitiesService; $this->appConfig = $appConfig; $this->trans = $trans; $this->userId = $UserId; @@ -99,11 +104,11 @@ class TokenManager { * @throws \Exception */ public function getToken($fileId, $shareToken = null, $editoruid = null, $direct = false, $isRemoteToken = false) { - list($fileId,, $version) = Helper::parseFileId($fileId); + list($fileId, , $version) = Helper::parseFileId($fileId); $owneruid = null; $hideDownload = false; // if the user is not logged-in do use the sharers storage - if($shareToken !== null) { + if ($shareToken !== null) { /** @var File $file */ $rootFolder = $this->rootFolder; $share = $this->shareManager->getShareByToken($shareToken); @@ -132,12 +137,12 @@ class TokenManager { $editorUser = $this->userManager->get($editoruid); if ($updatable && count($editGroups) > 0 && $editorUser) { $updatable = false; - foreach($editGroups as $editGroup) { - $editorGroup = $this->groupManager->get($editGroup); - if ($editorGroup !== null && $editorGroup->inGroup($editorUser)) { + foreach ($editGroups as $editGroup) { + $editorGroup = $this->groupManager->get($editGroup); + if ($editorGroup !== null && $editorGroup->inGroup($editorUser)) { $updatable = true; break; - } + } } } } catch (\Exception $e) { @@ -174,7 +179,7 @@ class TokenManager { $serverHost = $this->urlGenerator->getAbsoluteURL('/');//$this->request->getServerProtocol() . '://' . $this->request->getServerHost(); - $guest_name = NULL; + $guest_name = null; if ($this->userId === null) { if (isset($_COOKIE['guestUser']) && $_COOKIE['guestUser'] !== '') { $guest_name = $this->trans->t('%s (Guest)', Util::sanitizeHTML($_COOKIE['guestUser'])); @@ -188,11 +193,11 @@ class TokenManager { try { return [ - $this->wopiParser->getUrlSrc($file->getMimeType())['urlsrc'], + $this->wopiParser->getUrlSrc($file->getMimeType())['urlsrc'], // url src might not be found ehre $wopi->getToken(), $wopi ]; - } catch (\Exception $e){ + } catch (\Exception $e) { throw $e; } } @@ -208,10 +213,18 @@ class TokenManager { return $wopi; } - public function getTokenForTemplate(File $file, $userId, $templateDestination, $direct = false) { + public function getTokenForTemplate(File $templateFile, $userId, $targetFileId, $direct = false) { $owneruid = $userId; $editoruid = $userId; - $updatable = $file->isUpdateable(); + $rootFolder = $this->rootFolder->getUserFolder($editoruid); + /** @var File $targetFile */ + $targetFile = $rootFolder->getById($targetFileId); + $targetFile = $targetFile[0] ?? null; + if (!$targetFile) { + // TODO: Exception + return null; + } + $updatable = $targetFile->isUpdateable(); // Check if the editor (user who is accessing) is in editable group // UserCanWrite only if // 1. No edit groups are set or @@ -231,11 +244,16 @@ class TokenManager { $serverHost = $this->urlGenerator->getAbsoluteURL('/'); - $wopi = $this->wopiMapper->generateFileToken($file->getId(), $owneruid, $editoruid, 0, (int)$updatable, $serverHost, null, $templateDestination, $direct); + if ($this->capabilitiesService->hasTemplateSource()) { + $wopi = $this->wopiMapper->generateFileToken($targetFile->getId(), $owneruid, $editoruid, 0, (int)$updatable, $serverHost, null, 0, false, false, false, $templateFile->getId()); + } else { + // Legacy way of creating new documents from a template + $wopi = $this->wopiMapper->generateFileToken($templateFile->getId(), $owneruid, $editoruid, 0, (int)$updatable, $serverHost, null, $targetFile->getId(), $direct); + } return [ - $this->wopiParser->getUrlSrc($file->getMimeType())['urlsrc'], - $wopi->getToken(), + $this->wopiParser->getUrlSrc($templateFile->getMimeType())['urlsrc'], + $wopi ]; } |