Bulk export (#684)

* First pass (working) collection export to zip

* Add export confirmation screen

* 👕

* Refactor

* Job for team export, move to tmp file, settings UI

* Export all collections job

* 👕

* Add specs

* Clarify UI
This commit is contained in:
Tom Moor
2018-06-20 21:33:21 -07:00
committed by GitHub
parent cedd31c9ea
commit b9e0668d7d
26 changed files with 543 additions and 28 deletions

View File

@@ -1,10 +1,17 @@
// @flow
import * as React from 'react';
import debug from 'debug';
import bugsnag from 'bugsnag';
import nodemailer from 'nodemailer';
import Oy from 'oy-vey';
import Queue from 'bull';
import { baseStyles } from './emails/components/EmailLayout';
import { WelcomeEmail, welcomeEmailText } from './emails/WelcomeEmail';
import { ExportEmail, exportEmailText } from './emails/ExportEmail';
const log = debug('emails');
type Emails = 'welcome' | 'export';
type SendMailType = {
to: string,
@@ -14,6 +21,14 @@ type SendMailType = {
text: string,
html: React.Node,
headCSS?: string,
attachments?: Object[],
};
type EmailJob = {
data: {
type: Emails,
opts: SendMailType,
},
};
/**
@@ -27,7 +42,7 @@ type SendMailType = {
* HTML: http://localhost:3000/email/:email_type/html
* TEXT: http://localhost:3000/email/:email_type/text
*/
class Mailer {
export default class Mailer {
transporter: ?any;
/**
@@ -44,6 +59,7 @@ class Mailer {
});
try {
log(`Sending email "${data.title}" to ${data.to}`);
await transporter.sendMail({
from: process.env.SMTP_FROM_EMAIL,
replyTo: process.env.SMTP_REPLY_EMAIL || process.env.SMTP_FROM_EMAIL,
@@ -51,10 +67,11 @@ class Mailer {
subject: data.title,
html: html,
text: data.text,
attachments: data.attachments,
});
} catch (e) {
Bugsnag.notifyException(e);
throw e; // Re-throw for queue to re-try
} catch (err) {
bugsnag.notify(err);
throw err; // Re-throw for queue to re-try
}
}
};
@@ -70,17 +87,32 @@ class Mailer {
});
};
export = async (opts: { to: string, attachments: Object[] }) => {
this.sendMail({
to: opts.to,
attachments: opts.attachments,
title: 'Your requested export',
previewText: "Here's your request data export from Outline",
html: <ExportEmail />,
text: exportEmailText,
});
};
constructor() {
if (process.env.SMTP_HOST) {
let smtpConfig = {
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: true,
auth: {
secure: process.env.NODE_ENV === 'production',
auth: undefined,
};
if (process.env.SMTP_USERNAME) {
smtpConfig.auth = {
user: process.env.SMTP_USERNAME,
pass: process.env.SMTP_PASSWORD,
},
};
};
}
this.transporter = nodemailer.createTransport(smtpConfig);
}
@@ -88,14 +120,14 @@ class Mailer {
}
const mailer = new Mailer();
const mailerQueue = new Queue('email', process.env.REDIS_URL);
export const mailerQueue = new Queue('email', process.env.REDIS_URL);
mailerQueue.process(async function(job) {
mailerQueue.process(async (job: EmailJob) => {
// $FlowIssue flow doesn't like dynamic values
await mailer[job.data.type](job.data.opts);
});
const sendEmail = (type: string, to: string, options?: Object = {}) => {
export const sendEmail = (type: Emails, to: string, options?: Object = {}) => {
mailerQueue.add(
{
type,
@@ -113,5 +145,3 @@ const sendEmail = (type: string, to: string, options?: Object = {}) => {
}
);
};
export { Mailer, mailerQueue, sendEmail };