Test Failed
Push — master ( dc798f...d76e2d )
by Daniel
48:22
created

WebsitesService::getWebsiteFromId()   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 1
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 OCP\Files\InvalidPathException;
51
use OCP\IGroupManager;
52
53
class WebsitesService
54
{
55
	/** @var int */
56
	public const LINK_MODE_LONG = 1;
57
58
	/** @var int */
59
	public const LINK_MODE_SHORT = 2;
60
61
	/** @var WebsitesRequest */
62
	private $websiteRequest;
63
64
	/** @var IGroupManager */
65
	private $groupManager;
66
67
	/** @var ConfigService */
68
	private $configService;
69
70
	/** @var TemplatesService */
71
	private $templatesService;
72
73
	/** @var PicoService */
74
	private $picoService;
75
76
	/** @var AssetsService */
77
	private $assetsService;
78
79
	/** @var MiscService */
80
	private $miscService;
81
82
	/**
83
	 * WebsitesService constructor.
84
	 *
85
	 * @param WebsitesRequest  $websiteRequest
86
	 * @param IGroupManager    $groupManager
87
	 * @param ConfigService    $configService
88
	 * @param TemplatesService $templatesService
89
	 * @param PicoService      $picoService
90
	 * @param AssetsService    $assetsService
91
	 * @param MiscService      $miscService
92
	 *
93
	 * @internal param Manager $encryptionManager
94
	 */
95 1
	public function __construct(
96
		WebsitesRequest $websiteRequest,
97
		IGroupManager $groupManager,
98
		ConfigService $configService,
99
		TemplatesService $templatesService,
100
		PicoService $picoService,
101
		AssetsService $assetsService,
102
		MiscService $miscService
103
	) {
104 1
		$this->websiteRequest = $websiteRequest;
105 1
		$this->groupManager = $groupManager;
106 1
		$this->configService = $configService;
107 1
		$this->templatesService = $templatesService;
108 1
		$this->picoService = $picoService;
109 1
		$this->assetsService = $assetsService;
110 1
		$this->miscService = $miscService;
111 1
	}
112
113
	/**
114
	 * Creates a new website.
115
	 *
116
	 * @param Website $website
117
	 *
118
	 * @throws WebsiteExistsException
119
	 * @throws WebsiteInvalidDataException
120
	 * @throws WebsiteInvalidOwnerException
121
	 * @throws ThemeNotFoundException
122
	 * @throws ThemeNotCompatibleException
123
	 * @throws TemplateNotFoundException
124
	 * @throws TemplateNotCompatibleException
125
	 */
126 3
	public function createWebsite(Website $website): void
127
	{
128 3
		$website->assertValidOwner();
129 3
		$website->assertValidName();
130 3
		$website->assertValidSite();
131 3
		$website->assertValidPath();
132 3
		$website->assertValidTheme();
133 3
		$website->assertValidTemplate();
134
135
		try {
136 3
			$website = $this->websiteRequest->getWebsiteFromSite($website->getSite());
137
			throw new WebsiteExistsException();
138 3
		} catch (WebsiteNotFoundException $e) {
139
			// in fact we want the website not to exist yet
140
		}
141
142 3
		$this->templatesService->installTemplate($website);
143
		$this->websiteRequest->create($website);
144
	}
145
146
	/**
147
	 * Updates a website.
148
	 *
149
	 * Warning: This method does not check the ownership of the website!
150
	 * Please use {@see Website::assertOwnedBy()} beforehand.
151
	 *
152
	 * @param Website $website
153
	 *
154
	 * @throws WebsiteNotFoundException
155
	 * @throws WebsiteInvalidDataException
156
	 * @throws ThemeNotFoundException
157
	 * @throws ThemeNotCompatibleException
158
	 * @throws TemplateNotFoundException
159
	 * @throws TemplateNotCompatibleException
160
	 */
161
	public function updateWebsite(Website $website): void
162
	{
163
		$originalWebsite = $this->websiteRequest->getWebsiteFromId($website->getId());
164
165
		if ($website->getName() !== $originalWebsite->getName()) {
166
			$website->assertValidName();
167
		}
168
		if ($website->getSite() !== $originalWebsite->getSite()) {
169
			$website->assertValidSite();
170
		}
171
		if ($website->getPath() !== $originalWebsite->getPath()) {
172
			$website->assertValidPath();
173
		}
174
		if ($website->getTheme() !== $originalWebsite->getTheme()) {
175
			$website->assertValidTheme();
176
		}
177
		if ($website->getTemplateSource()) {
178
			if ($website->getTemplateSource() !== $originalWebsite->getTemplateSource()) {
179
				$website->assertValidTemplate();
180
			}
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 onUserRemoved(string $userId): void
208
	{
209
		$this->websiteRequest->deleteAllFromUser($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->setProxyRequest($proxyRequest);
273
		$website->setViewer($viewer ?: '');
274
		$website->setPage($page);
275
276
		$website->assertValidOwner();
277
278
		if (!$website->getWebsiteFolder()->isLocal()) {
279
			throw new FilesystemNotLocalException();
280
		}
281
282
		return $this->picoService->getPage($website);
283
	}
284
285
	/**
286
	 * @param string      $site
287
	 * @param string      $asset
288
	 * @param string|null $viewer
289
	 *
290
	 * @return PicoAsset
291
	 * @throws WebsiteNotFoundException
292
	 * @throws WebsiteInvalidOwnerException
293
	 * @throws WebsiteInvalidFilesystemException
294
	 * @throws WebsiteNotPermittedException
295
	 * @throws FilesystemNotLocalException
296
	 * @throws AssetInvalidPathException
297
	 * @throws AssetNotFoundException
298
	 * @throws AssetNotPermittedException
299
	 */
300
	public function getAsset(string $site, string $asset, ?string $viewer): PicoAsset
301
	{
302
		try {
303
			$asset = $this->miscService->normalizePath($asset);
304
			if ($asset === '') {
305
				throw new InvalidPathException();
306
			}
307
		} catch (InvalidPathException $e) {
308
			throw new AssetInvalidPathException($e);
309
		}
310
311
		$website = $this->getWebsiteFromSite($site);
312
		$website->setViewer($viewer ?: '');
313
		$website->setPage(PicoService::DIR_ASSETS . '/' . $asset);
314
315
		$website->assertValidOwner();
316
317
		if (!$website->getWebsiteFolder()->isLocal()) {
318
			throw new FilesystemNotLocalException();
319
		}
320
321
		return $this->assetsService->getAsset($website);
322
	}
323
324
	/**
325
	 * @param string[] $limitGroups
326
	 *
327
	 * @throws \UnexpectedValueException
328
	 */
329
	public function setLimitGroups(array $limitGroups): void
330
	{
331
		foreach ($limitGroups as $group) {
332
			if (!$this->groupManager->groupExists($group)) {
333
				throw new \UnexpectedValueException();
334
			}
335
		}
336
337
		$this->configService->setAppValue(ConfigService::LIMIT_GROUPS, json_encode($limitGroups));
338
	}
339
340
	/**
341
	 * @return string[]
342
	 */
343 3
	public function getLimitGroups(): array
344
	{
345 3
		$json = $this->configService->getAppValue(ConfigService::LIMIT_GROUPS);
346 3
		return $json ? json_decode($json, true) : [];
347
	}
348
349
	/**
350
	 * @param string|null $userId
351
	 *
352
	 * @return bool
353
	 */
354 3
	public function isUserAllowed(?string $userId): bool
355
	{
356 3
		if (!$userId) {
357
			return false;
358
		}
359
360 3
		$limitGroups = $this->getLimitGroups();
361 3
		if (empty($limitGroups)) {
362 3
			return true;
363
		}
364
365
		foreach ($this->getLimitGroups() as $group) {
366
			if ($this->groupManager->isInGroup($userId, $group)) {
367
				return true;
368
			}
369
		}
370
371
		return false;
372
	}
373
374
	/**
375
	 * @param int $linkMode
376
	 *
377
	 * @throws \UnexpectedValueException
378
	 */
379
	public function setLinkMode(int $linkMode): void
380
	{
381
		if (($linkMode !== self::LINK_MODE_LONG) && ($linkMode !== self::LINK_MODE_SHORT)) {
382
			throw new \UnexpectedValueException();
383
		}
384
385
		$this->configService->setAppValue(ConfigService::LINK_MODE, $linkMode);
386
	}
387
388
	/**
389
	 * @return int
390
	 */
391
	public function getLinkMode(): int
392
	{
393
		return (int) $this->configService->getAppValue(ConfigService::LINK_MODE);
394
	}
395
}
396