From 98ed3a970febe15f7c2b9c489119a01b18bfed3a Mon Sep 17 00:00:00 2001 From: Dan Head Date: Sat, 4 Mar 2017 18:35:27 +0000 Subject: [PATCH] Create settings for slack/email --- src/core/emailer.js | 35 ++++++++++++++----------- src/core/slack.js | 21 ++++++++++----- src/data/models/Settings.js | 23 +++++++++++++++++ src/data/queries/settings.js | 12 +++++++++ src/data/schema.js | 2 ++ src/data/types/SettingsItemType.js | 17 ++++++++++++ src/routes/admin/Admin.css | 15 +++++++++++ src/routes/admin/Admin.js | 37 +++++++++++++++++++++++++++ src/routes/admin/index.js | 4 +++ src/routes/adminPerson/AdminPerson.js | 1 - src/server.js | 24 +++++++++++++++++ 11 files changed, 168 insertions(+), 23 deletions(-) create mode 100644 src/data/models/Settings.js create mode 100644 src/data/queries/settings.js create mode 100644 src/data/types/SettingsItemType.js diff --git a/src/core/emailer.js b/src/core/emailer.js index ad3b411..cd365fe 100644 --- a/src/core/emailer.js +++ b/src/core/emailer.js @@ -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,21 +37,25 @@ ${person.attending && person.dietary.length > 0 ? `

Your dietary requirements } export const sendRSVPEmail = function sendRSVPEmail(person) { - if (email.enabled) { - const mailOptions = { - from: `"${email.senderName}" <${email.senderAddress}>`, - to: person.email, - subject: 'Thank you for your RSVP', - text: getEmailText(person), - html: getEmailHTML(person), - }; - // send mail with defined transport object - transporter.sendMail(mailOptions, (error) => { - if (error) { - handleError(error); - } - }); - } + Settings.findAll().then(data => { + if (data[0].email) { + const mailOptions = { + from: `"${email.senderName}" <${email.senderAddress}>`, + to: person.email, + subject: 'Thank you for your RSVP', + text: getEmailText(person), + html: getEmailHTML(person), + }; + // send mail with defined transport object + transporter.sendMail(mailOptions, (error) => { + if (error) { + handleError(error); + } + }); + } + }).catch(err => { + handleError(err); + }); }; export const sendRSVPEmailWithDebounce = function sendRSVPEmailWithDebounce(person) { diff --git a/src/core/slack.js b/src/core/slack.js index 054cf80..f73feba 100644 --- a/src/core/slack.js +++ b/src/core/slack.js @@ -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,14 +10,20 @@ slack.setWebhook(slackWebhook); const slackTimers = {}; export const sendSlackMsg = function sendSlackMsg(text, channel) { - slack.webhook({ - channel, - username: 'weddingbot', - text, - }, err => { - if (err) { - handleError(err); + Settings.findAll().then(data => { + if (data[0].slack) { + slack.webhook({ + channel, + username: 'weddingbot', + text, + }, err => { + if (err) { + handleError(err); + } + }); } + }).catch(err => { + handleError(err); }); }; diff --git a/src/data/models/Settings.js b/src/data/models/Settings.js new file mode 100644 index 0000000..d7269c3 --- /dev/null +++ b/src/data/models/Settings.js @@ -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; diff --git a/src/data/queries/settings.js b/src/data/queries/settings.js new file mode 100644 index 0000000..ddc066f --- /dev/null +++ b/src/data/queries/settings.js @@ -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; diff --git a/src/data/schema.js b/src/data/schema.js index 2faebbe..37e041a 100644 --- a/src/data/schema.js +++ b/src/data/schema.js @@ -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, }, }), }); diff --git a/src/data/types/SettingsItemType.js b/src/data/types/SettingsItemType.js new file mode 100644 index 0000000..be44aa6 --- /dev/null +++ b/src/data/types/SettingsItemType.js @@ -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; diff --git a/src/routes/admin/Admin.css b/src/routes/admin/Admin.css index 1583a46..9d6ba74 100644 --- a/src/routes/admin/Admin.css +++ b/src/routes/admin/Admin.css @@ -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; +} diff --git a/src/routes/admin/Admin.js b/src/routes/admin/Admin.js index 09e2e4a..65f0b82 100644 --- a/src/routes/admin/Admin.js +++ b/src/routes/admin/Admin.js @@ -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 { ))} +

+

Settings

+
+
+ + +
+
+ + +
+
+ +
+
+
Build hash: {this.props.build.hash}
diff --git a/src/routes/admin/index.js b/src/routes/admin/index.js index 5fd6078..9bd2279 100644 --- a/src/routes/admin/index.js +++ b/src/routes/admin/index.js @@ -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]} />, }; }, diff --git a/src/routes/adminPerson/AdminPerson.js b/src/routes/adminPerson/AdminPerson.js index 8da9432..a649842 100644 --- a/src/routes/adminPerson/AdminPerson.js +++ b/src/routes/adminPerson/AdminPerson.js @@ -112,7 +112,6 @@ class AdminPerson extends React.Component { - ); diff --git a/src/server.js b/src/server.js index 196c5b1..e27c66a 100644 --- a/src/server.js +++ b/src/server.js @@ -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