From c5d381e23a31c6ba2b6d00490ba2f6b68d32572e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 29 Nov 2012 03:04:26 -0800 Subject: Refactoring --- app.coffee | 90 +++++++------- app.js | 289 ++++++++++++++++++++++++++++++++++++++++++++ public/css/index.less | 9 +- public/js/calculator.coffee | 140 ++++++++++----------- public/js/index.coffee | 0 views/about.html | 2 +- views/exchangers.html | 2 +- views/layout.html | 7 +- views/merchants.html | 2 + 9 files changed, 414 insertions(+), 127 deletions(-) create mode 100644 app.js create mode 100644 public/js/index.coffee diff --git a/app.coffee b/app.coffee index 9d8ab3ba..e94e0a39 100644 --- a/app.coffee +++ b/app.coffee @@ -4,14 +4,15 @@ path = require('path') engines = require('consolidate') passport = require('passport') bcrypt = require('bcrypt') -db = require("redis") +db = require("redis").createClient() +async = require('async') config = require('./config') app = express() LocalStrategy = require('passport-local').Strategy passport.use(new LocalStrategy( (username, password, done) -> - user = {username: 'soltysa', password: 'adam'} + user = username: 'soltysa', password: 'adam' return done(null, user) )) @@ -20,15 +21,14 @@ passport.serializeUser((user, done) -> ) passport.deserializeUser((id, done) -> - user = {username: 'soltysa', password: 'adam'} + user = username: 'soltysa', password: 'adam' done(null, user) ) -app.engine('html', require('mmm').__express) app.enable('trust proxy') +app.engine('html', require('mmm').__express) app.set('view engine', 'html') app.set('views', __dirname + '/views') -app.set('layout', 'layout') app.use(express.static(__dirname + '/public')) app.use(require('connect-assets')(src: 'public')) app.use(express.bodyParser()) @@ -37,49 +37,28 @@ app.use(express.session(secret: 'weareallmadeofstars')) app.use(passport.initialize()) app.use(passport.session()) app.use(app.router) -app.use((err, req, res, next) -> - res.status(500) - console.log(err) - res.end() -) -app.get('/', (req, res) -> - res.render('index', js: (-> global.js), css: (-> global.css)) -) +for route in ['', 'about', 'exchangers', 'merchants'] + ((route) -> + app.get("/#{route}", (req, res) -> + route = 'index' if route == '' + res.render(route, js: (-> global.js), css: (-> global.css), layout: 'layout') + ) + )(route) app.get('/setup', (req, res) -> res.render('setup', js: (-> global.js), css: (-> global.css)) ) -app.get('/about', (req, res) -> - res.render('about', js: (-> global.js), css: (-> global.css)) -) - -app.get('/merchants', (req, res) -> - res.render('merchants', js: (-> global.js), css: (-> global.css)) -) - -app.get('/exchangers', (req, res) -> - res.render('exchangers', js: (-> global.js), css: (-> global.css)) -) - -app.get('/bcrypt', (req, res) -> - salt = "$2a$10$3R8tUtIoU/fllQD9zEgTZe" - hash = bcrypt.hashSync("chelsea", salt) - res.write(salt + "\n") - res.write(hash) - res.end() -) - app.get('/:user/report', (req, res) -> res.render('report', user: req.params.user, js: (-> global.js), - css: (-> global.css)) + css: (-> global.css) + ) ) app.get('/:user.json', (req, res) -> - db.createClient() db.hgetall(req.params.user, (err, obj) -> res.write(JSON.stringify(obj)) res.end() @@ -87,7 +66,6 @@ app.get('/:user.json', (req, res) -> ) app.get('/:user/transactions', (req, res) -> - db.createClient() user = req.params.user r = 'transactions': [] @@ -116,10 +94,16 @@ app.get('/ticker', (req, res) -> require('http').get(options, (r) -> r.setEncoding('utf-8') r.on('data', (chunk) -> + try + exchange = 1000 / JSON.parse(chunk).out + exchange = (Math.ceil(exchange * 100) / 100).toString() + catch e + exchange = "" + res.writeHead(200, - 'Content-Length': chunk.length, + 'Content-Length': exchange.length, 'Content-Type': 'text/plain') - res.write(chunk) + res.write(exchange) res.end() ) ) @@ -150,17 +134,22 @@ app.post('/users', (req, res) -> if req.body.login if req.body.password bcrypt.hash(req.body.password, 12, (err, hash) -> - db.createClient() db.hget(req.body.login, 'password', (err, password) -> - bcrypt.compare(req.body.password, password, (err, match) -> - if match - req.body.password = password - db.hmset(req.body.login, req.body, -> + if password + bcrypt.compare(req.body.password, password, (err, match) -> + if match + req.body.password = password + db.hmset(req.body.login, req.body, -> + res.redirect(req.body.login) + ) + else res.redirect(req.body.login) - ) - else + ) + else + req.body.password = hash + db.hmset(req.body.login, req.body, -> res.redirect(req.body.login) - ) + ) ) ) else @@ -173,7 +162,6 @@ app.post('/users', (req, res) -> app.post('/:user/transactions', (req, res) -> user = req.params.user - db.createClient() db.incr('transactions', (err, id) -> db.hmset("#{user}:transactions:#{id}", req.body, -> db.rpush("#{user}:transactions", id, -> @@ -187,7 +175,7 @@ app.post('/:user/transactions', (req, res) -> app.get('/calculator', (req, res) -> res.render('calculator', js: (-> global.js), - css: (-> global.css) + css: (-> global.css), ) ) @@ -199,7 +187,6 @@ app.get('/:user/edit', (req, res) -> ) ) - app.get('/:user', (req, res) -> res.render('calculator', user: req.params.user, @@ -208,5 +195,10 @@ app.get('/:user', (req, res) -> ) ) +app.use((err, req, res, next) -> + res.status(500) + console.log(err) + res.end() +) app.listen(3000) diff --git a/app.js b/app.js new file mode 100644 index 00000000..5a8a7912 --- /dev/null +++ b/app.js @@ -0,0 +1,289 @@ +// Generated by CoffeeScript 1.4.0 +(function() { + var LocalStrategy, app, bcrypt, config, db, engines, express, http, passport, path, route, _fn, _i, _len, _ref; + + express = require('express'); + + http = require('http'); + + path = require('path'); + + engines = require('consolidate'); + + passport = require('passport'); + + bcrypt = require('bcrypt'); + + db = require("redis").createClient(); + + config = require('./config'); + + app = express(); + + LocalStrategy = require('passport-local').Strategy; + + passport.use(new LocalStrategy(function(username, password, done) { + var user; + user = { + username: 'soltysa', + password: 'adam' + }; + return done(null, user); + })); + + passport.serializeUser(function(user, done) { + return done(null, user.username); + }); + + passport.deserializeUser(function(id, done) { + var user; + user = { + username: 'soltysa', + password: 'adam' + }; + return done(null, user); + }); + + app.enable('trust proxy'); + + app.engine('html', require('mmm').__express); + + app.set('view engine', 'html'); + + app.set('views', __dirname + '/views'); + + app.use(express["static"](__dirname + '/public')); + + app.use(require('connect-assets')({ + src: 'public' + })); + + app.use(express.bodyParser()); + + app.use(express.cookieParser()); + + app.use(express.session({ + secret: 'weareallmadeofstars' + })); + + app.use(passport.initialize()); + + app.use(passport.session()); + + app.use(app.router); + + app.use(function(err, req, res, next) { + res.status(500); + console.log(err); + return res.end(); + }); + + _ref = ['', 'about', 'exchangers', 'merchants']; + _fn = function(route) { + return app.get("/" + route, function(req, res) { + if (route === '') { + route = 'index'; + } + return res.render(route, { + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }), + layout: 'layout' + }); + }); + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + route = _ref[_i]; + _fn(route); + } + + app.get('/setup', function(req, res) { + return res.render('setup', { + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }); + }); + + app.get('/:user/report', function(req, res) { + return res.render('report', { + user: req.params.user, + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }); + }); + + app.get('/:user.json', function(req, res) { + return db.hgetall(req.params.user, function(err, obj) { + res.write(JSON.stringify(obj)); + return res.end(); + }); + }); + + app.get('/:user/transactions', function(req, res) { + var r, user; + user = req.params.user; + r = { + 'transactions': [] + }; + return db.lrange("" + user + ":transactions", 0, -1, function(err, transactions) { + var i, process; + process = function(err, t) { + r.transactions.push(t); + if (i >= transactions.length) { + res.write(JSON.stringify(r)); + return res.end(); + } else { + return db.hgetall("" + user + ":transactions:" + transactions[i++], process); + } + }; + i = 0; + return db.hgetall("" + user + ":transactions:" + transactions[i++], process); + }); + }); + + app.get('/ticker', function(req, res) { + var options; + options = { + host: 'bitcoincharts.com', + path: '/t/depthcalc.json?symbol=' + req.query.symbol + '&type=ask&amount=1000¤cy=true' + }; + return require('http').get(options, function(r) { + r.setEncoding('utf-8'); + return r.on('data', function(chunk) { + var exchange; + exchange = 1000 / JSON.parse(chunk).out; + exchange = (Math.ceil(exchange * 100) / 100).toString(); + res.writeHead(200, { + 'Content-Length': exchange.length, + 'Content-Type': 'text/plain' + }); + res.write(exchange); + return res.end(); + }); + }); + }); + + app.get('/login', function(req, res) { + return res.render('login', { + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }); + }); + + app.post('/login', function(req, res, next) { + return passport.authenticate('local', function(err, user, info) { + if (err) { + return next(err); + } + if (!user) { + return res.redirect('/login'); + } + return req.logIn(user, function(err) { + if (err) { + return next(err); + } + return res.redirect('/' + user.username); + }); + })(req, res, next); + }); + + app.post('/users', function(req, res) { + var k, params, v, _ref1; + if (req.body.login) { + if (req.body.password) { + return bcrypt.hash(req.body.password, 12, function(err, hash) { + console.log(req) + return db.hget(req.body.login, 'password', function(err, password) { + return bcrypt.compare(req.body.password, password, function(err, match) { + if (match) { + req.body.password = password; + return db.hmset(req.body.login, req.body, function() { + return res.redirect(req.body.login); + }); + } else { + return res.redirect(req.body.login); + } + }); + }); + }); + } + } else { + params = []; + _ref1 = req.body; + for (k in _ref1) { + v = _ref1[k]; + params.push(encodeURIComponent(k), '=', encodeURIComponent(v), '&'); + } + if (params.length) { + params.pop(); + } + return res.redirect('calculator?' + params.join('')); + } + }); + + app.post('/:user/transactions', function(req, res) { + var user; + user = req.params.user; + return db.incr('transactions', function(err, id) { + return db.hmset("" + user + ":transactions:" + id, req.body, function() { + return db.rpush("" + user + ":transactions", id, function() { + res.write(JSON.stringify(req.body)); + return res.end(); + }); + }); + }); + }); + + app.get('/calculator', function(req, res) { + return res.render('calculator', { + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }); + }); + + app.get('/:user/edit', function(req, res) { + return res.render('index', { + user: req.params.user, + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }); + }); + + app.get('/:user', function(req, res) { + return res.render('calculator', { + user: req.params.user, + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }); + }); + + app.listen(3000); + +}).call(this); diff --git a/public/css/index.less b/public/css/index.less index 1c72317c..35eb9420 100644 --- a/public/css/index.less +++ b/public/css/index.less @@ -1,13 +1,14 @@ @import "bootstrap.min.css"; -.navbar-inverse .brand, .navbar-inverse .nav > li > a { color: #ddd; } +.navbar-inverse, .navbar-inverse .navbar-link, .navbar-inverse .brand, .navbar-inverse .nav > li > a { color: #ddd; } footer { background: black; - color: white; + color: #ddd; padding: 10px 0px 2px 5px; - margin: 0 -20px 0 -20px; + margin: 0; + text-align: right; } -b.price { color: white; } +b.exchange { color: white; } div.directory img { width: 150px; height: 150px; float: left; padding-right: 20px; } div.row-fluid td.first { text-align: right; } diff --git a/public/js/calculator.coffee b/public/js/calculator.coffee index 114753cf..9a66167a 100644 --- a/public/js/calculator.coffee +++ b/public/js/calculator.coffee @@ -7,44 +7,39 @@ #= require jsbn2.js #= require check_address.js -g = exports ? this - EXCHANGE_FAIL = "Error fetching exchange rate" SOCKET_FAIL = "Error connecting to payment server" ADDRESS_FAIL = "Invalid address" +g = exports ? this + $(-> - g.websocket = null g.user = $('#user').val() g.name = get('name') g.address = get('address') g.symbol = get('symbol') g.commission = parseFloat(get('commission')) g.logo = get('logo') - g.exchange = 0 g.errors = [] - setupPage() - setupQR() - setupSocket() - - if g.user? and g.user + if g.user $.ajax( - url: user + '.json', + url: g.user + '.json', cache: false, dataType: 'json', success: (data) -> - return unless data? - g.name = data.name - g.address = data.address - g.symbol = data.symbol - g.commission = data.commission - g.logo = data.logo - setupPage() + if data? + g.name = data.name + g.address = data.address + g.symbol = data.symbol + g.commission = data.commission + g.logo = data.logo + setup() ) + else + setup() $('#amount').keyup(updateTotal) - $('#amount').focus() $('#amount').focus(-> $('#received').hide() $('#payment').fadeIn('slow') @@ -53,54 +48,7 @@ $(-> ) ) -updateTotal = -> - amount = parseFloat($('#amount').val()) - total = amount / g.exchange - total = Math.ceil(total * 10000) / 10000 - - unless $.isNumeric(total) - total = '' - - $('#total').html(total.toString()) - displayQR('bitcoin:' + g.address + '?amount=' + total.toString()) - -fetchExchangeRate = -> - $.ajax( - url: 'ticker?symbol=' + g.symbol, - dataType: 'json', - cache: false, - success: (data) -> - if data? - clear(EXCHANGE_FAIL) - else - fail(EXCHANGE_FAIL) - return - - exchange = 1000 / data.out - exchange = exchange - exchange * g.commission * 0.01 - g.exchange = Math.ceil(exchange * 100) / 100 - $('#exchange').val(g.exchange.toFixed(2)) - updateTotal() - error: -> fail(EXCHANGE_FAIL) - ) - - setTimeout(fetchExchangeRate, 900000) - -fail = (msg) -> - g.errors.push(msg) - $('#calculator').hide() - $('#error').show().html(g.errors.toString()) - -clear = (msg) -> - i = g.errors.indexOf(msg) - g.errors.splice(i, 1) if i >= 0 - if (g.errors.length > 0) - $('#error').show().html(g.errors.toString()) - else - $('#error').hide() - $('#calculator').fadeIn('slow') - -setupPage = -> +setup = -> g.address or= '1VAnbtCAnYccECnjaMCPnWwt81EHCVgNr' g.commission or= 0 g.symbol or= 'virtexCAD' @@ -128,8 +76,34 @@ setupPage = -> $('#currency').html(g.symbol.slice(-3)) $('#received').hide() - if g.exchange is 0 - fetchExchangeRate() + setupQR() + setupSocket() + fetchExchangeRate() + +fetchExchangeRate = -> + $.ajax( + url: 'ticker?symbol=' + g.symbol, + cache: false, + success: (exchange) -> + if exchange? + clear(EXCHANGE_FAIL) + else + fail(EXCHANGE_FAIL) + return + + unless g.setupComplete + finalize() + + g.exchange = exchange - exchange * g.commission * 0.01 + $('#exchange').val(g.exchange.toFixed(2)) + updateTotal() + error: -> fail(EXCHANGE_FAIL) + ) + setTimeout(fetchExchangeRate, 900000) + +finalize = -> + $('#amount').focus() + g.setupComplete = true setupSocket = -> setTimeout(setupSocket, 10000) @@ -173,6 +147,32 @@ setupSocket = -> exchange: g.exchange ) +updateTotal = -> + amount = parseFloat($('#amount').val()) + total = amount / g.exchange + total = Math.ceil(total * 10000) / 10000 + + unless $.isNumeric(total) + total = '' + + $('#total').html(total.toString()) + displayQR('bitcoin:' + g.address + '?amount=' + total.toString()) + +fail = (msg) -> + g.errors.push(msg) + g.errors = g.errors.uniq() + $('#calculator').hide() + $('#error').show().html(g.errors.toString()) + +clear = (msg) -> + i = g.errors.indexOf(msg) + g.errors.splice(i, 1) if i >= 0 + if (g.errors.length > 0) + $('#error').show().html(g.errors.toString()) + else + $('#error').hide() + $('#calculator').fadeIn('slow') + get = (name) -> name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]") regexS = "[\\?&]" + name + "=([^&#]*)" @@ -184,3 +184,7 @@ get = (name) -> else return decodeURIComponent(results[1].replace(/\+/g, " ")) +Array::uniq = -> + output = {} + output[@[key]] = @[key] for key in [0...@length] + value for key, value of output diff --git a/public/js/index.coffee b/public/js/index.coffee new file mode 100644 index 00000000..e69de29b diff --git a/views/about.html b/views/about.html index 790bfa62..44d4a982 100644 --- a/views/about.html +++ b/views/about.html @@ -7,7 +7,7 @@ They get sent to a bitcoin address and stored in a digital wallet that you can access with a password. Creating and using a new wallet and address is free and as - easy as email -- try it. + easy as email. Try it here.

diff --git a/views/exchangers.html b/views/exchangers.html index 9f89f83a..8623e4e1 100644 --- a/views/exchangers.html +++ b/views/exchangers.html @@ -13,7 +13,7 @@