aboutsummaryrefslogtreecommitdiffstats
path: root/apps/updatenotification/lib/Controller/APIController.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/updatenotification/lib/Controller/APIController.php')
-rw-r--r--apps/updatenotification/lib/Controller/APIController.php165
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,
+ ]);
+ }
}