refactor(updatenotification): Migrate legacy code

1. Remove hook usage and just provide an initial state
2. Replace jQuery code with modern non-deprecated frontend code

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
pull/48323/head
Ferdinand Thiessen 2024-09-24 17:23:48 +07:00
parent 280f6df66c
commit 71f1e0cb9c
No known key found for this signature in database
GPG Key ID: 45FAE7268762B400
7 changed files with 86 additions and 45 deletions

@ -24,11 +24,11 @@
<job>OCA\UpdateNotification\BackgroundJob\UpdateAvailableNotifications</job> <job>OCA\UpdateNotification\BackgroundJob\UpdateAvailableNotifications</job>
</background-jobs> </background-jobs>
<settings>
<admin>OCA\UpdateNotification\Settings\Admin</admin>
</settings>
<commands> <commands>
<command>OCA\UpdateNotification\Command\Check</command> <command>OCA\UpdateNotification\Command\Check</command>
</commands> </commands>
<settings>
<admin>OCA\UpdateNotification\Settings\Admin</admin>
</settings>
</info> </info>

@ -1,15 +0,0 @@
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2015-2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/**
* This only gets loaded if an update is available and the notifications app is not enabled for the user.
*/
window.addEventListener('DOMContentLoaded', function(){
var text = t('core', '{version} is available. Get more information on how to update.', {version: oc_updateState.updateVersion}),
element = $('<a>').attr('href', oc_updateState.updateLink).attr('target','_blank').text(text);
OC.Notification.showHtml(element.prop('outerHTML'), { type: 'error' });
});

@ -50,7 +50,8 @@ class Application extends App implements IBootstrap {
IAppManager $appManager, IAppManager $appManager,
IGroupManager $groupManager, IGroupManager $groupManager,
ContainerInterface $container, ContainerInterface $container,
LoggerInterface $logger): void { LoggerInterface $logger,
): void {
if ($config->getSystemValue('updatechecker', true) !== true) { if ($config->getSystemValue('updatechecker', true) !== true) {
// Updater check is disabled // Updater check is disabled
return; return;
@ -72,8 +73,8 @@ class Application extends App implements IBootstrap {
} }
if ($updateChecker->getUpdateState() !== []) { if ($updateChecker->getUpdateState() !== []) {
Util::addScript('updatenotification', 'legacy-notification'); Util::addScript('updatenotification', 'update-notification-legacy');
\OC_Hook::connect('\OCP\Config', 'js', $updateChecker, 'populateJavaScriptVariables'); $updateChecker->setInitialState();
} }
} }
}); });

@ -10,19 +10,15 @@ namespace OCA\UpdateNotification;
use OC\Updater\ChangesCheck; use OC\Updater\ChangesCheck;
use OC\Updater\VersionCheck; use OC\Updater\VersionCheck;
use OCP\AppFramework\Services\IInitialState;
class UpdateChecker { class UpdateChecker {
/** @var VersionCheck */
private $updater;
/** @var ChangesCheck */
private $changesCheck;
/** public function __construct(
* @param VersionCheck $updater private VersionCheck $updater,
*/ private ChangesCheck $changesCheck,
public function __construct(VersionCheck $updater, ChangesCheck $changesCheck) { private IInitialState $initialState,
$this->updater = $updater; ) {
$this->changesCheck = $changesCheck;
} }
/** /**
@ -59,13 +55,17 @@ class UpdateChecker {
} }
/** /**
* @param array $data * Provide update information as initial state
*/ */
public function populateJavaScriptVariables(array $data) { public function setInitialState(): void {
$data['array']['oc_updateState'] = json_encode([ $updateState = $this->getUpdateState();
'updateAvailable' => true, if (empty($updateState)) {
'updateVersion' => $this->getUpdateState()['updateVersionString'], return;
'updateLink' => $this->getUpdateState()['updateLink'] ?? '', }
$this->initialState->provideInitialState('updateState', [
'updateVersion' => $updateState['updateVersionString'],
'updateLink' => $updateState['updateLink'] ?? '',
]); ]);
} }
} }

