├── .gitignore
├── Cakefile
├── Gruntfile.coffee
├── Makefile
├── README.md
├── admin.js
├── app.js
├── assets
├── css
│ ├── admin.styl
│ ├── auth.styl
│ ├── chat.styl
│ ├── errors.styl
│ ├── font.styl
│ ├── framework.styl
│ ├── main.styl
│ ├── mixins.styl
│ ├── plugins
│ │ └── cdn.js
│ ├── static.styl
│ ├── trade.styl
│ ├── vendor
│ │ ├── jquery.jgrowl.css
│ │ └── normalize.css
│ └── wallets.styl
└── js
│ ├── admin.js
│ ├── admin_bootstrap.coffee
│ ├── app
│ ├── collections
│ │ ├── order_logs.coffee
│ │ ├── orders.coffee
│ │ ├── payments.coffee
│ │ ├── trade_stats.coffee
│ │ ├── transactions.coffee
│ │ └── wallets.coffee
│ ├── error_logger.coffee
│ ├── helpers
│ │ ├── crypto_currency.coffee
│ │ └── json.coffee
│ ├── models
│ │ ├── google_auth.coffee
│ │ ├── market_stats.coffee
│ │ ├── order.coffee
│ │ ├── order_log.coffee
│ │ ├── payment.coffee
│ │ ├── transaction.coffee
│ │ ├── user.coffee
│ │ └── wallet.coffee
│ └── views
│ │ ├── finances.coffee
│ │ ├── market_ticker.coffee
│ │ ├── master.coffee
│ │ ├── order_book.coffee
│ │ ├── order_logs.coffee
│ │ ├── orders.coffee
│ │ ├── pending_transactions.coffee
│ │ ├── settings.coffee
│ │ ├── trade.coffee
│ │ ├── trade_chart.coffee
│ │ └── transactions_history.coffee
│ ├── app_bootstrap.coffee
│ ├── application.js
│ ├── auth_bootstrap.coffee
│ ├── chat
│ ├── collections
│ │ └── chat_messages.coffee
│ ├── models
│ │ └── chat_message.coffee
│ └── views
│ │ └── chat.coffee
│ ├── chat_bootstrap.coffee
│ └── vendor
│ ├── BigInt.js
│ ├── ZeroClipboard.js
│ ├── ba-tiny-pubsub.js
│ ├── backbone.csrf.js
│ ├── backbone.js
│ ├── date.format.js
│ ├── highstock.exporting.js
│ ├── highstock.js
│ ├── jquery-1.10.2.js
│ ├── jquery.jgrowl.js
│ ├── jquery.tmpload.js
│ ├── jquery.validate.js
│ ├── mailcheck.js
│ ├── math.js
│ ├── modernizr-2.7.1.min.js
│ ├── qrcode.js
│ ├── sha256.js
│ ├── socket.io.js
│ ├── underscore.js
│ ├── underscore.string.js
│ ├── zxcvbn-async.js
│ └── zxcvbn.js
├── config.json.sample
├── configs
├── config.coffee
├── config.js
├── logger.coffee
├── logger.js
├── wallets.coffee
├── wallets.js
└── wallets_config
│ └── btc.json.sample
├── core_api.js
├── cron.js
├── cron_dump
├── currency.dump.sample
└── currency_exclude.dump.sample
├── lib
├── admin_auth.coffee
├── admin_auth.js
├── auth.coffee
├── auth.js
├── client_socket.coffee
├── client_socket.js
├── core_api_client.coffee
├── core_api_client.js
├── crypto_wallet.coffee
├── crypto_wallet.js
├── crypto_wallets
│ ├── doge_wallet.coffee
│ └── doge_wallet.js
├── emailer.coffee
├── emailer.js
├── fraud_helper.coffee
├── fraud_helper.js
├── json_beautifier.coffee
├── json_beautifier.js
├── json_renderer.coffee
├── json_renderer.js
├── market_helper.coffee
├── market_helper.js
├── market_settings.coffee
├── market_settings.js
├── math.coffee
├── math.js
├── queue
│ ├── event.coffee
│ ├── event.js
│ ├── index.coffee
│ ├── index.js
│ └── migrations
│ │ ├── 20140522192430-add_indexes.coffee
│ │ └── 20140522192430-add_indexes.js
├── sockets.coffee
├── sockets.js
├── trade_helper.coffee
├── trade_helper.js
├── transaction_helper.coffee
├── transaction_helper.js
├── underscore_string.coffee
└── underscore_string.js
├── models
├── admin_user.coffee
├── admin_user.js
├── auth_stats.coffee
├── auth_stats.js
├── chat.coffee
├── chat.js
├── index.coffee
├── index.js
├── market_stats.coffee
├── market_stats.js
├── migrations
│ ├── 20140330192430-add_indexes.coffee
│ ├── 20140330192430-add_indexes.js
│ ├── 20140425141930-alter_unsigned_amount.coffee
│ ├── 20140425141930-alter_unsigned_amount.js
│ ├── 20140505195830-add_order_log_indexes.coffee
│ ├── 20140505195830-add_order_log_indexes.js
│ ├── 20140507195900-alter_unsigned.coffee
│ ├── 20140507195900-alter_unsigned.js
│ ├── 20140524211930-add_indexes.coffee
│ ├── 20140524211930-add_indexes.js
│ ├── 20140607215430-add_indexes.coffee
│ ├── 20140607215430-add_indexes.js
│ ├── 20140610135430-add_indexes.coffee
│ └── 20140610135430-add_indexes.js
├── order.coffee
├── order.js
├── order_log.coffee
├── order_log.js
├── payment.coffee
├── payment.js
├── payment_log.coffee
├── payment_log.js
├── seeds
│ ├── market_stats.coffee
│ ├── market_stats.js
│ ├── trade_stats.coffee
│ └── trade_stats.js
├── trade_stats.coffee
├── trade_stats.js
├── transaction.coffee
├── transaction.js
├── user.coffee
├── user.js
├── user_token.coffee
├── user_token.js
├── wallet.coffee
├── wallet.js
├── wallet_health.coffee
└── wallet_health.js
├── package.json
├── public
├── 503.html
├── ZeroClipboard.swf
├── favicon.ico
├── favicon_admin.ico
├── fonts
│ ├── icons.eot
│ ├── icons.svg
│ ├── icons.ttf
│ └── icons.woff
├── img
│ ├── appstore-sprite.png
│ ├── coin-icons.png
│ ├── email
│ │ └── logo.png
│ ├── hero
│ │ ├── coins.svg
│ │ ├── hero-bg.png
│ │ ├── safe.svg
│ │ ├── save.svg
│ │ └── support.svg
│ ├── logo-gray.png
│ ├── logo-gray@2x.png
│ ├── logo-white.png
│ ├── logo-white@2x.png
│ ├── logo.png
│ └── logo@2x.png
└── robots.txt
├── queue.js
├── routes
├── admin.coffee
├── admin.js
├── api.coffee
├── api.js
├── auth.coffee
├── auth.js
├── chat.coffee
├── chat.js
├── core_api
│ ├── stats.coffee
│ ├── stats.js
│ ├── trade.coffee
│ ├── trade.js
│ ├── transactions.coffee
│ ├── transactions.js
│ ├── wallets.coffee
│ └── wallets.js
├── errors.coffee
├── errors.js
├── order_logs.coffee
├── order_logs.js
├── orders.coffee
├── orders.js
├── payments.coffee
├── payments.js
├── site.coffee
├── site.js
├── transactions.coffee
├── transactions.js
├── users.coffee
├── users.js
├── wallets.coffee
└── wallets.js
├── tests
├── helpers
│ ├── auth_helper.js
│ ├── btc_wallet_mock.coffee
│ ├── btc_wallet_mock.js
│ ├── ltc_wallet_mock.coffee
│ ├── ltc_wallet_mock.js
│ └── spec_helper.js
├── integrational
│ └── routes
│ │ ├── core_api
│ │ ├── stats.coffee
│ │ ├── trade.coffee
│ │ └── transactions.coffee
│ │ └── orders.coffee
└── unit
│ ├── lib
│ ├── fraud_helper.coffee
│ └── market_helper.coffee
│ └── models
│ ├── market_stats.coffee
│ ├── order.coffee
│ ├── payment.coffee
│ ├── transaction.coffee
│ ├── user.coffee
│ └── wallet.coffee
└── views
├── _analytics.jade
├── _config.jade
├── admin.jade
├── admin
├── login.jade
├── markets.jade
├── payments.jade
├── stats.jade
├── transactions.jade
├── user.jade
├── users.jade
├── wallet.jade
└── wallets.jade
├── auth.jade
├── auth
├── change_password.jade
├── login.jade
├── resend_verify_link.jade
├── send_password.jade
├── signup.jade
└── verify.jade
├── emails
├── change_password.html
├── confirm_email.html
└── user_login_notice.html
├── errors.jade
├── errors
├── 404.jade
└── 500.jade
├── layout.jade
├── site
├── _chatbox.jade
├── _footer.jade
├── _header.jade
├── _market-ticker.jade
├── _warnings.jade
├── funds.jade
├── funds
│ ├── _funds_list.jade
│ └── wallet.jade
├── index.jade
├── settings
│ ├── preferences.jade
│ ├── security.jade
│ └── settings.jade
├── status.jade
└── trade.jade
├── static
├── api.jade
├── cookie.jade
├── fees.jade
├── privacy.jade
├── security.jade
└── terms.jade
└── templates
├── chat_message.jade
├── coin_stats.jade
├── market_ticker.jade
├── open_order.jade
├── order_book_order.jade
├── pending_transaction.jade
├── site_closed_order.jade
├── transaction_history.jade
├── wallet_closed_order.jade
└── wallet_open_order.jade
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 |
17 | .DS_Store
18 | .idea
19 | .idea/*
20 | .settings.xml
21 | .monitor
22 | .env
23 | crash.log
24 | builtAssets
25 | config.json
26 | erl_crash.dump
27 | certs
28 | certs/*
29 |
30 | configs/wallets_config/*.json
31 |
32 | cron_dump/*.dump
33 | cron_dump/currency.dump
34 | cron_dump/currency_exclude.dump
35 |
--------------------------------------------------------------------------------
/Gruntfile.coffee:
--------------------------------------------------------------------------------
1 | # global module:false
2 | module.exports = (grunt) ->
3 |
4 | coffeeRename = (dest, src)->
5 | dest + '/' + src.replace(/\.coffee$/, '.js')
6 |
7 | # Project configuration.
8 | grunt.initConfig
9 | watch:
10 | tasks: ["coffee"]
11 | files: ["configs/**/*.coffee", "lib/**/*.coffee", "models/**/*.coffee", "routes/**/*.coffee", "tests/helpers/*.coffee"]
12 | options:
13 | spawn: false
14 |
15 | coffee:
16 | compile:
17 | files: [
18 | {expand: true, cwd: 'configs', src: ['**/*.coffee'], dest: 'configs', rename: coffeeRename}
19 | {expand: true, cwd: 'models', src: ['**/*.coffee'], dest: 'models', rename: coffeeRename}
20 | {expand: true, cwd: 'lib', src: ['**/*.coffee'], dest: 'lib', rename: coffeeRename}
21 | {expand: true, cwd: 'routes', src: ['**/*.coffee'], dest: 'routes', rename: coffeeRename}
22 | {expand: true, cwd: 'tests/helpers', src: ['*.coffee'], dest: 'tests/helpers', rename: coffeeRename}
23 | ]
24 |
25 | grunt.loadNpmTasks "grunt-contrib-coffee"
26 | grunt.loadNpmTasks "grunt-contrib-watch"
27 |
28 | # Default task.
29 | grunt.registerTask "default", "coffee"
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | REPORTER = nyan
3 | INTEGRATIONAL_TESTS = $(shell find tests/integrational -name "*.coffee")
4 | UNIT_TESTS = $(shell find tests/unit -name "*.coffee")
5 |
6 | test: test-integrational test-unit
7 |
8 | test-integrational:
9 | @NODE_ENV=test ./node_modules/.bin/mocha -u bdd \
10 | --reporter $(REPORTER) \
11 | --compilers coffee:coffee-script/register \
12 | --timeout 10000 \
13 | $(INTEGRATIONAL_TESTS)
14 |
15 | test-unit:
16 | @NODE_ENV=test ./node_modules/.bin/mocha -u bdd \
17 | --reporter $(REPORTER) \
18 | --compilers coffee:coffee-script/register \
19 | --timeout 10000 \
20 | $(UNIT_TESTS)
21 |
22 | test-w:
23 | @NODE_ENV=test ./node_modules/.bin/mocha -u bdd -b \
24 | --reporter $(REPORTER) \
25 | --compilers coffee:coffee-script/register \
26 | --watch \
27 | --growl \
28 | $(INTEGRATIONAL_TESTS)
29 |
30 | test-one:
31 | @NODE_ENV=test ./node_modules/.bin/mocha -u bdd -b \
32 | --reporter $(REPORTER) \
33 | --compilers coffee:coffee-script/register \
34 | --timeout 3000 \
35 | $f
36 |
37 | test-one-w:
38 | @NODE_ENV=test ./node_modules/.bin/mocha -u bdd -b \
39 | --reporter $(REPORTER) \
40 | --compilers coffee:coffee-script/register \
41 | --watch \
42 | --growl \
43 | $f
44 |
45 | .PHONY: test-integrational test-w test-unit test-one
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | coinnext
2 | ========
3 |
4 | Virtual coins market
5 |
6 | [App setup guide](https://www.evernote.com/l/AWWu1FCvmwlIIZZQYQmMzk9V1SEmmsFuCdk)
7 |
--------------------------------------------------------------------------------
/admin.js:
--------------------------------------------------------------------------------
1 | // Configure logger
2 | if (process.env.NODE_ENV === "production") require("./configs/logger");
3 |
4 | // Configure modules
5 | var express = require('express');
6 | var http = require('http');
7 | var RedisStore = require('connect-redis')(express);
8 | var helmet = require('helmet');
9 | var CoreAPIClient = require('./lib/core_api_client');
10 | var _str = require("./lib/underscore_string");
11 | var _ = require("underscore");
12 | var environment = process.env.NODE_ENV || 'development';
13 |
14 | // Configure globals
15 | GLOBAL.appConfig = require("./configs/config");
16 | GLOBAL.passport = require('passport');
17 | GLOBAL.coreAPIClient = new CoreAPIClient({host: GLOBAL.appConfig().wallets_host});
18 | GLOBAL.db = require('./models/index');
19 |
20 | require('./lib/admin_auth');
21 |
22 |
23 | // Setup express
24 | var app = express();
25 | var connectAssetsOptions = environment !== 'development' ? {minifyBuilds: true} : {};
26 | connectAssetsOptions.helperContext = app.locals
27 | app.locals._ = _;
28 | app.locals._str = _str;
29 | app.enable("trust proxy");
30 | app.disable('x-powered-by');
31 | app.configure(function () {
32 | app.set('port', process.env.PORT || 6983);
33 | app.set('views', __dirname + '/views');
34 | app.set('view engine', 'jade');
35 | app.use(express.compress());
36 | app.use(express.bodyParser());
37 | app.use(express.methodOverride());
38 | app.use(express.cookieParser(GLOBAL.appConfig().session.admin.cookie_secret));
39 | app.use(express.session({
40 | key: GLOBAL.appConfig().session.admin.session_key,
41 | store: new RedisStore(GLOBAL.appConfig().redis),
42 | proxy: true,
43 | cookie: GLOBAL.appConfig().session.admin.cookie
44 | }));
45 | if (environment !== "test") {
46 | app.use(express.csrf());
47 | app.use(function(req, res, next) {
48 | res.locals.csrfToken = req.csrfToken();
49 | next();
50 | });
51 | app.use(helmet.xframe('sameorigin'));
52 | app.use(helmet.hsts());
53 | app.use(helmet.iexss({setOnOldIE: true}));
54 | app.use(helmet.ienoopen());
55 | app.use(helmet.contentTypeOptions());
56 | app.use(helmet.cacheControl());
57 | }
58 | app.use(express.static(__dirname + '/public'));
59 | app.use(require('connect-assets')(connectAssetsOptions));
60 | app.use(passport.initialize());
61 | app.use(passport.session());
62 | app.use(app.router);
63 | app.use(function(err, req, res, next) {
64 | console.error(err);
65 | res.send(500, "Oups, seems that there is an error on our side. Your coins are safe and we'll be back shortly...");
66 | });
67 | });
68 |
69 |
70 | // Configuration
71 |
72 | app.configure('development', function(){
73 | app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
74 | });
75 |
76 | app.configure('production', function(){
77 | app.use(express.errorHandler());
78 | });
79 |
80 | var server = http.createServer(app);
81 |
82 | server.listen(app.get('port'), function(){
83 | console.log("Coinnext admin is running on port %d in %s mode", app.get("port"), app.settings.env);
84 | });
85 |
86 |
87 | // Routes
88 | require('./routes/admin')(app);
89 |
--------------------------------------------------------------------------------
/assets/css/chat.styl:
--------------------------------------------------------------------------------
1 | /* Chatbox */
2 | .chatbox
3 | @extends .container
4 | width 300px
5 | height 400px
6 | font-size 13px
7 |
8 | .message-list
9 | reset-list()
10 | padding 10px
11 | overflow-y scroll
12 | position absolute
13 | width 100%
14 | bottom 40px
15 | top 0
16 |
17 | .message
18 | margin-bottom 3px
19 | overflow hidden
20 | word-wrap break-word
21 | .sender
22 | font-weight bold
23 | color $blue
24 |
25 | .message-post
26 | position absolute
27 | bottom 0
28 | width 100%
29 | height 40px
30 | overflow hidden
31 | border-top 1px solid #e0e0e0
32 |
33 | .login-required
34 | padding 0 10px
35 | line-height 40px
36 | margin 0
37 |
38 | .chat-message-input
39 | border 0
40 | background transparent
41 | height 40px
42 | font-size 13px
43 | width 100%
44 | padding-right 60px
45 | #send-message-bt
46 | btn($blue)
47 | padding 0
48 | position absolute
49 | top 0
50 | right 0
51 | width 50px
52 | height 30px
53 | margin 5px
54 | font-size 13px
55 | z-index 1
--------------------------------------------------------------------------------
/assets/css/errors.styl:
--------------------------------------------------------------------------------
1 | html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6,
2 | p, blockquote, pre, a, abbr, address, cite, code, del, dfn, em,
3 | img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, hr,
4 | dl, dt, dd, ol, ul, li, fieldset, form, label, legend,
5 | table, caption, tbody, tfoot, thead, tr, th, td,
6 | article, aside, canvas, details, figure, figcaption, hgroup,
7 | menu, footer, header, nav, section, summary, time, mark, audio, video
8 | margin 0
9 | padding 0
10 | border 0
11 |
12 | body
13 | background #eceef1
14 | color #484c57
15 | font-family "Helvetica Neue", Helvetica, Arial, sans-serif
16 | font-size 100%
17 | text-align center
18 |
19 | .container
20 | background #fff
21 | border 1px solid #d5d5d5
22 | border-radius 3px
23 | padding 40px
24 | margin 0 auto
25 | margin-top 15%
26 | display inline-block
27 |
28 | h1
29 | margin 0 0 10px 0
30 | color #14294e
31 |
32 | label
33 | font-weight 500
34 |
35 | label, a
36 | color #549cd5
37 |
38 | a
39 | text-decoration none
40 | &:hover
41 | text-decoration underline
42 |
43 | p
44 | font-size 1.125em
45 | line-height 1.5em
46 | font-weight 300
47 | margin 0
--------------------------------------------------------------------------------
/assets/css/plugins/cdn.js:
--------------------------------------------------------------------------------
1 | var plugin = function(){
2 | return function(style){
3 | style.define("CDN", function(imgOptions) {
4 | var host = GLOBAL.appConfig().assets_host || "";
5 | var glueSign = imgOptions.string.indexOf("?") > -1 ? "&" : "?";
6 | var key = GLOBAL.appConfig().assets_key ? glueSign + "_=" + GLOBAL.appConfig().assets_key : "";
7 | return host + imgOptions.string + key;
8 | });
9 | };
10 | };
11 | module.exports = plugin;
--------------------------------------------------------------------------------
/assets/css/static.styl:
--------------------------------------------------------------------------------
1 | /* Terms */
2 | .last-updated
3 | font-style italic
4 | background #fafbd2
5 | border-radius 2px
6 | display inline-block
7 |
8 | h2
9 | font-size 15px
10 | margin 15px 0 5px
11 | font-weight 700
12 |
13 | .page-title
14 | color $text-color
15 | font-family "Open Sans", helvetica, arial, sans-serif
16 | margin 0 0 10px 0
17 | font-size 24px
18 | font-weight 500
19 |
20 | .content
21 | ol
22 | ul
23 | padding-left 20px
24 | margin 0 0 10px 0
25 |
26 | p
27 | max-width 800px
28 |
29 | #qr-gen-bt
30 | btn($teal)
31 | display inline-block
32 |
33 | .settings
34 | .con-body
35 | padding 15px 10px
36 |
37 | .appstore-badges
38 | font-size 0
39 |
40 | .appstore
41 | background transparent url(CDN('/img/appstore-sprite.png')) no-repeat
42 | display inline-block
43 | width 143px
44 | height 42px
45 | overflow hidden
46 | text-indent -999px
47 | border-radius 3px
48 | border 1px solid #000
49 | margin-right 10px
50 |
51 | .appstore-apple
52 | background #000 url(CDN('/img/appstore-sprite.png')) -1px -1px no-repeat
53 |
54 | .appstore-google
55 | background #000 url(CDN('/img/appstore-sprite.png')) -155px -1px no-repeat
56 |
57 | #username-update-form
58 | label
59 | margin-right 10px
60 | input
61 | width 250px
62 |
63 | .content
64 | .profile-group
65 | reset-list()
66 | clearfix()
67 |
68 | .profile
69 | width 400px
70 | margin 10px 40px 0px 0
71 | float left
72 | .portrait
73 | border-radius 2px
74 | overflow hidden
75 | float left
76 | margin 0 15px 0 0
77 | h3
78 | margin 0 0 3px 0
79 | font-size 16px
80 | h4
81 | margin 0 0 5px 0
82 | text-transform uppercase
83 | color $lightgray
84 | font-weight 400
85 |
86 | /* Api */
87 | .api
88 | background #f9f9f9
89 | padding 10px
90 | display block
91 | border 1px solid $border-color
92 | border-radius 2px
93 | margin-bottom 10px
94 | label
95 | &.get
96 | background $blue
97 | color #fff
98 | font-weight bold
99 | display inline-block
100 | padding 5px 10px
101 | border-radius 2px
102 | margin-right 10px
103 | text-transform uppercase
104 |
105 | .example
106 | font-style italic
107 |
108 | /* Status */
109 | .status-legend
110 | vertical-align top
111 | margin-bottom 10px
112 | max-width 800px
113 | td
114 | padding 5px 0
115 | .label
116 | padding-right 10px
117 |
118 | .wallet-status
119 | color #fff
120 | padding 3px 5px
121 | text-transform uppercase
122 | font-size .8em
123 | font-weight 700
124 | width 70px
125 | display inline-block
126 | text-align center
127 | border-radius 2px
128 | &.normal
129 | background-color $teal
130 | &.blocked
131 | background-color $red
132 | &.delayed
133 | background-color #f4ca06
134 | &.error
135 | background-color #c9c9c9
136 |
--------------------------------------------------------------------------------
/assets/js/admin.js:
--------------------------------------------------------------------------------
1 | //= require vendor/jquery-1.10.2
2 | //= require vendor/jquery.tmpload
3 | //= require vendor/date.format
4 | //= require vendor/math
5 | //= require vendor/underscore
6 | //= require vendor/underscore.string
7 | //= require vendor/backbone
8 |
9 | //= require app/helpers/json
10 |
11 | //= require admin_bootstrap
--------------------------------------------------------------------------------
/assets/js/app/collections/order_logs.coffee:
--------------------------------------------------------------------------------
1 | class window.App.OrderLogsCollection extends Backbone.Collection
2 |
3 | currency1: null
4 |
5 | currency2: null
6 |
7 | url: ()->
8 | url = "/order_logs"
9 | params = {}
10 | params.action = @action if @action
11 | params.currency1 = @currency1 if @currency1
12 | params.currency2 = @currency2 if @currency2
13 | params.user_id = @userId if @userId
14 | params.sort_by = @orderBy if @orderBy
15 | url += "?#{$.param(params)}"
16 |
17 | model: window.App.OrderLogModel
18 |
19 | initialize: (models, options = {})->
20 | @action = options.action
21 | @currency1 = options.currency1
22 | @currency2 = options.currency2
23 | @userId = options.userId
24 | @orderBy = options.orderBy
25 |
26 | calculateVolume: ()->
27 | total = 0
28 | @each (order)->
29 | total = App.math.add(total, order.calculateFirstNoFeeAmount())
30 | _.str.satoshiRound total
31 |
32 | calculateVolumeForPriceLimit: (unitPrice)->
33 | unitPrice = _.str.satoshiRound(unitPrice)
34 | totalAmount = 0
35 | @each (order)->
36 | orderPrice = _.str.satoshiRound(order.get("unit_price"))
37 | totalAmount = App.math.add(totalAmount, order.calculateFirstNoFeeAmount()) if orderPrice <= unitPrice
38 | return if orderPrice > unitPrice
39 | _.str.satoshiRound totalAmount
40 |
--------------------------------------------------------------------------------
/assets/js/app/collections/orders.coffee:
--------------------------------------------------------------------------------
1 | class window.App.OrdersCollection extends Backbone.Collection
2 |
3 | type: null
4 |
5 | currency1: null
6 |
7 | currency2: null
8 |
9 | published: null
10 |
11 | url: ()->
12 | url = "/orders"
13 | params = {}
14 | params.status = @type if @type
15 | params.action = @action if @action
16 | params.currency1 = @currency1 if @currency1
17 | params.currency2 = @currency2 if @currency2
18 | params.published = @published if @published?
19 | params.user_id = @userId if @userId
20 | params.sort_by = @orderBy if @orderBy
21 | url += "?#{$.param(params)}"
22 |
23 | model: window.App.OrderModel
24 |
25 | initialize: (models, options = {})->
26 | @type = options.type
27 | @action = options.action
28 | @currency1 = options.currency1
29 | @currency2 = options.currency2
30 | @published = options.published
31 | @userId = options.userId
32 | @orderBy = options.orderBy
33 |
34 | calculateVolume: ()->
35 | total = 0
36 | @each (order)->
37 | total = App.math.add(total, order.calculateFirstNoFeeAmount())
38 | _.str.satoshiRound total
39 |
40 | calculateVolumeForPriceLimit: (unitPrice)->
41 | unitPrice = _.str.satoshiRound(unitPrice)
42 | totalAmount = 0
43 | @each (order)->
44 | orderPrice = _.str.satoshiRound(order.get("unit_price"))
45 | totalAmount = App.math.add(totalAmount, order.calculateFirstNoFeeAmount()) if orderPrice <= unitPrice
46 | return if orderPrice > unitPrice
47 | _.str.satoshiRound totalAmount
48 |
49 | getStacked: ()->
50 | stackedOrders = {}
51 | @each (order)->
52 | unitPrice = _.str.toFixed order.get("unit_price")
53 | stackId = "id-#{unitPrice}"
54 | stackedOrders[stackId] = new App.OrderModel if not stackedOrders[stackId]
55 | stackedOrders[stackId].mergeWithOrder order
56 | _.values stackedOrders
57 |
58 | getIds: ()->
59 | ids = []
60 | @each (order)->
61 | ids.push order.id
62 | ids
63 |
--------------------------------------------------------------------------------
/assets/js/app/collections/payments.coffee:
--------------------------------------------------------------------------------
1 | class window.App.PaymentsCollection extends Backbone.Collection
2 |
3 | type: null
4 |
5 | walletId: null
6 |
7 | url: ()->
8 | url = "/payments"
9 | url += "/#{@type}" if @type
10 | url += "/#{@walletId}" if @walletId
11 | url
12 |
13 | model: window.App.PaymentModel
14 |
15 | initialize: (models, options = {})->
16 | @type = options.type
17 | @walletId = options.walletId
18 |
--------------------------------------------------------------------------------
/assets/js/app/collections/trade_stats.coffee:
--------------------------------------------------------------------------------
1 | class window.App.TradeStatsCollection extends Backbone.Collection
2 |
3 | type: null
4 |
5 | url: ()->
6 | "/trade_stats/#{@type}"
7 |
8 | initialize: (models, options = {})->
9 | @type = options.type
--------------------------------------------------------------------------------
/assets/js/app/collections/transactions.coffee:
--------------------------------------------------------------------------------
1 | class window.App.TransactionsCollection extends Backbone.Collection
2 |
3 | type: null
4 |
5 | walletId: null
6 |
7 | url: ()->
8 | url = "/transactions"
9 | url += "/#{@type}" if @type
10 | url += "/#{@walletId}" if @walletId
11 | url
12 |
13 | model: window.App.TransactionModel
14 |
15 | initialize: (models, options = {})->
16 | @type = options.type
17 | @walletId = options.walletId
18 |
--------------------------------------------------------------------------------
/assets/js/app/collections/wallets.coffee:
--------------------------------------------------------------------------------
1 | class window.App.WalletsCollection extends Backbone.Collection
2 |
3 | url: "/wallets"
4 |
5 | model: window.App.WalletModel
6 |
--------------------------------------------------------------------------------
/assets/js/app/error_logger.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.ErrorLogger
4 |
5 | constructor: ()->
6 | $.subscribe "error", @renderError
7 | $.subscribe "notice", @renderNotice
8 |
9 | renderError: (ev, xhrError = {}, $form)=>
10 | if xhrError.responseText
11 | try
12 | error = $.parseJSON xhrError.responseText
13 | error = error.error
14 | catch e
15 | error = xhrError.responseText
16 | else
17 | error = xhrError.error or xhrError
18 | return $form.find("#error-cnt").text error if $form
19 | $.jGrowl error,
20 | position: "top-right"
21 | theme: "error"
22 |
23 | renderNotice: (ev, msg)=>
24 | $.jGrowl msg,
25 | position: "top-right"
26 | theme: "notice"
--------------------------------------------------------------------------------
/assets/js/app/helpers/crypto_currency.coffee:
--------------------------------------------------------------------------------
1 | window.App = window.App or {}
2 | window.App.Helpers = window.App.Helpers or {}
3 | window.App.Helpers.CryptoCurrency =
4 |
5 | isValidAddress: (address) ->
6 | decoded = @base58_decode(address)
7 | return false unless decoded.length is 25
8 | true
9 | #cksum = decoded.substr(decoded.length - 4)
10 | #rest = decoded.substr(0, decoded.length - 4)
11 | #good_cksum = @hex2a(sha256_digest(@hex2a(sha256_digest(rest)))).substr(0, 4)
12 | #return false unless cksum is good_cksum
13 | #true
14 |
15 | base58_decode: (string) ->
16 | table = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
17 | table_rev = new Array()
18 | i = undefined
19 | i = 0
20 | while i < 58
21 | table_rev[table[i]] = int2bigInt(i, 8, 0)
22 | i++
23 | l = string.length
24 | long_value = int2bigInt(0, 1, 0)
25 | num_58 = int2bigInt(58, 8, 0)
26 | c = undefined
27 | i = 0
28 | while i < l
29 | c = string[l - i - 1]
30 | long_value = add(long_value, mult(table_rev[c], @pow(num_58, i)))
31 | i++
32 | hex = bigInt2str(long_value, 16)
33 | str = @hex2a(hex)
34 | nPad = undefined
35 | nPad = 0
36 | while string[nPad] is table[0]
37 | nPad++
38 | output = str
39 | output = @repeat("\u0000", nPad) + str if nPad > 0
40 | output
41 |
42 | hex2a: (hex) ->
43 | str = ""
44 | i = 0
45 |
46 | while i < hex.length
47 | str += String.fromCharCode(parseInt(hex.substr(i, 2), 16))
48 | i += 2
49 | str
50 |
51 | pow: (big, exp) ->
52 | return int2bigInt(1, 1, 0) if exp is 0
53 | i = undefined
54 | newbig = big
55 | i = 1
56 | while i < exp
57 | newbig = mult(newbig, big)
58 | i++
59 | newbig
60 |
61 | repeat: (s, n) ->
62 | a = []
63 | a.push s while a.length < n
64 | a.join ""
--------------------------------------------------------------------------------
/assets/js/app/helpers/json.coffee:
--------------------------------------------------------------------------------
1 | window.App = window.App or {}
2 | window.App.Helpers = window.App.Helpers or {}
3 | window.App.Helpers.JSON =
4 |
5 | # Format JSON function
6 | # http://ketanjetty.com/coldfusion/javascript/format-json/
7 | toHTML: (jsonString)->
8 | jsonString = JSON.stringify(jsonString) if typeof jsonString is "object"
9 | jsonString.replace(/(\\'|\\")/g, "")
10 | retval = ''
11 | pos = 0
12 | strLen = jsonString.length
13 | indentStr = ' '
14 | newLine = '
'
15 |
16 | for char in jsonString
17 |
18 | if char is "}" or char is "]"
19 | retval = retval + newLine
20 | pos = pos - 1
21 |
22 | j = 0
23 | while j < pos
24 | retval = retval + indentStr
25 | j++
26 |
27 | retval = retval + char
28 |
29 | if char is "{" or char is "[" or char is ","
30 | retval = retval + newLine
31 | pos = pos + 1 if char is "{" or char is "["
32 |
33 | k = 0
34 | while k < pos
35 | retval = retval + indentStr
36 | k++
37 |
38 | retval
--------------------------------------------------------------------------------
/assets/js/app/models/google_auth.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.GoogleAuthModel extends Backbone.Model
4 |
5 | urlRoot: "/google_auth"
6 |
--------------------------------------------------------------------------------
/assets/js/app/models/market_stats.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.MarketStatsModel extends Backbone.Model
4 |
5 | urlRoot: "/market_stats"
6 |
--------------------------------------------------------------------------------
/assets/js/app/models/order_log.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.OrderLogModel extends Backbone.Model
4 |
5 | urlRoot: "/order_logs"
6 |
7 | calculateFirstAmount: ()->
8 | return _.str.satoshiRound @get("result_amount") if @get("action") is "buy"
9 | return _.str.satoshiRound @get("matched_amount") if @get("action") is "sell"
10 |
11 | calculateSecondAmount: ()->
12 | return _.str.satoshiRound @get("result_amount") if @get("action") is "sell"
13 | return _.str.satoshiRound App.math.multiply @get("matched_amount"), @get("unit_price") if @get("action") is "buy"
14 |
15 | getTime: ()->
16 | new Date(@get('time')).format('dd.mm.yy H:MM')
17 |
--------------------------------------------------------------------------------
/assets/js/app/models/payment.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.PaymentModel extends Backbone.Model
4 |
5 | urlRoot: "/payments"
6 |
--------------------------------------------------------------------------------
/assets/js/app/models/transaction.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.TransactionModel extends Backbone.Model
4 |
5 | urlRoot: "/transactions"
6 |
7 | getCreatedDate: ()->
8 | new Date(@get('created_at')).format('dd.mm.yy H:MM')
--------------------------------------------------------------------------------
/assets/js/app/models/user.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.UserModel extends Backbone.Model
4 |
5 | urlRoot: "/user"
6 |
--------------------------------------------------------------------------------
/assets/js/app/models/wallet.coffee:
--------------------------------------------------------------------------------
1 | window.App or= {}
2 |
3 | class App.WalletModel extends Backbone.Model
4 |
5 | urlRoot: "/wallets"
6 |
--------------------------------------------------------------------------------
/assets/js/app/views/market_ticker.coffee:
--------------------------------------------------------------------------------
1 | class App.MarketTickerView extends App.MasterView
2 |
3 | model: null
4 |
5 | tpl: "market-ticker-tpl"
6 |
7 | activeCurrency: null
8 |
9 | initialize: (options = {})->
10 | $.subscribe "market-stats-updated", @onMarketStatsUpdated
11 |
12 | render: ()->
13 | @model.fetch
14 | success: ()=>
15 | @renderMarketTicker()
16 | error: ()=>
17 |
18 | renderMarketTicker: ()->
19 | @$el.html @template
20 | marketStats: @model
21 | @markActive()
22 |
23 | markActive: (currency = null)->
24 | @activeCurrency = currency if currency
25 | @$("[data-market-currency='#{@activeCurrency}']").addClass "active"
26 |
27 | onMarketStatsUpdated: (ev, data)=>
28 | @render()
29 |
--------------------------------------------------------------------------------
/assets/js/app/views/master.coffee:
--------------------------------------------------------------------------------
1 | class App.MasterView extends Backbone.View
2 |
3 | template: (data)->
4 | tpl = $.tmpload
5 | id: @tpl
6 | tpl data
7 |
8 | toggleVisible: ()=>
9 | if @$el.is ":empty"
10 | @$el.parents(".container:first").hide()
11 | else
12 | @$el.parents(".container:first").show()
--------------------------------------------------------------------------------
/assets/js/app/views/order_book.coffee:
--------------------------------------------------------------------------------
1 | class App.OrderBookView extends App.MasterView
2 |
3 | tpl: null
4 |
5 | collection: null
6 |
7 | events:
8 | "click .order-book-order": "onOrderClick"
9 |
10 | initialize: (options = {})->
11 | @tpl = options.tpl if options.tpl
12 | @$totalsEl = options.$totalsEl if options.$totalsEl
13 | $.subscribe "new-order", @onNewOrder
14 | $.subscribe "order-completed", @onOrderMatched
15 | $.subscribe "order-partially-completed", @onOrderMatched
16 | $.subscribe "order-canceled", @onOrderCanceled
17 |
18 | render: ()->
19 | @collection.fetch
20 | success: ()=>
21 | @$el.empty()
22 | for order in @collection.getStacked()
23 | @$el.append @template
24 | order: order
25 | @renderVolume() if @$totalsEl
26 |
27 | renderVolume: ()->
28 | @$totalsEl.text _.str.toFixed @collection.calculateVolume()
29 |
30 | onNewOrder: (ev, order)=>
31 | @render()
32 |
33 | onOrderMatched: (ev, order)=>
34 | unitPrice = _.str.toFixed order.get("unit_price")
35 | $existentOrder = @$("[data-unit-price='#{unitPrice}']")
36 | if $existentOrder.length
37 | $existentOrder.addClass "highlight"
38 | setTimeout ()=>
39 | $existentOrder.removeClass "highlight" if $existentOrder.length
40 | @render()
41 | , 1000
42 |
43 | onOrderCanceled: (ev, data)=>
44 | @render()
45 |
46 | onOrderClick: (ev)->
47 | $row = $(ev.currentTarget)
48 | unitPrice = parseFloat $row.data "unit-price"
49 | action = $row.data "action"
50 | order = new App.OrderModel
51 | unit_price: unitPrice
52 | action: action
53 | amount: @collection.calculateVolumeForPriceLimit unitPrice
54 | $.publish "order-book-order-selected", order
--------------------------------------------------------------------------------
/assets/js/app/views/order_logs.coffee:
--------------------------------------------------------------------------------
1 | class App.OrderLogsView extends App.MasterView
2 |
3 | tpl: null
4 |
5 | collection: null
6 |
7 | hideOnEmpty: false
8 |
9 | initialize: (options = {})->
10 | @tpl = options.tpl if options.tpl
11 | @hideOnEmpty = options.hideOnEmpty if options.hideOnEmpty
12 | @toggleVisible()
13 | $.subscribe "order-completed", @onOrderCompleted
14 | $.subscribe "order-partially-completed", @onOrderPartiallyCompleted
15 |
16 | render: (method)->
17 | @collection.fetch
18 | success: ()=>
19 | @renderOrders method
20 | @toggleVisible() if @hideOnEmpty
21 |
22 | renderOrders: (method = "append")->
23 | @collection.each (order)=>
24 | $existentOrder = @$("[data-id='#{order.id}']")
25 | tpl = @template
26 | order: order
27 | @$el[method] tpl if not $existentOrder.length
28 | $existentOrder.replaceWith tpl if $existentOrder.length
29 |
30 | onOrderCompleted: (ev, order)=>
31 | @render "prepend"
32 |
33 | onOrderPartiallyCompleted: (ev, order)=>
34 | @render "prepend"
--------------------------------------------------------------------------------
/assets/js/app/views/pending_transactions.coffee:
--------------------------------------------------------------------------------
1 | class App.PendingTransactionsView extends App.MasterView
2 |
3 | tpl: "pending-transaction-tpl"
4 |
5 | collection: null
6 |
7 | payments: null
8 |
9 | initialize: (options = {})->
10 | @payments = options.payments
11 | @hideOnEmpty = options.hideOnEmpty if options.hideOnEmpty
12 | @toggleVisible()
13 | $.subscribe "payment-submited", @onPaymentSubmited
14 | $.subscribe "payment-processed", @onPaymentProcessed
15 | $.subscribe "transaction-update", @onTransactionUpdate
16 |
17 | render: ()->
18 | @collection.fetch
19 | success: ()=>
20 | @collection.each (transaction)=>
21 | $tx = @template
22 | transaction: transaction
23 | $existentTx = @$("[data-id='#{transaction.id}']")
24 | if not $existentTx.length
25 | @$el.append $tx
26 | else
27 | $existentTx.replaceWith $tx
28 | @toggleVisible() if @hideOnEmpty
29 | @payments.fetch
30 | success: ()=>
31 | @payments.each (payment)=>
32 | $pm = @template
33 | payment: payment
34 | $existentPm = @$("[data-id='#{payment.id}']")
35 | if not $existentPm.length
36 | @$el.append $pm
37 | else
38 | $existentPm.replaceWith $pm
39 | @toggleVisible() if @hideOnEmpty
40 |
41 | onTransactionUpdate: (ev, transaction)=>
42 | @render()
43 | @$("[data-id='#{transaction.id}']").remove() if transaction.get("balance_loaded")
44 |
45 | onPaymentProcessed: (ev, payment)=>
46 | @render()
47 | @$("[data-id='#{payment.id}']").remove()
48 |
49 | onPaymentSubmited: (ev, payment)=>
50 | @render()
51 |
--------------------------------------------------------------------------------
/assets/js/app/views/trade_chart.coffee:
--------------------------------------------------------------------------------
1 | class App.TradeChartView extends App.MasterView
2 |
3 | collection: null
4 |
5 | initialize: (options = {})->
6 |
7 | render: ()->
8 | @collection.fetch
9 | success: ()=>
10 | @renderChart @collection.toJSON()
11 |
12 | renderChart: (data)->
13 | # split the data set into ohlc and volume
14 | ohlc = []
15 | volume = []
16 | xAxis = []
17 | dataLength = data.length
18 | i = 0
19 | while i < dataLength
20 | startTime = new Date(data[i].start_time).getTime()
21 | ohlc.push [
22 | startTime # the date
23 | data[i].open_price # open
24 | data[i].high_price # high
25 | data[i].low_price # low
26 | data[i].close_price # close
27 | ]
28 | volume.push [
29 | startTime # the date
30 | data[i].volume # the volume
31 | ]
32 | i++
33 |
34 | # create the chart
35 | @$el.highcharts "StockChart",
36 | rangeSelector:
37 | enabled: false
38 | scrollbar:
39 | enabled: false
40 | navigator:
41 | enabled: false
42 |
43 | exporting:
44 | buttons: [
45 | printButton:
46 | enabled: false
47 | exportButton:
48 | enabled: false
49 | ]
50 | credits:
51 | enabled: false
52 |
53 | yAxis: [
54 | {
55 | lineWidth: 0
56 | gridLineColor: "#ecedef"
57 | }
58 | {
59 | gridLineWidth: 0
60 | opposite: true
61 | }
62 | ]
63 | xAxis:
64 | lineColor: "#ecedef"
65 | type: "time"
66 | dateTimeLabelFormats:
67 | millisecond: '%H:%M'
68 | tooltip:
69 | shared: true
70 | shadow: false
71 | backgroundColor: "#ffffff"
72 | borderColor: "#d1d5dd"
73 | formatter: ()->
74 | s = Highcharts.dateFormat('%b %e %Y %H:%M', this.x) + "
"
75 | s += "Open: " + _.str.toFixed(@points[1].point.open) + "
"
76 | s += "High: " + _.str.toFixed(@points[1].point.high) + "
"
77 | s += "Low: " + _.str.toFixed(@points[1].point.low) + "
"
78 | s += "Close: " + _.str.toFixed(@points[1].point.close) + "
"
79 | s += "Volume: " + _.str.toFixed(@points[0].point.y)
80 | return s
81 | series: [
82 | {
83 | type: "column"
84 | name: "Volume"
85 | data: volume
86 | yAxis: 1
87 | color: "#dddddd"
88 | }
89 | {
90 | type: "candlestick"
91 | name: "Price"
92 | data: ohlc
93 | yAxis: 0
94 | color: "#3eae5f"
95 | upColor: "#da4444"
96 | lineColor: "#3eae5f"
97 | upLineColor: "#da4444"
98 | borderWidth: 0
99 | }
100 | ]
101 |
--------------------------------------------------------------------------------
/assets/js/app/views/transactions_history.coffee:
--------------------------------------------------------------------------------
1 | class App.TransactionsHistoryView extends App.MasterView
2 |
3 | tpl: "transaction-history-tpl"
4 |
5 | collection: null
6 |
7 | initialize: (options = {})->
8 | @hideOnEmpty = options.hideOnEmpty if options.hideOnEmpty
9 | @toggleVisible()
10 | $.subscribe "payment-processed", @onPaymentProcessed
11 | $.subscribe "transaction-update", @onTransactionUpdate
12 |
13 | render: ()->
14 | @collection.fetch
15 | success: ()=>
16 | @renderTransactions()
17 | @toggleVisible() if @hideOnEmpty
18 |
19 | renderTransactions: ()->
20 | @collection.each (transaction)=>
21 | $existentTransaction = @$("[data-id='#{transaction.id}']")
22 | tpl = @template
23 | transaction: transaction
24 | @$el.append tpl if not $existentTransaction.length
25 | $existentTransaction.replaceWith tpl if $existentTransaction.length
26 |
27 | onTransactionUpdate: (ev, transaction)=>
28 | @render()
29 |
30 | onPaymentProcessed: (ev, payment)=>
31 | @render()
32 |
--------------------------------------------------------------------------------
/assets/js/application.js:
--------------------------------------------------------------------------------
1 | //= require vendor/modernizr-2.7.1.min
2 | //= require vendor/jquery-1.10.2
3 | //= require vendor/date.format
4 | //= require vendor/math
5 | //= require vendor/underscore
6 | //= require vendor/underscore.string
7 | //= require vendor/backbone
8 | //= require vendor/qrcode
9 | //= require vendor/ba-tiny-pubsub
10 | //= require vendor/jquery.validate
11 | //= require vendor/jquery.tmpload
12 | //= require vendor/jquery.jgrowl
13 | //= require vendor/ZeroClipboard
14 | //= require vendor/highstock
15 | //= require vendor/highstock.exporting
16 | //= require vendor/BigInt
17 | //= require vendor/sha256
18 | //= require vendor/zxcvbn
19 | //= require vendor/socket.io
20 | //= require vendor/mailcheck
21 |
22 | //= require app/helpers/crypto_currency
23 |
24 | //= require app/models/user
25 | //= require app/models/google_auth
26 | //= require app/models/wallet
27 | //= require app/models/payment
28 | //= require app/models/transaction
29 | //= require app/models/order
30 | //= require app/models/order_log
31 | //= require app/models/market_stats
32 |
33 | //= require app/collections/wallets
34 | //= require app/collections/transactions
35 | //= require app/collections/payments
36 | //= require app/collections/orders
37 | //= require app/collections/order_logs
38 | //= require app/collections/trade_stats
39 |
40 | //= require app/views/master
41 | //= require app/views/finances
42 | //= require app/views/settings
43 | //= require app/views/pending_transactions
44 | //= require app/views/transactions_history
45 | //= require app/views/trade
46 | //= require app/views/trade_chart
47 | //= require app/views/orders
48 | //= require app/views/order_book
49 | //= require app/views/order_logs
50 | //= require app/views/market_ticker
51 |
52 | //= require chat/models/chat_message
53 | //= require chat/collections/chat_messages
54 | //= require chat/views/chat
55 |
56 | //= require app/error_logger
57 |
58 | //= require auth_bootstrap
59 | //= require app_bootstrap
60 | //= require chat_bootstrap
--------------------------------------------------------------------------------
/assets/js/chat/collections/chat_messages.coffee:
--------------------------------------------------------------------------------
1 | class App.ChatMessagesCollection extends Backbone.Collection
2 |
3 | model: App.ChatMessageModel
4 |
5 | url: "/chat/messages"
6 |
7 | initialize: (models, options)->
8 |
9 |
--------------------------------------------------------------------------------
/assets/js/chat/models/chat_message.coffee:
--------------------------------------------------------------------------------
1 | class App.ChatMessageModel extends Backbone.Model
--------------------------------------------------------------------------------
/assets/js/chat/views/chat.coffee:
--------------------------------------------------------------------------------
1 | class App.ChatView extends App.MasterView
2 |
3 | tpl: "chat-message-tpl"
4 |
5 | chatSocketUrl: null
6 |
7 | messageHistoryRootUrl: null
8 |
9 | events:
10 | "keydown #chat-message-box": "onMessageTyping"
11 | "click #send-message-bt": "onSendClick"
12 |
13 | initialize: ({@user, @chatSocketUrl, @messageHistoryRootUrl})->
14 | @chatSocketUrl ?= "/chat"
15 |
16 | render: ()->
17 | @loadHistory()
18 | @socket = io.connect @chatSocketUrl
19 | @socket.on "connect", ()=>
20 | # @socket.emit "join"
21 | @socket.on "new-message", (data)=>
22 | #console.log data
23 | @renderMessage data
24 |
25 | loadHistory: ()->
26 | messagesCollection = new App.ChatMessagesCollection null, {room: @room}
27 | messagesCollection.rootUrl = @messageHistoryRootUrl if @messageHistoryRootUrl
28 | messagesCollection.fetch
29 | success: ()=>
30 | messagesCollection.each (message)=>
31 | @renderMessage message, "prepend"
32 |
33 | renderMessage: (message = {}, mode = "append")->
34 | if not (message instanceof App.ChatMessageModel)
35 | message = new App.ChatMessageModel message
36 | $message = $(@template({message: message}))
37 | @$("#messages-list")[mode]($message)
38 | @scrollMessageList()
39 |
40 | scrollMessageList: ()->
41 | @$("#messages-list").scrollTop 1000000000
42 |
43 | sendMessage: ()->
44 | $messageBox = @$("#chat-message-box")
45 | messageText = _.str.trim $messageBox.val()
46 | if messageText.length
47 | @socket.emit "add-message", {room: @room, username: @user.get("username"), message: messageText}
48 | $messageBox.val ""
49 |
50 | onMessageTyping: (ev)=>
51 | if ev.keyCode is 13
52 | ev.preventDefault()
53 | @sendMessage()
54 |
55 | onSendClick: (ev)=>
56 | ev.preventDefault()
57 | @sendMessage()
58 |
--------------------------------------------------------------------------------
/assets/js/chat_bootstrap.coffee:
--------------------------------------------------------------------------------
1 | $(document).ready ()->
2 |
3 | $.tmpload.defaults.tplWrapper = _.template
4 |
5 | window.App = window.App or {}
6 |
7 | user = new App.UserModel
8 |
9 | $globalChat = $("#globalchat")
10 |
11 | if $globalChat.length
12 | user.fetch
13 | complete: ()->
14 | globalChat = new App.ChatView
15 | el: $globalChat
16 | user: user
17 | chatSocketUrl: "#{CONFIG.users.hostname}/chat"
18 | messageHistoryRootUrl: "/chat/messages"
19 | globalChat.render()
20 |
--------------------------------------------------------------------------------
/assets/js/vendor/BigInt.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doomhz/coinnext/c89b8e462876c567580e50d45287bda11399ec04/assets/js/vendor/BigInt.js
--------------------------------------------------------------------------------
/assets/js/vendor/ba-tiny-pubsub.js:
--------------------------------------------------------------------------------
1 | /*! Tiny Pub/Sub - v0.7.0 - 2013-01-29
2 | * https://github.com/cowboy/jquery-tiny-pubsub
3 | * Copyright (c) 2013 "Cowboy" Ben Alman; Licensed MIT */
4 | (function($) {
5 |
6 | var o = $({});
7 |
8 | $.subscribe = function() {
9 | o.on.apply(o, arguments);
10 | };
11 |
12 | $.unsubscribe = function() {
13 | o.off.apply(o, arguments);
14 | };
15 |
16 | $.publish = function() {
17 | o.trigger.apply(o, arguments);
18 | };
19 |
20 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/vendor/backbone.csrf.js:
--------------------------------------------------------------------------------
1 | Backbone.sync = (function(original) {
2 | return function(method, model, options) {
3 | options.beforeSend = function(xhr) {
4 | xhr.setRequestHeader('X-CSRF-Token', CONFIG.csrf);
5 | };
6 | original(method, model, options);
7 | };
8 | })(Backbone.sync);
--------------------------------------------------------------------------------
/assets/js/vendor/zxcvbn-async.js:
--------------------------------------------------------------------------------
1 | (function(){var a;a=function(){var a,b;b=document.createElement("script");b.src="/js/vendor/zxcvbn.js";b.type="text/javascript";b.async=!0;a=document.getElementsByTagName("script")[0];return a.parentNode.insertBefore(b,a)};null!=window.attachEvent?window.attachEvent("onload",a):window.addEventListener("load",a,!1)}).call(this);
2 |
--------------------------------------------------------------------------------
/configs/config.coffee:
--------------------------------------------------------------------------------
1 | fs = require "fs"
2 | environment = process.env.NODE_ENV or "development"
3 | walletsConfigPath = __dirname + "/wallets_config"
4 | config = JSON.parse(fs.readFileSync(process.cwd() + "/config.json", "utf8"))[environment]
5 | fs.readdirSync(walletsConfigPath).filter((file) ->
6 | /.json$/.test(file)
7 | ).forEach (file) ->
8 | currency = file.replace ".json", ""
9 | config.wallets[currency] = JSON.parse fs.readFileSync("#{walletsConfigPath}/#{file}")
10 | return
11 | exports = module.exports = ()->
12 | config
--------------------------------------------------------------------------------
/configs/config.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var config, environment, exports, fs, walletsConfigPath;
3 |
4 | fs = require("fs");
5 |
6 | environment = process.env.NODE_ENV || "development";
7 |
8 | walletsConfigPath = __dirname + "/wallets_config";
9 |
10 | config = JSON.parse(fs.readFileSync(process.cwd() + "/config.json", "utf8"))[environment];
11 |
12 | fs.readdirSync(walletsConfigPath).filter(function(file) {
13 | return /.json$/.test(file);
14 | }).forEach(function(file) {
15 | var currency;
16 | currency = file.replace(".json", "");
17 | config.wallets[currency] = JSON.parse(fs.readFileSync("" + walletsConfigPath + "/" + file));
18 | });
19 |
20 | exports = module.exports = function() {
21 | return config;
22 | };
23 |
24 | }).call(this);
25 |
--------------------------------------------------------------------------------
/configs/logger.coffee:
--------------------------------------------------------------------------------
1 | consoleLog = console.log
2 | consoleError = console.error
3 |
4 | console.log = ()->
5 | args = arguments
6 | args[0] = "#{new Date().toGMTString()} - log: #{args[0]}" if args[0]
7 | consoleLog.apply undefined, args
8 |
9 | console.error = ()->
10 | args = arguments
11 | args[0] = "#{new Date().toGMTString()} - error: #{args[0]}" if args[0]
12 | consoleError.apply undefined, args
13 |
14 | process.on "uncaughtException", (err)->
15 | console.error "Uncaught exception, exiting...", err.stack
16 | process.exit()
--------------------------------------------------------------------------------
/configs/logger.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var consoleError, consoleLog;
3 |
4 | consoleLog = console.log;
5 |
6 | consoleError = console.error;
7 |
8 | console.log = function() {
9 | var args;
10 | args = arguments;
11 | if (args[0]) {
12 | args[0] = "" + (new Date().toGMTString()) + " - log: " + args[0];
13 | }
14 | return consoleLog.apply(void 0, args);
15 | };
16 |
17 | console.error = function() {
18 | var args;
19 | args = arguments;
20 | if (args[0]) {
21 | args[0] = "" + (new Date().toGMTString()) + " - error: " + args[0];
22 | }
23 | return consoleError.apply(void 0, args);
24 | };
25 |
26 | process.on("uncaughtException", function(err) {
27 | console.error("Uncaught exception, exiting...", err.stack);
28 | return process.exit();
29 | });
30 |
31 | }).call(this);
32 |
--------------------------------------------------------------------------------
/configs/wallets.coffee:
--------------------------------------------------------------------------------
1 | fs = require "fs"
2 | MarketHelper = require "../lib/market_helper"
3 |
4 | wallets = {}
5 |
6 | for currency of MarketHelper.getCurrencies()
7 | walletType = currency.toLowerCase()
8 | options = if process.env.NODE_ENV isnt "production" and not GLOBAL.appConfig().wallets[walletType]? then GLOBAL.appConfig().wallets["btc"] else GLOBAL.appConfig().wallets[walletType]
9 | if process.env.NODE_ENV is "test"
10 | path = "#{process.cwd()}/tests/helpers/#{walletType}_wallet_mock.js"
11 | if fs.existsSync path
12 | Wallet = require path
13 | wallets[currency] = new Wallet options
14 | else
15 | path = "#{process.cwd()}/lib/crypto_wallets/#{walletType}_wallet.js"
16 | if fs.existsSync path
17 | Wallet = require path
18 | else
19 | Wallet = require "../lib/crypto_wallet"
20 | wallets[currency] = new Wallet options
21 |
22 | exports = module.exports = wallets
--------------------------------------------------------------------------------
/configs/wallets.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var MarketHelper, Wallet, currency, exports, fs, options, path, walletType, wallets;
3 |
4 | fs = require("fs");
5 |
6 | MarketHelper = require("../lib/market_helper");
7 |
8 | wallets = {};
9 |
10 | for (currency in MarketHelper.getCurrencies()) {
11 | walletType = currency.toLowerCase();
12 | options = process.env.NODE_ENV !== "production" && (GLOBAL.appConfig().wallets[walletType] == null) ? GLOBAL.appConfig().wallets["btc"] : GLOBAL.appConfig().wallets[walletType];
13 | if (process.env.NODE_ENV === "test") {
14 | path = "" + (process.cwd()) + "/tests/helpers/" + walletType + "_wallet_mock.js";
15 | if (fs.existsSync(path)) {
16 | Wallet = require(path);
17 | wallets[currency] = new Wallet(options);
18 | }
19 | } else {
20 | path = "" + (process.cwd()) + "/lib/crypto_wallets/" + walletType + "_wallet.js";
21 | if (fs.existsSync(path)) {
22 | Wallet = require(path);
23 | } else {
24 | Wallet = require("../lib/crypto_wallet");
25 | }
26 | wallets[currency] = new Wallet(options);
27 | }
28 | }
29 |
30 | exports = module.exports = wallets;
31 |
32 | }).call(this);
33 |
--------------------------------------------------------------------------------
/configs/wallets_config/btc.json.sample:
--------------------------------------------------------------------------------
1 | {
2 | "client": {
3 | "host": "127.0.0.1",
4 | "port": 18332,
5 | "user": "",
6 | "pass": "",
7 | "ssl": true,
8 | "sslStrict": false,
9 | "sslCa": false
10 | },
11 | "wallet": {
12 | "address": "",
13 | "account": "",
14 | "passphrase": ""
15 | },
16 | "confirmations": 1,
17 | "transaction_fee": 0.0001,
18 | "currency": "BTC"
19 | }
--------------------------------------------------------------------------------
/core_api.js:
--------------------------------------------------------------------------------
1 | // Configure logger
2 | if (process.env.NODE_ENV === "production") require("./configs/logger");
3 |
4 | // Configure modules
5 | var restify = require('restify');
6 | var environment = process.env.NODE_ENV || 'development';
7 |
8 | // Configure globals
9 | GLOBAL.appConfig = require("./configs/config");
10 | GLOBAL.wallets = require('./configs/wallets');
11 | GLOBAL.db = require('./models/index');
12 | GLOBAL.queue = require('./lib/queue/index');
13 |
14 | // Setup express
15 | var server = restify.createServer();
16 | server.use(restify.bodyParser());
17 | var port = process.env.PORT || 6000;
18 | server.listen(process.env.PORT || 6000, function(){
19 | console.log("Coinnext Core API is running on port %d in %s mode", port, environment);
20 | });
21 |
22 |
23 | // Routes
24 | require('./routes/core_api/wallets')(server);
25 | require('./routes/core_api/transactions')(server);
26 | require('./routes/core_api/trade')(server);
27 | require('./routes/core_api/stats')(server);
--------------------------------------------------------------------------------
/cron_dump/currency.dump.sample:
--------------------------------------------------------------------------------
1 | BTC
--------------------------------------------------------------------------------
/cron_dump/currency_exclude.dump.sample:
--------------------------------------------------------------------------------
1 | VIO
--------------------------------------------------------------------------------
/lib/admin_auth.coffee:
--------------------------------------------------------------------------------
1 | LocalStrategy = require('passport-local').Strategy
2 | AdminUser = GLOBAL.db.AdminUser
3 | strategyConfig =
4 | usernameField: "email"
5 | passwordField: "password"
6 |
7 | passport.use new LocalStrategy strategyConfig, (email, password, done)->
8 | AdminUser.findByEmail email, (err, user)->
9 | return done(err) if err
10 | return done(null, false, { message: 'Incorrect email.' }) if not user
11 | return done(null, false, { message: 'Incorrect password.' }) if not user.isValidPassword password
12 | return done(null, user)
13 |
14 | passport.serializeUser (user, done)->
15 | done(null, user.id)
16 |
17 | passport.deserializeUser (id, done)->
18 | AdminUser.findById id, done
19 |
--------------------------------------------------------------------------------
/lib/admin_auth.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var AdminUser, LocalStrategy, strategyConfig;
3 |
4 | LocalStrategy = require('passport-local').Strategy;
5 |
6 | AdminUser = GLOBAL.db.AdminUser;
7 |
8 | strategyConfig = {
9 | usernameField: "email",
10 | passwordField: "password"
11 | };
12 |
13 | passport.use(new LocalStrategy(strategyConfig, function(email, password, done) {
14 | return AdminUser.findByEmail(email, function(err, user) {
15 | if (err) {
16 | return done(err);
17 | }
18 | if (!user) {
19 | return done(null, false, {
20 | message: 'Incorrect email.'
21 | });
22 | }
23 | if (!user.isValidPassword(password)) {
24 | return done(null, false, {
25 | message: 'Incorrect password.'
26 | });
27 | }
28 | return done(null, user);
29 | });
30 | }));
31 |
32 | passport.serializeUser(function(user, done) {
33 | return done(null, user.id);
34 | });
35 |
36 | passport.deserializeUser(function(id, done) {
37 | return AdminUser.findById(id, done);
38 | });
39 |
40 | }).call(this);
41 |
--------------------------------------------------------------------------------
/lib/auth.coffee:
--------------------------------------------------------------------------------
1 | LocalStrategy = require('passport-local').Strategy
2 | User = GLOBAL.db.User
3 | strategyConfig =
4 | usernameField: "email"
5 | passwordField: "password"
6 | passReqToCallback: false
7 |
8 | passport.use "local", new LocalStrategy strategyConfig, (email, password, done)->
9 | User.findByEmail email, (err, user)->
10 | return done(err) if err
11 | return done(null, false, { message: 'Incorrect email.' }) if not user
12 | return done(null, false, { message: 'Incorrect password.' }) if not user.isValidPassword password
13 | done(null, user)
14 |
15 | passport.serializeUser (user, done)->
16 | done(null, user.id)
17 |
18 | passport.deserializeUser (id, done)->
19 | User.findById id, done
20 |
--------------------------------------------------------------------------------
/lib/auth.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var LocalStrategy, User, strategyConfig;
3 |
4 | LocalStrategy = require('passport-local').Strategy;
5 |
6 | User = GLOBAL.db.User;
7 |
8 | strategyConfig = {
9 | usernameField: "email",
10 | passwordField: "password",
11 | passReqToCallback: false
12 | };
13 |
14 | passport.use("local", new LocalStrategy(strategyConfig, function(email, password, done) {
15 | return User.findByEmail(email, function(err, user) {
16 | if (err) {
17 | return done(err);
18 | }
19 | if (!user) {
20 | return done(null, false, {
21 | message: 'Incorrect email.'
22 | });
23 | }
24 | if (!user.isValidPassword(password)) {
25 | return done(null, false, {
26 | message: 'Incorrect password.'
27 | });
28 | }
29 | return done(null, user);
30 | });
31 | }));
32 |
33 | passport.serializeUser(function(user, done) {
34 | return done(null, user.id);
35 | });
36 |
37 | passport.deserializeUser(function(id, done) {
38 | return User.findById(id, done);
39 | });
40 |
41 | }).call(this);
42 |
--------------------------------------------------------------------------------
/lib/client_socket.coffee:
--------------------------------------------------------------------------------
1 | redis = require "redis"
2 |
3 | class ClientSocket
4 |
5 | namespace: "users"
6 |
7 | pub: null
8 |
9 | constructor: (options = {})->
10 | @namespace = options.namespace if options.namespace
11 | @pub = redis.createClient options.redis.port, options.redis.host, {auth_pass: options.redis.pass}
12 |
13 | send: (data)->
14 | data.namespace = @namespace
15 | @pub.publish "external-events", JSON.stringify data
16 |
17 | close: ()->
18 | try
19 | @pub.quit() if @pub
20 | catch e
21 | console.error "Could not close Pub connection #{@namespace}", e
22 |
23 | exports = module.exports = ClientSocket
--------------------------------------------------------------------------------
/lib/client_socket.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var ClientSocket, exports, redis;
3 |
4 | redis = require("redis");
5 |
6 | ClientSocket = (function() {
7 | ClientSocket.prototype.namespace = "users";
8 |
9 | ClientSocket.prototype.pub = null;
10 |
11 | function ClientSocket(options) {
12 | if (options == null) {
13 | options = {};
14 | }
15 | if (options.namespace) {
16 | this.namespace = options.namespace;
17 | }
18 | this.pub = redis.createClient(options.redis.port, options.redis.host, {
19 | auth_pass: options.redis.pass
20 | });
21 | }
22 |
23 | ClientSocket.prototype.send = function(data) {
24 | data.namespace = this.namespace;
25 | return this.pub.publish("external-events", JSON.stringify(data));
26 | };
27 |
28 | ClientSocket.prototype.close = function() {
29 | var e;
30 | try {
31 | if (this.pub) {
32 | return this.pub.quit();
33 | }
34 | } catch (_error) {
35 | e = _error;
36 | return console.error("Could not close Pub connection " + this.namespace, e);
37 | }
38 | };
39 |
40 | return ClientSocket;
41 |
42 | })();
43 |
44 | exports = module.exports = ClientSocket;
45 |
46 | }).call(this);
47 |
--------------------------------------------------------------------------------
/lib/core_api_client.coffee:
--------------------------------------------------------------------------------
1 | request = require "request"
2 |
3 | class CoreAPIClient
4 |
5 | host: null
6 |
7 | commands:
8 | "create_account": "post"
9 | "publish_order": "post"
10 | "cancel_order": "del"
11 | "create_payment": "post"
12 | "process_payment": "put"
13 | "cancel_payment": "del"
14 | "wallet_balance": "get"
15 | "wallet_info": "get"
16 |
17 | constructor: (options = {})->
18 | @host = options.host if options.host
19 |
20 | send: (command, data, callback = ()->)->
21 | url = "http://#{@host}/#{command}"
22 | for param in data
23 | url += "/#{param}"
24 | if @commands[command]
25 | try
26 | request[@commands[command]](url, {json: true}, callback)
27 | catch e
28 | console.error e
29 | callback "Bad response '#{e}'"
30 | else
31 | callback "Invalid command '#{command}'"
32 |
33 | sendWithData: (command, data, callback = ()->)->
34 | uri = "http://#{@host}/#{command}"
35 | if @commands[command]
36 | options =
37 | uri: uri
38 | method: @commands[command]
39 | json: data
40 | try
41 | request options, callback
42 | catch e
43 | console.error e
44 | callback "Bad response #{e}"
45 | else
46 | callback "Invalid command '#{command}'"
47 |
48 | exports = module.exports = CoreAPIClient
--------------------------------------------------------------------------------
/lib/core_api_client.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var CoreAPIClient, exports, request;
3 |
4 | request = require("request");
5 |
6 | CoreAPIClient = (function() {
7 | CoreAPIClient.prototype.host = null;
8 |
9 | CoreAPIClient.prototype.commands = {
10 | "create_account": "post",
11 | "publish_order": "post",
12 | "cancel_order": "del",
13 | "create_payment": "post",
14 | "process_payment": "put",
15 | "cancel_payment": "del",
16 | "wallet_balance": "get",
17 | "wallet_info": "get"
18 | };
19 |
20 | function CoreAPIClient(options) {
21 | if (options == null) {
22 | options = {};
23 | }
24 | if (options.host) {
25 | this.host = options.host;
26 | }
27 | }
28 |
29 | CoreAPIClient.prototype.send = function(command, data, callback) {
30 | var e, param, url, _i, _len;
31 | if (callback == null) {
32 | callback = function() {};
33 | }
34 | url = "http://" + this.host + "/" + command;
35 | for (_i = 0, _len = data.length; _i < _len; _i++) {
36 | param = data[_i];
37 | url += "/" + param;
38 | }
39 | if (this.commands[command]) {
40 | try {
41 | return request[this.commands[command]](url, {
42 | json: true
43 | }, callback);
44 | } catch (_error) {
45 | e = _error;
46 | console.error(e);
47 | return callback("Bad response '" + e + "'");
48 | }
49 | } else {
50 | return callback("Invalid command '" + command + "'");
51 | }
52 | };
53 |
54 | CoreAPIClient.prototype.sendWithData = function(command, data, callback) {
55 | var e, options, uri;
56 | if (callback == null) {
57 | callback = function() {};
58 | }
59 | uri = "http://" + this.host + "/" + command;
60 | if (this.commands[command]) {
61 | options = {
62 | uri: uri,
63 | method: this.commands[command],
64 | json: data
65 | };
66 | try {
67 | return request(options, callback);
68 | } catch (_error) {
69 | e = _error;
70 | console.error(e);
71 | return callback("Bad response " + e);
72 | }
73 | } else {
74 | return callback("Invalid command '" + command + "'");
75 | }
76 | };
77 |
78 | return CoreAPIClient;
79 |
80 | })();
81 |
82 | exports = module.exports = CoreAPIClient;
83 |
84 | }).call(this);
85 |
--------------------------------------------------------------------------------
/lib/crypto_wallets/doge_wallet.coffee:
--------------------------------------------------------------------------------
1 | CryptoWallet = require "../crypto_wallet"
2 |
3 | class DogeWallet extends CryptoWallet
4 |
5 | getBalance: (account, callback)->
6 | @client.getBalance account, (err, balance)=>
7 | balance = if balance.result? then balance.result else balance
8 | balance = @convert @initialCurrency, @currency, balance
9 | callback(err, balance) if callback
10 |
11 | exports = module.exports = DogeWallet
--------------------------------------------------------------------------------
/lib/crypto_wallets/doge_wallet.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var CryptoWallet, DogeWallet, exports,
3 | __hasProp = {}.hasOwnProperty,
4 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
5 |
6 | CryptoWallet = require("../crypto_wallet");
7 |
8 | DogeWallet = (function(_super) {
9 | __extends(DogeWallet, _super);
10 |
11 | function DogeWallet() {
12 | return DogeWallet.__super__.constructor.apply(this, arguments);
13 | }
14 |
15 | DogeWallet.prototype.getBalance = function(account, callback) {
16 | return this.client.getBalance(account, (function(_this) {
17 | return function(err, balance) {
18 | balance = balance.result != null ? balance.result : balance;
19 | balance = _this.convert(_this.initialCurrency, _this.currency, balance);
20 | if (callback) {
21 | return callback(err, balance);
22 | }
23 | };
24 | })(this));
25 | };
26 |
27 | return DogeWallet;
28 |
29 | })(CryptoWallet);
30 |
31 | exports = module.exports = DogeWallet;
32 |
33 | }).call(this);
34 |
--------------------------------------------------------------------------------
/lib/emailer.coffee:
--------------------------------------------------------------------------------
1 | emailer = require("nodemailer")
2 | fs = require("fs")
3 | _ = require("underscore")
4 |
5 | class Emailer
6 |
7 | options: {}
8 |
9 | data: {}
10 |
11 | attachments: [
12 | ]
13 |
14 | constructor: (@options, @data)->
15 | @setUrls()
16 |
17 | send: (callback)->
18 | html = @getHtml(@options.template, @data)
19 | attachments = @getAttachments(html)
20 | messageData =
21 | to: @options.to.email
22 | from: GLOBAL.appConfig().emailer.from
23 | subject: @options.subject
24 | html: html
25 | generateTextFromHTML: true
26 | attachments: attachments
27 | transport = @getTransport()
28 | return callback() if not GLOBAL.appConfig().emailer.enabled
29 | transport.sendMail messageData, callback
30 |
31 | getTransport: ()->
32 | emailer.createTransport "SMTP", GLOBAL.appConfig().emailer.transport
33 |
34 | getHtml: (templateName, data)->
35 | templatePath = "./views/emails/#{templateName}.html"
36 | templateContent = fs.readFileSync(templatePath, encoding = "utf8")
37 | _.template templateContent, data, {interpolate: /\{\{(.+?)\}\}/g}
38 |
39 | getAttachments: (html)->
40 | attachments = []
41 | for attachment in @attachments
42 | attachments.push(attachment) if html.search("cid:#{attachment.cid}") > -1
43 | attachments
44 |
45 | setUrls: ()->
46 | @data.site_url = (GLOBAL.appConfig().emailer.host or @data.site_url)
47 | @data.img_path = (GLOBAL.appConfig().assets_host or @data.site_url) + "/img/email"
48 | @data.img_version = if GLOBAL.appConfig().assets_key then "?v=#{GLOBAL.appConfig().assets_key}" else ""
49 |
50 | exports = module.exports = Emailer
51 |
--------------------------------------------------------------------------------
/lib/emailer.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var Emailer, emailer, exports, fs, _;
3 |
4 | emailer = require("nodemailer");
5 |
6 | fs = require("fs");
7 |
8 | _ = require("underscore");
9 |
10 | Emailer = (function() {
11 | Emailer.prototype.options = {};
12 |
13 | Emailer.prototype.data = {};
14 |
15 | Emailer.prototype.attachments = [];
16 |
17 | function Emailer(options, data) {
18 | this.options = options;
19 | this.data = data;
20 | this.setUrls();
21 | }
22 |
23 | Emailer.prototype.send = function(callback) {
24 | var attachments, html, messageData, transport;
25 | html = this.getHtml(this.options.template, this.data);
26 | attachments = this.getAttachments(html);
27 | messageData = {
28 | to: this.options.to.email,
29 | from: GLOBAL.appConfig().emailer.from,
30 | subject: this.options.subject,
31 | html: html,
32 | generateTextFromHTML: true,
33 | attachments: attachments
34 | };
35 | transport = this.getTransport();
36 | if (!GLOBAL.appConfig().emailer.enabled) {
37 | return callback();
38 | }
39 | return transport.sendMail(messageData, callback);
40 | };
41 |
42 | Emailer.prototype.getTransport = function() {
43 | return emailer.createTransport("SMTP", GLOBAL.appConfig().emailer.transport);
44 | };
45 |
46 | Emailer.prototype.getHtml = function(templateName, data) {
47 | var encoding, templateContent, templatePath;
48 | templatePath = "./views/emails/" + templateName + ".html";
49 | templateContent = fs.readFileSync(templatePath, encoding = "utf8");
50 | return _.template(templateContent, data, {
51 | interpolate: /\{\{(.+?)\}\}/g
52 | });
53 | };
54 |
55 | Emailer.prototype.getAttachments = function(html) {
56 | var attachment, attachments, _i, _len, _ref;
57 | attachments = [];
58 | _ref = this.attachments;
59 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
60 | attachment = _ref[_i];
61 | if (html.search("cid:" + attachment.cid) > -1) {
62 | attachments.push(attachment);
63 | }
64 | }
65 | return attachments;
66 | };
67 |
68 | Emailer.prototype.setUrls = function() {
69 | this.data.site_url = GLOBAL.appConfig().emailer.host || this.data.site_url;
70 | this.data.img_path = (GLOBAL.appConfig().assets_host || this.data.site_url) + "/img/email";
71 | return this.data.img_version = GLOBAL.appConfig().assets_key ? "?v=" + (GLOBAL.appConfig().assets_key) : "";
72 | };
73 |
74 | return Emailer;
75 |
76 | })();
77 |
78 | exports = module.exports = Emailer;
79 |
80 | }).call(this);
81 |
--------------------------------------------------------------------------------
/lib/json_beautifier.coffee:
--------------------------------------------------------------------------------
1 | JsonBeautifier =
2 |
3 | constructor: ()->
4 |
5 | # Format JSON function
6 | # http://ketanjetty.com/coldfusion/javascript/format-json/
7 | toHTML: (jsonString)->
8 | jsonString = JSON.stringify(jsonString) if typeof jsonString is "object"
9 | jsonString.replace(/(\\'|\\")/g, "")
10 | retval = ''
11 | pos = 0
12 | strLen = jsonString.length
13 | indentStr = ' '
14 | newLine = '
'
15 |
16 | for char in jsonString
17 |
18 | if char is "}" or char is "]"
19 | retval = retval + newLine
20 | pos = pos - 1
21 |
22 | j = 0
23 | while j < pos
24 | retval = retval + indentStr
25 | j++
26 |
27 | retval = retval + char
28 |
29 | if char is "{" or char is "[" or char is ","
30 | retval = retval + newLine
31 | pos = pos + 1 if char is "{" or char is "["
32 |
33 | k = 0
34 | while k < pos
35 | retval = retval + indentStr
36 | k++
37 |
38 | retval
39 |
40 | exports = module.exports = JsonBeautifier
--------------------------------------------------------------------------------
/lib/json_beautifier.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var JsonBeautifier, exports;
3 |
4 | JsonBeautifier = {
5 | constructor: function() {},
6 | toHTML: function(jsonString) {
7 | var char, indentStr, j, k, newLine, pos, retval, strLen, _i, _len;
8 | if (typeof jsonString === "object") {
9 | jsonString = JSON.stringify(jsonString);
10 | }
11 | jsonString.replace(/(\\'|\\")/g, "");
12 | retval = '';
13 | pos = 0;
14 | strLen = jsonString.length;
15 | indentStr = ' ';
16 | newLine = '
';
17 | for (_i = 0, _len = jsonString.length; _i < _len; _i++) {
18 | char = jsonString[_i];
19 | if (char === "}" || char === "]") {
20 | retval = retval + newLine;
21 | pos = pos - 1;
22 | j = 0;
23 | while (j < pos) {
24 | retval = retval + indentStr;
25 | j++;
26 | }
27 | }
28 | retval = retval + char;
29 | if (char === "{" || char === "[" || char === ",") {
30 | retval = retval + newLine;
31 | if (char === "{" || char === "[") {
32 | pos = pos + 1;
33 | }
34 | k = 0;
35 | while (k < pos) {
36 | retval = retval + indentStr;
37 | k++;
38 | }
39 | }
40 | }
41 | return retval;
42 | }
43 | };
44 |
45 | exports = module.exports = JsonBeautifier;
46 |
47 | }).call(this);
48 |
--------------------------------------------------------------------------------
/lib/math.coffee:
--------------------------------------------------------------------------------
1 | exports = module.exports = require("mathjs")
2 | number: "bignumber"
3 | precision: 20
4 |
--------------------------------------------------------------------------------
/lib/math.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var exports;
3 |
4 | exports = module.exports = require("mathjs")({
5 | number: "bignumber",
6 | precision: 20
7 | });
8 |
9 | }).call(this);
10 |
--------------------------------------------------------------------------------
/lib/queue/event.coffee:
--------------------------------------------------------------------------------
1 | MarketHelper = require "../market_helper"
2 |
3 | module.exports = (sequelize, DataTypes) ->
4 |
5 | EVENTS_FETCH_LIMIT = 1
6 | VALID_EVENTS = [
7 | MarketHelper.getEventType "order_canceled"
8 | MarketHelper.getEventType "order_added"
9 | MarketHelper.getEventType "orders_match"
10 | ]
11 |
12 | Event = sequelize.define "Event",
13 | type:
14 | type: DataTypes.INTEGER.UNSIGNED
15 | allowNull: false
16 | comment: "orders_match, cancel_order, order_canceled, add_order, order_added"
17 | get: ()->
18 | MarketHelper.getEventTypeLiteral @getDataValue("type")
19 | set: (type)->
20 | @setDataValue "type", MarketHelper.getEventType(type)
21 | loadout:
22 | type: DataTypes.TEXT
23 | allowNull: true
24 | get: ()->
25 | JSON.parse @getDataValue("loadout")
26 | set: (loadout)->
27 | @setDataValue "loadout", JSON.stringify(loadout)
28 | status:
29 | type: DataTypes.INTEGER.UNSIGNED
30 | allowNull: false
31 | defaultValue: MarketHelper.getEventStatus "pending"
32 | comment: "pending, processed"
33 | get: ()->
34 | MarketHelper.getEventStatusLiteral @getDataValue("status")
35 | set: (status)->
36 | @setDataValue "status", MarketHelper.getEventStatus(status)
37 | ,
38 | tableName: "events"
39 | classMethods:
40 |
41 | addOrder: (loadout, callback = ()->)->
42 | data =
43 | type: "add_order"
44 | loadout: loadout
45 | status: "pending"
46 | Event.create(data).complete callback
47 |
48 | addCancelOrder: (loadout, callback = ()->)->
49 | data =
50 | type: "cancel_order"
51 | loadout: loadout
52 | status: "pending"
53 | Event.create(data).complete callback
54 |
55 | findNext: (type = null, callback = ()->)->
56 | query =
57 | where:
58 | status: MarketHelper.getEventStatus "pending"
59 | order: [
60 | ["created_at", "ASC"]
61 | ]
62 | limit: EVENTS_FETCH_LIMIT
63 | query.where.type = MarketHelper.getEventType type if type
64 | Event.find(query).complete callback
65 |
66 | findNextValid: (callback = ()->)->
67 | query =
68 | where:
69 | status: MarketHelper.getEventStatus "pending"
70 | type: VALID_EVENTS
71 | order: [
72 | ["created_at", "ASC"]
73 | ]
74 | limit: EVENTS_FETCH_LIMIT
75 | Event.find(query).complete callback
76 |
77 | Event
78 |
--------------------------------------------------------------------------------
/lib/queue/index.coffee:
--------------------------------------------------------------------------------
1 | fs = require("fs")
2 | path = require("path")
3 | Sequelize = require("sequelize")
4 | lodash = require("lodash")
5 |
6 | authData = GLOBAL.appConfig().queue
7 | sequelize = new Sequelize authData.db, authData.user, authData.password,
8 | port: authData.port
9 | host: authData.host
10 | logging: authData.logging
11 | maxConcurrentQueries: 100
12 | define:
13 | underscored: true
14 | freezeTableName: false
15 | syncOnAssociation: true
16 | charset: "utf8"
17 | collate: "utf8_general_ci"
18 | timestamps: true
19 | pool:
20 | maxConnections: 100
21 | maxIdleTime: 30
22 | db = {}
23 |
24 | fs.readdirSync(__dirname).filter((file) ->
25 | (file.indexOf(".") isnt 0) and (file.indexOf(".js") isnt -1) and (file isnt "index.js") and (file isnt "associations.js")
26 | ).forEach (file) ->
27 | model = sequelize.import(path.join(__dirname, file))
28 | db[model.name] = model
29 | return
30 |
31 | Object.keys(db).forEach (modelName) ->
32 | db[modelName].associate db if "associate" of db[modelName]
33 | return
34 |
35 | module.exports = lodash.extend(
36 | sequelize: sequelize
37 | Sequelize: Sequelize
38 | , db)
--------------------------------------------------------------------------------
/lib/queue/index.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var Sequelize, authData, db, fs, lodash, path, sequelize;
3 |
4 | fs = require("fs");
5 |
6 | path = require("path");
7 |
8 | Sequelize = require("sequelize");
9 |
10 | lodash = require("lodash");
11 |
12 | authData = GLOBAL.appConfig().queue;
13 |
14 | sequelize = new Sequelize(authData.db, authData.user, authData.password, {
15 | port: authData.port,
16 | host: authData.host,
17 | logging: authData.logging,
18 | maxConcurrentQueries: 100,
19 | define: {
20 | underscored: true,
21 | freezeTableName: false,
22 | syncOnAssociation: true,
23 | charset: "utf8",
24 | collate: "utf8_general_ci",
25 | timestamps: true
26 | },
27 | pool: {
28 | maxConnections: 100,
29 | maxIdleTime: 30
30 | }
31 | });
32 |
33 | db = {};
34 |
35 | fs.readdirSync(__dirname).filter(function(file) {
36 | return (file.indexOf(".") !== 0) && (file.indexOf(".js") !== -1) && (file !== "index.js") && (file !== "associations.js");
37 | }).forEach(function(file) {
38 | var model;
39 | model = sequelize["import"](path.join(__dirname, file));
40 | db[model.name] = model;
41 | });
42 |
43 | Object.keys(db).forEach(function(modelName) {
44 | if ("associate" in db[modelName]) {
45 | db[modelName].associate(db);
46 | }
47 | });
48 |
49 | module.exports = lodash.extend({
50 | sequelize: sequelize,
51 | Sequelize: Sequelize
52 | }, db);
53 |
54 | }).call(this);
55 |
--------------------------------------------------------------------------------
/lib/queue/migrations/20140522192430-add_indexes.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | up: (migration, DataTypes, done) ->
3 | migration.addIndex "events", ["status"]
4 | migration.addIndex "events", ["created_at"]
5 |
6 | done()
7 | return
8 |
9 | down: (migration, DataTypes, done) ->
10 | migration.removeIndex "events", ["status"]
11 | migration.removeIndex "events", ["created_at"]
12 |
13 | done()
14 | return
--------------------------------------------------------------------------------
/lib/queue/migrations/20140522192430-add_indexes.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = {
3 | up: function(migration, DataTypes, done) {
4 | migration.addIndex("events", ["status"]);
5 | migration.addIndex("events", ["created_at"]);
6 | done();
7 | },
8 | down: function(migration, DataTypes, done) {
9 | migration.removeIndex("events", ["status"]);
10 | migration.removeIndex("events", ["created_at"]);
11 | done();
12 | }
13 | };
14 |
15 | }).call(this);
16 |
--------------------------------------------------------------------------------
/lib/sockets.coffee:
--------------------------------------------------------------------------------
1 | io = require "socket.io"
2 | SessionSockets = require "session.socket.io"
3 | redis = require "redis"
4 | SocketsRedisStore = require "socket.io/lib/stores/redis"
5 | socketPub = redis.createClient GLOBAL.appConfig().redis.port, GLOBAL.appConfig().redis.host, {auth_pass: GLOBAL.appConfig().redis.pass}
6 | socketSub = redis.createClient GLOBAL.appConfig().redis.port, GLOBAL.appConfig().redis.host, {auth_pass: GLOBAL.appConfig().redis.pass}
7 | socketClient = redis.createClient GLOBAL.appConfig().redis.port, GLOBAL.appConfig().redis.host, {auth_pass: GLOBAL.appConfig().redis.pass}
8 | externalEventsSub = redis.createClient GLOBAL.appConfig().redis.port, GLOBAL.appConfig().redis.host, {auth_pass: GLOBAL.appConfig().redis.pass}
9 |
10 | Chat = GLOBAL.db.Chat
11 | JsonRenderer = require "./json_renderer"
12 |
13 | sockets = {}
14 |
15 | initSockets = (server, env, sessionStore, cookieParser)->
16 | ioOptions =
17 | log: if env is "production" then false else false
18 |
19 | sockets.io = io.listen server, ioOptions
20 |
21 | sockets.io.configure "production", ()->
22 | sockets.io.enable "browser client minification"
23 | sockets.io.enable "browser client etag"
24 | sockets.io.enable "browser client gzip"
25 | sockets.io.set "origins", "#{GLOBAL.appConfig().users.hostname}:*"
26 |
27 | sockets.io.set "store", new SocketsRedisStore
28 | redis: redis
29 | redisPub: socketPub
30 | redisSub: socketSub
31 | redisClient: socketClient
32 |
33 | externalEventsSub.subscribe "external-events"
34 | externalEventsSub.on "message", (channel, data)->
35 | if channel is "external-events"
36 | try
37 | data = JSON.parse data
38 | if data.namespace is "users"
39 | for sId, so of sockets.io.of("/users").sockets
40 | so.emit data.type, data.eventData if so.user_id is data.user_id
41 | if data.namespace is "orders"
42 | sockets.io.of("/orders").emit data.type, data.eventData
43 | catch e
44 | console.error "Could not emit to socket #{data}: #{e}"
45 | @
46 |
47 | sockets.sessionSockets = new SessionSockets sockets.io, sessionStore, cookieParser, GLOBAL.appConfig().session.session_key
48 |
49 | sockets.sessionSockets.of("/users").on "connection", (err, socket, session)->
50 | socket.user_id = session.passport.user if session and session.passport
51 |
52 | sockets.io.of("/orders").on "connection", (socket)->
53 |
54 | sockets.sessionSockets.of("/chat").on "connection", (err, socket, session)->
55 | socket.user_id = session.passport.user if session and session.passport
56 | socket.on "add-message", (data)->
57 | return if not socket.user_id
58 | data.user_id = socket.user_id
59 | Chat.addMessage data, (err, message)->
60 | return console.error err if err
61 | message.getUser().success (user)->
62 | sockets.io.of("/chat").emit "new-message", JsonRenderer.chatMessage message, user
63 | @
64 |
65 | sockets
66 |
67 | exports = module.exports = initSockets
--------------------------------------------------------------------------------
/lib/underscore_string.coffee:
--------------------------------------------------------------------------------
1 | _str = require "underscore.string"
2 |
3 | _str.roundTo = (number, decimals = 8)->
4 | multiplier = Math.pow(10, decimals)
5 | Math.round(parseFloat(number) * multiplier) / multiplier
6 |
7 | _str.satoshiRound = (number)->
8 | _str.roundTo number, 8
9 |
10 | _str.toFixed = (number, decimals = 8)->
11 | parseFloat(number).toFixed(decimals)
12 |
13 | exports = module.exports = _str
--------------------------------------------------------------------------------
/lib/underscore_string.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var exports, _str;
3 |
4 | _str = require("underscore.string");
5 |
6 | _str.roundTo = function(number, decimals) {
7 | var multiplier;
8 | if (decimals == null) {
9 | decimals = 8;
10 | }
11 | multiplier = Math.pow(10, decimals);
12 | return Math.round(parseFloat(number) * multiplier) / multiplier;
13 | };
14 |
15 | _str.satoshiRound = function(number) {
16 | return _str.roundTo(number, 8);
17 | };
18 |
19 | _str.toFixed = function(number, decimals) {
20 | if (decimals == null) {
21 | decimals = 8;
22 | }
23 | return parseFloat(number).toFixed(decimals);
24 | };
25 |
26 | exports = module.exports = _str;
27 |
28 | }).call(this);
29 |
--------------------------------------------------------------------------------
/models/admin_user.coffee:
--------------------------------------------------------------------------------
1 | crypto = require "crypto"
2 | speakeasy = require "speakeasy"
3 | _ = require "underscore"
4 |
5 | module.exports = (sequelize, DataTypes) ->
6 |
7 | AdminUser = sequelize.define "AdminUser",
8 | email:
9 | type: DataTypes.STRING
10 | allowNull: false
11 | unique: true
12 | validate:
13 | isEmail: true
14 | password:
15 | type: DataTypes.STRING
16 | allowNull: false
17 | validate:
18 | len: [5, 500]
19 | gauth_key:
20 | type: DataTypes.STRING(32)
21 | unique: true
22 | ,
23 | tableName: "admin_users"
24 | classMethods:
25 |
26 | findById: (id, callback = ()->)->
27 | AdminUser.find(id).complete callback
28 |
29 | findByEmail: (email, callback = ()->)->
30 | AdminUser.find({where:{email: email}}).complete callback
31 |
32 | hashPassword: (password)->
33 | crypto.createHash("sha256").update("#{password}#{GLOBAL.appConfig().salt}", "utf8").digest("hex")
34 |
35 | createNewUser: (data, callback)->
36 | userData = _.extend({}, data)
37 | userData.password = AdminUser.hashPassword userData.password
38 | AdminUser.create(userData).complete callback
39 |
40 | instanceMethods:
41 |
42 | isValidPassword: (password)->
43 | @password is AdminUser.hashPassword(password)
44 |
45 | generateGAuthData: (callback = ()->)->
46 | data = speakeasy.generate_key
47 | name: "administratiecnx"
48 | length: 20
49 | google_auth_qr: true
50 | @gauth_key = data.base32
51 | @save().complete (err, user)->
52 | callback data, user
53 |
54 | isValidGAuthPass: (pass)->
55 | currentPass = speakeasy.time
56 | key: @gauth_key
57 | encoding: "base32"
58 | currentPass is pass
59 |
60 | generateToken: (callback = ()->)->
61 | @token = crypto.createHash("sha256").update("#{@_id}#{GLOBAL.appConfig().salt}#{Date.now()}", "utf8").digest("hex")
62 | @save().complete (err, u)->
63 | callback(u.token)
64 |
65 | AdminUser
--------------------------------------------------------------------------------
/models/auth_stats.coffee:
--------------------------------------------------------------------------------
1 | require "date-utils"
2 | ipFormatter = require "ip"
3 | Emailer = require "../lib/emailer"
4 |
5 | module.exports = (sequelize, DataTypes) ->
6 |
7 | AuthStats = sequelize.define "AuthStats",
8 | user_id:
9 | type: DataTypes.INTEGER.UNSIGNED
10 | allowNull: false
11 | ip:
12 | type: DataTypes.INTEGER
13 | allowNull: true
14 | set: (ip)->
15 | @setDataValue "ip", ipFormatter.toLong ip
16 | get: ()->
17 | ipFormatter.fromLong @getDataValue "ip"
18 | ,
19 | tableName: "auth_stats"
20 | classMethods:
21 |
22 | findByUser: (userId, callback = ()->)->
23 | AuthStats.findAll({where: {user_id: userId}}).complete callback
24 |
25 | log: (data, sendByMail = true, callback = ()->)->
26 | stats =
27 | user_id: data.user.id
28 | ip: data.ip
29 | AuthStats.create(stats).complete (err, authStats)->
30 | AuthStats.sendUserLoginNotice authStats, data.user.email if sendByMail
31 | callback err, stats
32 |
33 | sendUserLoginNotice: (stats, email, callback = ()->)->
34 | data =
35 | ip: stats.ip or "unknown"
36 | auth_date: stats.created_at.toFormat "MMMM D, YYYY at HH24:MI"
37 | email: email
38 | options =
39 | to:
40 | email: email
41 | subject: "Login on Coinnext.com"
42 | template: "user_login_notice"
43 | emailer = new Emailer options, data
44 | emailer.send (err, result)->
45 | console.error err if err
46 | callback()
47 |
48 | AuthStats
--------------------------------------------------------------------------------
/models/auth_stats.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var Emailer, ipFormatter;
3 |
4 | require("date-utils");
5 |
6 | ipFormatter = require("ip");
7 |
8 | Emailer = require("../lib/emailer");
9 |
10 | module.exports = function(sequelize, DataTypes) {
11 | var AuthStats;
12 | AuthStats = sequelize.define("AuthStats", {
13 | user_id: {
14 | type: DataTypes.INTEGER.UNSIGNED,
15 | allowNull: false
16 | },
17 | ip: {
18 | type: DataTypes.INTEGER,
19 | allowNull: true,
20 | set: function(ip) {
21 | return this.setDataValue("ip", ipFormatter.toLong(ip));
22 | },
23 | get: function() {
24 | return ipFormatter.fromLong(this.getDataValue("ip"));
25 | }
26 | }
27 | }, {
28 | tableName: "auth_stats",
29 | classMethods: {
30 | findByUser: function(userId, callback) {
31 | if (callback == null) {
32 | callback = function() {};
33 | }
34 | return AuthStats.findAll({
35 | where: {
36 | user_id: userId
37 | }
38 | }).complete(callback);
39 | },
40 | log: function(data, sendByMail, callback) {
41 | var stats;
42 | if (sendByMail == null) {
43 | sendByMail = true;
44 | }
45 | if (callback == null) {
46 | callback = function() {};
47 | }
48 | stats = {
49 | user_id: data.user.id,
50 | ip: data.ip
51 | };
52 | return AuthStats.create(stats).complete(function(err, authStats) {
53 | if (sendByMail) {
54 | AuthStats.sendUserLoginNotice(authStats, data.user.email);
55 | }
56 | return callback(err, stats);
57 | });
58 | },
59 | sendUserLoginNotice: function(stats, email, callback) {
60 | var data, emailer, options;
61 | if (callback == null) {
62 | callback = function() {};
63 | }
64 | data = {
65 | ip: stats.ip || "unknown",
66 | auth_date: stats.created_at.toFormat("MMMM D, YYYY at HH24:MI"),
67 | email: email
68 | };
69 | options = {
70 | to: {
71 | email: email
72 | },
73 | subject: "Login on Coinnext.com",
74 | template: "user_login_notice"
75 | };
76 | emailer = new Emailer(options, data);
77 | emailer.send(function(err, result) {
78 | if (err) {
79 | return console.error(err);
80 | }
81 | });
82 | return callback();
83 | }
84 | }
85 | });
86 | return AuthStats;
87 | };
88 |
89 | }).call(this);
90 |
--------------------------------------------------------------------------------
/models/chat.coffee:
--------------------------------------------------------------------------------
1 | _s = require "underscore.string"
2 |
3 | module.exports = (sequelize, DataTypes) ->
4 |
5 | MESSAGES_LIMIT = 10000
6 | GLOBAL_ROOM_NAME = "global"
7 |
8 | Chat = sequelize.define "Chat",
9 | user_id:
10 | type: DataTypes.INTEGER.UNSIGNED
11 | allowNull: false
12 | message:
13 | type: DataTypes.TEXT
14 | allowNull: false
15 | len: [1, 150]
16 | set: (message)->
17 | @setDataValue "message", _s.truncate _s.trim(message), 150
18 | ,
19 | tableName: "chats"
20 | classMethods:
21 |
22 | findLastMessages: (callback)->
23 | oneDayAgo = new Date (Date.now() - 24*60*60*1000)
24 | query =
25 | where:
26 | created_at:
27 | gt: oneDayAgo
28 | order: [
29 | ["created_at", "DESC"]
30 | ]
31 | limit: MESSAGES_LIMIT
32 | include: [
33 | {model: GLOBAL.db.User, attributes: ["username"]}
34 | ]
35 | Chat.findAll(query).complete callback
36 |
37 | findLastUserMessage: (userId, callback)->
38 | query =
39 | where:
40 | user_id: userId
41 | order: [
42 | ["created_at", "DESC"]
43 | ]
44 | limit: 1
45 | Chat.find(query).complete callback
46 |
47 | getGlobalRoomName: ()->
48 | GLOBAL_ROOM_NAME
49 |
50 | addMessage: (data, callback = ()->)->
51 | Chat.findLastUserMessage data.user_id, (err, message)->
52 | return callback "Dropping spam message #{data.message} by user #{data.user_id}." if message and message.isSpam(data)
53 | Chat.create(data).complete callback
54 |
55 | instanceMethods:
56 |
57 | isSpam: (newMessage)->
58 | @isTooEarly() or @isDuplicate(newMessage)
59 |
60 | isDuplicate: (newMessage)->
61 | @message is newMessage.message
62 |
63 | isTooEarly: ()->
64 | twoSecondsAgo = new Date (Date.now() - 2*1000)
65 | @created_at >= twoSecondsAgo
66 |
67 | Chat
--------------------------------------------------------------------------------
/models/chat.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var _s;
3 |
4 | _s = require("underscore.string");
5 |
6 | module.exports = function(sequelize, DataTypes) {
7 | var Chat, GLOBAL_ROOM_NAME, MESSAGES_LIMIT;
8 | MESSAGES_LIMIT = 10000;
9 | GLOBAL_ROOM_NAME = "global";
10 | Chat = sequelize.define("Chat", {
11 | user_id: {
12 | type: DataTypes.INTEGER.UNSIGNED,
13 | allowNull: false
14 | },
15 | message: {
16 | type: DataTypes.TEXT,
17 | allowNull: false,
18 | len: [1, 150],
19 | set: function(message) {
20 | return this.setDataValue("message", _s.truncate(_s.trim(message), 150));
21 | }
22 | }
23 | }, {
24 | tableName: "chats",
25 | classMethods: {
26 | findLastMessages: function(callback) {
27 | var oneDayAgo, query;
28 | oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
29 | query = {
30 | where: {
31 | created_at: {
32 | gt: oneDayAgo
33 | }
34 | },
35 | order: [["created_at", "DESC"]],
36 | limit: MESSAGES_LIMIT,
37 | include: [
38 | {
39 | model: GLOBAL.db.User,
40 | attributes: ["username"]
41 | }
42 | ]
43 | };
44 | return Chat.findAll(query).complete(callback);
45 | },
46 | findLastUserMessage: function(userId, callback) {
47 | var query;
48 | query = {
49 | where: {
50 | user_id: userId
51 | },
52 | order: [["created_at", "DESC"]],
53 | limit: 1
54 | };
55 | return Chat.find(query).complete(callback);
56 | },
57 | getGlobalRoomName: function() {
58 | return GLOBAL_ROOM_NAME;
59 | },
60 | addMessage: function(data, callback) {
61 | if (callback == null) {
62 | callback = function() {};
63 | }
64 | return Chat.findLastUserMessage(data.user_id, function(err, message) {
65 | if (message && message.isSpam(data)) {
66 | return callback("Dropping spam message " + data.message + " by user " + data.user_id + ".");
67 | }
68 | return Chat.create(data).complete(callback);
69 | });
70 | }
71 | },
72 | instanceMethods: {
73 | isSpam: function(newMessage) {
74 | return this.isTooEarly() || this.isDuplicate(newMessage);
75 | },
76 | isDuplicate: function(newMessage) {
77 | return this.message === newMessage.message;
78 | },
79 | isTooEarly: function() {
80 | var twoSecondsAgo;
81 | twoSecondsAgo = new Date(Date.now() - 2 * 1000);
82 | return this.created_at >= twoSecondsAgo;
83 | }
84 | }
85 | });
86 | return Chat;
87 | };
88 |
89 | }).call(this);
90 |
--------------------------------------------------------------------------------
/models/index.coffee:
--------------------------------------------------------------------------------
1 | fs = require("fs")
2 | path = require("path")
3 | Sequelize = require("sequelize")
4 | lodash = require("lodash")
5 |
6 | authData = GLOBAL.appConfig().mysql
7 | sequelize = new Sequelize authData.db, authData.user, authData.password,
8 | port: authData.port
9 | host: authData.host
10 | logging: authData.logging
11 | maxConcurrentQueries: 100
12 | define:
13 | underscored: true
14 | freezeTableName: false
15 | syncOnAssociation: true
16 | charset: "utf8"
17 | collate: "utf8_general_ci"
18 | timestamps: true
19 | pool:
20 | maxConnections: 151
21 | maxIdleTime: 30
22 | db = {}
23 |
24 | fs.readdirSync(__dirname).filter((file) ->
25 | (file.indexOf(".") isnt 0) and (file.indexOf(".js") isnt -1) and (file isnt "index.js") and (file isnt "associations.js")
26 | ).forEach (file) ->
27 | model = sequelize.import(path.join(__dirname, file))
28 | db[model.name] = model
29 | return
30 |
31 | Object.keys(db).forEach (modelName) ->
32 | db[modelName].associate db if "associate" of db[modelName]
33 | return
34 |
35 | db.User.hasMany db.Chat
36 | db.User.hasMany db.UserToken
37 | db.User.hasMany db.Transaction
38 | db.Chat.belongsTo db.User
39 | db.Transaction.belongsTo db.User
40 | db.UserToken.belongsTo db.User
41 | db.Payment.hasMany db.PaymentLog
42 | db.PaymentLog.belongsTo db.Payment
43 | db.Order.hasMany db.OrderLog
44 | db.OrderLog.belongsTo db.Order
45 |
46 | module.exports = lodash.extend(
47 | sequelize: sequelize
48 | Sequelize: Sequelize
49 | , db)
--------------------------------------------------------------------------------
/models/index.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var Sequelize, authData, db, fs, lodash, path, sequelize;
3 |
4 | fs = require("fs");
5 |
6 | path = require("path");
7 |
8 | Sequelize = require("sequelize");
9 |
10 | lodash = require("lodash");
11 |
12 | authData = GLOBAL.appConfig().mysql;
13 |
14 | sequelize = new Sequelize(authData.db, authData.user, authData.password, {
15 | port: authData.port,
16 | host: authData.host,
17 | logging: authData.logging,
18 | maxConcurrentQueries: 100,
19 | define: {
20 | underscored: true,
21 | freezeTableName: false,
22 | syncOnAssociation: true,
23 | charset: "utf8",
24 | collate: "utf8_general_ci",
25 | timestamps: true
26 | },
27 | pool: {
28 | maxConnections: 151,
29 | maxIdleTime: 30
30 | }
31 | });
32 |
33 | db = {};
34 |
35 | fs.readdirSync(__dirname).filter(function(file) {
36 | return (file.indexOf(".") !== 0) && (file.indexOf(".js") !== -1) && (file !== "index.js") && (file !== "associations.js");
37 | }).forEach(function(file) {
38 | var model;
39 | model = sequelize["import"](path.join(__dirname, file));
40 | db[model.name] = model;
41 | });
42 |
43 | Object.keys(db).forEach(function(modelName) {
44 | if ("associate" in db[modelName]) {
45 | db[modelName].associate(db);
46 | }
47 | });
48 |
49 | db.User.hasMany(db.Chat);
50 |
51 | db.User.hasMany(db.UserToken);
52 |
53 | db.User.hasMany(db.Transaction);
54 |
55 | db.Chat.belongsTo(db.User);
56 |
57 | db.Transaction.belongsTo(db.User);
58 |
59 | db.UserToken.belongsTo(db.User);
60 |
61 | db.Payment.hasMany(db.PaymentLog);
62 |
63 | db.PaymentLog.belongsTo(db.Payment);
64 |
65 | db.Order.hasMany(db.OrderLog);
66 |
67 | db.OrderLog.belongsTo(db.Order);
68 |
69 | module.exports = lodash.extend({
70 | sequelize: sequelize,
71 | Sequelize: Sequelize
72 | }, db);
73 |
74 | }).call(this);
75 |
--------------------------------------------------------------------------------
/models/migrations/20140425141930-alter_unsigned_amount.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | up: (migration, DataTypes, done) ->
3 | migration.changeColumn "transactions", "amount",
4 | type: DataTypes.BIGINT
5 | defaultValue: 0
6 | allowNull: false
7 | comment: "FLOAT x 100000000"
8 |
9 | done()
10 | return
11 |
12 | down: (migration, DataTypes, done) ->
13 | migration.changeColumn "transactions", "amount",
14 | type: DataTypes.BIGINT.UNSIGNED
15 | defaultValue: 0
16 | allowNull: false
17 | comment: "FLOAT x 100000000"
18 |
19 | done()
20 | return
--------------------------------------------------------------------------------
/models/migrations/20140425141930-alter_unsigned_amount.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = {
3 | up: function(migration, DataTypes, done) {
4 | migration.changeColumn("transactions", "amount", {
5 | type: DataTypes.BIGINT,
6 | defaultValue: 0,
7 | allowNull: false,
8 | comment: "FLOAT x 100000000"
9 | });
10 | done();
11 | },
12 | down: function(migration, DataTypes, done) {
13 | migration.changeColumn("transactions", "amount", {
14 | type: DataTypes.BIGINT.UNSIGNED,
15 | defaultValue: 0,
16 | allowNull: false,
17 | comment: "FLOAT x 100000000"
18 | });
19 | done();
20 | }
21 | };
22 |
23 | }).call(this);
24 |
--------------------------------------------------------------------------------
/models/migrations/20140505195830-add_order_log_indexes.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | up: (migration, DataTypes, done) ->
3 | migration.addIndex "order_logs", ["order_id"]
4 | migration.addIndex "order_logs", ["active"]
5 | migration.addIndex "order_logs", ["time"]
6 | migration.addIndex "order_logs", ["status"]
7 |
8 | done()
9 | return
10 |
11 | down: (migration, DataTypes, done) ->
12 | migration.removeIndex "order_logs", ["order_id"]
13 | migration.removeIndex "order_logs", ["active"]
14 | migration.removeIndex "order_logs", ["time"]
15 | migration.removeIndex "order_logs", ["status"]
16 |
17 | done()
18 | return
--------------------------------------------------------------------------------
/models/migrations/20140505195830-add_order_log_indexes.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = {
3 | up: function(migration, DataTypes, done) {
4 | migration.addIndex("order_logs", ["order_id"]);
5 | migration.addIndex("order_logs", ["active"]);
6 | migration.addIndex("order_logs", ["time"]);
7 | migration.addIndex("order_logs", ["status"]);
8 | done();
9 | },
10 | down: function(migration, DataTypes, done) {
11 | migration.removeIndex("order_logs", ["order_id"]);
12 | migration.removeIndex("order_logs", ["active"]);
13 | migration.removeIndex("order_logs", ["time"]);
14 | migration.removeIndex("order_logs", ["status"]);
15 | done();
16 | }
17 | };
18 |
19 | }).call(this);
20 |
--------------------------------------------------------------------------------
/models/migrations/20140507195900-alter_unsigned.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | up: (migration, DataTypes, done) ->
3 | migration.changeColumn "market_stats", "growth_ratio",
4 | type: DataTypes.BIGINT
5 | defaultValue: 0
6 | allowNull: false
7 | comment: "FLOAT x 100000000"
8 |
9 | done()
10 | return
11 |
12 | down: (migration, DataTypes, done) ->
13 | migration.changeColumn "market_stats", "growth_ratio",
14 | type: DataTypes.BIGINT.UNSIGNED
15 | defaultValue: 0
16 | allowNull: false
17 | comment: "FLOAT x 100000000"
18 |
19 | done()
20 | return
--------------------------------------------------------------------------------
/models/migrations/20140507195900-alter_unsigned.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = {
3 | up: function(migration, DataTypes, done) {
4 | migration.changeColumn("market_stats", "growth_ratio", {
5 | type: DataTypes.BIGINT,
6 | defaultValue: 0,
7 | allowNull: false,
8 | comment: "FLOAT x 100000000"
9 | });
10 | done();
11 | },
12 | down: function(migration, DataTypes, done) {
13 | migration.changeColumn("market_stats", "growth_ratio", {
14 | type: DataTypes.BIGINT.UNSIGNED,
15 | defaultValue: 0,
16 | allowNull: false,
17 | comment: "FLOAT x 100000000"
18 | });
19 | done();
20 | }
21 | };
22 |
23 | }).call(this);
24 |
--------------------------------------------------------------------------------
/models/migrations/20140524211930-add_indexes.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | up: (migration, DataTypes, done) ->
3 | migration.addIndex "orders", ["deleted_at"]
4 |
5 | done()
6 | return
7 |
8 | down: (migration, DataTypes, done) ->
9 | migration.removeIndex "orders", ["deleted_at"]
10 |
11 | done()
12 | return
--------------------------------------------------------------------------------
/models/migrations/20140524211930-add_indexes.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = {
3 | up: function(migration, DataTypes, done) {
4 | migration.addIndex("orders", ["deleted_at"]);
5 | done();
6 | },
7 | down: function(migration, DataTypes, done) {
8 | migration.removeIndex("orders", ["deleted_at"]);
9 | done();
10 | }
11 | };
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/models/migrations/20140607215430-add_indexes.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | up: (migration, DataTypes, done) ->
3 | migration.addIndex "wallet_health", ["currency"]
4 | migration.addIndex "wallet_health", ["status"]
5 |
6 | done()
7 | return
8 |
9 | down: (migration, DataTypes, done) ->
10 | migration.removeIndex "wallet_health", ["currency"]
11 | migration.removeIndex "wallet_health", ["status"]
12 |
13 | done()
14 | return
--------------------------------------------------------------------------------
/models/migrations/20140607215430-add_indexes.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = {
3 | up: function(migration, DataTypes, done) {
4 | migration.addIndex("wallet_health", ["currency"]);
5 | migration.addIndex("wallet_health", ["status"]);
6 | done();
7 | },
8 | down: function(migration, DataTypes, done) {
9 | migration.removeIndex("wallet_health", ["currency"]);
10 | migration.removeIndex("wallet_health", ["status"]);
11 | done();
12 | }
13 | };
14 |
15 | }).call(this);
16 |
--------------------------------------------------------------------------------
/models/migrations/20140610135430-add_indexes.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | up: (migration, DataTypes, done) ->
3 | migration.addIndex "payments", ["fraud"]
4 |
5 | done()
6 | return
7 |
8 | down: (migration, DataTypes, done) ->
9 | migration.removeIndex "payments", ["fraud"]
10 |
11 | done()
12 | return
--------------------------------------------------------------------------------
/models/migrations/20140610135430-add_indexes.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = {
3 | up: function(migration, DataTypes, done) {
4 | migration.addIndex("payments", ["fraud"]);
5 | done();
6 | },
7 | down: function(migration, DataTypes, done) {
8 | migration.removeIndex("payments", ["fraud"]);
9 | done();
10 | }
11 | };
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/models/payment_log.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (sequelize, DataTypes) ->
2 |
3 | PaymentLog = sequelize.define "PaymentLog",
4 | payment_id:
5 | type: DataTypes.INTEGER.UNSIGNED
6 | allowNull: false
7 | log:
8 | type: DataTypes.TEXT
9 | set: (response)->
10 | try
11 | log = if typeof(response) is "string" then response else "#{response}"
12 | @setDataValue "log", log
13 | catch e
14 | @setDataValue "log", response
15 | ,
16 | tableName: "payment_logs"
17 | classMethods:
18 |
19 | findById: (id, callback)->
20 | PaymentLog.find(id).complete callback
21 |
22 | findByPaymentId: (paymentId, callback)->
23 | query =
24 | where:
25 | payment_id: paymentId
26 | PaymentLog.findAll(query).complete callback
27 |
28 | PaymentLog
--------------------------------------------------------------------------------
/models/payment_log.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | module.exports = function(sequelize, DataTypes) {
3 | var PaymentLog;
4 | PaymentLog = sequelize.define("PaymentLog", {
5 | payment_id: {
6 | type: DataTypes.INTEGER.UNSIGNED,
7 | allowNull: false
8 | },
9 | log: {
10 | type: DataTypes.TEXT,
11 | set: function(response) {
12 | var e, log;
13 | try {
14 | log = typeof response === "string" ? response : "" + response;
15 | return this.setDataValue("log", log);
16 | } catch (_error) {
17 | e = _error;
18 | return this.setDataValue("log", response);
19 | }
20 | }
21 | }
22 | }, {
23 | tableName: "payment_logs",
24 | classMethods: {
25 | findById: function(id, callback) {
26 | return PaymentLog.find(id).complete(callback);
27 | },
28 | findByPaymentId: function(paymentId, callback) {
29 | var query;
30 | query = {
31 | where: {
32 | payment_id: paymentId
33 | }
34 | };
35 | return PaymentLog.findAll(query).complete(callback);
36 | }
37 | }
38 | });
39 | return PaymentLog;
40 | };
41 |
42 | }).call(this);
43 |
--------------------------------------------------------------------------------
/models/seeds/market_stats.coffee:
--------------------------------------------------------------------------------
1 | MarketHelper = require "../../lib/market_helper"
2 | markets = []
3 | for literal, int of MarketHelper.getMarkets()
4 | markets.push {type: literal, status: "enabled"}
5 | module.exports = markets
--------------------------------------------------------------------------------
/models/seeds/market_stats.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var MarketHelper, int, literal, markets, _ref;
3 |
4 | MarketHelper = require("../../lib/market_helper");
5 |
6 | markets = [];
7 |
8 | _ref = MarketHelper.getMarkets();
9 | for (literal in _ref) {
10 | int = _ref[literal];
11 | markets.push({
12 | type: literal,
13 | status: "enabled"
14 | });
15 | }
16 |
17 | module.exports = markets;
18 |
19 | }).call(this);
20 |
--------------------------------------------------------------------------------
/models/wallet_health.coffee:
--------------------------------------------------------------------------------
1 | MarketHelper = require "../lib/market_helper"
2 | _ = require "underscore"
3 |
4 | module.exports = (sequelize, DataTypes) ->
5 |
6 | WalletHealth = sequelize.define "WalletHealth",
7 | currency:
8 | type: DataTypes.INTEGER.UNSIGNED
9 | allowNull: false
10 | get: ()->
11 | MarketHelper.getCurrencyLiteral @getDataValue("currency")
12 | set: (currency)->
13 | @setDataValue "currency", MarketHelper.getCurrency(currency)
14 | blocks:
15 | type: DataTypes.INTEGER.UNSIGNED
16 | defaultValue: 0
17 | allowNull: false
18 | connections:
19 | type: DataTypes.INTEGER.UNSIGNED
20 | defaultValue: 0
21 | allowNull: false
22 | last_updated:
23 | type: DataTypes.DATE
24 | balance:
25 | type: DataTypes.BIGINT.UNSIGNED
26 | defaultValue: 0
27 | allowNull: false
28 | comment: "FLOAT x 100000000"
29 | status:
30 | type: DataTypes.INTEGER.UNSIGNED
31 | defaultValue: MarketHelper.getWalletStatus "normal"
32 | allowNull: false
33 | comment: "normal, delayed, blocked, inactive"
34 | get: ()->
35 | MarketHelper.getWalletStatusLiteral @getDataValue("status")
36 | set: (status)->
37 | @setDataValue "status", MarketHelper.getWalletStatus(status)
38 | ,
39 | tableName: "wallet_health"
40 | instanceMethods:
41 |
42 | getFloat: (attribute)->
43 | return @[attribute] if not @[attribute]?
44 | MarketHelper.fromBigint @[attribute]
45 |
46 | classMethods:
47 |
48 | updateFromWalletInfo: (walletInfo, callback)->
49 | WalletHealth.findOrCreate({currency: MarketHelper.getCurrency(walletInfo.currency)}).complete (err, wallet, created)->
50 | wallet.updateAttributes(walletInfo).complete callback
51 |
52 | WalletHealth
53 |
54 |
--------------------------------------------------------------------------------
/models/wallet_health.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var MarketHelper, _;
3 |
4 | MarketHelper = require("../lib/market_helper");
5 |
6 | _ = require("underscore");
7 |
8 | module.exports = function(sequelize, DataTypes) {
9 | var WalletHealth;
10 | WalletHealth = sequelize.define("WalletHealth", {
11 | currency: {
12 | type: DataTypes.INTEGER.UNSIGNED,
13 | allowNull: false,
14 | get: function() {
15 | return MarketHelper.getCurrencyLiteral(this.getDataValue("currency"));
16 | },
17 | set: function(currency) {
18 | return this.setDataValue("currency", MarketHelper.getCurrency(currency));
19 | }
20 | },
21 | blocks: {
22 | type: DataTypes.INTEGER.UNSIGNED,
23 | defaultValue: 0,
24 | allowNull: false
25 | },
26 | connections: {
27 | type: DataTypes.INTEGER.UNSIGNED,
28 | defaultValue: 0,
29 | allowNull: false
30 | },
31 | last_updated: {
32 | type: DataTypes.DATE
33 | },
34 | balance: {
35 | type: DataTypes.BIGINT.UNSIGNED,
36 | defaultValue: 0,
37 | allowNull: false,
38 | comment: "FLOAT x 100000000"
39 | },
40 | status: {
41 | type: DataTypes.INTEGER.UNSIGNED,
42 | defaultValue: MarketHelper.getWalletStatus("normal"),
43 | allowNull: false,
44 | comment: "normal, delayed, blocked, inactive",
45 | get: function() {
46 | return MarketHelper.getWalletStatusLiteral(this.getDataValue("status"));
47 | },
48 | set: function(status) {
49 | return this.setDataValue("status", MarketHelper.getWalletStatus(status));
50 | }
51 | }
52 | }, {
53 | tableName: "wallet_health",
54 | instanceMethods: {
55 | getFloat: function(attribute) {
56 | if (this[attribute] == null) {
57 | return this[attribute];
58 | }
59 | return MarketHelper.fromBigint(this[attribute]);
60 | }
61 | },
62 | classMethods: {
63 | updateFromWalletInfo: function(walletInfo, callback) {
64 | return WalletHealth.findOrCreate({
65 | currency: MarketHelper.getCurrency(walletInfo.currency)
66 | }).complete(function(err, wallet, created) {
67 | return wallet.updateAttributes(walletInfo).complete(callback);
68 | });
69 | }
70 | }
71 | });
72 | return WalletHealth;
73 | };
74 |
75 | }).call(this);
76 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "coinnext",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node app",
7 | "test": "make test"
8 | },
9 | "dependencies": {
10 | "express": "~>3"
11 | , "stylus": "0.44.0"
12 | , "jade": "1.3.1"
13 | , "coffee-script": "latest"
14 | , "connect-assets": "2.x"
15 | , "bcrypt": "0.7.8"
16 | , "connect-redis": "1.4.7"
17 | , "hiredis": "0.1.16"
18 | , "redis": "0.10.1"
19 | , "passport": "0.2.0"
20 | , "passport-local": "1.0.0"
21 | , "underscore": "1.6.0"
22 | , "underscore.string": "2.3.3"
23 | , "node-coind": "1.0.1"
24 | , "date-utils": "1.2.15"
25 | , "socket.io": "0.9.16"
26 | , "socket.io-client": "0.9.16"
27 | , "session.socket.io": "0.1.6"
28 | , "winston": "0.7.3"
29 | , "async": "0.8.0"
30 | , "helmet": "0.2.1"
31 | , "speakeasy": "1.0.3"
32 | , "nodemailer": "0.6.3"
33 | , "restify": "2.7.0"
34 | , "request": "2.34.0"
35 | , "mysql": "2.2.0"
36 | , "sequelize": "1.7.1"
37 | , "lodash": "2.4.1"
38 | , "ip": "0.3.0"
39 | , "phonetic": "0.1.0"
40 | , "recaptcha-async": "0.0.4"
41 | , "mathjs": "0.22.0"
42 | , "express-simple-cdn": "1.0.1"
43 | , "cron": "1.0.4"
44 | , "slackhook": "0.0.3"
45 | },
46 | "devDependencies": {
47 | "mocha": "latest"
48 | , "should": "latest"
49 | , "growl": "latest"
50 | , "nodemock": "latest"
51 | , "supertest": "latest"
52 | , "grunt-contrib-coffee": "latest"
53 | , "grunt-contrib-watch": "latest"
54 | }
55 | }
--------------------------------------------------------------------------------
/public/503.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
The server is currently unavailable. We'll be back soon.
52 |