├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── handler.js ├── lib ├── index.js ├── reports.js └── templates │ └── email.js ├── package.json ├── serverless.yml └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | dist 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 29 | node_modules 30 | 31 | #IDE 32 | **/.idea 33 | 34 | #OS 35 | .DS_Store 36 | .tmp 37 | 38 | #SERVERLESS 39 | admin.env 40 | .env 41 | 42 | #Ignore _meta folder 43 | _meta -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | dist 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 29 | node_modules 30 | 31 | #IDE Stuff 32 | **/.idea 33 | 34 | #OS STUFF 35 | .DS_Store 36 | .tmp 37 | 38 | #SERVERLESS STUFF 39 | admin.env 40 | .env 41 | _meta -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2020 Richard Dancsi 2 | 3 | Lincesed under The MIT License (MIT) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Daily Email Reports 2 | 3 | A Serverless - Node.js project to create html reports from database queries, and send those reports out in pretty emails. 4 | 5 | Using AWS Lambda, you can then schedule this super-lightweight reporting app, to send out a daily email about new signups, basic usage etc. 6 | 7 | ## Dependencies 8 | 9 | Make sure you have: 10 | 11 | 1. The [Serverless Framework](https://www.serverless.com) installed, 12 | 13 | 2. Node.js v12.0+. 14 | 15 | 3. An Amazon AWS account (as described by the [Serverless Framework](https://www.serverless.com)) 16 | 17 | ## Install 18 | 19 | 1. Install project dependencies: 20 | 21 | ``` 22 | $ yarn install 23 | ``` 24 | 25 | 2. Set up all environment variables: 26 | 27 | You have to include your database and sendmail provider's details. Look into `serverless.yml` to see which variables you need to set. 28 | 29 | 3. Deploy the function and the /email endpoint: 30 | 31 | Deploy it to AWS Lambda: 32 | 33 | ``` 34 | $ sls deploy 35 | ``` 36 | 37 | To remove a deployed Lambda, call: 38 | 39 | ``` 40 | $ sls remove 41 | ``` 42 | 43 | ## License 44 | 45 | [MIT, do-with-the-code-whatever-you-please License](https://github.com/wimagguc/node-serverless-reports/blob/master/LICENSE.md) 46 | 47 | And as always, feel free to contribute! 48 | 49 | ## About 50 | 51 | Richard Dancsi 52 | 53 | - Blog: [wimagguc.com](https://www.wimagguc.com/) 54 | - Twitter: [twitter.com/wimagguc](https://twitter.com/wimagguc) 55 | - Linkedin: [linkedin.com/in/richarddancsi](https://linkedin.com/in/richarddancsi) 56 | -------------------------------------------------------------------------------- /handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * Serverless Module: Lambda Handler 5 | * - Your lambda functions should be a thin wrapper around your own separate 6 | * modules, to keep your code testable, reusable and AWS independent 7 | * - 'serverless-helpers-js' module is required for Serverless ENV var support. Hopefully, AWS will add ENV support to Lambda soon :) 8 | */ 9 | 10 | // Require Logic 11 | const lib = require('./lib/') 12 | 13 | // Lambda Handler 14 | module.exports.handler = async (event, context) => { 15 | const { error, success: response } = await lib.sendReports() 16 | return context.done(error, response) 17 | } 18 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Lib 3 | */ 4 | 5 | const Promise = require('bluebird') 6 | const nodemailer = require('nodemailer') 7 | const reports = require('./reports') 8 | const handlebars = require('handlebars') 9 | const emailTemplates = require('./templates/email') 10 | 11 | module.exports.sendReports = async function () { 12 | if ( 13 | !process.env.EMAIL_SERVICE_HOST || 14 | !process.env.EMAIL_SERVICE_USER || 15 | !process.env.EMAIL_SERVICE_PASS || 16 | !process.env.EMAIL_FROM || 17 | !process.env.EMAIL_TO 18 | ) { 19 | return { error: 'ENV vars are not correctly set' } 20 | } 21 | 22 | const getReports = () => { 23 | return new Promise((resolve) => { 24 | reports.createReports((results) => { 25 | resolve({ results }) 26 | }) 27 | }) 28 | } 29 | 30 | const { error, data } = await getReports() 31 | 32 | const mailOptions = { 33 | from: process.env.EMAIL_FROM, 34 | to: process.env.EMAIL_TO, 35 | template: 'email.handlebars', 36 | subject: 'Reports', 37 | context: { 38 | name: 'Admin', 39 | usernames: data, 40 | }, 41 | } 42 | 43 | const template = handlebars.compile(emailTemplates.reports) 44 | mailOptions.html = template(mailOptions.context) 45 | 46 | const transporter = nodemailer.createTransport({ 47 | host: process.env.EMAIL_SERVICE_HOST, 48 | port: process.env.EMAIL_SERVICE_PORT, 49 | secure: false, 50 | auth: { 51 | user: process.env.EMAIL_SERVICE_USER, 52 | pass: process.env.EMAIL_SERVICE_PASS, 53 | }, 54 | }) 55 | 56 | Promise.promisifyAll(transporter) 57 | 58 | const sendMail = (mailOptions) => { 59 | return new Promise((resolve) => { 60 | transporter.sendMail(mailOptions, function (error) { 61 | resolve({ error }) 62 | }) 63 | }) 64 | } 65 | 66 | const { error } = await sendMail(mailOptions) 67 | 68 | if (error) { 69 | return { error } 70 | } 71 | return { success: 'Email sent: ' + mailOptions.html } 72 | } 73 | -------------------------------------------------------------------------------- /lib/reports.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql') 2 | 3 | module.exports.createReports = async function () { 4 | const pool = mysql.createPool({ 5 | connectionLimit: 5, 6 | host: process.env.DATABASE_HOST, 7 | user: process.env.DATABASE_USER, 8 | password: process.env.DATABASE_PASS, 9 | database: process.env.DATABASE_DB_NAME, 10 | }) 11 | 12 | const getDatabaseResults = (pool) => { 13 | return new Promise((resolve) => { 14 | pool.query('SELECT username FROM auth_user', function ( 15 | error, 16 | rows, 17 | fields, 18 | ) { 19 | resolve({ error, rows, fields }) 20 | }) 21 | }) 22 | } 23 | 24 | const { error, rows } = await getDatabaseResults(pool) 25 | 26 | pool.end(function (_) { 27 | // All connections in the pool have ended 28 | }); 29 | 30 | if (error) { 31 | return { error }; 32 | } else { 33 | return { data: rows }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/templates/email.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports.reports = "\ 3 |
A list of users in your database:
\ 5 |\
6 | {{#each usernames}}\
7 | {{username}}
\
8 | {{/each}}\
9 |
---
\ 11 | "; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_npmOperationalInternal": { 3 | "host": "packages-13-west.internal.npmjs.com", 4 | "tmp": "tmp/node-serverless-reports-0.2.1.tgz_1458892667270_0.7738919164985418" 5 | }, 6 | "author": { 7 | "name": "Richard Dancsi" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/wimagguc/node-serverless-reports" 11 | }, 12 | "dependencies": { 13 | "bluebird": "^3.4.0", 14 | "handlebars": "^4.0.5", 15 | "mysql": "^2.10.2", 16 | "nodemailer": "^2.4.2" 17 | }, 18 | "description": "A Serverless - Node.js project to create reports from database queries, and send those reports out in pretty emails", 19 | "devDependencies": { 20 | "serverless": "^2.16.1", 21 | "serverless-optimizer-plugin": "^2.1.0" 22 | }, 23 | "homepage": "https://www.wimagguc.com/", 24 | "license": "MIT", 25 | "name": "node-serverless-reports", 26 | "optionalDependencies": {}, 27 | "private": true, 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/wimagguc/node-serverless-reports.git" 31 | }, 32 | "scripts": {}, 33 | "version": "1.0.0" 34 | } 35 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | service: node-serverless-reports 2 | 3 | provider: 4 | name: aws 5 | runtime: nodejs12.x 6 | stage: dev 7 | 8 | functions: 9 | email: 10 | handler: handler.handler 11 | 12 | events: 13 | # Will send a new message every morning at 8:05 14 | - schedule: cron(5 8 * * ? *) 15 | 16 | environment: 17 | stage: dev 18 | 19 | EMAIL_SERVICE_HOST: ${env:EMAIL_SERVICE_HOST} 20 | EMAIL_SERVICE_USER: ${env:EMAIL_SERVICE_USER} 21 | EMAIL_SERVICE_PASS: ${env:EMAIL_SERVICE_PASS} 22 | EMAIL_SERVICE_PORT: ${env:EMAIL_SERVICE_PORT} 23 | EMAIL_FROM: ${env:EMAIL_FROM} 24 | EMAIL_TO: ${env:EMAIL_TO} 25 | 26 | DATABASE_HOST: ${env:DATABASE_HOST} 27 | DATABASE_USER: ${env:DATABASE_USER} 28 | DATABASE_PASS: ${env:DATABASE_PASS} 29 | DATABASE_DB_NAME: ${env:DATABASE_DB_NAME} 30 | --------------------------------------------------------------------------------