diff options
author | Vincent Petry <pvince81@owncloud.com> | 2016-05-25 09:13:10 +0200 |
---|---|---|
committer | Vincent Petry <pvince81@owncloud.com> | 2016-05-25 09:13:10 +0200 |
commit | c36cf30ade2107342710c31ce963a7b9a224c902 (patch) | |
tree | 5fc58fc8e4f7e29949f99a09b53544f99d2805a5 /apps | |
parent | 768a057aab5f4ae9bd876cb1a9c951c48048d8f5 (diff) | |
parent | a1e872aad6c2483e7349609690f9172192f4559a (diff) | |
download | nextcloud-server-c36cf30ade2107342710c31ce963a7b9a224c902.tar.gz nextcloud-server-c36cf30ade2107342710c31ce963a7b9a224c902.zip |
Merge pull request #24444 from owncloud/update-notifications-for-core-and-apps
Update notifications for core and apps
Diffstat (limited to 'apps')
-rw-r--r-- | apps/updatenotification/appinfo/app.php | 14 | ||||
-rw-r--r-- | apps/updatenotification/appinfo/info.xml | 6 | ||||
-rw-r--r-- | apps/updatenotification/js/admin.js | 16 | ||||
-rw-r--r-- | apps/updatenotification/lib/Controller/AdminController.php | 5 | ||||
-rw-r--r-- | apps/updatenotification/lib/Notification/BackgroundJob.php | 213 | ||||
-rw-r--r-- | apps/updatenotification/lib/Notification/Notifier.php | 108 | ||||
-rw-r--r-- | apps/updatenotification/templates/admin.php | 11 | ||||
-rw-r--r-- | apps/updatenotification/tests/Notification/BackgroundJobTest.php | 430 | ||||
-rw-r--r-- | apps/updatenotification/tests/Notification/NotifierTest.php | 105 |
9 files changed, 907 insertions, 1 deletions
diff --git a/apps/updatenotification/appinfo/app.php b/apps/updatenotification/appinfo/app.php index a88861c0942..e9780757cc4 100644 --- a/apps/updatenotification/appinfo/app.php +++ b/apps/updatenotification/appinfo/app.php @@ -38,4 +38,18 @@ if(\OC::$server->getConfig()->getSystemValue('updatechecker', true) === true) { \OC_App::registerAdmin('updatenotification', 'admin'); } } + + $manager = \OC::$server->getNotificationManager(); + $manager->registerNotifier(function() use ($manager) { + return new \OCA\UpdateNotification\Notification\Notifier( + $manager, + \OC::$server->getL10NFactory() + ); + }, function() { + $l = \OC::$server->getL10N('updatenotification'); + return [ + 'id' => 'updatenotification', + 'name' => $l->t('Update notifications'), + ]; + }); } diff --git a/apps/updatenotification/appinfo/info.xml b/apps/updatenotification/appinfo/info.xml index 5d7a647fd03..3ea2d1a13de 100644 --- a/apps/updatenotification/appinfo/info.xml +++ b/apps/updatenotification/appinfo/info.xml @@ -5,10 +5,14 @@ <description>Displays update notifications for ownCloud and provides the SSO for the updater.</description> <licence>AGPL</licence> <author>Lukas Reschke</author> - <version>0.2.0</version> + <version>0.2.1</version> <namespace>UpdateNotification</namespace> <default_enable/> <dependencies> <owncloud min-version="9.1" max-version="9.1" /> </dependencies> + + <background-jobs> + <job>OCA\UpdateNotification\Notification\BackgroundJob</job> + </background-jobs> </info> diff --git a/apps/updatenotification/js/admin.js b/apps/updatenotification/js/admin.js index 3bc5dd21527..3ca45a191d4 100644 --- a/apps/updatenotification/js/admin.js +++ b/apps/updatenotification/js/admin.js @@ -39,8 +39,16 @@ $(document).ready(function(){ }); }); }); + $('#release-channel').change(function() { var newChannel = $('#release-channel').find(":selected").val(); + + if (newChannel === 'git' || newChannel === 'daily') { + $('#oca_updatenotification_groups em').removeClass('hidden'); + } else { + $('#oca_updatenotification_groups em').addClass('hidden'); + } + $.post( OC.generateUrl('/apps/updatenotification/channel'), { @@ -51,4 +59,12 @@ $(document).ready(function(){ } ); }); + + var $notificationTargetGroups = $('#oca_updatenotification_groups_list'); + OC.Settings.setupGroupsSelect($notificationTargetGroups); + $notificationTargetGroups.change(function(ev) { + var groups = ev.val || []; + groups = JSON.stringify(groups); + OC.AppConfig.setValue('updatenotification', 'notify_groups', groups); + }); }); diff --git a/apps/updatenotification/lib/Controller/AdminController.php b/apps/updatenotification/lib/Controller/AdminController.php index 5dbcc685809..2fc12140b20 100644 --- a/apps/updatenotification/lib/Controller/AdminController.php +++ b/apps/updatenotification/lib/Controller/AdminController.php @@ -100,12 +100,17 @@ class AdminController extends Controller { unset($channels[$key]); } $updateState = $this->updateChecker->getUpdateState(); + + $notifyGroups = json_decode($this->config->getAppValue('updatenotification', 'notify_groups', '["admin"]'), true); + $params = [ 'isNewVersionAvailable' => ($updateState === []) ? false : true, 'lastChecked' => $lastUpdateCheck, 'currentChannel' => $currentChannel, 'channels' => $channels, 'newVersionString' => ($updateState === []) ? '' : $updateState['updateVersion'], + + 'notify_groups' => implode('|', $notifyGroups), ]; return new TemplateResponse($this->appName, 'admin', $params, ''); diff --git a/apps/updatenotification/lib/Notification/BackgroundJob.php b/apps/updatenotification/lib/Notification/BackgroundJob.php new file mode 100644 index 00000000000..e455a1642f4 --- /dev/null +++ b/apps/updatenotification/lib/Notification/BackgroundJob.php @@ -0,0 +1,213 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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/> + * + */ + +namespace OCA\UpdateNotification\Notification; + + +use OC\BackgroundJob\TimedJob; +use OC\Installer; +use OC\Updater\VersionCheck; +use OCP\App\IAppManager; +use OCP\Http\Client\IClientService; +use OCP\IConfig; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Notification\IManager; + +class BackgroundJob extends TimedJob { + + /** @var IConfig */ + protected $config; + + /** @var IManager */ + protected $notificationManager; + + /** @var IGroupManager */ + protected $groupManager; + + /** @var IAppManager */ + protected $appManager; + + /** @var IClientService */ + protected $client; + + /** @var IURLGenerator */ + protected $urlGenerator; + + /** @var IUser[] */ + protected $users; + + /** + * NotificationBackgroundJob constructor. + * + * @param IConfig $config + * @param IManager $notificationManager + * @param IGroupManager $groupManager + * @param IAppManager $appManager + * @param IClientService $client + * @param IURLGenerator $urlGenerator + */ + public function __construct(IConfig $config, IManager $notificationManager, IGroupManager $groupManager, IAppManager $appManager, IClientService $client, IURLGenerator $urlGenerator) { + // Run once a day + $this->setInterval(60 * 60 * 24); + + $this->config = $config; + $this->notificationManager = $notificationManager; + $this->groupManager = $groupManager; + $this->appManager = $appManager; + $this->client = $client; + $this->urlGenerator = $urlGenerator; + } + + protected function run($argument) { + $this->checkCoreUpdate(); + $this->checkAppUpdates(); + } + + /** + * Check for ownCloud update + */ + protected function checkCoreUpdate() { + if (in_array($this->getChannel(), ['daily', 'git'])) { + // "These aren't the update channels you're looking for." - Ben Obi-Wan Kenobi + return; + } + + $updater = $this->createVersionCheck(); + + $status = $updater->check(); + if (isset($status['version'])) { + $url = $this->urlGenerator->linkToRouteAbsolute('settings_admin') . '#updater'; + $this->createNotifications('core', $status['version'], $url); + } + } + + /** + * Check all installed apps for updates + */ + protected function checkAppUpdates() { + $apps = $this->appManager->getInstalledApps(); + foreach ($apps as $app) { + $update = $this->isUpdateAvailable($app); + if ($update !== false) { + $url = $this->urlGenerator->linkToRouteAbsolute('settings.AppSettings.viewApps') . '#app-' . $app; + $this->createNotifications($app, $update, $url); + } + } + } + + /** + * Create notifications for this app version + * + * @param string $app + * @param string $version + * @param string $url + */ + protected function createNotifications($app, $version, $url) { + $lastNotification = $this->config->getAppValue('updatenotification', $app, false); + if ($lastNotification === $version) { + // We already notified about this update + return; + } else if ($lastNotification !== false) { + // Delete old updates + $this->deleteOutdatedNotifications($app, $lastNotification); + } + + + $notification = $this->notificationManager->createNotification(); + $notification->setApp('updatenotification') + ->setDateTime(new \DateTime()) + ->setObject($app, $version) + ->setSubject('update_available') + ->setLink($url); + + foreach ($this->getUsersToNotify() as $uid) { + $notification->setUser($uid); + $this->notificationManager->notify($notification); + } + + $this->config->setAppValue('updatenotification', $app, $version); + } + + /** + * @return string[] + */ + protected function getUsersToNotify() { + if ($this->users !== null) { + return $this->users; + } + + $notifyGroups = json_decode($this->config->getAppValue('updatenotification', 'notify_groups', '["admin"]'), true); + $this->users = []; + foreach ($notifyGroups as $group) { + $groupToNotify = $this->groupManager->get($group); + if ($groupToNotify instanceof IGroup) { + foreach ($groupToNotify->getUsers() as $user) { + $this->users[$user->getUID()] = true; + } + } + } + + $this->users = array_keys($this->users); + + return $this->users; + } + + /** + * Delete notifications for old updates + * + * @param string $app + * @param string $version + */ + protected function deleteOutdatedNotifications($app, $version) { + $notification = $this->notificationManager->createNotification(); + $notification->setApp('updatenotification') + ->setObject($app, $version); + $this->notificationManager->markProcessed($notification); + } + + /** + * @return VersionCheck + */ + protected function createVersionCheck() { + return new VersionCheck( + $this->client, + $this->config + ); + } + + /** + * @return string + */ + protected function getChannel() { + return \OC_Util::getChannel(); + } + + /** + * @param string $app + * @return string|false + */ + protected function isUpdateAvailable($app) { + return Installer::isUpdateAvailable($app); + } +} diff --git a/apps/updatenotification/lib/Notification/Notifier.php b/apps/updatenotification/lib/Notification/Notifier.php new file mode 100644 index 00000000000..50505ef13f6 --- /dev/null +++ b/apps/updatenotification/lib/Notification/Notifier.php @@ -0,0 +1,108 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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/> + * + */ + +namespace OCA\UpdateNotification\Notification; + + +use OCP\L10N\IFactory; +use OCP\Notification\IManager; +use OCP\Notification\INotification; +use OCP\Notification\INotifier; + +class Notifier implements INotifier { + + /** @var IManager */ + protected $notificationManager; + + /** @var IFactory */ + protected $l10NFactory; + + /** @var string[] */ + protected $appVersions; + + /** + * Notifier constructor. + * + * @param IManager $notificationManager + * @param IFactory $l10NFactory + */ + public function __construct(IManager $notificationManager, IFactory $l10NFactory) { + $this->notificationManager = $notificationManager; + $this->l10NFactory = $l10NFactory; + $this->appVersions = $this->getAppVersions(); + } + + /** + * @param INotification $notification + * @param string $languageCode The code of the language that should be used to prepare the notification + * @return INotification + * @throws \InvalidArgumentException When the notification was not prepared by a notifier + * @since 9.0.0 + */ + public function prepare(INotification $notification, $languageCode) { + if ($notification->getApp() !== 'updatenotification') { + throw new \InvalidArgumentException(); + } + + $l = $this->l10NFactory->get('updatenotification', $languageCode); + if ($notification->getObjectType() === 'core') { + $appName = $l->t('ownCloud core'); + + $this->updateAlreadyInstalledCheck($notification, $this->getCoreVersions()); + } else { + $appInfo = $this->getAppInfo($notification->getObjectType()); + $appName = ($appInfo === null) ? $notification->getObjectType() : $appInfo['name']; + + if (isset($this->appVersions[$notification->getObjectType()])) { + $this->updateAlreadyInstalledCheck($notification, $this->appVersions[$notification->getObjectType()]); + } + } + + $notification->setParsedSubject($l->t('Update for %1$s to version %2$s is available.', [$appName, $notification->getObjectId()])); + return $notification; + } + + /** + * Remove the notification and prevent rendering, when the update is installed + * + * @param INotification $notification + * @param string $installedVersion + * @throws \InvalidArgumentException When the update is already installed + */ + protected function updateAlreadyInstalledCheck(INotification $notification, $installedVersion) { + if (version_compare($notification->getObjectId(), $installedVersion, '<=')) { + $this->notificationManager->markProcessed($notification); + throw new \InvalidArgumentException(); + } + } + + protected function getCoreVersions() { + return implode('.', \OCP\Util::getVersion()); + } + + protected function getAppVersions() { + return \OC_App::getAppVersions(); + } + + protected function getAppInfo($appId) { + return \OC_App::getAppInfo($appId); + } +} diff --git a/apps/updatenotification/templates/admin.php b/apps/updatenotification/templates/admin.php index c1adc8d0d3e..5974b106f72 100644 --- a/apps/updatenotification/templates/admin.php +++ b/apps/updatenotification/templates/admin.php @@ -39,4 +39,15 @@ <p> <em><?php p($l->t('You can always update to a newer version / experimental channel. But you can never downgrade to a more stable channel.')); ?></em> </p> + + + <p id="oca_updatenotification_groups"> + <br /> + <?php p($l->t('Notify members of the following groups about available updates:')); ?> + <input name="oca_updatenotification_groups_list" type="hidden" id="oca_updatenotification_groups_list" value="<?php p($_['notify_groups']) ?>" style="width: 400px"> + <em class="<?php if (!in_array($currentChannel, ['daily', 'git'])) p('hidden'); ?>"> + <br /> + <?php p($l->t('Only notification for app updates are available, because the selected update channel for ownCloud itself does not allow notifications.')); ?> + </em> + </p> </form> diff --git a/apps/updatenotification/tests/Notification/BackgroundJobTest.php b/apps/updatenotification/tests/Notification/BackgroundJobTest.php new file mode 100644 index 00000000000..d1076e10be5 --- /dev/null +++ b/apps/updatenotification/tests/Notification/BackgroundJobTest.php @@ -0,0 +1,430 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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/> + * + */ + +namespace OCA\UpdateNotification\Tests\Notification; + + +use OCA\UpdateNotification\Notification\BackgroundJob; +use OCP\App\IAppManager; +use OCP\Http\Client\IClientService; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Notification\IManager; +use Test\TestCase; + +class BackgroundJobTest extends TestCase { + + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $config; + /** @var IManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $notificationManager; + /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $groupManager; + /** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $appManager; + /** @var IClientService|\PHPUnit_Framework_MockObject_MockObject */ + protected $client; + /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ + protected $urlGenerator; + + public function setUp() { + parent::setUp(); + + $this->config = $this->getMock('OCP\IConfig'); + $this->notificationManager = $this->getMock('OCP\Notification\IManager'); + $this->groupManager = $this->getMock('OCP\IGroupManager'); + $this->appManager = $this->getMock('OCP\App\IAppManager'); + $this->client = $this->getMock('OCP\Http\Client\IClientService'); + $this->urlGenerator = $this->getMock('OCP\IURLGenerator'); + } + + /** + * @param array $methods + * @return BackgroundJob|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getJob(array $methods = []) { + if (empty($methods)) { + return new BackgroundJob( + $this->config, + $this->notificationManager, + $this->groupManager, + $this->appManager, + $this->client, + $this->urlGenerator + ); + } { + return $this->getMockBuilder('OCA\UpdateNotification\Notification\BackgroundJob') + ->setConstructorArgs([ + $this->config, + $this->notificationManager, + $this->groupManager, + $this->appManager, + $this->client, + $this->urlGenerator, + ]) + ->setMethods($methods) + ->getMock(); + } + } + + public function testRun() { + $job = $this->getJob([ + 'checkCoreUpdate', + 'checkAppUpdates', + ]); + + $job->expects($this->once()) + ->method('checkCoreUpdate'); + $job->expects($this->once()) + ->method('checkAppUpdates'); + + $this->invokePrivate($job, 'run', [null]); + } + + public function dataCheckCoreUpdate() { + return [ + ['daily', null, null], + ['git', null, null], + ['beta', false, null], + ['beta', [ + 'version' => '9.2.0', + ], '9.2.0'], + ['stable', false, null], + ['stable', [ + 'version' => '9.2.0', + ], '9.2.0'], + ['production', false, null], + ['production', [ + 'version' => '9.2.0', + ], '9.2.0'], + ]; + } + + /** + * @dataProvider dataCheckCoreUpdate + * + * @param string $channel + * @param mixed $versionCheck + * @param null|string $notification + */ + public function testCheckCoreUpdate($channel, $versionCheck, $notification) { + $job = $this->getJob([ + 'getChannel', + 'createVersionCheck', + 'createNotifications', + ]); + + $job->expects($this->once()) + ->method('getChannel') + ->willReturn($channel); + + if ($versionCheck === null) { + $job->expects($this->never()) + ->method('createVersionCheck'); + } else { + $check = $this->getMockBuilder('OC\Updater\VersionCheck') + ->disableOriginalConstructor() + ->getMock(); + $check->expects($this->once()) + ->method('check') + ->willReturn($versionCheck); + + $job->expects($this->once()) + ->method('createVersionCheck') + ->willReturn($check); + } + + if ($notification === null) { + $this->urlGenerator->expects($this->never()) + ->method('linkToRouteAbsolute'); + + $job->expects($this->never()) + ->method('createNotifications'); + } else { + $this->urlGenerator->expects($this->once()) + ->method('linkToRouteAbsolute') + ->with('settings_admin') + ->willReturn('admin-url'); + + $job->expects($this->once()) + ->method('createNotifications') + ->willReturn('core', $notification, 'admin-url#updater'); + } + + $this->invokePrivate($job, 'checkCoreUpdate'); + } + + public function dataCheckAppUpdates() { + return [ + [ + ['app1', 'app2'], + [ + ['app1', false], + ['app2', '1.9.2'], + ], + [ + ['app2', '1.9.2', 'apps-url#app-app2'], + ], + ], + ]; + } + + /** + * @dataProvider dataCheckAppUpdates + * + * @param string[] $apps + * @param array $isUpdateAvailable + * @param array $notifications + */ + public function testCheckAppUpdates(array $apps, array $isUpdateAvailable, array $notifications) { + $job = $this->getJob([ + 'isUpdateAvailable', + 'createNotifications', + ]); + + $this->appManager->expects($this->once()) + ->method('getInstalledApps') + ->willReturn($apps); + + $job->expects($this->exactly(sizeof($apps))) + ->method('isUpdateAvailable') + ->willReturnMap($isUpdateAvailable); + + $this->urlGenerator->expects($this->exactly(sizeof($notifications))) + ->method('linkToRouteAbsolute') + ->with('settings.AppSettings.viewApps') + ->willReturn('apps-url'); + + $mockedMethod = $job->expects($this->exactly(sizeof($notifications))) + ->method('createNotifications'); + call_user_func_array([$mockedMethod, 'withConsecutive'], $notifications); + + $this->invokePrivate($job, 'checkAppUpdates'); + } + + public function dataCreateNotifications() { + return [ + ['app1', '1.0.0', 'link1', '1.0.0', false, false, null, null], + ['app2', '1.0.1', 'link2', '1.0.0', '1.0.0', true, ['user1'], [['user1']]], + ['app3', '1.0.1', 'link3', false, false, true, ['user2', 'user3'], [['user2'], ['user3']]], + ]; + } + + /** + * @dataProvider dataCreateNotifications + * + * @param string $app + * @param string $version + * @param string $url + * @param string|false $lastNotification + * @param string|false $callDelete + * @param bool $createNotification + * @param string[]|null $users + * @param array|null $userNotifications + */ + public function testCreateNotifications($app, $version, $url, $lastNotification, $callDelete, $createNotification, $users, $userNotifications) { + $job = $this->getJob([ + 'deleteOutdatedNotifications', + 'getUsersToNotify', + ]); + + $this->config->expects($this->once()) + ->method('getAppValue') + ->with('updatenotification', $app, false) + ->willReturn($lastNotification); + + if ($lastNotification !== $version) { + $this->config->expects($this->once()) + ->method('setAppValue') + ->with('updatenotification', $app, $version); + } + + if ($callDelete === false) { + $job->expects($this->never()) + ->method('deleteOutdatedNotifications'); + } else { + $job->expects($this->once()) + ->method('deleteOutdatedNotifications') + ->with($app, $callDelete); + } + + if ($users === null) { + $job->expects($this->never()) + ->method('getUsersToNotify'); + } else { + $job->expects($this->once()) + ->method('getUsersToNotify') + ->willReturn($users); + } + + if ($createNotification) { + $notification = $this->getMock('OCP\Notification\INotification'); + $notification->expects($this->once()) + ->method('setApp') + ->with('updatenotification') + ->willReturnSelf(); + $notification->expects($this->once()) + ->method('setDateTime') + ->willReturnSelf(); + $notification->expects($this->once()) + ->method('setObject') + ->with($app, $version) + ->willReturnSelf(); + $notification->expects($this->once()) + ->method('setSubject') + ->with('update_available') + ->willReturnSelf(); + $notification->expects($this->once()) + ->method('setLink') + ->with($url) + ->willReturnSelf(); + + if ($userNotifications !== null) { + $mockedMethod = $notification->expects($this->exactly(sizeof($userNotifications))) + ->method('setUser') + ->willReturnSelf(); + call_user_func_array([$mockedMethod, 'withConsecutive'], $userNotifications); + + $this->notificationManager->expects($this->exactly(sizeof($userNotifications))) + ->method('notify') + ->willReturn($notification); + } + + $this->notificationManager->expects($this->once()) + ->method('createNotification') + ->willReturn($notification); + } else { + $this->notificationManager->expects($this->never()) + ->method('createNotification'); + } + + $this->invokePrivate($job, 'createNotifications', [$app, $version, $url]); + } + + public function dataGetUsersToNotify() { + return [ + [['g1', 'g2'], ['g1' => null, 'g2' => ['u1', 'u2']], ['u1', 'u2']], + [['g3', 'g4'], ['g3' => ['u1', 'u2'], 'g4' => ['u2', 'u3']], ['u1', 'u2', 'u3']], + ]; + } + + /** + * @dataProvider dataGetUsersToNotify + * @param string[] $groups + * @param array $groupUsers + * @param string[] $expected + */ + public function testGetUsersToNotify($groups, array $groupUsers, array $expected) { + $job = $this->getJob(); + + $this->config->expects($this->once()) + ->method('getAppValue') + ->with('updatenotification', 'notify_groups', '["admin"]') + ->willReturn(json_encode($groups)); + + $groupMap = []; + foreach ($groupUsers as $gid => $uids) { + if ($uids === null) { + $group = null; + } else { + $group = $this->getGroup($gid); + $group->expects($this->any()) + ->method('getUsers') + ->willReturn($this->getUsers($uids)); + } + $groupMap[] = [$gid, $group]; + } + $this->groupManager->expects($this->exactly(sizeof($groups))) + ->method('get') + ->willReturnMap($groupMap); + + $result = $this->invokePrivate($job, 'getUsersToNotify'); + $this->assertEquals($expected, $result); + + // Test caching + $result = $this->invokePrivate($job, 'getUsersToNotify'); + $this->assertEquals($expected, $result); + } + + public function dataDeleteOutdatedNotifications() { + return [ + ['app1', '1.1.0'], + ['app2', '1.2.0'], + ]; + } + + /** + * @dataProvider dataDeleteOutdatedNotifications + * @param string $app + * @param string $version + */ + public function testDeleteOutdatedNotifications($app, $version) { + $notification = $this->getMock('OCP\Notification\INotification'); + $notification->expects($this->once()) + ->method('setApp') + ->with('updatenotification') + ->willReturnSelf(); + $notification->expects($this->once()) + ->method('setObject') + ->with($app, $version) + ->willReturnSelf(); + + $this->notificationManager->expects($this->once()) + ->method('createNotification') + ->willReturn($notification); + $this->notificationManager->expects($this->once()) + ->method('markProcessed') + ->with($notification); + + $job = $this->getJob(); + $this->invokePrivate($job, 'deleteOutdatedNotifications', [$app, $version]); + } + + /** + * @param string[] $userIds + * @return IUser[]|\PHPUnit_Framework_MockObject_MockObject[] + */ + protected function getUsers(array $userIds) { + $users = []; + foreach ($userIds as $uid) { + $user = $this->getMock('OCP\IUser'); + $user->expects($this->any()) + ->method('getUID') + ->willReturn($uid); + $users[] = $user; + } + return $users; + } + + /** + * @param $gid + * @return \OCP\IGroup|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getGroup($gid) { + $group = $this->getMock('OCP\IGroup'); + $group->expects($this->any()) + ->method('getGID') + ->willReturn($gid); + return $group; + } +} diff --git a/apps/updatenotification/tests/Notification/NotifierTest.php b/apps/updatenotification/tests/Notification/NotifierTest.php new file mode 100644 index 00000000000..d85cf3e7072 --- /dev/null +++ b/apps/updatenotification/tests/Notification/NotifierTest.php @@ -0,0 +1,105 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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/> + * + */ + +namespace OCA\UpdateNotification\Tests\Notification; + + +use OCA\UpdateNotification\Notification\Notifier; +use OCP\L10N\IFactory; +use OCP\Notification\IManager; +use Test\TestCase; + +class NotifierTest extends TestCase { + + /** @var IManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $notificationManager; + /** @var IFactory|\PHPUnit_Framework_MockObject_MockObject */ + protected $l10nFactory; + + public function setUp() { + parent::setUp(); + + $this->notificationManager = $this->getMock('OCP\Notification\IManager'); + $this->l10nFactory = $this->getMock('OCP\L10n\IFactory'); + } + + /** + * @param array $methods + * @return Notifier|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getNotifier(array $methods = []) { + if (empty($methods)) { + return new Notifier( + $this->notificationManager, + $this->l10nFactory + ); + } { + return $this->getMockBuilder('OCA\UpdateNotification\Notification\Notifier') + ->setConstructorArgs([ + $this->notificationManager, + $this->l10nFactory, + ]) + ->setMethods($methods) + ->getMock(); + } + } + + public function dataUpdateAlreadyInstalledCheck() { + return [ + ['1.1.0', '1.0.0', false], + ['1.1.0', '1.1.0', true], + ['1.1.0', '1.2.0', true], + ]; + } + + /** + * @dataProvider dataUpdateAlreadyInstalledCheck + * + * @param string $versionNotification + * @param string $versionInstalled + * @param bool $exception + */ + public function testUpdateAlreadyInstalledCheck($versionNotification, $versionInstalled, $exception) { + $notifier = $this->getNotifier(); + + $notification = $this->getMock('OCP\Notification\INotification'); + $notification->expects($this->once()) + ->method('getObjectId') + ->willReturn($versionNotification); + + if ($exception) { + $this->notificationManager->expects($this->once()) + ->method('markProcessed') + ->with($notification); + } else { + $this->notificationManager->expects($this->never()) + ->method('markProcessed'); + } + + try { + $this->invokePrivate($notifier, 'updateAlreadyInstalledCheck', [$notification, $versionInstalled]); + $this->assertFalse($exception); + } catch (\Exception $e) { + $this->assertTrue($exception); + $this->assertInstanceOf('InvalidArgumentException', $e); + } + } +} |