From 11d8decbb3b444561ee51daa0f0d2a609da13e47 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 18 Sep 2016 15:55:47 -0700 Subject: Send basic notification on transaction receipt --- routes/transactions.js | 19 +++++++++++++++++++ src/routes/transactions.coffee | 17 +++++++++++++++++ views/transactions/notification.html | 3 +++ 3 files changed, 39 insertions(+) create mode 100644 views/transactions/notification.html diff --git a/routes/transactions.js b/routes/transactions.js index 759ec14a..31875918 100644 --- a/routes/transactions.js +++ b/routes/transactions.js @@ -62,6 +62,25 @@ if (result) { return finish(); } + res.render('notification', { + layout: 'mail', + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }, function(err, html) { + var email, sendgrid; + sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password); + email = new sendgrid.Email({ + to: 'asoltys@gmail.com', + from: 'info@coinos.io', + subject: 'Transaction Sent', + html: html + }); + return sendgrid.send(email); + }); multi = db.multi(); multi.hmset(req.body.txid, req.body); multi.rpush("" + req.params.user + ":transactions", req.body.txid); diff --git a/src/routes/transactions.coffee b/src/routes/transactions.coffee index 25ccbbc9..cadb73b1 100644 --- a/src/routes/transactions.coffee +++ b/src/routes/transactions.coffee @@ -46,6 +46,23 @@ module.exports = db.exists(req.body.txid, (err, result) -> return finish() if result + res.render('notification', + layout: 'mail', + js: (-> global.js), + css: (-> global.css), + (err, html) -> + sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password) + + email = new sendgrid.Email( + to: 'asoltys@gmail.com' + from: 'info@coinos.io' + subject: 'Transaction Sent' + html: html + ) + + sendgrid.send(email) + ) + multi = db.multi() multi.hmset(req.body.txid, req.body) multi.rpush("#{req.params.user}:transactions", req.body.txid) diff --git a/views/transactions/notification.html b/views/transactions/notification.html new file mode 100644 index 00000000..49a045a7 --- /dev/null +++ b/views/transactions/notification.html @@ -0,0 +1,3 @@ +

Transaction Received

