Completed
Push — master ( 968d4f...0def38 )
by Julius
43s
created

AppSettingsController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 19

Duplication

Lines 20
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 19
nc 1
nop 10
dl 20
loc 20
rs 9.4285
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 * @copyright Copyright (c) 2016, Lukas Reschke <[email protected]>
5
 *
6
 * @author Christoph Wurst <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OC\Settings\Controller;
29
30
use OC\App\AppStore\Bundles\BundleFetcher;
31
use OC\App\AppStore\Fetcher\AppFetcher;
32
use OC\App\AppStore\Fetcher\CategoryFetcher;
33
use OC\App\AppStore\Version\VersionParser;
34
use OC\App\DependencyAnalyzer;
35
use OC\App\Platform;
36
use OCP\App\IAppManager;
37
use \OCP\AppFramework\Controller;
38
use OCP\AppFramework\Http\ContentSecurityPolicy;
39
use OCP\AppFramework\Http\JSONResponse;
40
use OCP\AppFramework\Http\TemplateResponse;
41
use OCP\INavigationManager;
42
use OCP\IRequest;
43
use OCP\IL10N;
44
use OCP\IConfig;
45
use OCP\L10N\IFactory;
46
47
/**
48
 * @package OC\Settings\Controller
49
 */
50
class AppSettingsController extends Controller {
51
	const CAT_ENABLED = 0;
52
	const CAT_DISABLED = 1;
53
	const CAT_ALL_INSTALLED = 2;
54
	const CAT_APP_BUNDLES = 3;
55
	const CAT_UPDATES = 4;
56
57
	/** @var \OCP\IL10N */
58
	private $l10n;
59
	/** @var IConfig */
60
	private $config;
61
	/** @var INavigationManager */
62
	private $navigationManager;
63
	/** @var IAppManager */
64
	private $appManager;
65
	/** @var CategoryFetcher */
66
	private $categoryFetcher;
67
	/** @var AppFetcher */
68
	private $appFetcher;
69
	/** @var IFactory */
70
	private $l10nFactory;
71
	/** @var BundleFetcher */
72
	private $bundleFetcher;
73
74
	/**
75
	 * @param string $appName
76
	 * @param IRequest $request
77
	 * @param IL10N $l10n
78
	 * @param IConfig $config
79
	 * @param INavigationManager $navigationManager
80
	 * @param IAppManager $appManager
81
	 * @param CategoryFetcher $categoryFetcher
82
	 * @param AppFetcher $appFetcher
83
	 * @param IFactory $l10nFactory
84
	 * @param BundleFetcher $bundleFetcher
85
	 */
86 View Code Duplication
	public function __construct($appName,
87
								IRequest $request,
88
								IL10N $l10n,
89
								IConfig $config,
90
								INavigationManager $navigationManager,
91
								IAppManager $appManager,
92
								CategoryFetcher $categoryFetcher,
93
								AppFetcher $appFetcher,
94
								IFactory $l10nFactory,
95
								BundleFetcher $bundleFetcher) {
96
		parent::__construct($appName, $request);
97
		$this->l10n = $l10n;
98
		$this->config = $config;
99
		$this->navigationManager = $navigationManager;
100
		$this->appManager = $appManager;
101
		$this->categoryFetcher = $categoryFetcher;
102
		$this->appFetcher = $appFetcher;
103
		$this->l10nFactory = $l10nFactory;
104
		$this->bundleFetcher = $bundleFetcher;
105
	}
106
107
	/**
108
	 * @NoCSRFRequired
109
	 *
110
	 * @param string $category
111
	 * @return TemplateResponse
112
	 */
113
	public function viewApps($category = '') {
114
		if ($category === '') {
115
			$category = 'installed';
116
		}
117
118
		$params = [];
119
		$params['category'] = $category;
120
		$params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
121
		$this->navigationManager->setActiveEntry('core_apps');
122
123
		$templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user');
124
		$policy = new ContentSecurityPolicy();
125
		$policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
126
		$templateResponse->setContentSecurityPolicy($policy);
127
128
		return $templateResponse;
129
	}
130
131
	private function getAllCategories() {
132
		$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
133
134
		$updateCount = count($this->getAppsWithUpdates());
135
		$formattedCategories = [
136
			['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string)$this->l10n->t('Your apps')],
137
			['id' => self::CAT_UPDATES, 'ident' => 'updates', 'displayName' => (string)$this->l10n->t('Updates'), 'counter' => $updateCount],
138
			['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled apps')],
139
			['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Disabled apps')],
140
			['id' => self::CAT_APP_BUNDLES, 'ident' => 'app-bundles', 'displayName' => (string)$this->l10n->t('App bundles')],
141
		];
142
		$categories = $this->categoryFetcher->get();
143
		foreach($categories as $category) {
144
			$formattedCategories[] = [
145
				'id' => $category['id'],
146
				'ident' => $category['id'],
147
				'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
148
			];
149
		}
150
151
		return $formattedCategories;
152
	}
