From 03271573be50631de75d08a9f0b3dc31f6a98f85 Mon Sep 17 00:00:00 2001 From: baldo Date: Fri, 20 May 2016 22:11:35 +0200 Subject: [PATCH] Added sqlite db and email queue. --- config.json.example | 9 ++- package.json | 2 + server/config.js | 6 +- server/db/database.js | 79 +++++++++++++++++++ .../db/patches/001_add-email-queue-table.sql | 11 +++ server/main.js | 11 ++- server/services/mailService.js | 20 +++++ server/services/nodeService.js | 43 +++++++++- 8 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 server/db/database.js create mode 100644 server/db/patches/001_add-email-queue-table.sql create mode 100644 server/services/mailService.js diff --git a/config.json.example b/config.json.example index 38aae1e..7abaacf 100644 --- a/config.json.example +++ b/config.json.example @@ -2,7 +2,11 @@ "server": { "baseUrl": "http://localhost:8080", "port": 8080, - "peersPath": "/tmp/peers" + "peersPath": "/tmp/peers", + + "email": { + "from": "no-reply@musterstadt.freifunk.net" + } }, "client": { "community": { @@ -14,9 +18,6 @@ "graphUrl": "http://graph.hamburg.freifunk.net/graph.html", "mapUrl": "http://graph.hamburg.freifunk.net/geomap.html" }, - "monitoring": { - "enabled": true - }, "coordsSelector": { "lat": 53.565278, "lng": 10.001389, diff --git a/package.json b/package.json index 3abdba6..42147e5 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "license": "MIT", "dependencies": {}, "devDependencies": { + "async": "~1.5.2", "body-parser": "~1.15.1", "compression": "~1.6.2", "deep-extend": "~0.4.1", @@ -40,6 +41,7 @@ "lodash": "~4.12.0", "ng-di": "~0.2.1", "serve-static": "~1.10.2", + "sqlite3": "~3.1.4", "time-grunt": "~1.3.0" }, "engines": { diff --git a/server/config.js b/server/config.js index 1fb994b..f423fe2 100644 --- a/server/config.js +++ b/server/config.js @@ -5,7 +5,11 @@ angular.module('ffffng').factory('config', function (fs, deepExtend) { server: { baseUrl: 'http://localhost:8080', port: 8080, - peersPath: '/tmp/peers' + peersPath: '/tmp/peers', + + email: { + from: 'no-reply@musterstadt.freifunk.net' + } }, client: { community: { diff --git a/server/db/database.js b/server/db/database.js new file mode 100644 index 0000000..71f233d --- /dev/null +++ b/server/db/database.js @@ -0,0 +1,79 @@ +'use strict'; + +var async = require('async'); +var fs = require('fs'); +var glob = require('glob'); +var path = require('path'); + +function applyPatch(db, file, callback) { + fs.readFile(file, function (err, contents) { + if (err) { + return callback(err); + } + + var version = path.basename(file, '.sql'); + + db.get('SELECT * FROM schema_version WHERE version = ?', version, function (err, row) { + if (err) { + return callback(err); + } + + if (row) { + // patch is already applied. skip! + return callback(null); + } + + var sql = 'BEGIN TRANSACTION;\n' + + contents.toString() + '\n' + + 'INSERT INTO schema_version (version) VALUES (\'' + version + '\');\n' + + 'END TRANSACTION;'; + + db.exec(sql, callback); + }); + }); +} + +function applyMigrations(db, callback) { + var sql = 'BEGIN TRANSACTION; CREATE TABLE IF NOT EXISTS schema_version (\n' + + ' version VARCHAR(255) PRIMARY KEY ASC,\n' + + ' applied_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL\n' + + '); END TRANSACTION;'; + db.exec(sql, function (err) { + if (err) { + return callback(err); + } + + glob(__dirname + '/patches/*.sql', function (err, files) { + if (err) { + return callback(err); + } + + async.each( + files, + function (file, fileCallback) { + applyPatch(db, file, fileCallback); + }, + callback + ); + }); + }); +} + +module.exports = { + init: function (callback) { + var SQLite3 = require('sqlite3'); + var db = new SQLite3.Database('/tmp/test.sqlite'); + + applyMigrations(db, function (err) { + if (err) { + throw err; + } + + angular.module('ffffng').factory('Database', function () { + return db; + }); + + callback(); + }); + } +}; diff --git a/server/db/patches/001_add-email-queue-table.sql b/server/db/patches/001_add-email-queue-table.sql new file mode 100644 index 0000000..54ce16a --- /dev/null +++ b/server/db/patches/001_add-email-queue-table.sql @@ -0,0 +1,11 @@ +CREATE TABLE email_queue ( + id INTEGER PRIMARY KEY ASC AUTOINCREMENT, + failures INTEGER NOT NULL, + + sender VARCHAR(255) NOT NULL, + recipient VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL, + data TEXT NOT NULL, + + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL +); diff --git a/server/main.js b/server/main.js index a18b307..081e776 100644 --- a/server/main.js +++ b/server/main.js @@ -19,15 +19,18 @@ require('./utils/strings'); require('./resources/nodeResource'); require('./resources/monitoringResource'); +require('./services/mailService'); require('./services/nodeService'); require('./services/monitoringService'); require('../shared/validation/constraints'); require('./validation/validator'); -angular.injector(['ffffng']).invoke(function (config, app, Router) { - Router.init(); +require('./db/database').init(function () { + angular.injector(['ffffng']).invoke(function (config, app, Router) { + Router.init(); - app.listen(config.server.port, '::'); - module.exports = app; + app.listen(config.server.port, '::'); + module.exports = app; + }); }); diff --git a/server/services/mailService.js b/server/services/mailService.js new file mode 100644 index 0000000..88c5209 --- /dev/null +++ b/server/services/mailService.js @@ -0,0 +1,20 @@ +'use strict'; + +angular.module('ffffng') +.service('MailService', function (Database, _) { + return { + enqueue: function (sender, recipient, email, data, callback) { + if (!_.isPlainObject(data)) { + return callback(new Error('Unexpected data: ' + data)); + } + Database.run( + 'INSERT INTO email_queue (failures, sender, recipient, email, data) VALUES (?, ?, ?, ?, ?)', + [0, sender, recipient, email, JSON.stringify(data)], + function (err, res) { + debugger; + callback(err, res); + } + ); + } + }; +}); diff --git a/server/services/nodeService.js b/server/services/nodeService.js index 6b20010..2b33397 100644 --- a/server/services/nodeService.js +++ b/server/services/nodeService.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('ffffng') -.service('NodeService', function (config, _, crypto, fs, glob, Strings, ErrorTypes) { +.service('NodeService', function (config, _, crypto, fs, glob, MailService, Strings, ErrorTypes) { var linePrefixes = { hostname: '# Knotenname: ', nickname: '# Ansprechpartner: ', @@ -196,6 +196,31 @@ angular.module('ffffng') return parseNodeFile(file, callback); } + function sendMonitoringConfirmationMail(node, nodeSecrets, callback) { + var monitoringQueryString = '?mac=' + node.mac + '&token=' + nodeSecrets.monitoringToken; + var confirmUrl = config.server.baseUrl + '/#!/monitoring/confirm' + monitoringQueryString; + var disableUrl = config.server.baseUrl + '/#!/monitoring/disable' + monitoringQueryString; + + MailService.enqueue( + config.server.email.from, + node.email, + 'monitoring-confirmation', + { + node: node, + confirmUrl: confirmUrl, + disableUrl: disableUrl + }, + function (err) { + if (err) { + console.log(err); + return callback({data: 'Internal error.', type: ErrorTypes.internalError}); + } + + callback(null); + } + ); + } + return { createNode: function (node, callback) { var token = generateToken(); @@ -213,7 +238,13 @@ angular.module('ffffng') } if (node.monitoring && !node.monitoringConfirmed) { - // TODO: Send mail... + return sendMonitoringConfirmationMail(node, nodeSecrets, function (err) { + if (err) { + return callback(err); + } + + return callback(null, token, node); + }); } return callback(null, token, node); @@ -260,7 +291,13 @@ angular.module('ffffng') } if (node.monitoring && !node.monitoringConfirmed) { - // TODO: Send mail... + return sendMonitoringConfirmationMail(node, nodeSecrets, function (err) { + if (err) { + return callback(err); + } + + return callback(null, token, node); + }); } return callback(null, token, node);