aboutsummaryrefslogtreecommitdiffstats
path: root/apps/updatenotification/lib/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'apps/updatenotification/lib/Controller')
-rw-r--r--apps/updatenotification/lib/Controller/APIController.php165
-rw-r--r--apps/updatenotification/lib/Controller/AdminController.php78
-rw-r--r--apps/updatenotification/lib/Controller/ChangelogController.php62
3 files changed, 189 insertions, 116 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,
+ ]);
+ }
}
diff --git a/apps/updatenotification/lib/Controller/AdminController.php b/apps/updatenotification/lib/Controller/AdminController.php
index b13ba66efd5..26745948890 100644
--- a/apps/updatenotification/lib/Controller/AdminController.php
+++ b/apps/updatenotification/lib/Controller/AdminController.php
@@ -3,36 +3,19 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Vincent Petry <vincent@nextcloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\UpdateNotification\Controller;
-use OCA\UpdateNotification\ResetTokenBackgroundJob;
+use OCA\UpdateNotification\BackgroundJob\ResetToken;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
@@ -40,43 +23,22 @@ use OCP\Security\ISecureRandom;
use OCP\Util;
class AdminController extends Controller {
- /** @var IJobList */
- private $jobList;
- /** @var ISecureRandom */
- private $secureRandom;
- /** @var IConfig */
- private $config;
- /** @var ITimeFactory */
- private $timeFactory;
- /** @var IL10N */
- private $l10n;
- /**
- * @param string $appName
- * @param IRequest $request
- * @param IJobList $jobList
- * @param ISecureRandom $secureRandom
- * @param IConfig $config
- * @param ITimeFactory $timeFactory
- * @param IL10N $l10n
- */
- public function __construct($appName,
- IRequest $request,
- IJobList $jobList,
- ISecureRandom $secureRandom,
- IConfig $config,
- ITimeFactory $timeFactory,
- IL10N $l10n) {
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ private IJobList $jobList,
+ private ISecureRandom $secureRandom,
+ private IConfig $config,
+ private IAppConfig $appConfig,
+ private ITimeFactory $timeFactory,
+ private IL10N $l10n,
+ ) {
parent::__construct($appName, $request);
- $this->jobList = $jobList;
- $this->secureRandom = $secureRandom;
- $this->config = $config;
- $this->timeFactory = $timeFactory;
- $this->l10n = $l10n;
}
- private function isUpdaterEnabled() {
- return !$this->config->getSystemValue('upgrade.disable-web', false);
+ private function isUpdaterEnabled(): bool {
+ return !$this->config->getSystemValueBool('upgrade.disable-web');
}
/**
@@ -85,7 +47,7 @@ class AdminController extends Controller {
*/
public function setChannel(string $channel): DataResponse {
Util::setChannel($channel);
- $this->config->setAppValue('core', 'lastupdatedat', 0);
+ $this->appConfig->setValueInt('core', 'lastupdatedat', 0);
return new DataResponse(['status' => 'success', 'data' => ['message' => $this->l10n->t('Channel updated')]]);
}
@@ -98,8 +60,8 @@ class AdminController extends Controller {
}
// Create a new job and store the creation date
- $this->jobList->add(ResetTokenBackgroundJob::class);
- $this->config->setAppValue('core', 'updater.secret.created', $this->timeFactory->getTime());
+ $this->jobList->add(ResetToken::class);
+ $this->appConfig->setValueInt('core', 'updater.secret.created', $this->timeFactory->getTime());
// Create a new token
$newToken = $this->secureRandom->generate(64);
diff --git a/apps/updatenotification/lib/Controller/ChangelogController.php b/apps/updatenotification/lib/Controller/ChangelogController.php
new file mode 100644
index 00000000000..a274ed3d2b2
--- /dev/null
+++ b/apps/updatenotification/lib/Controller/ChangelogController.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\UpdateNotification\Controller;
+
+use OCA\UpdateNotification\Manager;
+use OCP\App\IAppManager;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+use OCP\AppFramework\Http\Attribute\OpenAPI;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\AppFramework\Services\IInitialState;
+use OCP\IRequest;
+use OCP\Util;
+
+#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
+class ChangelogController extends Controller {
+
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ private Manager $manager,
+ private IAppManager $appManager,
+ private IInitialState $initialState,
+ ) {
+ parent::__construct($appName, $request);
+ }
+
+ /**
+ * This page is only used for clients not support showing the app changelog feature in-app and thus need to show it on a dedicated page.
+ * @param string $app App to show the changelog for
+ * @param string|null $version Version entry to show (defaults to latest installed)
+ */
+ #[NoAdminRequired]
+ #[NoCSRFRequired]
+ public function showChangelog(string $app, ?string $version = null): TemplateResponse {
+ $version = $version ?? $this->appManager->getAppVersion($app);
+ $appInfo = $this->appManager->getAppInfo($app) ?? [];
+ $appName = $appInfo['name'] ?? $app;
+
+ $changes = $this->manager->getChangelog($app, $version) ?? '';
+ // Remove version headline
+ /** @var string[] */
+ $changes = explode("\n", $changes, 2);
+ $changes = trim(end($changes));
+
+ $this->initialState->provideInitialState('changelog', [
+ 'appName' => $appName,
+ 'appVersion' => $version,
+ 'text' => $changes,
+ ]);
+
+ Util::addScript($this->appName, 'view-changelog-page');
+ return new TemplateResponse($this->appName, 'empty');
+ }
+}