153
154
	/**
155
	 * Get all available categories
156
	 *
157
	 * @return JSONResponse
158
	 */
159
	public function listCategories() {
160
		return new JSONResponse($this->getAllCategories());
161
	}
162
163
	/**
164
	 * Get all apps for a category
165
	 *
166
	 * @param string $requestedCategory
167
	 * @return array
168
	 */
169
	private function getAppsForCategory($requestedCategory) {
170
		$versionParser = new VersionParser();
171
		$formattedApps = [];
172
		$apps = $this->appFetcher->get();
173
		foreach($apps as $app) {
174
			if (isset($app['isFeatured'])) {
175
				$app['featured'] = $app['isFeatured'];
176
			}
177
178
			// Skip all apps not in the requested category
179
			$isInCategory = false;
180
			foreach($app['categories'] as $category) {
181
				if($category === $requestedCategory) {
182
					$isInCategory = true;
183
				}
184
			}
185
			if(!$isInCategory) {
186
				continue;
187
			}
188
189
			$nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
190
			$nextCloudVersionDependencies = [];
191
			if($nextCloudVersion->getMinimumVersion() !== '') {
192
				$nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
193
			}
194
			if($nextCloudVersion->getMaximumVersion() !== '') {
195
				$nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
196
			}
197
			$phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
198
			$existsLocally = (\OC_App::getAppPath($app['id']) !== false) ? true : false;
199
			$phpDependencies = [];
200
			if($phpVersion->getMinimumVersion() !== '') {
201
				$phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
202
			}
203
			if($phpVersion->getMaximumVersion() !== '') {
204
				$phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
205
			}
206
			if(isset($app['releases'][0]['minIntSize'])) {
207
				$phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
208
			}
209
			$authors = '';
210
			foreach($app['authors'] as $key => $author) {
211
				$authors .= $author['name'];
212
				if($key !== count($app['authors']) - 1) {
213
					$authors .= ', ';
214
				}
215
			}
216
217
			$currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
218
			$enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
219
			$groups = null;
220
			if($enabledValue !== 'no' && $enabledValue !== 'yes') {
221
				$groups = $enabledValue;
222
			}
223
224
			$currentVersion = '';
225
			if($this->appManager->isInstalled($app['id'])) {
226
				$currentVersion = \OC_App::getAppVersion($app['id']);
227
			} else {
228
				$currentLanguage = $app['releases'][0]['version'];
229
			}
230
231
			$formattedApps[] = [
232
				'id' => $app['id'],
233
				'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
234
				'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
235
				'license' => $app['releases'][0]['licenses'],
236
				'author' => $authors,
237
				'shipped' => false,
238
				'version' => $currentVersion,
239
				'default_enable' => '',
240
				'types' => [],
241
				'documentation' => [
242
					'admin' => $app['adminDocs'],
243
					'user' => $app['userDocs'],
244
					'developer' => $app['developerDocs']
245
				],
246
				'website' => $app['website'],
247
				'bugs' => $app['issueTracker'],
248
				'detailpage' => $app['website'],
249
				'dependencies' => array_merge(
250
					$nextCloudVersionDependencies,
251
					$phpDependencies
252
				),
253
				'level' => ($app['featured'] === true) ? 200 : 100,
254
				'missingMaxOwnCloudVersion' => false,
255
				'missingMinOwnCloudVersion' => false,
256
				'canInstall' => true,
257
				'preview' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '',
258
				'score' => $app['ratingOverall'],
259
				'ratingNumOverall' => $app['ratingNumOverall'],
260
				'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5 ? true : false,
261
				'removable' => $existsLocally,
262
				'active' => $this->appManager->isEnabledForUser($app['id']),
263
				'needsDownload' => !$existsLocally,
264
				'groups' => $groups,
265
				'fromAppStore' => true,
266
			];
267
268
269
			$appFetcher = \OC::$server->getAppFetcher();
270
			$newVersion = \OC\Installer::isUpdateAvailable($app['id'], $appFetcher);
271
			if($newVersion && $this->appManager->isInstalled($app['id'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $newVersion of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
272
				$formattedApps[count($formattedApps)-1]['update'] = $newVersion;
273
			}
274
		}
275
276
		return $formattedApps;
277
	}
278
279
	private function getAppsWithUpdates() {
280
		$appClass = new \OC_App();
281
		$apps = $appClass->listAllApps();
282
		foreach($apps as $key => $app) {
283
			$newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher);
284
			if($newVersion !== false) {
285
				$apps[$key]['update'] = $newVersion;
286
			} else {
287
				unset($apps[$key]);
288
			}
289
		}
290 View Code Duplication
		usort($apps, function ($a, $b) {
291
			$a = (string)$a['name'];
292
			$b = (string)$b['name'];
293
			if ($a === $b) {
294
				return 0;
295
			}
296
			return ($a < $b) ? -1 : 1;
297
		});
298
		return $apps;
299
	}
300
301
	/**
302
	 * Get all available apps in a category
303
	 *
304
	 * @param string $category
305
	 * @return JSONResponse
306
	 */
307
	public function listApps($category = '') {
308
		$appClass = new \OC_App();
309
310
		switch ($category) {
311
			// installed apps
312
			case 'installed':
313
				$apps = $appClass->listAllApps();
314
315 View Code Duplication
				foreach($apps as $key => $app) {
316
					$newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher);
317
					$apps[$key]['update'] = $newVersion;
318
				}
319
320 View Code Duplication
				usort($apps, function ($a, $b) {
321
					$a = (string)$a['name'];
322
					$b = (string)$b['name'];
323
					if ($a === $b) {
324
						return 0;
325
					}
326
					return ($a < $b) ? -1 : 1;
327
				});
328
				break;
329
			// updates
330
			case 'updates':
331
				$apps = $this->getAppsWithUpdates();
332
				break;
333
			// enabled apps
334
			case 'enabled':
335
				$apps = $appClass->listAllApps();
336
				$apps = array_filter($apps, function ($app) {
337
					return $app['active'];
338
				});
339
340 View Code Duplication
				foreach($apps as $key => $app) {
341
					$newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher);
342
					$apps[$key]['update'] = $newVersion;
343
				}
344
345 View Code Duplication
				usort($apps, function ($a, $b) {
346
					$a = (string)$a['name'];
347
					$b = (string)$b['name'];
348
					if ($a === $b) {
349
						return 0;
350
					}
351
					return ($a < $b) ? -1 : 1;
352
				});
353
				break;
354
			// disabled  apps
355
			case 'disabled':
356
				$apps = $appClass->listAllApps();
357
				$apps = array_filter($apps, function ($app) {
358
					return !$app['active'];
359
				});
360
361
				$apps = array_map(function ($app) {
362
					$newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher);
363
					if ($newVersion !== false) {
364
						$app['update'] = $newVersion;
365
					}
366
					return $app;
367
				}, $apps);
