Backend work to provide NC whats New info to users

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
This commit is contained in:
Arthur Schiwon 2018-07-05 00:41:59 +02:00
Родитель cbfcfb236f
Коммит 772bbd99be
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 7424F1874854DF23
17 изменённых файлов: 593 добавлений и 62 удалений

Просмотреть файл

@ -131,6 +131,8 @@
});
this._debouncedPersistShowHiddenFilesState = _.debounce(this._persistShowHiddenFilesState, 1200);
OCP.WhatsNew.query(); // for Nextcloud server
},
/**

Просмотреть файл

@ -123,39 +123,18 @@ class Admin implements ISettings {
return $filtered;
}
$isFirstCall = true;
$iterator = $this->l10nFactory->getLanguageIterator();
do {
$lang = $this->l10nFactory->iterateLanguage($isFirstCall);
if($this->findWhatsNewTranslation($lang, $filtered, $changes['whatsNew'])) {
return $filtered;
$lang = $iterator->current();
if(isset($changes['whatsNew'][$lang])) {
return $filtered['whatsNew'][$lang];
}
$isFirstCall = false;
} while($lang !== 'en');
$iterator->next();
} while($lang !== 'en' && $iterator->valid());
return $filtered;
}
protected function getLangTrunk(string $lang):string {
$pos = strpos($lang, '_');
if($pos !== false) {
$lang = substr($lang, 0, $pos);
}
return $lang;
}
protected function findWhatsNewTranslation(string $lang, array &$result, array $whatsNew): bool {
if(isset($whatsNew[$lang])) {
$result['whatsNew'] = $whatsNew[$lang];
return true;
}
$trunkedLang = $this->getLangTrunk($lang);
if($trunkedLang !== $lang && isset($whatsNew[$trunkedLang])) {
$result['whatsNew'] = $whatsNew[$trunkedLang];
return true;
}
return false;
}
/**
* @param array $groupIds
* @return array

Просмотреть файл

@ -0,0 +1,117 @@
<?php
/**
* @copyright Copyright (c) 2018 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Core\Controller;
use OC\CapabilitiesManager;
use OC\Security\IdentityProof\Manager;
use OC\Updater\ChangesCheck;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\L10N\IFactory;
class WhatsNewController extends OCSController {
/** @var IConfig */
protected $config;
/** @var IUserSession */
private $userSession;
/** @var ChangesCheck */
private $whatsNewService;
/** @var IFactory */
private $langFactory;
public function __construct(
string $appName,
IRequest $request,
CapabilitiesManager $capabilitiesManager,
IUserSession $userSession,
IUserManager $userManager,
Manager $keyManager,
IConfig $config,
ChangesCheck $whatsNewService,
IFactory $langFactory
) {
parent::__construct($appName, $request, $capabilitiesManager, $userSession, $userManager, $keyManager);
$this->config = $config;
$this->userSession = $userSession;
$this->whatsNewService = $whatsNewService;
$this->langFactory = $langFactory;
}
/**
* @NoAdminRequired
*/
public function get():DataResponse {
$user = $this->userSession->getUser();
if($user === null) {
throw new \RuntimeException("Acting user cannot be resolved");
}
$lastRead = $this->config->getUserValue($user->getUID(), 'core', 'whatsNewLastRead', 0);
$currentVersion = $this->whatsNewService->normalizeVersion($this->config->getSystemValue('version'));
if(version_compare($lastRead, $currentVersion, '>=')) {
return new DataResponse([], Http::STATUS_NO_CONTENT);
}
try {
$iterator = $this->langFactory->getLanguageIterator();
$whatsNew = $this->whatsNewService->getChangesForVersion($currentVersion);
$resultData = ['changelogURL' => $whatsNew['changelogURL']];
do {
$lang = $iterator->current();
if(isset($whatsNew['whatsNew'][$lang])) {
$resultData['whatsNew'] = $whatsNew['whatsNew'][$lang];
break;
}
$iterator->next();
} while ($lang !== 'en' && $iterator->valid());
return new DataResponse($resultData);
} catch (DoesNotExistException $e) {
return new DataResponse([], Http::STATUS_NO_CONTENT);
}
}
/**
* @NoAdminRequired
*
* @throws \OCP\PreConditionNotMetException
* @throws DoesNotExistException
*/
public function dismiss(string $version):DataResponse {
$user = $this->userSession->getUser();
if($user === null) {
throw new \RuntimeException("Acting user cannot be resolved");
}
$version = $this->whatsNewService->normalizeVersion($version);
// checks whether it's a valid version, throws an Exception otherwise
$this->whatsNewService->getChangesForVersion($version);
$this->config->setUserValue($user->getUID(), 'core', 'whatsNewLastRead', $version);
return new DataResponse();
}
}

