Skip to content

Commit

Permalink
Allow configuring all drivers via frontend (#1169)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
franzliedke committed Mar 19, 2019
1 parent 2bd40b5 commit 5154d7e
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 33 deletions.
78 changes: 45 additions & 33 deletions js/src/admin/components/MailPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.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.loading = true;
this.saving = false;

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 (
<div className="MailPage">
<div className="container">
<LoadingIndicator />
</div>
</div>
);
}

return (
<div className="MailPage">
<div className="container">
Expand Down Expand Up @@ -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: [
<div className="MailPage-MailSettings-input">
<label>{app.translator.trans('core.admin.email.host_label')}</label>
<input className = "FormControl" value={this.values.mail_host() || ''} onInput={m.withAttr('value', this.values.mail_host)} />
<label>{app.translator.trans('core.admin.email.port_label')}</label>
<input className="FormControl" value={this.values.mail_port() || ''} oninput={m.withAttr('value', this.values.mail_port)} />
<label>{app.translator.trans('core.admin.email.encryption_label')}</label>
<input className="FormControl" value={this.values.mail_encryption() || ''} oninput={m.withAttr('value', this.values.mail_encryption)} />
<label>{app.translator.trans('core.admin.email.username_label')}</label>
<input className="FormControl" value={this.values.mail_username() || ''} onInput={m.withAttr('value', this.values.mail_username)}/>
<label>{app.translator.trans('core.admin.email.password_label')}</label>
<input className="FormControl" value={this.values.mail_password() || ''} onInput={m.withAttr('value', this.values.mail_password)}/>
{this.driverFields[this.values.mail_driver()].flatMap(field => [
<label>{app.translator.trans(`core.admin.email.${field}_label`)}</label>,
<input className="FormControl" value={this.values[field]() || ''} onInput={m.withAttr('value', this.values[field])} />
])}
</div>
]
})}
Expand All @@ -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()
})}
</form>
Expand All @@ -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 = {};
Expand All @@ -118,7 +130,7 @@ export default class MailPage extends Page {
})
.catch(() => {})
.then(() => {
this.loading = false;
this.saving = false;
m.redraw();
});
}
Expand Down
46 changes: 46 additions & 0 deletions src/Api/Controller/ListMailDriversController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* 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;
}
}
49 changes: 49 additions & 0 deletions src/Api/Serializer/MailDriverSerializer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* 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'];
}
}
7 changes: 7 additions & 0 deletions src/Api/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -308,4 +308,11 @@
'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)
);
};
5 changes: 5 additions & 0 deletions src/Mail/DriverInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
*/
interface DriverInterface
{
/**
* Provide a list of settings for this driver.
*/
public function availableSettings(): array;

/**
* Build a mail transport based on Flarum's current settings.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/Mail/LogDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public function __construct(LoggerInterface $logger)
$this->logger = $logger;
}

public function availableSettings(): array
{
return [];
}

public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport
{
return new LogTransport($this->logger);
Expand Down
8 changes: 8 additions & 0 deletions src/Mail/MailgunDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@

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(
Expand Down
7 changes: 7 additions & 0 deletions src/Mail/MandrillDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@

class MandrillDriver implements DriverInterface
{
public function availableSettings(): array
{
return [
'mail_mandrill_secret',
];
}

public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport
{
return new MandrillTransport(
Expand Down
5 changes: 5 additions & 0 deletions src/Mail/SendmailDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@

class SendmailDriver implements DriverInterface
{
public function availableSettings(): array
{
return [];
}

public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport
{
return new Swift_SendmailTransport;
Expand Down
9 changes: 9 additions & 0 deletions src/Mail/SesDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@

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 = [
Expand Down
11 changes: 11 additions & 0 deletions src/Mail/SmtpDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@

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(
Expand Down

0 comments on commit 5154d7e

Please sign in to comment.