diff --git a/.env.sample b/.env.sample index 98b69fda..ff475682 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 10af2392..669b6d1b 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 00000000..16181db3 --- /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 5da56006..202e5ee9 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 00000000..4cf4b96c --- /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 +

+ + + +

+ +

+ + +