+ +You got paid -- cgit v1.2.3 From 236a39ff26178cff69cee92b8065d8a332f89f90 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 18 Sep 2016 17:35:19 -0700 Subject: Update README to include bower installation --- README.md | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9c6ff470..f8b86724 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,30 @@ # CoinOS -CoinOS is a mobile-friendly Point-of-Sale page that merchants can use to accept Bitcoin payments. +CoinOS is a mobile-friendly point-of-sale app that merchants can use to accept Bitcoin payments. -# How it Works +# Features -* You create an account and configure some basic parameters for your storefront like a name, logo, and bitcoin receiving address -* You set an exchange rate to be used to convert from your local currency to bitcoin -* CoinOS creates a custom webpage that you can bring up on a mobile device to generate payment requests -* You enter a sale amount in your local currency and CoinOS converts it to bitcoin using your chosen exchange rate -* CoinOS creates a QR code for the payment request with your receiving address and the sale amount encoded -* CoinOS listens for transactions on the Bitcoin network and displays a notification when the requested amount is received at your address -* The details of the transaction and the exchange rate used at the time of sale are recorded and made available in a convenient report - -# Technical Details - -The site is programmed in HTML and Coffeescript using NodeJS and jQuery. Account details and transaction data are stored in a Redis database. Users are responsible for providing their own receiving addresses managed with whatever wallet they prefer, so CoinOS never stores any bitcoins. - -We use the websocket payment notification API from http://blockchain.info/api/api_websocket to listen for and display payment notifications in real time. The bitcoin exchange rates are fetched from http://bitcoinaverage.com/ +* Setup a customized payment page with your company name and logo +* Enter sale amounts in your local currency and have them converted to an amount in bitcoin using your chosen exchange rate +* A QR code payment request is generated with your receiving address and the sale amount for your customers to scan +* Get am on-screen notification when the requested amount is received at your address +* Transactions and the exchange rate at the time of sale are recorded and can be viewed later and filtered by date range # Installation -Install nodeJS (http://nodejs.org/) and redis (http://redis.io/). On Ubuntu, this would be: +Install nodeJS (http://nodejs.org/) and redis (http://redis.io/). On Ubuntu that looks like: sudo apt-get install nodejs redis-server - sudo ln -sf /usr/bin/nodejs /usr/bin/node Download and configure CoinOS: git clone https://github.com/thebitcoincoop/coinos cd coinos - npm install + npm install + bower install npm start -Now the app should be runnning at http://localhost:3000/ +Now the app should be runnning at http://localhost:3001/ # License -- cgit v1.2.3 From 515b1a63871af43fca536f0a1dd653dcaa1d2ba9 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 18 Sep 2016 20:58:39 -0700 Subject: Point to bootstrap fork commit in bower config --- bower.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 7dbb4b43..632362a9 100644 --- a/bower.json +++ b/bower.json @@ -28,12 +28,14 @@ "font-awesome": "~4.5.0", "jquery": "~2.1.4", "jquery-ui": "~1.11.4", - "bootstrap": "https://github.com/asoltys/bootstrap.git#master", + "bootstrap": "https://github.com/asoltys/bootstrap.git#b962f8a4308d094c23c9ac47a0a5ee3d4e9a4bfd", "bootstrap-validator": "~0.9.0", "bootstrap3-dialog": "~1.34.7", "jquery-serialize-object": "~2.5.0", "crypto-js": "~3.1.5", "bootbox.js": "bootbox#~4.4.0" - + }, + "resolutions": { + "bootstrap": "b962f8a4308d094c23c9ac47a0a5ee3d4e9a4bfd" } } -- cgit v1.2.3 From acd47767d0c02dfa1a4152208a16c21255e4943b Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 22 Sep 2016 10:11:19 -0700 Subject: Upgrade sendgrid and fill in transaction details in notification email --- package.json | 2 +- public/js/profile.coffee | 1 - public/js/profile.js | 1 - routes/transactions.js | 54 +++++++++++++++++++++++------------- routes/users.js | 42 +++++++++++++++++----------- src/routes/transactions.coffee | 45 ++++++++++++++++++------------ src/routes/users.coffee | 41 +++++++++++++++++---------- views/transactions/notification.html | 2 +- views/users/profile.html | 5 +--- 9 files changed, 117 insertions(+), 76 deletions(-) diff --git a/package.json b/package.json index 0f94d4b8..ec334a23 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "passport-local": "1.0.0", "redis": "0.11.0", "request": "~2.40.0", - "sendgrid": "~1.2.0" + "sendgrid": "^4.3.0" }, "devDependencies": { "coffeeify": "^1.2.0", diff --git a/public/js/profile.coffee b/public/js/profile.coffee index dda0597c..fdbde8ee 100644 --- a/public/js/profile.coffee +++ b/public/js/profile.coffee @@ -7,7 +7,6 @@ $(-> user = $('#username').val() $.getJSON("/#{user}.json", (data) -> - $('#username').val(data.username) $('#email').val(data.email) $('#profile').fadeIn() ) diff --git a/public/js/profile.js b/public/js/profile.js index d680e209..a49c7583 100644 --- a/public/js/profile.js +++ b/public/js/profile.js @@ -12,7 +12,6 @@ $('#title').focus(); user = $('#username').val(); $.getJSON("/" + user + ".json", function(data) { - $('#username').val(data.username); $('#email').val(data.email); return $('#profile').fadeIn(); }); diff --git a/routes/transactions.js b/routes/transactions.js index 31875918..d132e418 100644 --- a/routes/transactions.js +++ b/routes/transactions.js @@ -1,8 +1,12 @@ (function() { - var db; + var config, db, moment; db = require('../redis'); + config = require("../config"); + + moment = require('moment'); + module.exports = { index: function(req, res) { return res.render('transactions/index', { @@ -53,6 +57,35 @@ create: function(req, res) { var finish; finish = function() { + db.hgetall("user:" + req.params.user.toLowerCase(), function(err, user) { + return res.render('transactions/notification', { + layout: 'mail', + amount: (req.body.received * req.body.exchange).toFixed(2).toString() + ' ' + user.currency, + address: req.body.address, + txid: req.body.txid, + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }, function(err, html) { + var content, from_email, helper, mail, request, sg, subject, to_email; + helper = require('sendgrid').mail; + from_email = new helper.Email('info@coinos.io'); + to_email = new helper.Email(user.email); + subject = 'Transaction Sent'; + content = new helper.Content('text/html', html); + mail = new helper.Mail(from_email, subject, to_email, content); + sg = require('sendgrid')(config.sendgrid_token); + request = sg.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: mail.toJSON() + }); + return sg.API(request); + }); + }); res.write(JSON.stringify(req.body)); return res.end(); }; @@ -62,25 +95,6 @@ if (result) { return finish(); } - res.render('notification', { - layout: 'mail', - js: (function() { - return global.js; - }), - css: (function() { - return global.css; - }) - }, function(err, html) { - var email, sendgrid; - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password); - email = new sendgrid.Email({ - to: 'asoltys@gmail.com', - from: 'info@coinos.io', - subject: 'Transaction Sent', - html: html - }); - return sendgrid.send(email); - }); multi = db.multi(); multi.hmset(req.body.txid, req.body); multi.rpush("" + req.params.user + ":transactions", req.body.txid); diff --git a/routes/users.js b/routes/users.js index 1449eb02..2c79cb31 100644 --- a/routes/users.js +++ b/routes/users.js @@ -154,15 +154,20 @@ return global.css; }) }, function(err, html) { - var email, sendgrid; - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password); - email = new sendgrid.Email({ - to: req.body.email, - from: 'adam@coinos.io', - subject: 'Welcome to CoinOS', - html: html + var content, from_email, helper, mail, sg, subject, to_email; + helper = require('sendgrid').mail; + from_email = new helper.Email('info@coinos.io'); + to_email = new helper.Email(req.body.email); + subject = 'Welcome to CoinOS'; + content = new helper.Content('text/html', html); + mail = new helper.Mail(from_email, subject, to_email, content); + sg = require('sendgrid')(config.sendgrid_token); + request = sg.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: mail.toJSON() }); - return sendgrid.send(email); + return sg.API(request); }); }); }); @@ -232,15 +237,20 @@ return global.css; }) }, function(err, html) { - var email, sendgrid; - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password); - email = new sendgrid.Email({ - to: req.body.email, - from: 'adam@coinos.io', - subject: 'CoinOS Wallet Key', - html: html + var content, from_email, helper, mail, sg, subject, to_email; + helper = require('sendgrid').mail; + from_email = new helper.Email('info@coinos.io'); + to_email = new helper.Email(req.body.email); + subject = 'CoinOS Wallet Key'; + content = new helper.Content('text/html', html); + mail = new helper.Mail(from_email, subject, to_email, content); + sg = require('sendgrid')(config.sendgrid_token); + request = sg.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: mail.toJSON() }); - return sendgrid.send(email); + return sg.API(request); }); } }, diff --git a/src/routes/transactions.coffee b/src/routes/transactions.coffee index cadb73b1..696eefba 100644 --- a/src/routes/transactions.coffee +++ b/src/routes/transactions.coffee @@ -1,4 +1,6 @@ db = require('../redis') +config = require("../config") +moment = require('moment') module.exports = index: (req, res) -> @@ -39,6 +41,32 @@ module.exports = create: (req, res) -> finish = -> + db.hgetall("user:"+req.params.user.toLowerCase(), (err, user) -> + res.render('transactions/notification', + layout: 'mail' + amount: (req.body.received * req.body.exchange).toFixed(2).toString() + ' ' + user.currency + address: req.body.address + txid: req.body.txid + js: (-> global.js) + css: (-> global.css) + (err, html) -> + helper = require('sendgrid').mail + from_email = new helper.Email('info@coinos.io') + to_email = new helper.Email(user.email) + subject = 'Transaction Sent' + content = new helper.Content('text/html', html) + mail = new helper.Mail(from_email, subject, to_email, content) + + sg = require('sendgrid')(config.sendgrid_token) + request = sg.emptyRequest( + method: 'POST' + path: '/v3/mail/send' + body: mail.toJSON() + ) + + sg.API(request) + ) + ) res.write(JSON.stringify(req.body)) res.end() @@ -46,23 +74,6 @@ module.exports = db.exists(req.body.txid, (err, result) -> return finish() if result - res.render('notification', - layout: 'mail', - js: (-> global.js), - css: (-> global.css), - (err, html) -> - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password) - - email = new sendgrid.Email( - to: 'asoltys@gmail.com' - from: 'info@coinos.io' - subject: 'Transaction Sent' - html: html - ) - - sendgrid.send(email) - ) - multi = db.multi() multi.hmset(req.body.txid, req.body) multi.rpush("#{req.params.user}:transactions", req.body.txid) diff --git a/src/routes/users.coffee b/src/routes/users.coffee index e682602b..d1c8f602 100644 --- a/src/routes/users.coffee +++ b/src/routes/users.coffee @@ -112,16 +112,22 @@ module.exports = (sessions) -> js: (-> global.js), css: (-> global.css), (err, html) -> - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password) - email = new sendgrid.Email( - to: req.body.email - from: 'adam@coinos.io' - subject: 'Welcome to CoinOS' - html: html + helper = require('sendgrid').mail + from_email = new helper.Email('info@coinos.io') + to_email = new helper.Email(req.body.email) + subject = 'Welcome to CoinOS' + content = new helper.Content('text/html', html) + mail = new helper.Mail(from_email, subject, to_email, content) + + sg = require('sendgrid')(config.sendgrid_token) + request = sg.emptyRequest( + method: 'POST' + path: '/v3/mail/send' + body: mail.toJSON() ) - sendgrid.send(email) + sg.API(request) ) ) ) @@ -178,16 +184,21 @@ module.exports = (sessions) -> js: (-> global.js), css: (-> global.css), (err, html) -> - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password) - - email = new sendgrid.Email( - to: req.body.email - from: 'adam@coinos.io' - subject: 'CoinOS Wallet Key' - html: html + helper = require('sendgrid').mail + from_email = new helper.Email('info@coinos.io') + to_email = new helper.Email(req.body.email) + subject = 'CoinOS Wallet Key' + content = new helper.Content('text/html', html) + mail = new helper.Mail(from_email, subject, to_email, content) + + sg = require('sendgrid')(config.sendgrid_token) + request = sg.emptyRequest( + method: 'POST' + path: '/v3/mail/send' + body: mail.toJSON() ) - sendgrid.send(email) + sg.API(request) ) verify: (req, res) -> diff --git a/views/transactions/notification.html b/views/transactions/notification.html index 49a045a7..5f066cf8 100644 --- a/views/transactions/notification.html +++ b/views/transactions/notification.html @@ -1,3 +1,3 @@

Transaction Received

-You got paid +You received {{amount}} from {{address}}. Visit https://blockchain.info/tx/{{txid}} for more details. diff --git a/views/users/profile.html b/views/users/profile.html index 70f9acfc..0f37d20e 100644 --- a/views/users/profile.html +++ b/views/users/profile.html @@ -5,10 +5,7 @@