зеркало из https://github.com/nextcloud/server.git
Backend work to provide NC whats New info to users
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
This commit is contained in:
Родитель
cbfcfb236f
Коммит
772bbd99be
|
@ -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']));
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче