diff --git a/.env.sample b/.env.sample index 98b69fda4..ff475682a 100644 --- a/.env.sample +++ b/.env.sample @@ -13,3 +13,9 @@ URL=http://localhost:3000 DEPLOYMENT=hosted ENABLE_UPDATES=true GOOGLE_ANALYTICS_ID= + +SMTP_HOST= +SMTP_PORT= +SMTP_USERNAME= +SMTP_PASSWORD= +SMTP_SENDER_EMAIL= \ No newline at end of file diff --git a/package.json b/package.json index 10af2392b..669b6d1b7 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,8 @@ "main": "index.js", "scripts": { "clean": "rimraf dist", - "build:webpack": - "NODE_ENV=production webpack --config webpack.config.prod.js", - "build:analyze": - "NODE_ENV=production webpack --config webpack.config.prod.js --json | webpack-bundle-size-analyzer", + "build:webpack": "NODE_ENV=production webpack --config webpack.config.prod.js", + "build:analyze": "NODE_ENV=production webpack --config webpack.config.prod.js --json | webpack-bundle-size-analyzer", "build": "npm run clean && npm run build:webpack", "start": "NODE_ENV=production node index.js", "dev": "NODE_ENV=development nodemon --inspect --watch server index.js", @@ -20,24 +18,39 @@ "sequelize:migrate": "sequelize db:migrate", "test": "npm run test:app && npm run test:server", "test:app": "jest", - "test:server": - "jest --config=server/.jestconfig.json --runInBand --forceExit", + "test:server": "jest --config=server/.jestconfig.json --runInBand --forceExit", "precommit": "lint-staged" }, "lint-staged": { - "*.js": ["eslint --fix", "git add"] + "*.js": [ + "eslint --fix", + "git add" + ] }, "jest": { "verbose": false, - "roots": ["app"], + "roots": [ + "app" + ], "moduleNameMapper": { "^.*[.](s?css|css)$": "/__mocks__/styleMock.js", "^.*[.](gif|ttf|eot|svg)$": "/__test__/fileMock.js" }, - "moduleFileExtensions": ["js", "jsx", "json"], - "moduleDirectories": ["node_modules"], - "modulePaths": ["app"], - "setupFiles": ["/setupJest.js", "/__mocks__/window.js"] + "moduleFileExtensions": [ + "js", + "jsx", + "json" + ], + "moduleDirectories": [ + "node_modules" + ], + "modulePaths": [ + "app" + ], + "setupFiles": [ + "/setupJest.js", + "/__mocks__/window.js" + ] }, "engines": { "node": ">= 7.6" @@ -117,8 +130,10 @@ "mobx-react-devtools": "^4.2.11", "moment": "2.13.0", "node-dev": "3.1.0", + "nodemailer": "^4.4.0", "normalize.css": "^7.0.0", "normalizr": "2.0.1", + "oy-vey": "^0.10.0", "pg": "^6.1.5", "pg-hstore": "2.3.2", "polished": "1.2.1", diff --git a/server/__snapshots__/mailer.test.js.snap b/server/__snapshots__/mailer.test.js.snap new file mode 100644 index 000000000..16181db37 --- /dev/null +++ b/server/__snapshots__/mailer.test.js.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Mailer #welcome 1`] = ` +Object { + "from": "Outline ", + "html": " + + + + + + + + Welcome to Outline + + + + + + + + + + +
+ Outline is a place for your team to build and share knowledge. +
 

Welcome to Outline!

Outline is a place for your team to build and share knowledge.

To get started, head to your dashboard and try creating a collection to help document your workflow, create playbooks or help with team onboarding.

You can also import existing Markdown document by drag and dropping them to your collections

 

View my dashboard

 
Outline
+
+ + + ", + "subject": "Welcome to Outline", + "text": " +Welcome to Outline! + +Outline is a place for your team to build and share knowledge. + +To get started, head to your dashboard and try creating a collection to help document your workflow, create playbooks or help with team onboarding. + +You can also import existing Markdown document by drag and dropping them to your collections + +http://localhost:3000/dashboard +", + "to": "user@example.com", +} +`; diff --git a/server/api/auth.test.js b/server/api/auth.test.js index 5da560065..202e5ee9f 100644 --- a/server/api/auth.test.js +++ b/server/api/auth.test.js @@ -10,6 +10,12 @@ afterAll(server.close); describe.skip('#auth.signup', async () => { it('should signup a new user', async () => { + const welcomeEmailMock = jest.fn(); + jest.doMock('../mailer', () => { + return { + welcome: welcomeEmailMock, + }; + }); const res = await server.post('/api/auth.signup', { body: { username: 'testuser', @@ -23,6 +29,7 @@ describe.skip('#auth.signup', async () => { expect(res.status).toEqual(200); expect(body.ok).toBe(true); expect(body.data.user).toBeTruthy(); + expect(welcomeEmailMock).toBeCalledWith('new.user@example.com'); }); it('should require params', async () => { diff --git a/server/emails/WelcomeEmail.js b/server/emails/WelcomeEmail.js new file mode 100644 index 000000000..4cf4b96ce --- /dev/null +++ b/server/emails/WelcomeEmail.js @@ -0,0 +1,52 @@ +// @flow +import React from 'react'; +import EmailTemplate from './components/EmailLayout'; +import Body from './components/Body'; +import Button from './components/Button'; +import Footer from './components/Footer'; +import EmptySpace from './components/EmptySpace'; + +export const welcomeEmailText = ` +Welcome to Outline! + +Outline is a place for your team to build and share knowledge. + +To get started, head to your dashboard and try creating a collection to help document your workflow, create playbooks or help with team onboarding. + +You can also import existing Markdown document by drag and dropping them to your collections + +${process.env.URL}/dashboard +`; + +export const WelcomeEmail = () => { + return ( + + +

+ Welcome to Outline! +

+ +

Outline is a place for your team to build and share knowledge.

+

+ To get started, head to your dashboard and try creating a collection + to help document your workflow, create playbooks or help with team + onboarding. +

+

+ You can also import existing Markdown document by drag and dropping + them to your collections +

+ + + +

+ +

+ + +