From 418df5b00d73ea9f11a9ed7e7f903e2671623040 Mon Sep 17 00:00:00 2001 From: Lucas Pirola Date: Tue, 15 Dec 2015 20:35:44 -0200 Subject: [PATCH] Add dist version to repo --- .gitignore | 1 - dist/app.js | 121 +++++++++++++++++++ dist/client/index.js | 50 ++++++++ dist/models/datasource.js | 23 ++++ dist/models/index.js | 44 +++++++ dist/modules/check.js | 74 ++++++++++++ dist/modules/datasource.js | 106 +++++++++++++++++ dist/modules/mailer.js | 80 +++++++++++++ dist/modules/process.js | 108 +++++++++++++++++ dist/modules/queue.js | 89 ++++++++++++++ dist/modules/rules/index.js | 171 +++++++++++++++++++++++++++ dist/modules/rules/onConfirmation.js | 94 +++++++++++++++ dist/modules/rules/onRegister.js | 99 ++++++++++++++++ dist/routes/datasources.js | 56 +++++++++ dist/routes/index.js | 20 ++++ dist/server.js | 102 ++++++++++++++++ package.json | 1 - 17 files changed, 1237 insertions(+), 2 deletions(-) create mode 100644 dist/app.js create mode 100644 dist/client/index.js create mode 100644 dist/models/datasource.js create mode 100644 dist/models/index.js create mode 100644 dist/modules/check.js create mode 100644 dist/modules/datasource.js create mode 100644 dist/modules/mailer.js create mode 100644 dist/modules/process.js create mode 100644 dist/modules/queue.js create mode 100644 dist/modules/rules/index.js create mode 100644 dist/modules/rules/onConfirmation.js create mode 100644 dist/modules/rules/onRegister.js create mode 100644 dist/routes/datasources.js create mode 100644 dist/routes/index.js create mode 100644 dist/server.js diff --git a/.gitignore b/.gitignore index d5ccb23..24b8ddd 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ coverage # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release -dist/ # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules diff --git a/dist/app.js b/dist/app.js new file mode 100644 index 0000000..d544abb --- /dev/null +++ b/dist/app.js @@ -0,0 +1,121 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _express = require('express'); + +var _express2 = _interopRequireDefault(_express); + +var _path = require('path'); + +var _path2 = _interopRequireDefault(_path); + +var _serveFavicon = require('serve-favicon'); + +var _serveFavicon2 = _interopRequireDefault(_serveFavicon); + +var _morgan = require('morgan'); + +var _morgan2 = _interopRequireDefault(_morgan); + +var _cookieParser = require('cookie-parser'); + +var _cookieParser2 = _interopRequireDefault(_cookieParser); + +var _bodyParser = require('body-parser'); + +var _bodyParser2 = _interopRequireDefault(_bodyParser); + +var _browserifyMiddleware = require('browserify-middleware'); + +var _browserifyMiddleware2 = _interopRequireDefault(_browserifyMiddleware); + +var _stylus = require('stylus'); + +var _stylus2 = _interopRequireDefault(_stylus); + +var _jeet = require('jeet'); + +var _jeet2 = _interopRequireDefault(_jeet); + +var _kue = require('kue'); + +var _kue2 = _interopRequireDefault(_kue); + +var _modulesQueue = require('./modules/queue'); + +var _modulesQueue2 = _interopRequireDefault(_modulesQueue); + +var _routesIndex = require('./routes/index'); + +var _routesIndex2 = _interopRequireDefault(_routesIndex); + +var _routesDatasources = require('./routes/datasources'); + +var _routesDatasources2 = _interopRequireDefault(_routesDatasources); + +_modulesQueue2['default'].init(); + +var app = (0, _express2['default'])(); + +// view engine setup +app.set('views', _path2['default'].join(__dirname, 'views')); +app.set('view engine', 'jade'); + +// uncomment after placing your favicon in /public +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); +app.use((0, _morgan2['default'])('dev')); +app.use(_bodyParser2['default'].json()); +app.use(_bodyParser2['default'].urlencoded({ extended: false })); +app.use((0, _cookieParser2['default'])()); +app.use(_stylus2['default'].middleware({ + src: __dirname + '/stylus', + dest: __dirname + '/public', + compile: function compile(str, path) { + return (0, _stylus2['default'])(str).set('filename', path).set('compress', true).use((0, _jeet2['default'])())['import']('jeet'); + } +})); +app.use(_express2['default']['static'](_path2['default'].join(__dirname, 'public'))); +app.get('/main.js', (0, _browserifyMiddleware2['default'])(__dirname + '/client/index.js')); + +app.use('/fila', _kue2['default'].app); +app.use('/', _routesIndex2['default']); +app.use('/datasources', _routesDatasources2['default']); + +// catch 404 and forward to error handler +app.use(function (req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handlers + +// development error handler +// will print stacktrace +if (app.get('env') === 'development') { + app.use(function (err, req, res, next) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: err + }); + }); +} + +// production error handler +// no stacktraces leaked to user +app.use(function (err, req, res, next) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: {} + }); +}); + +exports['default'] = app; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/client/index.js b/dist/client/index.js new file mode 100644 index 0000000..9a38eb9 --- /dev/null +++ b/dist/client/index.js @@ -0,0 +1,50 @@ +'use strict'; + +var m = require('mithril'); + +var Datasource = function Datasource(data) { + data = data || { id: '', name: '', key: '', interval_update: '' }; + this.id = m.prop(data.id); + this.name = m.prop(data.name); + this.key = m.prop(data.key); + this.interval_update = m.prop(data.interval_update); +}; +Datasource.list = function (data) { + return m.request({ method: "GET", url: "/datasources", data: data }); +}; +Datasource.save = function (data) { + return m.request({ method: "POST", url: "/datasources", data: data }); +}; + +var DatasourceForm = { + controller: function controller(args) { + this.ds = m.prop(args.ds || new Datasource()); + }, + view: function view(ctrl, args) { + var ds = ctrl.ds(); + + return m('.teste', [m('h1', 'Processador de inscrições (beta)'), m('.half', [m('.pure-form.pure-form-aligned', [m('h2', 'Adicionar planilha'), m('.pure-control-group', [m('label', 'Nome'), m("input", { onchange: m.withAttr("value", ds.name), value: ds.name() })]), m('.pure-control-group', [m('label', 'Chave da planilha no Google Drive'), m("input[placeholder=Ex.: 1gKGxto-RDqS5k2F3TbLXnOoj6IB6RFp18K_MUzBP_Hw]", { onchange: m.withAttr("value", ds.key), value: ds.key() })]), m('.pure-control-group', [m('label', 'Intervalo atualização (min)'), m("input", { onchange: m.withAttr("value", ds.interval_update), value: ds.interval_update() })]), m('.pure-controls', [m("button.pure-button.pure-button-primary", { onclick: args.onsave.bind(this, ds) }, "Salvar")])])])]); + } +}; + +var DatasourceList = { + view: function view(ctrl, args) { + return m('.half.active-spreadsheets', [m('h2', 'Planilhas ativas'), m("table", [args.ds().map(function (ds) { + return m("tr", [m("td", ds.id), m("td", ds.name), m("td", ds.key), m("td", ds.interval_update)]); + })])]); + } +}; + +var Home = { + controller: function update() { + this.datasources = Datasource.list(); + this.save = (function (ds) { + Datasource.save(ds).then(update.bind(this)); + }).bind(this); + }, + view: function view(ctrl) { + return [m.component(DatasourceForm, { onsave: ctrl.save }), m.component(DatasourceList, { ds: ctrl.datasources })]; + } +}; + +m.mount(document.body, Home); \ No newline at end of file diff --git a/dist/models/datasource.js b/dist/models/datasource.js new file mode 100644 index 0000000..f289de6 --- /dev/null +++ b/dist/models/datasource.js @@ -0,0 +1,23 @@ +"use strict"; + +module.exports = function (sequelize, DataTypes) { + var Datasource = sequelize.define("Datasource", { + name: DataTypes.STRING, + key: DataTypes.STRING, + interval_update: DataTypes.INTEGER, + user_id: DataTypes.STRING + }, { + // classMethods: { + // associate: function(models) { + // Task.belongsTo(models.User, { + // onDelete: "CASCADE", + // foreignKey: { + // allowNull: false + // } + // }); + // } + // } + }); + + return Datasource; +}; \ No newline at end of file diff --git a/dist/models/index.js b/dist/models/index.js new file mode 100644 index 0000000..5eefc25 --- /dev/null +++ b/dist/models/index.js @@ -0,0 +1,44 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +var _fs = require("fs"); + +var _fs2 = _interopRequireDefault(_fs); + +var _path = require("path"); + +var _path2 = _interopRequireDefault(_path); + +var _sequelize = require("sequelize"); + +var _sequelize2 = _interopRequireDefault(_sequelize); + +// https://github.com/sequelize/express-example/blob/master/models/index.js + +var db_url = process.env.DATABASE_URL || "mysql://root@127.0.0.1:/processador-inscricao-evento"; +var sequelize = new _sequelize2["default"](db_url); +var db = {}; + +_fs2["default"].readdirSync(__dirname).filter(function (file) { + return file.indexOf(".") !== 0 && file !== "index.js"; +}).forEach(function (file) { + var model = sequelize["import"](_path2["default"].join(__dirname, file)); + db[model.name] = model; +}); + +Object.keys(db).forEach(function (modelName) { + if ("associate" in db[modelName]) { + db[modelName].associate(db); + } +}); + +db.sequelize = sequelize; +db.Sequelize = _sequelize2["default"]; + +exports["default"] = db; +module.exports = exports["default"]; \ No newline at end of file diff --git a/dist/modules/check.js b/dist/modules/check.js new file mode 100644 index 0000000..cfbabca --- /dev/null +++ b/dist/modules/check.js @@ -0,0 +1,74 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var _datasource = require('./datasource'); + +var _datasource2 = _interopRequireDefault(_datasource); + +var _mailer = require('./mailer'); + +var _mailer2 = _interopRequireDefault(_mailer); + +var _async = require('async'); + +var _async2 = _interopRequireDefault(_async); + +var Check = (function () { + function Check() { + _classCallCheck(this, Check); + + this.DS = new _datasource2['default'](); + this.ML = new _mailer2['default'](); + this.validate = false; + } + + _createClass(Check, [{ + key: 'setMailer', + value: function setMailer(mailer) { + this.ML = mailer; + } + }, { + key: 'isValid', + value: function isValid() { + var callback = arguments.length <= 0 || arguments[0] === undefined ? function (err, results) {} : arguments[0]; + + var that = this; + + if (!this.DS.isConfigEmpty()) { + callback('As configurações da fonte de dados não foram informados'); + } else if (!this.ML.isConfigEmpty()) { + callback('As configurações do envio do email não foram informados'); + } else { + // valida datasource + _async2['default'].series([function (done) { + that.DS.testConnection(done); + }, function (done) { + that.DS.readContent(done); + }, function (done) { + that.ML.testSend(done); + }], function (err, results) { + if (!err) { + that.validate = true; + callback(null, ['-> Checagem de conexão com a planilha ok.', '-> Checagem de envio de e-mail ok.'].join('\n')); + } else { + callback(err.toString()); + } + }); + } + } + }]); + + return Check; +})(); + +exports['default'] = Check; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/modules/datasource.js b/dist/modules/datasource.js new file mode 100644 index 0000000..c1d8f30 --- /dev/null +++ b/dist/modules/datasource.js @@ -0,0 +1,106 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var _googleSpreadsheet = require('google-spreadsheet'); + +var _googleSpreadsheet2 = _interopRequireDefault(_googleSpreadsheet); + +var _async = require('async'); + +var _async2 = _interopRequireDefault(_async); + +// TODO: melhorar trafego das mensagens de erro e acerto para fora da classe + +var Datasource = (function () { + function Datasource() { + _classCallCheck(this, Datasource); + + this.google_spreadsheet_key = process.env['GOOGLE_SPREADSHEET_KEY']; + this.creds = null; + this.validate = false; + if (process.env['GOOGLE_CREDS']) { + this.creds = JSON.parse(process.env['GOOGLE_CREDS']); + } + } + + _createClass(Datasource, [{ + key: 'isConfigEmpty', + value: function isConfigEmpty() { + if (!this.google_spreadsheet_key) { + return false; + } + return true; + } + }, { + key: 'testConnection', + value: function testConnection(callback) { + var doc = new _googleSpreadsheet2['default'](this.google_spreadsheet_key); + _async2['default'].series([function (done) { + doc.getInfo(function (err, results) { + if (err) { + done('As configurações fornecidas para fonte de dados não são válidos' + err, null); + } else { + done(null, results); + } + }); + }], callback); + } + }, { + key: 'readContent', + value: function readContent(callback) { + var doc = new _googleSpreadsheet2['default'](this.google_spreadsheet_key); + var worksheet_id = ''; + var that = this; + _async2['default'].waterfall([ + // Tenta autenticar com credenciais do ambiente + function (done) { + if (that.creds) { + doc.useServiceAccountAuth(that.creds, done); + } else { + done(null); + } + }, + // Testa conexão e retorna infos básicas da planilha + function (done) { + doc.getInfo(function (err, results) { + if (err) { + done('As configurações fornecidas para fonte de dados não são válidos' + err, null); + } else { + worksheet_id = results.worksheets[0].id; + that.validate = true; + done(null, results); + } + }); + }, + // Lê conteúdo e certifica-se que planilha não está vazia + function (sheetinfo, done) { + doc.getRows(worksheet_id, {}, function (err, results) { + if (err) { + done('Problema ao tentar ler detalhes da planilha' + err, null); + } else { + if (parseInt(results.length) <= 1) { + done('Datasource não pode ser vazio.'); + } else { + that.content = results; + done(null, results); + } + } + }); + }], callback); + } + }]); + + return Datasource; +})(); + +exports['default'] = Datasource; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/modules/mailer.js b/dist/modules/mailer.js new file mode 100644 index 0000000..561556b --- /dev/null +++ b/dist/modules/mailer.js @@ -0,0 +1,80 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var _nodemailer = require('nodemailer'); + +var _nodemailer2 = _interopRequireDefault(_nodemailer); + +var Mailer = (function () { + function Mailer() { + _classCallCheck(this, Mailer); + + this.mail_service = process.env['MAIL_SERVICE']; + this.mail_user = process.env['MAIL_USER']; + this.mail_pass = process.env['MAIL_PASS']; + this.validate = false; + + this.transporter = _nodemailer2['default'].createTransport({ + service: this.mail_service, + auth: { + user: this.mail_user, + pass: this.mail_pass + } + }, { + // default values for sendMail method + from: 'Fórum Social Porto Alegre ', + replyTo: 'espaco.fsm.poa@gmail.com' + }); + } + + _createClass(Mailer, [{ + key: 'setTransporter', + value: function setTransporter(transporter) { + this.transporter = transporter; + } + }, { + key: 'isConfigEmpty', + value: function isConfigEmpty() { + if (!this.mail_service || !this.mail_user || !this.mail_pass) { + return false; + } + return true; + } + }, { + key: 'send', + value: function send(to, subject, content, done) { + var that = this; + return this.transporter.sendMail({ + to: to, + subject: subject, + text: content + }, function (err, info) { + if (err) { + return done('Não foi possível enviar o email de teste.', null); + } else { + that.validate = true; + return done(null, info.response.toString()); + } + }); + } + }, { + key: 'testSend', + value: function testSend(done) { + return this.send('lucaspirola@gmail.com', 'hello', 'hello world!', done); + } + }]); + + return Mailer; +})(); + +exports['default'] = Mailer; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/modules/process.js b/dist/modules/process.js new file mode 100644 index 0000000..515a4b2 --- /dev/null +++ b/dist/modules/process.js @@ -0,0 +1,108 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var _check = require('./check'); + +var _check2 = _interopRequireDefault(_check); + +var _datasource = require('./datasource'); + +var _datasource2 = _interopRequireDefault(_datasource); + +var _async = require('async'); + +var _async2 = _interopRequireDefault(_async); + +var _mailer = require('./mailer'); + +var _mailer2 = _interopRequireDefault(_mailer); + +var _rulesIndex = require('./rules/index'); + +var _rulesIndex2 = _interopRequireDefault(_rulesIndex); + +var Process = (function () { + function Process() { + _classCallCheck(this, Process); + + this.CK = new _check2['default'](); + this.DS = new _datasource2['default'](); + this.setMailer(); + this._rule = new _rulesIndex2['default']([]); + this.finished = false; + } + + _createClass(Process, [{ + key: 'setMailer', + value: function setMailer() { + var mailer = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0]; + + if (!mailer) { + mailer = new _mailer2['default'](); + } + this.ML = mailer; + this.CK.setMailer(mailer); + } + }, { + key: 'check', + value: function check(done) { + this.CK.isValid(done); + } + }, { + key: 'run', + value: function run() { + var callback = arguments.length <= 0 || arguments[0] === undefined ? function (err, results) {} : arguments[0]; + + var that = this; + _async2['default'].waterfall([function (done) { + that.readDatasource(done); + }, function (sheet_content, done) { + var r = that.getRule(); + that.parseRule(r, sheet_content, done); + }], function (err, results) { + if (!err) { + that.finished = true; + callback(null, ['-> Processamento finalizado com sucesso.'].join('\n')); + } else { + callback(['-> ' + err].join('\n')); + } + }); + } + }, { + key: 'readDatasource', + value: function readDatasource(done) { + this.DS.readContent(done); + } + }, { + key: 'parseRule', + value: function parseRule(r, sheet_content, done) { + r.setRows(sheet_content); + r.setMailer(this.ML); + r.validate(done); + } + }, { + key: 'setRule', + value: function setRule(rule) { + this._rule = rule; + } + }, { + key: 'getRule', + value: function getRule() { + return this._rule; + } + }]); + + return Process; +})(); + +exports['default'] = Process; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/modules/queue.js b/dist/modules/queue.js new file mode 100644 index 0000000..af00c1c --- /dev/null +++ b/dist/modules/queue.js @@ -0,0 +1,89 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _check = require('./check'); + +var _check2 = _interopRequireDefault(_check); + +var _process = require('./process'); + +var _process2 = _interopRequireDefault(_process); + +var _rulesOnRegister = require('./rules/onRegister'); + +var _rulesOnRegister2 = _interopRequireDefault(_rulesOnRegister); + +var _rulesOnConfirmation = require('./rules/onConfirmation'); + +var _rulesOnConfirmation2 = _interopRequireDefault(_rulesOnConfirmation); + +var _kue = require('kue'); + +var _kue2 = _interopRequireDefault(_kue); + +var _models = require('../models'); + +var _models2 = _interopRequireDefault(_models); + +var redis_url = process.env['REDIS_URL'] || 'redis://127.0.0.1:6379'; +var queue = _kue2['default'].createQueue({ redis: redis_url }); +var jobs = { + createRegister: function createRegister(ds) { + var j = queue.create('register', { + id: ds.id, + title: 'Verificando inscritos que não receberam boleto: ' + ds.name + }).delay(parseInt(ds.interval_update)).save(); + }, + processRegister: function processRegister(job, done) { + if (job.data.id == undefined) { + _models2['default'].Datasource.findAll({}).then(function (dss) { + dss.forEach(jobs.createRegister); + }); + done(); + } else { + _models2['default'].Datasource.findById(job.data.id).then(function (ds) { + jobs.createRegister(ds); + process.env['GOOGLE_SPREADSHEET_KEY'] = ds.key; + var prc = new _process2['default'](); + prc.setRule(new _rulesOnRegister2['default']()); + prc.run(done); + }); + } + }, + createConfirm: function createConfirm(ds) { + queue.create('confirm', { + id: ds.id, + title: 'Confirmando inscritos que já pagaram: ' + ds.name + }).delay(parseInt(ds.interval_update)).save(); + }, + processConfirm: function processConfirm(job, done) { + if (job.data.id == undefined) { + _models2['default'].Datasource.findAll({}).then(function (dss) { + dss.forEach(jobs.createConfirm); + }); + done(); + } else { + _models2['default'].Datasource.findById(job.data.id).then(function (ds) { + jobs.createConfirm(ds); + process.env['GOOGLE_SPREADSHEET_KEY'] = ds.key; + var prc = new _process2['default'](); + prc.setRule(new _rulesOnConfirmation2['default']()); + prc.run(done); + }); + } + }, + init: function init() { + var jobR = queue.create('register', { title: 'Iniciando verificação registros.' }).save(); + var jobC = queue.create('confirm', { title: 'Iniciando confirmação inscritos.' }).save(); + queue.process('register', jobs.processRegister); + queue.process('confirm', jobs.processConfirm); + } +}; + +exports['default'] = jobs; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/modules/rules/index.js b/dist/modules/rules/index.js new file mode 100644 index 0000000..48a1ddc --- /dev/null +++ b/dist/modules/rules/index.js @@ -0,0 +1,171 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var _async = require('async'); + +var _async2 = _interopRequireDefault(_async); + +var _mailer = require('./../mailer'); + +var _mailer2 = _interopRequireDefault(_mailer); + +/** + * Implementa a de validação de e-mail, execução de ações de acordo com o filtro definido + * e deve ser extendida na criação de novas regras + */ + +var Rule = (function () { + /** + * @param {SpreadsheetRow[]} rows - Lista de linhas disponíveis para verificação + * @construct + */ + + function Rule() { + var rows = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; + + _classCallCheck(this, Rule); + + this.rows = rows; + this.ML = new _mailer2['default'](); + this.valid = false; + + this._actions = []; + } + + /** + * Valida o e-mail presente na linha da planilha em análise + * @param {string[]} row - Linha da planilha contendo informações do participante + * @returns {Boolean} - retorna verdadeiro se e-mail for inválido, + * truque para ação ser executada filtro é inválido + * @abstract + */ + + _createClass(Rule, [{ + key: 'filter', + value: function filter(row) { + var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + if (re.test(row['e-mail'].trim())) { + return false; + } + return true; + } + + /** + * Executa ações previamente adicionadas na regra em execução + * @param {Spreadsheetrow[]} row - linha que será passada para as ações + * @param {Function} done2 - callback + * @abstract + */ + }, { + key: 'action', + value: function action(row, done2) { + var that = this; + _async2['default'].eachSeries(that.getActions(), function (action, done) { + that[action](row, done); + }, done2); + } + + /** + * Filtra todas as linhas da planilha e executa ação nas que passarem pelo filtro + * @param {Function} done2 - callback + * @public + */ + }, { + key: 'validate', + value: function validate(done2) { + var that = this; + that.addActions(); + _async2['default'].eachSeries(that.rows, function (row, done) { + if (that.filter(row)) { + that.action(row, done); + } else { + that.valid = true; + done(null, row); + } + }, done2); + } + + /** + * Marca linha da planilha como inválida + * @param {Spreadsheetrow[]} row - linha que será passada para as ações + * @param {Function} done2 - callback + * @protected + */ + }, { + key: 'invalidateSubscriber', + value: function invalidateSubscriber(row, done) { + row.status = 'Inválida'; + row.save(function (err, results) { + done('E-mail inválido encontrado: ' + row['e-mail']); + }); + } + + /** + * Envia e-mail para organizador avisando que foi encontrado e-mail inválido na planilha + * @param {Spreadsheetrow[]} row - linha que será passada para as ações + * @param {Function} done2 - callback + * @protected + */ + }, { + key: 'warningOrganizer', + value: function warningOrganizer(row, done) { + this.ML.send('lucaspirola@gmail.com', 'email inválido encontrado na planilha', 'conteúdo da planilha', done); + } + + /** + * Adiciona ações a serem executadas para essa regra + * @abstract + */ + }, { + key: 'addActions', + value: function addActions() { + this._actions.push('warningOrganizer'); + this._actions.push('invalidateSubscriber'); + } + + /** + * Retorna ações adicionadas + * @returns {string[]} - ações disponíveis + * @public + */ + }, { + key: 'getActions', + value: function getActions() { + return this._actions; + } + + /** + * Configura módulo envio de e-mail + * @param {Mailer} mailer - Classe que implementa método send + */ + }, { + key: 'setMailer', + value: function setMailer(mailer) { + this.ML = mailer; + } + + /** + * Define conteúdo a ser usado como fonte de dados + * @param {Object[]} content - Conteúdo a ser usado nos filtros e ações + */ + }, { + key: 'setRows', + value: function setRows(content) { + this.rows = content; + } + }]); + + return Rule; +})(); + +exports['default'] = Rule; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/modules/rules/onConfirmation.js b/dist/modules/rules/onConfirmation.js new file mode 100644 index 0000000..88a4f44 --- /dev/null +++ b/dist/modules/rules/onConfirmation.js @@ -0,0 +1,94 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var _index = require('./index'); + +var _index2 = _interopRequireDefault(_index); + +var _async = require('async'); + +var _async2 = _interopRequireDefault(_async); + +/** + * Implementa verificação do participante se já pagou boleto, + * se verdadeiro, faz envio de confirmação e mudança de status na planilha + */ + +var Confirmation = (function (_Rules) { + _inherits(Confirmation, _Rules); + + function Confirmation() { + _classCallCheck(this, Confirmation); + + _get(Object.getPrototypeOf(Confirmation.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(Confirmation, [{ + key: 'addActions', + value: function addActions() { + this._actions.push('markSubscriberMakePayment'); + this._actions.push('sendConfirmationMessage'); + } + + /** + * Verifica se participante está marcado como quem pagou boleto + * @param {string[]} row - Linha da planilha contendo informações do participante + * @returns {Boolean} - + */ + }, { + key: 'filter', + value: function filter(row) { + // pegadinha com "!" por causa da validação por e-mail + return !_get(Object.getPrototypeOf(Confirmation.prototype), 'filter', this).call(this, row) && row['status'] === 'Boleto Pago'; + } + + /** + * Envia por e-mail mensagem de confirmação para participante + * @param {Spreadsheetrow[]} row - linha que será passada para as ações + * @param {Function} done2 - callback + */ + }, { + key: 'sendConfirmationMessage', + value: function sendConfirmationMessage(row, done) { + var that = this, + data = { + email: row['e-mail'], + nome: row['nomecompleto'] + }; + this.ML.send(data.email, 'Confirmação do pagamento da inscrição', 'Olá ' + data.nome + ',\n\n\t\tO pagamento da sua inscrição como participante foi confirmado.\n\n\t\tObrigado!', function (err, results) { + that.valid = true; + done(err, 'Confirmação de: ' + data.email); + }); + } + + /** + * Marca na planilha que participante está confirmado + * @param {Spreadsheetrow[]} row - linha que será passada para as ações + * @param {Function} done2 - callback + */ + }, { + key: 'markSubscriberMakePayment', + value: function markSubscriberMakePayment(row, done) { + row.status = 'Confirmado'; + row.save(done); + } + }]); + + return Confirmation; +})(_index2['default']); + +exports['default'] = Confirmation; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/modules/rules/onRegister.js b/dist/modules/rules/onRegister.js new file mode 100644 index 0000000..e2f621f --- /dev/null +++ b/dist/modules/rules/onRegister.js @@ -0,0 +1,99 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var _index = require('./index'); + +var _index2 = _interopRequireDefault(_index); + +var _async = require('async'); + +var _async2 = _interopRequireDefault(_async); + +/** + * Implementa verificação no participante se já recebeu informações + * para pagamento, as envia em caso negativo e realiza mudança de + * status do participante na planilha + */ + +var Register = (function (_Rules) { + _inherits(Register, _Rules); + + function Register() { + _classCallCheck(this, Register); + + _get(Object.getPrototypeOf(Register.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(Register, [{ + key: 'addActions', + value: function addActions() { + this._actions.push('markSubscriberReceivedInstructions'); + this._actions.push('sendInstructions'); + } + + /** + * Valida se a linha está com a coluna status em branco e possui e-mail válido + * @param {string[]} row - Linha da planilha contendo informações do participante + * @return {Boolean} + * @public + */ + }, { + key: 'filter', + value: function filter(row) { + // pegadinha com "!" por causa da validação por e-mail + return !_get(Object.getPrototypeOf(Register.prototype), 'filter', this).call(this, row) && row['status'] === ''; + } + + /** + * Envia instruções para pagamento + * @param {Spreadsheetrow[]} row - linha que será passada para as ações + * @param {Function} done2 - callback + * @protected + */ + }, { + key: 'sendInstructions', + value: function sendInstructions(row, done) { + var that = this, + data = { + email: row['e-mail'], + nome: row['nomecompleto'], + link_boleto: "https://ww8.banrisul.com.br/brb/link/Brbw2Lhw_Bloqueto_Titulos_Internet.aspx?Origem=EX&CodCedente=0051101408020&Valor=20,00&SeuNumero=645364312&DiaVcto=15&MesVcto=01&AnoVcto=2016&NomeSacado=" + encodeURIComponent(row['nomecompleto']) + '&UF=' + row['estadobrasileiro'] + "&OcultarFormulario=S&Observacoes=Aten%E7%E3o%3A%20Este%20comprovante%20poder%E1%20ser%20solicitado%20no%20CREDENCIAMENTO." + }; + this.ML.send(data.email, 'Instruções para pagamento da inscrição', 'Olá ' + data.nome + ',\n\nSua inscrição como participante foi iniciada com sucesso! Clique no link abaixo para acessar o boleto e realizar o pagamento.\n\n' + data.link_boleto + '\n\nEle poderá ser feito até 15 de janeiro de 2016 em qualquer agência bancária, lotérica ou através do seu internet banking.\n\nA confirmação da inscrição será enviada assim que recebermos do banco responsável a confirmação de pagamento (o que pode demorar até 5 dias úteis a partir da data de pagamento).\n\nObrigado!', function (err, results) { + that.valid = true; + done(err, 'Registro de: ' + data.email); + }); + } + + /** + * @param {Spreadsheetrow[]} row - linha que será passada para as ações + * @param {Function} done2 - callback + * @protected + */ + }, { + key: 'markSubscriberReceivedInstructions', + value: function markSubscriberReceivedInstructions(row, done) { + var that = this; + row.status = 'Boleto Enviado'; + return row.save(done); + } + }]); + + return Register; +})(_index2['default']); + +exports['default'] = Register; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/routes/datasources.js b/dist/routes/datasources.js new file mode 100644 index 0000000..e536893 --- /dev/null +++ b/dist/routes/datasources.js @@ -0,0 +1,56 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _models = require('../models'); + +var _models2 = _interopRequireDefault(_models); + +var _express = require('express'); + +var _express2 = _interopRequireDefault(_express); + +var router = _express2['default'].Router(); + +router.get('/', function (req, res) { + _models2['default'].Datasource.findAll({}).then(function (ds) { + res.json(ds); + }); +}); + +router.post('/', function (req, res) { + _models2['default'].Datasource.create({ + name: req.body.name, + key: req.body.key, + interval_update: req.body.interval_update * 60000 + }).then(function (err, result) { + res.json(result); + }); +}); + +router.put('/', function (req, res) { + _models2['default'].Datasources.upsert({ + name: req.body.name, + key: req.body.key, + interval_update: req.body.interval_update * 60000 + }).then(function (err, result) { + res.json(result); + }); +}); + +router['delete']('/:ds_id', function (req, res) { + _models2['default'].Datasource.destroy({ + where: { + id: req.params.ds_id + } + }).then(function () { + res.redirect('/'); + }); +}); + +exports['default'] = router; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/routes/index.js b/dist/routes/index.js new file mode 100644 index 0000000..21dce86 --- /dev/null +++ b/dist/routes/index.js @@ -0,0 +1,20 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _express = require('express'); + +var _express2 = _interopRequireDefault(_express); + +var router = _express2['default'].Router(); + +router.get('/', function (req, res, next) { + res.render('index', { title: 'Processador inscrição evento' }); +}); + +exports['default'] = router; +module.exports = exports['default']; \ No newline at end of file diff --git a/dist/server.js b/dist/server.js new file mode 100644 index 0000000..2175e03 --- /dev/null +++ b/dist/server.js @@ -0,0 +1,102 @@ +/** + * Module dependencies. + */ + +'use strict'; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _app = require('./app'); + +var _app2 = _interopRequireDefault(_app); + +var _models = require("./models"); + +var _models2 = _interopRequireDefault(_models); + +var _debug = require('debug'); + +var _debug2 = _interopRequireDefault(_debug); + +var _http = require('http'); + +var _http2 = _interopRequireDefault(_http); + +(0, _debug2['default'])('web:server'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +_app2['default'].set('port', port); + +/** + * Create HTTP server. + */ + +var server = _http2['default'].createServer(_app2['default']); + +/** + * Listen on provided port, on all network interfaces. + */ +_models2['default'].sequelize.sync().then(function () { + server.listen(port); + server.on('error', onError); + server.on('listening', onListening); +}); +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; + (0, _debug2['default'])('Listening on ' + bind); +} \ No newline at end of file diff --git a/package.json b/package.json index a7ab7b4..53cddbb 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,6 @@ "description": "Processador de inscrições em eventos que utiliza uma planilha no Google Drive para controlar o envio de e-mail para pagamento e para confirmação da inscrição", "main": "bin/www", "scripts": { - "postinstall": "./node_modules/.bin/babel ./src/ -d ./dist/", "start": "./node_modules/.bin/babel-node ./src/server.js", "test": "./node_modules/.bin/jasmine", "generate-docs": "./node_modules/.bin/jsdoc --configure .jsdoc.json --verbose"