diff options
Diffstat (limited to 'apps/updatenotification/lib/Controller/APIController.php')
-rw-r--r-- | apps/updatenotification/lib/Controller/APIController.php | 165 |
1 files changed, 107 insertions, 58 deletions
diff --git a/apps/updatenotification/lib/Controller/APIController.php b/apps/updatenotification/lib/Controller/APIController.php index 9d5d1c2d764..4360d814dd2 100644 --- a/apps/updatenotification/lib/Controller/APIController.php +++ b/apps/updatenotification/lib/Controller/APIController.php @@ -3,30 +3,14 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UpdateNotification\Controller; use OC\App\AppStore\Fetcher\AppFetcher; +use OCA\UpdateNotification\Manager; +use OCA\UpdateNotification\ResponseDefinitions; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; use OCP\AppFramework\Http; @@ -37,45 +21,50 @@ use OCP\IRequest; use OCP\IUserSession; use OCP\L10N\IFactory; +/** + * @psalm-import-type UpdateNotificationApp from ResponseDefinitions + */ class APIController extends OCSController { - /** @var IConfig */ - protected $config; - - /** @var IAppManager */ - protected $appManager; - - /** @var AppFetcher */ - protected $appFetcher; - - /** @var IFactory */ - protected $l10nFactory; + protected ?string $language = null; - /** @var IUserSession */ - protected $userSession; - - /** @var string */ - protected $language; - - public function __construct(string $appName, - IRequest $request, - IConfig $config, - IAppManager $appManager, - AppFetcher $appFetcher, - IFactory $l10nFactory, - IUserSession $userSession) { + /** + * List of apps that were in the appstore but are now shipped and don't have + * a compatible update available. + * + * @var array<string, int> + */ + protected array $appsShippedInFutureVersion = [ + 'bruteforcesettings' => 25, + 'suspicious_login' => 25, + 'twofactor_totp' => 25, + 'files_downloadlimit' => 29, + 'twofactor_nextcloud_notification' => 30, + 'app_api' => 30, + ]; + + public function __construct( + string $appName, + IRequest $request, + protected IConfig $config, + protected IAppManager $appManager, + protected AppFetcher $appFetcher, + protected IFactory $l10nFactory, + protected IUserSession $userSession, + protected Manager $manager, + ) { parent::__construct($appName, $request); - - $this->config = $config; - $this->appManager = $appManager; - $this->appFetcher = $appFetcher; - $this->l10nFactory = $l10nFactory; - $this->userSession = $userSession; } /** - * @param string $newVersion - * @return DataResponse + * List available updates for apps + * + * @param string $newVersion Server version to check updates for + * + * @return DataResponse<Http::STATUS_OK, array{missing: list<UpdateNotificationApp>, available: list<UpdateNotificationApp>}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array{appstore_disabled: bool, already_on_latest?: bool}, array{}> + * + * 200: Apps returned + * 404: New versions not found */ public function getAppList(string $newVersion): DataResponse { if (!$this->config->getSystemValue('appstoreenabled', true)) { @@ -85,14 +74,14 @@ class APIController extends OCSController { } // Get list of installed custom apps - $installedApps = $this->appManager->getInstalledApps(); + $installedApps = $this->appManager->getEnabledApps(); $installedApps = array_filter($installedApps, function ($app) { try { $this->appManager->getAppPath($app); } catch (AppPathNotFoundException $e) { return false; } - return !$this->appManager->isShipped($app); + return !$this->appManager->isShipped($app) && !isset($this->appsShippedInFutureVersion[$app]); }); if (empty($installedApps)) { @@ -105,7 +94,7 @@ class APIController extends OCSController { $this->appFetcher->setVersion($newVersion, 'future-apps.json', false); // Apps available on the app store for that version - $availableApps = array_map(static function (array $app) { + $availableApps = array_map(static function (array $app): string { return $app['id']; }, $this->appFetcher->get()); @@ -116,7 +105,14 @@ class APIController extends OCSController { ], Http::STATUS_NOT_FOUND); } - $this->language = $this->l10nFactory->getUserLanguage($this->userSession->getUser()); + // Ignore apps that are deployed from git + $installedApps = array_filter($installedApps, function (string $appId) { + try { + return !file_exists($this->appManager->getAppPath($appId) . '/.git'); + } catch (AppPathNotFoundException $e) { + return true; + } + }); $missing = array_diff($installedApps, $availableApps); $missing = array_map([$this, 'getAppDetails'], $missing); @@ -136,13 +132,66 @@ class APIController extends OCSController { * Get translated app name * * @param string $appId - * @return string[] + * @return UpdateNotificationApp */ protected function getAppDetails(string $appId): array { $app = $this->appManager->getAppInfo($appId, false, $this->language); + $name = $app['name'] ?? $appId; return [ 'appId' => $appId, - 'appName' => $app['name'] ?? $appId, + 'appName' => $name, ]; } + + protected function getLanguage(): string { + if ($this->language === null) { + $this->language = $this->l10nFactory->getUserLanguage($this->userSession->getUser()); + } + return $this->language; + } + + /** + * Get changelog entry for an app + * + * @param string $appId App to search changelog entry for + * @param string|null $version The version to search the changelog entry for (defaults to the latest installed) + * + * @return DataResponse<Http::STATUS_OK, array{appName: string, content: string, version: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array{}, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{}, array{}> + * + * 200: Changelog entry returned + * 400: The `version` parameter is not a valid version format + * 404: No changelog found + */ + public function getAppChangelogEntry(string $appId, ?string $version = null): DataResponse { + $version = $version ?? $this->appManager->getAppVersion($appId); + // handle pre-release versions + $matches = []; + $result = preg_match('/^(\d+\.\d+(\.\d+)?)/', $version, $matches); + if ($result === false || $result === 0) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + $shortVersion = $matches[0]; + + $changes = $this->manager->getChangelog($appId, $shortVersion); + + if ($changes === null) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + // Remove version headline + /** @var string[] */ + $changes = explode("\n", $changes, 2); + $changes = trim(end($changes)); + + // Get app info for localized app name + $info = $this->appManager->getAppInfo($appId) ?? []; + /** @var string */ + $appName = $info['name'] ?? $appId; + + return new DataResponse([ + 'appName' => $appName, + 'content' => $changes, + 'version' => $version, + ]); + } } |