Completed
Push — master ( ca7125...f4c0cd )
by Julius
04:26
created

TemplateManager::getAll()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 15
cp 0
rs 9.7
c 0
b 0
f 0
cc 4
nc 2
nop 1
crap 20
1
<?php
2
declare (strict_types = 1);
3
/**
4
 * @copyright Copyright (c) 2018 John Molakvoæ <[email protected]>
5
 *
6
 * @author John Molakvoæ <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
namespace OCA\Richdocuments;
26
27
use OCP\Files\File;
28
use OCP\Files\Folder;
29
use OCP\Files\IAppData;
30
use OCP\Files\IRootFolder;
31
use OCP\Files\Node;
32
use OCP\Files\NotFoundException;
33
use OCP\IConfig;
34
use OCP\IL10N;
35
use OCP\IPreview;
36
use OCP\IURLGenerator;
37
use OC\Files\AppData\Factory;
38
39
class TemplateManager {
40
41
	/** @var string */
42
	protected $appName;
43
44
	/** @var string */
45
	protected $userId;
46
47
	/** @var IConfig */
48
	private $config;
49
50
	/** @var IURLGenerator */
51
	private $urlGenerator;
52
53
	/** @var IRootFolder */
54
	private $rootFolder;
55
56
	/** @var IL10N */
57
	private $l;
58
59
	/** Accepted templates mime types */
60
	const MIMES_DOCUMENTS = [
61
		'application/vnd.oasis.opendocument.text-template'
62
	];
63
	const MIMES_SHEETS = [
64
		'application/vnd.oasis.opendocument.spreadsheet-template'
65
	];
66
	const MIMES_PRESENTATIONS = [
67
		'application/vnd.oasis.opendocument.presentation-template'
68
	];
69
70
	/** @var array Template mime types match */
71
	static public $tplTypes = [
72
		'document'     => self::MIMES_DOCUMENTS,
73
		'spreadsheet'  => self::MIMES_SHEETS,
74
		'presentation' => self::MIMES_PRESENTATIONS
75
	];
76
77
	const TYPE_EXTENTION = [
78
		'document'     => 'odt',
79
		'spreadsheet'  => 'ods',
80
		'presentation' => 'odp'
81
	];
82
83
	const TYPE_EXTENSION_OOXML = [
84
		'document'     => 'docx',
85
		'spreadsheet'  => 'xlsx',
86
		'presentation' => 'pptx'
87
	];
88
89
	const EMPTY_TEMPLATE_ID_TYPE = [
90
		-1 => 'document',
91
		-2 => 'spreadsheet',
92
		-3 => 'presentation',
93
	];
94
	const EMPTY_TEMPLATE_TYPE_ID = [
95
		'document'     => -1,
96
		'spreadsheet'  => -2,
97
		'presentation' => -3,
98
	];
99
100
101
	/**
102
	 * Template manager
103
	 *
104
	 * @param string $appName
105
	 * @param string $userId
106
	 * @param IConfig $config
107
	 * @param Factory $appDataFactory
0 ignored issues
show
Documentation introduced by
There is no parameter named $appDataFactory. Did you maybe mean $appData?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
108
	 * @param IURLGenerator $urlGenerator
109
	 * @param IRootFolder $rootFolder
110
	 * @param IL10N $l
111
	 * @throws \OCP\Files\NotPermittedException
112
	 */
113
	public function __construct($appName,
114
								$userId,
115
								IConfig $config,
116
								IAppData $appData,
117
								IURLGenerator $urlGenerator,
118
								IRootFolder $rootFolder,
119
								IL10N $l) {
120
		$this->appName        = $appName;
121
		$this->userId         = $userId;
122
		$this->config         = $config;
123
		$this->rootFolder     = $rootFolder;
124
		$this->urlGenerator   = $urlGenerator;
125
126
127
		$this->appData = $appData;
0 ignored issues
show
Bug introduced by
The property appData does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
128
		$this->createAppDataFolders();
129
130
		$this->l = $l;
131
	}
132
133
	private function createAppDataFolders() {
134
		/*
135
		 * Init the appdata folder
136
		 * We need an actual folder for the fileid and previews.
137
		 * TODO: Fix this at some point
138
		 */
139
		try {
140
			$this->appData->getFolder('templates');
141
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
142
			$this->appData->newFolder('templates');
143
		}
144
		try {
145
			$this->appData->getFolder('empty_templates');
146
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
147
			$this->appData->newFolder('empty_templates');
148
		}
149
	}
150
151
	public function setUserId($userId) {
152
		$this->userId = $userId;
153
	}
154
155
	/**
156
	 * Get template ISimpleFile|Node
157
	 *
158
	 * @param int $fileId
159
	 * @return File
160
	 */
