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

Website::getTimeZone()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
ccs 4
cts 4
cp 1
rs 10
cc 2
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\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\TemplatesService;
38
use OCA\CMSPico\Service\ThemesService;
39
use OCA\CMSPico\Service\WebsitesService;
40
use OCP\Files\InvalidPathException;
41
use OCP\Files\NotFoundException;
42
use OCP\IConfig;
43
use OCP\IL10N;
44
use OCP\IURLGenerator;
45
use OCP\IUserManager;
46
47
class Website extends WebsiteCore
48
{
49
	/** @var int */
50
	public const SITE_LENGTH_MIN = 3;
51
52
	/** @var int */
53
	public const SITE_LENGTH_MAX = 255;
54
55
	/** @var string */
56
	public const SITE_REGEX = '^[a-z0-9][a-z0-9_-]+[a-z0-9]$';
57
58
	/** @var int */
59
	public const NAME_LENGTH_MIN = 3;
60
61
	/** @var int */
62
	public const NAME_LENGTH_MAX = 255;
63
64
	/** @var IConfig */
65
	private $config;
66
67
	/** @var IL10N */
68
	private $l10n;
69
70
	/** @var IUserManager */
71
	private $userManager;
72
73
	/** @var IURLGenerator */
74
	private $urlGenerator;
75
76
	/** @var WebsitesService */
77
	private $websitesService;
78
79
	/** @var ThemesService */
80
	private $themesService;
81
82
	/** @var TemplatesService */
83
	private $templatesService;
84
85
	/** @var MiscService */
86
	private $miscService;
87
88
	/** @var StorageFolder */
89
	private $folder;
90
91
	/**
92
	 * Website constructor.
93
	 *
94
	 * @param array|string|null $data
95
	 */
96
	public function __construct($data = null)
97
	{
98
		$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

98
		$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...
99
		$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

99
		$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...
100
		$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

100
		$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...
101
		$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

101
		$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...
102
		$this->websitesService = \OC::$server->query(WebsitesService::class);
1 ignored issue
show
Documentation Bug introduced by
It seems like OC::server->query(OCA\CM...WebsitesService::class) can also be of type stdClass. However, the property $websitesService is declared as type OCA\CMSPico\Service\WebsitesService. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
103
		$this->themesService = \OC::$server->query(ThemesService::class);
1 ignored issue
show
Documentation Bug introduced by
It seems like OC::server->query(OCA\CM...e\ThemesService::class) can also be of type stdClass. However, the property $themesService is declared as type OCA\CMSPico\Service\ThemesService. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
104
		$this->templatesService = \OC::$server->query(TemplatesService::class);
1 ignored issue
show
Documentation Bug introduced by
It seems like OC::server->query(OCA\CM...emplatesService::class) can also be of type stdClass. However, the property $templatesService is declared as type OCA\CMSPico\Service\TemplatesService. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
105
		$this->miscService = \OC::$server->query(MiscService::class);
1 ignored issue
show
Documentation Bug introduced by
It seems like OC::server->query(OCA\CM...ice\MiscService::class) can also be of type stdClass. However, the property $miscService is declared as type OCA\CMSPico\Service\MiscService. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
106
107 3
		parent::__construct($data);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type string; however, parameter $data of OCA\CMSPico\Model\WebsiteCore::__construct() does only seem to accept array|null, 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

107
		parent::__construct(/** @scrutinizer ignore-type */ $data);
Loading history...
108
	}
109 3
110 3
	/**
111 3
	 * @return string
112 3
	 */
113 3
	public function getTimeZone(): string
114 3
	{
115 3
		$serverTimeZone = date_default_timezone_get() ?: 'UTC';
116 3
		return $this->config->getUserValue($this->getUserId(), 'core', 'timezone', $serverTimeZone);
117 3
	}
118
119 3
	/**
120 3
	 * @throws WebsiteInvalidOwnerException
121
	 */
122
	public function assertValidOwner(): void
123
	{
124
		$user = $this->userManager->get($this->getUserId());
125
		if ($user === null) {
126
			throw new WebsiteInvalidOwnerException();
127
		}
128
		if (!$user->isEnabled()) {
129
			throw new WebsiteInvalidOwnerException();
130
		}
131
		if (!$this->websitesService->isUserAllowed($this->getUserId())) {
132
			throw new WebsiteInvalidOwnerException();
133
		}
134
	}
135
136
	/**
137
	 * @throws WebsiteInvalidDataException
138
	 */
139
	public function assertValidName(): void
140
	{
141
		if (strlen($this->getName()) < self::NAME_LENGTH_MIN) {
142
			throw new WebsiteInvalidDataException('name', $this->l10n->t('The name of the website must be longer.'));
143
		}
144
		if (strlen($this->getName()) > self::NAME_LENGTH_MAX) {
145
			throw new WebsiteInvalidDataException('name', $this->l10n->t('The name of the website is too long.'));
146
		}
147
	}
148
149
	/**
150
	 * @throws WebsiteInvalidDataException
151
	 */
152
	public function assertValidSite(): void
153
	{
154
		if (strlen($this->getSite()) < self::SITE_LENGTH_MIN) {
155
			$error = $this->l10n->t('The identifier of the website must be longer.');
156
			throw new WebsiteInvalidDataException('site', $error);
157
		}
158
		if (strlen($this->getSite()) > self::SITE_LENGTH_MAX) {
159
			$error = $this->l10n->t('The identifier of the website is too long.');
160
			throw new WebsiteInvalidDataException('site', $error);
161
		}
162
		if (preg_match('/' . self::SITE_REGEX . '/', $this->getSite()) !== 1) {
163
			$error = $this->l10n->t('The identifier of the website can only contain lowercase alpha numeric chars.');
164
			throw new WebsiteInvalidDataException('site', $error);
165
		}
166
	}
167
168
	/**
169
	 * @throws WebsiteInvalidDataException
170
	 */
171
	public function assertValidPath(): void
172
	{
173
		try {
174
			$path = $this->miscService->normalizePath($this->getPath());
175
			if ($path === '') {
176
				throw new InvalidPathException();
177
			}
178
		} catch (InvalidPathException $e) {
179
			throw new WebsiteInvalidDataException(
180
				'path',
181
				$this->l10n->t('The path of the website is invalid.')
182
			);
183
		}
184
185
		$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

185
		$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...
186
187
		try {
188
			$websiteBaseFolder = $userFolder->getFolder(dirname($path));
189
190
			try {
191
				$websiteFolder = $websiteBaseFolder->getFolder(basename($path));
192
193
				if (!$websiteFolder->isLocal()) {
194
					throw new WebsiteInvalidDataException(
195
						'path',
196
						$this->l10n->t('The website\'s path is stored on a non-local storage.')
197
					);
198
				}
199
			} catch (NotFoundException $e) {
200
				if (!$websiteBaseFolder->isLocal()) {
201
					throw new WebsiteInvalidDataException(
202
						'path',
203
						$this->l10n->t('The website\'s path is stored on a non-local storage.')
204
					);
205
				}
206
			}
207
		} catch (InvalidPathException | NotFoundException $e) {
208
			throw new WebsiteInvalidDataException(
209
				'path',
210
				$this->l10n->t('Parent folder of the website\'s path not found.')
211
			);
212
		}
213
	}
214
215
	/**
216
	 * @throws ThemeNotFoundException
217
	 * @throws ThemeNotCompatibleException
218
	 */
219
	public function assertValidTheme(): void
220
	{
221
		$this->themesService->assertValidTheme($this->getTheme());
222
	}
223
224
	/**
225 3
	 * @param string $userId
226
	 *
227 3
	 * @throws WebsiteForeignOwnerException
228 3
	 */
229
	public function assertOwnedBy(string $userId): void
230
	{
231 3
		if ($this->getUserId() !== $userId) {
232
			throw new WebsiteForeignOwnerException();
233
		}
234 3
	}
235
236
	/**
237 3
	 * @return StorageFolder
238
	 * @throws WebsiteInvalidFilesystemException
239
	 */
240
	public function getWebsiteFolder(): StorageFolder
241
	{
242 3
		if ($this->folder !== null) {
243
			try {
244 3
				// NC doesn't guarantee that mounts are present for the whole request lifetime
245
				// for example, if you call \OC\Files\Utils\Scanner::scan(), all mounts are reset
246
				// this makes OCNode instances, which rely on mounts of different users than the current, unusable
247 3
				// by calling OCFolder::get('') we can detect this situation and re-init the required mounts
248
				$this->folder->get('');
249
			} catch (\Exception $e) {
250 3
				$this->folder = null;
251
			}
252
		}
253
254
		if ($this->folder === null) {
255 3
			try {
256
				$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

256
				$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...
257 3
				$userFolder = new StorageFolder($ocUserFolder);
258
259
				$websiteFolder = $userFolder->getFolder($this->getPath());
260
				$this->folder = $websiteFolder->fakeRoot();
261 3
			} catch (InvalidPathException | NotFoundException $e) {
262
				throw new WebsiteInvalidFilesystemException($e);
263
			}
264
		}
265 3
266
		return $this->folder;
267
	}
268
269 3
	/**
270
	 * @return string
271
	 * @throws WebsiteInvalidFilesystemException
272
	 */
273
	public function getWebsitePath(): string
274 3
	{
275
		try {
276
			return $this->getWebsiteFolder()->getLocalPath() . '/';
277 3
		} catch (InvalidPathException | NotFoundException $e) {
278 3
			throw new WebsiteInvalidFilesystemException($e);
279 3
		}
280
	}
281
282
	/**
283
	 * @return string
284
	 */
285
	public function getWebsiteUrl(bool $proxyRequest = false): string
286
	{
287
		if (!$proxyRequest) {
288 3
			$route = Application::APP_NAME . '.Pico.getPage';
289
			$parameters = [ 'site' => $this->getSite(), 'page' => '' ];
290
			return $this->urlGenerator->linkToRoute($route, $parameters) . '/';
291 3
		} else {
292
			return \OC::$WEBROOT . '/sites/' . urlencode($this->getSite()) . '/';
293
		}
294 3
	}
295
}
296