From d82e7c81973267bb716ad52e604ff1a02c50c0e4 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Mon, 16 May 2022 23:04:44 -0700 Subject: [PATCH] Create a Nextcloud app to send a user to an external URL to change their password --- CHANGELOG.md | 3 + appinfo/info.xml | 6 +- appinfo/routes.php | 2 +- css/admin.css | 12 +++ css/style.css | 3 - js/admin.js | 44 ++++++++++ lib/Controller/SettingsController.php | 44 ++++++++-- lib/Settings/Admin.php | 81 +++++++++++++++++++ lib/Settings/Personal.php | 81 +++++++++++++++++++ templates/settings/admin.php | 48 +++++++++++ templates/settings/personal.php | 32 ++++++++ tests/Unit/Controller/PageControllerTest.php | 31 ------- .../Controller/SettingsControllerTest.php | 33 ++++++++ 13 files changed, 373 insertions(+), 47 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 css/admin.css create mode 100644 js/admin.js create mode 100644 lib/Settings/Admin.php create mode 100644 lib/Settings/Personal.php create mode 100644 templates/settings/admin.php create mode 100644 templates/settings/personal.php delete mode 100644 tests/Unit/Controller/PageControllerTest.php create mode 100644 tests/Unit/Controller/SettingsControllerTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..023f9b1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## [0.1.0] - 2022-05-16 +### Added +- Create a Nextcloud app to send users to an external URL to change their password diff --git a/appinfo/info.xml b/appinfo/info.xml index fb92f28..bedacd4 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -5,7 +5,7 @@ External Password An app for Nextcloud to allow an administrator to direct a user to an external site for changing their password. - 0.1.0 + 0.1.1 agpl Raoul Snyman ExternalPassword @@ -15,12 +15,10 @@ https://git.snyman.info/raoul/externalpassword https://git.snyman.info/raoul/externalpassword/issues - + OCA\ExternalPassword\Settings\Admin - OCA\ExternalPassword\Settings\AdminSection OCA\ExternalPassword\Settings\Personal - OCA\ExternalPassword\Settings\PersonalSection diff --git a/appinfo/routes.php b/appinfo/routes.php index 2edef29..454e981 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -9,6 +9,6 @@ */ return [ 'routes' => [ - ['name' => 'Settings#save', 'url' => '/settings/admin/security/externalpassword', 'verb' => 'POST'], + ['name' => 'settings#save', 'url' => '/settings', 'verb' => 'POST'], ] ]; diff --git a/css/admin.css b/css/admin.css new file mode 100644 index 0000000..d9fbd64 --- /dev/null +++ b/css/admin.css @@ -0,0 +1,12 @@ +#security-externalpassword label { + display: inline-block; + width: 12rem; +} + +#security-externalpassword input[type=text] { + width: 30rem; +} + +#security-externalpassword input[type=text].small { + width: 12rem; +} diff --git a/css/style.css b/css/style.css index ce350c6..e69de29 100644 --- a/css/style.css +++ b/css/style.css @@ -1,3 +0,0 @@ -#hello { - color: red; -} diff --git a/js/admin.js b/js/admin.js new file mode 100644 index 0000000..91c0564 --- /dev/null +++ b/js/admin.js @@ -0,0 +1,44 @@ +/* global OC */ + +/** + * @copyright Copyright (c) 2022 Raoul Snyman + * + * @author Raoul Snyman + * + * @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 . + * + */ +window.addEventListener('DOMContentLoaded', function () { + $('#externalpassword-save').click(function () { + var formData = $('#externalpassword-form').serialize(); + $('#externalpassword-error-msg').hide(); + $('#externalpassword-save').attr('disabled', 'disabled'); + $.post(OC.generateUrl('apps/externalpassword/settings'), formData, function (response) { + if (typeof(response.data) !== "undefined") { + OC.msg.finishedSaving('#externalpassword-error-msg', response); + } else { + OC.msg.finishedSaving('#externalpassword-error-msg', { + 'status' : 'error', + 'data' : { + 'message' : t('externalpassword', 'Unable to save settings') + } + }); + } + $("#externalpassword-save").removeAttr('disabled'); + }); + return false; + }); +}); diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 0c8ca8c..3348bff 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -1,34 +1,62 @@ + * + * @author Raoul Snyman + * + * @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 . + * + */ namespace OCA\ExternalPassword\Controller; -use OCP\IRequest; -use OCP\IConfig; -use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\JSONResponse; +use OCP\IConfig; +use OCP\IRequest; class SettingsController extends Controller { /** @var IConfig */ private $config; + /** + * @param string $AppName + * @param IRequest $request + * @param IConfig $config + */ public function __construct($AppName, IRequest $request, IConfig $config) { parent::__construct($AppName, $request); $this->config = $config; } /** - * @param string + * @param string $changePasswordUrl + * @param string $descriptionText + * @param string $buttonText */ public function save(string $changePasswordUrl, string $descriptionText, string $buttonText): JSONResponse { $this->config->setAppValue('externalpassword', 'changePasswordUrl', $changePasswordUrl); $this->config->setAppValue('externalpassword', 'descriptionText', $descriptionText); $this->config->setAppValue('externalpassword', 'buttonText', $buttonText); $parameters = [ - 'changePasswordUrl' => $changePasswordUrl, - 'descriptionText' => $descriptionText, - 'buttonText' => $buttonText + 'status' => 'success', + 'data' => [ + 'message' => 'Saved' + ] ]; return new JSONResponse($parameters); } - } diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php new file mode 100644 index 0000000..d033850 --- /dev/null +++ b/lib/Settings/Admin.php @@ -0,0 +1,81 @@ + + * + * @author Raoul Snyman + * + * @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 . + * + */ +namespace OCA\ExternalPassword\Settings; + +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; +use OCP\IL10N; +use OCP\Settings\ISettings; + +class Admin implements ISettings { + + /** @var IConfig */ + private $config; + + /** @var IL10N */ + private $l; + + /** + * Admin constructor. + * + * @param IConfig $config + * @param IL10N $l + */ + public function __construct(IConfig $config, IL10N $l) { + $this->config = $config; + $this->l = $l; + } + + /** + * @return TemplateResponse + */ + public function getForm() { + $changePasswordUrl = $this->config->getAppValue('externalpassword', 'changePasswordUrl', ''); + $descriptionText = $this->config->getAppValue('externalpassword', 'descriptionText', + 'Your password is managed externally, please click the button below to change your password.'); + $buttonText = $this->config->getAppValue('externalpassword', 'buttonText', 'Change password'); + $parameters = [ + 'changePasswordUrl' => $changePasswordUrl, + 'descriptionText' => $descriptionText, + 'buttonText' => $buttonText + ]; + return new TemplateResponse('externalpassword', 'settings/admin', $parameters); + } + + /** + * @return string the section ID, e.g. 'sharing' + */ + public function getSection() { + return 'security'; + } + + /** + * @return int whether the form should be rather on the top or bottom of + * the admin section. The forms are arranged in ascending order of the + * priority values. It is required to return a value between 0 and 100. + */ + public function getPriority() { + return 10; + } + +} diff --git a/lib/Settings/Personal.php b/lib/Settings/Personal.php new file mode 100644 index 0000000..2bfba6e --- /dev/null +++ b/lib/Settings/Personal.php @@ -0,0 +1,81 @@ + + * + * @author Raoul Snyman + * + * @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 . + * + */ +namespace OCA\ExternalPassword\Settings; + +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; +use OCP\IL10N; +use OCP\Settings\ISettings; + +class Personal implements ISettings { + + /** @var IConfig */ + private $config; + + /** @var IL10N */ + private $l; + + /** + * Admin constructor. + * + * @param IConfig $config + * @param IL10N $l + */ + public function __construct(IConfig $config, IL10N $l) { + $this->config = $config; + $this->l = $l; + } + + /** + * @return TemplateResponse + */ + public function getForm() { + $changePasswordUrl = $this->config->getAppValue('externalpassword', 'changePasswordUrl', ''); + $descriptionText = $this->config->getAppValue('externalpassword', 'descriptionText', + 'Your password is managed externally, please click the button below to change your password.'); + $buttonText = $this->config->getAppValue('externalpassword', 'buttonText', 'Change password'); + $parameters = [ + 'changePasswordUrl' => $changePasswordUrl, + 'descriptionText' => $descriptionText, + 'buttonText' => $buttonText + ]; + return new TemplateResponse('externalpassword', 'settings/personal', $parameters); + } + + /** + * @return string the section ID, e.g. 'sharing' + */ + public function getSection() { + return 'security'; + } + + /** + * @return int whether the form should be rather on the top or bottom of + * the admin section. The forms are arranged in ascending order of the + * priority values. It is required to return a value between 0 and 100. + */ + public function getPriority() { + return 10; + } + +} diff --git a/templates/settings/admin.php b/templates/settings/admin.php new file mode 100644 index 0000000..ae08839 --- /dev/null +++ b/templates/settings/admin.php @@ -0,0 +1,48 @@ + + * + * @author Raoul Snyman + * + * @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 . + * + */ + +script('externalpassword', 'admin'); +style('externalpassword', 'admin'); +?> +
+

