diff options
author | Roeland Jago Douma <rullzer@users.noreply.github.com> | 2018-12-20 09:58:55 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-20 09:58:55 +0300 |
commit | c7becd4ee8cd0e3cdd742ca7fc54ad164ec65c70 (patch) | |
tree | 68462abedf9dbab617dd461affd843a29ba9a395 /lib | |
parent | f2b8d73472b6ef936eaaba3f93f0c987b7c21da9 (diff) | |
parent | 2beab3e864ef46aadf2a5e4e910559b09787dec7 (diff) |
Merge pull request #263 from nextcloud/templates-manager
Template management
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AppInfo/Application.php | 20 | ||||
-rw-r--r-- | lib/Controller/DirectViewController.php | 46 | ||||
-rw-r--r-- | lib/Controller/DocumentController.php | 55 | ||||
-rw-r--r-- | lib/Controller/OCSController.php | 96 | ||||
-rw-r--r-- | lib/Controller/SettingsController.php | 43 | ||||
-rw-r--r-- | lib/Controller/TemplatesController.php | 216 | ||||
-rw-r--r-- | lib/Controller/WopiController.php | 137 | ||||
-rw-r--r-- | lib/Db/Direct.php | 6 | ||||
-rw-r--r-- | lib/Db/DirectMapper.php | 4 | ||||
-rw-r--r-- | lib/Db/Wopi.php | 10 | ||||
-rw-r--r-- | lib/Db/WopiMapper.php | 6 | ||||
-rw-r--r-- | lib/Settings/Admin.php | 38 | ||||
-rw-r--r-- | lib/Settings/Personal.php | 78 | ||||
-rw-r--r-- | lib/TemplateManager.php | 456 | ||||
-rw-r--r-- | lib/TokenManager.php | 32 |
15 files changed, 1183 insertions, 60 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 83ba668d..4d5d49c3 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -2,6 +2,9 @@ /** * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * + * @author Lukas Reschke <lukas@statuscode.ch> + * @author Roeland Jago Douma <roeland@famdouma.nl> + * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify @@ -15,27 +18,26 @@ * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OCA\Richdocuments\AppInfo; -use OC\AppFramework\Utility\TimeFactory; +use OC\Files\Type\Detection; use OCA\Richdocuments\Capabilities; use OCA\Richdocuments\Preview\MSExcel; use OCA\Richdocuments\Preview\MSWord; use OCA\Richdocuments\Preview\OOXML; use OCA\Richdocuments\Preview\OpenDocument; use OCP\AppFramework\App; -use OCP\AppFramework\IAppContainer; use OCP\IPreview; -class Application extends App { +class Application extends App { const APPNAME = 'richdocuments'; - public function __construct (array $urlParams = array()) { + public function __construct(array $urlParams = array()) { parent::__construct(self::APPNAME, $urlParams); $this->getContainer()->registerCapability(Capabilities::class); @@ -44,6 +46,14 @@ class Application extends App { public function registerProvider() { $container = $this->getContainer(); + // Register mimetypes + /** @var Detection $detector */ + $detector = $container->query(\OCP\Files\IMimeTypeDetector::class); + $detector->getAllMappings(); + $detector->registerType('ott','application/vnd.oasis.opendocument.text-template'); + $detector->registerType('ots', 'application/vnd.oasis.opendocument.spreadsheet-template'); + $detector->registerType('otp', 'application/vnd.oasis.opendocument.presentation-template'); + /** @var IPreview $previewManager */ $previewManager = $container->query(IPreview::class); diff --git a/lib/Controller/DirectViewController.php b/lib/Controller/DirectViewController.php index 2ba8d64f..9ce2d2d3 100644 --- a/lib/Controller/DirectViewController.php +++ b/lib/Controller/DirectViewController.php @@ -24,6 +24,7 @@ namespace OCA\Richdocuments\Controller; use OCA\Richdocuments\AppConfig; use OCA\Richdocuments\Db\DirectMapper; +use OCA\Richdocuments\TemplateManager; use OCA\Richdocuments\TokenManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Db\DoesNotExistException; @@ -52,13 +53,17 @@ class DirectViewController extends Controller { /** @var AppConfig */ private $appConfig; + /** @var TemplateManager */ + private $templateManager; + public function __construct($appName, IRequest $request, IRootFolder $rootFolder, TokenManager $tokenManager, DirectMapper $directMapper, IConfig $config, - AppConfig $appConfig) { + AppConfig $appConfig, + TemplateManager $templateManager) { parent::__construct($appName, $request); $this->rootFolder = $rootFolder; @@ -66,6 +71,7 @@ class DirectViewController extends Controller { $this->directMapper = $directMapper; $this->config = $config; $this->appConfig = $appConfig; + $this->templateManager = $templateManager; } /** @@ -86,20 +92,44 @@ class DirectViewController extends Controller { // Delete the token. They are for 1 time use only $this->directMapper->delete($direct); - try { - $folder = $this->rootFolder->getUserFolder($direct->getUid()); - $item = $folder->getById($direct->getFileid())[0]; - if(!($item instanceof Node)) { - throw new \Exception(); + $folder = $this->rootFolder->getUserFolder($direct->getUid()); + if ($this->templateManager->isTemplate($direct->getFileid())) { + $item = $this->templateManager->get($direct->getFileid()); + if ($direct->getTemplateDestination() === 0 || $direct->getTemplateDestination() === null) { + return new JSONResponse([], Http::STATUS_BAD_REQUEST); + } + + try { + list($urlSrc, $token) = $this->tokenManager->getTokenForTemplate($item, $direct->getUid(), $direct->getTemplateDestination()); + } catch (\Exception $e) { + return new JSONResponse([], Http::STATUS_BAD_REQUEST); + } + + $relativePath = '/new.odt'; + + } else { + try { + $item = $folder->getById($direct->getFileid())[0]; + if(!($item instanceof Node)) { + throw new \Exception(); + } + + list($urlSrc, $token) = $this->tokenManager->getToken($item->getId(), null, $direct->getUid()); + } catch (\Exception $e) { + return new JSONResponse([], Http::STATUS_BAD_REQUEST); } - list($urlSrc, $token) = $this->tokenManager->getToken($item->getId(), null, $direct->getUid()); + + $relativePath = $folder->getRelativePath($item->getPath()); + } + + try { $params = [ 'permissions' => $item->getPermissions(), 'title' => $item->getName(), 'fileId' => $item->getId() . '_' . $this->config->getSystemValue('instanceid'), 'token' => $token, 'urlsrc' => $urlSrc, - 'path' => $folder->getRelativePath($item->getPath()), + 'path' => $relativePath, 'instanceId' => $this->config->getSystemValue('instanceid'), 'canonical_webroot' => $this->appConfig->getAppValue('canonical_webroot'), 'direct' => true, diff --git a/lib/Controller/DocumentController.php b/lib/Controller/DocumentController.php index 7219114a..a11399d3 100644 --- a/lib/Controller/DocumentController.php +++ b/lib/Controller/DocumentController.php @@ -52,9 +52,12 @@ class DocumentController extends Controller { private $session; /** @var IRootFolder */ private $rootFolder; + /** @var \OCA\Richdocuments\TemplateManager */ + private $templateManager; const ODT_TEMPLATE_PATH = '/assets/odttemplate.odt'; + /** * @param string $appName * @param IRequest $request @@ -78,7 +81,8 @@ class DocumentController extends Controller { IRootFolder $rootFolder, ISession $session, $UserId, - ILogger $logger) { + ILogger $logger, + \OCA\Richdocuments\TemplateManager $templateManager) { parent::__construct($appName, $request); $this->uid = $UserId; $this->l10n = $l10n; @@ -89,6 +93,7 @@ class DocumentController extends Controller { $this->rootFolder = $rootFolder; $this->session = $session; $this->logger = $logger; + $this->templateManager = $templateManager; } /** @@ -225,6 +230,54 @@ class DocumentController extends Controller { } /** + * @NoAdminRequired + * + * @param int $templateId + * @param string $fileName + * @param string $dir + * @return TemplateResponse + */ + public function template($templateId, $fileName, $dir) { + if (!$this->templateManager->isTemplate($templateId)) { + return new TemplateResponse('core', '403', [], 'guest'); + } + + $userFolder = $this->rootFolder->getUserFolder($this->uid); + try { + $folder = $userFolder->get($dir); + } catch (NotFoundException $e) { + return new TemplateResponse('core', '403', [], 'guest'); + } + + if ((!$folder instanceof Folder)) { + return new TemplateResponse('core', '403', [], 'guest'); + } + + $file = $folder->newFile($fileName); + + $template = $this->templateManager->get($templateId); + list($urlSrc, $token) = $this->tokenManager->getTokenForTemplate($template, $this->uid, $file->getId()); + + $params = [ + 'permissions' => $template->getPermissions(), + 'title' => $template->getName(), + 'fileId' => $template->getId() . '_' . $this->settings->getSystemValue('instanceid'), + 'token' => $token, + 'urlsrc' => $urlSrc, + 'path' => $userFolder->getRelativePath($file->getPath()), + 'instanceId' => $this->settings->getSystemValue('instanceid'), + 'canonical_webroot' => $this->appConfig->getAppValue('canonical_webroot'), + ]; + + $response = new TemplateResponse('richdocuments', 'documents', $params, 'empty'); + $policy = new ContentSecurityPolicy(); + $policy->addAllowedFrameDomain($this->domainOnly($this->appConfig->getAppValue('wopi_url'))); + $policy->allowInlineScript(true); + $response->setContentSecurityPolicy($policy); + return $response; + } + + /** * @PublicPage * * @param string $shareToken diff --git a/lib/Controller/OCSController.php b/lib/Controller/OCSController.php index 14651409..cbb93c73 100644 --- a/lib/Controller/OCSController.php +++ b/lib/Controller/OCSController.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> * * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author John Molakvoæ <skjnldsv@protonmail.com> * * @license GNU AGPL version 3 or any later version * @@ -23,9 +24,11 @@ namespace OCA\Richdocuments\Controller; use OCA\Richdocuments\Db\DirectMapper; +use OCA\Richdocuments\TemplateManager; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSNotFoundException; +use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; @@ -33,6 +36,7 @@ use OCP\IRequest; use OCP\IURLGenerator; class OCSController extends \OCP\AppFramework\OCSController { + /** @var IRootFolder */ private $rootFolder; @@ -45,32 +49,52 @@ class OCSController extends \OCP\AppFramework\OCSController { /** @var IURLGenerator */ private $urlGenerator; - public function __construct($appName, - IRequest $request, - IRootFolder $rootFolder, - $userId, - DirectMapper $directMapper, - IURLGenerator $urlGenerator) { + /** @var TemplateManager */ + private $manager; + + /** + * OCS controller + * + * @param string $appName + * @param IRequest $request + * @param IRootFolder $rootFolder + * @param string $userId + * @param DirectMapper $directMapper + * @param IURLGenerator $urlGenerator + * @param TemplateManager $manager + */ + public function __construct(string $appName, + IRequest $request, + IRootFolder $rootFolder, + $userId, + DirectMapper $directMapper, + IURLGenerator $urlGenerator, + TemplateManager $manager) { parent::__construct($appName, $request); - $this->rootFolder = $rootFolder; - $this->userId = $userId; + $this->rootFolder = $rootFolder; + $this->userId = $userId; $this->directMapper = $directMapper; $this->urlGenerator = $urlGenerator; + $this->manager = $manager; } /** * @NoAdminRequired * + * Init an editing session + * * @param int $fileId + * @return DataResponse + * @throws OCSNotFoundException|OCSBadRequestException */ public function create($fileId) { try { $userFolder = $this->rootFolder->getUserFolder($this->userId); - $nodes = $userFolder->getById($fileId); + $nodes = $userFolder->getById($fileId); if ($nodes === []) { - throw new NotFoundException(); + throw new OCSNotFoundException(); } $node = $nodes[0]; @@ -79,7 +103,7 @@ class OCSController extends \OCP\AppFramework\OCSController { } //TODO check if we can even edit this file with collabora - + $direct = $this->directMapper->newDirect($this->userId, $fileId); return new DataResponse([ @@ -91,4 +115,54 @@ class OCSController extends \OCP\AppFramework\OCSController { throw new OCSNotFoundException(); } } + + /** + * @NoAdminRequired + * + * @param string $type The template type + * @return DataResponse + * @throws OCSBadRequestException + */ + public function getTemplates($type) { + if (array_key_exists($type, TemplateManager::$tplTypes)) { + $templates = $this->manager->getAllFormatted($type); + return new DataResponse($templates); + } + throw new OCSBadRequestException('Wrong type'); + } + + /** + * @NoAdminRequired + * + * @param string $path Where to create the document + * @param int $template The template id + */ + public function createFromTemplate($path, $template) { + if ($path === null || $template === null) { + throw new OCSBadRequestException('path and template must be set'); + } + + if (!$this->manager->isTemplate($template)) { + throw new OCSBadRequestException('Invalid template provided'); + } + + $info = pathinfo($path); + + $userFolder = $this->rootFolder->getUserFolder($this->userId); + $folder = $userFolder->get($info['dirname']); + $name = $folder->getNonExistingName($info['basename']); + $file = $folder->newFile($name); + + try { + $direct = $this->directMapper->newDirect($this->userId, $template, $file->getId()); + + return new DataResponse([ + 'url' => $this->urlGenerator->linkToRouteAbsolute('richdocuments.directView.show', [ + 'token' => $direct->getToken() + ]) + ]); + } catch (NotFoundException $e) { + throw new OCSNotFoundException(); + } + } } diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 2d7222f3..122cf116 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -17,31 +17,43 @@ use OCP\AppFramework\Http\JSONResponse; use \OCP\IRequest; use \OCP\IL10N; use OCA\Richdocuments\AppConfig; +use OCP\IConfig; +use OCP\PreConditionNotMetException; class SettingsController extends Controller{ /** @var IL10N */ private $l10n; /** @var AppConfig */ private $appConfig; + /** @var IConfig */ + private $config; /** @var DiscoveryManager */ private $discoveryManager; + /** @var string */ + private $userId; /** * @param string $appName * @param IRequest $request * @param IL10N $l10n * @param AppConfig $appConfig + * @param IConfig $config * @param DiscoveryManager $discoveryManager + * @param string $userId */ public function __construct($appName, IRequest $request, IL10N $l10n, AppConfig $appConfig, - DiscoveryManager $discoveryManager) { + IConfig $config, + DiscoveryManager $discoveryManager, + $userId) { parent::__construct($appName, $request); $this->l10n = $l10n; $this->appConfig = $appConfig; + $this->config = $config; $this->discoveryManager = $discoveryManager; + $this->userId = $userId; } /** @@ -113,4 +125,33 @@ class SettingsController extends Controller{ return new JSONResponse($response); } + + /** + * @NoAdminRequired + * + * @param $key + * @param $value + * @return JSONResponse + */ + public function setPersonalSettings($templateFolder) { + $message = $this->l10n->t('Saved'); + $status = 'success'; + + if ($templateFolder !== null){ + try { + $this->config->setUserValue($this->userId, 'richdocuments', 'templateFolder', $templateFolder); + } catch (PreConditionNotMetException $e) { + $message = $this->l10n->t('Error when saving'); + $status = 'error'; + } + } + + $response = [ + 'status' => $status, + 'data' => ['message' => $message] + ]; + + return new JSONResponse($response); + + } } diff --git a/lib/Controller/TemplatesController.php b/lib/Controller/TemplatesController.php new file mode 100644 index 00000000..548c3528 --- /dev/null +++ b/lib/Controller/TemplatesController.php @@ -0,0 +1,216 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Richdocuments\Controller; + +use OCA\Richdocuments\TemplateManager; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\NotFoundResponse; +use OCP\Files\Node; +use OCP\Files\NotFoundException; +use OCP\Files\SimpleFS\ISimpleFile; +use OCP\IL10N; +use OCP\IPreview; +use OCP\IRequest; +use OC\Files\Filesystem; + +class TemplatesController extends Controller { + /** @var IL10N */ + private $l10n; + + /** @var TemplateManager */ + private $manager; + + /** @var IPreview */ + private $preview; + + /** @var int Max template size */ + private $maxSize = 20 * 1024 * 1024; + + /** + * Templates controller + * + * @param string $appName + * @param IRequest $request + * @param L10N $l10n + * @param TemplateManager $manager + * @param IPreview $preview + */ + public function __construct($appName, + IRequest $request, + IL10N $l10n, + TemplateManager $manager, + IPreview $preview) { + parent::__construct($appName, $request); + + $this->appName = $appName; + $this->request = $request; + $this->l10n = $l10n; + $this->manager = $manager; + $this->preview = $preview; + } + + /** + * @NoAdminRequired + * @NoCSRFRequired + * + * Get preview for a specific template + * + * @param int $fileId The template id + * @param int $x + * @param int $y + * @param bool $a + * @param bool $forceIcon + * @param string $mode + * @return DataResponse + * @throws NotFoundResponse + */ + public function getPreview($fileId, + $x = 150, + $y = 150, + $a = false, + $forceIcon = true, + $mode = 'fill') { + + if ($fileId === '' || $x === 0 || $y === 0) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + + try { + $template = $this->manager->get($fileId); + } catch (NotFoundException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + if ($template instanceof ISimpleFile) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + return $this->fetchPreview($template, $x, $y, $a, $forceIcon, $mode); + } + + /** + * Add a global template + * + * @return JSONResponse + */ + public function add() { + $files = $this->request->getUploadedFile('files'); + + if (!is_null($files)) { + if ($files['error'][0] === 0 + && is_uploaded_file($files['tmp_name'][0]) + && !Filesystem::isFileBlacklisted($files['tmp_name'][0])) { + + // TODO: ensure the size limit is decent for preview + if ($files['size'][0] > $this->maxSize) { + return new JSONResponse( + ['data' => ['message' => $this->l10n->t('File is too big')]], + Http::STATUS_BAD_REQUEST + ); + } + + $templateName = $files['name'][0]; + $templateFile = file_get_contents($files['tmp_name'][0]); + + unlink($files['tmp_name'][0]); + + $template = $this->manager->add($templateName, $templateFile); + + return new JSONResponse( + ['data' => $template], + Http::STATUS_CREATED + ); + } + } + + return new JSONResponse( + ['data' => ['message' => $this->l10n->t('Invalid file provided')]], + Http::STATUS_BAD_REQUEST + ); + } + + /** + * Delete a global template + * + * @param int $fileId + * @return JSONResponse + */ + public function delete($fileId) { + try { + $this->manager->delete($fileId); + + return new JSONResponse( + ['data' => ['status' => 'success']], + Http::STATUS_NO_CONTENT + ); + } catch (NotFoundException $e) { + return new JSONResponse( + ['data' => ['message' => $this->l10n->t('Template not found')]], + Http::STATUS_NOT_FOUND + ); + } + } + + /** + * @param Node $node + * @param int $x + * @param int $y + * @param bool $a + * @param bool $forceIcon + * @param string $mode + * @return DataResponse|FileDisplayResponse + */ + private function fetchPreview( + Node $node, + $x, + $y, + $a = false, + $forceIcon = true, + string $mode): Http\Response { + + if (!($node instanceof Node) || (!$forceIcon && !$this->preview->isAvailable($node))) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + if (!$node->isReadable()) { + return new DataResponse([], Http::STATUS_FORBIDDEN); + } + + try { + $f = $this->preview->getPreview($node, $x, $y, !$a, $mode); + $response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]); + $response->cacheFor(3600 * 24); + + return $response; + } catch (NotFoundException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } catch (\InvalidArgumentException $e) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + } +} diff --git a/lib/Controller/WopiController.php b/lib/Controller/WopiController.php index 13bf5655..9ef12282 100644 --- a/lib/Controller/WopiController.php +++ b/lib/Controller/WopiController.php @@ -23,6 +23,7 @@ namespace OCA\Richdocuments\Controller; use OC\Files\View; use OCA\Richdocuments\Db\WopiMapper; +use OCA\Richdocuments\TemplateManager; use OCA\Richdocuments\TokenManager; use OCA\Richdocuments\Helper; use OCP\AppFramework\Controller; @@ -56,13 +57,14 @@ class WopiController extends Controller { private $logger; /** @var IUserSession */ private $userSession; + /** @var TemplateManager */ + private $templateManager; // Signifies LOOL that document has been changed externally in this storage const LOOL_STATUS_DOC_CHANGED = 1010; /** * @param string $appName - * @param string $UserId * @param IRequest $request * @param IRootFolder $rootFolder * @param IURLGenerator $urlGenerator @@ -71,9 +73,10 @@ class WopiController extends Controller { * @param IUserManager $userManager * @param WopiMapper $wopiMapper * @param ILogger $logger + * @param IUserSession $userSession + * @param TemplateManager $templateManager */ public function __construct($appName, - $UserId, IRequest $request, IRootFolder $rootFolder, IURLGenerator $urlGenerator, @@ -82,7 +85,8 @@ class WopiController extends Controller { IUserManager $userManager, WopiMapper $wopiMapper, ILogger $logger, - IUserSession $userSession) { + IUserSession $userSession, + TemplateManager $templateManager) { parent::__construct($appName, $request); $this->rootFolder = $rootFolder; $this->urlGenerator = $urlGenerator; @@ -92,6 +96,7 @@ class WopiController extends Controller { $this->wopiMapper = $wopiMapper; $this->logger = $logger; $this->userSession = $userSession; + $this->templateManager = $templateManager; } /** @@ -102,26 +107,32 @@ class WopiController extends Controller { * @PublicPage * * @param string $fileId + * @param string $access_token * @return JSONResponse + * @throws \OCP\Files\InvalidPathException + * @throws \OCP\Files\NotFoundException */ - public function checkFileInfo($fileId) { - $token = $this->request->getParam('access_token'); - + public function checkFileInfo($fileId, $access_token) { list($fileId, , $version) = Helper::parseFileId($fileId); try { - $wopi = $this->wopiMapper->getPathForToken($token); + $wopi = $this->wopiMapper->getPathForToken($access_token); } catch (DoesNotExistException $e) { return new JSONResponse([], Http::STATUS_FORBIDDEN); } - // Login the user to see his mount locations - try { - /** @var File $file */ - $userFolder = $this->rootFolder->getUserFolder($wopi->getOwnerUid()); - $file = $userFolder->getById($fileId)[0]; - } catch (\Exception $e) { - return new JSONResponse([], Http::STATUS_FORBIDDEN); + if ($wopi->isTemplateToken()) { + $this->templateManager->setUserId($wopi->getOwnerUid()); + $file = $this->templateManager->get($wopi->getFileid()); + } else { + // Login the user to see his mount locations + try { + /** @var File $file */ + $userFolder = $this->rootFolder->getUserFolder($wopi->getOwnerUid()); + $file = $userFolder->getById($fileId)[0]; + } catch (\Exception $e) { + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } } if(!($file instanceof File)) { @@ -145,12 +156,15 @@ class WopiController extends Controller { 'EnableShare' => true, ]; - $serverVersion = $this->config->getSystemValue('version'); - if (version_compare($serverVersion, '13', '>=')) { - $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]); - } + if ($wopi->isTemplateToken()) { + $userFolder = $this->rootFolder->getUserFolder($wopi->getOwnerUid()); + $file = $userFolder->getById($wopi->getTemplateDestination())[0]; + $response['TemplateSaveAs'] = $file->getName(); + } + + $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]); } return new JSONResponse($response); @@ -177,6 +191,16 @@ class WopiController extends Controller { return new JSONResponse([], Http::STATUS_FORBIDDEN); } + // Template is just returned as there is no version logic + if ($wopi->isTemplateToken()) { + $this->templateManager->setUserId($wopi->getOwnerUid()); + $file = $this->templateManager->get($wopi->getFileid()); + $response = new StreamResponse($file->fopen('rb')); + $response->addHeader('Content-Disposition', 'attachment'); + $response->addHeader('Content-Type', 'application/octet-stream'); + return $response; + } + try { /** @var File $file */ $userFolder = $this->rootFolder->getUserFolder($wopi->getOwnerUid()); @@ -329,6 +353,77 @@ class WopiController extends Controller { */ public function putRelativeFile($fileId, $access_token) { - return $this->putFile($fileId, $access_token); + list($fileId, ,) = Helper::parseFileId($fileId); + $wopi = $this->wopiMapper->getPathForToken($access_token); + + if (!$wopi->getCanwrite()) { + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + + // Unless the editor is empty (public link) we modify the files as the current editor + $editor = $wopi->getEditorUid(); + if ($editor === null) { + $editor = $wopi->getOwnerUid(); + } + + try { + // the new file needs to be installed in the current user dir + $userFolder = $this->rootFolder->getUserFolder($editor); + + if ($wopi->isTemplateToken()) { + $this->templateManager->setUserId($wopi->getOwnerUid()); + $file = $userFolder->getById($wopi->getTemplateDestination())[0]; + } else { + $file = $userFolder->getById($fileId)[0]; + + $suggested = $this->request->getHeader('X-WOPI-SuggestedTarget'); + $suggested = iconv('utf-7', 'utf-8', $suggested); + + if ($suggested[0] === '.') { + $path = dirname($file->getPath()) . '/New File' . $suggested; + } else if ($suggested[0] !== '/') { + $path = dirname($file->getPath()) . '/' . $suggested; + } else { + $path = $userFolder->getPath() . $suggested; + } + + if ($path === '') { + return new JSONResponse([ + 'status' => 'error', + 'message' => 'Cannot create the file' + ]); + } + + // create the folder first + if (!$this->rootFolder->nodeExists(dirname($path))) { + $this->rootFolder->newFolder(dirname($path)); + } + + // create a unique new file + $path = $this->rootFolder->getNonExistingName($path); + $file = $this->rootFolder->newFile($path); + } + + $content = fopen('php://input', 'rb'); + + // Set the user to register the change under his name + $editor = $this->userManager->get($wopi->getEditorUid()); + if (!is_null($editor)) { + $this->userSession->setUser($editor); + } + + $file->putContent($content); + + // generate a token for the new file (the user still has to be + // logged in) + list(, $wopiToken) = $this->tokenManager->getToken($file->getId(), null, $wopi->getEditorUid()); + + $wopi = 'index.php/apps/richdocuments/wopi/files/' . $file->getId() . '_' . $this->config->getSystemValue('instanceid') . '?access_token=' . $wopiToken; + $url = $this->urlGenerator->getAbsoluteURL($wopi); + + return new JSONResponse([ 'Name' => $file->getName(), 'Url' => $url ], Http::STATUS_OK); + } catch (\Exception $e) { + return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); + } } } diff --git a/lib/Db/Direct.php b/lib/Db/Direct.php index 26c29672..437df370 100644 --- a/lib/Db/Direct.php +++ b/lib/Db/Direct.php @@ -34,6 +34,8 @@ use OCP\AppFramework\Db\Entity; * @method int getFileid() * @method void setTimestamp(int $timestamp) * @method int getTimestamp() + * @method void setTemplateDestination(int $fileId) + * @method int getTemplateDestination() */ class Direct extends Entity { /** @var string */ @@ -48,10 +50,14 @@ class Direct extends Entity { /** @var int */ protected $timestamp; + /** @var int */ + protected $templateDestination; + public function __construct() { $this->addType('token', 'string'); $this->addType('uid', 'string'); $this->addType('fileid', 'int'); $this->addType('timestamp', 'int'); + $this->addType('template_destination', 'int'); } } diff --git a/lib/Db/DirectMapper.php b/lib/Db/DirectMapper.php index dd414e2b..e3fa8841 100644 --- a/lib/Db/DirectMapper.php +++ b/lib/Db/DirectMapper.php @@ -53,14 +53,16 @@ class DirectMapper extends Mapper { /** * @param string $uid * @param int $fileid + * @param int $destination * @return Direct */ - public function newDirect($uid, $fileid) { + public function newDirect($uid, $fileid, $destination = null) { $direct = new Direct(); $direct->setUid($uid); $direct->setFileid($fileid); $direct->setToken($this->random->generate(64, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER)); $direct->setTimestamp($this->timeFactory->getTime()); + $direct->setTemplateDestination($destination); $direct = $this->insert($direct); return $direct; diff --git a/lib/Db/Wopi.php b/lib/Db/Wopi.php index 90f29f96..941e241b 100644 --- a/lib/Db/Wopi.php +++ b/lib/Db/Wopi.php @@ -47,6 +47,8 @@ use OCP\AppFramework\Db\Entity; * @method int getExpiry() * @method void setGuestDisplayname(string $token) * @method string getGuestDisplayname() + * @method void setTemplateDestination(int $fileId) + * @method int getTemplateDestination() */ class Wopi extends Entity { /** @var string */ @@ -76,6 +78,9 @@ class Wopi extends Entity { /** @var string */ protected $guestDisplayname; + /** @var int */ + protected $templateDestination; + public function __construct() { $this->addType('owner_uid', 'string'); $this->addType('editor_uid', 'string'); @@ -86,6 +91,11 @@ class Wopi extends Entity { $this->addType('token', 'string'); $this->addType('expiry', 'int'); $this->addType('guest_displayname', 'string'); + $this->addType('templateDestination', 'int'); + } + + public function isTemplateToken() { + return $this->getTemplateDestination() !== 0 && $this->getTemplateDestination() !== null; } } diff --git a/lib/Db/WopiMapper.php b/lib/Db/WopiMapper.php index a9c4f18b..01dfded3 100644 --- a/lib/Db/WopiMapper.php +++ b/lib/Db/WopiMapper.php @@ -56,14 +56,15 @@ class WopiMapper extends Mapper { /** * @param int $fileId * @param string $owner - * @param string$editor + * @param string $editor * @param int $version * @param bool $updatable * @param string $serverHost * @param string $guestDisplayname + * @param int $templateDestination * @return Wopi */ - public function generateFileToken($fileId, $owner, $editor, $version, $updatable, $serverHost, $guestDisplayname) { + public function generateFileToken($fileId, $owner, $editor, $version, $updatable, $serverHost, $guestDisplayname, $templateDestination = 0) { $token = $this->random->generate(32, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS); $wopi = Wopi::fromParams([ @@ -76,6 +77,7 @@ class WopiMapper extends Mapper { 'token' => $token, 'expiry' => $this->timeFactory->getTime() + self::TOKEN_LIFETIME_SECONDS, 'guestDisplayname' => $guestDisplayname, + 'templateDestination' => $templateDestination, ]); /** @var Wopi $wopi */ diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index 0bad4f7c..00a5e8c1 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -23,20 +23,36 @@ namespace OCA\Richdocuments\Settings; +use OCA\Richdocuments\Capabilities; +use OCA\Richdocuments\TemplateManager; use OCP\AppFramework\Http\TemplateResponse; -use OCP\Defaults; use OCP\IConfig; -use OCP\IL10N; use OCP\Settings\ISettings; class Admin implements ISettings { + /** @var IConfig */ private $config; + + /** @var TemplateManager */ + private $manager; + + /** @var array */ + private $capabilities; + /** + * Admin template settings + * * @param IConfig $config + * @param TemplateManager $manager + * @param Capabilities $capabilities */ - public function __construct(IConfig $config) { - $this->config = $config; + public function __construct(IConfig $config, + TemplateManager $manager, + Capabilities $capabilities) { + $this->config = $config; + $this->manager = $manager; + $this->capabilities = $capabilities->getCapabilities()['richdocuments']; } /** * @return TemplateResponse @@ -46,12 +62,14 @@ class Admin implements ISettings { 'richdocuments', 'admin', [ - 'wopi_url' => $this->config->getAppValue('richdocuments', 'wopi_url'), - 'edit_groups' => $this->config->getAppValue('richdocuments', 'edit_groups'), - 'use_groups' => $this->config->getAppValue('richdocuments', 'use_groups'), - 'doc_format' => $this->config->getAppValue('richdocuments', 'doc_format'), - 'external_apps' => $this->config->getAppValue('richdocuments', 'external_apps'), - 'canonical_webroot' => $this->config->getAppValue('richdocuments', 'canonical_webroot'), + 'wopi_url' => $this->config->getAppValue('richdocuments', 'wopi_url'), + 'edit_groups' => $this->config->getAppValue('richdocuments', 'edit_groups'), + 'use_groups' => $this->config->getAppValue('richdocuments', 'use_groups'), + 'doc_format' => $this->config->getAppValue('richdocuments', 'doc_format'), + 'external_apps' => $this->config->getAppValue('richdocuments', 'external_apps'), + 'canonical_webroot' => $this->config->getAppValue('richdocuments', 'canonical_webroot'), + 'templates' => $this->manager->getSystemFormatted(), + 'templatesAvailable' => array_key_exists('templates', $this->capabilities) && $this->capabilities['templates'] ], 'blank' ); diff --git a/lib/Settings/Personal.php b/lib/Settings/Personal.php new file mode 100644 index 00000000..3aa80803 --- /dev/null +++ b/lib/Settings/Personal.php @@ -0,0 +1,78 @@ +<?php +/** + * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Richdocuments\Settings; + +use OCA\Richdocuments\Capabilities; +use OCA\Richdocuments\TemplateManager; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; +use OCP\Settings\ISettings; + +class Personal implements ISettings { + + private $config; + private $userId; + private $capabilities; + + public function __construct(IConfig $config, Capabilities $capabilities, $userId) { + $this->config = $config; + $this->capabilities = $capabilities->getCapabilities()['richdocuments']; + $this->userId = $userId; + } + + /** + * @return TemplateResponse + */ + public function getForm() { + if (array_key_exists('templates', $this->capabilities) && $this->capabilities['templates'] === true) { + return new TemplateResponse( + 'richdocuments', + 'personal', + [ + 'templateFolder' => $this->config->getUserValue($this->userId, 'richdocuments', 'templateFolder', '') + ], + 'blank' + ); + } + } + /** + * @return string the section ID, e.g. 'sharing' + */ + public function getSection() { + // Only show the personal section if templates are available + if (array_key_exists('templates', $this->capabilities) && $this->capabilities['templates'] === true) { + return 'richdocuments'; + } + } + /** + * @return int whether the form should be rather on the top or bottom of + * the admin section. The forms are arranged in ascending order of the + * priority values. It is required to return a value between 0 and 100. + * + * keep the server setting at the top, right after "server settings" + */ + public function getPriority() { + return 0; + } +} diff --git a/lib/TemplateManager.php b/lib/TemplateManager.php new file mode 100644 index 00000000..19a7d4cb --- /dev/null +++ b/lib/TemplateManager.php @@ -0,0 +1,456 @@ +<?php +declare (strict_types = 1); +/** + * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Richdocuments; + +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Node; +use OCP\Files\NotFoundException; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IPreview; +use OCP\IURLGenerator; +use OC\Files\AppData\Factory; + +class TemplateManager { + + /** @var string */ + protected $appName; + + /** @var string */ + protected $userId; + + /** @var IConfig */ + private $config; + + /** @var IURLGenerator */ + private $urlGenerator; + + /** @var IRootFolder */ + private $rootFolder; + + /** @var IL10N */ + private $l; + + /** Accepted templates mime types */ + const MIMES_DOCUMENTS = [ + 'application/vnd.oasis.opendocument.text-template' + ]; + const MIMES_SHEETS = [ + 'application/vnd.oasis.opendocument.spreadsheet-template' + ]; + const MIMES_PRESENTATIONS = [ + 'application/vnd.oasis.opendocument.presentation-template' + ]; + + /** @var array Template mime types match */ + static public $tplTypes = [ + 'document' => self::MIMES_DOCUMENTS, + 'spreadsheet' => self::MIMES_SHEETS, + 'presentation' => self::MIMES_PRESENTATIONS + ]; + + const EMPTY_TEMPLATE_ID_TYPE = [ + -1 => 'document', + -2 => 'spreadsheet', + -3 => 'presentation', + ]; + const EMPTY_TEMPLATE_TYPE_ID = [ + 'document' => -1, + 'spreadsheet' => -2, + 'presentation' => -3, + ]; + const TYPE_EXTENTION = [ + 'document' => 'odt', + 'spreadsheet' => 'ods', + 'presentation' => 'odp', + ]; + + + /** + * Template manager + * + * @param string $appName + * @param string $userId + * @param IConfig $config + * @param Factory $appDataFactory + * @param IURLGenerator $urlGenerator + * @param IRootFolder $rootFolder + * @param IL10N $l + * @throws \OCP\Files\NotPermittedException + */ + public function __construct($appName, + $userId, + IConfig $config, + Factory $appDataFactory, + IURLGenerator $urlGenerator, + IRootFolder $rootFolder, + IL10N $l) { + $this->appName = $appName; + $this->userId = $userId; + $this->config = $config; + $this->rootFolder = $rootFolder; + $this->urlGenerator = $urlGenerator; + + /* + * Init the appdata folder + * We need an actual folder for the fileid and previews. + * TODO: Fix this at some point + */ + $appData = $appDataFactory->get($appName); + try { + $appData->getFolder('templates'); + } catch (NotFoundException $e) { + $appData->newFolder('templates'); + } + try { + $appData->getFolder('empty_templates'); + } catch (NotFoundException $e) { + $appData->newFolder('empty_templates'); + } + + $this->l = $l; + } + + public function setUserId($userId) { + $this->userId = $userId; + } + + /** + * Get template ISimpleFile|Node + * + * @param int $fileId + * @return File + */ + public function get($fileId) { + // is this a global template ? + $files = $this->getEmptyTemplateDir()->getDirectoryListing(); + + foreach ($files as $file) { + if ($file->getId() === $fileId) { + return $file; + } + } + + // is this a global template ? + $files = $this->getSystemTemplateDir()->getDirectoryListing(); + + foreach ($files as $file) { + if ($file->getId() === $fileId) { + return $file; + } + } + + $templateDir = $this->getUserTemplateDir(); + // finally get the template file + $files = $templateDir->getById($fileId); + if ($files !== []) { + return $files[0]; + } + + throw new NotFoundException(); + } + + /** + * @param File[] $templates + * @return File[] + */ + private function filterTemplates($templates, $type = null) { + return array_filter($templates, function (Node $templateFile) use ($type) { + if (!($templateFile instanceof File)) { + return false; + } + + if ($type !== null && !in_array($templateFile->getMimeType(), self::$tplTypes[$type])) { + return false; + } + + //Todo validate mimetypes etc + + return true; + }); + } + + private function getEmpty($type = null) { + $folder = $this->getEmptyTemplateDir(); + + $templateFiles = $folder->getDirectoryListing(); + + if ($templateFiles === []) { + // Empty so lets copy over the basic templates + $templates = [ + 'document.ott', + 'spreadsheet.ots', + 'presentation.otp', + ]; + + foreach ($templates as $template) { + $file = $folder->newFile($template); + $file->putContent(file_get_contents(__DIR__ . '/../assets/' . $template)); + $templateFiles[] = $file; + } + } + + return $this->filterTemplates($templateFiles, $type); + } + + /** + * Get all global templates + * + * @return File[] + */ + public function getSystem($type = null) { + $folder = $this->getSystemTemplateDir(); + + $templateFiles = $folder->getDirectoryListing(); + return $this->filterTemplates($templateFiles, $type); + } + + /** + * @return array + */ + public function getSystemFormatted($type = null) { + $empty = $this->getEmpty($type); + $system = $this->getSystem($type); + + $emptyFormatted = array_map(function(File $file) { + return $this->formatEmpty($file); + }, $empty); + + $systemFormatted = array_map(function(File $file) { + return $this->formatNodeReturn($file); + }, $system); + + return array_merge($emptyFormatted, $systemFormatted); + } + + /** + * Get all user templates + * + * @return File[] + */ + public function getUser($type = null) { + try { + $templateDir = $this->getUserTemplateDir(); + $templateFiles = $templateDir->getDirectoryListing(); + + return $this->filterTemplates($templateFiles, $type); + } catch(NotFoundException $e) { + return []; + } + } + + /** + * @return array + */ + public function getUserFormatted($type) { + $templates = $this->getUser($type); + + return array_map(function(File $file) { + return $this->formatNodeReturn($file); + }, $templates); + } + + /** + * Get all templates + * + * @return File[] + */ + public function getAll($type = 'document') { + $system = $this->getSystem(); + $user = $this->getUser(); + + if (!array_key_exists($type, self::$tplTypes)) { + return []; + } + + return array_values(array_filter(array_merge($user, $system), function (File $template) use ($type) { + foreach (self::$tplTypes[$type] as $mime) { + if ($template->getMimeType() === $mime) { + return true; + } + } + return false; + })); + } + + public function getAllFormatted($type) { + if (!array_key_exists($type, self::$tplTypes)) { + return []; + } + + $system = $this->getSystemFormatted($type); + $user = $this->getUserFormatted($type); + + return array_merge($system, $user); + } + + /** + * Add a template to the global template folder + * + * @param string $templateName + * @param string $templateFile + * @return array + */ + public function add($templateName, $templateFile) { + $folder = $this->getSystemTemplateDir(); + + try { + $template = $folder->get($templateName); + } catch (NotFoundException $e) { + $template = $folder->newFile($templateName); + } + $template->putContent($templateFile); + + return $this->formatNodeReturn($this->get($template->getId())); + } + + /** + * Delete a template to the global template folder + * + * @param int $fileId + * @return boolean + * @throws NotFoundException + */ + public function delete($fileId) { + $files = $this->getSystemTemplateDir()->getDirectoryListing(); + foreach ($files as $file) { + if ($file->getId() === $fileId) { + $file->delete(); + return true; + } + } + + throw new NotFoundException(); + } + + /** + * Flip $tplTypes to retrieve types by mime + * + * @return array + */ + private function flipTypes() { + $result = []; + foreach ($this::$tplTypes as $type => $mime) { + $result = array_merge($result, array_fill_keys($mime, $type)); + } + + return $result; + } + + /** + * Get the user template directory + * + * @return Folder + * @throws NotFoundException + */ + private function getUserTemplateDir() { + if ($this->userId === null) { + throw new NotFoundException('userId not set'); + } + + // has the user manually set a directory as the default template dir ? + $templateDirPath = $this->config->getUserValue($this->userId, $this->appName, 'templateFolder', false); + $userFolder = $this->rootFolder->getUserFolder($this->userId); + + if ($templateDirPath !== false) { + $templateDir = $userFolder->get($templateDirPath); + } else { + // fallback to default template dir + try { + $templateDir = $userFolder->get('Templates'); + } catch (NotFoundException $e) { + throw new NotFoundException($e->getMessage()); + } + } + + if (!($templateDir instanceof Folder)) { + throw new NotFoundException('Template dir points to a file'); + } + + return $templateDir; + } + + /** + * @return Folder + */ + private function getSystemTemplateDir() { + return $this->rootFolder->get('appdata_' . $this->config->getSystemValue('instanceid', null)) + ->get('richdocuments') + ->get('templates'); + } + + /** + * @return Folder + */ + private function getEmptyTemplateDir() { + return $this->rootFolder->get('appdata_' . $this->config->getSystemValue('instanceid', null)) + ->get('richdocuments') + ->get('empty_templates'); + } + + /** + * Format template file for json return object + * + * @param File $template + * @return array + */ + public function formatNodeReturn(File $template) { + return [ + 'id' => $template->getId(), + 'name' => $template->getName(), + 'preview' => $this->urlGenerator->linkToRouteAbsolute('richdocuments.templates.getPreview', ['fileId' => $template->getId()]), + 'type' => $this->flipTypes()[$template->getMimeType()], + 'delete' => $this->urlGenerator->linkToRouteAbsolute('richdocuments.templates.delete', ['fileId' => $template->getId()]), + 'extension' => self::TYPE_EXTENTION[$this->flipTypes()[$template->getMimeType()]], + ]; + } + + public function isTemplate($fileId) { + $empty = $this->getEmpty(); + $system = $this->getSystem(); + $user = $this->getUser(); + /** @var File[] $all */ + $all = array_merge($empty, $system, $user); + + foreach ($all as $template) { + if ($template->getId() === $fileId) { + return true; + } + } + + return false; + } + + public function formatEmpty(File $template) { + return [ + 'id' => $template->getId(), + 'name' => $this->l->t('Empty'), + 'type' => $this->flipTypes()[$template->getMimeType()], + 'extension' => self::TYPE_EXTENTION[$this->flipTypes()[$template->getMimeType()]], + ]; + } +} diff --git a/lib/TokenManager.php b/lib/TokenManager.php index f11b1873..98707420 100644 --- a/lib/TokenManager.php +++ b/lib/TokenManager.php @@ -81,6 +81,7 @@ class TokenManager { /** * @param string $fileId * @param string $shareToken + * @param string $editoruid * @return array * @throws \Exception */ @@ -152,4 +153,35 @@ class TokenManager { throw $e; } } + + public function getTokenForTemplate(File $file, $userId, $templateDestination) { + $owneruid = $userId; + $editoruid = $userId; + $rootFolder = $this->rootFolder->getUserFolder($editoruid); + $updatable = $rootFolder->isUpdateable(); + // Check if the editor (user who is accessing) is in editable group + // UserCanWrite only if + // 1. No edit groups are set or + // 2. if they are set, it is in one of the edit groups + $editGroups = array_filter(explode('|', $this->appConfig->getAppValue('edit_groups'))); + if ($updatable && count($editGroups) > 0) { + $updatable = false; + foreach($editGroups as $editGroup) { + $editorGroup = \OC::$server->getGroupManager()->get($editGroup); + if ($editorGroup !== null && sizeof($editorGroup->searchUsers($editoruid)) > 0) { + $updatable = true; + break; + } + } + } + + $serverHost = $this->urlGenerator->getAbsoluteURL('/'); + + $wopi = $this->wopiMapper->generateFileToken($file->getId(), $owneruid, $editoruid, 0, (int)$updatable, $serverHost, null, $templateDestination); + + return [ + $this->wopiParser->getUrlSrc($file->getMimeType())['urlsrc'], + $wopi->getToken(), + ]; + } } |