| Total Complexity | 74 |
| Total Lines | 505 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like AppSettingsController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AppSettingsController, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 56 | class AppSettingsController extends Controller { |
||
| 57 | |||
| 58 | /** @var \OCP\IL10N */ |
||
| 59 | private $l10n; |
||
| 60 | /** @var IConfig */ |
||
| 61 | private $config; |
||
| 62 | /** @var INavigationManager */ |
||
| 63 | private $navigationManager; |
||
| 64 | /** @var IAppManager */ |
||
| 65 | private $appManager; |
||
| 66 | /** @var CategoryFetcher */ |
||
| 67 | private $categoryFetcher; |
||
| 68 | /** @var AppFetcher */ |
||
| 69 | private $appFetcher; |
||
| 70 | /** @var IFactory */ |
||
| 71 | private $l10nFactory; |
||
| 72 | /** @var BundleFetcher */ |
||
| 73 | private $bundleFetcher; |
||
| 74 | /** @var Installer */ |
||
| 75 | private $installer; |
||
| 76 | /** @var IURLGenerator */ |
||
| 77 | private $urlGenerator; |
||
| 78 | /** @var ILogger */ |
||
| 79 | private $logger; |
||
| 80 | |||
| 81 | /** @var array */ |
||
| 82 | private $allApps = []; |
||
| 83 | |||
| 84 | /** |
||
| 85 | * @param string $appName |
||
| 86 | * @param IRequest $request |
||
| 87 | * @param IL10N $l10n |
||
| 88 | * @param IConfig $config |
||
| 89 | * @param INavigationManager $navigationManager |
||
| 90 | * @param IAppManager $appManager |
||
| 91 | * @param CategoryFetcher $categoryFetcher |
||
| 92 | * @param AppFetcher $appFetcher |
||
| 93 | * @param IFactory $l10nFactory |
||
| 94 | * @param BundleFetcher $bundleFetcher |
||
| 95 | * @param Installer $installer |
||
| 96 | * @param IURLGenerator $urlGenerator |
||
| 97 | * @param ILogger $logger |
||
| 98 | */ |
||
| 99 | public function __construct(string $appName, |
||
| 100 | IRequest $request, |
||
| 101 | IL10N $l10n, |
||
| 102 | IConfig $config, |
||
| 103 | INavigationManager $navigationManager, |
||
| 104 | IAppManager $appManager, |
||
| 105 | CategoryFetcher $categoryFetcher, |
||
| 106 | AppFetcher $appFetcher, |
||
| 107 | IFactory $l10nFactory, |
||
| 108 | BundleFetcher $bundleFetcher, |
||
| 109 | Installer $installer, |
||
| 110 | IURLGenerator $urlGenerator, |
||
| 111 | ILogger $logger) { |
||
| 112 | parent::__construct($appName, $request); |
||
| 113 | $this->l10n = $l10n; |
||
| 114 | $this->config = $config; |
||
| 115 | $this->navigationManager = $navigationManager; |
||
| 116 | $this->appManager = $appManager; |
||
| 117 | $this->categoryFetcher = $categoryFetcher; |
||
| 118 | $this->appFetcher = $appFetcher; |
||
| 119 | $this->l10nFactory = $l10nFactory; |
||
| 120 | $this->bundleFetcher = $bundleFetcher; |
||
| 121 | $this->installer = $installer; |
||
| 122 | $this->urlGenerator = $urlGenerator; |
||
| 123 | $this->logger = $logger; |
||
| 124 | } |
||
| 125 | |||
| 126 | /** |
||
| 127 | * @NoCSRFRequired |
||
| 128 | * |
||
| 129 | * @return TemplateResponse |
||
| 130 | */ |
||
| 131 | public function viewApps(): TemplateResponse { |
||
| 132 | \OC_Util::addScript('settings', 'apps'); |
||
| 133 | $params = []; |
||
| 134 | $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true; |
||
| 135 | $params['updateCount'] = count($this->getAppsWithUpdates()); |
||
| 136 | $params['developerDocumentation'] = $this->urlGenerator->linkToDocs('developer-manual'); |
||
| 137 | $params['bundles'] = $this->getBundles(); |
||
| 138 | $this->navigationManager->setActiveEntry('core_apps'); |
||
| 139 | |||
| 140 | $templateResponse = new TemplateResponse('settings', 'settings-vue', ['serverData' => $params]); |
||
| 141 | $policy = new ContentSecurityPolicy(); |
||
| 142 | $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com'); |
||
| 143 | $templateResponse->setContentSecurityPolicy($policy); |
||
| 144 | |||
| 145 | return $templateResponse; |
||
| 146 | } |
||
| 147 | |||
| 148 | private function getAppsWithUpdates() { |
||
| 149 | $appClass = new \OC_App(); |
||
| 150 | $apps = $appClass->listAllApps(); |
||
| 151 | foreach($apps as $key => $app) { |
||
| 152 | $newVersion = $this->installer->isUpdateAvailable($app['id']); |
||
| 153 | if($newVersion === false) { |
||
| 154 | unset($apps[$key]); |
||
| 155 | } |
||
| 156 | } |
||
| 157 | return $apps; |
||
| 158 | } |
||
| 159 | |||
| 160 | private function getBundles() { |
||
| 161 | $result = []; |
||
| 162 | $bundles = $this->bundleFetcher->getBundles(); |
||
| 163 | foreach ($bundles as $bundle) { |
||
| 164 | $result[] = [ |
||
| 165 | 'name' => $bundle->getName(), |
||
| 166 | 'id' => $bundle->getIdentifier(), |
||
| 167 | 'appIdentifiers' => $bundle->getAppIdentifiers() |
||
| 168 | ]; |
||
| 169 | } |
||
| 170 | return $result; |
||
| 171 | |||
| 172 | } |
||
| 173 | |||
| 174 | /** |
||
| 175 | * Get all available categories |
||
| 176 | * |
||
| 177 | * @return JSONResponse |
||
| 178 | */ |
||
| 179 | public function listCategories(): JSONResponse { |
||
| 180 | return new JSONResponse($this->getAllCategories()); |
||
| 181 | } |
||
| 182 | |||
| 183 | private function getAllCategories() { |
||
| 197 | } |
||
| 198 | |||
| 199 | private function fetchApps() { |
||
| 200 | $appClass = new \OC_App(); |
||
| 201 | $apps = $appClass->listAllApps(); |
||
| 202 | foreach ($apps as $app) { |
||
| 203 | $app['installed'] = true; |
||
| 204 | $this->allApps[$app['id']] = $app; |
||
| 205 | } |
||
| 206 | |||
| 207 | $apps = $this->getAppsForCategory(''); |
||
| 208 | foreach ($apps as $app) { |
||
| 209 | $app['appstore'] = true; |
||
| 210 | if (!array_key_exists($app['id'], $this->allApps)) { |
||
| 211 | $this->allApps[$app['id']] = $app; |
||
| 212 | } else { |
||
| 213 | $this->allApps[$app['id']] = array_merge($app, $this->allApps[$app['id']]); |
||
| 214 | } |
||
| 215 | } |
||
| 216 | |||
| 217 | // add bundle information |
||
| 218 | $bundles = $this->bundleFetcher->getBundles(); |
||
| 219 | foreach($bundles as $bundle) { |
||
| 220 | foreach($bundle->getAppIdentifiers() as $identifier) { |
||
| 221 | foreach($this->allApps as &$app) { |
||
| 222 | if($app['id'] === $identifier) { |
||
| 223 | $app['bundleId'] = $bundle->getIdentifier(); |
||
| 224 | continue; |
||
| 225 | } |
||
| 226 | } |
||
| 227 | } |
||
| 228 | } |
||
| 229 | } |
||
| 230 | |||
| 231 | private function getAllApps() { |
||
| 232 | return $this->allApps; |
||
| 233 | } |
||
| 234 | /** |
||
| 235 | * Get all available apps in a category |
||
| 236 | * |
||
| 237 | * @param string $category |
||
| 238 | * @return JSONResponse |
||
| 239 | * @throws \Exception |
||
| 240 | */ |
||
| 241 | public function listApps(): JSONResponse { |
||
| 242 | |||
| 243 | $this->fetchApps(); |
||
| 244 | $apps = $this->getAllApps(); |
||
| 245 | |||
| 246 | $dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n); |
||
| 247 | |||
| 248 | // Extend existing app details |
||
| 249 | $apps = array_map(function($appData) use ($dependencyAnalyzer) { |
||
| 250 | if (isset($appData['appstoreData'])) { |
||
| 251 | $appstoreData = $appData['appstoreData']; |
||
| 252 | $appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/' . base64_encode($appstoreData['screenshots'][0]['url']) : ''; |
||
| 253 | $appData['category'] = $appstoreData['categories']; |
||
| 254 | } |
||
| 255 | |||
| 256 | $newVersion = $this->installer->isUpdateAvailable($appData['id']); |
||
| 257 | if($newVersion) { |
||
| 258 | $appData['update'] = $newVersion; |
||
| 259 | } |
||
| 260 | |||
| 261 | // fix groups to be an array |
||
| 262 | $groups = array(); |
||
| 263 | if (is_string($appData['groups'])) { |
||
| 264 | $groups = json_decode($appData['groups']); |
||
| 265 | } |
||
| 266 | $appData['groups'] = $groups; |
||
| 267 | $appData['canUnInstall'] = !$appData['active'] && $appData['removable']; |
||
| 268 | |||
| 269 | // fix licence vs license |
||
| 270 | if (isset($appData['license']) && !isset($appData['licence'])) { |
||
| 271 | $appData['licence'] = $appData['license']; |
||
| 272 | } |
||
| 273 | |||
| 274 | $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []); |
||
| 275 | $ignoreMax = in_array($appData['id'], $ignoreMaxApps); |
||
| 276 | |||
| 277 | // analyse dependencies |
||
| 278 | $missing = $dependencyAnalyzer->analyze($appData, $ignoreMax); |
||
| 279 | $appData['canInstall'] = empty($missing); |
||
| 280 | $appData['missingDependencies'] = $missing; |
||
| 281 | |||
| 282 | $appData['missingMinOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['min-version']); |
||
| 283 | $appData['missingMaxOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['max-version']); |
||
| 284 | $appData['isCompatible'] = $dependencyAnalyzer->isMarkedCompatible($appData); |
||
| 285 | |||
| 286 | return $appData; |
||
| 287 | }, $apps); |
||
| 288 | |||
| 289 | usort($apps, [$this, 'sortApps']); |
||
| 290 | |||
| 291 | return new JSONResponse(['apps' => $apps, 'status' => 'success']); |
||
| 292 | } |
||
| 293 | |||
| 294 | /** |
||
| 295 | * Get all apps for a category from the app store |
||
| 296 | * |
||
| 297 | * @param string $requestedCategory |
||
| 298 | * @return array |
||
| 299 | * @throws \Exception |
||
| 300 | */ |
||
| 301 | private function getAppsForCategory($requestedCategory = ''): array { |
||
| 302 | $versionParser = new VersionParser(); |
||
| 303 | $formattedApps = []; |
||
| 304 | $apps = $this->appFetcher->get(); |
||
| 305 | foreach($apps as $app) { |
||
| 306 | // Skip all apps not in the requested category |
||
| 307 | if ($requestedCategory !== '') { |
||
| 308 | $isInCategory = false; |
||
| 309 | foreach($app['categories'] as $category) { |
||
| 310 | if($category === $requestedCategory) { |
||
| 311 | $isInCategory = true; |
||
| 312 | } |
||
| 313 | } |
||
| 314 | if(!$isInCategory) { |
||
| 315 | continue; |
||
| 316 | } |
||
| 317 | } |
||
| 318 | |||
| 319 | if (!isset($app['releases'][0]['rawPlatformVersionSpec'])) { |
||
| 320 | continue; |
||
| 321 | } |
||
| 322 | $nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']); |
||
| 323 | $nextCloudVersionDependencies = []; |
||
| 324 | if($nextCloudVersion->getMinimumVersion() !== '') { |
||
| 325 | $nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion(); |
||
| 326 | } |
||
| 327 | if($nextCloudVersion->getMaximumVersion() !== '') { |
||
| 328 | $nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion(); |
||
| 329 | } |
||
| 330 | $phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']); |
||
| 331 | $existsLocally = \OC_App::getAppPath($app['id']) !== false; |
||
|
|
|||
| 332 | $phpDependencies = []; |
||
| 333 | if($phpVersion->getMinimumVersion() !== '') { |
||
| 334 | $phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion(); |
||
| 335 | } |
||
| 336 | if($phpVersion->getMaximumVersion() !== '') { |
||
| 337 | $phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion(); |
||
| 338 | } |
||
| 339 | if(isset($app['releases'][0]['minIntSize'])) { |
||
| 340 | $phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize']; |
||
| 341 | } |
||
| 342 | $authors = ''; |
||
| 343 | foreach($app['authors'] as $key => $author) { |
||
| 344 | $authors .= $author['name']; |
||
| 345 | if($key !== count($app['authors']) - 1) { |
||
| 346 | $authors .= ', '; |
||
| 347 | } |
||
| 348 | } |
||
| 349 | |||
| 350 | $currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2); |
||
| 351 | $enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no'); |
||
| 352 | $groups = null; |
||
| 353 | if($enabledValue !== 'no' && $enabledValue !== 'yes') { |
||
| 354 | $groups = $enabledValue; |
||
| 355 | } |
||
| 356 | |||
| 357 | $currentVersion = ''; |
||
| 358 | if($this->appManager->isInstalled($app['id'])) { |
||
| 359 | $currentVersion = $this->appManager->getAppVersion($app['id']); |
||
| 360 | } else { |
||
| 361 | $currentLanguage = $app['releases'][0]['version']; |
||
| 362 | } |
||
| 363 | |||
| 364 | $formattedApps[] = [ |
||
| 365 | 'id' => $app['id'], |
||
| 366 | 'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'], |
||
| 367 | 'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'], |
||
| 368 | 'summary' => isset($app['translations'][$currentLanguage]['summary']) ? $app['translations'][$currentLanguage]['summary'] : $app['translations']['en']['summary'], |
||
| 369 | 'license' => $app['releases'][0]['licenses'], |
||
| 370 | 'author' => $authors, |
||
| 371 | 'shipped' => false, |
||
| 372 | 'version' => $currentVersion, |
||
| 373 | 'default_enable' => '', |
||
| 374 | 'types' => [], |
||
| 375 | 'documentation' => [ |
||
| 376 | 'admin' => $app['adminDocs'], |
||
| 377 | 'user' => $app['userDocs'], |
||
| 378 | 'developer' => $app['developerDocs'] |
||
| 379 | ], |
||
| 380 | 'website' => $app['website'], |
||
| 381 | 'bugs' => $app['issueTracker'], |
||
| 382 | 'detailpage' => $app['website'], |
||
| 383 | 'dependencies' => array_merge( |
||
| 384 | $nextCloudVersionDependencies, |
||
| 385 | $phpDependencies |
||
| 386 | ), |
||
| 387 | 'level' => ($app['isFeatured'] === true) ? 200 : 100, |
||
| 388 | 'missingMaxOwnCloudVersion' => false, |
||
| 389 | 'missingMinOwnCloudVersion' => false, |
||
| 390 | 'canInstall' => true, |
||
| 391 | 'screenshot' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '', |
||
| 392 | 'score' => $app['ratingOverall'], |
||
| 393 | 'ratingNumOverall' => $app['ratingNumOverall'], |
||
| 394 | 'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5, |
||
| 395 | 'removable' => $existsLocally, |
||
| 396 | 'active' => $this->appManager->isEnabledForUser($app['id']), |
||
| 397 | 'needsDownload' => !$existsLocally, |
||
| 398 | 'groups' => $groups, |
||
| 399 | 'fromAppStore' => true, |
||
| 400 | 'appstoreData' => $app, |
||
| 401 | ]; |
||
| 402 | } |
||
| 403 | |||
| 404 | return $formattedApps; |
||
| 405 | } |
||
| 406 | |||
| 407 | /** |
||
| 408 | * @PasswordConfirmationRequired |
||
| 409 | * |
||
| 410 | * @param string $appId |
||
| 411 | * @param array $groups |
||
| 412 | * @return JSONResponse |
||
| 413 | */ |
||
| 414 | public function enableApp(string $appId, array $groups = []): JSONResponse { |
||
| 415 | return $this->enableApps([$appId], $groups); |
||
| 416 | } |
||
| 417 | |||
| 418 | /** |
||
| 419 | * Enable one or more apps |
||
| 420 | * |
||
| 421 | * apps will be enabled for specific groups only if $groups is defined |
||
| 422 | * |
||
| 423 | * @PasswordConfirmationRequired |
||
| 424 | * @param array $appIds |
||
| 425 | * @param array $groups |
||
| 426 | * @return JSONResponse |
||
| 427 | */ |
||
| 428 | public function enableApps(array $appIds, array $groups = []): JSONResponse { |
||
| 429 | try { |
||
| 430 | $updateRequired = false; |
||
| 431 | |||
| 432 | foreach ($appIds as $appId) { |
||
| 433 | $appId = OC_App::cleanAppId($appId); |
||
| 434 | |||
| 435 | // Check if app is already downloaded |
||
| 436 | /** @var Installer $installer */ |
||
| 437 | $installer = \OC::$server->query(Installer::class); |
||
| 438 | $isDownloaded = $installer->isDownloaded($appId); |
||
| 439 | |||
| 440 | if(!$isDownloaded) { |
||
| 441 | $installer->downloadApp($appId); |
||
| 442 | } |
||
| 443 | |||
| 444 | $installer->installApp($appId); |
||
| 445 | |||
| 446 | if (count($groups) > 0) { |
||
| 447 | $this->appManager->enableAppForGroups($appId, $this->getGroupList($groups)); |
||
| 448 | } else { |
||
| 449 | $this->appManager->enableApp($appId); |
||
| 450 | } |
||
| 451 | if (\OC_App::shouldUpgrade($appId)) { |
||
| 452 | $updateRequired = true; |
||
| 453 | } |
||
| 454 | } |
||
| 455 | return new JSONResponse(['data' => ['update_required' => $updateRequired]]); |
||
| 456 | |||
| 457 | } catch (\Exception $e) { |
||
| 458 | $this->logger->logException($e); |
||
| 459 | return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR); |
||
| 460 | } |
||
| 461 | } |
||
| 462 | |||
| 463 | private function getGroupList(array $groups) { |
||
| 464 | $groupManager = \OC::$server->getGroupManager(); |
||
| 465 | $groupsList = []; |
||
| 466 | foreach ($groups as $group) { |
||
| 467 | $groupItem = $groupManager->get($group); |
||
| 468 | if ($groupItem instanceof \OCP\IGroup) { |
||
| 469 | $groupsList[] = $groupManager->get($group); |
||
| 470 | } |
||
| 471 | } |
||
| 472 | return $groupsList; |
||
| 473 | } |
||
| 474 | |||
| 475 | /** |
||
| 476 | * @PasswordConfirmationRequired |
||
| 477 | * |
||
| 478 | * @param string $appId |
||
| 479 | * @return JSONResponse |
||
| 480 | */ |
||
| 481 | public function disableApp(string $appId): JSONResponse { |
||
| 483 | } |
||
| 484 | |||
| 485 | /** |
||
| 486 | * @PasswordConfirmationRequired |
||
| 487 | * |
||
| 488 | * @param array $appIds |
||
| 489 | * @return JSONResponse |
||
| 490 | */ |
||
| 491 | public function disableApps(array $appIds): JSONResponse { |
||
| 492 | try { |
||
| 493 | foreach ($appIds as $appId) { |
||
| 494 | $appId = OC_App::cleanAppId($appId); |
||
| 495 | $this->appManager->disableApp($appId); |
||
| 496 | } |
||
| 497 | return new JSONResponse([]); |
||
| 498 | } catch (\Exception $e) { |
||
| 499 | $this->logger->logException($e); |
||
| 500 | return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR); |
||
| 501 | } |
||
| 502 | } |
||
| 503 | |||
| 504 | /** |
||
| 505 | * @PasswordConfirmationRequired |
||
| 506 | * |
||
| 507 | * @param string $appId |
||
| 508 | * @return JSONResponse |
||
| 509 | */ |
||
| 510 | public function uninstallApp(string $appId): JSONResponse { |
||
| 518 | } |
||
| 519 | |||
| 520 | /** |
||
| 521 | * @param string $appId |
||
| 522 | * @return JSONResponse |
||
| 523 | */ |
||
| 524 | public function updateApp(string $appId): JSONResponse { |
||
| 540 | } |
||
| 541 | |||
| 542 | private function sortApps($a, $b) { |
||
| 543 | $a = (string)$a['name']; |
||
| 544 | $b = (string)$b['name']; |
||
| 545 | if ($a === $b) { |
||
| 546 | return 0; |
||
| 547 | } |
||
| 548 | return ($a < $b) ? -1 : 1; |
||
| 549 | } |
||
| 550 | |||
| 551 | public function force(string $appId): JSONResponse { |
||
| 552 | $appId = OC_App::cleanAppId($appId); |
||
| 553 | |||
| 561 | } |
||
| 562 | |||
| 564 |
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.