From 5154d7e5a636983956a70e04050592ed3c17a336 Mon Sep 17 00:00:00 2001 From: Franz Liedke Date: Tue, 19 Mar 2019 09:56:20 +0100 Subject: [PATCH] Allow configuring all drivers via frontend (#1169) This includes an API endpoint for fetching the list of possible drivers and their configuration fields. In the future, this can be extended to include more meta information about each field. --- js/src/admin/components/MailPage.js | 76 +++++++++++-------- .../Controller/ListMailDriversController.php | 46 +++++++++++ src/Api/Serializer/MailDriverSerializer.php | 49 ++++++++++++ src/Api/routes.php | 7 ++ src/Mail/DriverInterface.php | 5 ++ src/Mail/LogDriver.php | 5 ++ src/Mail/MailgunDriver.php | 8 ++ src/Mail/MandrillDriver.php | 7 ++ src/Mail/SendmailDriver.php | 5 ++ src/Mail/SesDriver.php | 9 +++ src/Mail/SmtpDriver.php | 11 +++ 11 files changed, 196 insertions(+), 32 deletions(-) create mode 100644 src/Api/Controller/ListMailDriversController.php create mode 100644 src/Api/Serializer/MailDriverSerializer.php diff --git a/js/src/admin/components/MailPage.js b/js/src/admin/components/MailPage.js index 78570a7a0..d4e830fba 100644 --- a/js/src/admin/components/MailPage.js +++ b/js/src/admin/components/MailPage.js @@ -3,36 +3,54 @@ import FieldSet from '../../common/components/FieldSet'; import Button from '../../common/components/Button'; import Alert from '../../common/components/Alert'; import Select from '../../common/components/Select'; +import LoadingIndicator from '../../common/components/LoadingIndicator'; import saveSettings from '../utils/saveSettings'; export default class MailPage extends Page { init() { super.init(); - this.loading = false; + this.loading = true; + this.saving = false; - this.driverFields = { - smtp: ['mail_host', 'mail_port', 'mail_encryption', 'mail_username', 'mail_password'], - mail: [], - log: [], - }; - - this.fields = [ - 'mail_driver', - 'mail_host', - 'mail_from', - 'mail_port', - 'mail_username', - 'mail_password', - 'mail_encryption' - ]; + this.driverFields = {}; + this.fields = ['mail_driver', 'mail_from']; this.values = {}; const settings = app.data.settings; this.fields.forEach(key => this.values[key] = m.prop(settings[key])); + + app.request({ + method: 'GET', + url: app.forum.attribute('apiUrl') + '/mail-drivers' + }).then(response => { + this.driverFields = response['data'].reduce( + (hash, driver) => ({...hash, [driver['id']]: driver['attributes']['fields']}), + {} + ); + + Object.keys(this.driverFields).flatMap(key => this.driverFields[key]).forEach( + key => { + this.fields.push(key); + this.values[key] = m.prop(settings[key]); + } + ); + this.loading = false; + m.redraw(); + }); } view() { + if (this.loading) { + return ( +
+
+ +
+
+ ); + } + return (
@@ -64,21 +82,15 @@ export default class MailPage extends Page { ] })} - {this.values.mail_driver() == 'smtp' && FieldSet.component({ - label: app.translator.trans('core.admin.email.smtp_heading'), + {Object.keys(this.driverFields[this.values.mail_driver()]).length > 0 && FieldSet.component({ + label: app.translator.trans(`core.admin.email.${this.values.mail_driver()}_heading`), className: 'MailPage-MailSettings', children: [
- - - - - - - - - - + {this.driverFields[this.values.mail_driver()].flatMap(field => [ + , + + ])}
] })} @@ -87,7 +99,7 @@ export default class MailPage extends Page { type: 'submit', className: 'Button Button--primary', children: app.translator.trans('core.admin.email.submit_button'), - loading: this.loading, + loading: this.saving, disabled: !this.changed() })} @@ -103,9 +115,9 @@ export default class MailPage extends Page { onsubmit(e) { e.preventDefault(); - if (this.loading) return; + if (this.saving) return; - this.loading = true; + this.saving = true; app.alerts.dismiss(this.successAlert); const settings = {}; @@ -118,7 +130,7 @@ export default class MailPage extends Page { }) .catch(() => {}) .then(() => { - this.loading = false; + this.saving = false; m.redraw(); }); } diff --git a/src/Api/Controller/ListMailDriversController.php b/src/Api/Controller/ListMailDriversController.php new file mode 100644 index 000000000..179ec6f2d --- /dev/null +++ b/src/Api/Controller/ListMailDriversController.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Api\Controller; + +use Flarum\Api\Serializer\MailDriverSerializer; +use Flarum\User\AssertPermissionTrait; +use Illuminate\Contracts\Container\Container; +use Psr\Http\Message\ServerRequestInterface; +use Tobscure\JsonApi\Document; + +class ListMailDriversController extends AbstractListController +{ + use AssertPermissionTrait; + + /** + * {@inheritdoc} + */ + public $serializer = MailDriverSerializer::class; + + /** + * {@inheritdoc} + */ + protected function data(ServerRequestInterface $request, Document $document) + { + $this->assertAdmin($request->getAttribute('actor')); + + $drivers = self::$container->make('mail.supported_drivers'); + array_walk($drivers, function (&$driver, $key) { + $driver = [ + 'id' => $key, + 'driver' => self::$container->make($driver), + ]; + }); + + return $drivers; + } +} diff --git a/src/Api/Serializer/MailDriverSerializer.php b/src/Api/Serializer/MailDriverSerializer.php new file mode 100644 index 000000000..5dd3b827f --- /dev/null +++ b/src/Api/Serializer/MailDriverSerializer.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Api\Serializer; + +use Flarum\Mail\DriverInterface; +use InvalidArgumentException; + +class MailDriverSerializer extends AbstractSerializer +{ + /** + * {@inheritdoc} + */ + protected $type = 'mail-drivers'; + + /** + * {@inheritdoc} + * + * @param \Flarum\Mail\DriverInterface $driver + * @throws InvalidArgumentException + */ + protected function getDefaultAttributes($driver) + { + if (! ($driver['driver'] instanceof DriverInterface)) { + throw new InvalidArgumentException( + get_class($this).' can only serialize instances of '.DriverInterface::class + ); + } + + $driver = $driver['driver']; + + return [ + 'fields' => $driver->availableSettings(), + ]; + } + + public function getId($model) + { + return $model['id']; + } +} diff --git a/src/Api/routes.php b/src/Api/routes.php index 96dae18ae..6af843c84 100644 --- a/src/Api/routes.php +++ b/src/Api/routes.php @@ -308,4 +308,11 @@ return function (RouteCollection $map, RouteHandlerFactory $route) { 'cache.clear', $route->toController(Controller\ClearCacheController::class) ); + + // List available mail drivers and their configuration fields + $map->get( + '/mail-drivers', + 'mailDrivers.index', + $route->toController(Controller\ListMailDriversController::class) + ); }; diff --git a/src/Mail/DriverInterface.php b/src/Mail/DriverInterface.php index 9dd642d39..4a6dae983 100644 --- a/src/Mail/DriverInterface.php +++ b/src/Mail/DriverInterface.php @@ -24,6 +24,11 @@ use Swift_Transport; */ interface DriverInterface { + /** + * Provide a list of settings for this driver. + */ + public function availableSettings(): array; + /** * Build a mail transport based on Flarum's current settings. */ diff --git a/src/Mail/LogDriver.php b/src/Mail/LogDriver.php index ee7df0cdb..8c038fb5f 100644 --- a/src/Mail/LogDriver.php +++ b/src/Mail/LogDriver.php @@ -28,6 +28,11 @@ class LogDriver implements DriverInterface $this->logger = $logger; } + public function availableSettings(): array + { + return []; + } + public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport { return new LogTransport($this->logger); diff --git a/src/Mail/MailgunDriver.php b/src/Mail/MailgunDriver.php index a0457bcfc..02b353b2c 100644 --- a/src/Mail/MailgunDriver.php +++ b/src/Mail/MailgunDriver.php @@ -18,6 +18,14 @@ use Swift_Transport; class MailgunDriver implements DriverInterface { + public function availableSettings(): array + { + return [ + 'mail_mailgun_secret', // the secret key + 'mail_mailgun_domain', // the API base URL + ]; + } + public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport { return new MailgunTransport( diff --git a/src/Mail/MandrillDriver.php b/src/Mail/MandrillDriver.php index 8d6127d41..ec20829c3 100644 --- a/src/Mail/MandrillDriver.php +++ b/src/Mail/MandrillDriver.php @@ -18,6 +18,13 @@ use Swift_Transport; class MandrillDriver implements DriverInterface { + public function availableSettings(): array + { + return [ + 'mail_mandrill_secret', + ]; + } + public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport { return new MandrillTransport( diff --git a/src/Mail/SendmailDriver.php b/src/Mail/SendmailDriver.php index 502b0e369..76455934e 100644 --- a/src/Mail/SendmailDriver.php +++ b/src/Mail/SendmailDriver.php @@ -17,6 +17,11 @@ use Swift_Transport; class SendmailDriver implements DriverInterface { + public function availableSettings(): array + { + return []; + } + public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport { return new Swift_SendmailTransport; diff --git a/src/Mail/SesDriver.php b/src/Mail/SesDriver.php index c5a683a9b..653d5fcce 100644 --- a/src/Mail/SesDriver.php +++ b/src/Mail/SesDriver.php @@ -18,6 +18,15 @@ use Swift_Transport; class SesDriver implements DriverInterface { + public function availableSettings(): array + { + return [ + 'mail_ses_key', + 'mail_ses_secret', + 'mail_ses_region', + ]; + } + public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport { $config = [ diff --git a/src/Mail/SmtpDriver.php b/src/Mail/SmtpDriver.php index e2ed654ed..d74f8b75d 100644 --- a/src/Mail/SmtpDriver.php +++ b/src/Mail/SmtpDriver.php @@ -17,6 +17,17 @@ use Swift_Transport; class SmtpDriver implements DriverInterface { + public function availableSettings(): array + { + return [ + 'mail_host', // a hostname, IPv4 address or IPv6 wrapped in [] + 'mail_port', // a number, defaults to 25 + 'mail_encryption', // "tls" or "ssl" + 'mail_username', // required + 'mail_password', // required + ]; + } + public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport { $transport = new Swift_SmtpTransport(