t('External Password'));?>

+ +

t('To direct users to an external website in order to change their password, set the URL below.')); ?>

+
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
diff --git a/templates/settings/personal.php b/templates/settings/personal.php new file mode 100644 index 0000000..03c2c0b --- /dev/null +++ b/templates/settings/personal.php @@ -0,0 +1,32 @@ + + * + * @author Raoul Snyman + * + * @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 . + * + */ +?> + +
+

t('Password'));?>

+
+

+

+
+
+ diff --git a/tests/Unit/Controller/PageControllerTest.php b/tests/Unit/Controller/PageControllerTest.php deleted file mode 100644 index 5f1b943..0000000 --- a/tests/Unit/Controller/PageControllerTest.php +++ /dev/null @@ -1,31 +0,0 @@ -getMockBuilder('OCP\IRequest')->getMock(); - - $this->controller = new PageController( - 'externalpassword', $request, $this->userId - ); - } - - public function testIndex() { - $result = $this->controller->index(); - - $this->assertEquals('index', $result->getTemplateName()); - $this->assertTrue($result instanceof TemplateResponse); - } - -} diff --git a/tests/Unit/Controller/SettingsControllerTest.php b/tests/Unit/Controller/SettingsControllerTest.php new file mode 100644 index 0000000..f4c4212 --- /dev/null +++ b/tests/Unit/Controller/SettingsControllerTest.php @@ -0,0 +1,33 @@ +getMockBuilder('OCP\IRequest')->getMock(); + $config = $this->getMockBuilder('OCP\IConfig')->getMock(); + + $this->controller = new SettingsController( + 'externalpassword', $request, $config + ); + } + + public function testSave() { + $changePasswordUrl = 'https://example.com/change-password'; + $descriptionText = 'Use the link below to change your password'; + $buttonText = 'Change password'; + + $result = $this->controller->saveSettings($changePasswordUrl, $descriptionText, $buttonText); + $this->assertTrue($result instanceof JSONResponse); + } + +}