mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 08:44:07 -04:00
Merge pull request #13646 from nextcloud/enh/13488/initialstate
Allow apps to register an initial state
This commit is contained in:
commit
9d4e71f64d
20 changed files with 223 additions and 21 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -29,6 +29,7 @@ use OCA\TwoFactorBackupCodes\Settings\Personal;
|
|||
use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
|
||||
use OCP\Authentication\TwoFactorAuth\IProvider;
|
||||
use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\IL10N;
|
||||
use OCP\IUser;
|
||||
use OCP\Template;
|
||||
|
|
@ -46,6 +47,8 @@ class BackupCodesProvider implements IProvider, IProvidesPersonalSettings {
|
|||
|
||||
/** @var AppManager */
|
||||
private $appManager;
|
||||
/** @var IInitialStateService */
|
||||
private $initialStateService;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
|
|
@ -53,11 +56,16 @@ class BackupCodesProvider implements IProvider, IProvidesPersonalSettings {
|
|||
* @param IL10N $l10n
|
||||
* @param AppManager $appManager
|
||||
*/
|
||||
public function __construct(string $appName, BackupCodeStorage $storage, IL10N $l10n, AppManager $appManager) {
|
||||
public function __construct(string $appName,
|
||||
BackupCodeStorage $storage,
|
||||
IL10N $l10n,
|
||||
AppManager $appManager,
|
||||
IInitialStateService $initialStateService) {
|
||||
$this->appName = $appName;
|
||||
$this->l10n = $l10n;
|
||||
$this->storage = $storage;
|
||||
$this->appManager = $appManager;
|
||||
$this->initialStateService = $initialStateService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -149,7 +157,8 @@ class BackupCodesProvider implements IProvider, IProvidesPersonalSettings {
|
|||
*/
|
||||
public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
|
||||
$state = $this->storage->getBackupCodesState($user);
|
||||
return new Personal(base64_encode(json_encode($state)));
|
||||
$this->initialStateService->provideInitialState($this->appName, $state);
|
||||
return new Personal();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,18 +28,8 @@ use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
|
|||
use OCP\Template;
|
||||
|
||||
class Personal implements IPersonalProviderSettings {
|
||||
|
||||
/** @var string */
|
||||
private $state;
|
||||
|
||||
public function __construct(string $state) {
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
public function getBody(): Template {
|
||||
$template = new Template('twofactor_backupcodes', 'personal');
|
||||
$template->assign('state', $this->state);
|
||||
return $template;
|
||||
return new Template('twofactor_backupcodes', 'personal');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import store from './store';
|
|||
|
||||
Vue.prototype.t = t;
|
||||
|
||||
const initialStateElem = document.getElementById('twofactor-backupcodes-initial-state');
|
||||
const initialState = OCP.InitialState.loadState('twofactor_backupcodes');
|
||||
store.replaceState(
|
||||
JSON.parse(atob(initialStateElem.value))
|
||||
initialState
|
||||
)
|
||||
|
||||
const View = Vue.extend(PersonalSettings)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace OCA\TwoFactorBackupCodes\Tests\Unit\Provider;
|
|||
use OC\App\AppManager;
|
||||
use OCA\TwoFactorBackupCodes\Provider\BackupCodesProvider;
|
||||
use OCA\TwoFactorBackupCodes\Service\BackupCodeStorage;
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\IL10N;
|
||||
use OCP\IUser;
|
||||
use OCP\Template;
|
||||
|
|
@ -45,6 +46,9 @@ class BackupCodesProviderTest extends TestCase {
|
|||
/** @var AppManager|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $appManager;
|
||||
|
||||
/** @var IInitialStateService|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $initialState;
|
||||
|
||||
/** @var BackupCodesProvider */
|
||||
private $provider;
|
||||
|
||||
|
|
@ -55,8 +59,9 @@ class BackupCodesProviderTest extends TestCase {
|
|||
$this->storage = $this->createMock(BackupCodeStorage::class);
|
||||
$this->l10n = $this->createMock(IL10N::class);
|
||||
$this->appManager = $this->createMock(AppManager::class);
|
||||
$this->initialState = $this->createMock(IInitialStateService::class);
|
||||
|
||||
$this->provider = new BackupCodesProvider($this->appName, $this->storage, $this->l10n, $this->appManager);
|
||||
$this->provider = new BackupCodesProvider($this->appName, $this->storage, $this->l10n, $this->appManager, $this->initialState);
|
||||
}
|
||||
|
||||
public function testGetId() {
|
||||
|
|
|
|||
2
core/js/dist/main.js
vendored
2
core/js/dist/main.js
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/main.js.map
vendored
2
core/js/dist/main.js.map
vendored
File diff suppressed because one or more lines are too long
|
|
@ -2,8 +2,10 @@
|
|||
*
|
||||
*/
|
||||
import loader from './loader'
|
||||
import initialState from './initialstate'
|
||||
|
||||
/** @namespace OCP */
|
||||
export default {
|
||||
Loader: loader,
|
||||
InitialState: initialState,
|
||||
};
|
||||
|
|
|
|||
42
core/src/OCP/initialstate.js
Normal file
42
core/src/OCP/initialstate.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* @copyright Copyright (c) 2019 Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @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
|
||||
* @class InitialState
|
||||
*/
|
||||
export default {
|
||||
loadState: function(app) {
|
||||
const elem = document.querySelector('#initial-state-' + app);
|
||||
if (elem === null) {
|
||||
console.error('Could not find initial state of ' + app);
|
||||
throw new Error('Could not find initial state of ' + app);
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(atob(elem.value));
|
||||
} catch (e) {
|
||||
console.error('Could not parse initial state of ' + app);
|
||||
throw new Error('Could not parse initial state of ' + app);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -18,6 +18,9 @@
|
|||
</head>
|
||||
<body id="body-public" class="layout-base">
|
||||
<?php include 'layout.noscript.warning.php'; ?>
|
||||
<?php foreach ($_['initialStates'] as $app => $initialState) { ?>
|
||||
<input type="hidden" id="initial-state-<?php p($app); ?>" value="<?php p(base64_encode($initialState)); ?>">
|
||||
<?php }?>
|
||||
<div id="content" class="app-public" role="main">
|
||||
<?php print_unescaped($_['content']); ?>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
</head>
|
||||
<body id="<?php p($_['bodyid']);?>">
|
||||
<?php include 'layout.noscript.warning.php'; ?>
|
||||
<?php foreach ($_['initialStates'] as $app => $initialState) { ?>
|
||||
<input type="hidden" id="initial-state-<?php p($app); ?>" value="<?php p(base64_encode($initialState)); ?>">
|
||||
<?php }?>
|
||||
<div class="wrapper">
|
||||
<div class="v-align">
|
||||
<?php if ($_['bodyid'] === 'body-login' ): ?>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
</head>
|
||||
<body id="<?php p($_['bodyid']);?>">
|
||||
<?php include('layout.noscript.warning.php'); ?>
|
||||
<?php foreach ($_['initialStates'] as $app => $initialState) { ?>
|
||||
<input type="hidden" id="initial-state-<?php p($app); ?>" value="<?php p(base64_encode($initialState)); ?>">
|
||||
<?php }?>
|
||||
<div id="notification-container">
|
||||
<div id="notification"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@
|
|||
<body id="<?php p($_['bodyid']);?>">
|
||||
<?php include 'layout.noscript.warning.php'; ?>
|
||||
|
||||
<?php foreach ($_['initialStates'] as $app => $initialState) { ?>
|
||||
<input type="hidden" id="initial-state-<?php p($app); ?>" value="<?php p(base64_encode($initialState)); ?>">
|
||||
<?php }?>
|
||||
|
||||
<a href="#app-content" class="button primary skip-navigation skip-content"><?php p($l->t('Skip to main content')); ?></a>
|
||||
<a href="#app-navigation" class="button primary skip-navigation"><?php p($l->t('Skip to navigation of app')); ?></a>
|
||||
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ return array(
|
|||
'OCP\\IGroup' => $baseDir . '/lib/public/IGroup.php',
|
||||
'OCP\\IGroupManager' => $baseDir . '/lib/public/IGroupManager.php',
|
||||
'OCP\\IImage' => $baseDir . '/lib/public/IImage.php',
|
||||
'OCP\\IInitialStateService' => $baseDir . '/lib/public/IInitialStateService.php',
|
||||
'OCP\\IL10N' => $baseDir . '/lib/public/IL10N.php',
|
||||
'OCP\\ILogger' => $baseDir . '/lib/public/ILogger.php',
|
||||
'OCP\\IMemcache' => $baseDir . '/lib/public/IMemcache.php',
|
||||
|
|
@ -854,6 +855,7 @@ return array(
|
|||
'OC\\Http\\Client\\ClientService' => $baseDir . '/lib/private/Http/Client/ClientService.php',
|
||||
'OC\\Http\\Client\\Response' => $baseDir . '/lib/private/Http/Client/Response.php',
|
||||
'OC\\Http\\CookieHelper' => $baseDir . '/lib/private/Http/CookieHelper.php',
|
||||
'OC\\InitialStateService' => $baseDir . '/lib/private/InitialStateService.php',
|
||||
'OC\\Installer' => $baseDir . '/lib/private/Installer.php',
|
||||
'OC\\IntegrityCheck\\Checker' => $baseDir . '/lib/private/IntegrityCheck/Checker.php',
|
||||
'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException' => $baseDir . '/lib/private/IntegrityCheck/Exceptions/InvalidSignatureException.php',
|
||||
|
|
|
|||
|
|
@ -314,6 +314,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OCP\\IGroup' => __DIR__ . '/../../..' . '/lib/public/IGroup.php',
|
||||
'OCP\\IGroupManager' => __DIR__ . '/../../..' . '/lib/public/IGroupManager.php',
|
||||
'OCP\\IImage' => __DIR__ . '/../../..' . '/lib/public/IImage.php',
|
||||
'OCP\\IInitialStateService' => __DIR__ . '/../../..' . '/lib/public/IInitialStateService.php',
|
||||
'OCP\\IL10N' => __DIR__ . '/../../..' . '/lib/public/IL10N.php',
|
||||
'OCP\\ILogger' => __DIR__ . '/../../..' . '/lib/public/ILogger.php',
|
||||
'OCP\\IMemcache' => __DIR__ . '/../../..' . '/lib/public/IMemcache.php',
|
||||
|
|
@ -884,6 +885,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Http\\Client\\ClientService' => __DIR__ . '/../../..' . '/lib/private/Http/Client/ClientService.php',
|
||||
'OC\\Http\\Client\\Response' => __DIR__ . '/../../..' . '/lib/private/Http/Client/Response.php',
|
||||
'OC\\Http\\CookieHelper' => __DIR__ . '/../../..' . '/lib/private/Http/CookieHelper.php',
|
||||
'OC\\InitialStateService' => __DIR__ . '/../../..' . '/lib/private/InitialStateService.php',
|
||||
'OC\\Installer' => __DIR__ . '/../../..' . '/lib/private/Installer.php',
|
||||
'OC\\IntegrityCheck\\Checker' => __DIR__ . '/../../..' . '/lib/private/IntegrityCheck/Checker.php',
|
||||
'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException' => __DIR__ . '/../../..' . '/lib/private/IntegrityCheck/Exceptions/InvalidSignatureException.php',
|
||||
|
|
|
|||
74
lib/private/InitialStateService.php
Normal file
74
lib/private/InitialStateService.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @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;
|
||||
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\ILogger;
|
||||
|
||||
class InitialStateService implements IInitialStateService {
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var array */
|
||||
private $states = [];
|
||||
|
||||
/** @var array */
|
||||
private $lazyStates = [];
|
||||
|
||||
public function __construct(ILogger $logger) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function provideInitialState(string $appName, $data) {
|
||||
// Scalars and JsonSerializable are fine
|
||||
if (is_scalar($data) || $data instanceof \JsonSerializable || is_array($data)) {
|
||||
$this->states[$appName] = json_encode($data);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->warning('Invalid data provided to provideInitialState by ' . $appName);
|
||||
}
|
||||
|
||||
public function provideLazyInitialState(string $appName, \Closure $closure) {
|
||||
$this->lazyStates[$appName] = $closure;
|
||||
}
|
||||
|
||||
public function getInitialStates(): array {
|
||||
$states = $this->states;
|
||||
foreach ($this->lazyStates as $app => $lazyState) {
|
||||
$state = $lazyState();
|
||||
|
||||
if (!($lazyState instanceof \JsonSerializable)) {
|
||||
$this->logger->warning($app . ' provided an invalid lazy state');
|
||||
}
|
||||
|
||||
$states[$app] = json_encode($state);
|
||||
}
|
||||
|
||||
return $states;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -144,6 +144,7 @@ use OCP\GlobalScale\IConfig;
|
|||
use OCP\Group\ISubAdmin;
|
||||
use OCP\ICacheFactory;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\IL10N;
|
||||
use OCP\IServerContainer;
|
||||
use OCP\ITempManager;
|
||||
|
|
@ -1204,6 +1205,8 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
|
||||
$this->registerAlias(ISubAdmin::class, SubAdmin::class);
|
||||
|
||||
$this->registerAlias(IInitialStateService::class, InitialStateService::class);
|
||||
|
||||
$this->connectDispatcher();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -220,6 +220,10 @@ class TemplateLayout extends \OC_Template {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
/** @var InitialStateService $initialState */
|
||||
$initialState = \OC::$server->query(InitialStateService::class);
|
||||
$this->assign('initialStates', $initialState->getInitialStates());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
56
lib/public/IInitialStateService.php
Normal file
56
lib/public/IInitialStateService.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @since 16.0.0
|
||||
*/
|
||||
interface IInitialStateService {
|
||||
/**
|
||||
* Allows an app to provide its initial state to the template system.
|
||||
* Use this if you know your initial state sill be used for example if
|
||||
* you are in the render function of you controller.
|
||||
*
|
||||
* @since 16.0.0
|
||||
*
|
||||
* @param string $appName
|
||||
* @param bool|int|float|string|array|\JsonSerializable $data
|
||||
*/
|
||||
public function provideInitialState(string $appName, $data);
|
||||
|
||||
/**
|
||||
* Allows an app to provide its initial state via a lazy method.
|
||||
* This will call the closure when the template is being generated.
|
||||
* Use this if your app is injected into pages. Since then the render method
|
||||
* is not called explicitly. But we do not want to load the state on webdav
|
||||
* requests for example.
|
||||
*
|
||||
* @since 16.0.0
|
||||
*
|
||||
* @param string $appName
|
||||
* @param \Closure $closure Has to return an object that implements JsonSerializable
|
||||
*/
|
||||
public function provideLazyInitialState(string $appName, \Closure $closure);
|
||||
}
|
||||
Loading…
Reference in a new issue