Merge pull request #9830 from nextcloud/feature/noid/oauth_vue_redirect_validate

Migrate OAuth Admin settings to vue
This commit is contained in:
Morris Jobke 2018-06-19 14:50:03 +02:00 committed by GitHub
commit c3aea9cdf6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 6136 additions and 151 deletions

25
apps/oauth2/Makefile Normal file
View File

@ -0,0 +1,25 @@
all: dev-setup build-js-production
dev-setup: clean clean-dev npm-init
npm-init:
npm install
npm-update:
npm update
build-js:
npm run dev
build-js-production:
npm run build
watch-js:
npm run watch
clean:
rm -f js/oauth2.js
rm -f js/oauth2.map
clean-dev:
rm -rf node_modules

View File

@ -23,13 +23,18 @@ return [
'routes' => [ 'routes' => [
[ [
'name' => 'Settings#addClient', 'name' => 'Settings#addClient',
'url' => '/settings', 'url' => '/clients',
'verb' => 'POST', 'verb' => 'POST',
], ],
[
'name' => 'Settings#getClients',
'url' => '/clients',
'verb' => 'GET',
],
[ [
'name' => 'Settings#deleteClient', 'name' => 'Settings#deleteClient',
'url' => '/clients/{id}/delete', 'url' => '/clients/{id}',
'verb' => 'POST' 'verb' => 'DELETE'
], ],
[ [
'name' => 'LoginRedirector#authorize', 'name' => 'LoginRedirector#authorize',

View File

@ -3,3 +3,18 @@
opacity: 0.3; opacity: 0.3;
cursor: pointer; cursor: pointer;
} }
#oauth2 .icon-toggle,
#oauth2 .icon-delete {
display: inline-block;
width: 16px;
height: 16px;
padding: 10px;
vertical-align: middle;
}
#oauth2 .grid td code {
display: inline-block;
vertical-align: middle;
padding: 3px;
}

37
apps/oauth2/js/oauth2.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,15 +0,0 @@
$(document).ready(function () {
$('.show-oauth-credentials').click(function() {
var row = $(this).parent();
var code = $(row).find('code');
if(code.text() === '****') {
code.text(row.data('value'));
$(this).css('opacity', 0.9);
} else {
code.text('****');
$(this).css('opacity', 0.3);
}
})
});

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
* *
@ -26,14 +27,11 @@ use OCA\OAuth2\Db\AccessTokenMapper;
use OCA\OAuth2\Db\Client; use OCA\OAuth2\Db\Client;
use OCA\OAuth2\Db\ClientMapper; use OCA\OAuth2\Db\ClientMapper;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest; use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\Security\ISecureRandom; use OCP\Security\ISecureRandom;
class SettingsController extends Controller { class SettingsController extends Controller {
/** @var IURLGenerator */
private $urlGenerator;
/** @var ClientMapper */ /** @var ClientMapper */
private $clientMapper; private $clientMapper;
/** @var ISecureRandom */ /** @var ISecureRandom */
@ -48,53 +46,68 @@ class SettingsController extends Controller {
/** /**
* @param string $appName * @param string $appName
* @param IRequest $request * @param IRequest $request
* @param IURLGenerator $urlGenerator
* @param ClientMapper $clientMapper * @param ClientMapper $clientMapper
* @param ISecureRandom $secureRandom * @param ISecureRandom $secureRandom
* @param AccessTokenMapper $accessTokenMapper * @param AccessTokenMapper $accessTokenMapper
* @param DefaultTokenMapper $defaultTokenMapper * @param DefaultTokenMapper $defaultTokenMapper
*/ */
public function __construct($appName, public function __construct(string $appName,
IRequest $request, IRequest $request,
IURLGenerator $urlGenerator,
ClientMapper $clientMapper, ClientMapper $clientMapper,
ISecureRandom $secureRandom, ISecureRandom $secureRandom,
AccessTokenMapper $accessTokenMapper, AccessTokenMapper $accessTokenMapper,
DefaultTokenMapper $defaultTokenMapper DefaultTokenMapper $defaultTokenMapper
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
$this->urlGenerator = $urlGenerator;
$this->secureRandom = $secureRandom; $this->secureRandom = $secureRandom;
$this->clientMapper = $clientMapper; $this->clientMapper = $clientMapper;
$this->accessTokenMapper = $accessTokenMapper; $this->accessTokenMapper = $accessTokenMapper;
$this->defaultTokenMapper = $defaultTokenMapper; $this->defaultTokenMapper = $defaultTokenMapper;
} }
/** public function addClient(string $name,
* @param string $name string $redirectUri): JSONResponse {
* @param string $redirectUri
* @return RedirectResponse
*/
public function addClient($name,
$redirectUri) {
$client = new Client(); $client = new Client();
$client->setName($name); $client->setName($name);
$client->setRedirectUri($redirectUri); $client->setRedirectUri($redirectUri);
$client->setSecret($this->secureRandom->generate(64, self::validChars)); $client->setSecret($this->secureRandom->generate(64, self::validChars));
$client->setClientIdentifier($this->secureRandom->generate(64, self::validChars)); $client->setClientIdentifier($this->secureRandom->generate(64, self::validChars));
$this->clientMapper->insert($client); $client = $this->clientMapper->insert($client);
return new RedirectResponse($this->urlGenerator->getAbsoluteURL('/index.php/settings/admin/security'));
$result = [
'id' => $client->getId(),
'name' => $client->getName(),
'redirectUri' => $client->getRedirectUri(),
'clientId' => $client->getClientIdentifier(),
'clientSecret' => $client->getSecret(),
];
return new JSONResponse($result);
} }
/** public function deleteClient(int $id): JSONResponse {
* @param int $id
* @return RedirectResponse
*/
public function deleteClient($id) {
$client = $this->clientMapper->getByUid($id); $client = $this->clientMapper->getByUid($id);
$this->accessTokenMapper->deleteByClientId($id); $this->accessTokenMapper->deleteByClientId($id);
$this->defaultTokenMapper->deleteByName($client->getName()); $this->defaultTokenMapper->deleteByName($client->getName());
$this->clientMapper->delete($client); $this->clientMapper->delete($client);
return new RedirectResponse($this->urlGenerator->getAbsoluteURL('/index.php/settings/admin/security')); return new JSONResponse([]);
}
public function getClients(): JSONResponse {
$clients = $this->clientMapper->getClients();
$result = [];
foreach ($clients as $client) {
$result[] = [
'id' => $client->getId(),
'name' => $client->getName(),
'redirectUri' => $client->getRedirectUri(),
'clientId' => $client->getClientIdentifier(),
'clientSecret' => $client->getSecret(),
];
}
return new JSONResponse($result);
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
* *
@ -21,46 +22,25 @@
namespace OCA\OAuth2\Settings; namespace OCA\OAuth2\Settings;
use OCA\OAuth2\Db\ClientMapper;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
use OCP\Settings\ISettings; use OCP\Settings\ISettings;
class Admin implements ISettings { class Admin implements ISettings {
/** @var ClientMapper */
private $clientMapper;
/** public function getForm(): TemplateResponse {
* @param ClientMapper $clientMapper
*/
public function __construct(ClientMapper $clientMapper) {
$this->clientMapper = $clientMapper;
}
/**
* @return TemplateResponse
*/
public function getForm() {
return new TemplateResponse( return new TemplateResponse(
'oauth2', 'oauth2',
'admin', 'admin',
[ [],
'clients' => $this->clientMapper->getClients(),
],
'' ''
); );
} }
/** public function getSection(): string {
* {@inheritdoc}
*/
public function getSection() {
return 'security'; return 'security';
} }
/** public function getPriority(): int {
* {@inheritdoc}
*/
public function getPriority() {
return 0; return 0;
} }
} }

5650
apps/oauth2/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

31
apps/oauth2/package.json Normal file
View File

@ -0,0 +1,31 @@
{
"name": "oauth2",
"version": "1.0.0",
"description": "OAuth2 setup",
"author": "Roeland Jago Douma <roeland@famdouma.nl>",
"license": "AGPL-3.0-or-later",
"main": "init.js",
"directories": {
"lib": "lib",
"test": "tests"
},
"scripts": {
"dev": "webpack --config src/webpack.dev.js",
"watch": "webpack --progress --watch --config src/webpack.dev.js",
"build": "webpack --progress --hide-modules --config src/webpack.prod.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"axios": "^0.18.0",
"vue": "^2.5.16"
},
"devDependencies": {
"css-loader": "^0.28.11",
"file-loader": "^1.1.11",
"vue-loader": "^15.2.4",
"vue-template-compiler": "^2.5.16",
"webpack": "^4.11.1",
"webpack-cli": "^3.0.3",
"webpack-merge": "^4.1.2"
}
}

113
apps/oauth2/src/App.vue Normal file
View File

@ -0,0 +1,113 @@
<!--
- @copyright Copyright (c) 2018 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/>.
-
-->
<template>
<div id="oauth2" class="section">
<h2>{{ t('oauth2', 'OAuth 2.0 clients') }}</h2>
<p class="settings-hint">{{ t('oauth2', 'OAuth 2.0 allows external services to request access to {instanceName}.', { instanceName: oc_defaults.name}) }}</p>
<table class="grid">
<thead>
<tr>
<th id="headerName" scope="col">{{ t('oauth2', 'Name') }}</th>
<th id="headerRedirectUri" scope="col">{{ t('oauth2', 'Redirection URI') }}</th>
<th id="headerClientIdentifier" scope="col">{{ t('oauth2', 'Client Identifier') }}</th>
<th id="headerSecret" scope="col">{{ t('oauth2', 'Secret') }}</th>
<th id="headerRemove">&nbsp;</th>
</tr>
</thead>
<tbody>
<OAuthItem v-for="client in clients"
:key="client.id"
:client="client"
@delete="deleteClient"
/>
</tbody>
</table>
<br/>
<h3>{{ t('oauth2', 'Add client') }}</h3>
<form @submit.prevent="addClient">
<input type="text" id="name" name="name" :placeholder="t('oauth2', 'Name')" v-model="newClient.name">
<input type="url" id="redirectUri" name="redirectUri" :placeholder="t('oauth2', 'Redirection URI')" v-model="newClient.redirectUri">
<input type="submit" class="button" :value="t('oauth2', 'Add')">
</form>
</div>
</template>
<script>
import axios from 'axios';
import OAuthItem from './components/OAuthItem';
export default {
name: 'App',
components: {
OAuthItem
},
data: function() {
return {
clients: [],
newClient: {
name: '',
redirectUri: ''
}
};
},
beforeMount: function() {
let requestToken = OC.requestToken;
let tokenHeaders = { headers: { requesttoken: requestToken } };
axios.get(OC.generateUrl('apps/oauth2/clients'), tokenHeaders)
.then((response) => {
this.clients = response.data;
});
},
methods: {
deleteClient(id) {
let requestToken = OC.requestToken;
let tokenHeaders = { headers: { requesttoken: requestToken } };
axios.delete(OC.generateUrl('apps/oauth2/clients/{id}', {id: id}), tokenHeaders)
.then((response) => {
this.clients = this.clients.filter(client => client.id !== id);
});
},
addClient() {
let requestToken = OC.requestToken;
let tokenHeaders = { headers: { requesttoken: requestToken } };
axios.post(
OC.generateUrl('apps/oauth2/clients'),
{
name: this.newClient.name,
redirectUri: this.newClient.redirectUri
},
tokenHeaders)
.then((response) => {
this.clients.push(response.data)
this.newClient.name = '';
this.newClient.redirectUri = '';
}
);
}
},
}
</script>

View File

@ -0,0 +1,66 @@
<!--
- @copyright Copyright (c) 2018 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/>.
-
-->
<template>
<tr>
<td>{{name}}</td>
<td>{{redirectUri}}</td>
<td><code>{{clientId}}</code></td>
<td><code>{{renderedSecret}}</code><a class='icon-toggle has-tooltip' :title="t('oauth2', 'Show client secret')" @click="toggleSecret"></a></td>
<td class="action-column"><span><a class="icon-delete has-tooltip" :title="t('oauth2', 'Delete')" @click="$emit('delete', id)"></a></span></td>
</tr>
</template>
<script>
export default {
name: 'OAuthItem',
props: {
client: {
type: Object,
required: true
}
},
data: function() {
return {
id: this.client.id,
name: this.client.name,
redirectUri: this.client.redirectUri,
clientId: this.client.clientId,
clientSecret: this.client.clientSecret,
renderSecret: false,
};
},
computed: {
renderedSecret: function() {
if (this.renderSecret) {
return this.clientSecret;
} else {
return '****';
}
}
},
methods: {
toggleSecret() {
this.renderSecret = !this.renderSecret;
}
}
}
</script>

35
apps/oauth2/src/main.js Normal file
View File

@ -0,0 +1,35 @@
/**
* @copyright Copyright (c) 2018 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/>.
*
*/
import Vue from 'vue';
import App from './App.vue';
Vue.prototype.t = t;
Vue.prototype.oc_defaults = oc_defaults;
Vue.prototype.OC = OC;
const app = new Vue({
render: h => h(App)
}).$mount('#oauth2');
export { app };

View File

@ -0,0 +1,28 @@
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
entry: path.join(__dirname, 'main.js'),
output: {
path: path.resolve(__dirname, '../js'),
publicPath: '/js',
filename: 'oauth2.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
}
]
},
plugins: [
new VueLoaderPlugin()
],
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
}
}

