* * @author John Molakvoæ * * @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 . * */ 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; } /** * 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()]), 'ext' => 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()], 'ext' => self::TYPE_EXTENTION[$this->flipTypes()[$template->getMimeType()]], ]; } }