diff options
author | Joas Schilling <coding@schilljs.com> | 2016-10-25 10:57:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-25 10:57:48 +0200 |
commit | 890f752a6b57598ee6b2088a615c41f60d697847 (patch) | |
tree | 191c38b854d23f34a285b6fab711c82b2d5ed1f7 | |
parent | 79706e0ddc6ab970d5709e89b8d0caec4d34662b (diff) | |
parent | 2aca56f207048e6dff44983fe4cd7af834e70b42 (diff) | |
download | nextcloud-server-890f752a6b57598ee6b2088a615c41f60d697847.tar.gz nextcloud-server-890f752a6b57598ee6b2088a615c41f60d697847.zip |
Merge pull request #1452 from nextcloud/appconfig-endpoint
Appconfig endpoint
-rw-r--r-- | apps/federatedfilesharing/js/settings-admin.js | 2 | ||||
-rw-r--r-- | apps/files_external/js/settings.js | 6 | ||||
-rw-r--r-- | apps/provisioning_api/appinfo/routes.php | 17 | ||||
-rw-r--r-- | apps/provisioning_api/lib/Controller/AppConfigController.php | 157 | ||||
-rw-r--r-- | apps/provisioning_api/tests/Controller/AppConfigControllerTest.php | 382 | ||||
-rw-r--r-- | apps/updatenotification/js/admin.js | 2 | ||||
-rw-r--r-- | core/ajax/appconfig.php | 70 | ||||
-rw-r--r-- | core/js/config.js | 94 | ||||
-rw-r--r-- | core/js/core.json | 1 | ||||
-rw-r--r-- | core/js/js.js | 3 | ||||
-rw-r--r-- | core/js/public/appconfig.js | 113 | ||||
-rw-r--r-- | core/routes.php | 3 | ||||
-rw-r--r-- | core/shipped.json | 1 | ||||
-rw-r--r-- | lib/private/legacy/template.php | 1 | ||||
-rw-r--r-- | settings/js/admin.js | 41 | ||||
-rw-r--r-- | settings/js/users/users.js | 20 | ||||
-rw-r--r-- | tests/lib/App/ManagerTest.php | 14 | ||||
-rw-r--r-- | tests/lib/AppTest.php | 9 |
18 files changed, 775 insertions, 161 deletions
diff --git a/apps/federatedfilesharing/js/settings-admin.js b/apps/federatedfilesharing/js/settings-admin.js index 257c864b04f..a0b8feb945e 100644 --- a/apps/federatedfilesharing/js/settings-admin.js +++ b/apps/federatedfilesharing/js/settings-admin.js @@ -5,7 +5,7 @@ $(document).ready(function() { if (this.checked) { value = 'yes'; } - OC.AppConfig.setValue('files_sharing', $(this).attr('name'), value); + OCP.AppConfig.setValue('files_sharing', $(this).attr('name'), value); }); }); diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index da3e2397b7e..0270b7a6957 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -1317,12 +1317,12 @@ $(document).ready(function() { $allowUserMounting.bind('change', function() { OC.msg.startSaving('#userMountingMsg'); if (this.checked) { - OC.AppConfig.setValue('files_external', 'allow_user_mounting', 'yes'); + OCP.AppConfig.setValue('files_external', 'allow_user_mounting', 'yes'); $('input[name="allowUserMountingBackends\\[\\]"]').prop('checked', true); $('#userMountingBackends').removeClass('hidden'); $('input[name="allowUserMountingBackends\\[\\]"]').eq(0).trigger('change'); } else { - OC.AppConfig.setValue('files_external', 'allow_user_mounting', 'no'); + OCP.AppConfig.setValue('files_external', 'allow_user_mounting', 'no'); $('#userMountingBackends').addClass('hidden'); } OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}}); @@ -1342,7 +1342,7 @@ $(document).ready(function() { }).get(); userMountingBackends = userMountingBackends.concat(deprecatedBackends); - OC.AppConfig.setValue('files_external', 'user_mounting_backends', userMountingBackends.join()); + OCP.AppConfig.setValue('files_external', 'user_mounting_backends', userMountingBackends.join()); OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}}); // disable allowUserMounting diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php index a7366a32a06..04a34fba903 100644 --- a/apps/provisioning_api/appinfo/routes.php +++ b/apps/provisioning_api/appinfo/routes.php @@ -26,12 +26,7 @@ * */ -use OCA\Provisioning_API\Apps; -use OCA\Provisioning_API\Users; -use OCP\API; - -$app = new \OCA\Provisioning_API\AppInfo\Application(); -$app->registerRoutes($this, [ +return [ 'ocs' => [ // Apps ['root' => '/cloud', 'name' => 'Apps#getApps', 'url' => '/apps', 'verb' => 'GET'], @@ -46,7 +41,7 @@ $app->registerRoutes($this, [ ['root' => '/cloud', 'name' => 'Groups#deleteGroup', 'url' => '/groups/{groupId}', 'verb' => 'DELETE'], ['root' => '/cloud', 'name' => 'Groups#getSubAdminsOfGroup', 'url' => '/groups/{groupId}/subadmins', 'verb' => 'GET'], - //Users + // Users ['root' => '/cloud', 'name' => 'Users#getUsers', 'url' => '/users', 'verb' => 'GET'], ['root' => '/cloud', 'name' => 'Users#addUser', 'url' => '/users', 'verb' => 'POST'], ['root' => '/cloud', 'name' => 'Users#getUser', 'url' => '/users/{userId}', 'verb' => 'GET'], @@ -61,5 +56,11 @@ $app->registerRoutes($this, [ ['root' => '/cloud', 'name' => 'Users#addSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'POST'], ['root' => '/cloud', 'name' => 'Users#removeSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'DELETE'], + // Config + ['name' => 'AppConfig#getApps', 'url' => '/api/v1/config/apps', 'verb' => 'GET'], + ['name' => 'AppConfig#getKeys', 'url' => '/api/v1/config/apps/{app}', 'verb' => 'GET'], + ['name' => 'AppConfig#getValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'GET'], + ['name' => 'AppConfig#setValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'POST'], + ['name' => 'AppConfig#deleteKey', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'DELETE'], ], -]); +]; diff --git a/apps/provisioning_api/lib/Controller/AppConfigController.php b/apps/provisioning_api/lib/Controller/AppConfigController.php new file mode 100644 index 00000000000..f710eda6529 --- /dev/null +++ b/apps/provisioning_api/lib/Controller/AppConfigController.php @@ -0,0 +1,157 @@ +<?php +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @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 OCA\Provisioning_API\Controller; + + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\IRequest; + +class AppConfigController extends OCSController { + + /** @var IConfig */ + protected $config; + + /** @var IAppConfig */ + protected $appConfig; + + /** + * @param string $appName + * @param IRequest $request + * @param IConfig $config + * @param IAppConfig $appConfig + */ + public function __construct($appName, + IRequest $request, + IConfig $config, + IAppConfig $appConfig) { + parent::__construct($appName, $request); + $this->config = $config; + $this->appConfig = $appConfig; + } + + /** + * @return DataResponse + */ + public function getApps() { + return new DataResponse([ + 'data' => $this->appConfig->getApps(), + ]); + } + + /** + * @param string $app + * @return DataResponse + */ + public function getKeys($app) { + try { + $this->verifyAppId($app); + } catch (\InvalidArgumentException $e) { + return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN); + } + return new DataResponse([ + 'data' => $this->config->getAppKeys($app), + ]); + } + + /** + * @param string $app + * @param string $key + * @param string $defaultValue + * @return DataResponse + */ + public function getValue($app, $key, $defaultValue = '') { + try { + $this->verifyAppId($app); + } catch (\InvalidArgumentException $e) { + return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN); + } + return new DataResponse([ + 'data' => $this->config->getAppValue($app, $key, $defaultValue), + ]); + } + + /** + * @PasswordConfirmationRequired + * @param string $app + * @param string $key + * @param string $value + * @return DataResponse + */ + public function setValue($app, $key, $value) { + try { + $this->verifyAppId($app); + $this->verifyConfigKey($app, $key); + } catch (\InvalidArgumentException $e) { + return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN); + } + + $this->config->setAppValue($app, $key, $value); + return new DataResponse(); + } + + /** + * @PasswordConfirmationRequired + * @param string $app + * @param string $key + * @return DataResponse + */ + public function deleteKey($app, $key) { + try { + $this->verifyAppId($app); + $this->verifyConfigKey($app, $key); + } catch (\InvalidArgumentException $e) { + return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN); + } + + $this->config->deleteAppValue($app, $key); + return new DataResponse(); + } + + /** + * @param string $app + * @throws \InvalidArgumentException + */ + protected function verifyAppId($app) { + if (\OC_App::cleanAppId($app) !== $app) { + throw new \InvalidArgumentException('Invalid app id given'); + } + } + + /** + * @param string $app + * @param string $key + * @throws \InvalidArgumentException + */ + protected function verifyConfigKey($app, $key) { + if (in_array($key, ['installed_version', 'enabled', 'types'])) { + throw new \InvalidArgumentException('The given key can not be set'); + } + + if ($app === 'core' && (strpos($key, 'public_') === 0 || strpos($key, 'remote_') === 0)) { + throw new \InvalidArgumentException('The given key can not be set'); + } + } +} diff --git a/apps/provisioning_api/tests/Controller/AppConfigControllerTest.php b/apps/provisioning_api/tests/Controller/AppConfigControllerTest.php new file mode 100644 index 00000000000..b7cb76c77c6 --- /dev/null +++ b/apps/provisioning_api/tests/Controller/AppConfigControllerTest.php @@ -0,0 +1,382 @@ +<?php +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @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 OCA\Provisioning_API\Tests\Controller; + + +use OCA\Provisioning_API\Controller\AppConfigController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\IRequest; +use Test\TestCase; + +/** + * Class AppConfigControllerTest + * + * @package OCA\Provisioning_API\Tests + */ +class AppConfigControllerTest extends TestCase { + + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $config; + /** @var IAppConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $appConfig; + + protected function setUp() { + parent::setUp(); + + $this->config = $this->createMock(IConfig::class); + $this->appConfig = $this->createMock(IAppConfig::class); + + } + + /** + * @param string[] $methods + * @return AppConfigController|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getInstance(array $methods = []) { + $request = $this->createMock(IRequest::class); + + if (empty($methods)) { + return new AppConfigController( + 'provisioning_api', + $request, + $this->config, + $this->appConfig + ); + } else { + return $this->getMockBuilder(AppConfigController::class) + ->setConstructorArgs([ + 'provisioning_api', + $request, + $this->config, + $this->appConfig, + ]) + ->setMethods($methods) + ->getMock(); + } + } + + public function testGetApps() { + $this->appConfig->expects($this->once()) + ->method('getApps') + ->willReturn(['apps']); + + $result = $this->getInstance()->getApps(); + $this->assertInstanceOf(DataResponse::class, $result); + $this->assertSame(Http::STATUS_OK, $result->getStatus()); + $this->assertEquals(['data' => ['apps']], $result->getData()); + } + + public function dataGetKeys() { + return [ + ['app1 ', null, new \InvalidArgumentException('error'), Http::STATUS_FORBIDDEN], + ['app2', ['keys'], null, Http::STATUS_OK], + ]; + } + + /** + * @dataProvider dataGetKeys + * @param string $app + * @param array|null $keys + * @param \Exception|null $throws + * @param int $status + */ + public function testGetKeys($app, $keys, $throws, $status) { + + $api = $this->getInstance(['verifyAppId']); + if ($throws instanceof \Exception) { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app) + ->willThrowException($throws); + + $this->config->expects($this->never()) + ->method('getAppKeys'); + } else { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app); + + $this->config->expects($this->once()) + ->method('getAppKeys') + ->with($app) + ->willReturn($keys); + } + + $result = $api->getKeys($app); + $this->assertInstanceOf(DataResponse::class, $result); + $this->assertSame($status, $result->getStatus()); + if ($throws instanceof \Exception) { + $this->assertEquals(['data' => ['message' => $throws->getMessage()]], $result->getData()); + } else { + $this->assertEquals(['data' => $keys], $result->getData()); + } + } + + public function dataGetValue() { + return [ + ['app1 ', null, null, null, new \InvalidArgumentException('error'), Http::STATUS_FORBIDDEN], + ['app2', 'key', 'default', 'return', null, Http::STATUS_OK], + ]; + } + + /** + * @dataProvider dataGetValue + * @param string $app + * @param string|null $key + * @param string|null $default + * @param string|null $return + * @param \Exception|null $throws + * @param int $status + */ + public function testGetValue($app, $key, $default, $return, $throws, $status) { + + $api = $this->getInstance(['verifyAppId']); + if ($throws instanceof \Exception) { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app) + ->willThrowException($throws); + + $this->config->expects($this->never()) + ->method('getAppValue'); + } else { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app); + + $this->config->expects($this->once()) + ->method('getAppValue') + ->with($app, $key, $default) + ->willReturn($return); + } + + $result = $api->getValue($app, $key, $default); + $this->assertInstanceOf(DataResponse::class, $result); + $this->assertSame($status, $result->getStatus()); + if ($throws instanceof \Exception) { + $this->assertEquals(['data' => ['message' => $throws->getMessage()]], $result->getData()); + } else { + $this->assertEquals(['data' => $return], $result->getData()); + } + } + + public function dataSetValue() { + return [ + ['app1 ', null, null, new \InvalidArgumentException('error1'), null, Http::STATUS_FORBIDDEN], + ['app2', 'key', null, null, new \InvalidArgumentException('error2'), Http::STATUS_FORBIDDEN], + ['app2', 'key', 'default', null, null, Http::STATUS_OK], + ]; + } + + /** + * @dataProvider dataSetValue + * @param string $app + * @param string|null $key + * @param string|null $value + * @param \Exception|null $appThrows + * @param \Exception|null $keyThrows + * @param int $status + */ + public function testSetValue($app, $key, $value, $appThrows, $keyThrows, $status) { + + $api = $this->getInstance(['verifyAppId', 'verifyConfigKey']); + if ($appThrows instanceof \Exception) { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app) + ->willThrowException($appThrows); + + $api->expects($this->never()) + ->method('verifyConfigKey'); + $this->config->expects($this->never()) + ->method('setAppValue'); + } else if ($keyThrows instanceof \Exception) { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app); + $api->expects($this->once()) + ->method('verifyConfigKey') + ->with($app, $key) + ->willThrowException($keyThrows); + + $this->config->expects($this->never()) + ->method('setAppValue'); + } else { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app); + $api->expects($this->once()) + ->method('verifyConfigKey') + ->with($app, $key); + + $this->config->expects($this->once()) + ->method('setAppValue') + ->with($app, $key, $value); + } + + $result = $api->setValue($app, $key, $value); + $this->assertInstanceOf(DataResponse::class, $result); + $this->assertSame($status, $result->getStatus()); + if ($appThrows instanceof \Exception) { + $this->assertEquals(['data' => ['message' => $appThrows->getMessage()]], $result->getData()); + } else if ($keyThrows instanceof \Exception) { + $this->assertEquals(['data' => ['message' => $keyThrows->getMessage()]], $result->getData()); + } else { + $this->assertEquals([], $result->getData()); + } + } + + public function dataDeleteValue() { + return [ + ['app1 ', null, new \InvalidArgumentException('error1'), null, Http::STATUS_FORBIDDEN], + ['app2', 'key', null, new \InvalidArgumentException('error2'), Http::STATUS_FORBIDDEN], + ['app2', 'key', null, null, Http::STATUS_OK], + ]; + } + + /** + * @dataProvider dataDeleteValue + * @param string $app + * @param string|null $key + * @param \Exception|null $appThrows + * @param \Exception|null $keyThrows + * @param int $status + */ + public function testDeleteValue($app, $key, $appThrows, $keyThrows, $status) { + + $api = $this->getInstance(['verifyAppId', 'verifyConfigKey']); + if ($appThrows instanceof \Exception) { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app) + ->willThrowException($appThrows); + + $api->expects($this->never()) + ->method('verifyConfigKey'); + $this->config->expects($this->never()) + ->method('deleteAppValue'); + } else if ($keyThrows instanceof \Exception) { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app); + $api->expects($this->once()) + ->method('verifyConfigKey') + ->with($app, $key) + ->willThrowException($keyThrows); + + $this->config->expects($this->never()) + ->method('deleteAppValue'); + } else { + $api->expects($this->once()) + ->method('verifyAppId') + ->with($app); + $api->expects($this->once()) + ->method('verifyConfigKey') + ->with($app, $key); + + $this->config->expects($this->once()) + ->method('deleteAppValue') + ->with($app, $key); + } + + $result = $api->deleteKey($app, $key); + $this->assertInstanceOf(DataResponse::class, $result); + $this->assertSame($status, $result->getStatus()); + if ($appThrows instanceof \Exception) { + $this->assertEquals(['data' => ['message' => $appThrows->getMessage()]], $result->getData()); + } else if ($keyThrows instanceof \Exception) { + $this->assertEquals(['data' => ['message' => $keyThrows->getMessage()]], $result->getData()); + } else { + $this->assertEquals([], $result->getData()); + } + } + + public function testVerifyAppId() { + $api = $this->getInstance(); + $this->invokePrivate($api, 'verifyAppId', ['activity']); + $this->assertTrue(true); + } + + public function dataVerifyAppIdThrows() { + return [ + ['activity..'], + ['activity/'], + ['activity\\'], + ['activity\0'], + ]; + } + + /** + * @dataProvider dataVerifyAppIdThrows + * @expectedException \InvalidArgumentException + * @param string $app + */ + public function testVerifyAppIdThrows($app) { + $api = $this->getInstance(); + $this->invokePrivate($api, 'verifyAppId', [$app]); + } + + public function dataVerifyConfigKey() { + return [ + ['activity', 'abc'], + ['dav', 'public_route'], + ['files', 'remote_route'], + ]; + } + + /** + * @dataProvider dataVerifyConfigKey + * @param string $app + * @param string $key + */ + public function testVerifyConfigKey($app, $key) { + $api = $this->getInstance(); + $this->invokePrivate($api, 'verifyConfigKey', [$app, $key]); + $this->assertTrue(true); + } + + public function dataVerifyConfigKeyThrows() { + return [ + ['activity', 'installed_version'], + ['calendar', 'enabled'], + ['contacts', 'types'], + ['core', 'public_files'], + ['core', 'public_dav'], + ['core', 'remote_files'], + ['core', 'remote_dav'], + ]; + } + + /** + * @dataProvider dataVerifyConfigKeyThrows + * @expectedException \InvalidArgumentException + * @param string $app + * @param string $key + */ + public function testVerifyConfigKeyThrows($app, $key) { + $api = $this->getInstance(); + $this->invokePrivate($api, 'verifyConfigKey', [$app, $key]); + } +} diff --git a/apps/updatenotification/js/admin.js b/apps/updatenotification/js/admin.js index 91d9f80b605..813ec48c87a 100644 --- a/apps/updatenotification/js/admin.js +++ b/apps/updatenotification/js/admin.js @@ -70,6 +70,6 @@ $(document).ready(function(){ $notificationTargetGroups.change(function(ev) { var groups = ev.val || []; groups = JSON.stringify(groups); - OC.AppConfig.setValue('updatenotification', 'notify_groups', groups); + OCP.AppConfig.setValue('updatenotification', 'notify_groups', groups); }); }); diff --git a/core/ajax/appconfig.php b/core/ajax/appconfig.php deleted file mode 100644 index 6bb70e4c393..00000000000 --- a/core/ajax/appconfig.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -OC_Util::checkAdminUser(); -OCP\JSON::callCheck(); - -$action=isset($_POST['action'])?$_POST['action']:$_GET['action']; - -if(isset($_POST['app']) || isset($_GET['app'])) { - $app=OC_App::cleanAppId(isset($_POST['app'])? (string)$_POST['app']: (string)$_GET['app']); -} - -// An admin should not be able to add remote and public services -// on its own. This should only be possible programmatically. -// This change is due the fact that an admin may not be expected -// to execute arbitrary code in every environment. -if($app === 'core' && isset($_POST['key']) &&(substr((string)$_POST['key'],0,7) === 'remote_' || substr((string)$_POST['key'],0,7) === 'public_')) { - OC_JSON::error(array('data' => array('message' => 'Unexpected error!'))); - return; -} - -$result=false; -$appConfig = \OC::$server->getAppConfig(); -switch($action) { - case 'getValue': - $result=$appConfig->getValue($app, (string)$_GET['key'], (string)$_GET['defaultValue']); - break; - case 'setValue': - $result=$appConfig->setValue($app, (string)$_POST['key'], (string)$_POST['value']); - break; - case 'getApps': - $result=$appConfig->getApps(); - break; - case 'getKeys': - $result=$appConfig->getKeys($app); - break; - case 'hasKey': - $result=$appConfig->hasKey($app, (string)$_GET['key']); - break; - case 'deleteKey': - $result=$appConfig->deleteKey($app, (string)$_POST['key']); - break; - case 'deleteApp': - $result=$appConfig->deleteApp($app); - break; -} -OC_JSON::success(array('data'=>$result)); - diff --git a/core/js/config.js b/core/js/config.js index b034b7e8cd3..7dc742f7567 100644 --- a/core/js/config.js +++ b/core/js/config.js @@ -1,58 +1,80 @@ /** - * Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com> - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @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 + * @deprecated Use OCP.AppConfig instead */ OC.AppConfig={ - url:OC.filePath('core','ajax','appconfig.php'), - getCall:function(action,data,callback){ - data.action=action; - $.getJSON(OC.AppConfig.url,data,function(result){ - if(result.status==='success'){ - if(callback){ - callback(result.data); - } - } - }); - }, - postCall:function(action,data,callback){ - data.action=action; - $.post(OC.AppConfig.url,data,function(result){ - if(result.status==='success'){ - if(callback){ - callback(result.data); - } - } - },'json'); - }, + /** + * @deprecated Use OCP.AppConfig.getValue() instead + */ getValue:function(app,key,defaultValue,callback){ - if(typeof defaultValue=='function'){ - callback=defaultValue; - defaultValue=null; - } - OC.AppConfig.getCall('getValue',{app:app,key:key,defaultValue:defaultValue},callback); + OCP.AppConfig.getValue(app, key, defaultValue, { + success: callback + }); }, + + /** + * @deprecated Use OCP.AppConfig.setValue() instead + */ setValue:function(app,key,value){ - OC.AppConfig.postCall('setValue',{app:app,key:key,value:value}); + OCP.AppConfig.setValue(app, key, value); }, + + /** + * @deprecated Use OCP.AppConfig.getApps() instead + */ getApps:function(callback){ - OC.AppConfig.getCall('getApps',{},callback); + OCP.AppConfig.getApps({ + success: callback + }); }, + + /** + * @deprecated Use OCP.AppConfig.getKeys() instead + */ getKeys:function(app,callback){ - OC.AppConfig.getCall('getKeys',{app:app},callback); + OCP.AppConfig.getKeys(app, { + success: callback + }); }, + + /** + * @deprecated + */ hasKey:function(app,key,callback){ - OC.AppConfig.getCall('hasKey',{app:app,key:key},callback); + console.error('OC.AppConfig.hasKey is not supported anymore. Use OCP.AppConfig.getValue instead.'); }, + + /** + * @deprecated Use OCP.AppConfig.deleteKey() instead + */ deleteKey:function(app,key){ - OC.AppConfig.postCall('deleteKey',{app:app,key:key}); + OCP.AppConfig.deleteKey(app, key); }, + + /** + * @deprecated + */ deleteApp:function(app){ - OC.AppConfig.postCall('deleteApp',{app:app}); + console.error('OC.AppConfig.deleteApp is not supported anymore.'); } }; -//TODO OC.Preferences diff --git a/core/js/core.json b/core/js/core.json index c98928d0fed..7e72234aaa4 100644 --- a/core/js/core.json +++ b/core/js/core.json @@ -39,6 +39,7 @@ "octemplate.js", "eventsource.js", "config.js", + "public/appconfig.js", "multiselect.js", "oc-requesttoken.js", "setupchecks.js", diff --git a/core/js/js.js b/core/js/js.js index 0db9967094b..ce55f47894b 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -58,7 +58,8 @@ function fileDownloadPath(dir, file) { } /** @namespace */ -var OC={ +var OCP = {}, + OC = { PERMISSION_CREATE:4, PERMISSION_READ:1, PERMISSION_UPDATE:2, diff --git a/core/js/public/appconfig.js b/core/js/public/appconfig.js new file mode 100644 index 00000000000..cde2700c86c --- /dev/null +++ b/core/js/public/appconfig.js @@ -0,0 +1,113 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @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 + * @since 9.2.0 + */ +OCP.AppConfig = { + /** + * @param {string} method + * @param {string} endpoint + * @param {Object} [options] + * @param {Object} [options.data] + * @param {function} [options.success] + * @param {function} [options.error] + * @internal + */ + _call: function(method, endpoint, options) { + + $.ajax({ + type: method.toUpperCase(), + url: OC.linkToOCS('apps/provisioning_api/api/v1', 2) + 'config/apps' + endpoint, + data: options.data || {}, + success: options.success, + error: options.error + }); + }, + + /** + * @param {Object} [options] + * @param {function} [options.success] + * @since 9.2.0 + */ + getApps: function(options) { + this._call('get', '', options); + }, + + /** + * @param {string} app + * @param {Object} [options] + * @param {function} [options.success] + * @param {function} [options.error] + * @since 9.2.0 + */ + getKeys: function(app, options) { + this._call('get', '/' + app, options); + }, + + /** + * @param {string} app + * @param {string} key + * @param {string|function} defaultValue + * @param {Object} [options] + * @param {function} [options.success] + * @param {function} [options.error] + * @since 9.2.0 + */ + getValue: function(app, key, defaultValue, options) { + options = options || {}; + options['data'] = { + defaultValue: defaultValue + }; + + this._call('get', '/' + app + '/' + key, options); + }, + + /** + * @param {string} app + * @param {string} key + * @param {string} value + * @param {Object} [options] + * @param {function} [options.success] + * @param {function} [options.error] + * @since 9.2.0 + */ + setValue: function(app, key, value, options) { + options = options || {}; + options['data'] = { + value: value + }; + + this._call('post', '/' + app + '/' + key, options); + }, + + /** + * @param {string} app + * @param {string} key + * @param {Object} [options] + * @param {function} [options.success] + * @param {function} [options.error] + * @since 9.2.0 + */ + deleteKey: function(app, key, options) { + this._call('delete', '/' + app + '/' + key, options); + } +}; diff --git a/core/routes.php b/core/routes.php index 337f6fb27c3..3ca83815ad4 100644 --- a/core/routes.php +++ b/core/routes.php @@ -66,9 +66,6 @@ $application->registerRoutes($this, [ // Search $this->create('search_ajax_search', '/core/search') ->actionInclude('core/search/ajax/search.php'); -// AppConfig -$this->create('core_ajax_appconfig', '/core/ajax/appconfig.php') - ->actionInclude('core/ajax/appconfig.php'); // oC JS config $this->create('js_config', '/core/js/oc.js') ->actionInclude('core/js/config.php'); diff --git a/core/shipped.json b/core/shipped.json index 0ddaf68eb64..ee8a2b05ef6 100644 --- a/core/shipped.json +++ b/core/shipped.json @@ -40,6 +40,7 @@ "files", "dav", "federatedfilesharing", + "provisioning_api", "twofactor_backupcodes", "workflowengine" ] diff --git a/lib/private/legacy/template.php b/lib/private/legacy/template.php index 7520ffd44ed..7c0b58db0c0 100644 --- a/lib/private/legacy/template.php +++ b/lib/private/legacy/template.php @@ -139,6 +139,7 @@ class OC_Template extends \OC\Template\Base { OC_Util::addScript("oc-requesttoken", null, true); OC_Util::addScript('search', 'search', true); OC_Util::addScript("config", null, true); + OC_Util::addScript("public/appconfig", null, true); OC_Util::addScript("eventsource", null, true); OC_Util::addScript("octemplate", null, true); OC_Util::addTranslations("core", null, true); diff --git a/settings/js/admin.js b/settings/js/admin.js index a2a1cef531c..f5750b23790 100644 --- a/settings/js/admin.js +++ b/settings/js/admin.js @@ -24,7 +24,7 @@ $(document).ready(function(){ $(element).change(function(ev) { var groups = ev.val || []; groups = JSON.stringify(groups); - OC.AppConfig.setValue('core', $(this).attr('name'), groups); + OCP.AppConfig.setValue('core', $(this).attr('name'), groups); }); }); @@ -41,9 +41,9 @@ $(document).ready(function(){ if($(this).is(':checked')){ var mode = $(this).val(); if (mode === 'ajax' || mode === 'webcron' || mode === 'cron') { - OC.AppConfig.setValue('core', 'backgroundjobs_mode', mode); + OCP.AppConfig.setValue('core', 'backgroundjobs_mode', mode); // clear cron errors on background job mode change - OC.AppConfig.deleteKey('core', 'cronErrors'); + OCP.AppConfig.deleteKey('core', 'cronErrors'); } } }); @@ -59,7 +59,7 @@ $(document).ready(function(){ $('#reallyEnableEncryption').click(function() { $('#encryptionAPI div#EncryptionWarning').toggleClass('hidden'); $('#encryptionAPI div#EncryptionSettingsArea').toggleClass('hidden'); - OC.AppConfig.setValue('core', 'encryption_enabled', 'yes'); + OCP.AppConfig.setValue('core', 'encryption_enabled', 'yes'); $('#enableEncryption').attr('disabled', 'disabled'); }); @@ -99,7 +99,7 @@ $(document).ready(function(){ value = 'no'; } } - OC.AppConfig.setValue('core', $(this).attr('name'), value); + OCP.AppConfig.setValue('core', $(this).attr('name'), value); }); $('#shareapiDefaultExpireDate').change(function() { @@ -114,31 +114,22 @@ $(document).ready(function(){ }); var savePublicShareDisclaimerText = _.debounce(function(value) { - var data = { - app:'core', - key:'shareapi_public_link_disclaimertext' + var options = { + success: function() { + OC.msg.finishedSuccess('#publicShareDisclaimerStatus', t('core', 'Saved')); + }, + error: function() { + OC.msg.finishedError('#publicShareDisclaimerStatus', t('core', 'Not saved')); + } }; + + OC.msg.startSaving('#publicShareDisclaimerStatus'); if (_.isString(value) && value !== '') { - data['action'] = 'setValue'; - data['value'] = value; + OCP.AppConfig.setValue('core', 'shareapi_public_link_disclaimertext', value, options); } else { - data['action'] = 'deleteKey'; $('#publicShareDisclaimerText').val(''); + OCP.AppConfig.deleteKey('core', 'shareapi_public_link_disclaimertext', options); } - - OC.msg.startSaving('#publicShareDisclaimerStatus'); - $.post( - OC.AppConfig.url, - data, - function(result){ - if(result.status === 'success'){ - OC.msg.finishedSuccess('#publicShareDisclaimerStatus', t('core', 'Saved')) - } else { - OC.msg.finishedError('#publicShareDisclaimerStatus', t('core', 'Not saved')) - } - }, - 'json' - ); }, 500); $('#publicShareDisclaimerText').on('change, keyup', function() { diff --git a/settings/js/users/users.js b/settings/js/users/users.js index d25f9d92db2..3a357c0e9c4 100644 --- a/settings/js/users/users.js +++ b/settings/js/users/users.js @@ -875,10 +875,10 @@ $(document).ready(function () { $('#CheckboxStorageLocation').click(function() { if ($('#CheckboxStorageLocation').is(':checked')) { $("#userlist .storageLocation").show(); - OC.AppConfig.setValue('core', 'umgmt_show_storage_location', 'true'); + OCP.AppConfig.setValue('core', 'umgmt_show_storage_location', 'true'); } else { $("#userlist .storageLocation").hide(); - OC.AppConfig.setValue('core', 'umgmt_show_storage_location', 'false'); + OCP.AppConfig.setValue('core', 'umgmt_show_storage_location', 'false'); } }); @@ -889,10 +889,10 @@ $(document).ready(function () { $('#CheckboxLastLogin').click(function() { if ($('#CheckboxLastLogin').is(':checked')) { $("#userlist .lastLogin").show(); - OC.AppConfig.setValue('core', 'umgmt_show_last_login', 'true'); + OCP.AppConfig.setValue('core', 'umgmt_show_last_login', 'true'); } else { $("#userlist .lastLogin").hide(); - OC.AppConfig.setValue('core', 'umgmt_show_last_login', 'false'); + OCP.AppConfig.setValue('core', 'umgmt_show_last_login', 'false'); } }); @@ -903,10 +903,10 @@ $(document).ready(function () { $('#CheckboxEmailAddress').click(function() { if ($('#CheckboxEmailAddress').is(':checked')) { $("#userlist .mailAddress").show(); - OC.AppConfig.setValue('core', 'umgmt_show_email', 'true'); + OCP.AppConfig.setValue('core', 'umgmt_show_email', 'true'); } else { $("#userlist .mailAddress").hide(); - OC.AppConfig.setValue('core', 'umgmt_show_email', 'false'); + OCP.AppConfig.setValue('core', 'umgmt_show_email', 'false'); } }); @@ -917,10 +917,10 @@ $(document).ready(function () { $('#CheckboxUserBackend').click(function() { if ($('#CheckboxUserBackend').is(':checked')) { $("#userlist .userBackend").show(); - OC.AppConfig.setValue('core', 'umgmt_show_backend', 'true'); + OCP.AppConfig.setValue('core', 'umgmt_show_backend', 'true'); } else { $("#userlist .userBackend").hide(); - OC.AppConfig.setValue('core', 'umgmt_show_backend', 'false'); + OCP.AppConfig.setValue('core', 'umgmt_show_backend', 'false'); } }); @@ -931,10 +931,10 @@ $(document).ready(function () { $('#CheckboxMailOnUserCreate').click(function() { if ($('#CheckboxMailOnUserCreate').is(':checked')) { $("#newemail").show(); - OC.AppConfig.setValue('core', 'umgmt_send_email', 'true'); + OCP.AppConfig.setValue('core', 'umgmt_send_email', 'true'); } else { $("#newemail").hide(); - OC.AppConfig.setValue('core', 'umgmt_send_email', 'false'); + OCP.AppConfig.setValue('core', 'umgmt_send_email', 'false'); } }); diff --git a/tests/lib/App/ManagerTest.php b/tests/lib/App/ManagerTest.php index f3a91d4f5f4..e04f7c82375 100644 --- a/tests/lib/App/ManagerTest.php +++ b/tests/lib/App/ManagerTest.php @@ -306,7 +306,16 @@ class ManagerTest extends TestCase { $this->appConfig->setValue('test1', 'enabled', 'yes'); $this->appConfig->setValue('test2', 'enabled', 'no'); $this->appConfig->setValue('test3', 'enabled', '["foo"]'); - $apps = ['dav', 'federatedfilesharing', 'files', 'test1', 'test3', 'twofactor_backupcodes', 'workflowengine']; + $apps = [ + 'dav', + 'federatedfilesharing', + 'files', + 'provisioning_api', + 'test1', + 'test3', + 'twofactor_backupcodes', + 'workflowengine', + ]; $this->assertEquals($apps, $this->manager->getInstalledApps()); } @@ -325,6 +334,7 @@ class ManagerTest extends TestCase { 'dav', 'federatedfilesharing', 'files', + 'provisioning_api', 'test1', 'test3', 'twofactor_backupcodes', @@ -343,6 +353,7 @@ class ManagerTest extends TestCase { 'dav' => ['id' => 'dav'], 'files' => ['id' => 'files'], 'federatedfilesharing' => ['id' => 'federatedfilesharing'], + 'provisioning_api' => ['id' => 'provisioning_api'], 'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '9.0.0'], 'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'], 'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'], @@ -386,6 +397,7 @@ class ManagerTest extends TestCase { 'dav' => ['id' => 'dav'], 'files' => ['id' => 'files'], 'federatedfilesharing' => ['id' => 'federatedfilesharing'], + 'provisioning_api' => ['id' => 'provisioning_api'], 'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '8.0.0'], 'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'], 'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'], diff --git a/tests/lib/AppTest.php b/tests/lib/AppTest.php index ea4f328b63a..b7263adb78b 100644 --- a/tests/lib/AppTest.php +++ b/tests/lib/AppTest.php @@ -317,6 +317,7 @@ class AppTest extends \Test\TestCase { 'appforgroup12', 'dav', 'federatedfilesharing', + 'provisioning_api', 'twofactor_backupcodes', 'workflowengine', ), @@ -333,6 +334,7 @@ class AppTest extends \Test\TestCase { 'appforgroup2', 'dav', 'federatedfilesharing', + 'provisioning_api', 'twofactor_backupcodes', 'workflowengine', ), @@ -350,6 +352,7 @@ class AppTest extends \Test\TestCase { 'appforgroup2', 'dav', 'federatedfilesharing', + 'provisioning_api', 'twofactor_backupcodes', 'workflowengine', ), @@ -367,6 +370,7 @@ class AppTest extends \Test\TestCase { 'appforgroup2', 'dav', 'federatedfilesharing', + 'provisioning_api', 'twofactor_backupcodes', 'workflowengine', ), @@ -384,6 +388,7 @@ class AppTest extends \Test\TestCase { 'appforgroup2', 'dav', 'federatedfilesharing', + 'provisioning_api', 'twofactor_backupcodes', 'workflowengine', ), @@ -463,11 +468,11 @@ class AppTest extends \Test\TestCase { ); $apps = \OC_App::getEnabledApps(); - $this->assertEquals(array('files', 'app3', 'dav', 'federatedfilesharing', 'twofactor_backupcodes', 'workflowengine'), $apps); + $this->assertEquals(array('files', 'app3', 'dav', 'federatedfilesharing', 'provisioning_api', 'twofactor_backupcodes', 'workflowengine'), $apps); // mock should not be called again here $apps = \OC_App::getEnabledApps(); - $this->assertEquals(array('files', 'app3', 'dav', 'federatedfilesharing', 'twofactor_backupcodes', 'workflowengine'), $apps); + $this->assertEquals(array('files', 'app3', 'dav', 'federatedfilesharing', 'provisioning_api', 'twofactor_backupcodes', 'workflowengine'), $apps); $this->restoreAppConfig(); \OC_User::setUserId(null); |