Passed
Pull Request — master (#77)
by Daniel
47:29
created

Pico::getFiles()   B

Complexity

Conditions 10
Paths 12

Size

Total Lines 41
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 61.2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 19
c 1
b 0
f 1
dl 0
loc 41
ccs 4
cts 20
cp 0.2
rs 7.6666
cc 10
nc 12
nop 3
crap 61.2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * CMS Pico - Create websites using Pico CMS for Nextcloud.
4
 *
5
 * @copyright Copyright (c) 2017, Maxence Lange (<[email protected]>)
6
 * @copyright Copyright (c) 2019, Daniel Rudolf (<[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
declare(strict_types=1);
25
26
namespace OCA\CMSPico;
27
28
use HTMLPurifier;
29
use HTMLPurifier_HTML5Config;
30
use OCA\CMSPico\Exceptions\WebsiteInvalidFilesystemException;
31
use OCA\CMSPico\Files\FileInterface;
32
use OCA\CMSPico\Files\FolderInterface;
33
use OCA\CMSPico\Files\Glob\GlobIterator;
34
use OCA\CMSPico\Files\NodeInterface;
35
use OCA\CMSPico\Model\Website;
36
use OCA\CMSPico\Service\PicoService;
37
use OCP\Files\InvalidPathException;
38
use OCP\Files\NotFoundException;
39
use OCP\Files\NotPermittedException;
40
use Symfony\Component\Yaml\Exception\ParseException;
41
42
class Pico extends \Pico
43
{
44
	/** @var PicoService */
45
	private $picoService;
46
47
	/** @var HTMLPurifier */
48
	private $htmlPurifier;
49
50
	/** @var Website */
51
	private $website;
52
53
	/**
54
	 * Pico constructor.
55
	 *
56
	 * {@inheritDoc}
57
	 */
58 2
	public function __construct($rootDir, $configDir, $pluginsDir, $themesDir, $enableLocalPlugins = true)
59
	{
60 2
		$this->picoService = \OC::$server->query(PicoService::class);
61
62 2
		parent::__construct($rootDir, $configDir, $pluginsDir, $themesDir, $enableLocalPlugins);
63 2
	}
64
65
	/**
66
	 * {@inheritDoc}
67
	 *
68
	 * @return string
69
	 * @throws WebsiteInvalidFilesystemException
70
	 * @throws InvalidPathException
71
	 * @throws NotFoundException
72
	 * @throws NotPermittedException
73
	 */
74 2
	public function run()
75
	{
76 2
		return parent::run();
77
	}
78
79
	/**
80
	 * Set's Nextcloud's website instance.
81
	 *
82
	 * @param Website $website Nextcloud's website instance
83
	 *
84
	 * @return void
85
	 */
86 2
	public function setNextcloudWebsite(Website $website)
87
	{
88 2
		$this->website = $website;
89 2
	}
90
91
	/**
92
	 * Set's Pico's request URL.
93
	 *
94
	 * @param string $requestUrl request URL
95
	 *
96
	 * @return void
97
	 */
98 2
	public function setRequestUrl($requestUrl)
99
	{
100 2
		$this->requestUrl = $requestUrl;
101 2
	}
102
103
	/**
104
	 * Don't let Pico evaluate the request URL.
105
	 *
106
	 * @see Pico::setRequestUrl()
107
	 *
108
	 * @return void
109
	 */
110 2
	protected function evaluateRequestUrl()
111
	{
112
		// do nothing
113 2
	}
114
115
	/**
116
	 * Checks whether a file is readable in Nextcloud and returns the raw contents of this file
117
	 *
118
	 * @param string $absolutePath file path
119
	 *
120
	 * @return string raw contents of the file
121
	 * @throws WebsiteInvalidFilesystemException
122
	 * @throws InvalidPathException
123
	 * @throws NotFoundException
124
	 * @throws NotPermittedException
125
	 */
126 2
	public function loadFileContent($absolutePath)
127
	{
128
		/** @var FolderInterface $folder */
129
		/** @var string $basePath */
130
		/** @var string $relativePath */
131 2
		list($folder, $basePath, $relativePath) = $this->picoService->getRelativePath($this->website, $absolutePath);
132
133 2
		$file = $folder->getFile($relativePath);
134 2
		return $file->getContent();
135
	}
136
137
	/**
138
	 * Returns the parsed and purified file meta from raw file contents.
139
	 *
140
	 * @param string $rawContent
141
	 * @param string[] $headers
142
	 *
143
	 * @return array
144
	 * @throws ParseException
145
	 */
146 2
	public function parseFileMeta($rawContent, array $headers)
147
	{
148 2
		$meta = parent::parseFileMeta($rawContent, $headers);
149 2
		return $this->purifyFileMeta($meta);
150
	}
151
152
	/**
153
	 * Purifies file meta.
154
	 *
155
	 * @param array $meta
156
	 *
157
	 * @return array
158
	 */
159 2
	protected function purifyFileMeta(array $meta)
160
	{
161 2
		$newMeta = [];
162 2
		foreach ($meta as $key => $value) {
163 2
			if (is_array($value)) {
164 2
				$newMeta[$key] = $this->purifyFileMeta($value);
165
			} else {
166 2
				$newMeta[$key] = $this->getHtmlPurifier()->purify($value);
167
			}
168
		}
169
170 2
		return $newMeta;
171
	}
172
173
	/**
174
	 * Returns the parsed and purified contents of a page.
175
	 *
176
	 * @param string $markdown
177
	 *
178
	 * @return string
179
	 */
180 2
	public function parseFileContent($markdown)
181
	{
182 2
		$content = parent::parseFileContent($markdown);
183 2
		return $this->purifyFileContent($content);
184
	}
185
186
	/**
187
	 * Purifies file content.
188
	 *
189
	 * @param string $content
190
	 *
191
	 * @return string
192
	 */
193 2
	protected function purifyFileContent(string $content)
194
	{
195 2
		return $this->getHtmlPurifier()->purify($content);
196
	}
197
198
	/**
199
	 * Returns the HTMLPurifier instance.
200
	 *
201
	 * @return HTMLPurifier
202
	 */
203 2
	public function getHtmlPurifier()
204
	{
205 2
		if ($this->htmlPurifier === null) {
206 2
			$htmlPurifierConfig = HTMLPurifier_HTML5Config::createDefault();
207 2
			$this->htmlPurifier = new HTMLPurifier($htmlPurifierConfig);
208
209 2
			$this->triggerEvent('onHtmlPurifier', [ &$this->htmlPurifier ]);
210
		}
211
212 2
		return $this->htmlPurifier;
213
	}
214
215
	/**
216
	 * @param string $absolutePath
217
	 * @param string $fileExtension
218
	 * @param int    $order
219
	 *
220
	 * @return string[]
221
	 * @throws WebsiteInvalidFilesystemException
222
	 * @throws InvalidPathException
223
	 */
224 2
	public function getFiles($absolutePath, $fileExtension = '', $order = \Pico::SORT_ASC)
225
	{
226
		/** @var FolderInterface $folder */
227
		/** @var string $basePath */
228
		/** @var string $relativePath */
229 2
		list($folder, $basePath, $relativePath) = $this->picoService->getRelativePath($this->website, $absolutePath);
230
231 2
		if ($folder->isLocal()) {
232 2
			return parent::getFiles($absolutePath, $fileExtension, $order);
233
		}
234
235
		$folderFilter = function (NodeInterface $node, int $key, FolderInterface $folder) use ($fileExtension) {
236
			$fileName = $node->getName();
237
238
			// exclude hidden files/dirs starting with a .
239
			// exclude files ending with a ~ (vim/nano backup) or # (emacs backup)
240
			if (($fileName[0] === '.') || in_array(substr($fileName, -1), [ '~', '#' ], true)) {
241
				return false;
242
			}
243
244
			if ($node->isFile()) {
245
				/** @var FileInterface $node */
246
				if ($fileExtension && ($fileExtension !== '.' . $node->getExtension())) {
247
					return false;
248
				}
249
			}
250
251
			return true;
252
		};
253
254
		try {
255
			$folderIterator = new \RecursiveCallbackFilterIterator($folder->fakeRoot(), $folderFilter);
256
257
			$result = [];
258
			foreach (new \RecursiveIteratorIterator($folderIterator) as $file) {
259
				$result[] = $basePath . '/' . $relativePath . $file->getPath();
260
			}
261
262
			return ($order === \Pico::SORT_DESC) ? array_reverse($result) : $result;
263
		} catch (\Exception $e) {
264
			return [];
265
		}
266
	}
267
268
	/**
269
	 * @param string $absolutePathPattern
270
	 * @param int    $order
271
	 *
272
	 * @return string[]
273
	 * @throws WebsiteInvalidFilesystemException
274
	 * @throws InvalidPathException
275
	 */
276 2
	public function getFilesGlob($absolutePathPattern, $order = \Pico::SORT_ASC)
277
	{
278
		/** @var FolderInterface $folder */
279
		/** @var string $basePath */
280
		/** @var string $pattern */
281 2
		list($folder, $basePath, $pattern) = $this->picoService->getRelativePath($this->website, $absolutePathPattern);
282
283 2
		if ($folder->isLocal()) {
284 2
			return parent::getFilesGlob($absolutePathPattern, $order);
285
		}
286
287
		try {
288
			$result = [];
289
			foreach (new GlobIterator($folder, $pattern) as $file) {
290
				$fileName = $file->getName();
291
292
				// exclude files ending with a ~ (vim/nano backup) or # (emacs backup)
293
				if (in_array(substr($fileName, -1), [ '~', '#' ], true)) {
294
					continue;
295
				}
296
297
				$result[] = $basePath . $file->getPath();
298
			}
299
300
			return ($order === \Pico::SORT_DESC) ? array_reverse($result) : $result;
301
		} catch (\Exception $e) {
302
			return [];
303
		}
304
	}
305
}
306