Passed
Push — master ( 6b84e0...00c2c4 )
by Daniel
16:34
created

WebsitesService::getWebsites()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
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 $websitesRequest;
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 1
	public function __construct(
95
		WebsitesRequest $websiteRequest,
96
		IGroupManager $groupManager,
97
		ConfigService $configService,
98
		TemplatesService $templatesService,
99
		PicoService $picoService,
100
		AssetsService $assetsService,
101
		MiscService $miscService
102
	) {
103 1
		$this->websitesRequest = $websiteRequest;
104 1
		$this->groupManager = $groupManager;
105 1
		$this->configService = $configService;
106 1
		$this->templatesService = $templatesService;
107 1
		$this->picoService = $picoService;
108 1
		$this->assetsService = $assetsService;
109 1
		$this->miscService = $miscService;
110 1
	}
111
112
	/**
113
	 * Creates a new website.
114
	 *
115
	 * Warning: This method does not check whether the user is allowed to create websites!
116
	 * Please use {@see Website::assertValidOwner()} beforehand.
117
	 *
118
	 * @param Website $website
119
	 * @param string  $templateName
120
	 *
121
	 * @throws WebsiteExistsException
122
	 * @throws WebsiteInvalidDataException
123
	 * @throws WebsiteInvalidOwnerException
124
	 * @throws ThemeNotFoundException
125
	 * @throws ThemeNotCompatibleException
126
	 * @throws TemplateNotFoundException
127
	 * @throws TemplateNotCompatibleException
128
	 */
129 5
	public function createWebsite(Website $website, string $templateName): void
130
	{
131 5
		$website->assertValidName();
132 5
		$website->assertValidSite();
133 5
		$website->assertValidPath();
134 5
		$website->assertValidTheme();
135
136
		try {
137 5
			$this->websitesRequest->getWebsiteFromSite($website->getSite());
138 1
			throw new WebsiteExistsException();
139 5
		} catch (WebsiteNotFoundException $e) {
140
			// in fact we want the website not to exist yet
141
		}
142
143 4
		$this->templatesService->assertValidTemplate($templateName);
144 4
		$this->templatesService->installTemplate($website, $templateName);
145
146 4
		$this->websitesRequest->create($website);
147 4
	}
148
149
	/**
150
	 * Updates a website.
151
	 *
152
	 * Warning: This method does not check the ownership of the website!
153
	 * Please use {@see Website::assertOwnedBy()} beforehand.
154
	 *
155
	 * @param Website $website
156
	 *
157
	 * @throws WebsiteNotFoundException
158
	 * @throws WebsiteInvalidDataException
159
	 * @throws ThemeNotFoundException
160
	 * @throws ThemeNotCompatibleException
161
	 * @throws TemplateNotFoundException
162
	 * @throws TemplateNotCompatibleException
163
	 */
164 1
	public function updateWebsite(Website $website): void
165
	{
166 1
		$originalWebsite = $this->websitesRequest->getWebsiteFromId($website->getId());
167
168 1
		if ($website->getName() !== $originalWebsite->getName()) {
169
			$website->assertValidName();
170
		}
171 1
		if ($website->getSite() !== $originalWebsite->getSite()) {
172
			$website->assertValidSite();
173
		}
174 1
		if ($website->getPath() !== $originalWebsite->getPath()) {
175
			$website->assertValidPath();
176
		}
177 1
		if ($website->getTheme() !== $originalWebsite->getTheme()) {
178
			$website->assertValidTheme();
179
		}
180
181 1
		$this->websitesRequest->update($website);
182 1
	}
183
184
	/**
185
	 * Deletes a website.
186
	 *
187
	 * Warning: This method does not check the ownership of the website!
188
	 * Please use {@see Website::assertOwnedBy()} beforehand.
189
	 *
190
	 * @param Website $website
191
	 *
192
	 * @throws WebsiteNotFoundException
193
	 */
194 1
	public function deleteWebsite(Website $website): void
195
	{
196
		// check whether website actually exists
197 1
		$this->websitesRequest->getWebsiteFromId($website->getId());
198
199 1
		$this->websitesRequest->delete($website);
200 1
	}
201
202
	/**
203
	 * Deletes all websites of a user.
204
	 *
205
	 * Warning: This method does not check the ownership of the website!
206
	 * Please use {@see Website::assertOwnedBy()} beforehand.
207
	 *
208
	 * @param string $userId
209
	 */
210
	public function deleteUserWebsites(string $userId): void
211
	{
212
		$this->websitesRequest->deleteAllFromUserId($userId);
213
	}
214
215
	/**
216
	 * @param int $siteId
217
	 *
218
	 * @return Website
219
	 * @throws WebsiteNotFoundException
220
	 */
221 2
	public function getWebsiteFromId(int $siteId): Website
222
	{
223 2
		return $this->websitesRequest->getWebsiteFromId($siteId);
224
	}
225
226
	/**
227
	 * @param string $site
228
	 *
229
	 * @return Website
230
	 * @throws WebsiteNotFoundException
231
	 */
232 9
	public function getWebsiteFromSite(string $site): Website
233
	{
234 9
		return $this->websitesRequest->getWebsiteFromSite($site);
235
	}
236
237
	/**
238
	 * @param string $userId
239
	 *
240
	 * @return Website[]
241
	 */
242 6
	public function getWebsitesFromUser(string $userId): array