368
369 View Code Duplication
				usort($apps, function ($a, $b) {
370
					$a = (string)$a['name'];
371
					$b = (string)$b['name'];
372
					if ($a === $b) {
373
						return 0;
374
					}
375
					return ($a < $b) ? -1 : 1;
376
				});
377
				break;
378
			case 'app-bundles':
379
				$bundles = $this->bundleFetcher->getBundles();
380
				$apps = [];
381
				foreach($bundles as $bundle) {
382
					$newCategory = true;
383
					$allApps = $appClass->listAllApps();
384
					$categories = $this->getAllCategories();
385
					foreach($categories as $singleCategory) {
386
						$newApps = $this->getAppsForCategory($singleCategory['id']);
387
						foreach($allApps as $app) {
388
							foreach($newApps as $key => $newApp) {
389
								if($app['id'] === $newApp['id']) {
390
									unset($newApps[$key]);
391
								}
392
							}
393
						}
394
						$allApps = array_merge($allApps, $newApps);
395
					}
396
397
					foreach($bundle->getAppIdentifiers() as $identifier) {
398
						foreach($allApps as $app) {
399
							if($app['id'] === $identifier) {
400
								if($newCategory) {
401
									$app['newCategory'] = true;
402
									$app['categoryName'] = $bundle->getName();
403
								}
404
								$app['bundleId'] = $bundle->getIdentifier();
405
								$newCategory = false;
406
								$apps[] = $app;
407
								continue;
408
							}
409
						}
410
					}
411
				}
412
				break;
413
			default:
414
				$apps = $this->getAppsForCategory($category);
415
416
				// sort by score
417
				usort($apps, function ($a, $b) {
418
					$a = (int)$a['score'];
419
					$b = (int)$b['score'];
420
					if ($a === $b) {
421
						return 0;
422
					}
423
					return ($a > $b) ? -1 : 1;
424
				});
425
				break;
426
		}
427
428
		// fix groups to be an array
429
		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
430
		$apps = array_map(function($app) use ($dependencyAnalyzer) {
431
432
			// fix groups
433
			$groups = array();
434
			if (is_string($app['groups'])) {
435
				$groups = json_decode($app['groups']);
436
			}
437
			$app['groups'] = $groups;
438
			$app['canUnInstall'] = !$app['active'] && $app['removable'];
439
440
			// fix licence vs license
441
			if (isset($app['license']) && !isset($app['licence'])) {
442
				$app['licence'] = $app['license'];
443
			}
444
445
			// analyse dependencies
446
			$missing = $dependencyAnalyzer->analyze($app);
447
			$app['canInstall'] = empty($missing);
448
			$app['missingDependencies'] = $missing;
449
450
			$app['missingMinOwnCloudVersion'] = !isset($app['dependencies']['nextcloud']['@attributes']['min-version']);
451
			$app['missingMaxOwnCloudVersion'] = !isset($app['dependencies']['nextcloud']['@attributes']['max-version']);
452
453
			return $app;
454
		}, $apps);
455
456
		return new JSONResponse(['apps' => $apps, 'status' => 'success']);
457
	}
458
}
459