@ -0,0 +1,24 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { showInfo } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
interface IUpdateNotificationState {
updateLink: string
updateVersion: string
}
/**
* This only gets loaded if an update is available and the notifications app is not enabled for the user.
*/
window.addEventListener('DOMContentLoaded', function() {
const { updateLink, updateVersion } = loadState<IUpdateNotificationState>('updatenotification', 'updateState')
const text = t('core', '{version} is available. Get more information on how to update.', { version: updateVersion })
// On click open the update link in a new tab
showInfo(text, { onClick: () => window.open(updateLink, '_blank') })
})

@ -11,22 +11,28 @@ namespace OCA\UpdateNotification\Tests;
use OC\Updater\ChangesCheck; use OC\Updater\ChangesCheck;
use OC\Updater\VersionCheck; use OC\Updater\VersionCheck;
use OCA\UpdateNotification\UpdateChecker; use OCA\UpdateNotification\UpdateChecker;
use OCP\AppFramework\Services\IInitialState;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase; use Test\TestCase;
class UpdateCheckerTest extends TestCase { class UpdateCheckerTest extends TestCase {
/** @var ChangesCheck|\PHPUnit\Framework\MockObject\MockObject */
protected $changesChecker; private ChangesCheck&MockObject $changesChecker;
/** @var VersionCheck|\PHPUnit\Framework\MockObject\MockObject */ private VersionCheck&MockObject $updater;
private $updater; private IInitialState&MockObject $initialState;
/** @var UpdateChecker */ private UpdateChecker $updateChecker;
private $updateChecker;
protected function setUp(): void { protected function setUp(): void {
parent::setUp(); parent::setUp();
$this->updater = $this->createMock(VersionCheck::class); $this->updater = $this->createMock(VersionCheck::class);
$this->changesChecker = $this->createMock(ChangesCheck::class); $this->changesChecker = $this->createMock(ChangesCheck::class);
$this->updateChecker = new UpdateChecker($this->updater, $this->changesChecker); $this->initialState = $this->createMock(IInitialState::class);
$this->updateChecker = new UpdateChecker(
$this->updater,
$this->changesChecker,
$this->initialState,
);
} }
public function testGetUpdateStateWithUpdateAndInvalidLink(): void { public function testGetUpdateStateWithUpdateAndInvalidLink(): void {
@ -110,4 +116,28 @@ class UpdateCheckerTest extends TestCase {
$expected = []; $expected = [];
$this->assertSame($expected, $this->updateChecker->getUpdateState()); $this->assertSame($expected, $this->updateChecker->getUpdateState());
} }
public function testSetInitialState(): void {
$this->updater
->expects($this->once())
->method('check')
->willReturn([
'version' => '1.2.3',
'versionstring' => 'Nextcloud 1.2.3',
'web' => 'https://docs.nextcloud.com/myUrl',
'url' => 'https://downloads.nextcloud.org/server',
'changes' => 'https://updates.nextcloud.com/changelog_server/?version=123.0.0',
'autoupdater' => '1',
'eol' => '0',
]);
$this->initialState->expects(self::once())
->method('provideInitialState')
->with('updateState', [
'updateVersion' => 'Nextcloud 1.2.3',
'updateLink' => 'https://docs.nextcloud.com/myUrl',
]);
$this->updateChecker->setInitialState();
}
} }

@ -107,6 +107,7 @@ module.exports = {
init: path.join(__dirname, 'apps/updatenotification/src', 'init.ts'), init: path.join(__dirname, 'apps/updatenotification/src', 'init.ts'),
'view-changelog-page': path.join(__dirname, 'apps/updatenotification/src', 'view-changelog-page.ts'), 'view-changelog-page': path.join(__dirname, 'apps/updatenotification/src', 'view-changelog-page.ts'),
updatenotification: path.join(__dirname, 'apps/updatenotification/src', 'updatenotification.js'), updatenotification: path.join(__dirname, 'apps/updatenotification/src', 'updatenotification.js'),
'update-notification-legacy': path.join(__dirname, 'apps/updatenotification/src', 'update-notification-legacy.ts'),
}, },
user_status: { user_status: {
menu: path.join(__dirname, 'apps/user_status/src', 'menu.js'), menu: path.join(__dirname, 'apps/user_status/src', 'menu.js'),