Просмотреть файл

@ -48,6 +48,7 @@
"public/appconfig.js",
"public/comments.js",
"public/publicpage.js",
"public/whatsnew.js",
"multiselect.js",
"oc-requesttoken.js",
"setupchecks.js",

Просмотреть файл

@ -7,6 +7,7 @@
"eventsource.js",
"public/appconfig.js",
"public/comments.js",
"public/whatsnew.js",
"config.js",
"oc-requesttoken.js",
"apps.js",

Просмотреть файл

@ -0,0 +1,54 @@
/**
* @copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*/
(function(OCP) {
"use strict";
OCP.WhatsNew = {
query: function(options) {
options = options || {};
$.ajax({
type: 'GET',
url: options.url || OC.linkToOCS('core', 2) + 'whatsnew?format=json',
success: options.success || this._onQuerySuccess,
error: options.error || this._onQueryError
});
},
dismiss: function(version, options) {
options = options || {};
$.ajax({
type: 'POST',
url: options.url || OC.linkToOCS('core', 2) + 'whatsnew',
data: {version: encodeURIComponent(version)},
success: options.success || this._onDismissSuccess,
error: options.error || this._onDismissError
});
},
_onQuerySuccess: function(data, statusText) {
console.debug('querying Whats New data was successful: ' + data || statusText);
console.debug(data);
},
_onQueryError: function (o, t, e) {
console.debug(o);
console.debug('querying Whats New Data resulted in an error: ' + t +e);
},
_onDismissSuccess: function(data) {
console.debug('dismissing Whats New data was successful: ' + data);
},
_onDismissError: function (data) {
console.debug('dismissing Whats New data resulted in an error: ' + data);
}
};
})(OCP);

Просмотреть файл

@ -76,6 +76,8 @@ $application->registerRoutes($this, [
['root' => '/core', 'name' => 'Navigation#getAppsNavigation', 'url' => '/navigation/apps', 'verb' => 'GET'],
['root' => '/core', 'name' => 'Navigation#getSettingsNavigation', 'url' => '/navigation/settings', 'verb' => 'GET'],
['root' => '/core', 'name' => 'AutoComplete#get', 'url' => '/autocomplete/get', 'verb' => 'GET'],
['root' => '/core', 'name' => 'WhatsNew#get', 'url' => '/whatsnew', 'verb' => 'GET'],
['root' => '/core', 'name' => 'WhatsNew#dismiss', 'url' => '/whatsnew', 'verb' => 'POST'],
],
]);

Просмотреть файл