161
	public function get($fileId) {
162
		// is this a global template ?
163
		$files = $this->getEmptyTemplateDir()->getDirectoryListing();
164
165
		foreach ($files as $file) {
166
			if ($file->getId() === $fileId) {
167
				return $file;
168
			}
169
		}
170
171
		// is this a global template ?
172
		$files = $this->getSystemTemplateDir()->getDirectoryListing();
173
174
		foreach ($files as $file) {
175
			if ($file->getId() === $fileId) {
176
				return $file;
177
			}
178
		}
179
180
		$templateDir = $this->getUserTemplateDir();
181
		// finally get the template file
182
		$files = $templateDir->getById($fileId);
183
		if ($files !== []) {
184
			return $files[0];
185
		}
186
187
		throw new NotFoundException();
188
	}
189
190
	/**
191
	 * @param File[] $templates
192
	 * @return File[]
193
	 */
194
	private function filterTemplates($templates, $type = null) {
195
		return array_filter($templates, function (Node $templateFile) use ($type) {
196
			if (!($templateFile instanceof File)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\File does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
197
				return false;
198
			}
199
200
			if ($type !== null && !in_array($templateFile->getMimeType(), self::$tplTypes[$type])) {
201
				return false;
202
			}
203
204
			//Todo validate mimetypes etc
205
206
			return true;
207
		});
208
	}
209
210
	private function getEmpty($type = null) {
211
		$folder = $this->getEmptyTemplateDir();
212
213
		$templateFiles = $folder->getDirectoryListing();
214
215
		if ($templateFiles === []) {
216
			// Empty so lets copy over the basic templates
217
			$templates = [
218
				'document.ott',
219
				'spreadsheet.ots',
220
				'presentation.otp',
221
			];
222
223
			foreach ($templates as $template) {
224
				$file = $folder->newFile($template);
225
				$file->putContent(file_get_contents(__DIR__ . '/../assets/' . $template));
226
				$templateFiles[] = $file;
227
			}
228
		}
229
230
		return $this->filterTemplates($templateFiles, $type);
231
	}
232
233
	/**
234
	 * Remove empty_templates in appdata and recreate it from the apps templates
235
	 */
236
	public function updateEmptyTemplates() {
237
		try {
238
			$folder = $this->getEmptyTemplateDir();
239
			$folder->delete();
240
		} catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
241
		}
242
		$this->appData->newFolder('empty_templates');
243
		$this->getEmpty();
244
	}
245
246
	/**
247
	 * Get all global templates
248
	 *
249
	 * @return File[]
250
	 */
251
	public function getSystem($type = null) {
252
		$folder = $this->getSystemTemplateDir();
253
254
		$templateFiles = $folder->getDirectoryListing();
255
		return $this->filterTemplates($templateFiles, $type);
256
	}
257
258
	/**
259
	 * @return array
260
	 */
261
	public function getSystemFormatted($type = null) {
262
		$empty = $this->getEmpty($type);
263
		$system = $this->getSystem($type);
264
265
		$emptyFormatted = array_map(function(File $file) {
266
			return $this->formatEmpty($file);
267
		}, $empty);
268
269
		$systemFormatted = array_map(function(File $file) {
270
			return $this->formatNodeReturn($file);
271
		}, $system);
272
273
		return array_merge($emptyFormatted, $systemFormatted);
274
	}
275
276
	/**
277
	 * Get all user templates
278
	 *
279
	 * @return File[]
280
	 */
281
	public function getUser($type = null) {
282
		try {
283
			$templateDir   = $this->getUserTemplateDir();
284
			$templateFiles = $templateDir->getDirectoryListing();
285
286
			return $this->filterTemplates($templateFiles, $type);
287
		} catch(NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
288
			return [];
289
		}
290
	}
291
292
	/**
293
	 * @return array
294
	 */
295
	public function getUserFormatted($type) {
296
		$templates = $this->getUser($type);
297
298
		return array_map(function(File $file) {
299
			return $this->formatNodeReturn($file);
300
		}, $templates);
301
	}
302
303
	/**
304
	 * Get all templates
305
	 *
306
	 * @return File[]
307
	 */
308
	public function getAll($type = 'document') {
309
		$system = $this->getSystem();
310
		$user   = $this->getUser();
311
312
		if (!array_key_exists($type, self::$tplTypes)) {
313
			return [];
314
		}
315
316
		return array_values(array_filter(array_merge($user, $system), function (File $template) use ($type) {
317
			foreach (self::$tplTypes[$type] as $mime) {
318
				if ($template->getMimeType() === $mime) {
319
					return true;
320
				}
321
			}
322
			return false;
323
		}));
324
	}
325
326
	public function getAllFormatted($type) {
327
		if (!array_key_exists($type, self::$tplTypes)) {
328
			return [];
329
		}
330
331
		$system = $this->getSystemFormatted($type);
332
		$user   = $this->getUserFormatted($type);
333
334
		return array_merge($system, $user);
335
	}
336
337
	/**
338
	 * Add a template to the global template folder
339
	 *
340
	 * @param string $templateName
341
	 * @param string $templateFile
342
	 * @return array
343
	 */