View File

@ -0,0 +1,12 @@
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
devtool: '#eval-source-map',
})

View File

@ -0,0 +1,7 @@
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'production',
devtool: '#source-map'
})

View File

@ -19,58 +19,9 @@
* *
*/ */
$urlGenerator = \OC::$server->getURLGenerator(); script('oauth2', 'oauth2');
$themingDefaults = \OC::$server->getThemingDefaults();
script('oauth2', 'setting-admin');
style('oauth2', 'setting-admin'); style('oauth2', 'setting-admin');
/** @var array $_ */
/** @var \OCA\OAuth2\Db\Client[] $clients */
$clients = $_['clients'];
?> ?>
<div id="oauth2" class="section"> <div id="oauth2"></div>
<h2><?php p($l->t('OAuth 2.0 clients')); ?></h2>
<p class="settings-hint"><?php p($l->t('OAuth 2.0 allows external services to request access to %s.', [$themingDefaults->getName()])); ?></p>
<table class="grid">
<thead>
<tr>
<th id="headerName" scope="col"><?php p($l->t('Name')); ?></th>
<th id="headerRedirectUri" scope="col"><?php p($l->t('Redirection URI')); ?></th>
<th id="headerClientIdentifier" scope="col"><?php p($l->t('Client Identifier')); ?></th>
<th id="headerSecret" scope="col"><?php p($l->t('Secret')); ?></th>
<th id="headerRemove">&nbsp;</th>
</tr>
</thead>
<tbody>
<?php
$imageUrl = $urlGenerator->imagePath('core', 'actions/toggle.svg');
foreach ($clients as $client) {
?>
<tr>
<td><?php p($client->getName()); ?></td>
<td><?php p($client->getRedirectUri()); ?></td>
<td><code><?php p($client->getClientIdentifier()); ?></code></td>
<td data-value="<?php p($client->getSecret()); ?>"><code>****</code><img class='show-oauth-credentials' src="<?php p($imageUrl); ?>"/></td>
<td>
<form id="form-inline" class="delete" action="<?php p($urlGenerator->linkToRoute('oauth2.Settings.deleteClient', ['id' => $client->getId()])); ?>" method="POST">
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="submit" class="button icon-delete" value="">
</form>
</td>
</tr>
<?php } ?>
</tbody>
</table>
<br/>
<h3><?php p($l->t('Add client')); ?></h3>
<form action="<?php p($urlGenerator->linkToRoute('oauth2.Settings.addClient')); ?>" method="POST">
<input type="text" id="name" name="name" placeholder="<?php p($l->t('Name')); ?>">
<input type="url" id="redirectUri" name="redirectUri" placeholder="<?php p($l->t('Redirection URI')); ?>">
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="submit" class="button" value="<?php p($l->t('Add')); ?>">
</form>
</div>

