diff --git a/framework/core/js/src/admin/components/MailPage.js b/framework/core/js/src/admin/components/MailPage.js index 78570a7a0..d4e830fba 100644 --- a/framework/core/js/src/admin/components/MailPage.js +++ b/framework/core/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/framework/core/src/Api/Controller/ListMailDriversController.php b/framework/core/src/Api/Controller/ListMailDriversController.php new file mode 100644 index 000000000..179ec6f2d --- /dev/null +++ b/framework/core/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/framework/core/src/Api/Serializer/MailDriverSerializer.php b/framework/core/src/Api/Serializer/MailDriverSerializer.php new file mode 100644 index 000000000..5dd3b827f --- /dev/null +++ b/framework/core/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/framework/core/src/Api/routes.php b/framework/core/src/Api/routes.php index 96dae18ae..6af843c84 100644 --- a/framework/core/src/Api/routes.php +++ b/framework/core/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/framework/core/src/Mail/DriverInterface.php b/framework/core/src/Mail/DriverInterface.php index 9dd642d39..4a6dae983 100644 --- a/framework/core/src/Mail/DriverInterface.php +++ b/framework/core/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/framework/core/src/Mail/LogDriver.php b/framework/core/src/Mail/LogDriver.php index ee7df0cdb..8c038fb5f 100644 --- a/framework/core/src/Mail/LogDriver.php +++ b/framework/core/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/framework/core/src/Mail/MailgunDriver.php b/framework/core/src/Mail/MailgunDriver.php index a0457bcfc..02b353b2c 100644 --- a/framework/core/src/Mail/MailgunDriver.php +++ b/framework/core/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/framework/core/src/Mail/MandrillDriver.php b/framework/core/src/Mail/MandrillDriver.php index 8d6127d41..ec20829c3 100644 --- a/framework/core/src/Mail/MandrillDriver.php +++ b/framework/core/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/framework/core/src/Mail/SendmailDriver.php b/framework/core/src/Mail/SendmailDriver.php index 502b0e369..76455934e 100644 --- a/framework/core/src/Mail/SendmailDriver.php +++ b/framework/core/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/framework/core/src/Mail/SesDriver.php b/framework/core/src/Mail/SesDriver.php index c5a683a9b..653d5fcce 100644 --- a/framework/core/src/Mail/SesDriver.php +++ b/framework/core/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/framework/core/src/Mail/SmtpDriver.php b/framework/core/src/Mail/SmtpDriver.php index e2ed654ed..d74f8b75d 100644 --- a/framework/core/src/Mail/SmtpDriver.php +++ b/framework/core/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(