344
	public function add($templateName, $templateFile) {
345
		$folder = $this->getSystemTemplateDir();
346
347
		try {
348
			$template = $folder->get($templateName);
349
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
350
			$template = $folder->newFile($templateName);
351
		}
352
		$template->putContent($templateFile);
353
354
		return $this->formatNodeReturn($this->get($template->getId()));
355
	}
356
357
	/**
358
	 * Delete a template to the global template folder
359
	 *
360
	 * @param int $fileId
361
	 * @return boolean
362
	 * @throws NotFoundException
363
	 */
364
	public function delete($fileId) {
365
		$files = $this->getSystemTemplateDir()->getDirectoryListing();
366
		foreach ($files as $file) {
367
			if ($file->getId() === $fileId) {
368
				$file->delete();
369
				return true;
370
			}
371
		}
372
373
		throw new NotFoundException();
374
	}
375
376
	/**
377
	 * Flip $tplTypes to retrieve types by mime
378
	 *
379
	 * @return array
380
	 */
381
	private function flipTypes() {
382
		$result = [];
383
		foreach ($this::$tplTypes as $type => $mime) {
384
			$result = array_merge($result, array_fill_keys($mime, $type));
385
		}
386
387
		return $result;
388
	}
389
390
	/**
391
	 * Get the user template directory
392
	 *
393
	 * @return Folder
394
	 * @throws NotFoundException
395
	 */
396
	private function getUserTemplateDir() {
397
		if ($this->userId === null) {
398
			throw new NotFoundException('userId not set');
399
		}
400
401
		// has the user manually set a directory as the default template dir ?
402
		$templateDirPath = $this->config->getUserValue($this->userId, $this->appName, 'templateFolder', false);
403
		$userFolder = $this->rootFolder->getUserFolder($this->userId);
404
405
		if ($templateDirPath !== false) {
406
			$templateDir = $userFolder->get($templateDirPath);
407
		} else {
408
			// fallback to default template dir
409
			try {
410
				$templateDir = $userFolder->get('Templates');
411
			} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
412
				throw new NotFoundException($e->getMessage());
413
			}
414
		}
415
416
		if (!($templateDir instanceof Folder)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
417
			throw new NotFoundException('Template dir points to a file');
418
		}
419
420
		return $templateDir;
421
	}
422
423
	/**
424
	 * @return Folder
425
	 */
426
	private function getSystemTemplateDir() {
427
		return $this->rootFolder->get('appdata_' . $this->config->getSystemValue('instanceid', null))
428
			->get('richdocuments')
429
			->get('templates');
430
	}
431
432
	/**
433
	 * @return Folder
434
	 */
435
	private function getEmptyTemplateDir() {
436
		return $this->rootFolder->get('appdata_' . $this->config->getSystemValue('instanceid', null))
437
			->get('richdocuments')
438
			->get('empty_templates');
439
	}
440
441
	/**
442
	 * Format template file for json return object
443
	 *
444
	 * @param File $template
445
	 * @return array
446
	 */
447
	public function formatNodeReturn(File $template) {
448
		$ooxml = $this->config->getAppValue($this->appName, 'doc_format', '') === 'ooxml';
449
		$documentType = $this->flipTypes()[$template->getMimeType()];
450
		return [
451
			'id'        => $template->getId(),
452
			'name'      => $template->getName(),
453
			'preview'   => $this->urlGenerator->linkToRouteAbsolute('richdocuments.templates.getPreview', ['fileId' => $template->getId()]),
454
			'type'      => $this->flipTypes()[$template->getMimeType()],
455
			'delete'    => $this->urlGenerator->linkToRouteAbsolute('richdocuments.templates.delete', ['fileId' => $template->getId()]),
456
			'extension' => $ooxml ? self::TYPE_EXTENSION_OOXML[$documentType] : self::TYPE_EXTENTION[$documentType],
457
		];
458
	}
459
460
	public function isTemplate($fileId) {
461
		$empty = $this->getEmpty();
462
		$system = $this->getSystem();
463
		$user = $this->getUser();
464
		/** @var File[] $all */
465
		$all = array_merge($empty, $system, $user);
466
467
		foreach ($all as $template) {
468
			if ($template->getId() === $fileId) {
469
				return true;
470
			}
471
		}
472
473
		return false;
474
	}
475
476
	public function formatEmpty(File $template) {
477
		$ooxml = $this->config->getAppValue($this->appName, 'doc_format', '') === 'ooxml';
478
		$documentType = $this->flipTypes()[$template->getMimeType()];
479
		return [
480
			'id'        => $template->getId(),
481
			'name'      => $this->l->t('Empty'),
482
			'type'      => $this->flipTypes()[$template->getMimeType()],
483
			'extension' => $ooxml ? self::TYPE_EXTENSION_OOXML[$documentType] : self::TYPE_EXTENTION[$documentType],
484
		];
485
	}
486
}
487