@ -259,6 +259,7 @@ return array(
'OCP\\IUserSession' => $baseDir . '/lib/public/IUserSession.php',
'OCP\\Image' => $baseDir . '/lib/public/Image.php',
'OCP\\L10N\\IFactory' => $baseDir . '/lib/public/L10N/IFactory.php',
'OCP\\L10N\\ILanguageIterator' => $baseDir . '/lib/public/L10N/ILanguageIterator.php',
'OCP\\LDAP\\IDeletionFlagSupport' => $baseDir . '/lib/public/LDAP/IDeletionFlagSupport.php',
'OCP\\LDAP\\ILDAPProvider' => $baseDir . '/lib/public/LDAP/ILDAPProvider.php',
'OCP\\LDAP\\ILDAPProviderFactory' => $baseDir . '/lib/public/LDAP/ILDAPProviderFactory.php',
@ -595,6 +596,7 @@ return array(
'OC\\Core\\Controller\\TwoFactorChallengeController' => $baseDir . '/core/Controller/TwoFactorChallengeController.php',
'OC\\Core\\Controller\\UserController' => $baseDir . '/core/Controller/UserController.php',
'OC\\Core\\Controller\\WalledGardenController' => $baseDir . '/core/Controller/WalledGardenController.php',
'OC\\Core\\Controller\\WhatsNewController' => $baseDir . '/core/Controller/WhatsNewController.php',
'OC\\Core\\Middleware\\TwoFactorMiddleware' => $baseDir . '/core/Middleware/TwoFactorMiddleware.php',
'OC\\Core\\Migrations\\Version13000Date20170705121758' => $baseDir . '/core/Migrations/Version13000Date20170705121758.php',
'OC\\Core\\Migrations\\Version13000Date20170718121200' => $baseDir . '/core/Migrations/Version13000Date20170718121200.php',
@ -792,6 +794,7 @@ return array(
'OC\\L10N\\Factory' => $baseDir . '/lib/private/L10N/Factory.php',
'OC\\L10N\\L10N' => $baseDir . '/lib/private/L10N/L10N.php',
'OC\\L10N\\L10NString' => $baseDir . '/lib/private/L10N/L10NString.php',
'OC\\L10N\\LanguageIterator' => $baseDir . '/lib/private/L10N/LanguageIterator.php',
'OC\\L10N\\LanguageNotFoundException' => $baseDir . '/lib/private/L10N/LanguageNotFoundException.php',
'OC\\LargeFileHelper' => $baseDir . '/lib/private/LargeFileHelper.php',
'OC\\Lock\\AbstractLockingProvider' => $baseDir . '/lib/private/Lock/AbstractLockingProvider.php',

Просмотреть файл

@ -289,6 +289,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\IUserSession' => __DIR__ . '/../../..' . '/lib/public/IUserSession.php',
'OCP\\Image' => __DIR__ . '/../../..' . '/lib/public/Image.php',
'OCP\\L10N\\IFactory' => __DIR__ . '/../../..' . '/lib/public/L10N/IFactory.php',
'OCP\\L10N\\ILanguageIterator' => __DIR__ . '/../../..' . '/lib/public/L10N/ILanguageIterator.php',
'OCP\\LDAP\\IDeletionFlagSupport' => __DIR__ . '/../../..' . '/lib/public/LDAP/IDeletionFlagSupport.php',
'OCP\\LDAP\\ILDAPProvider' => __DIR__ . '/../../..' . '/lib/public/LDAP/ILDAPProvider.php',
'OCP\\LDAP\\ILDAPProviderFactory' => __DIR__ . '/../../..' . '/lib/public/LDAP/ILDAPProviderFactory.php',
@ -625,6 +626,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Controller\\TwoFactorChallengeController' => __DIR__ . '/../../..' . '/core/Controller/TwoFactorChallengeController.php',
'OC\\Core\\Controller\\UserController' => __DIR__ . '/../../..' . '/core/Controller/UserController.php',
'OC\\Core\\Controller\\WalledGardenController' => __DIR__ . '/../../..' . '/core/Controller/WalledGardenController.php',
'OC\\Core\\Controller\\WhatsNewController' => __DIR__ . '/../../..' . '/core/Controller/WhatsNewController.php',
'OC\\Core\\Middleware\\TwoFactorMiddleware' => __DIR__ . '/../../..' . '/core/Middleware/TwoFactorMiddleware.php',
'OC\\Core\\Migrations\\Version13000Date20170705121758' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170705121758.php',
'OC\\Core\\Migrations\\Version13000Date20170718121200' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170718121200.php',
@ -822,6 +824,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\L10N\\Factory' => __DIR__ . '/../../..' . '/lib/private/L10N/Factory.php',
'OC\\L10N\\L10N' => __DIR__ . '/../../..' . '/lib/private/L10N/L10N.php',
'OC\\L10N\\L10NString' => __DIR__ . '/../../..' . '/lib/private/L10N/L10NString.php',
'OC\\L10N\\LanguageIterator' => __DIR__ . '/../../..' . '/lib/private/L10N/LanguageIterator.php',
'OC\\L10N\\LanguageNotFoundException' => __DIR__ . '/../../..' . '/lib/private/L10N/LanguageNotFoundException.php',
'OC\\LargeFileHelper' => __DIR__ . '/../../..' . '/lib/private/LargeFileHelper.php',
'OC\\Lock\\AbstractLockingProvider' => __DIR__ . '/../../..' . '/lib/private/Lock/AbstractLockingProvider.php',

Просмотреть файл

@ -35,6 +35,7 @@ use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCP\L10N\IFactory;
use OCP\L10N\ILanguageIterator;
/**
* A factory that generates language instances
@ -322,35 +323,12 @@ class Factory implements IFactory {
return array_search($lang, $languages) !== false;
}
public function iterateLanguage(bool $reset = false): string {
static $i = 0;
if($reset) {
$i = 0;
}
switch($i) {
/** @noinspection PhpMissingBreakStatementInspection */
case 0:
$i++;
$forcedLang = $this->config->getSystemValue('force_language', false);
if(is_string($forcedLang)) {
return $forcedLang;
}
/** @noinspection PhpMissingBreakStatementInspection */
case 1:
$i++;
$user = $this->userSession->getUser();
if($user instanceof IUser) {
$userLang = $this->config->getUserValue($user->getUID(), 'core', 'lang', null);
if(is_string($userLang)) {
return $userLang;
}
}
case 2:
$i++;
return $this->config->getSystemValue('default_language', 'en');
default:
return 'en';
public function getLanguageIterator(IUser $user = null): ILanguageIterator {
$user = $user ?? $this->userSession->getUser();
if($user === null) {
throw new \RuntimeException('Failed to get an IUser instance');
}
return new LanguageIterator($user, $this->config);
}
/**

Просмотреть файл

@ -0,0 +1,137 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\L10N;
use OCP\IConfig;
use OCP\IUser;
use OCP\L10N\ILanguageIterator;
class LanguageIterator implements ILanguageIterator {
private $i = 0;
/** @var IConfig */
private $config;
/** @var IUser */
private $user;
public function __construct(IUser $user, IConfig $config) {
$this->config = $config;
$this->user = $user;
}
/**
* Rewind the Iterator to the first element
*/
public function rewind() {
$this->i = 0;
}
/**
* Return the current element
*
* @since 14.0.0
*/
public function current(): string {
switch($this->i) {
/** @noinspection PhpMissingBreakStatementInspection */
case 0:
$forcedLang = $this->config->getSystemValue('force_language', false);
if(is_string($forcedLang)) {
return $forcedLang;
}
$this->next();
/** @noinspection PhpMissingBreakStatementInspection */
case 1:
$forcedLang = $this->config->getSystemValue('force_language', false);
if(is_string($forcedLang)
&& ($truncated = $this->getTruncatedLanguage($forcedLang)) !== $forcedLang
) {
return $truncated;
}
$this->next();
/** @noinspection PhpMissingBreakStatementInspection */
case 2:
$userLang = $this->config->getUserValue($this->user->getUID(), 'core', 'lang', null);
if(is_string($userLang)) {
return $userLang;
}
$this->next();
/** @noinspection PhpMissingBreakStatementInspection */
case 3:
$userLang = $this->config->getUserValue($this->user->getUID(), 'core', 'lang', null);
if(is_string($userLang)
&& ($truncated = $this->getTruncatedLanguage($userLang)) !== $userLang
) {
return $truncated;
}
$this->next();
case 4:
return $this->config->getSystemValue('default_language', 'en');
/** @noinspection PhpMissingBreakStatementInspection */
case 5:
$defaultLang = $this->config->getSystemValue('default_language', 'en');
if(($truncated = $this->getTruncatedLanguage($defaultLang)) !== $defaultLang) {
return $truncated;
}
$this->next();
default:
return 'en';
}
}
/**
* Move forward to next element
*
* @since 14.0.0
*/
public function next() {
++$this->i;
}
/**
* Return the key of the current element
*
* @since 14.0.0
*/
public function key(): int {
return $this->i;
}
/**
* Checks if current position is valid
*
* @since 14.0.0
*/
public function valid(): bool {
return $this->i <= 6;
}
protected function getTruncatedLanguage(string $lang):string {
$pos = strpos($lang, '_');
if($pos !== false) {
$lang = substr($lang, 0, $pos);
}
return $lang;
}
}

Просмотреть файл

@ -47,6 +47,15 @@ class ChangesCheck {
$this->logger = $logger;
}
/**
* @throws DoesNotExistException
*/
public function getChangesForVersion(string $version): array {
$version = $this->normalizeVersion($version);
$changesInfo = $this->mapper->getChanges($version);
return json_decode($changesInfo->getData(), true);
}
/**
* @throws \Exception
*/
@ -145,7 +154,7 @@ class ChangesCheck {
* returns a x.y.z form of the provided version. Extra numbers will be
* omitted, missing ones added as zeros.
*/
protected function normalizeVersion(string $version): string {
public function normalizeVersion(string $version): string {
$versionNumbers = array_slice(explode('.', $version), 0, 3);
$versionNumbers[0] = $versionNumbers[0] ?: '0'; // deal with empty input
while(count($versionNumbers) < 3) {

Просмотреть файл

@ -21,6 +21,8 @@
*/
namespace OCP\L10N;
use OCP\IUser;
/**
* @since 8.2.0
*/
@ -93,10 +95,16 @@ interface IFactory {
/**
* iterate through language settings (if provided) in this order:
* 1. returns the forced language or:
* 2. returns the user language or:
* 3. returns the system default language or:
* 4+. returns 'en'
* 2. if applicable, the trunk of 1 (e.g. "fu" instead of "fu_BAR"
* 3. returns the user language or:
* 4. if applicable, the trunk of 3
* 5. returns the system default language or:
* 6. if applicable, the trunk of 5
* 7+. returns 'en'
*
* Hint: in most cases findLanguage() suits you fine
*
* @since 14.0.0
*/
public function iterateLanguage(bool $reset = false): string;
public function getLanguageIterator(IUser $user = null): ILanguageIterator;
}

Просмотреть файл

@ -0,0 +1,74 @@
<?php
/**
* @copyright Copyright (c) 2018 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\L10N;
/**
* Interface ILanguageIterator
*
* iterator across language settings (if provided) in this order:
* 1. returns the forced language or:
* 2. if applicable, the trunk of 1 (e.g. "fu" instead of "fu_BAR"
* 3. returns the user language or:
* 4. if applicable, the trunk of 3
* 5. returns the system default language or:
* 6. if applicable, the trunk of 5
* 7+. returns 'en'
*
* if settings are not present or truncating is not applicable, the iterator
* skips to the next valid item itself
*
* @package OCP\L10N
*
* @since 14.0.0
*/
interface ILanguageIterator extends \Iterator {
/**
* Return the current element
*
* @since 14.0.0
*/
public function current(): string;
/**
* Move forward to next element
*
* @since 14.0.0
*/
public function next();
/**
* Return the key of the current element
*
* @since 14.0.0
*/
public function key():int;
/**
* Checks if current position is valid
*
* @since 14.0.0
*/
public function valid():bool;
}

Просмотреть файл

@ -14,6 +14,7 @@ use OCP\IConfig;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCP\L10N\ILanguageIterator;
use Test\TestCase;
/**
@ -596,4 +597,33 @@ class FactoryTest extends TestCase {
$this->assertSame($expected, $result);
}
public function languageIteratorRequestProvider():array {
return [
[ true, $this->createMock(IUser::class)],
[ false, $this->createMock(IUser::class)],
[ false, null]
];
}
/**
* @dataProvider languageIteratorRequestProvider
*/
public function testGetLanguageIterator(bool $hasSession, IUser $iUserMock = null) {
$factory = $this->getFactory();
if($iUserMock === null) {
$matcher = $this->userSession->expects($this->once())
->method('getUser');
if($hasSession) {
$matcher->willReturn($this->createMock(IUser::class));
} else {
$this->expectException(\RuntimeException::class);
}
}
$iterator = $factory->getLanguageIterator($iUserMock);
$this->assertInstanceOf(ILanguageIterator::class, $iterator);
}
}

Просмотреть файл

@ -0,0 +1,98 @@
<?php
/**
* @copyright Copyright (c) 2018 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Test\L10N;
use OC\L10N\LanguageIterator;
use OCP\IConfig;
use OCP\IUser;
use Test\TestCase;
class LanguageIteratorTest extends TestCase {
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject */
protected $user;
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
protected $config;
/** @var LanguageIterator */
protected $iterator;
public function setUp() {
parent::setUp();
$this->user = $this->createMock(IUser::class);
$this->config = $this->createMock(IConfig::class);
$this->iterator = new LanguageIterator($this->user, $this->config);
}
public function languageSettingsProvider() {
return [
// all language settings set
[ 'de_DE', 'es_CU', 'zh_TW', ['de_DE', 'de', 'es_CU', 'es', 'zh_TW', 'zh', 'en']],
[ 'de', 'es', 'zh', ['de', 'es', 'zh', 'en']],
[ 'en', 'en', 'en', ['en', 'en', 'en', 'en']],
// one possible setting is missing each
[ false, 'es_CU', 'zh_TW', ['es_CU', 'es', 'zh_TW', 'zh', 'en']],
[ false, 'es', 'zh_TW', ['es', 'zh_TW', 'zh', 'en']],
[ false, 'es_CU', 'zh', ['es_CU', 'es', 'zh', 'en']],
[ 'de_DE', null, 'zh_TW', ['de_DE', 'de', 'zh_TW', 'zh', 'en']],
[ 'de_DE', null, 'zh', ['de_DE', 'de', 'zh', 'en']],
[ 'de', null, 'zh_TW', ['de', 'zh_TW', 'zh', 'en']],
[ 'de_DE', 'es_CU', 'en', ['de_DE', 'de', 'es_CU', 'es', 'en', 'en']],
[ 'de', 'es_CU', 'en', ['de', 'es_CU', 'es', 'en', 'en']],
[ 'de_DE', 'es', 'en', ['de_DE', 'de', 'es', 'en', 'en']],
// two possible settings are missing each
[ false, null, 'zh_TW', ['zh_TW', 'zh', 'en']],
[ false, null, 'zh', ['zh', 'en']],
[ false, 'es_CU', 'en', ['es_CU', 'es', 'en', 'en']],
[ false, 'es', 'en', ['es', 'en', 'en']],
[ 'de_DE', null, 'en', ['de_DE', 'de', 'en', 'en']],
[ 'de', null, 'en', ['de', 'en', 'en']],
// nothing is set
[ false, null, 'en', ['en', 'en']],
];
}
/**
* @dataProvider languageSettingsProvider
*/
public function testIterator($forcedLang, $userLang, $sysLang, $expectedValues) {
$this->config->expects($this->any())
->method('getSystemValue')
->willReturnMap([
['force_language', false, $forcedLang],
['default_language', 'en', $sysLang],
]);
$this->config->expects($this->any())
->method('getUserValue')
->willReturn($userLang);
foreach ($expectedValues as $expected) {
$this->assertTrue($this->iterator->valid());
$this->assertSame($expected, $this->iterator->current());
$this->iterator->next();
}
$this->assertFalse($this->iterator->valid());
}
}

Просмотреть файл

@ -29,11 +29,11 @@ namespace Test\Updater;
use OC\Updater\ChangesCheck;
use OC\Updater\ChangesMapper;
use OC\Updater\ChangesResult;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
use OCP\ILogger;
use const Solarium\QueryType\Select\Query\Component\Facet\INCLUDE_LOWER;
use Test\TestCase;
class ChangesCheckTest extends TestCase {
@ -338,7 +338,42 @@ class ChangesCheckTest extends TestCase {
* @dataProvider versionProvider
*/
public function testNormalizeVersion(string $input, string $expected) {
$normalized = $this->invokePrivate($this->checker, 'normalizeVersion', [$input]);
$normalized = $this->checker->normalizeVersion($input);
$this->assertSame($expected, $normalized);
}
public function changeDataProvider():array {
$testDataFound = $testDataNotFound = $this->versionProvider();
array_walk($testDataFound, function(&$params) { $params[] = true; });
array_walk($testDataNotFound, function(&$params) { $params[] = false; });
return array_merge($testDataFound, $testDataNotFound);
}
/**
* @dataProvider changeDataProvider
*
*/
public function testGetChangesForVersion(string $inputVersion, string $normalizedVersion, bool $isFound) {
$mocker = $this->mapper->expects($this->once())
->method('getChanges')
->with($normalizedVersion);
if(!$isFound) {
$this->expectException(DoesNotExistException::class);
$mocker->willThrowException(new DoesNotExistException('Changes info is not present'));
} else {
$entry = $this->createMock(ChangesResult::class);
$entry->expects($this->once())
->method('__call')
->with('getData')
->willReturn('{"changelogURL":"https:\/\/nextcloud.com\/changelog\/#13-0-0","whatsNew":{"en":{"regular":["Refined user interface","End-to-end Encryption","Video and Text Chat"],"admin":["Changes to the Nginx configuration","Theming: CSS files were consolidated"]},"de":{"regular":["\u00dcberarbeitete Benutzerschnittstelle","Ende-zu-Ende Verschl\u00fcsselung","Video- und Text-Chat"],"admin":["\u00c4nderungen an der Nginx Konfiguration","Theming: CSS Dateien wurden konsolidiert"]}}}');
$mocker->willReturn($entry);
}
/** @noinspection PhpUnhandledExceptionInspection */
$data = $this->checker->getChangesForVersion($inputVersion);
$this->assertTrue(isset($data['whatsNew']['en']['regular']));
$this->assertTrue(isset($data['changelogURL']));
}
}