Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>pull/10110/head
parent
cbfcfb236f
commit
772bbd99be
@ -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(); |
||||
} |
||||
} |
||||
@ -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); |
||||
@ -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; |
||||
} |
||||
} |
||||
@ -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; |
||||
} |
||||
@ -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()); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue