@@ -23,127 +23,127 @@ |
||
23 | 23 | use Psr\Log\LoggerInterface; |
24 | 24 | |
25 | 25 | class Admin implements ISettings { |
26 | - public function __construct( |
|
27 | - private IConfig $config, |
|
28 | - private IAppConfig $appConfig, |
|
29 | - private UpdateChecker $updateChecker, |
|
30 | - private IGroupManager $groupManager, |
|
31 | - private IDateTimeFormatter $dateTimeFormatter, |
|
32 | - private IFactory $l10nFactory, |
|
33 | - private IRegistry $subscriptionRegistry, |
|
34 | - private IUserManager $userManager, |
|
35 | - private LoggerInterface $logger, |
|
36 | - private IInitialState $initialState, |
|
37 | - ) { |
|
38 | - } |
|
39 | - |
|
40 | - public function getForm(): TemplateResponse { |
|
41 | - $lastUpdateCheckTimestamp = $this->appConfig->getValueInt('core', 'lastupdatedat'); |
|
42 | - $lastUpdateCheck = $this->dateTimeFormatter->formatDateTime($lastUpdateCheckTimestamp); |
|
43 | - |
|
44 | - $channels = [ |
|
45 | - 'daily', |
|
46 | - 'beta', |
|
47 | - 'stable', |
|
48 | - 'production', |
|
49 | - ]; |
|
50 | - $currentChannel = Util::getChannel(); |
|
51 | - if ($currentChannel === 'git') { |
|
52 | - $channels[] = 'git'; |
|
53 | - } |
|
54 | - |
|
55 | - $updateState = $this->updateChecker->getUpdateState(); |
|
56 | - |
|
57 | - $notifyGroups = json_decode($this->config->getAppValue('updatenotification', 'notify_groups', '["admin"]'), true); |
|
58 | - |
|
59 | - $defaultUpdateServerURL = 'https://updates.nextcloud.com/updater_server/'; |
|
60 | - $updateServerURL = $this->config->getSystemValue('updater.server.url', $defaultUpdateServerURL); |
|
61 | - $defaultCustomerUpdateServerURLPrefix = 'https://updates.nextcloud.com/customers/'; |
|
62 | - |
|
63 | - $isDefaultUpdateServerURL = $updateServerURL === $defaultUpdateServerURL |
|
64 | - || strpos($updateServerURL, $defaultCustomerUpdateServerURLPrefix) === 0; |
|
65 | - |
|
66 | - $hasValidSubscription = $this->subscriptionRegistry->delegateHasValidSubscription(); |
|
67 | - |
|
68 | - $params = [ |
|
69 | - 'isNewVersionAvailable' => !empty($updateState['updateAvailable']), |
|
70 | - 'isUpdateChecked' => $lastUpdateCheckTimestamp > 0, |
|
71 | - 'lastChecked' => $lastUpdateCheck, |
|
72 | - 'currentChannel' => $currentChannel, |
|
73 | - 'channels' => $channels, |
|
74 | - 'newVersion' => empty($updateState['updateVersion']) ? '' : $updateState['updateVersion'], |
|
75 | - 'newVersionString' => empty($updateState['updateVersionString']) ? '' : $updateState['updateVersionString'], |
|
76 | - 'downloadLink' => empty($updateState['downloadLink']) ? '' : $updateState['downloadLink'], |
|
77 | - 'changes' => $this->filterChanges($updateState['changes'] ?? []), |
|
78 | - 'webUpdaterEnabled' => !$this->config->getSystemValue('upgrade.disable-web', false), |
|
79 | - 'isWebUpdaterRecommended' => $this->isWebUpdaterRecommended(), |
|
80 | - 'updaterEnabled' => empty($updateState['updaterEnabled']) ? false : $updateState['updaterEnabled'], |
|
81 | - 'versionIsEol' => empty($updateState['versionIsEol']) ? false : $updateState['versionIsEol'], |
|
82 | - 'isDefaultUpdateServerURL' => $isDefaultUpdateServerURL, |
|
83 | - 'updateServerURL' => $updateServerURL, |
|
84 | - 'notifyGroups' => $this->getSelectedGroups($notifyGroups), |
|
85 | - 'hasValidSubscription' => $hasValidSubscription, |
|
86 | - ]; |
|
87 | - $this->initialState->provideInitialState('data', $params); |
|
88 | - |
|
89 | - return new TemplateResponse('updatenotification', 'admin', [], ''); |
|
90 | - } |
|
91 | - |
|
92 | - protected function filterChanges(array $changes): array { |
|
93 | - $filtered = []; |
|
94 | - if (isset($changes['changelogURL'])) { |
|
95 | - $filtered['changelogURL'] = $changes['changelogURL']; |
|
96 | - } |
|
97 | - if (!isset($changes['whatsNew'])) { |
|
98 | - return $filtered; |
|
99 | - } |
|
100 | - |
|
101 | - $iterator = $this->l10nFactory->getLanguageIterator(); |
|
102 | - do { |
|
103 | - $lang = $iterator->current(); |
|
104 | - if (isset($changes['whatsNew'][$lang])) { |
|
105 | - $filtered['whatsNew'] = $changes['whatsNew'][$lang]; |
|
106 | - return $filtered; |
|
107 | - } |
|
108 | - $iterator->next(); |
|
109 | - } while ($lang !== 'en' && $iterator->valid()); |
|
110 | - |
|
111 | - return $filtered; |
|
112 | - } |
|
113 | - |
|
114 | - /** |
|
115 | - * @param list<string> $groupIds |
|
116 | - * @return list<array{id: string, displayname: string}> |
|
117 | - */ |
|
118 | - protected function getSelectedGroups(array $groupIds): array { |
|
119 | - $result = []; |
|
120 | - foreach ($groupIds as $groupId) { |
|
121 | - $group = $this->groupManager->get($groupId); |
|
122 | - |
|
123 | - if ($group === null) { |
|
124 | - continue; |
|
125 | - } |
|
126 | - |
|
127 | - $result[] = ['id' => $group->getGID(), 'displayname' => $group->getDisplayName()]; |
|
128 | - } |
|
129 | - |
|
130 | - return $result; |
|
131 | - } |
|
132 | - |
|
133 | - public function getSection(): ?string { |
|
134 | - if (!$this->config->getSystemValueBool('updatechecker', true)) { |
|
135 | - // update checker is disabled so we do not show the section at all |
|
136 | - return null; |
|
137 | - } |
|
138 | - |
|
139 | - return 'overview'; |
|
140 | - } |
|
141 | - |
|
142 | - public function getPriority(): int { |
|
143 | - return 11; |
|
144 | - } |
|
145 | - |
|
146 | - private function isWebUpdaterRecommended(): bool { |
|
147 | - return (int)$this->userManager->countUsersTotal(100) < 100; |
|
148 | - } |
|
26 | + public function __construct( |
|
27 | + private IConfig $config, |
|
28 | + private IAppConfig $appConfig, |
|
29 | + private UpdateChecker $updateChecker, |
|
30 | + private IGroupManager $groupManager, |
|
31 | + private IDateTimeFormatter $dateTimeFormatter, |
|
32 | + private IFactory $l10nFactory, |
|
33 | + private IRegistry $subscriptionRegistry, |
|
34 | + private IUserManager $userManager, |
|
35 | + private LoggerInterface $logger, |
|
36 | + private IInitialState $initialState, |
|
37 | + ) { |
|
38 | + } |
|
39 | + |
|
40 | + public function getForm(): TemplateResponse { |
|
41 | + $lastUpdateCheckTimestamp = $this->appConfig->getValueInt('core', 'lastupdatedat'); |
|
42 | + $lastUpdateCheck = $this->dateTimeFormatter->formatDateTime($lastUpdateCheckTimestamp); |
|
43 | + |
|
44 | + $channels = [ |
|
45 | + 'daily', |
|
46 | + 'beta', |
|
47 | + 'stable', |
|
48 | + 'production', |
|
49 | + ]; |
|
50 | + $currentChannel = Util::getChannel(); |
|
51 | + if ($currentChannel === 'git') { |
|
52 | + $channels[] = 'git'; |
|
53 | + } |
|
54 | + |
|
55 | + $updateState = $this->updateChecker->getUpdateState(); |
|
56 | + |
|
57 | + $notifyGroups = json_decode($this->config->getAppValue('updatenotification', 'notify_groups', '["admin"]'), true); |
|
58 | + |
|
59 | + $defaultUpdateServerURL = 'https://updates.nextcloud.com/updater_server/'; |
|
60 | + $updateServerURL = $this->config->getSystemValue('updater.server.url', $defaultUpdateServerURL); |
|
61 | + $defaultCustomerUpdateServerURLPrefix = 'https://updates.nextcloud.com/customers/'; |
|
62 | + |
|
63 | + $isDefaultUpdateServerURL = $updateServerURL === $defaultUpdateServerURL |
|
64 | + || strpos($updateServerURL, $defaultCustomerUpdateServerURLPrefix) === 0; |
|
65 | + |
|
66 | + $hasValidSubscription = $this->subscriptionRegistry->delegateHasValidSubscription(); |
|
67 | + |
|
68 | + $params = [ |
|
69 | + 'isNewVersionAvailable' => !empty($updateState['updateAvailable']), |
|
70 | + 'isUpdateChecked' => $lastUpdateCheckTimestamp > 0, |
|
71 | + 'lastChecked' => $lastUpdateCheck, |
|
72 | + 'currentChannel' => $currentChannel, |
|
73 | + 'channels' => $channels, |
|
74 | + 'newVersion' => empty($updateState['updateVersion']) ? '' : $updateState['updateVersion'], |
|
75 | + 'newVersionString' => empty($updateState['updateVersionString']) ? '' : $updateState['updateVersionString'], |
|
76 | + 'downloadLink' => empty($updateState['downloadLink']) ? '' : $updateState['downloadLink'], |
|
77 | + 'changes' => $this->filterChanges($updateState['changes'] ?? []), |
|
78 | + 'webUpdaterEnabled' => !$this->config->getSystemValue('upgrade.disable-web', false), |
|
79 | + 'isWebUpdaterRecommended' => $this->isWebUpdaterRecommended(), |
|
80 | + 'updaterEnabled' => empty($updateState['updaterEnabled']) ? false : $updateState['updaterEnabled'], |
|
81 | + 'versionIsEol' => empty($updateState['versionIsEol']) ? false : $updateState['versionIsEol'], |
|
82 | + 'isDefaultUpdateServerURL' => $isDefaultUpdateServerURL, |
|
83 | + 'updateServerURL' => $updateServerURL, |
|
84 | + 'notifyGroups' => $this->getSelectedGroups($notifyGroups), |
|
85 | + 'hasValidSubscription' => $hasValidSubscription, |
|
86 | + ]; |
|
87 | + $this->initialState->provideInitialState('data', $params); |
|
88 | + |
|
89 | + return new TemplateResponse('updatenotification', 'admin', [], ''); |
|
90 | + } |
|
91 | + |
|
92 | + protected function filterChanges(array $changes): array { |
|
93 | + $filtered = []; |
|
94 | + if (isset($changes['changelogURL'])) { |
|
95 | + $filtered['changelogURL'] = $changes['changelogURL']; |
|
96 | + } |
|
97 | + if (!isset($changes['whatsNew'])) { |
|
98 | + return $filtered; |
|
99 | + } |
|
100 | + |
|
101 | + $iterator = $this->l10nFactory->getLanguageIterator(); |
|
102 | + do { |
|
103 | + $lang = $iterator->current(); |
|
104 | + if (isset($changes['whatsNew'][$lang])) { |
|
105 | + $filtered['whatsNew'] = $changes['whatsNew'][$lang]; |
|
106 | + return $filtered; |
|
107 | + } |
|
108 | + $iterator->next(); |
|
109 | + } while ($lang !== 'en' && $iterator->valid()); |
|
110 | + |
|
111 | + return $filtered; |
|
112 | + } |
|
113 | + |
|
114 | + /** |
|
115 | + * @param list<string> $groupIds |
|
116 | + * @return list<array{id: string, displayname: string}> |
|
117 | + */ |
|
118 | + protected function getSelectedGroups(array $groupIds): array { |
|
119 | + $result = []; |
|
120 | + foreach ($groupIds as $groupId) { |
|
121 | + $group = $this->groupManager->get($groupId); |
|
122 | + |
|
123 | + if ($group === null) { |
|
124 | + continue; |
|
125 | + } |
|
126 | + |
|
127 | + $result[] = ['id' => $group->getGID(), 'displayname' => $group->getDisplayName()]; |
|
128 | + } |
|
129 | + |
|
130 | + return $result; |
|
131 | + } |
|
132 | + |
|
133 | + public function getSection(): ?string { |
|
134 | + if (!$this->config->getSystemValueBool('updatechecker', true)) { |
|
135 | + // update checker is disabled so we do not show the section at all |
|
136 | + return null; |
|
137 | + } |
|
138 | + |
|
139 | + return 'overview'; |
|
140 | + } |
|
141 | + |
|
142 | + public function getPriority(): int { |
|
143 | + return 11; |
|
144 | + } |
|
145 | + |
|
146 | + private function isWebUpdaterRecommended(): bool { |
|
147 | + return (int)$this->userManager->countUsersTotal(100) < 100; |
|
148 | + } |
|
149 | 149 | } |
@@ -21,218 +21,218 @@ |
||
21 | 21 | use OCP\ServerVersion; |
22 | 22 | |
23 | 23 | class UpdateAvailableNotifications extends TimedJob { |
24 | - protected $connectionNotifications = [3, 7, 14, 30]; |
|
25 | - |
|
26 | - /** @var string[] */ |
|
27 | - protected $users; |
|
28 | - |
|
29 | - public function __construct( |
|
30 | - ITimeFactory $timeFactory, |
|
31 | - protected ServerVersion $serverVersion, |
|
32 | - protected IConfig $config, |
|
33 | - protected IAppConfig $appConfig, |
|
34 | - protected IManager $notificationManager, |
|
35 | - protected IGroupManager $groupManager, |
|
36 | - protected IAppManager $appManager, |
|
37 | - protected Installer $installer, |
|
38 | - protected VersionCheck $versionCheck, |
|
39 | - ) { |
|
40 | - parent::__construct($timeFactory); |
|
41 | - // Run once a day |
|
42 | - $this->setInterval(60 * 60 * 24); |
|
43 | - $this->setTimeSensitivity(self::TIME_INSENSITIVE); |
|
44 | - } |
|
45 | - |
|
46 | - protected function run($argument) { |
|
47 | - // Do not check for updates if not connected to the internet |
|
48 | - if (!$this->config->getSystemValueBool('has_internet_connection', true)) { |
|
49 | - return; |
|
50 | - } |
|
51 | - |
|
52 | - if (\OC::$CLI && !$this->config->getSystemValueBool('debug', false)) { |
|
53 | - try { |
|
54 | - // Jitter the pinging of the updater server and the appstore a bit. |
|
55 | - // Otherwise all Nextcloud installations are pinging the servers |
|
56 | - // in one of 288 |
|
57 | - sleep(random_int(1, 180)); |
|
58 | - } catch (\Exception $e) { |
|
59 | - } |
|
60 | - } |
|
61 | - |
|
62 | - $this->checkCoreUpdate(); |
|
63 | - $this->checkAppUpdates(); |
|
64 | - } |
|
65 | - |
|
66 | - /** |
|
67 | - * Check for Nextcloud server update |
|
68 | - */ |
|
69 | - protected function checkCoreUpdate() { |
|
70 | - if (!$this->config->getSystemValueBool('updatechecker', true)) { |
|
71 | - // update checker is disabled so no core update check! |
|
72 | - return; |
|
73 | - } |
|
74 | - |
|
75 | - if (\in_array($this->serverVersion->getChannel(), ['daily', 'git'], true)) { |
|
76 | - // "These aren't the update channels you're looking for." - Ben Obi-Wan Kenobi |
|
77 | - return; |
|
78 | - } |
|
79 | - |
|
80 | - $status = $this->versionCheck->check(); |
|
81 | - if ($status === false) { |
|
82 | - $errors = 1 + $this->appConfig->getAppValueInt('update_check_errors', 0); |
|
83 | - $this->appConfig->setAppValueInt('update_check_errors', $errors); |
|
84 | - |
|
85 | - if (\in_array($errors, $this->connectionNotifications, true)) { |
|
86 | - $this->sendErrorNotifications($errors); |
|
87 | - } |
|
88 | - } elseif (\is_array($status)) { |
|
89 | - $this->appConfig->setAppValueInt('update_check_errors', 0); |
|
90 | - $this->clearErrorNotifications(); |
|
91 | - |
|
92 | - if (isset($status['version'])) { |
|
93 | - $this->createNotifications('core', $status['version'], $status['versionstring']); |
|
94 | - } |
|
95 | - } |
|
96 | - } |
|
97 | - |
|
98 | - /** |
|
99 | - * Send a message to the admin when the update server could not be reached |
|
100 | - * @param int $numDays |
|
101 | - */ |
|
102 | - protected function sendErrorNotifications($numDays) { |
|
103 | - $this->clearErrorNotifications(); |
|
104 | - |
|
105 | - $notification = $this->notificationManager->createNotification(); |
|
106 | - try { |
|
107 | - $notification->setApp('updatenotification') |
|
108 | - ->setDateTime(new \DateTime()) |
|
109 | - ->setObject('updatenotification', 'error') |
|
110 | - ->setSubject('connection_error', ['days' => $numDays]); |
|
111 | - |
|
112 | - foreach ($this->getUsersToNotify() as $uid) { |
|
113 | - $notification->setUser($uid); |
|
114 | - $this->notificationManager->notify($notification); |
|
115 | - } |
|
116 | - } catch (\InvalidArgumentException $e) { |
|
117 | - return; |
|
118 | - } |
|
119 | - } |
|
120 | - |
|
121 | - /** |
|
122 | - * Remove error notifications again |
|
123 | - */ |
|
124 | - protected function clearErrorNotifications() { |
|
125 | - $notification = $this->notificationManager->createNotification(); |
|
126 | - try { |
|
127 | - $notification->setApp('updatenotification') |
|
128 | - ->setSubject('connection_error') |
|
129 | - ->setObject('updatenotification', 'error'); |
|
130 | - } catch (\InvalidArgumentException $e) { |
|
131 | - return; |
|
132 | - } |
|
133 | - $this->notificationManager->markProcessed($notification); |
|
134 | - } |
|
135 | - |
|
136 | - /** |
|
137 | - * Check all installed apps for updates |
|
138 | - */ |
|
139 | - protected function checkAppUpdates() { |
|
140 | - $apps = $this->appManager->getEnabledApps(); |
|
141 | - foreach ($apps as $app) { |
|
142 | - $update = $this->isUpdateAvailable($app); |
|
143 | - if ($update !== false) { |
|
144 | - $this->createNotifications($app, $update); |
|
145 | - } |
|
146 | - } |
|
147 | - } |
|
148 | - |
|
149 | - /** |
|
150 | - * Create notifications for this app version |
|
151 | - * |
|
152 | - * @param string $app |
|
153 | - * @param string $version |
|
154 | - * @param string $visibleVersion |
|
155 | - */ |
|
156 | - protected function createNotifications($app, $version, $visibleVersion = '') { |
|
157 | - $lastNotification = $this->appConfig->getAppValueString($app, ''); |
|
158 | - if ($lastNotification === $version) { |
|
159 | - // We already notified about this update |
|
160 | - return; |
|
161 | - } |
|
162 | - |
|
163 | - if ($lastNotification !== '') { |
|
164 | - // Delete old updates |
|
165 | - $this->deleteOutdatedNotifications($app, $lastNotification); |
|
166 | - } |
|
167 | - |
|
168 | - $notification = $this->notificationManager->createNotification(); |
|
169 | - try { |
|
170 | - $notification->setApp('updatenotification') |
|
171 | - ->setDateTime(new \DateTime()) |
|
172 | - ->setObject($app, $version); |
|
173 | - |
|
174 | - if ($visibleVersion !== '') { |
|
175 | - $notification->setSubject('update_available', ['version' => $visibleVersion]); |
|
176 | - } else { |
|
177 | - $notification->setSubject('update_available'); |
|
178 | - } |
|
179 | - |
|
180 | - foreach ($this->getUsersToNotify() as $uid) { |
|
181 | - $notification->setUser($uid); |
|
182 | - $this->notificationManager->notify($notification); |
|
183 | - } |
|
184 | - } catch (\InvalidArgumentException $e) { |
|
185 | - return; |
|
186 | - } |
|
187 | - |
|
188 | - $this->appConfig->setAppValueString($app, $version); |
|
189 | - } |
|
190 | - |
|
191 | - /** |
|
192 | - * @return string[] |
|
193 | - */ |
|
194 | - protected function getUsersToNotify(): array { |
|
195 | - if ($this->users !== null) { |
|
196 | - return $this->users; |
|
197 | - } |
|
198 | - |
|
199 | - $notifyGroups = $this->appConfig->getAppValueArray('notify_groups', ['admin']); |
|
200 | - $this->users = []; |
|
201 | - foreach ($notifyGroups as $group) { |
|
202 | - $groupToNotify = $this->groupManager->get($group); |
|
203 | - if ($groupToNotify instanceof IGroup) { |
|
204 | - foreach ($groupToNotify->getUsers() as $user) { |
|
205 | - $this->users[] = $user->getUID(); |
|
206 | - } |
|
207 | - } |
|
208 | - } |
|
209 | - |
|
210 | - $this->users = array_values(array_unique($this->users)); |
|
211 | - return $this->users; |
|
212 | - } |
|
213 | - |
|
214 | - /** |
|
215 | - * Delete notifications for old updates |
|
216 | - * |
|
217 | - * @param string $app |
|
218 | - * @param string $version |
|
219 | - */ |
|
220 | - protected function deleteOutdatedNotifications($app, $version) { |
|
221 | - $notification = $this->notificationManager->createNotification(); |
|
222 | - try { |
|
223 | - $notification->setApp('updatenotification') |
|
224 | - ->setObject($app, $version); |
|
225 | - } catch (\InvalidArgumentException $e) { |
|
226 | - return; |
|
227 | - } |
|
228 | - $this->notificationManager->markProcessed($notification); |
|
229 | - } |
|
230 | - |
|
231 | - /** |
|
232 | - * @param string $app |
|
233 | - * @return string|false |
|
234 | - */ |
|
235 | - protected function isUpdateAvailable($app) { |
|
236 | - return $this->installer->isUpdateAvailable($app); |
|
237 | - } |
|
24 | + protected $connectionNotifications = [3, 7, 14, 30]; |
|
25 | + |
|
26 | + /** @var string[] */ |
|
27 | + protected $users; |
|
28 | + |
|
29 | + public function __construct( |
|
30 | + ITimeFactory $timeFactory, |
|
31 | + protected ServerVersion $serverVersion, |
|
32 | + protected IConfig $config, |
|
33 | + protected IAppConfig $appConfig, |
|
34 | + protected IManager $notificationManager, |
|
35 | + protected IGroupManager $groupManager, |
|
36 | + protected IAppManager $appManager, |
|
37 | + protected Installer $installer, |
|
38 | + protected VersionCheck $versionCheck, |
|
39 | + ) { |
|
40 | + parent::__construct($timeFactory); |
|
41 | + // Run once a day |
|
42 | + $this->setInterval(60 * 60 * 24); |
|
43 | + $this->setTimeSensitivity(self::TIME_INSENSITIVE); |
|
44 | + } |
|
45 | + |
|
46 | + protected function run($argument) { |
|
47 | + // Do not check for updates if not connected to the internet |
|
48 | + if (!$this->config->getSystemValueBool('has_internet_connection', true)) { |
|
49 | + return; |
|
50 | + } |
|
51 | + |
|
52 | + if (\OC::$CLI && !$this->config->getSystemValueBool('debug', false)) { |
|
53 | + try { |
|
54 | + // Jitter the pinging of the updater server and the appstore a bit. |
|
55 | + // Otherwise all Nextcloud installations are pinging the servers |
|
56 | + // in one of 288 |
|
57 | + sleep(random_int(1, 180)); |
|
58 | + } catch (\Exception $e) { |
|
59 | + } |
|
60 | + } |
|
61 | + |
|
62 | + $this->checkCoreUpdate(); |
|
63 | + $this->checkAppUpdates(); |
|
64 | + } |
|
65 | + |
|
66 | + /** |
|
67 | + * Check for Nextcloud server update |
|
68 | + */ |
|
69 | + protected function checkCoreUpdate() { |
|
70 | + if (!$this->config->getSystemValueBool('updatechecker', true)) { |
|
71 | + // update checker is disabled so no core update check! |
|
72 | + return; |
|
73 | + } |
|
74 | + |
|
75 | + if (\in_array($this->serverVersion->getChannel(), ['daily', 'git'], true)) { |
|
76 | + // "These aren't the update channels you're looking for." - Ben Obi-Wan Kenobi |
|
77 | + return; |
|
78 | + } |
|
79 | + |
|
80 | + $status = $this->versionCheck->check(); |
|
81 | + if ($status === false) { |
|
82 | + $errors = 1 + $this->appConfig->getAppValueInt('update_check_errors', 0); |
|
83 | + $this->appConfig->setAppValueInt('update_check_errors', $errors); |
|
84 | + |
|
85 | + if (\in_array($errors, $this->connectionNotifications, true)) { |
|
86 | + $this->sendErrorNotifications($errors); |
|
87 | + } |
|
88 | + } elseif (\is_array($status)) { |
|
89 | + $this->appConfig->setAppValueInt('update_check_errors', 0); |
|
90 | + $this->clearErrorNotifications(); |
|
91 | + |
|
92 | + if (isset($status['version'])) { |
|
93 | + $this->createNotifications('core', $status['version'], $status['versionstring']); |
|
94 | + } |
|
95 | + } |
|
96 | + } |
|
97 | + |
|
98 | + /** |
|
99 | + * Send a message to the admin when the update server could not be reached |
|
100 | + * @param int $numDays |
|
101 | + */ |
|
102 | + protected function sendErrorNotifications($numDays) { |
|
103 | + $this->clearErrorNotifications(); |
|
104 | + |
|
105 | + $notification = $this->notificationManager->createNotification(); |
|
106 | + try { |
|
107 | + $notification->setApp('updatenotification') |
|
108 | + ->setDateTime(new \DateTime()) |
|
109 | + ->setObject('updatenotification', 'error') |
|
110 | + ->setSubject('connection_error', ['days' => $numDays]); |
|
111 | + |
|
112 | + foreach ($this->getUsersToNotify() as $uid) { |
|
113 | + $notification->setUser($uid); |
|
114 | + $this->notificationManager->notify($notification); |
|
115 | + } |
|
116 | + } catch (\InvalidArgumentException $e) { |
|
117 | + return; |
|
118 | + } |
|
119 | + } |
|
120 | + |
|
121 | + /** |
|
122 | + * Remove error notifications again |
|
123 | + */ |
|
124 | + protected function clearErrorNotifications() { |
|
125 | + $notification = $this->notificationManager->createNotification(); |
|
126 | + try { |
|
127 | + $notification->setApp('updatenotification') |
|
128 | + ->setSubject('connection_error') |
|
129 | + ->setObject('updatenotification', 'error'); |
|
130 | + } catch (\InvalidArgumentException $e) { |
|
131 | + return; |
|
132 | + } |
|
133 | + $this->notificationManager->markProcessed($notification); |
|
134 | + } |
|
135 | + |
|
136 | + /** |
|
137 | + * Check all installed apps for updates |
|
138 | + */ |
|
139 | + protected function checkAppUpdates() { |
|
140 | + $apps = $this->appManager->getEnabledApps(); |
|
141 | + foreach ($apps as $app) { |
|
142 | + $update = $this->isUpdateAvailable($app); |
|
143 | + if ($update !== false) { |
|
144 | + $this->createNotifications($app, $update); |
|
145 | + } |
|
146 | + } |
|
147 | + } |
|
148 | + |
|
149 | + /** |
|
150 | + * Create notifications for this app version |
|
151 | + * |
|
152 | + * @param string $app |
|
153 | + * @param string $version |
|
154 | + * @param string $visibleVersion |
|
155 | + */ |
|
156 | + protected function createNotifications($app, $version, $visibleVersion = '') { |
|
157 | + $lastNotification = $this->appConfig->getAppValueString($app, ''); |
|
158 | + if ($lastNotification === $version) { |
|
159 | + // We already notified about this update |
|
160 | + return; |
|
161 | + } |
|
162 | + |
|
163 | + if ($lastNotification !== '') { |
|
164 | + // Delete old updates |
|
165 | + $this->deleteOutdatedNotifications($app, $lastNotification); |
|
166 | + } |
|
167 | + |
|
168 | + $notification = $this->notificationManager->createNotification(); |
|
169 | + try { |
|
170 | + $notification->setApp('updatenotification') |
|
171 | + ->setDateTime(new \DateTime()) |
|
172 | + ->setObject($app, $version); |
|
173 | + |
|
174 | + if ($visibleVersion !== '') { |
|
175 | + $notification->setSubject('update_available', ['version' => $visibleVersion]); |
|
176 | + } else { |
|
177 | + $notification->setSubject('update_available'); |
|
178 | + } |
|
179 | + |
|
180 | + foreach ($this->getUsersToNotify() as $uid) { |
|
181 | + $notification->setUser($uid); |
|
182 | + $this->notificationManager->notify($notification); |
|
183 | + } |
|
184 | + } catch (\InvalidArgumentException $e) { |
|
185 | + return; |
|
186 | + } |
|
187 | + |
|
188 | + $this->appConfig->setAppValueString($app, $version); |
|
189 | + } |
|
190 | + |
|
191 | + /** |
|
192 | + * @return string[] |
|
193 | + */ |
|
194 | + protected function getUsersToNotify(): array { |
|
195 | + if ($this->users !== null) { |
|
196 | + return $this->users; |
|
197 | + } |
|
198 | + |
|
199 | + $notifyGroups = $this->appConfig->getAppValueArray('notify_groups', ['admin']); |
|
200 | + $this->users = []; |
|
201 | + foreach ($notifyGroups as $group) { |
|
202 | + $groupToNotify = $this->groupManager->get($group); |
|
203 | + if ($groupToNotify instanceof IGroup) { |
|
204 | + foreach ($groupToNotify->getUsers() as $user) { |
|
205 | + $this->users[] = $user->getUID(); |
|
206 | + } |
|
207 | + } |
|
208 | + } |
|
209 | + |
|
210 | + $this->users = array_values(array_unique($this->users)); |
|
211 | + return $this->users; |
|
212 | + } |
|
213 | + |
|
214 | + /** |
|
215 | + * Delete notifications for old updates |
|
216 | + * |
|
217 | + * @param string $app |
|
218 | + * @param string $version |
|
219 | + */ |
|
220 | + protected function deleteOutdatedNotifications($app, $version) { |
|
221 | + $notification = $this->notificationManager->createNotification(); |
|
222 | + try { |
|
223 | + $notification->setApp('updatenotification') |
|
224 | + ->setObject($app, $version); |
|
225 | + } catch (\InvalidArgumentException $e) { |
|
226 | + return; |
|
227 | + } |
|
228 | + $this->notificationManager->markProcessed($notification); |
|
229 | + } |
|
230 | + |
|
231 | + /** |
|
232 | + * @param string $app |
|
233 | + * @return string|false |
|
234 | + */ |
|
235 | + protected function isUpdateAvailable($app) { |
|
236 | + return $this->installer->isUpdateAvailable($app); |
|
237 | + } |
|
238 | 238 | } |
@@ -26,452 +26,452 @@ |
||
26 | 26 | use Test\TestCase; |
27 | 27 | |
28 | 28 | class AdminTest extends TestCase { |
29 | - /** @var IFactory|\PHPUnit\Framework\MockObject\MockObject */ |
|
30 | - protected $l10nFactory; |
|
31 | - /** @var Admin */ |
|
32 | - private $admin; |
|
33 | - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ |
|
34 | - private $config; |
|
35 | - /** @var IAppConfig|\PHPUnit\Framework\MockObject\MockObject */ |
|
36 | - private $appConfig; |
|
37 | - /** @var UpdateChecker|\PHPUnit\Framework\MockObject\MockObject */ |
|
38 | - private $updateChecker; |
|
39 | - /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */ |
|
40 | - private $groupManager; |
|
41 | - /** @var IDateTimeFormatter|\PHPUnit\Framework\MockObject\MockObject */ |
|
42 | - private $dateTimeFormatter; |
|
43 | - /** @var IRegistry|\PHPUnit\Framework\MockObject\MockObject */ |
|
44 | - private $subscriptionRegistry; |
|
45 | - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ |
|
46 | - private $userManager; |
|
47 | - /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ |
|
48 | - private $logger; |
|
49 | - /** IInitialState|\PHPUnit\Framework\MockObject\MockObject */ |
|
50 | - private $initialState; |
|
51 | - |
|
52 | - protected function setUp(): void { |
|
53 | - parent::setUp(); |
|
54 | - |
|
55 | - $this->config = $this->createMock(IConfig::class); |
|
56 | - $this->appConfig = $this->createMock(IAppConfig::class); |
|
57 | - $this->updateChecker = $this->createMock(UpdateChecker::class); |
|
58 | - $this->groupManager = $this->createMock(IGroupManager::class); |
|
59 | - $this->dateTimeFormatter = $this->createMock(IDateTimeFormatter::class); |
|
60 | - $this->l10nFactory = $this->createMock(IFactory::class); |
|
61 | - $this->subscriptionRegistry = $this->createMock(IRegistry::class); |
|
62 | - $this->userManager = $this->createMock(IUserManager::class); |
|
63 | - $this->logger = $this->createMock(LoggerInterface::class); |
|
64 | - $this->initialState = $this->createMock(IInitialState::class); |
|
65 | - |
|
66 | - $this->admin = new Admin( |
|
67 | - $this->config, |
|
68 | - $this->appConfig, |
|
69 | - $this->updateChecker, |
|
70 | - $this->groupManager, |
|
71 | - $this->dateTimeFormatter, |
|
72 | - $this->l10nFactory, |
|
73 | - $this->subscriptionRegistry, |
|
74 | - $this->userManager, |
|
75 | - $this->logger, |
|
76 | - $this->initialState |
|
77 | - ); |
|
78 | - } |
|
79 | - |
|
80 | - public function testGetFormWithUpdate(): void { |
|
81 | - $this->userManager |
|
82 | - ->expects($this->once()) |
|
83 | - ->method('countUsersTotal') |
|
84 | - ->willReturn(5); |
|
85 | - $channels = [ |
|
86 | - 'daily', |
|
87 | - 'beta', |
|
88 | - 'stable', |
|
89 | - 'production', |
|
90 | - ]; |
|
91 | - $currentChannel = Util::getChannel(); |
|
92 | - if ($currentChannel === 'git') { |
|
93 | - $channels[] = 'git'; |
|
94 | - } |
|
95 | - $this->appConfig |
|
96 | - ->expects($this->once()) |
|
97 | - ->method('getValueInt') |
|
98 | - ->with('core', 'lastupdatedat', 0) |
|
99 | - ->willReturn(12345); |
|
100 | - $this->config |
|
101 | - ->expects($this->once()) |
|
102 | - ->method('getAppValue') |
|
103 | - ->with('updatenotification', 'notify_groups', '["admin"]') |
|
104 | - ->willReturn('["admin"]'); |
|
105 | - $this->config |
|
106 | - ->method('getSystemValue') |
|
107 | - ->willReturnMap([ |
|
108 | - ['updater.server.url', 'https://updates.nextcloud.com/updater_server/', 'https://updates.nextcloud.com/updater_server/'], |
|
109 | - ['upgrade.disable-web', false, false], |
|
110 | - ]); |
|
111 | - $this->config |
|
112 | - ->expects(self::any()) |
|
113 | - ->method('getSystemValueBool') |
|
114 | - ->with('updatechecker', true) |
|
115 | - ->willReturn(true); |
|
116 | - $this->dateTimeFormatter |
|
117 | - ->expects($this->once()) |
|
118 | - ->method('formatDateTime') |
|
119 | - ->with(12345) |
|
120 | - ->willReturn('LastCheckedReturnValue'); |
|
121 | - $this->updateChecker |
|
122 | - ->expects($this->once()) |
|
123 | - ->method('getUpdateState') |
|
124 | - ->willReturn([ |
|
125 | - 'updateAvailable' => true, |
|
126 | - 'updateVersion' => '8.1.2', |
|
127 | - 'updateVersionString' => 'Nextcloud 8.1.2', |
|
128 | - 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
129 | - 'changes' => [], |
|
130 | - 'updaterEnabled' => true, |
|
131 | - 'versionIsEol' => false, |
|
132 | - ]); |
|
133 | - |
|
134 | - $group = $this->createMock(IGroup::class); |
|
135 | - $group->expects($this->any()) |
|
136 | - ->method('getDisplayName') |
|
137 | - ->willReturn('Administrators'); |
|
138 | - $group->expects($this->any()) |
|
139 | - ->method('getGID') |
|
140 | - ->willReturn('admin'); |
|
141 | - $this->groupManager->expects($this->once()) |
|
142 | - ->method('get') |
|
143 | - ->with('admin') |
|
144 | - ->willReturn($group); |
|
145 | - |
|
146 | - $this->subscriptionRegistry |
|
147 | - ->expects($this->once()) |
|
148 | - ->method('delegateHasValidSubscription') |
|
149 | - ->willReturn(true); |
|
150 | - |
|
151 | - $this->initialState->expects($this->once()) |
|
152 | - ->method('provideInitialState') |
|
153 | - ->with('data', [ |
|
154 | - 'isNewVersionAvailable' => true, |
|
155 | - 'isUpdateChecked' => true, |
|
156 | - 'lastChecked' => 'LastCheckedReturnValue', |
|
157 | - 'currentChannel' => Util::getChannel(), |
|
158 | - 'channels' => $channels, |
|
159 | - 'newVersion' => '8.1.2', |
|
160 | - 'newVersionString' => 'Nextcloud 8.1.2', |
|
161 | - 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
162 | - 'changes' => [], |
|
163 | - 'webUpdaterEnabled' => true, |
|
164 | - 'isWebUpdaterRecommended' => true, |
|
165 | - 'updaterEnabled' => true, |
|
166 | - 'versionIsEol' => false, |
|
167 | - 'isDefaultUpdateServerURL' => true, |
|
168 | - 'updateServerURL' => 'https://updates.nextcloud.com/updater_server/', |
|
169 | - 'notifyGroups' => [ |
|
170 | - ['id' => 'admin', 'displayname' => 'Administrators'], |
|
171 | - ], |
|
172 | - 'hasValidSubscription' => true, |
|
173 | - ]); |
|
174 | - |
|
175 | - $expected = new TemplateResponse('updatenotification', 'admin', [], ''); |
|
176 | - $this->assertEquals($expected, $this->admin->getForm()); |
|
177 | - } |
|
178 | - |
|
179 | - public function testGetFormWithUpdateAndChangedUpdateServer(): void { |
|
180 | - $this->userManager |
|
181 | - ->expects($this->once()) |
|
182 | - ->method('countUsersTotal') |
|
183 | - ->willReturn(5); |
|
184 | - $channels = [ |
|
185 | - 'daily', |
|
186 | - 'beta', |
|
187 | - 'stable', |
|
188 | - 'production', |
|
189 | - ]; |
|
190 | - $currentChannel = Util::getChannel(); |
|
191 | - if ($currentChannel === 'git') { |
|
192 | - $channels[] = 'git'; |
|
193 | - } |
|
194 | - |
|
195 | - $this->appConfig |
|
196 | - ->expects($this->once()) |
|
197 | - ->method('getValueInt') |
|
198 | - ->with('core', 'lastupdatedat', 0) |
|
199 | - ->willReturn(12345); |
|
200 | - $this->config |
|
201 | - ->expects(self::any()) |
|
202 | - ->method('getSystemValueBool') |
|
203 | - ->with('updatechecker', true) |
|
204 | - ->willReturn(true); |
|
205 | - $this->config |
|
206 | - ->expects($this->once()) |
|
207 | - ->method('getAppValue') |
|
208 | - ->with('updatenotification', 'notify_groups', '["admin"]') |
|
209 | - ->willReturn('["admin"]'); |
|
210 | - $this->config |
|
211 | - ->method('getSystemValue') |
|
212 | - ->willReturnMap([ |
|
213 | - ['updater.server.url', 'https://updates.nextcloud.com/updater_server/', 'https://updates.nextcloud.com/updater_server_changed/'], |
|
214 | - ['upgrade.disable-web', false, true], |
|
215 | - ]); |
|
216 | - $this->dateTimeFormatter |
|
217 | - ->expects($this->once()) |
|
218 | - ->method('formatDateTime') |
|
219 | - ->with('12345') |
|
220 | - ->willReturn('LastCheckedReturnValue'); |
|
221 | - $this->updateChecker |
|
222 | - ->expects($this->once()) |
|
223 | - ->method('getUpdateState') |
|
224 | - ->willReturn([ |
|
225 | - 'updateAvailable' => true, |
|
226 | - 'updateVersion' => '8.1.2', |
|
227 | - 'updateVersionString' => 'Nextcloud 8.1.2', |
|
228 | - 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
229 | - 'changes' => [], |
|
230 | - 'updaterEnabled' => true, |
|
231 | - 'versionIsEol' => false, |
|
232 | - ]); |
|
233 | - |
|
234 | - $group = $this->createMock(IGroup::class); |
|
235 | - $group->expects($this->any()) |
|
236 | - ->method('getDisplayName') |
|
237 | - ->willReturn('Administrators'); |
|
238 | - $group->expects($this->any()) |
|
239 | - ->method('getGID') |
|
240 | - ->willReturn('admin'); |
|
241 | - $this->groupManager->expects($this->once()) |
|
242 | - ->method('get') |
|
243 | - ->with('admin') |
|
244 | - ->willReturn($group); |
|
245 | - |
|
246 | - $this->subscriptionRegistry |
|
247 | - ->expects($this->once()) |
|
248 | - ->method('delegateHasValidSubscription') |
|
249 | - ->willReturn(true); |
|
250 | - |
|
251 | - $this->initialState->expects($this->once()) |
|
252 | - ->method('provideInitialState') |
|
253 | - ->with('data', [ |
|
254 | - 'isNewVersionAvailable' => true, |
|
255 | - 'isUpdateChecked' => true, |
|
256 | - 'lastChecked' => 'LastCheckedReturnValue', |
|
257 | - 'currentChannel' => Util::getChannel(), |
|
258 | - 'channels' => $channels, |
|
259 | - 'newVersion' => '8.1.2', |
|
260 | - 'newVersionString' => 'Nextcloud 8.1.2', |
|
261 | - 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
262 | - 'changes' => [], |
|
263 | - 'webUpdaterEnabled' => false, |
|
264 | - 'isWebUpdaterRecommended' => true, |
|
265 | - 'updaterEnabled' => true, |
|
266 | - 'versionIsEol' => false, |
|
267 | - 'isDefaultUpdateServerURL' => false, |
|
268 | - 'updateServerURL' => 'https://updates.nextcloud.com/updater_server_changed/', |
|
269 | - 'notifyGroups' => [ |
|
270 | - ['id' => 'admin', 'displayname' => 'Administrators'], |
|
271 | - ], |
|
272 | - 'hasValidSubscription' => true, |
|
273 | - ]); |
|
274 | - |
|
275 | - $expected = new TemplateResponse('updatenotification', 'admin', [], ''); |
|
276 | - $this->assertEquals($expected, $this->admin->getForm()); |
|
277 | - } |
|
278 | - |
|
279 | - public function testGetFormWithUpdateAndCustomersUpdateServer(): void { |
|
280 | - $this->userManager |
|
281 | - ->expects($this->once()) |
|
282 | - ->method('countUsersTotal') |
|
283 | - ->willReturn(5); |
|
284 | - $channels = [ |
|
285 | - 'daily', |
|
286 | - 'beta', |
|
287 | - 'stable', |
|
288 | - 'production', |
|
289 | - ]; |
|
290 | - $currentChannel = Util::getChannel(); |
|
291 | - if ($currentChannel === 'git') { |
|
292 | - $channels[] = 'git'; |
|
293 | - } |
|
294 | - |
|
295 | - $this->appConfig |
|
296 | - ->expects($this->once()) |
|
297 | - ->method('getValueInt') |
|
298 | - ->with('core', 'lastupdatedat', 0) |
|
299 | - ->willReturn(12345); |
|
300 | - $this->config |
|
301 | - ->expects(self::any()) |
|
302 | - ->method('getSystemValueBool') |
|
303 | - ->with('updatechecker', true) |
|
304 | - ->willReturn(true); |
|
305 | - $this->config |
|
306 | - ->expects($this->once()) |
|
307 | - ->method('getAppValue') |
|
308 | - ->with('updatenotification', 'notify_groups', '["admin"]') |
|
309 | - ->willReturn('["admin"]'); |
|
310 | - $this->config |
|
311 | - ->method('getSystemValue') |
|
312 | - ->willReturnMap([ |
|
313 | - ['updater.server.url', 'https://updates.nextcloud.com/updater_server/', 'https://updates.nextcloud.com/customers/ABC-DEF/'], |
|
314 | - ['upgrade.disable-web', false, false], |
|
315 | - ]); |
|
316 | - $this->dateTimeFormatter |
|
317 | - ->expects($this->once()) |
|
318 | - ->method('formatDateTime') |
|
319 | - ->with('12345') |
|
320 | - ->willReturn('LastCheckedReturnValue'); |
|
321 | - $this->updateChecker |
|
322 | - ->expects($this->once()) |
|
323 | - ->method('getUpdateState') |
|
324 | - ->willReturn([ |
|
325 | - 'updateAvailable' => true, |
|
326 | - 'updateVersion' => '8.1.2', |
|
327 | - 'updateVersionString' => 'Nextcloud 8.1.2', |
|
328 | - 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
329 | - 'changes' => [], |
|
330 | - 'updaterEnabled' => true, |
|
331 | - 'versionIsEol' => false, |
|
332 | - ]); |
|
333 | - |
|
334 | - $group = $this->createMock(IGroup::class); |
|
335 | - $group->expects($this->any()) |
|
336 | - ->method('getDisplayName') |
|
337 | - ->willReturn('Administrators'); |
|
338 | - $group->expects($this->any()) |
|
339 | - ->method('getGID') |
|
340 | - ->willReturn('admin'); |
|
341 | - $this->groupManager->expects($this->once()) |
|
342 | - ->method('get') |
|
343 | - ->with('admin') |
|
344 | - ->willReturn($group); |
|
345 | - |
|
346 | - $this->subscriptionRegistry |
|
347 | - ->expects($this->once()) |
|
348 | - ->method('delegateHasValidSubscription') |
|
349 | - ->willReturn(true); |
|
350 | - |
|
351 | - $this->initialState->expects($this->once()) |
|
352 | - ->method('provideInitialState') |
|
353 | - ->with('data', [ |
|
354 | - 'isNewVersionAvailable' => true, |
|
355 | - 'isUpdateChecked' => true, |
|
356 | - 'lastChecked' => 'LastCheckedReturnValue', |
|
357 | - 'currentChannel' => Util::getChannel(), |
|
358 | - 'channels' => $channels, |
|
359 | - 'newVersion' => '8.1.2', |
|
360 | - 'newVersionString' => 'Nextcloud 8.1.2', |
|
361 | - 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
362 | - 'changes' => [], |
|
363 | - 'webUpdaterEnabled' => true, |
|
364 | - 'isWebUpdaterRecommended' => true, |
|
365 | - 'updaterEnabled' => true, |
|
366 | - 'versionIsEol' => false, |
|
367 | - 'isDefaultUpdateServerURL' => true, |
|
368 | - 'updateServerURL' => 'https://updates.nextcloud.com/customers/ABC-DEF/', |
|
369 | - 'notifyGroups' => [ |
|
370 | - ['id' => 'admin', 'displayname' => 'Administrators'], |
|
371 | - ], |
|
372 | - 'hasValidSubscription' => true, |
|
373 | - ]); |
|
374 | - |
|
375 | - $expected = new TemplateResponse('updatenotification', 'admin', [], ''); |
|
376 | - $this->assertEquals($expected, $this->admin->getForm()); |
|
377 | - } |
|
378 | - |
|
379 | - |
|
380 | - public function testGetSection(): void { |
|
381 | - $this->config |
|
382 | - ->expects(self::atLeastOnce()) |
|
383 | - ->method('getSystemValueBool') |
|
384 | - ->with('updatechecker', true) |
|
385 | - ->willReturn(true); |
|
386 | - |
|
387 | - $this->assertSame('overview', $this->admin->getSection()); |
|
388 | - } |
|
389 | - |
|
390 | - public function testGetSectionDisabled(): void { |
|
391 | - $this->config |
|
392 | - ->expects(self::atLeastOnce()) |
|
393 | - ->method('getSystemValueBool') |
|
394 | - ->with('updatechecker', true) |
|
395 | - ->willReturn(false); |
|
396 | - |
|
397 | - $this->assertNull($this->admin->getSection()); |
|
398 | - } |
|
399 | - |
|
400 | - public function testGetPriority(): void { |
|
401 | - $this->assertSame(11, $this->admin->getPriority()); |
|
402 | - } |
|
403 | - |
|
404 | - public function changesProvider() { |
|
405 | - return [ |
|
406 | - [ #0, all info, en |
|
407 | - [ |
|
408 | - 'changelogURL' => 'https://go.to.changelog', |
|
409 | - 'whatsNew' => [ |
|
410 | - 'en' => [ |
|
411 | - 'regular' => ['content'], |
|
412 | - ], |
|
413 | - 'de' => [ |
|
414 | - 'regular' => ['inhalt'], |
|
415 | - ] |
|
416 | - ], |
|
417 | - ], |
|
418 | - 'en', |
|
419 | - [ |
|
420 | - 'changelogURL' => 'https://go.to.changelog', |
|
421 | - 'whatsNew' => [ |
|
422 | - 'regular' => ['content'], |
|
423 | - ], |
|
424 | - ] |
|
425 | - ], |
|
426 | - [ #1, all info, de |
|
427 | - [ |
|
428 | - 'changelogURL' => 'https://go.to.changelog', |
|
429 | - 'whatsNew' => [ |
|
430 | - 'en' => [ |
|
431 | - 'regular' => ['content'], |
|
432 | - ], |
|
433 | - 'de' => [ |
|
434 | - 'regular' => ['inhalt'], |
|
435 | - ] |
|
436 | - ], |
|
437 | - ], |
|
438 | - 'de', |
|
439 | - [ |
|
440 | - 'changelogURL' => 'https://go.to.changelog', |
|
441 | - 'whatsNew' => [ |
|
442 | - 'regular' => ['inhalt'], |
|
443 | - ] |
|
444 | - ], |
|
445 | - ], |
|
446 | - [ #2, just changelog |
|
447 | - [ 'changelogURL' => 'https://go.to.changelog' ], |
|
448 | - 'en', |
|
449 | - [ 'changelogURL' => 'https://go.to.changelog' ], |
|
450 | - ], |
|
451 | - [ #3 nothing |
|
452 | - [], |
|
453 | - 'ru', |
|
454 | - [] |
|
455 | - ] |
|
456 | - ]; |
|
457 | - } |
|
458 | - |
|
459 | - /** |
|
460 | - * @dataProvider changesProvider |
|
461 | - */ |
|
462 | - public function testFilterChanges($changes, $userLang, $expectation): void { |
|
463 | - $iterator = $this->createMock(ILanguageIterator::class); |
|
464 | - $iterator->expects($this->any()) |
|
465 | - ->method('current') |
|
466 | - ->willReturnOnConsecutiveCalls('es', $userLang, 'it', 'en'); |
|
467 | - $iterator->expects($this->any()) |
|
468 | - ->method('valid') |
|
469 | - ->willReturn(true); |
|
470 | - |
|
471 | - $this->l10nFactory->expects($this->atMost(1)) |
|
472 | - ->method('getLanguageIterator') |
|
473 | - ->willReturn($iterator); |
|
474 | - $result = $this->invokePrivate($this->admin, 'filterChanges', [$changes]); |
|
475 | - $this->assertSame($expectation, $result); |
|
476 | - } |
|
29 | + /** @var IFactory|\PHPUnit\Framework\MockObject\MockObject */ |
|
30 | + protected $l10nFactory; |
|
31 | + /** @var Admin */ |
|
32 | + private $admin; |
|
33 | + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ |
|
34 | + private $config; |
|
35 | + /** @var IAppConfig|\PHPUnit\Framework\MockObject\MockObject */ |
|
36 | + private $appConfig; |
|
37 | + /** @var UpdateChecker|\PHPUnit\Framework\MockObject\MockObject */ |
|
38 | + private $updateChecker; |
|
39 | + /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */ |
|
40 | + private $groupManager; |
|
41 | + /** @var IDateTimeFormatter|\PHPUnit\Framework\MockObject\MockObject */ |
|
42 | + private $dateTimeFormatter; |
|
43 | + /** @var IRegistry|\PHPUnit\Framework\MockObject\MockObject */ |
|
44 | + private $subscriptionRegistry; |
|
45 | + /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ |
|
46 | + private $userManager; |
|
47 | + /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ |
|
48 | + private $logger; |
|
49 | + /** IInitialState|\PHPUnit\Framework\MockObject\MockObject */ |
|
50 | + private $initialState; |
|
51 | + |
|
52 | + protected function setUp(): void { |
|
53 | + parent::setUp(); |
|
54 | + |
|
55 | + $this->config = $this->createMock(IConfig::class); |
|
56 | + $this->appConfig = $this->createMock(IAppConfig::class); |
|
57 | + $this->updateChecker = $this->createMock(UpdateChecker::class); |
|
58 | + $this->groupManager = $this->createMock(IGroupManager::class); |
|
59 | + $this->dateTimeFormatter = $this->createMock(IDateTimeFormatter::class); |
|
60 | + $this->l10nFactory = $this->createMock(IFactory::class); |
|
61 | + $this->subscriptionRegistry = $this->createMock(IRegistry::class); |
|
62 | + $this->userManager = $this->createMock(IUserManager::class); |
|
63 | + $this->logger = $this->createMock(LoggerInterface::class); |
|
64 | + $this->initialState = $this->createMock(IInitialState::class); |
|
65 | + |
|
66 | + $this->admin = new Admin( |
|
67 | + $this->config, |
|
68 | + $this->appConfig, |
|
69 | + $this->updateChecker, |
|
70 | + $this->groupManager, |
|
71 | + $this->dateTimeFormatter, |
|
72 | + $this->l10nFactory, |
|
73 | + $this->subscriptionRegistry, |
|
74 | + $this->userManager, |
|
75 | + $this->logger, |
|
76 | + $this->initialState |
|
77 | + ); |
|
78 | + } |
|
79 | + |
|
80 | + public function testGetFormWithUpdate(): void { |
|
81 | + $this->userManager |
|
82 | + ->expects($this->once()) |
|
83 | + ->method('countUsersTotal') |
|
84 | + ->willReturn(5); |
|
85 | + $channels = [ |
|
86 | + 'daily', |
|
87 | + 'beta', |
|
88 | + 'stable', |
|
89 | + 'production', |
|
90 | + ]; |
|
91 | + $currentChannel = Util::getChannel(); |
|
92 | + if ($currentChannel === 'git') { |
|
93 | + $channels[] = 'git'; |
|
94 | + } |
|
95 | + $this->appConfig |
|
96 | + ->expects($this->once()) |
|
97 | + ->method('getValueInt') |
|
98 | + ->with('core', 'lastupdatedat', 0) |
|
99 | + ->willReturn(12345); |
|
100 | + $this->config |
|
101 | + ->expects($this->once()) |
|
102 | + ->method('getAppValue') |
|
103 | + ->with('updatenotification', 'notify_groups', '["admin"]') |
|
104 | + ->willReturn('["admin"]'); |
|
105 | + $this->config |
|
106 | + ->method('getSystemValue') |
|
107 | + ->willReturnMap([ |
|
108 | + ['updater.server.url', 'https://updates.nextcloud.com/updater_server/', 'https://updates.nextcloud.com/updater_server/'], |
|
109 | + ['upgrade.disable-web', false, false], |
|
110 | + ]); |
|
111 | + $this->config |
|
112 | + ->expects(self::any()) |
|
113 | + ->method('getSystemValueBool') |
|
114 | + ->with('updatechecker', true) |
|
115 | + ->willReturn(true); |
|
116 | + $this->dateTimeFormatter |
|
117 | + ->expects($this->once()) |
|
118 | + ->method('formatDateTime') |
|
119 | + ->with(12345) |
|
120 | + ->willReturn('LastCheckedReturnValue'); |
|
121 | + $this->updateChecker |
|
122 | + ->expects($this->once()) |
|
123 | + ->method('getUpdateState') |
|
124 | + ->willReturn([ |
|
125 | + 'updateAvailable' => true, |
|
126 | + 'updateVersion' => '8.1.2', |
|
127 | + 'updateVersionString' => 'Nextcloud 8.1.2', |
|
128 | + 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
129 | + 'changes' => [], |
|
130 | + 'updaterEnabled' => true, |
|
131 | + 'versionIsEol' => false, |
|
132 | + ]); |
|
133 | + |
|
134 | + $group = $this->createMock(IGroup::class); |
|
135 | + $group->expects($this->any()) |
|
136 | + ->method('getDisplayName') |
|
137 | + ->willReturn('Administrators'); |
|
138 | + $group->expects($this->any()) |
|
139 | + ->method('getGID') |
|
140 | + ->willReturn('admin'); |
|
141 | + $this->groupManager->expects($this->once()) |
|
142 | + ->method('get') |
|
143 | + ->with('admin') |
|
144 | + ->willReturn($group); |
|
145 | + |
|
146 | + $this->subscriptionRegistry |
|
147 | + ->expects($this->once()) |
|
148 | + ->method('delegateHasValidSubscription') |
|
149 | + ->willReturn(true); |
|
150 | + |
|
151 | + $this->initialState->expects($this->once()) |
|
152 | + ->method('provideInitialState') |
|
153 | + ->with('data', [ |
|
154 | + 'isNewVersionAvailable' => true, |
|
155 | + 'isUpdateChecked' => true, |
|
156 | + 'lastChecked' => 'LastCheckedReturnValue', |
|
157 | + 'currentChannel' => Util::getChannel(), |
|
158 | + 'channels' => $channels, |
|
159 | + 'newVersion' => '8.1.2', |
|
160 | + 'newVersionString' => 'Nextcloud 8.1.2', |
|
161 | + 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
162 | + 'changes' => [], |
|
163 | + 'webUpdaterEnabled' => true, |
|
164 | + 'isWebUpdaterRecommended' => true, |
|
165 | + 'updaterEnabled' => true, |
|
166 | + 'versionIsEol' => false, |
|
167 | + 'isDefaultUpdateServerURL' => true, |
|
168 | + 'updateServerURL' => 'https://updates.nextcloud.com/updater_server/', |
|
169 | + 'notifyGroups' => [ |
|
170 | + ['id' => 'admin', 'displayname' => 'Administrators'], |
|
171 | + ], |
|
172 | + 'hasValidSubscription' => true, |
|
173 | + ]); |
|
174 | + |
|
175 | + $expected = new TemplateResponse('updatenotification', 'admin', [], ''); |
|
176 | + $this->assertEquals($expected, $this->admin->getForm()); |
|
177 | + } |
|
178 | + |
|
179 | + public function testGetFormWithUpdateAndChangedUpdateServer(): void { |
|
180 | + $this->userManager |
|
181 | + ->expects($this->once()) |
|
182 | + ->method('countUsersTotal') |
|
183 | + ->willReturn(5); |
|
184 | + $channels = [ |
|
185 | + 'daily', |
|
186 | + 'beta', |
|
187 | + 'stable', |
|
188 | + 'production', |
|
189 | + ]; |
|
190 | + $currentChannel = Util::getChannel(); |
|
191 | + if ($currentChannel === 'git') { |
|
192 | + $channels[] = 'git'; |
|
193 | + } |
|
194 | + |
|
195 | + $this->appConfig |
|
196 | + ->expects($this->once()) |
|
197 | + ->method('getValueInt') |
|
198 | + ->with('core', 'lastupdatedat', 0) |
|
199 | + ->willReturn(12345); |
|
200 | + $this->config |
|
201 | + ->expects(self::any()) |
|
202 | + ->method('getSystemValueBool') |
|
203 | + ->with('updatechecker', true) |
|
204 | + ->willReturn(true); |
|
205 | + $this->config |
|
206 | + ->expects($this->once()) |
|
207 | + ->method('getAppValue') |
|
208 | + ->with('updatenotification', 'notify_groups', '["admin"]') |
|
209 | + ->willReturn('["admin"]'); |
|
210 | + $this->config |
|
211 | + ->method('getSystemValue') |
|
212 | + ->willReturnMap([ |
|
213 | + ['updater.server.url', 'https://updates.nextcloud.com/updater_server/', 'https://updates.nextcloud.com/updater_server_changed/'], |
|
214 | + ['upgrade.disable-web', false, true], |
|
215 | + ]); |
|
216 | + $this->dateTimeFormatter |
|
217 | + ->expects($this->once()) |
|
218 | + ->method('formatDateTime') |
|
219 | + ->with('12345') |
|
220 | + ->willReturn('LastCheckedReturnValue'); |
|
221 | + $this->updateChecker |
|
222 | + ->expects($this->once()) |
|
223 | + ->method('getUpdateState') |
|
224 | + ->willReturn([ |
|
225 | + 'updateAvailable' => true, |
|
226 | + 'updateVersion' => '8.1.2', |
|
227 | + 'updateVersionString' => 'Nextcloud 8.1.2', |
|
228 | + 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
229 | + 'changes' => [], |
|
230 | + 'updaterEnabled' => true, |
|
231 | + 'versionIsEol' => false, |
|
232 | + ]); |
|
233 | + |
|
234 | + $group = $this->createMock(IGroup::class); |
|
235 | + $group->expects($this->any()) |
|
236 | + ->method('getDisplayName') |
|
237 | + ->willReturn('Administrators'); |
|
238 | + $group->expects($this->any()) |
|
239 | + ->method('getGID') |
|
240 | + ->willReturn('admin'); |
|
241 | + $this->groupManager->expects($this->once()) |
|
242 | + ->method('get') |
|
243 | + ->with('admin') |
|
244 | + ->willReturn($group); |
|
245 | + |
|
246 | + $this->subscriptionRegistry |
|
247 | + ->expects($this->once()) |
|
248 | + ->method('delegateHasValidSubscription') |
|
249 | + ->willReturn(true); |
|
250 | + |
|
251 | + $this->initialState->expects($this->once()) |
|
252 | + ->method('provideInitialState') |
|
253 | + ->with('data', [ |
|
254 | + 'isNewVersionAvailable' => true, |
|
255 | + 'isUpdateChecked' => true, |
|
256 | + 'lastChecked' => 'LastCheckedReturnValue', |
|
257 | + 'currentChannel' => Util::getChannel(), |
|
258 | + 'channels' => $channels, |
|
259 | + 'newVersion' => '8.1.2', |
|
260 | + 'newVersionString' => 'Nextcloud 8.1.2', |
|
261 | + 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
262 | + 'changes' => [], |
|
263 | + 'webUpdaterEnabled' => false, |
|
264 | + 'isWebUpdaterRecommended' => true, |
|
265 | + 'updaterEnabled' => true, |
|
266 | + 'versionIsEol' => false, |
|
267 | + 'isDefaultUpdateServerURL' => false, |
|
268 | + 'updateServerURL' => 'https://updates.nextcloud.com/updater_server_changed/', |
|
269 | + 'notifyGroups' => [ |
|
270 | + ['id' => 'admin', 'displayname' => 'Administrators'], |
|
271 | + ], |
|
272 | + 'hasValidSubscription' => true, |
|
273 | + ]); |
|
274 | + |
|
275 | + $expected = new TemplateResponse('updatenotification', 'admin', [], ''); |
|
276 | + $this->assertEquals($expected, $this->admin->getForm()); |
|
277 | + } |
|
278 | + |
|
279 | + public function testGetFormWithUpdateAndCustomersUpdateServer(): void { |
|
280 | + $this->userManager |
|
281 | + ->expects($this->once()) |
|
282 | + ->method('countUsersTotal') |
|
283 | + ->willReturn(5); |
|
284 | + $channels = [ |
|
285 | + 'daily', |
|
286 | + 'beta', |
|
287 | + 'stable', |
|
288 | + 'production', |
|
289 | + ]; |
|
290 | + $currentChannel = Util::getChannel(); |
|
291 | + if ($currentChannel === 'git') { |
|
292 | + $channels[] = 'git'; |
|
293 | + } |
|
294 | + |
|
295 | + $this->appConfig |
|
296 | + ->expects($this->once()) |
|
297 | + ->method('getValueInt') |
|
298 | + ->with('core', 'lastupdatedat', 0) |
|
299 | + ->willReturn(12345); |
|
300 | + $this->config |
|
301 | + ->expects(self::any()) |
|
302 | + ->method('getSystemValueBool') |
|
303 | + ->with('updatechecker', true) |
|
304 | + ->willReturn(true); |
|
305 | + $this->config |
|
306 | + ->expects($this->once()) |
|
307 | + ->method('getAppValue') |
|
308 | + ->with('updatenotification', 'notify_groups', '["admin"]') |
|
309 | + ->willReturn('["admin"]'); |
|
310 | + $this->config |
|
311 | + ->method('getSystemValue') |
|
312 | + ->willReturnMap([ |
|
313 | + ['updater.server.url', 'https://updates.nextcloud.com/updater_server/', 'https://updates.nextcloud.com/customers/ABC-DEF/'], |
|
314 | + ['upgrade.disable-web', false, false], |
|
315 | + ]); |
|
316 | + $this->dateTimeFormatter |
|
317 | + ->expects($this->once()) |
|
318 | + ->method('formatDateTime') |
|
319 | + ->with('12345') |
|
320 | + ->willReturn('LastCheckedReturnValue'); |
|
321 | + $this->updateChecker |
|
322 | + ->expects($this->once()) |
|
323 | + ->method('getUpdateState') |
|
324 | + ->willReturn([ |
|
325 | + 'updateAvailable' => true, |
|
326 | + 'updateVersion' => '8.1.2', |
|
327 | + 'updateVersionString' => 'Nextcloud 8.1.2', |
|
328 | + 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
329 | + 'changes' => [], |
|
330 | + 'updaterEnabled' => true, |
|
331 | + 'versionIsEol' => false, |
|
332 | + ]); |
|
333 | + |
|
334 | + $group = $this->createMock(IGroup::class); |
|
335 | + $group->expects($this->any()) |
|
336 | + ->method('getDisplayName') |
|
337 | + ->willReturn('Administrators'); |
|
338 | + $group->expects($this->any()) |
|
339 | + ->method('getGID') |
|
340 | + ->willReturn('admin'); |
|
341 | + $this->groupManager->expects($this->once()) |
|
342 | + ->method('get') |
|
343 | + ->with('admin') |
|
344 | + ->willReturn($group); |
|
345 | + |
|
346 | + $this->subscriptionRegistry |
|
347 | + ->expects($this->once()) |
|
348 | + ->method('delegateHasValidSubscription') |
|
349 | + ->willReturn(true); |
|
350 | + |
|
351 | + $this->initialState->expects($this->once()) |
|
352 | + ->method('provideInitialState') |
|
353 | + ->with('data', [ |
|
354 | + 'isNewVersionAvailable' => true, |
|
355 | + 'isUpdateChecked' => true, |
|
356 | + 'lastChecked' => 'LastCheckedReturnValue', |
|
357 | + 'currentChannel' => Util::getChannel(), |
|
358 | + 'channels' => $channels, |
|
359 | + 'newVersion' => '8.1.2', |
|
360 | + 'newVersionString' => 'Nextcloud 8.1.2', |
|
361 | + 'downloadLink' => 'https://downloads.nextcloud.org/server', |
|
362 | + 'changes' => [], |
|
363 | + 'webUpdaterEnabled' => true, |
|
364 | + 'isWebUpdaterRecommended' => true, |
|
365 | + 'updaterEnabled' => true, |
|
366 | + 'versionIsEol' => false, |
|
367 | + 'isDefaultUpdateServerURL' => true, |
|
368 | + 'updateServerURL' => 'https://updates.nextcloud.com/customers/ABC-DEF/', |
|
369 | + 'notifyGroups' => [ |
|
370 | + ['id' => 'admin', 'displayname' => 'Administrators'], |
|
371 | + ], |
|
372 | + 'hasValidSubscription' => true, |
|
373 | + ]); |
|
374 | + |
|
375 | + $expected = new TemplateResponse('updatenotification', 'admin', [], ''); |
|
376 | + $this->assertEquals($expected, $this->admin->getForm()); |
|
377 | + } |
|
378 | + |
|
379 | + |
|
380 | + public function testGetSection(): void { |
|
381 | + $this->config |
|
382 | + ->expects(self::atLeastOnce()) |
|
383 | + ->method('getSystemValueBool') |
|
384 | + ->with('updatechecker', true) |
|
385 | + ->willReturn(true); |
|
386 | + |
|
387 | + $this->assertSame('overview', $this->admin->getSection()); |
|
388 | + } |
|
389 | + |
|
390 | + public function testGetSectionDisabled(): void { |
|
391 | + $this->config |
|
392 | + ->expects(self::atLeastOnce()) |
|
393 | + ->method('getSystemValueBool') |
|
394 | + ->with('updatechecker', true) |
|
395 | + ->willReturn(false); |
|
396 | + |
|
397 | + $this->assertNull($this->admin->getSection()); |
|
398 | + } |
|
399 | + |
|
400 | + public function testGetPriority(): void { |
|
401 | + $this->assertSame(11, $this->admin->getPriority()); |
|
402 | + } |
|
403 | + |
|
404 | + public function changesProvider() { |
|
405 | + return [ |
|
406 | + [ #0, all info, en |
|
407 | + [ |
|
408 | + 'changelogURL' => 'https://go.to.changelog', |
|
409 | + 'whatsNew' => [ |
|
410 | + 'en' => [ |
|
411 | + 'regular' => ['content'], |
|
412 | + ], |
|
413 | + 'de' => [ |
|
414 | + 'regular' => ['inhalt'], |
|
415 | + ] |
|
416 | + ], |
|
417 | + ], |
|
418 | + 'en', |
|
419 | + [ |
|
420 | + 'changelogURL' => 'https://go.to.changelog', |
|
421 | + 'whatsNew' => [ |
|
422 | + 'regular' => ['content'], |
|
423 | + ], |
|
424 | + ] |
|
425 | + ], |
|
426 | + [ #1, all info, de |
|
427 | + [ |
|
428 | + 'changelogURL' => 'https://go.to.changelog', |
|
429 | + 'whatsNew' => [ |
|
430 | + 'en' => [ |
|
431 | + 'regular' => ['content'], |
|
432 | + ], |
|
433 | + 'de' => [ |
|
434 | + 'regular' => ['inhalt'], |
|
435 | + ] |
|
436 | + ], |
|
437 | + ], |
|
438 | + 'de', |
|
439 | + [ |
|
440 | + 'changelogURL' => 'https://go.to.changelog', |
|
441 | + 'whatsNew' => [ |
|
442 | + 'regular' => ['inhalt'], |
|
443 | + ] |
|
444 | + ], |
|
445 | + ], |
|
446 | + [ #2, just changelog |
|
447 | + [ 'changelogURL' => 'https://go.to.changelog' ], |
|
448 | + 'en', |
|
449 | + [ 'changelogURL' => 'https://go.to.changelog' ], |
|
450 | + ], |
|
451 | + [ #3 nothing |
|
452 | + [], |
|
453 | + 'ru', |
|
454 | + [] |
|
455 | + ] |
|
456 | + ]; |
|
457 | + } |
|
458 | + |
|
459 | + /** |
|
460 | + * @dataProvider changesProvider |
|
461 | + */ |
|
462 | + public function testFilterChanges($changes, $userLang, $expectation): void { |
|
463 | + $iterator = $this->createMock(ILanguageIterator::class); |
|
464 | + $iterator->expects($this->any()) |
|
465 | + ->method('current') |
|
466 | + ->willReturnOnConsecutiveCalls('es', $userLang, 'it', 'en'); |
|
467 | + $iterator->expects($this->any()) |
|
468 | + ->method('valid') |
|
469 | + ->willReturn(true); |
|
470 | + |
|
471 | + $this->l10nFactory->expects($this->atMost(1)) |
|
472 | + ->method('getLanguageIterator') |
|
473 | + ->willReturn($iterator); |
|
474 | + $result = $this->invokePrivate($this->admin, 'filterChanges', [$changes]); |
|
475 | + $this->assertSame($expectation, $result); |
|
476 | + } |
|
477 | 477 | } |
@@ -25,448 +25,448 @@ |
||
25 | 25 | use Test\TestCase; |
26 | 26 | |
27 | 27 | class UpdateAvailableNotificationsTest extends TestCase { |
28 | - private ServerVersion&MockObject $serverVersion; |
|
29 | - private IConfig|MockObject $config; |
|
30 | - private IManager|MockObject $notificationManager; |
|
31 | - private IGroupManager|MockObject $groupManager; |
|
32 | - private IAppManager|MockObject $appManager; |
|
33 | - private IAppConfig|MockObject $appConfig; |
|
34 | - private ITimeFactory|MockObject $timeFactory; |
|
35 | - private Installer|MockObject $installer; |
|
36 | - private VersionCheck|MockObject $versionCheck; |
|
37 | - |
|
38 | - protected function setUp(): void { |
|
39 | - parent::setUp(); |
|
40 | - |
|
41 | - $this->serverVersion = $this->createMock(ServerVersion::class); |
|
42 | - $this->config = $this->createMock(IConfig::class); |
|
43 | - $this->appConfig = $this->createMock(IAppConfig::class); |
|
44 | - $this->notificationManager = $this->createMock(IManager::class); |
|
45 | - $this->groupManager = $this->createMock(IGroupManager::class); |
|
46 | - $this->appManager = $this->createMock(IAppManager::class); |
|
47 | - $this->timeFactory = $this->createMock(ITimeFactory::class); |
|
48 | - $this->installer = $this->createMock(Installer::class); |
|
49 | - $this->versionCheck = $this->createMock(VersionCheck::class); |
|
50 | - } |
|
51 | - |
|
52 | - /** |
|
53 | - * @param array $methods |
|
54 | - * @return UpdateAvailableNotifications|MockObject |
|
55 | - */ |
|
56 | - protected function getJob(array $methods = []) { |
|
57 | - if (empty($methods)) { |
|
58 | - return new UpdateAvailableNotifications( |
|
59 | - $this->timeFactory, |
|
60 | - $this->serverVersion, |
|
61 | - $this->config, |
|
62 | - $this->appConfig, |
|
63 | - $this->notificationManager, |
|
64 | - $this->groupManager, |
|
65 | - $this->appManager, |
|
66 | - $this->installer, |
|
67 | - $this->versionCheck, |
|
68 | - ); |
|
69 | - } |
|
70 | - { |
|
71 | - return $this->getMockBuilder(UpdateAvailableNotifications::class) |
|
72 | - ->setConstructorArgs([ |
|
73 | - $this->timeFactory, |
|
74 | - $this->serverVersion, |
|
75 | - $this->config, |
|
76 | - $this->appConfig, |
|
77 | - $this->notificationManager, |
|
78 | - $this->groupManager, |
|
79 | - $this->appManager, |
|
80 | - $this->installer, |
|
81 | - $this->versionCheck, |
|
82 | - ]) |
|
83 | - ->onlyMethods($methods) |
|
84 | - ->getMock(); |
|
85 | - } |
|
86 | - } |
|
87 | - |
|
88 | - public function testRun(): void { |
|
89 | - $job = $this->getJob([ |
|
90 | - 'checkCoreUpdate', |
|
91 | - 'checkAppUpdates', |
|
92 | - ]); |
|
93 | - |
|
94 | - $job->expects($this->once()) |
|
95 | - ->method('checkCoreUpdate'); |
|
96 | - $job->expects($this->once()) |
|
97 | - ->method('checkAppUpdates'); |
|
98 | - |
|
99 | - $this->config->expects(self::exactly(2)) |
|
100 | - ->method('getSystemValueBool') |
|
101 | - ->willReturnMap([ |
|
102 | - ['debug', false, true], |
|
103 | - ['has_internet_connection', true, true], |
|
104 | - ]); |
|
105 | - self::invokePrivate($job, 'run', [null]); |
|
106 | - } |
|
107 | - |
|
108 | - public function testRunNoInternet(): void { |
|
109 | - $job = $this->getJob([ |
|
110 | - 'checkCoreUpdate', |
|
111 | - 'checkAppUpdates', |
|
112 | - ]); |
|
113 | - |
|
114 | - $job->expects($this->never()) |
|
115 | - ->method('checkCoreUpdate'); |
|
116 | - $job->expects($this->never()) |
|
117 | - ->method('checkAppUpdates'); |
|
118 | - |
|
119 | - $this->config |
|
120 | - ->expects(self::once()) |
|
121 | - ->method('getSystemValueBool') |
|
122 | - ->with('has_internet_connection', true) |
|
123 | - ->willReturn(false); |
|
124 | - |
|
125 | - self::invokePrivate($job, 'run', [null]); |
|
126 | - } |
|
127 | - |
|
128 | - public function dataCheckCoreUpdate(): array { |
|
129 | - return [ |
|
130 | - ['daily', null, null, null, null], |
|
131 | - ['git', null, null, null, null], |
|
132 | - ['beta', [], null, null, null], |
|
133 | - ['beta', false, false, null, null], |
|
134 | - ['beta', false, false, null, 13], |
|
135 | - ['beta', [ |
|
136 | - 'version' => '9.2.0', |
|
137 | - 'versionstring' => 'Nextcloud 11.0.0', |
|
138 | - ], '9.2.0', 'Nextcloud 11.0.0', null], |
|
139 | - ['stable', [], null, null, null], |
|
140 | - ['stable', false, false, null, null], |
|
141 | - ['stable', false, false, null, 6], |
|
142 | - ['stable', [ |
|
143 | - 'version' => '9.2.0', |
|
144 | - 'versionstring' => 'Nextcloud 11.0.0', |
|
145 | - ], '9.2.0', 'Nextcloud 11.0.0', null], |
|
146 | - ['production', [], null, null, null], |
|
147 | - ['production', false, false, null, null], |
|
148 | - ['production', false, false, null, 2], |
|
149 | - ['production', [ |
|
150 | - 'version' => '9.2.0', |
|
151 | - 'versionstring' => 'Nextcloud 11.0.0', |
|
152 | - ], '9.2.0', 'Nextcloud 11.0.0', null], |
|
153 | - ]; |
|
154 | - } |
|
155 | - |
|
156 | - /** |
|
157 | - * @dataProvider dataCheckCoreUpdate |
|
158 | - * |
|
159 | - * @param string $channel |
|
160 | - * @param mixed $versionCheck |
|
161 | - * @param null|string $version |
|
162 | - * @param null|string $readableVersion |
|
163 | - * @param null|int $errorDays |
|
164 | - */ |
|
165 | - public function testCheckCoreUpdate(string $channel, $versionCheck, $version, $readableVersion, $errorDays): void { |
|
166 | - $job = $this->getJob([ |
|
167 | - 'createNotifications', |
|
168 | - 'clearErrorNotifications', |
|
169 | - 'sendErrorNotifications', |
|
170 | - ]); |
|
171 | - |
|
172 | - $this->serverVersion->expects($this->once()) |
|
173 | - ->method('getChannel') |
|
174 | - ->willReturn($channel); |
|
175 | - |
|
176 | - if ($versionCheck === null) { |
|
177 | - $this->versionCheck->expects($this->never()) |
|
178 | - ->method('check'); |
|
179 | - } else { |
|
180 | - $this->versionCheck->expects($this->once()) |
|
181 | - ->method('check') |
|
182 | - ->willReturn($versionCheck); |
|
183 | - } |
|
184 | - |
|
185 | - if ($version === null) { |
|
186 | - $job->expects($this->never()) |
|
187 | - ->method('createNotifications'); |
|
188 | - $job->expects($versionCheck === null ? $this->never() : $this->once()) |
|
189 | - ->method('clearErrorNotifications'); |
|
190 | - } elseif ($version === false) { |
|
191 | - $job->expects($this->never()) |
|
192 | - ->method('createNotifications'); |
|
193 | - $job->expects($this->never()) |
|
194 | - ->method('clearErrorNotifications'); |
|
195 | - |
|
196 | - $this->appConfig->expects($this->once()) |
|
197 | - ->method('getAppValueInt') |
|
198 | - ->willReturn($errorDays ?? 0); |
|
199 | - $this->appConfig->expects($this->once()) |
|
200 | - ->method('setAppValueInt') |
|
201 | - ->with('update_check_errors', $errorDays + 1); |
|
202 | - $job->expects($errorDays !== null ? $this->once() : $this->never()) |
|
203 | - ->method('sendErrorNotifications') |
|
204 | - ->with($errorDays + 1); |
|
205 | - } else { |
|
206 | - $this->appConfig->expects($this->once()) |
|
207 | - ->method('setAppValueInt') |
|
208 | - ->with('update_check_errors', 0); |
|
209 | - $job->expects($this->once()) |
|
210 | - ->method('clearErrorNotifications'); |
|
211 | - $job->expects($this->once()) |
|
212 | - ->method('createNotifications') |
|
213 | - ->with('core', $version, $readableVersion); |
|
214 | - } |
|
215 | - |
|
216 | - $this->config->expects(self::any()) |
|
217 | - ->method('getSystemValueBool') |
|
218 | - ->willReturnMap([ |
|
219 | - ['updatechecker', true, true], |
|
220 | - ['has_internet_connection', true, true], |
|
221 | - ]); |
|
222 | - |
|
223 | - self::invokePrivate($job, 'checkCoreUpdate'); |
|
224 | - } |
|
225 | - |
|
226 | - public function dataCheckAppUpdates(): array { |
|
227 | - return [ |
|
228 | - [ |
|
229 | - ['app1', 'app2'], |
|
230 | - [ |
|
231 | - ['app1', false], |
|
232 | - ['app2', '1.9.2'], |
|
233 | - ], |
|
234 | - [ |
|
235 | - ['app2', '1.9.2', ''], |
|
236 | - ], |
|
237 | - ], |
|
238 | - ]; |
|
239 | - } |
|
240 | - |
|
241 | - /** |
|
242 | - * @dataProvider dataCheckAppUpdates |
|
243 | - * |
|
244 | - * @param string[] $apps |
|
245 | - * @param array $isUpdateAvailable |
|
246 | - * @param array $notifications |
|
247 | - */ |
|
248 | - public function testCheckAppUpdates(array $apps, array $isUpdateAvailable, array $notifications): void { |
|
249 | - $job = $this->getJob([ |
|
250 | - 'isUpdateAvailable', |
|
251 | - 'createNotifications', |
|
252 | - ]); |
|
253 | - |
|
254 | - $this->appManager->expects($this->once()) |
|
255 | - ->method('getEnabledApps') |
|
256 | - ->willReturn($apps); |
|
257 | - |
|
258 | - $job->expects($this->exactly(\count($apps))) |
|
259 | - ->method('isUpdateAvailable') |
|
260 | - ->willReturnMap($isUpdateAvailable); |
|
261 | - |
|
262 | - $i = 0; |
|
263 | - $job->expects($this->exactly(\count($notifications))) |
|
264 | - ->method('createNotifications') |
|
265 | - ->willReturnCallback(function () use ($notifications, &$i): void { |
|
266 | - $this->assertEquals($notifications[$i], func_get_args()); |
|
267 | - $i++; |
|
268 | - }); |
|
269 | - |
|
270 | - |
|
271 | - self::invokePrivate($job, 'checkAppUpdates'); |
|
272 | - } |
|
273 | - |
|
274 | - public function dataCreateNotifications(): array { |
|
275 | - return [ |
|
276 | - ['app1', '1.0.0', '1.0.0', false, false, null, null], |
|
277 | - ['app2', '1.0.1', '1.0.0', '1.0.0', true, ['user1'], [['user1']]], |
|
278 | - ['app3', '1.0.1', false, false, true, ['user2', 'user3'], [['user2'], ['user3']]], |
|
279 | - ]; |
|
280 | - } |
|
281 | - |
|
282 | - /** |
|
283 | - * @dataProvider dataCreateNotifications |
|
284 | - * |
|
285 | - * @param string $app |
|
286 | - * @param string $version |
|
287 | - * @param string|false $lastNotification |
|
288 | - * @param string|false $callDelete |
|
289 | - * @param bool $createNotification |
|
290 | - * @param string[]|null $users |
|
291 | - * @param array|null $userNotifications |
|
292 | - */ |
|
293 | - public function testCreateNotifications(string $app, string $version, $lastNotification, $callDelete, $createNotification, $users, $userNotifications): void { |
|
294 | - $job = $this->getJob([ |
|
295 | - 'deleteOutdatedNotifications', |
|
296 | - 'getUsersToNotify', |
|
297 | - ]); |
|
298 | - |
|
299 | - $this->appConfig->expects($this->once()) |
|
300 | - ->method('getAppValueString') |
|
301 | - ->with($app, '') |
|
302 | - ->willReturn($lastNotification ?: ''); |
|
303 | - |
|
304 | - if ($lastNotification !== $version) { |
|
305 | - $this->appConfig->expects($this->once()) |
|
306 | - ->method('setAppValueString') |
|
307 | - ->with($app, $version); |
|
308 | - } |
|
309 | - |
|
310 | - if ($callDelete === false) { |
|
311 | - $job->expects($this->never()) |
|
312 | - ->method('deleteOutdatedNotifications'); |
|
313 | - } else { |
|
314 | - $job->expects($this->once()) |
|
315 | - ->method('deleteOutdatedNotifications') |
|
316 | - ->with($app, $callDelete); |
|
317 | - } |
|
318 | - |
|
319 | - if ($users === null) { |
|
320 | - $job->expects($this->never()) |
|
321 | - ->method('getUsersToNotify'); |
|
322 | - } else { |
|
323 | - $job->expects($this->once()) |
|
324 | - ->method('getUsersToNotify') |
|
325 | - ->willReturn($users); |
|
326 | - } |
|
327 | - |
|
328 | - if ($createNotification) { |
|
329 | - $notification = $this->createMock(INotification::class); |
|
330 | - $notification->expects($this->once()) |
|
331 | - ->method('setApp') |
|
332 | - ->with('updatenotification') |
|
333 | - ->willReturnSelf(); |
|
334 | - $notification->expects($this->once()) |
|
335 | - ->method('setDateTime') |
|
336 | - ->willReturnSelf(); |
|
337 | - $notification->expects($this->once()) |
|
338 | - ->method('setObject') |
|
339 | - ->with($app, $version) |
|
340 | - ->willReturnSelf(); |
|
341 | - $notification->expects($this->once()) |
|
342 | - ->method('setSubject') |
|
343 | - ->with('update_available') |
|
344 | - ->willReturnSelf(); |
|
345 | - |
|
346 | - if ($userNotifications !== null) { |
|
347 | - $notification->expects($this->exactly(\count($userNotifications))) |
|
348 | - ->method('setUser') |
|
349 | - ->willReturnSelf(); |
|
350 | - |
|
351 | - $this->notificationManager->expects($this->exactly(\count($userNotifications))) |
|
352 | - ->method('notify'); |
|
353 | - } |
|
354 | - |
|
355 | - $this->notificationManager->expects($this->once()) |
|
356 | - ->method('createNotification') |
|
357 | - ->willReturn($notification); |
|
358 | - } else { |
|
359 | - $this->notificationManager->expects($this->never()) |
|
360 | - ->method('createNotification'); |
|
361 | - } |
|
362 | - |
|
363 | - self::invokePrivate($job, 'createNotifications', [$app, $version]); |
|
364 | - } |
|
365 | - |
|
366 | - public function dataGetUsersToNotify(): array { |
|
367 | - return [ |
|
368 | - [['g1', 'g2'], ['g1' => null, 'g2' => ['u1', 'u2']], ['u1', 'u2']], |
|
369 | - [['g3', 'g4'], ['g3' => ['u1', 'u2'], 'g4' => ['u2', 'u3']], ['u1', 'u2', 'u3']], |
|
370 | - ]; |
|
371 | - } |
|
372 | - |
|
373 | - /** |
|
374 | - * @dataProvider dataGetUsersToNotify |
|
375 | - * @param string[] $groups |
|
376 | - * @param array $groupUsers |
|
377 | - * @param string[] $expected |
|
378 | - */ |
|
379 | - public function testGetUsersToNotify(array $groups, array $groupUsers, array $expected): void { |
|
380 | - $job = $this->getJob(); |
|
381 | - |
|
382 | - $this->appConfig->expects($this->once()) |
|
383 | - ->method('getAppValueArray') |
|
384 | - ->with('notify_groups', ['admin']) |
|
385 | - ->willReturn($groups); |
|
386 | - |
|
387 | - $groupMap = []; |
|
388 | - foreach ($groupUsers as $gid => $uids) { |
|
389 | - if ($uids === null) { |
|
390 | - $group = null; |
|
391 | - } else { |
|
392 | - $group = $this->getGroup($gid); |
|
393 | - $group->expects($this->any()) |
|
394 | - ->method('getUsers') |
|
395 | - ->willReturn($this->getUsers($uids)); |
|
396 | - } |
|
397 | - $groupMap[] = [$gid, $group]; |
|
398 | - } |
|
399 | - $this->groupManager->expects($this->exactly(\count($groups))) |
|
400 | - ->method('get') |
|
401 | - ->willReturnMap($groupMap); |
|
402 | - |
|
403 | - $result = self::invokePrivate($job, 'getUsersToNotify'); |
|
404 | - $this->assertEquals($expected, $result); |
|
405 | - |
|
406 | - // Test caching |
|
407 | - $result = self::invokePrivate($job, 'getUsersToNotify'); |
|
408 | - $this->assertEquals($expected, $result); |
|
409 | - } |
|
410 | - |
|
411 | - public function dataDeleteOutdatedNotifications(): array { |
|
412 | - return [ |
|
413 | - ['app1', '1.1.0'], |
|
414 | - ['app2', '1.2.0'], |
|
415 | - ]; |
|
416 | - } |
|
417 | - |
|
418 | - /** |
|
419 | - * @dataProvider dataDeleteOutdatedNotifications |
|
420 | - * @param string $app |
|
421 | - * @param string $version |
|
422 | - */ |
|
423 | - public function testDeleteOutdatedNotifications(string $app, string $version): void { |
|
424 | - $notification = $this->createMock(INotification::class); |
|
425 | - $notification->expects($this->once()) |
|
426 | - ->method('setApp') |
|
427 | - ->with('updatenotification') |
|
428 | - ->willReturnSelf(); |
|
429 | - $notification->expects($this->once()) |
|
430 | - ->method('setObject') |
|
431 | - ->with($app, $version) |
|
432 | - ->willReturnSelf(); |
|
433 | - |
|
434 | - $this->notificationManager->expects($this->once()) |
|
435 | - ->method('createNotification') |
|
436 | - ->willReturn($notification); |
|
437 | - $this->notificationManager->expects($this->once()) |
|
438 | - ->method('markProcessed') |
|
439 | - ->with($notification); |
|
440 | - |
|
441 | - $job = $this->getJob(); |
|
442 | - self::invokePrivate($job, 'deleteOutdatedNotifications', [$app, $version]); |
|
443 | - } |
|
444 | - |
|
445 | - /** |
|
446 | - * @param string[] $userIds |
|
447 | - * @return IUser[]|MockObject[] |
|
448 | - */ |
|
449 | - protected function getUsers(array $userIds): array { |
|
450 | - $users = []; |
|
451 | - foreach ($userIds as $uid) { |
|
452 | - $user = $this->createMock(IUser::class); |
|
453 | - $user->expects($this->any()) |
|
454 | - ->method('getUID') |
|
455 | - ->willReturn($uid); |
|
456 | - $users[] = $user; |
|
457 | - } |
|
458 | - return $users; |
|
459 | - } |
|
460 | - |
|
461 | - /** |
|
462 | - * @param string $gid |
|
463 | - * @return IGroup|MockObject |
|
464 | - */ |
|
465 | - protected function getGroup(string $gid) { |
|
466 | - $group = $this->createMock(IGroup::class); |
|
467 | - $group->expects($this->any()) |
|
468 | - ->method('getGID') |
|
469 | - ->willReturn($gid); |
|
470 | - return $group; |
|
471 | - } |
|
28 | + private ServerVersion&MockObject $serverVersion; |
|
29 | + private IConfig|MockObject $config; |
|
30 | + private IManager|MockObject $notificationManager; |
|
31 | + private IGroupManager|MockObject $groupManager; |
|
32 | + private IAppManager|MockObject $appManager; |
|
33 | + private IAppConfig|MockObject $appConfig; |
|
34 | + private ITimeFactory|MockObject $timeFactory; |
|
35 | + private Installer|MockObject $installer; |
|
36 | + private VersionCheck|MockObject $versionCheck; |
|
37 | + |
|
38 | + protected function setUp(): void { |
|
39 | + parent::setUp(); |
|
40 | + |
|
41 | + $this->serverVersion = $this->createMock(ServerVersion::class); |
|
42 | + $this->config = $this->createMock(IConfig::class); |
|
43 | + $this->appConfig = $this->createMock(IAppConfig::class); |
|
44 | + $this->notificationManager = $this->createMock(IManager::class); |
|
45 | + $this->groupManager = $this->createMock(IGroupManager::class); |
|
46 | + $this->appManager = $this->createMock(IAppManager::class); |
|
47 | + $this->timeFactory = $this->createMock(ITimeFactory::class); |
|
48 | + $this->installer = $this->createMock(Installer::class); |
|
49 | + $this->versionCheck = $this->createMock(VersionCheck::class); |
|
50 | + } |
|
51 | + |
|
52 | + /** |
|
53 | + * @param array $methods |
|
54 | + * @return UpdateAvailableNotifications|MockObject |
|
55 | + */ |
|
56 | + protected function getJob(array $methods = []) { |
|
57 | + if (empty($methods)) { |
|
58 | + return new UpdateAvailableNotifications( |
|
59 | + $this->timeFactory, |
|
60 | + $this->serverVersion, |
|
61 | + $this->config, |
|
62 | + $this->appConfig, |
|
63 | + $this->notificationManager, |
|
64 | + $this->groupManager, |
|
65 | + $this->appManager, |
|
66 | + $this->installer, |
|
67 | + $this->versionCheck, |
|
68 | + ); |
|
69 | + } |
|
70 | + { |
|
71 | + return $this->getMockBuilder(UpdateAvailableNotifications::class) |
|
72 | + ->setConstructorArgs([ |
|
73 | + $this->timeFactory, |
|
74 | + $this->serverVersion, |
|
75 | + $this->config, |
|
76 | + $this->appConfig, |
|
77 | + $this->notificationManager, |
|
78 | + $this->groupManager, |
|
79 | + $this->appManager, |
|
80 | + $this->installer, |
|
81 | + $this->versionCheck, |
|
82 | + ]) |
|
83 | + ->onlyMethods($methods) |
|
84 | + ->getMock(); |
|
85 | + } |
|
86 | + } |
|
87 | + |
|
88 | + public function testRun(): void { |
|
89 | + $job = $this->getJob([ |
|
90 | + 'checkCoreUpdate', |
|
91 | + 'checkAppUpdates', |
|
92 | + ]); |
|
93 | + |
|
94 | + $job->expects($this->once()) |
|
95 | + ->method('checkCoreUpdate'); |
|
96 | + $job->expects($this->once()) |
|
97 | + ->method('checkAppUpdates'); |
|
98 | + |
|
99 | + $this->config->expects(self::exactly(2)) |
|
100 | + ->method('getSystemValueBool') |
|
101 | + ->willReturnMap([ |
|
102 | + ['debug', false, true], |
|
103 | + ['has_internet_connection', true, true], |
|
104 | + ]); |
|
105 | + self::invokePrivate($job, 'run', [null]); |
|
106 | + } |
|
107 | + |
|
108 | + public function testRunNoInternet(): void { |
|
109 | + $job = $this->getJob([ |
|
110 | + 'checkCoreUpdate', |
|
111 | + 'checkAppUpdates', |
|
112 | + ]); |
|
113 | + |
|
114 | + $job->expects($this->never()) |
|
115 | + ->method('checkCoreUpdate'); |
|
116 | + $job->expects($this->never()) |
|
117 | + ->method('checkAppUpdates'); |
|
118 | + |
|
119 | + $this->config |
|
120 | + ->expects(self::once()) |
|
121 | + ->method('getSystemValueBool') |
|
122 | + ->with('has_internet_connection', true) |
|
123 | + ->willReturn(false); |
|
124 | + |
|
125 | + self::invokePrivate($job, 'run', [null]); |
|
126 | + } |
|
127 | + |
|
128 | + public function dataCheckCoreUpdate(): array { |
|
129 | + return [ |
|
130 | + ['daily', null, null, null, null], |
|
131 | + ['git', null, null, null, null], |
|
132 | + ['beta', [], null, null, null], |
|
133 | + ['beta', false, false, null, null], |
|
134 | + ['beta', false, false, null, 13], |
|
135 | + ['beta', [ |
|
136 | + 'version' => '9.2.0', |
|
137 | + 'versionstring' => 'Nextcloud 11.0.0', |
|
138 | + ], '9.2.0', 'Nextcloud 11.0.0', null], |
|
139 | + ['stable', [], null, null, null], |
|
140 | + ['stable', false, false, null, null], |
|
141 | + ['stable', false, false, null, 6], |
|
142 | + ['stable', [ |
|
143 | + 'version' => '9.2.0', |
|
144 | + 'versionstring' => 'Nextcloud 11.0.0', |
|
145 | + ], '9.2.0', 'Nextcloud 11.0.0', null], |
|
146 | + ['production', [], null, null, null], |
|
147 | + ['production', false, false, null, null], |
|
148 | + ['production', false, false, null, 2], |
|
149 | + ['production', [ |
|
150 | + 'version' => '9.2.0', |
|
151 | + 'versionstring' => 'Nextcloud 11.0.0', |
|
152 | + ], '9.2.0', 'Nextcloud 11.0.0', null], |
|
153 | + ]; |
|
154 | + } |
|
155 | + |
|
156 | + /** |
|
157 | + * @dataProvider dataCheckCoreUpdate |
|
158 | + * |
|
159 | + * @param string $channel |
|
160 | + * @param mixed $versionCheck |
|
161 | + * @param null|string $version |
|
162 | + * @param null|string $readableVersion |
|
163 | + * @param null|int $errorDays |
|
164 | + */ |
|
165 | + public function testCheckCoreUpdate(string $channel, $versionCheck, $version, $readableVersion, $errorDays): void { |
|
166 | + $job = $this->getJob([ |
|
167 | + 'createNotifications', |
|
168 | + 'clearErrorNotifications', |
|
169 | + 'sendErrorNotifications', |
|
170 | + ]); |
|
171 | + |
|
172 | + $this->serverVersion->expects($this->once()) |
|
173 | + ->method('getChannel') |
|
174 | + ->willReturn($channel); |
|
175 | + |
|
176 | + if ($versionCheck === null) { |
|
177 | + $this->versionCheck->expects($this->never()) |
|
178 | + ->method('check'); |
|
179 | + } else { |
|
180 | + $this->versionCheck->expects($this->once()) |
|
181 | + ->method('check') |
|
182 | + ->willReturn($versionCheck); |
|
183 | + } |
|
184 | + |
|
185 | + if ($version === null) { |
|
186 | + $job->expects($this->never()) |
|
187 | + ->method('createNotifications'); |
|
188 | + $job->expects($versionCheck === null ? $this->never() : $this->once()) |
|
189 | + ->method('clearErrorNotifications'); |
|
190 | + } elseif ($version === false) { |
|
191 | + $job->expects($this->never()) |
|
192 | + ->method('createNotifications'); |
|
193 | + $job->expects($this->never()) |
|
194 | + ->method('clearErrorNotifications'); |
|
195 | + |
|
196 | + $this->appConfig->expects($this->once()) |
|
197 | + ->method('getAppValueInt') |
|
198 | + ->willReturn($errorDays ?? 0); |
|
199 | + $this->appConfig->expects($this->once()) |
|
200 | + ->method('setAppValueInt') |
|
201 | + ->with('update_check_errors', $errorDays + 1); |
|
202 | + $job->expects($errorDays !== null ? $this->once() : $this->never()) |
|
203 | + ->method('sendErrorNotifications') |
|
204 | + ->with($errorDays + 1); |
|
205 | + } else { |
|
206 | + $this->appConfig->expects($this->once()) |
|
207 | + ->method('setAppValueInt') |
|
208 | + ->with('update_check_errors', 0); |
|
209 | + $job->expects($this->once()) |
|
210 | + ->method('clearErrorNotifications'); |
|
211 | + $job->expects($this->once()) |
|
212 | + ->method('createNotifications') |
|
213 | + ->with('core', $version, $readableVersion); |
|
214 | + } |
|
215 | + |
|
216 | + $this->config->expects(self::any()) |
|
217 | + ->method('getSystemValueBool') |
|
218 | + ->willReturnMap([ |
|
219 | + ['updatechecker', true, true], |
|
220 | + ['has_internet_connection', true, true], |
|
221 | + ]); |
|
222 | + |
|
223 | + self::invokePrivate($job, 'checkCoreUpdate'); |
|
224 | + } |
|
225 | + |
|
226 | + public function dataCheckAppUpdates(): array { |
|
227 | + return [ |
|
228 | + [ |
|
229 | + ['app1', 'app2'], |
|
230 | + [ |
|
231 | + ['app1', false], |
|
232 | + ['app2', '1.9.2'], |
|
233 | + ], |
|
234 | + [ |
|
235 | + ['app2', '1.9.2', ''], |
|
236 | + ], |
|
237 | + ], |
|
238 | + ]; |
|
239 | + } |
|
240 | + |
|
241 | + /** |
|
242 | + * @dataProvider dataCheckAppUpdates |
|
243 | + * |
|
244 | + * @param string[] $apps |
|
245 | + * @param array $isUpdateAvailable |
|
246 | + * @param array $notifications |
|
247 | + */ |
|
248 | + public function testCheckAppUpdates(array $apps, array $isUpdateAvailable, array $notifications): void { |
|
249 | + $job = $this->getJob([ |
|
250 | + 'isUpdateAvailable', |
|
251 | + 'createNotifications', |
|
252 | + ]); |
|
253 | + |
|
254 | + $this->appManager->expects($this->once()) |
|
255 | + ->method('getEnabledApps') |
|
256 | + ->willReturn($apps); |
|
257 | + |
|
258 | + $job->expects($this->exactly(\count($apps))) |
|
259 | + ->method('isUpdateAvailable') |
|
260 | + ->willReturnMap($isUpdateAvailable); |
|
261 | + |
|
262 | + $i = 0; |
|
263 | + $job->expects($this->exactly(\count($notifications))) |
|
264 | + ->method('createNotifications') |
|
265 | + ->willReturnCallback(function () use ($notifications, &$i): void { |
|
266 | + $this->assertEquals($notifications[$i], func_get_args()); |
|
267 | + $i++; |
|
268 | + }); |
|
269 | + |
|
270 | + |
|
271 | + self::invokePrivate($job, 'checkAppUpdates'); |
|
272 | + } |
|
273 | + |
|
274 | + public function dataCreateNotifications(): array { |
|
275 | + return [ |
|
276 | + ['app1', '1.0.0', '1.0.0', false, false, null, null], |
|
277 | + ['app2', '1.0.1', '1.0.0', '1.0.0', true, ['user1'], [['user1']]], |
|
278 | + ['app3', '1.0.1', false, false, true, ['user2', 'user3'], [['user2'], ['user3']]], |
|
279 | + ]; |
|
280 | + } |
|
281 | + |
|
282 | + /** |
|
283 | + * @dataProvider dataCreateNotifications |
|
284 | + * |
|
285 | + * @param string $app |
|
286 | + * @param string $version |
|
287 | + * @param string|false $lastNotification |
|
288 | + * @param string|false $callDelete |
|
289 | + * @param bool $createNotification |
|
290 | + * @param string[]|null $users |
|
291 | + * @param array|null $userNotifications |
|
292 | + */ |
|
293 | + public function testCreateNotifications(string $app, string $version, $lastNotification, $callDelete, $createNotification, $users, $userNotifications): void { |
|
294 | + $job = $this->getJob([ |
|
295 | + 'deleteOutdatedNotifications', |
|
296 | + 'getUsersToNotify', |
|
297 | + ]); |
|
298 | + |
|
299 | + $this->appConfig->expects($this->once()) |
|
300 | + ->method('getAppValueString') |
|
301 | + ->with($app, '') |
|
302 | + ->willReturn($lastNotification ?: ''); |
|
303 | + |
|
304 | + if ($lastNotification !== $version) { |
|
305 | + $this->appConfig->expects($this->once()) |
|
306 | + ->method('setAppValueString') |
|
307 | + ->with($app, $version); |
|
308 | + } |
|
309 | + |
|
310 | + if ($callDelete === false) { |
|
311 | + $job->expects($this->never()) |
|
312 | + ->method('deleteOutdatedNotifications'); |
|
313 | + } else { |
|
314 | + $job->expects($this->once()) |
|
315 | + ->method('deleteOutdatedNotifications') |
|
316 | + ->with($app, $callDelete); |
|
317 | + } |
|
318 | + |
|
319 | + if ($users === null) { |
|
320 | + $job->expects($this->never()) |
|
321 | + ->method('getUsersToNotify'); |
|
322 | + } else { |
|
323 | + $job->expects($this->once()) |
|
324 | + ->method('getUsersToNotify') |
|
325 | + ->willReturn($users); |
|
326 | + } |
|
327 | + |
|
328 | + if ($createNotification) { |
|
329 | + $notification = $this->createMock(INotification::class); |
|
330 | + $notification->expects($this->once()) |
|
331 | + ->method('setApp') |
|
332 | + ->with('updatenotification') |
|
333 | + ->willReturnSelf(); |
|
334 | + $notification->expects($this->once()) |
|
335 | + ->method('setDateTime') |
|
336 | + ->willReturnSelf(); |
|
337 | + $notification->expects($this->once()) |
|
338 | + ->method('setObject') |
|
339 | + ->with($app, $version) |
|
340 | + ->willReturnSelf(); |
|
341 | + $notification->expects($this->once()) |
|
342 | + ->method('setSubject') |
|
343 | + ->with('update_available') |
|
344 | + ->willReturnSelf(); |
|
345 | + |
|
346 | + if ($userNotifications !== null) { |
|
347 | + $notification->expects($this->exactly(\count($userNotifications))) |
|
348 | + ->method('setUser') |
|
349 | + ->willReturnSelf(); |
|
350 | + |
|
351 | + $this->notificationManager->expects($this->exactly(\count($userNotifications))) |
|
352 | + ->method('notify'); |
|
353 | + } |
|
354 | + |
|
355 | + $this->notificationManager->expects($this->once()) |
|
356 | + ->method('createNotification') |
|
357 | + ->willReturn($notification); |
|
358 | + } else { |
|
359 | + $this->notificationManager->expects($this->never()) |
|
360 | + ->method('createNotification'); |
|
361 | + } |
|
362 | + |
|
363 | + self::invokePrivate($job, 'createNotifications', [$app, $version]); |
|
364 | + } |
|
365 | + |
|
366 | + public function dataGetUsersToNotify(): array { |
|
367 | + return [ |
|
368 | + [['g1', 'g2'], ['g1' => null, 'g2' => ['u1', 'u2']], ['u1', 'u2']], |
|
369 | + [['g3', 'g4'], ['g3' => ['u1', 'u2'], 'g4' => ['u2', 'u3']], ['u1', 'u2', 'u3']], |
|
370 | + ]; |
|
371 | + } |
|
372 | + |
|
373 | + /** |
|
374 | + * @dataProvider dataGetUsersToNotify |
|
375 | + * @param string[] $groups |
|
376 | + * @param array $groupUsers |
|
377 | + * @param string[] $expected |
|
378 | + */ |
|
379 | + public function testGetUsersToNotify(array $groups, array $groupUsers, array $expected): void { |
|
380 | + $job = $this->getJob(); |
|
381 | + |
|
382 | + $this->appConfig->expects($this->once()) |
|
383 | + ->method('getAppValueArray') |
|
384 | + ->with('notify_groups', ['admin']) |
|
385 | + ->willReturn($groups); |
|
386 | + |
|
387 | + $groupMap = []; |
|
388 | + foreach ($groupUsers as $gid => $uids) { |
|
389 | + if ($uids === null) { |
|
390 | + $group = null; |
|
391 | + } else { |
|
392 | + $group = $this->getGroup($gid); |
|
393 | + $group->expects($this->any()) |
|
394 | + ->method('getUsers') |
|
395 | + ->willReturn($this->getUsers($uids)); |
|
396 | + } |
|
397 | + $groupMap[] = [$gid, $group]; |
|
398 | + } |
|
399 | + $this->groupManager->expects($this->exactly(\count($groups))) |
|
400 | + ->method('get') |
|
401 | + ->willReturnMap($groupMap); |
|
402 | + |
|
403 | + $result = self::invokePrivate($job, 'getUsersToNotify'); |
|
404 | + $this->assertEquals($expected, $result); |
|
405 | + |
|
406 | + // Test caching |
|
407 | + $result = self::invokePrivate($job, 'getUsersToNotify'); |
|
408 | + $this->assertEquals($expected, $result); |
|
409 | + } |
|
410 | + |
|
411 | + public function dataDeleteOutdatedNotifications(): array { |
|
412 | + return [ |
|
413 | + ['app1', '1.1.0'], |
|
414 | + ['app2', '1.2.0'], |
|
415 | + ]; |
|
416 | + } |
|
417 | + |
|
418 | + /** |
|
419 | + * @dataProvider dataDeleteOutdatedNotifications |
|
420 | + * @param string $app |
|
421 | + * @param string $version |
|
422 | + */ |
|
423 | + public function testDeleteOutdatedNotifications(string $app, string $version): void { |
|
424 | + $notification = $this->createMock(INotification::class); |
|
425 | + $notification->expects($this->once()) |
|
426 | + ->method('setApp') |
|
427 | + ->with('updatenotification') |
|
428 | + ->willReturnSelf(); |
|
429 | + $notification->expects($this->once()) |
|
430 | + ->method('setObject') |
|
431 | + ->with($app, $version) |
|
432 | + ->willReturnSelf(); |
|
433 | + |
|
434 | + $this->notificationManager->expects($this->once()) |
|
435 | + ->method('createNotification') |
|
436 | + ->willReturn($notification); |
|
437 | + $this->notificationManager->expects($this->once()) |
|
438 | + ->method('markProcessed') |
|
439 | + ->with($notification); |
|
440 | + |
|
441 | + $job = $this->getJob(); |
|
442 | + self::invokePrivate($job, 'deleteOutdatedNotifications', [$app, $version]); |
|
443 | + } |
|
444 | + |
|
445 | + /** |
|
446 | + * @param string[] $userIds |
|
447 | + * @return IUser[]|MockObject[] |
|
448 | + */ |
|
449 | + protected function getUsers(array $userIds): array { |
|
450 | + $users = []; |
|
451 | + foreach ($userIds as $uid) { |
|
452 | + $user = $this->createMock(IUser::class); |
|
453 | + $user->expects($this->any()) |
|
454 | + ->method('getUID') |
|
455 | + ->willReturn($uid); |
|
456 | + $users[] = $user; |
|
457 | + } |
|
458 | + return $users; |
|
459 | + } |
|
460 | + |
|
461 | + /** |
|
462 | + * @param string $gid |
|
463 | + * @return IGroup|MockObject |
|
464 | + */ |
|
465 | + protected function getGroup(string $gid) { |
|
466 | + $group = $this->createMock(IGroup::class); |
|
467 | + $group->expects($this->any()) |
|
468 | + ->method('getGID') |
|
469 | + ->willReturn($gid); |
|
470 | + return $group; |
|
471 | + } |
|
472 | 472 | } |
@@ -26,14 +26,14 @@ discard block |
||
26 | 26 | |
27 | 27 | class UpdateAvailableNotificationsTest extends TestCase { |
28 | 28 | private ServerVersion&MockObject $serverVersion; |
29 | - private IConfig|MockObject $config; |
|
30 | - private IManager|MockObject $notificationManager; |
|
31 | - private IGroupManager|MockObject $groupManager; |
|
32 | - private IAppManager|MockObject $appManager; |
|
33 | - private IAppConfig|MockObject $appConfig; |
|
34 | - private ITimeFactory|MockObject $timeFactory; |
|
35 | - private Installer|MockObject $installer; |
|
36 | - private VersionCheck|MockObject $versionCheck; |
|
29 | + private IConfig | MockObject $config; |
|
30 | + private IManager | MockObject $notificationManager; |
|
31 | + private IGroupManager | MockObject $groupManager; |
|
32 | + private IAppManager | MockObject $appManager; |
|
33 | + private IAppConfig | MockObject $appConfig; |
|
34 | + private ITimeFactory | MockObject $timeFactory; |
|
35 | + private Installer | MockObject $installer; |
|
36 | + private VersionCheck | MockObject $versionCheck; |
|
37 | 37 | |
38 | 38 | protected function setUp(): void { |
39 | 39 | parent::setUp(); |
@@ -262,7 +262,7 @@ discard block |
||
262 | 262 | $i = 0; |
263 | 263 | $job->expects($this->exactly(\count($notifications))) |
264 | 264 | ->method('createNotifications') |
265 | - ->willReturnCallback(function () use ($notifications, &$i): void { |
|
265 | + ->willReturnCallback(function() use ($notifications, &$i): void { |
|
266 | 266 | $this->assertEquals($notifications[$i], func_get_args()); |
267 | 267 | $i++; |
268 | 268 | }); |