Test Failed
Push — master ( 6e750b...ddc13c )
by Daniel
19:00
created

WebsitesService::updateWebsite()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 10
c 2
b 0
f 0
dl 0
loc 18
ccs 0
cts 11
cp 0
rs 9.6111
cc 5
nc 16
nop 1
crap 30
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\Service;
27
28
use OCA\CMSPico\Db\WebsitesRequest;
29
use OCA\CMSPico\Exceptions\AssetInvalidPathException;
30
use OCA\CMSPico\Exceptions\AssetNotFoundException;
31
use OCA\CMSPico\Exceptions\AssetNotPermittedException;
32
use OCA\CMSPico\Exceptions\FilesystemNotLocalException;
33
use OCA\CMSPico\Exceptions\PageInvalidPathException;
34
use OCA\CMSPico\Exceptions\PageNotFoundException;
35
use OCA\CMSPico\Exceptions\PageNotPermittedException;
36
use OCA\CMSPico\Exceptions\PicoRuntimeException;
37
use OCA\CMSPico\Exceptions\TemplateNotCompatibleException;
38
use OCA\CMSPico\Exceptions\TemplateNotFoundException;
39
use OCA\CMSPico\Exceptions\ThemeNotCompatibleException;
40
use OCA\CMSPico\Exceptions\ThemeNotFoundException;
41
use OCA\CMSPico\Exceptions\WebsiteExistsException;
42
use OCA\CMSPico\Exceptions\WebsiteInvalidDataException;
43
use OCA\CMSPico\Exceptions\WebsiteInvalidFilesystemException;
44
use OCA\CMSPico\Exceptions\WebsiteInvalidOwnerException;
45
use OCA\CMSPico\Exceptions\WebsiteNotFoundException;
46
use OCA\CMSPico\Exceptions\WebsiteNotPermittedException;
47
use OCA\CMSPico\Model\PicoAsset;
48
use OCA\CMSPico\Model\PicoPage;
49
use OCA\CMSPico\Model\Website;
50
use OCA\CMSPico\Model\WebsiteRequest;
51
use OCP\Files\InvalidPathException;
52
use OCP\IGroupManager;
53
54
class WebsitesService
55
{
56
	/** @var int */
57
	public const LINK_MODE_LONG = 1;
58
59
	/** @var int */
60
	public const LINK_MODE_SHORT = 2;
61
62
	/** @var WebsitesRequest */
63
	private $websiteRequest;
64
65
	/** @var IGroupManager */
66
	private $groupManager;
67
68
	/** @var ConfigService */
69
	private $configService;
70
71
	/** @var TemplatesService */
72
	private $templatesService;
73
74
	/** @var PicoService */
75
	private $picoService;
76
77
	/** @var AssetsService */
78
	private $assetsService;
79
80
	/** @var MiscService */
81
	private $miscService;
82
83
	/**
84
	 * WebsitesService constructor.
85
	 *
86
	 * @param WebsitesRequest  $websiteRequest
87
	 * @param IGroupManager    $groupManager
88
	 * @param ConfigService    $configService
89
	 * @param TemplatesService $templatesService
90
	 * @param PicoService      $picoService
91
	 * @param AssetsService    $assetsService
92
	 * @param MiscService      $miscService
93
	 *
94
	 * @internal param Manager $encryptionManager
95 1
	 */
96
	public function __construct(
97
		WebsitesRequest $websiteRequest,
98
		IGroupManager $groupManager,
99
		ConfigService $configService,
100
		TemplatesService $templatesService,
101
		PicoService $picoService,
102
		AssetsService $assetsService,
103
		MiscService $miscService
104 1
	) {
105 1
		$this->websiteRequest = $websiteRequest;
106 1
		$this->groupManager = $groupManager;
107 1
		$this->configService = $configService;
108 1
		$this->templatesService = $templatesService;
109 1
		$this->picoService = $picoService;
110 1
		$this->assetsService = $assetsService;
111 1
		$this->miscService = $miscService;
112
	}
113
114
	/**
115
	 * Creates a new website.
116
	 *
117
	 * Warning: This method does not check whether the user is allowed to create websites!
118
	 * Please use {@see Website::assertValidOwner()} beforehand.
119
	 *
120
	 * @param Website $website
121
	 * @param string  $templateName
122
	 *
123
	 * @throws WebsiteExistsException
124
	 * @throws WebsiteInvalidDataException
125
	 * @throws WebsiteInvalidOwnerException
126 3
	 * @throws ThemeNotFoundException
127
	 * @throws ThemeNotCompatibleException
128 3
	 * @throws TemplateNotFoundException
129 3
	 * @throws TemplateNotCompatibleException
130 3
	 */
131 3
	public function createWebsite(Website $website, string $templateName): void
132 3
	{
133 3
		$website->assertValidName();
134
		$website->assertValidSite();
135
		$website->assertValidPath();
136 3
		$website->assertValidTheme();
137
138 3
		try {
139
			$website = $this->websiteRequest->getWebsiteFromSite($website->getSite());
140
			throw new WebsiteExistsException();
141
		} catch (WebsiteNotFoundException $e) {
142 3
			// in fact we want the website not to exist yet
143
		}
144
145
		$this->templatesService->assertValidTemplate($templateName);
146
		$this->templatesService->installTemplate($website, $templateName);
147
148
		$this->websiteRequest->create($website);
149
	}
150
151
	/**
152
	 * Updates a website.
153
	 *
154
	 * Warning: This method does not check the ownership of the website!
155
	 * Please use {@see Website::assertOwnedBy()} beforehand.
156
	 *
157
	 * @param Website $website
158
	 *
159
	 * @throws WebsiteNotFoundException
160
	 * @throws WebsiteInvalidDataException
161
	 * @throws ThemeNotFoundException
162
	 * @throws ThemeNotCompatibleException
163
	 * @throws TemplateNotFoundException
164
	 * @throws TemplateNotCompatibleException
165
	 */
166
	public function updateWebsite(Website $website): void
167
	{
168
		$originalWebsite = $this->websiteRequest->getWebsiteFromId($website->getId());
169
170
		if ($website->getName() !== $originalWebsite->getName()) {
171
			$website->assertValidName();
172
		}
173
		if ($website->getSite() !== $originalWebsite->getSite()) {
174
			$website->assertValidSite();
175
		}
176
		if ($website->getPath() !== $originalWebsite->getPath()) {
177
			$website->assertValidPath();
178
		}
179
		if ($website->getTheme() !== $originalWebsite->getTheme()) {
180
			$website->assertValidTheme();
181
		}
182
183
		$this->websiteRequest->update($website);
184
	}
185
186
	/**
187
	 * Deletes a website.
188
	 *
189
	 * Warning: This method does not check the ownership of the website!
190
	 * Please use {@see Website::assertOwnedBy()} beforehand.
191
	 *
192
	 * @param Website $website
193
	 *
194
	 * @throws WebsiteNotFoundException
195
	 */
196
	public function deleteWebsite(Website $website): void
197
	{
198
		// check whether website actually exists
199
		$this->websiteRequest->getWebsiteFromId($website->getId());
200
201
		$this->websiteRequest->delete($website);
202
	}
203
204
	/**
205
	 * @param string $userId
206
	 */
207
	public function deleteUserWebsites(string $userId): void
208
	{
209
		$this->websiteRequest->deleteAllFromUserId($userId);
210
	}
211
212
	/**
213
	 * @param int $siteId
214
	 *
215
	 * @return Website
216
	 * @throws WebsiteNotFoundException
217
	 */
218
	public function getWebsiteFromId(int $siteId): Website
219
	{
220
		return $this->websiteRequest->getWebsiteFromId($siteId);
221
	}
222
223
	/**
224
	 * @param string $site
225
	 *
226
	 * @return Website
227
	 * @throws WebsiteNotFoundException
228
	 */
229 3
	public function getWebsiteFromSite(string $site): Website
230
	{
231 3
		return $this->websiteRequest->getWebsiteFromSite($site);
232
	}
233
234
	/**
235
	 * @param string $userId
236
	 *
237
	 * @return Website[]
238
	 */
239 4
	public function getWebsitesFromUser(string $userId): array
240
	{
241 4
		return $this->websiteRequest->getWebsitesFromUserId($userId);
242
	}
243
244
	/**
245
	 * @param string      $site
246
	 * @param string      $page
247
	 * @param string|null $viewer
248
	 * @param bool        $proxyRequest
249
	 *
250
	 * @return PicoPage
251
	 * @throws WebsiteNotFoundException
252
	 * @throws WebsiteInvalidOwnerException
253
	 * @throws WebsiteInvalidFilesystemException
254
	 * @throws WebsiteNotPermittedException
255
	 * @throws FilesystemNotLocalException
256
	 * @throws PageInvalidPathException
257
	 * @throws PageNotFoundException
258
	 * @throws PageNotPermittedException
259
	 * @throws ThemeNotFoundException
260
	 * @throws ThemeNotCompatibleException
261
	 * @throws PicoRuntimeException
262
	 */
263 1
	public function getPage(string $site, string $page, ?string $viewer, bool $proxyRequest = false): PicoPage
264
	{
265
		try {
266 1
			$page = $this->miscService->normalizePath($page);
267
		} catch (InvalidPathException $e) {
268
			throw new PageInvalidPathException($e);
269
		}
270
271 1
		$website = $this->getWebsiteFromSite($site);
272
		$website->assertValidOwner();
273
274
		if (!$website->getWebsiteFolder()->isLocal()) {
275
			throw new FilesystemNotLocalException();
276
		}
277
278
		$websiteRequest = new WebsiteRequest($website, $viewer, $page, $proxyRequest);
279
		return $this->picoService->getPage($websiteRequest);
280
	}
281
282
	/**
283
	 * @param string      $site
284
	 * @param string      $asset
285
	 * @param string|null $viewer
286
	 *
287
	 * @return PicoAsset
288
	 * @throws WebsiteNotFoundException
289
	 * @throws WebsiteInvalidOwnerException
290
	 * @throws WebsiteInvalidFilesystemException
291
	 * @throws WebsiteNotPermittedException
292
	 * @throws FilesystemNotLocalException
293
	 * @throws AssetInvalidPathException
294
	 * @throws AssetNotFoundException
295
	 * @throws AssetNotPermittedException
296
	 */
297
	public function getAsset(string $site, string $asset, ?string $viewer): PicoAsset
298
	{
299
		try {
300
			$asset = $this->miscService->normalizePath($asset);
301
			if ($asset === '') {
302
				throw new InvalidPathException();
303
			}
304
		} catch (InvalidPathException $e) {
305
			throw new AssetInvalidPathException($e);
306
		}
307
308
		$website = $this->getWebsiteFromSite($site);
309
		$website->assertValidOwner();
310
311
		if (!$website->getWebsiteFolder()->isLocal()) {
312
			throw new FilesystemNotLocalException();
313
		}
314
315
		$websiteRequest = new WebsiteRequest($website, $viewer, PicoService::DIR_ASSETS . '/' . $asset);
316
		return $this->assetsService->getAsset($websiteRequest);
317
	}
318
319
	/**
320
	 * @param string[] $limitGroups
321
	 *
322
	 * @throws \UnexpectedValueException
323
	 */
324
	public function setLimitGroups(array $limitGroups): void
325
	{
326
		foreach ($limitGroups as $group) {
327
			if (!$this->groupManager->groupExists($group)) {
328
				throw new \UnexpectedValueException();
329
			}
330
		}
331
332
		$this->configService->setAppValue(ConfigService::LIMIT_GROUPS, json_encode($limitGroups));
333
	}
334
335
	/**
336
	 * @return string[]
337
	 */
338 3
	public function getLimitGroups(): array
339
	{
340 3
		$json = $this->configService->getAppValue(ConfigService::LIMIT_GROUPS);
341 3
		return $json ? json_decode($json, true) : [];
342
	}
343
344
	/**
345
	 * @param string|null $userId
346
	 *
347
	 * @return bool
348
	 */
349 3
	public function isUserAllowed(?string $userId): bool
350
	{
351 3
		if (!$userId) {
352
			return false;
353
		}
354
355 3
		$limitGroups = $this->getLimitGroups();
356 3
		if (!$limitGroups) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limitGroups of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
introduced by
$limitGroups is an empty array, thus ! $limitGroups is always true.
Loading history...
357 3
			return true;
358
		}
359
360
		foreach ($limitGroups as $groupId) {
361
			if ($this->groupManager->isInGroup($userId, $groupId)) {
362
				return true;
363
			}
364
		}
365
366
		return false;
367
	}
368
369
	/**
370
	 * @param int $linkMode
371
	 *
372
	 * @throws \UnexpectedValueException
373
	 */
374
	public function setLinkMode(int $linkMode): void
375
	{
376
		if (($linkMode !== self::LINK_MODE_LONG) && ($linkMode !== self::LINK_MODE_SHORT)) {
377
			throw new \UnexpectedValueException();
378
		}
379
380
		$this->configService->setAppValue(ConfigService::LINK_MODE, (string) $linkMode);
381
	}
382
383
	/**
384
	 * @return int
385
	 */
386
	public function getLinkMode(): int
387
	{
388
		return (int) $this->configService->getAppValue(ConfigService::LINK_MODE);
389
	}
390
}
391