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

Website::getWebsitePath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 6
ccs 0
cts 4
cp 0
rs 10
cc 2
nc 2
nop 0
crap 6
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\TemplateNotCompatibleException;
30
use OCA\CMSPico\Exceptions\TemplateNotFoundException;
31
use OCA\CMSPico\Exceptions\ThemeNotCompatibleException;
32
use OCA\CMSPico\Exceptions\ThemeNotFoundException;
33
use OCA\CMSPico\Exceptions\WebsiteForeignOwnerException;
34
use OCA\CMSPico\Exceptions\WebsiteInvalidDataException;
35
use OCA\CMSPico\Exceptions\WebsiteInvalidFilesystemException;
36
use OCA\CMSPico\Exceptions\WebsiteInvalidOwnerException;
37
use OCA\CMSPico\Exceptions\WebsiteNotPermittedException;
38
use OCA\CMSPico\Files\StorageFile;
39
use OCA\CMSPico\Files\StorageFolder;
40
use OCA\CMSPico\Service\MiscService;
41
use OCA\CMSPico\Service\TemplatesService;
42
use OCA\CMSPico\Service\ThemesService;
43
use OCA\CMSPico\Service\WebsitesService;
44
use OCP\Files\Folder as OCFolder;
45
use OCP\Files\InvalidPathException;
46
use OCP\Files\Node as OCNode;
47
use OCP\Files\NotFoundException;
48
use OCP\Files\NotPermittedException;
49
use OCP\IConfig;
50
use OCP\IGroupManager;
51
use OCP\IL10N;
52
use OCP\IURLGenerator;
53
use OCP\IUserManager;
54
55
class Website extends WebsiteCore
56
{
57
	/** @var int */
58
	public const SITE_LENGTH_MIN = 3;
59
60
	/** @var int */
61
	public const SITE_LENGTH_MAX = 255;
62
63
	/** @var string */
64
	public const SITE_REGEX = '^[a-z0-9][a-z0-9_-]+[a-z0-9]$';
65
66
	/** @var int */
67
	public const NAME_LENGTH_MIN = 3;
68
69
	/** @var int */
70
	public const NAME_LENGTH_MAX = 255;
71
72
	/** @var IConfig */
73
	private $config;
74
75
	/** @var IL10N */
76
	private $l10n;
77
78
	/** @var IUserManager */
79
	private $userManager;
80
81
	/** @var IGroupManager */
82
	private $groupManager;
83
84
	/** @var IURLGenerator */
85
	private $urlGenerator;
86
87
	/** @var WebsitesService */
88
	private $websitesService;
89
90
	/** @var ThemesService */
91
	private $themesService;
92
93
	/** @var TemplatesService */
94
	private $templatesService;
95
96
	/** @var MiscService */
97
	private $miscService;
98
99
	/** @var StorageFolder */
100
	private $folder;
101
102
	/**
103
	 * Website constructor.
104
	 *
105
	 * @param array|string|null $data
106
	 */
107 3
	public function __construct($data = null)
108
	{
109 3
		$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

109
		$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...
110 3
		$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

110
		$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...
111 3
		$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

111
		$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...
112 3
		$this->groupManager = \OC::$server->getGroupManager();
0 ignored issues
show
Deprecated Code introduced by
The function OC\Server::getGroupManager() 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

112
		$this->groupManager = /** @scrutinizer ignore-deprecated */ \OC::$server->getGroupManager();

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...
113 3
		$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

113
		$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...
114 3
		$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...
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

114
		$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...
115 3
		$this->themesService = \OC::$server->query(ThemesService::class);
1 ignored issue
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

115
		$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...
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...
116 3
		$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...
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

116
		$this->templatesService = /** @scrutinizer ignore-deprecated */ \OC::$server->query(TemplatesService::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...
117 3
		$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...
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

117
		$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...
118
119 3
		parent::__construct($data);
120 3
	}
121
122
	/**
123
	 * @return string
124
	 */
125
	public function getTimeZone(): string
126
	{
127
		$serverTimeZone = date_default_timezone_get() ?: 'UTC';
128
		return $this->config->getUserValue($this->getUserId(), 'core', 'timezone', $serverTimeZone);
129
	}
130
131
	/**
132
	 * @param string $path
133
	 * @param array  $meta
134
	 *
135
	 * @throws InvalidPathException
136
	 * @throws WebsiteInvalidFilesystemException
137
	 * @throws WebsiteNotPermittedException
138
	 * @throws NotPermittedException
139
	 */
140
	public function assertViewerAccess(string $path, array $meta = []): void
141
	{
142
		$exceptionClass = WebsiteNotPermittedException::class;
143
		if ($this->getType() === self::TYPE_PUBLIC) {
144
			if (empty($meta['access'])) {
145
				return;
146
			}
147
148
			$groupAccess = $meta['access'];
149
			if (!is_array($groupAccess)) {
150
				$groupAccess = explode(',', $groupAccess);
151
			}
152
153
			foreach ($groupAccess as $group) {
154
				$group = trim($group);
155
156
				if ($group === 'public') {
157
					return;
158
				} elseif ($group === 'private') {
159
					continue;
160
				}
161
162
				if ($this->getViewer() && $this->groupManager->groupExists($group)) {
163
					if ($this->groupManager->isInGroup($this->getViewer(), $group)) {
164
						return;
165
					}
166
				}
167
			}
168
169
			$exceptionClass = NotPermittedException::class;
170
		}
171
172
		if ($this->getViewer()) {
173
			if ($this->getViewer() === $this->getUserId()) {
174
				return;
175
			}
176
177
			/** @var OCFolder $viewerOCFolder */
178
			$viewerOCFolder = \OC::$server->getUserFolder($this->getViewer());
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

178
			$viewerOCFolder = /** @scrutinizer ignore-deprecated */ \OC::$server->getUserFolder($this->getViewer());

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...
179
			$viewerAccessClosure = function (OCNode $node) use ($viewerOCFolder) {
180
				$nodeId = $node->getId();
181
182
				$viewerNodes = $viewerOCFolder->getById($nodeId);
183
				foreach ($viewerNodes as $viewerNode) {
184
					if ($viewerNode->isReadable()) {
185
						return true;
186
					}
187
				}
188
189
				return false;
190
			};
191
192
			$websiteFolder = $this->getWebsiteFolder();
193
194
			$path = $this->miscService->normalizePath($path);
195
			while ($path && ($path !== '.')) {
196
				try {
197
					/** @var StorageFile|StorageFolder $file */
198
					$file = $websiteFolder->get($path);
199
				} catch (NotFoundException $e) {
200
					$file = null;
201
				}
202
203
				if ($file) {
204
					if ($viewerAccessClosure($file->getOCNode())) {
205
						return;
206
					}
207
208
					throw new $exceptionClass();
209
				}
210
211
				$path = dirname($path);
212
			}
213
214
			if ($viewerAccessClosure($websiteFolder->getOCNode())) {
215
				return;
216
			}
217
		}
218
219
		throw new $exceptionClass();
220
	}
221
222
	/**
223
	 * @throws WebsiteInvalidOwnerException
224
	 */
225 3
	public function assertValidOwner(): void
226
	{
227 3
		$user = $this->userManager->get($this->getUserId());
228 3
		if ($user === null) {
229
			throw new WebsiteInvalidOwnerException();
230
		}
231 3
		if (!$user->isEnabled()) {
232
			throw new WebsiteInvalidOwnerException();
233
		}
234 3
		if (!$this->websitesService->isUserAllowed($this->getUserId())) {
235
			throw new WebsiteInvalidOwnerException();
236
		}
237 3
	}
238
239
	/**
240
	 * @throws WebsiteInvalidDataException
241
	 */
242 3
	public function assertValidName(): void
243
	{
244 3
		if (strlen($this->getName()) < self::NAME_LENGTH_MIN) {
245
			throw new WebsiteInvalidDataException('name', $this->l10n->t('The name of the website must be longer.'));
246
		}
247 3
		if (strlen($this->getName()) > self::NAME_LENGTH_MAX) {
248
			throw new WebsiteInvalidDataException('name', $this->l10n->t('The name of the website is too long.'));
249
		}
250 3
	}
251
252
	/**
253
	 * @throws WebsiteInvalidDataException
254
	 */
255 3
	public function assertValidSite(): void
256
	{
257 3
		if (strlen($this->getSite()) < self::SITE_LENGTH_MIN) {
258
			$error = $this->l10n->t('The identifier of the website must be longer.');
259
			throw new WebsiteInvalidDataException('site', $error);
260
		}
261 3
		if (strlen($this->getSite()) > self::SITE_LENGTH_MAX) {
262
			$error = $this->l10n->t('The identifier of the website is too long.');
263
			throw new WebsiteInvalidDataException('site', $error);
264
		}
265 3
		if (preg_match('/' . self::SITE_REGEX . '/', $this->getSite()) !== 1) {
266
			$error = $this->l10n->t('The identifier of the website can only contain lowercase alpha numeric chars.');
267
			throw new WebsiteInvalidDataException('site', $error);
268
		}
269 3
	}
270
271
	/**
272
	 * @throws WebsiteInvalidDataException
273
	 */
274 3
	public function assertValidPath(): void
275
	{
276
		try {
277 3
			$path = $this->miscService->normalizePath($this->getPath());
278 3
			if ($path === '') {
279 3
				throw new InvalidPathException();
280
			}
281
		} catch (InvalidPathException $e) {
282
			throw new WebsiteInvalidDataException(
283
				'path',
284
				$this->l10n->t('The path of the website is invalid.')
285
			);
286
		}
287
288 3
		$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

288
		$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...
289
290
		try {
291 3
			$websiteBaseFolder = $userFolder->getFolder(dirname($path));
292
293
			try {
294 3
				$websiteFolder = $websiteBaseFolder->getFolder(basename($path));
295
296
				if (!$websiteFolder->isLocal()) {
297
					throw new WebsiteInvalidDataException(
298
						'path',
299
						$this->l10n->t('The website\'s path is stored on a non-local storage.')
300
					);
301
				}
302 3
			} catch (NotFoundException $e) {
303 3
				if (!$websiteBaseFolder->isLocal()) {
304
					throw new WebsiteInvalidDataException(
305
						'path',
306 3
						$this->l10n->t('The website\'s path is stored on a non-local storage.')
307
					);
308
				}
309
			}
310
		} catch (InvalidPathException | NotFoundException $e) {
311
			throw new WebsiteInvalidDataException(
312
				'path',
313
				$this->l10n->t('Parent folder of the website\'s path not found.')
314
			);
315
		}
316 3
	}
317
318
	/**
319
	 * @throws ThemeNotFoundException
320
	 * @throws ThemeNotCompatibleException
321
	 */
322 3
	public function assertValidTheme(): void
323
	{
324 3
		$this->themesService->assertValidTheme($this->getTheme());
325 3
	}
326
327
	/**
328
	 * @throws TemplateNotFoundException
329
	 * @throws TemplateNotCompatibleException
330
	 */
331 3
	public function assertValidTemplate(): void
332
	{
333 3
		$this->templatesService->assertValidTemplate($this->getTemplateSource());
334 3
	}
335
336
	/**
337
	 * @param string $userId
338
	 *
339
	 * @throws WebsiteForeignOwnerException
340
	 */
341
	public function assertOwnedBy(string $userId): void
342
	{
343
		if ($this->getUserId() !== $userId) {
344
			throw new WebsiteForeignOwnerException();
345
		}
346
	}
347
348
	/**
349
	 * @return StorageFolder
350
	 * @throws WebsiteInvalidFilesystemException
351
	 */
352
	public function getWebsiteFolder(): StorageFolder
353
	{
354
		if ($this->folder !== null) {
355
			try {
356
				// NC doesn't guarantee that mounts are present for the whole request lifetime
357
				// for example, if you call \OC\Files\Utils\Scanner::scan(), all mounts are reset
358
				// this makes OCNode instances, which rely on mounts of different users than the current, unusable
359
				// by calling OCFolder::get('') we can detect this situation and re-init the required mounts
360
				$this->folder->get('');
361
			} catch (\Exception $e) {
362
				$this->folder = null;
363
			}
364
		}
365
366
		if ($this->folder === null) {
367
			try {
368
				$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

368
				$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...
369
				$userFolder = new StorageFolder($ocUserFolder);
370
371
				$websiteFolder = $userFolder->getFolder($this->getPath());
372
				$this->folder = $websiteFolder->fakeRoot();
373
			} catch (InvalidPathException | NotFoundException $e) {
374
				throw new WebsiteInvalidFilesystemException($e);
375
			}
376
		}
377
378
		return $this->folder;
379
	}
380
381
	/**
382
	 * @return string
383
	 * @throws WebsiteInvalidFilesystemException
384
	 */
385
	public function getWebsitePath(): string
386
	{
387
		try {
388
			return $this->getWebsiteFolder()->getLocalPath() . '/';
389
		} catch (InvalidPathException | NotFoundException $e) {
390
			throw new WebsiteInvalidFilesystemException($e);
391
		}
392
	}
393
394
	/**
395
	 * @return string
396
	 */
397
	public function getWebsiteUrl(): string
398
	{
399
		if (!$this->getProxyRequest()) {
400
			$route = Application::APP_NAME . '.Pico.getPage';
401
			$parameters = [ 'site' => $this->getSite(), 'page' => '' ];
402
			return $this->urlGenerator->linkToRoute($route, $parameters) . '/';
403
		} else {
404
			return \OC::$WEBROOT . '/sites/' . urlencode($this->getSite()) . '/';
405
		}
406
	}
407
}
408