Create settings for slack/email

This commit is contained in:
2017-03-04 18:35:27 +00:00
parent e3fd086792
commit 98ed3a970f
11 changed files with 168 additions and 23 deletions

View File

@@ -1,6 +1,7 @@
import Nodemailer from 'nodemailer';
import { email, starters, mains, getRsvpEnd } from '../config';
import { handleError } from '../core/rollbar';
import Settings from '../data/models/Settings';
const transporter = Nodemailer.createTransport({
service: 'gmail',
@@ -36,7 +37,8 @@ ${person.attending && person.dietary.length > 0 ? `<p>Your dietary requirements
}
export const sendRSVPEmail = function sendRSVPEmail(person) {
if (email.enabled) {
Settings.findAll().then(data => {
if (data[0].email) {
const mailOptions = {
from: `"${email.senderName}" <${email.senderAddress}>`,
to: person.email,
@@ -51,6 +53,9 @@ export const sendRSVPEmail = function sendRSVPEmail(person) {
}
});
}
}).catch(err => {
handleError(err);
});
};
export const sendRSVPEmailWithDebounce = function sendRSVPEmailWithDebounce(person) {

View File

@@ -1,6 +1,7 @@
import Slack from 'slack-node';
import { slackWebhook } from '../config';
import { handleError } from '../core/rollbar';
import Settings from '../data/models/Settings';
const slack = new Slack();
slack.setWebhook(slackWebhook);
@@ -9,6 +10,8 @@ slack.setWebhook(slackWebhook);
const slackTimers = {};
export const sendSlackMsg = function sendSlackMsg(text, channel) {
Settings.findAll().then(data => {
if (data[0].slack) {
slack.webhook({
channel,
username: 'weddingbot',
@@ -18,6 +21,10 @@ export const sendSlackMsg = function sendSlackMsg(text, channel) {
handleError(err);
}
});
}
}).catch(err => {
handleError(err);
});
};
export const sendSlackMsgWithDebounce = function sendSlackMsgWithDebounce(text, channel, key) {

View File

@@ -0,0 +1,23 @@
import DataType from 'sequelize';
import Model from '../sequelize';
const Settings = Model.define('Settings', {
key: {
type: DataType.UUID,
defaultValue: DataType.UUIDV1,
primaryKey: true,
},
slack: {
type: DataType.BOOLEAN,
defaultValue: false,
},
email: {
type: DataType.BOOLEAN,
defaultValue: false,
},
});
export default Settings;

View File

@@ -0,0 +1,12 @@
import { GraphQLList as List } from 'graphql';
import SettingsItemType from '../types/SettingsItemType';
import Settings from '../models/Settings';
const settings = {
type: new List(SettingsItemType),
resolve() {
return Settings.findAll();
},
};
export default settings;

View File

@@ -7,6 +7,7 @@ import me from './queries/me';
import getAllPersons from './queries/getAllPersons';
import getPersonByKey from './queries/getPersonByKey';
import getPersonsByPassword from './queries/getPersonsByPassword';
import settings from './queries/settings';
const schema = new Schema({
query: new ObjectType({
@@ -16,6 +17,7 @@ const schema = new Schema({
getAllPersons,
getPersonByKey,
getPersonsByPassword,
settings,
},
}),
});

View File

@@ -0,0 +1,17 @@
import {
GraphQLObjectType as ObjectType,
GraphQLID as ID,
GraphQLBoolean as BooleanType,
GraphQLNonNull as NonNull,
} from 'graphql';
const SettingsItemType = new ObjectType({
name: 'SettingsItem',
fields: {
key: { type: new NonNull(ID) },
slack: { type: BooleanType },
email: { type: BooleanType },
},
});
export default SettingsItemType;

View File

@@ -11,3 +11,18 @@
max-width: var(--max-content-width);
}
.formGroup {
position: relative;
margin-bottom: 15px;
}
.label {
display: inline-block;
margin-bottom: 5px;
max-width: 100%;
font-weight: 700;
}
.input {
margin-left: 10px;
}

View File

@@ -2,6 +2,7 @@ import React, { PropTypes } from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './Admin.css';
import Link from '../../components/Link';
import Button from '../../components/Button';
class Admin extends React.Component {
static propTypes = {
@@ -26,6 +27,10 @@ class Admin extends React.Component {
hash: PropTypes.string,
time: PropTypes.string,
}),
settings: PropTypes.shape({
slack: PropTypes.boolean,
email: PropTypes.boolean,
}),
};
render() {
@@ -54,6 +59,38 @@ class Admin extends React.Component {
))}
</ul>
</div>
<div>
<h3>Settings</h3>
<form method="post" action="/admin/settings">
<div className={s.formGroup}>
<label className={s.label} htmlFor="slack">
Send slack messages on RSVP:
</label>
<input
className={s.input}
type="checkbox"
name="slack"
defaultChecked={this.props.settings.slack}
/>
</div>
<div className={s.formGroup}>
<label className={s.label} htmlFor="email">
Send confirmation emails on RSVP:
</label>
<input
className={s.input}
type="checkbox"
name="email"
defaultChecked={this.props.settings.email}
/>
</div>
<div className={s.formGroup}>
<Button type="submit">
Save
</Button>
</div>
</form>
</div>
<div>
Build hash: <a href={`https://bitbucket.org/dan_head/wedding/commits/${this.props.build.hash}`}>{this.props.build.hash}</a>
</div>

View File

@@ -19,8 +19,11 @@ export default {
},
credentials: 'include',
});
const settingsResp = await fetchQL('{settings{slack,email}}');
const { data } = await resp.json();
const config = await configResp.json();
const settings = await settingsResp.json();
const people = data.getAllPersons || [];
const food = {
@@ -47,6 +50,7 @@ export default {
starters={food.starters}
mains={food.mains}
build={config.build}
settings={settings.data.settings[0]}
/></Layout>,
};
},

View File

@@ -112,7 +112,6 @@ class AdminPerson extends React.Component {
</Button>
</div>
</form>
</div>
</div>
);

View File

@@ -23,6 +23,7 @@ import routes from './routes';
import assets from './assets'; // eslint-disable-line import/no-unresolved
import { port, auth, starters, mains, rsvpEndDate } from './config';
import Person from './data/models/Person';
import Settings from './data/models/Settings';
import Rollbar from './core/rollbar';
import { sendSlackMsg, sendSlackMsgWithDebounce } from './core/slack';
import sequelize from './data/sequelize';
@@ -318,6 +319,29 @@ app.post('/admin/people/import', (req, res, next) => {
}
});
app.post('/admin/settings', (req, res, next) => {
try {
Settings.destroy({ where: {} }).then(() => {
const settings = {
slack: !!req.body.slack,
email: !!req.body.email,
};
Settings.create(settings).then(() => {
res.redirect(201, '/admin');
}).catch(err => {
Rollbar.handleError(err);
next(err);
});
}).catch(err => {
Rollbar.handleError(err);
next(err);
});
} catch (err) {
Rollbar.handleError(err);
next(err);
}
});
//
// Register server-side rendering middleware