View File

@ -26,17 +26,14 @@ use OCA\OAuth2\Controller\SettingsController;
use OCA\OAuth2\Db\AccessTokenMapper; use OCA\OAuth2\Db\AccessTokenMapper;
use OCA\OAuth2\Db\Client; use OCA\OAuth2\Db\Client;
use OCA\OAuth2\Db\ClientMapper; use OCA\OAuth2\Db\ClientMapper;
use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest; use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\Security\ISecureRandom; use OCP\Security\ISecureRandom;
use Test\TestCase; use Test\TestCase;
class SettingsControllerTest extends TestCase { class SettingsControllerTest extends TestCase {
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
private $request; private $request;
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
private $urlGenerator;
/** @var ClientMapper|\PHPUnit_Framework_MockObject_MockObject */ /** @var ClientMapper|\PHPUnit_Framework_MockObject_MockObject */
private $clientMapper; private $clientMapper;
/** @var ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */ /** @var ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */
@ -52,7 +49,6 @@ class SettingsControllerTest extends TestCase {
parent::setUp(); parent::setUp();
$this->request = $this->createMock(IRequest::class); $this->request = $this->createMock(IRequest::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->clientMapper = $this->createMock(ClientMapper::class); $this->clientMapper = $this->createMock(ClientMapper::class);
$this->secureRandom = $this->createMock(ISecureRandom::class); $this->secureRandom = $this->createMock(ISecureRandom::class);
$this->accessTokenMapper = $this->createMock(AccessTokenMapper::class); $this->accessTokenMapper = $this->createMock(AccessTokenMapper::class);
@ -61,7 +57,6 @@ class SettingsControllerTest extends TestCase {
$this->settingsController = new SettingsController( $this->settingsController = new SettingsController(
'oauth2', 'oauth2',
$this->request, $this->request,
$this->urlGenerator,
$this->clientMapper, $this->clientMapper,
$this->secureRandom, $this->secureRandom,
$this->accessTokenMapper, $this->accessTokenMapper,
@ -90,27 +85,39 @@ class SettingsControllerTest extends TestCase {
$this->clientMapper $this->clientMapper
->expects($this->once()) ->expects($this->once())
->method('insert') ->method('insert')
->with($client); ->with($this->callback(function (Client $c) {
return $c->getName() === 'My Client Name' &&
$c->getRedirectUri() === 'https://example.com/' &&
$c->getSecret() === 'MySecret' &&
$c->getClientIdentifier() === 'MyClientIdentifier';
}))->will($this->returnCallback(function (Client $c) {
$c->setId(42);
return $c;
}));
$this->urlGenerator $result = $this->settingsController->addClient('My Client Name', 'https://example.com/');
->expects($this->once()) $this->assertInstanceOf(JSONResponse::class, $result);
->method('getAbsoluteURL')
->with('/index.php/settings/admin/security')
->willReturn('https://example.com/index.php/settings/admin/security');
$expected = new RedirectResponse('https://example.com/index.php/settings/admin/security'); $data = $result->getData();
$this->assertEquals($expected, $this->settingsController->addClient('My Client Name', 'https://example.com/'));
$this->assertEquals([
'id' => 42,
'name' => 'My Client Name',
'redirectUri' => 'https://example.com/',
'clientId' => 'MyClientIdentifier',
'clientSecret' => 'MySecret',
], $data);
} }
public function testDeleteClient() { public function testDeleteClient() {
$client = new Client(); $client = new Client();
$client->setId(123);
$client->setName('My Client Name'); $client->setName('My Client Name');
$client->setRedirectUri('https://example.com/'); $client->setRedirectUri('https://example.com/');
$client->setSecret('MySecret'); $client->setSecret('MySecret');
$client->setClientIdentifier('MyClientIdentifier'); $client->setClientIdentifier('MyClientIdentifier');
$this->clientMapper $this->clientMapper
->expects($this->at(0))
->method('getByUid') ->method('getByUid')
->with(123) ->with(123)
->willReturn($client); ->willReturn($client);
@ -123,17 +130,52 @@ class SettingsControllerTest extends TestCase {
->method('deleteByName') ->method('deleteByName')
->with('My Client Name'); ->with('My Client Name');
$this->clientMapper $this->clientMapper
->expects($this->at(1))
->method('delete') ->method('delete')
->with($client); ->with($client);
$this->urlGenerator $result = $this->settingsController->deleteClient(123);
->expects($this->once()) $this->assertInstanceOf(JSONResponse::class, $result);
->method('getAbsoluteURL') $this->assertEquals([], $result->getData());
->with('/index.php/settings/admin/security') }
->willReturn('https://example.com/index.php/settings/admin/security');
$expected = new RedirectResponse('https://example.com/index.php/settings/admin/security'); public function testGetClients() {
$this->assertEquals($expected, $this->settingsController->deleteClient(123)); $client1 = new Client();
$client1->setId(123);
$client1->setName('My Client Name');
$client1->setRedirectUri('https://example.com/');
$client1->setSecret('MySecret');
$client1->setClientIdentifier('MyClientIdentifier');
$client2 = new Client();
$client2->setId(42);
$client2->setName('My Client Name2');
$client2->setRedirectUri('https://example.com/2');
$client2->setSecret('MySecret2');
$client2->setClientIdentifier('MyClientIdentifier2');
$this->clientMapper->method('getClients')
->willReturn([$client1, $client2]);
$result = $this->settingsController->getClients();
$this->assertInstanceOf(JSONResponse::class, $result);
$data = $result->getData();
$this->assertSame([
[
'id' => 123,
'name' => 'My Client Name',
'redirectUri' => 'https://example.com/',
'clientId' => 'MyClientIdentifier',
'clientSecret' => 'MySecret',
],
[
'id' => 42,
'name' => 'My Client Name2',
'redirectUri' => 'https://example.com/2',
'clientId' => 'MyClientIdentifier2',
'clientSecret' => 'MySecret2',
],
], $data);
} }
} }

View File

@ -21,35 +21,25 @@
namespace OCA\OAuth2\Tests\Settings; namespace OCA\OAuth2\Tests\Settings;
use OCA\OAuth2\Db\ClientMapper;
use OCA\OAuth2\Settings\Admin; use OCA\OAuth2\Settings\Admin;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
use Test\TestCase; use Test\TestCase;
class AdminTest extends TestCase { class AdminTest extends TestCase {
/** @var ClientMapper|\PHPUnit_Framework_MockObject_MockObject */
private $clientMapper;
/** @var Admin|\PHPUnit_Framework_MockObject_MockObject */ /** @var Admin|\PHPUnit_Framework_MockObject_MockObject */
private $admin; private $admin;
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
$this->clientMapper = $this->createMock(ClientMapper::class); $this->admin = new Admin();
$this->admin = new Admin($this->clientMapper);
} }
public function testGetForm() { public function testGetForm() {
$this->clientMapper
->expects($this->once())
->method('getClients')
->willReturn(['MyClients']);
$expected = new TemplateResponse( $expected = new TemplateResponse(
'oauth2', 'oauth2',
'admin', 'admin',
[ [
'clients' => ['MyClients'],
], ],
'' ''
); );