243
	{
244 6
		return $this->websitesRequest->getWebsitesFromUserId($userId);
245
	}
246
247
	/**
248
	 * @return Website[]
249
	 */
250
	public function getWebsites(): array
251
	{
252
		return $this->websitesRequest->getWebsites();
253
	}
254
255
	/**
256
	 * @param string      $site
257
	 * @param string      $page
258
	 * @param string|null $viewer
259
	 * @param bool        $proxyRequest
260
	 *
261
	 * @return PicoPage
262
	 * @throws WebsiteNotFoundException
263
	 * @throws WebsiteInvalidOwnerException
264
	 * @throws WebsiteInvalidFilesystemException
265
	 * @throws WebsiteNotPermittedException
266
	 * @throws FilesystemNotLocalException
267
	 * @throws PageInvalidPathException
268
	 * @throws PageNotFoundException
269
	 * @throws PageNotPermittedException
270
	 * @throws ThemeNotFoundException
271
	 * @throws ThemeNotCompatibleException
272
	 * @throws PicoRuntimeException
273
	 */
274 6
	public function getPage(string $site, string $page, ?string $viewer, bool $proxyRequest = false): PicoPage
275
	{
276
		try {
277 6
			$page = $this->miscService->normalizePath($page);
278
		} catch (InvalidPathException $e) {
279
			throw new PageInvalidPathException($e);
280
		}
281
282 6
		$website = $this->getWebsiteFromSite($site);
283 6
		$website->assertValidOwner();
284
285 6
		if (!$website->getWebsiteFolder()->isLocal()) {
286
			throw new FilesystemNotLocalException();
287
		}
288
289 6
		$websiteRequest = new WebsiteRequest($website, $viewer, $page, $proxyRequest);
290 6
		return $this->picoService->getPage($websiteRequest);
291
	}
292
293
	/**
294
	 * @param string      $site
295
	 * @param string      $asset
296
	 * @param string|null $viewer
297
	 *
298
	 * @return PicoAsset
299
	 * @throws WebsiteNotFoundException
300
	 * @throws WebsiteInvalidOwnerException
301
	 * @throws WebsiteInvalidFilesystemException
302
	 * @throws WebsiteNotPermittedException
303
	 * @throws FilesystemNotLocalException
304
	 * @throws AssetInvalidPathException
305
	 * @throws AssetNotFoundException
306
	 * @throws AssetNotPermittedException
307
	 */
308 3
	public function getAsset(string $site, string $asset, ?string $viewer): PicoAsset
309
	{
310
		try {
311 3
			$asset = $this->miscService->normalizePath($asset);
312 3
			if ($asset === '') {
313 3
				throw new InvalidPathException();
314
			}
315
		} catch (InvalidPathException $e) {
316
			throw new AssetInvalidPathException($e);
317
		}
318
319 3
		$website = $this->getWebsiteFromSite($site);
320 3
		$website->assertValidOwner();
321
322 3
		if (!$website->getWebsiteFolder()->isLocal()) {
323
			throw new FilesystemNotLocalException();
324
		}
325
326 3
		$websiteRequest = new WebsiteRequest($website, $viewer, PicoService::DIR_ASSETS . '/' . $asset);
327 3
		return $this->assetsService->getAsset($websiteRequest);
328
	}
329
330
	/**
331
	 * @param string[] $limitGroups
332
	 *
333
	 * @throws \UnexpectedValueException
334
	 */
335
	public function setLimitGroups(array $limitGroups): void
336
	{
337
		foreach ($limitGroups as $group) {
338
			if (!$this->groupManager->groupExists($group)) {
339
				throw new \UnexpectedValueException();
340
			}
341
		}
342
343
		$this->configService->setAppValue(ConfigService::LIMIT_GROUPS, json_encode($limitGroups));
344
	}
345
346
	/**
347
	 * @return string[]
348
	 */
349 12
	public function getLimitGroups(): array
350
	{
351 12
		$json = $this->configService->getAppValue(ConfigService::LIMIT_GROUPS);
352 12
		return $json ? json_decode($json, true) : [];
353
	}
354
355
	/**
356
	 * @param string|null $userId
357
	 *
358
	 * @return bool
359
	 */
360 12
	public function isUserAllowed(?string $userId): bool
361
	{
362 12
		if (!$userId) {
363
			return false;
364
		}
365
366 12
		$limitGroups = $this->getLimitGroups();
367 12
		if (empty($limitGroups)) {
368 12
			return true;
369
		}
370
371
		foreach ($limitGroups as $groupId) {
372
			if ($this->groupManager->isInGroup($userId, $groupId)) {
373
				return true;
374
			}
375
		}
376
377
		return false;
378
	}
379
380
	/**
381
	 * @param int $linkMode
382
	 *
383
	 * @throws \UnexpectedValueException
384
	 */
385
	public function setLinkMode(int $linkMode): void
386
	{
387
		if (($linkMode !== self::LINK_MODE_LONG) && ($linkMode !== self::LINK_MODE_SHORT)) {
388
			throw new \UnexpectedValueException();
389
		}
390
391
		$this->configService->setAppValue(ConfigService::LINK_MODE, (string) $linkMode);
392
	}
393
394
	/**
395
	 * @return int
396
	 */
397
	public function getLinkMode(): int
398
	{
399
		return (int) $this->configService->getAppValue(ConfigService::LINK_MODE);
400
	}
401
}
402