Passed
Push — master ( fa41e0...4bd63f )
by Daniel
07:07 queued 12s
created

Website::getOptionsJSON()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
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\Model;
27
28
use OCA\CMSPico\AppInfo\Application;
29
use OCA\CMSPico\Exceptions\ThemeNotCompatibleException;
30
use OCA\CMSPico\Exceptions\ThemeNotFoundException;
31
use OCA\CMSPico\Exceptions\WebsiteForeignOwnerException;
32
use OCA\CMSPico\Exceptions\WebsiteInvalidDataException;
33
use OCA\CMSPico\Exceptions\WebsiteInvalidFilesystemException;
34
use OCA\CMSPico\Exceptions\WebsiteInvalidOwnerException;
35
use OCA\CMSPico\Files\StorageFolder;
36
use OCA\CMSPico\Service\MiscService;
37
use OCA\CMSPico\Service\ThemesService;
38
use OCA\CMSPico\Service\WebsitesService;
39
use OCP\Files\InvalidPathException;
40
use OCP\Files\NotFoundException;
41
use OCP\IConfig;
42
use OCP\IL10N;
43
use OCP\IURLGenerator;
44
use OCP\IUserManager;
45
46
class Website extends WebsiteCore
47
{
48
	/** @var int */
49
	public const SITE_LENGTH_MIN = 3;
50
51
	/** @var int */
52
	public const SITE_LENGTH_MAX = 255;
53
54
	/** @var string */
55
	public const SITE_REGEX = '^[a-z0-9][a-z0-9_-]+[a-z0-9]$';
56
57
	/** @var int */
58
	public const NAME_LENGTH_MIN = 3;
59
60
	/** @var int */
61
	public const NAME_LENGTH_MAX = 255;
62
63
	/** @var IConfig */
64
	private $config;
65
66
	/** @var IL10N */
67
	private $l10n;
68
69
	/** @var IUserManager */
70
	private $userManager;
71
72
	/** @var IURLGenerator */
73
	private $urlGenerator;
74
75
	/** @var WebsitesService */
76
	private $websitesService;
77
78
	/** @var ThemesService */
79
	private $themesService;
80
81
	/** @var MiscService */
82
	private $miscService;
83
84
	/** @var StorageFolder */
85
	private $folder;
86
87
	/**
88
	 * Website constructor.
89
	 *
90
	 * @param array|null $data
91
	 */
92 15
	public function __construct($data = null)
93
	{
94 15
		$this->config = \OC::$server->getConfig();
0 ignored issues
show
Deprecated Code introduced by
The function OC\Server::getConfig() has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

94
		$this->config = /** @scrutinizer ignore-deprecated */ \OC::$server->getConfig();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
95 15
		$this->l10n = \OC::$server->getL10N(Application::APP_NAME);
0 ignored issues
show
Deprecated Code introduced by
The function OC\Server::getL10N() has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

95
		$this->l10n = /** @scrutinizer ignore-deprecated */ \OC::$server->getL10N(Application::APP_NAME);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
96 15
		$this->userManager = \OC::$server->getUserManager();
0 ignored issues
show
Deprecated Code introduced by
The function OC\Server::getUserManager() has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

96
		$this->userManager = /** @scrutinizer ignore-deprecated */ \OC::$server->getUserManager();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
97 15
		$this->urlGenerator = \OC::$server->getURLGenerator();
0 ignored issues
show
Deprecated Code introduced by
The function OC\Server::getURLGenerator() has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

97
		$this->urlGenerator = /** @scrutinizer ignore-deprecated */ \OC::$server->getURLGenerator();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
98 15
		$this->websitesService = \OC::$server->query(WebsitesService::class);
0 ignored issues
show
Deprecated Code introduced by
The function OC\ServerContainer::query() has been deprecated: 20.0.0 use \Psr\Container\ContainerInterface::get ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

98
		$this->websitesService = /** @scrutinizer ignore-deprecated */ \OC::$server->query(WebsitesService::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
99 15
		$this->themesService = \OC::$server->query(ThemesService::class);
0 ignored issues
show
Deprecated Code introduced by
The function OC\ServerContainer::query() has been deprecated: 20.0.0 use \Psr\Container\ContainerInterface::get ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

99
		$this->themesService = /** @scrutinizer ignore-deprecated */ \OC::$server->query(ThemesService::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
100 15
		$this->miscService = \OC::$server->query(MiscService::class);
0 ignored issues
show
Deprecated Code introduced by
The function OC\ServerContainer::query() has been deprecated: 20.0.0 use \Psr\Container\ContainerInterface::get ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

100
		$this->miscService = /** @scrutinizer ignore-deprecated */ \OC::$server->query(MiscService::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
101
102 15
		parent::__construct($data);
103 15
	}
104
105
	/**
106
	 * @return string
107
	 */
108 5
	public function getOptionsJSON(): string
109
	{
110 5
		return json_encode($this->getOptions());
111
	}
112
113
	/**
114
	 * @return string
115
	 */
116 13
	public function getTimeZone(): string
117
	{
118 13
		$serverTimeZone = date_default_timezone_get() ?: 'UTC';
119 13
		return $this->config->getUserValue($this->getUserId(), 'core', 'timezone', $serverTimeZone);
120
	}
121
122
	/**
123
	 * {@inheritDoc}
124
	 */
125 10
	public function getData(): array
126
	{
127 10
		$data = parent::getData();
128 10
		$data['timezone'] = $this->getTimeZone();
129 10
		return $data;
130
	}
131
132
	/**
133
	 * @throws WebsiteInvalidOwnerException
134
	 */
135 12
	public function assertValidOwner(): void
136
	{
137 12
		$user = $this->userManager->get($this->getUserId());
138 12
		if ($user === null) {
139
			throw new WebsiteInvalidOwnerException();
140
		}
141 12
		if (!$user->isEnabled()) {
142
			throw new WebsiteInvalidOwnerException();
143
		}
144 12
		if (!$this->websitesService->isUserAllowed($this->getUserId())) {
145
			throw new WebsiteInvalidOwnerException();
146
		}
147 12
	}
148
149
	/**
150
	 * @throws WebsiteInvalidDataException
151
	 */
152 5
	public function assertValidName(): void
153
	{
154 5
		if (strlen($this->getName()) < self::NAME_LENGTH_MIN) {
155
			throw new WebsiteInvalidDataException('name', $this->l10n->t('The name of the website must be longer.'));
156
		}
157 5
		if (strlen($this->getName()) > self::NAME_LENGTH_MAX) {
158
			throw new WebsiteInvalidDataException('name', $this->l10n->t('The name of the website is too long.'));
159
		}
160 5
	}
161
162
	/**
163
	 * @throws WebsiteInvalidDataException
164
	 */
165 5
	public function assertValidSite(): void
166
	{
167 5
		if (strlen($this->getSite()) < self::SITE_LENGTH_MIN) {
168
			$error = $this->l10n->t('The identifier of the website must be longer.');
169
			throw new WebsiteInvalidDataException('site', $error);
170
		}
171 5
		if (strlen($this->getSite()) > self::SITE_LENGTH_MAX) {
172
			$error = $this->l10n->t('The identifier of the website is too long.');
173
			throw new WebsiteInvalidDataException('site', $error);
174
		}
175 5
		if (preg_match('/' . self::SITE_REGEX . '/', $this->getSite()) !== 1) {
176
			$error = $this->l10n->t('The identifier of the website can only contain lowercase alpha numeric chars.');
177
			throw new WebsiteInvalidDataException('site', $error);
178
		}
179 5
	}
180
181
	/**
182
	 * @throws WebsiteInvalidDataException
183
	 */
184 5
	public function assertValidPath(): void
185
	{
186
		try {
187 5
			$path = $this->miscService->normalizePath($this->getPath());
188 5
			if ($path === '') {
189 5
				throw new InvalidPathException();
190
			}
191
		} catch (InvalidPathException $e) {
192
			throw new WebsiteInvalidDataException(
193
				'path',
194
				$this->l10n->t('The path of the website is invalid.')
195
			);
196
		}
197
198 5
		$userFolder = new StorageFolder(\OC::$server->getUserFolder($this->getUserId()));
0 ignored issues
show
Deprecated Code introduced by
The function OC\Server::getUserFolder() has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

198
		$userFolder = new StorageFolder(/** @scrutinizer ignore-deprecated */ \OC::$server->getUserFolder($this->getUserId()));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Bug introduced by
It seems like OC::server->getUserFolder($this->getUserId()) can also be of type null; however, parameter $folder of OCA\CMSPico\Files\StorageFolder::__construct() does only seem to accept OCP\Files\Folder, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

198
		$userFolder = new StorageFolder(/** @scrutinizer ignore-type */ \OC::$server->getUserFolder($this->getUserId()));
Loading history...
199
200
		try {
201 5
			$websiteBaseFolder = $userFolder->getFolder(dirname($path));
202
203
			try {
204 5
				$websiteFolder = $websiteBaseFolder->getFolder(basename($path));
205
206 2
				if (!$websiteFolder->isLocal()) {
207
					throw new WebsiteInvalidDataException(
208
						'path',
209 2
						$this->l10n->t('The website\'s path is stored on a non-local storage.')
210
					);
211
				}
212 3
			} catch (NotFoundException $e) {
213 3
				if (!$websiteBaseFolder->isLocal()) {
214
					throw new WebsiteInvalidDataException(
215
						'path',
216 5
						$this->l10n->t('The website\'s path is stored on a non-local storage.')
217
					);
218
				}
219
			}
220
		} catch (InvalidPathException | NotFoundException $e) {
221
			throw new WebsiteInvalidDataException(
222
				'path',
223
				$this->l10n->t('Parent folder of the website\'s path not found.')
224
			);
225
		}
226 5
	}
227
228
	/**
229
	 * @throws ThemeNotFoundException
230
	 * @throws ThemeNotCompatibleException
231
	 */
232 5
	public function assertValidTheme(): void
233
	{
234 5
		$this->themesService->assertValidTheme($this->getTheme());
235 5
	}
236
237
	/**
238
	 * @param string $userId
239
	 *
240
	 * @throws WebsiteForeignOwnerException
241
	 */
242 2
	public function assertOwnedBy(string $userId): void
243
	{
244 2
		if ($this->getUserId() !== $userId) {
245
			throw new WebsiteForeignOwnerException();
246
		}
247 2
	}
248
249
	/**
250
	 * @return StorageFolder
251
	 * @throws WebsiteInvalidFilesystemException
252
	 */
253 9
	public function getWebsiteFolder(): StorageFolder
254
	{
255 9
		if ($this->folder !== null) {
256
			try {
257
				// NC doesn't guarantee that mounts are present for the whole request lifetime
258
				// for example, if you call \OC\Files\Utils\Scanner::scan(), all mounts are reset
259
				// this makes OCNode instances, which rely on mounts of different users than the current, unusable
260
				// by calling OCFolder::get('') we can detect this situation and re-init the required mounts
261 9
				$this->folder->get('');
262
			} catch (\Exception $e) {
263
				$this->folder = null;
264
			}
265
		}
266
267 9
		if ($this->folder === null) {
268
			try {
269 9
				$ocUserFolder = \OC::$server->getUserFolder($this->getUserId());
0 ignored issues
show
Deprecated Code introduced by
The function OC\Server::getUserFolder() has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

269
				$ocUserFolder = /** @scrutinizer ignore-deprecated */ \OC::$server->getUserFolder($this->getUserId());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
270 9
				$userFolder = new StorageFolder($ocUserFolder);
0 ignored issues
show
Bug introduced by
It seems like $ocUserFolder can also be of type null; however, parameter $folder of OCA\CMSPico\Files\StorageFolder::__construct() does only seem to accept OCP\Files\Folder, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

270
				$userFolder = new StorageFolder(/** @scrutinizer ignore-type */ $ocUserFolder);
Loading history...
271
272 9
				$websiteFolder = $userFolder->getFolder($this->getPath());
273 9
				$this->folder = $websiteFolder->fakeRoot();
274
			} catch (InvalidPathException | NotFoundException $e) {
275
				throw new WebsiteInvalidFilesystemException($e);
276
			}
277
		}
278
279 9
		return $this->folder;
280
	}
281
282
	/**
283
	 * @return string
284
	 * @throws WebsiteInvalidFilesystemException
285
	 */
286 5
	public function getWebsitePath(): string
287
	{
288
		try {
289 5
			return $this->getWebsiteFolder()->getLocalPath() . '/';
290
		} catch (InvalidPathException | NotFoundException $e) {
291
			throw new WebsiteInvalidFilesystemException($e);
292
		}
293
	}
294
295
	/**
296
	 * @param bool $proxyRequest
297
	 *
298
	 * @return string
299
	 */
300 5
	public function getWebsiteUrl(bool $proxyRequest = false): string
301
	{
302 5
		if (!$proxyRequest) {
303 5
			$route = Application::APP_NAME . '.Pico.getPage';
304 5
			$parameters = [ 'site' => $this->getSite(), 'page' => '' ];
305 5
			return $this->urlGenerator->linkToRoute($route, $parameters) . '/';
306
		} else {
307
			return \OC::$WEBROOT . '/sites/' . urlencode($this->getSite()) . '/';
308
		}
309
	}
310
}
311