aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app.coffee90
-rw-r--r--app.js289
-rw-r--r--public/css/index.less9
-rw-r--r--public/js/calculator.coffee140
-rw-r--r--public/js/index.coffee0
-rw-r--r--views/about.html2
-rw-r--r--views/exchangers.html2
-rw-r--r--views/layout.html7
-rw-r--r--views/merchants.html2
9 files changed, 414 insertions, 127 deletions
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&currency=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
--- /dev/null
+++ b/public/js/index.coffee
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 -- <a href="https://blockchain.info/wallet/new">try it</a>.
+ easy as email. <a href="https://blockchain.info/wallet/new" target="_blank">Try it here</a>.
</p>
<p>
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 @@
<ul>
<li>Contact one of us to let us know your availability and how much you want to spend</li>
<li>We'll arrange a time to meet at a public place like a caf&eacute; or a bank</li>
- <li>At the time of meeting, we'll look up the exchange rate above and figure out how many bitcoins to send for the amount you specified</li>
+ <li>At the time of meeting, we'll look up the exchange rate above to determine how many bitcoins to send for the amount you specified</li>
<li>You'll provide us with a bitcoin address to send to and count out the cash for us</li>
<li>We'll send the bitcoins to your address using a phone or laptop</li>
<li>When the transaction is confirmed, we take the cash and you keep the bitcoins!</li>
diff --git a/views/layout.html b/views/layout.html
index f2e7a1ef..dbac084f 100644
--- a/views/layout.html
+++ b/views/layout.html
@@ -5,6 +5,7 @@
<meta name="viewport" content="width=480, height=752, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<title>Vancouver Bitcoin</title>
<link href="img/favicon.ico" rel="shortcut icon" />
+ {{#js}}index{{/js}}
{{#css}}index{{/css}}
</head>
<body>
@@ -14,7 +15,7 @@
<a class="brand" href="/">VanBTC</a>
<div class="nav-collapse collapse">
<p class="navbar-text pull-right">
- Exchange Rate: <b class="price">$12.50</b> |
+ Exchange Rate: <b class="exchange"></b> |
<a href="/login" class="navbar-link">Login</a>
</p>
<ul class="nav">
@@ -31,8 +32,6 @@
{{>content}}
</div>
<hr>
- <footer>
- <p>&copy; VanBTC 2012</p>
- </footer>
+ <footer>Website by Adam Soltys</footer>
</body>
</html>
diff --git a/views/merchants.html b/views/merchants.html
index 896ecd65..da3089c8 100644
--- a/views/merchants.html
+++ b/views/merchants.html
@@ -8,6 +8,7 @@
<p><a class="btn" href="/merchants/new">Sign me up!</a></p>
</div>
</div>
+
<div class="row-fluid">
<div class="span4">
<h2>Pacific Bliss Massage</h2>
@@ -31,3 +32,4 @@
<p>Authentic Turkish kebab and desserts</p>
</div>
</div>
+</div>