Skip to content
Snippets Groups Projects
Commit 39482dbc authored by Caner Candan's avatar Caner Candan
Browse files

+ added transfer page

parent 867ef8ff
No related branches found
No related tags found
No related merge requests found
...@@ -10,3 +10,9 @@ ...@@ -10,3 +10,9 @@
[submodule "static/chartjs"] [submodule "static/chartjs"]
path = static/chartjs path = static/chartjs
url = git://github.com/nnnick/Chart.js.git url = git://github.com/nnnick/Chart.js.git
[submodule "static/typeahead"]
path = static/typeahead
url = https://github.com/twitter/typeahead.js
[submodule "static/hogan"]
path = static/hogan
url = https://github.com/twitter/hogan.js
Subproject commit 5450e5ab61be562c843985409b04316a96840066
Subproject commit 331cff944d00f1d8e98694fc6f73ab80455bd3be
.typeahead,
.tt-query,
.tt-hint {
width: 800px;
height: 30px;
padding: 8px 12px;
font-size: 24px;
line-height: 30px;
border: 2px solid #ccc;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
outline: none;
}
.typeahead {
background-color: #fff;
}
.typeahead:focus {
border: 2px solid #0097cf;
}
.tt-query {
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.tt-hint {
color: #999
}
.tt-dropdown-menu {
width: 800px;
margin-top: 12px;
padding: 8px 0;
background-color: #fff;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.2);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
}
.tt-suggestion {
padding: 3px 20px;
font-size: 18px;
line-height: 24px;
}
.tt-suggestion.tt-is-under-cursor {
color: #fff;
background-color: #0097cf;
}
.tt-suggestion p {
margin: 0;
}
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
var $SCRIPT_ROOT = {{ request.script_root|tojson|safe }}; var $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
</script> </script>
{% block head %}{% endblock %} {% block head -%}{% endblock -%}
</head> </head>
<body> <body>
{% include "nav.html" %} {% include "nav.html" %}
......
...@@ -2,18 +2,26 @@ ...@@ -2,18 +2,26 @@
{% block section_title %}Wallets{% endblock %} {% block section_title %}Wallets{% endblock %}
{% block head -%}
{% block subhead -%}{% endblock -%}
{% endblock -%}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-lg-3"> <div class="col-lg-3">
<div class="list-group" style="background-color: #f7f5fa;"> <div class="list-group" style="background-color: #f7f5fa;">
<a id="new" href="{{ url_for('new_wallet') }}" class="list-group-item"><i class="glyphicon glyphicon-plus-sign"></i> New</a> <a id="new" href="{{ url_for('new_wallet') }}" class="list-group-item"><i class="glyphicon glyphicon-plus-sign"></i> New</a>
<a id="list" href="{{ url_for('wallets') }}" class="list-group-item"><i class="glyphicon glyphicon-list-alt"></i> Wallet list</a> <a id="list" href="{{ url_for('wallets') }}" class="list-group-item"><i class="glyphicon glyphicon-credit-card"></i> Wallets</a>
</div> </div>
{% if key -%} {% if key -%}
<div class="panel panel-default">
<div class="panel-heading">{{key.uids.0}}</div>
<div class="list-group" style="background-color: #f7f5fa;"> <div class="list-group" style="background-color: #f7f5fa;">
<a id="history" href="{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint) }}" class="list-group-item"><i class="glyphicon glyphicon-calendar"></i> History</a> <a id="history" href="{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint) }}" class="list-group-item"><i class="glyphicon glyphicon-calendar"></i> History</a>
<a id="transfer" href="{{ url_for('wallet_transfer', pgp_fingerprint=key.fingerprint) }}" class="list-group-item"><i class="glyphicon glyphicon-transfer"></i> Transfer</a>
</div>
</div> </div>
{% endif -%} {% endif -%}
</div> </div>
...@@ -35,6 +43,7 @@ ...@@ -35,6 +43,7 @@
{% if key -%} {% if key -%}
'{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint) }}': 'history', '{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint) }}': 'history',
'{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint, type=type) }}': 'history', '{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint, type=type) }}': 'history',
'{{ url_for('wallet_transfer', pgp_fingerprint=key.fingerprint) }}': 'transfer',
{% endif -%} {% endif -%}
}; };
......
...@@ -3,11 +3,25 @@ ...@@ -3,11 +3,25 @@
{% block sub_content %} {% block sub_content %}
<h1><span class="label label-default">History</span> <span class="label label-primary">{{key.uids.0|truncate(50)}}</span></h1> <h1><span class="label label-default">History</span> <span class="label label-primary">{{key.uids.0|truncate(50)}}</span></h1>
<br/>
<div class="row">
{% with coins=clist.1|map(attribute="amount")|list|join(" + ") -%}
<div class="col-md-3">
<div class="alert alert-info tooltip_link" title="{{coins}}">Account balance: <span class="badge alert-default">{{clist.0}}</span></div>
</div>
<div class="col-md-2">
<div class="alert alert-info">{{coins}}</div>
</div>
{% endwith %}
<div class="col-md-7">
<ul class="nav nav-tabs pull-right"> <ul class="nav nav-tabs pull-right">
{% for name, color in [("all", "default"), ("transfer", "info"), ("issuance", "success"), ("fusion", "warning")] -%} {% for name, color in [("all", "default"), ("transfer", "info"), ("issuance", "success"), ("fusion", "warning")] -%}
<li {% if type == name %}class="active"{% endif %}><a href="{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint, type=name) }}"><span class="label label-{{color}}">{{name|title}}</span></a></li> <li {% if type == name %}class="active"{% endif %}><a href="{{ url_for('wallet_history', pgp_fingerprint=key.fingerprint, type=name) }}"><span class="label label-{{color}}">{{name|title}}</span></a></li>
{% endfor -%} {% endfor -%}
</ul> </ul>
</div>
</div>
{% for label,data in [("Received", recipient), ("Sent", sender)] -%} {% for label,data in [("Received", recipient), ("Sent", sender)] -%}
<h3>{{label}} transactions</h3> <h3>{{label}} transactions</h3>
...@@ -30,7 +44,7 @@ ...@@ -30,7 +44,7 @@
<td> <td>
{% with reference=tx.sender if label == "Received" else tx.recipient -%} {% with reference=tx.sender if label == "Received" else tx.recipient -%}
{% with name=settings.list_keys[reference].uids.0 if settings.list_keys[reference] else "", keyid=reference[-8:] -%} {% with name=settings.public_keys[reference].uids.0 if settings.public_keys[reference] else "", keyid=reference[-8:] -%}
<a class="tooltip_link" title="{{name}} ({{keyid}})"> <a class="tooltip_link" title="{{name}} ({{keyid}})">
{% if reference == key.fingerprint -%} {% if reference == key.fingerprint -%}
<span class="label label-default">me</span> <span class="label label-default">me</span>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</div> </div>
<div class="list-group"> <div class="list-group">
{% for fp,k in settings.list_keys.items() %} {% for fp,k in settings.secret_keys.items() %}
<a href="{{ url_for('wallet_history', pgp_fingerprint=fp) }}" class="list-group-item {% if k.keyid == settings.keyid %}active{% endif %}"> <a href="{{ url_for('wallet_history', pgp_fingerprint=fp) }}" class="list-group-item {% if k.keyid == settings.keyid %}active{% endif %}">
<h4 class="list-group-item-heading">{{k.uids.0}}</h4> <h4 class="list-group-item-heading">{{k.uids.0}}</h4>
<p class="list-group-item-text">{{fp}}</p> <p class="list-group-item-text">{{fp}}</p>
......
{% extends "wallets/base.html" %}
{% block subhead -%}
<link rel="stylesheet" href="{{ url_for('static', filename='jqueryui/themes/base/jquery.ui.all.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='wallets/typeahead.css') }}" />
{% endblock -%}
{% block sub_content %}
<h1><span class="label label-default">Transfer</span> <span class="label label-primary">{{key.uids.0|truncate(50)}}</span></h1>
<br/>
<div class="row">
{% with coins=clist.1|map(attribute="amount")|list|join(" + ") -%}
<div class="col-md-3">
<div class="alert alert-info tooltip_link" title="{{coins}}">Account balance: <span class="badge alert-default">{{clist.0}}</span></div>
</div>
<div class="col-md-2">
<div class="alert alert-info">{{coins}}</div>
</div>
{% endwith -%}
<div class="col-md-7">
</div>
</div>
<form role="form" method="post" action="{{ url_for('wallet_transfer', pgp_fingerprint=key.fingerprint) }}">
<div class="panel panel-success">
<div class="panel-heading"><h4>Recipient</h4></div>
<div class="panel-body">
<input class="typeahead" type="text" placeholder="Your recipient" name="recipient"/>
</div>
</div>
<div class="panel panel-success">
<div class="panel-heading"><h4>Amount</h4></div>
<div class="panel-body" style="padding: 20px 30px">
<div class="one_slide">
<div class="row">
<div class="col-md-10" id="amounts-slide"></div>
<div class="col-md-2 input-group" style="padding-left: 20px">
<input type="text" name="amount" id="amount" class="form-control" value="0"/>
<span class="input-group-addon">U</span>
</div>
</div>
</div>
</div>
<div class="panel-footer">
Choose the amount you want to send.
</div>
</div>
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block" type="submit">Transfer</button>
</div>
</form>
{% endblock %}
{% block subfoot %}
<script src="{{ url_for('static', filename='jqueryui/ui/jquery.ui.core.js') }}"></script>
<script src="{{ url_for('static', filename='jqueryui/ui/jquery.ui.widget.js') }}"></script>
<script src="{{ url_for('static', filename='jqueryui/ui/jquery.ui.mouse.js') }}"></script>
<script src="{{ url_for('static', filename='jqueryui/ui/jquery.ui.slider.js') }}"></script>
<script src="{{ url_for('static', filename='typeahead/dist/typeahead.min.js') }}"></script>
<script src="{{ url_for('static', filename='hogan/web/builds/2.0.0/hogan-2.0.0.min.js') }}"></script>
<script>
$(function() {
var amounts = [{{ sums|join(",") }}]
$('#amounts-slide').slider({
range: 'max',
min: 0,
max: amounts.length-1,
value: 0,
slide: function( event, ui ) {
$('#amount')[0].value = amounts[parseInt(ui.value)];
}
});
$('#amount')[0].value = amounts[parseInt($('#amounts-slide').slider('value'))];
$('.payment_type_detail').hide();
$('.radio-select').each(function() {
if ($(this)[0].checked) {
$(this).parent().addClass('active');
$('#payment_type_' + $(this).val()).show();
}
if ($(this).hasClass('disabled')) {
$(this).parent().addClass('disabled');
}
});
$('.radio-select').change(function() {
$('.payment_type_detail').hide();
$('#payment_type_' + $(this).val()).show();
});
});
</script>
<style>
.ui-slider .ui-slider-handle { height: 2.7em; }
.ui-slider { height: 2.2em; }
</style>
<script>
$(function() {
$('.typeahead').typeahead({
name: 'recipient',
prefetch: '{{ url_for('wallet_public_keys') }}',
template: [
{% raw -%}
'<p class="key-name">{{name}}</p>',
'<p class="key-fingerprint">{{fingerprint}}</p>',
{% endraw -%}
].join(''),
engine: Hogan,
});
});
</script>
{% endblock %}
...@@ -23,10 +23,12 @@ from collections import OrderedDict ...@@ -23,10 +23,12 @@ from collections import OrderedDict
from merkle import Merkle from merkle import Merkle
from flask import Flask, request, render_template, jsonify from flask import Flask, request, render_template, jsonify
from io import StringIO from io import StringIO
from werkzeug.contrib.cache import SimpleCache
from itertools import combinations, chain
logger = logging.getLogger("cli") logger = logging.getLogger("cli")
app = Flask(__name__) app = Flask(__name__)
cache = SimpleCache()
@app.template_filter('split') @app.template_filter('split')
def split_filter(s, sep=' '): def split_filter(s, sep=' '):
...@@ -76,28 +78,185 @@ VotersCount\t\t%(votersCount)s ...@@ -76,28 +78,185 @@ VotersCount\t\t%(votersCount)s
def wallets(): def wallets():
return render_template('wallets/index.html', settings=ucoin.settings) return render_template('wallets/index.html', settings=ucoin.settings)
@app.route('/wallets/new')
def new_wallet():
return render_template('wallets/new.html', settings=ucoin.settings)
@app.route('/wallets/new/create')
def new_wallet_create():
__input = 'Key-Type: %(type)s\nName-Email: %(email)s\nName-Real: %(realm)s\nKey-Length: %(length)s\n%%commit\n' % request.args
newkey = ucoin.settings['gpg'].gen_key(__input)
return jsonify(result="Your new key (%s) has been successfully created." % newkey.fingerprint)
def get_sender_transactions(pgp_fingerprint):
k = 'sender_transactions_%s' % pgp_fingerprint
rv = cache.get(k)
if rv is None:
rv = list(ucoin.hdc.transactions.Sender(pgp_fingerprint).get())
cache.set(k, rv, timeout=5*60)
return rv
def get_recipient_transactions(pgp_fingerprint):
k = 'sender_transactions_%s' % pgp_fingerprint
rv = cache.get(k)
if rv is None:
rv = list(ucoin.hdc.transactions.Recipient(pgp_fingerprint).get())
cache.set(k, rv, timeout=5*60)
return rv
def clist(pgp_fingerprint):
__list = ucoin.hdc.coins.List(pgp_fingerprint).get()
coins = []
__sum = 0
for c in __list['coins']:
for id in c['ids']:
n,b,p,t,i = id.split('-')
amount = int(b) * 10**int(p)
__dict = {'issuer': c['issuer'], 'number': int(n), 'base': int(b), 'power': int(p), 'type': t, 'type_number': int(i), 'amount': amount}
coins.append(__dict)
__sum += amount
return __sum, coins
@app.route('/wallets/<pgp_fingerprint>/history') @app.route('/wallets/<pgp_fingerprint>/history')
@app.route('/wallets/<pgp_fingerprint>/history/<type>') @app.route('/wallets/<pgp_fingerprint>/history/<type>')
def wallet_history(pgp_fingerprint, type='all'): def wallet_history(pgp_fingerprint, type='all'):
sender = ucoin.hdc.transactions.Sender(pgp_fingerprint).get() sender = get_sender_transactions(pgp_fingerprint)
recipient = ucoin.hdc.transactions.Recipient(pgp_fingerprint).get() recipient = get_recipient_transactions(pgp_fingerprint)
return render_template('wallets/history.html', return render_template('wallets/history.html',
settings=ucoin.settings, settings=ucoin.settings,
key=ucoin.settings['list_keys'].get(pgp_fingerprint), key=ucoin.settings['secret_keys'].get(pgp_fingerprint),
sender=sender, sender=sender,
recipient=recipient, recipient=recipient,
type=type) type=type,
clist=clist(pgp_fingerprint))
def powerset(iterable):
xs = list(iterable)
return chain.from_iterable( combinations(xs,n) for n in range(len(xs)+1) )
def cget(pgp_fingerprint, values):
__list = ucoin.hdc.coins.List(pgp_fingerprint).get()
coins = {}
for c in __list['coins']:
for id in c['ids']:
n,b,p,t,i = id.split('-')
amount = int(b) * 10**int(p)
coins[amount] = {'issuer': c['issuer'], 'number': int(n), 'base': int(b), 'power': int(p), 'type': t, 'type_number': int(i), 'amount': amount}
issuers = {}
for v in values:
if v in coins:
c = coins[v]
issuers[c['issuer']] = issuers.get(c['issuer']) or []
issuers[c['issuer']].append(c)
else:
raise ValueError('You do not have enough coins of value (%d)' % v)
@app.route('/wallets/new') res = ''
def new_wallet(): for i, issuer in enumerate(issuers):
return render_template('wallets/new.html', settings=ucoin.settings) if i > 0: res += ','
res += issuer
for c in issuers[issuer]:
res += ':%(number)d' % c
@app.route('/wallets/new/create') return res
def new_wallet_create():
__input = 'Key-Type: %(type)s\nName-Email: %(email)s\nName-Real: %(realm)s\nKey-Length: %(length)s\n%%commit\n' % request.args def transfer(pgp_fingerprint, recipient, coins, message=''):
newkey = ucoin.settings['gpg'].gen_key(__input) try:
return jsonify(result="Your new key (%s) has been successfully created." % newkey.fingerprint) last_tx = ucoin.hdc.transactions.sender.Last(pgp_fingerprint).get()
except ValueError:
last_tx = None
__dict = {}
__dict.update(ucoin.settings)
__dict['version'] = 1
__dict['number'] = 0 if not last_tx else last_tx['transaction']['number']+1
__dict['previousHash'] = hashlib.sha1(("%(raw)s%(signature)s" % last_tx).encode('ascii')).hexdigest().upper()
__dict['type'] = 'TRANSFER'
__dict['recipient'] = recipient
__dict['message'] = message
tx = """\
Version: %(version)d
Currency: %(currency)s
Sender: %(fingerprint)s
Number: %(number)d
""" % __dict
if last_tx: tx += "PreviousHash: %(previousHash)s\n" % __dict
tx += """\
Recipient: %(recipient)s
Type: %(type)s
Coins:
""" % __dict
for coin in coins.split(','):
data = coin.split(':')
issuer = data[0]
for number in data[1:]:
__dict.update(ucoin.hdc.coins.View(issuer, int(number)).get())
tx += '%(id)s, %(transaction)s\n' % __dict
tx += """\
Comment:
%(message)s
""" % __dict
tx = tx.replace("\n", "\r\n")
txs = ucoin.settings['gpg'].sign(tx, detach=True)
try:
ucoin.hdc.transactions.Process().post(transaction=tx, signature=txs)
except ValueError as e:
print(e)
else:
return True
return False
@app.route('/wallets/<pgp_fingerprint>/transfer', methods=['GET', 'POST',])
def wallet_transfer(pgp_fingerprint):
balance, __clist = clist(pgp_fingerprint)
amounts = [x['amount'] for x in __clist]
__combinations = list(map(lambda x: (sum(x), x), powerset(amounts)))[1:]
__combinations.sort()
sums = [x[0] for x in __combinations]
if request.method == 'GET':
return render_template('wallets/transfer.html',
settings=ucoin.settings,
key=ucoin.settings['secret_keys'].get(pgp_fingerprint),
clist=(balance,__clist),
sums=sums)
amount = request.form.get('amount', type=int)
recipient = request.form.get('recipient')
message = request.form.get('message', '')
try:
idx = sums.index(amount)
except ValueError as e:
raise ValueError(e)
selected_combination = __combinations[idx][1]
coins = cget(pgp_fingerprint, selected_combination)
if not transfer(pgp_fingerprint, recipient, coins, message):
raise ValueError('transfer error')
return '%s %s' % (str(selected_combination), recipient)
@app.route('/wallets/public_keys')
def wallet_public_keys():
keys = ucoin.settings['public_keys']
for k,v in keys.items():
v['value'] = v['fingerprint']
v['tokens'] = v['uids']
v['name'] = v['uids'][0]
return json.dumps(list(keys.values()))
@app.route('/api') @app.route('/api')
def api(): def api():
...@@ -390,14 +549,19 @@ if __name__ == '__main__': ...@@ -390,14 +549,19 @@ if __name__ == '__main__':
logger.debug('selected keyid: %s' % ucoin.settings['user']) logger.debug('selected keyid: %s' % ucoin.settings['user'])
ucoin.settings['gpg'] = gpg = gnupg.GPG(options=['-u %s' % ucoin.settings['user']]) ucoin.settings['gpg'] = gpg = gnupg.GPG(options=['-u %s' % ucoin.settings['user']])
keys = gpg.list_keys(True) secret_keys = gpg.list_keys(True)
for idx, fp in enumerate(keys.fingerprints): public_keys = gpg.list_keys()
for idx, fp in enumerate(secret_keys.fingerprints):
if fp[-8:] == ucoin.settings['user']: if fp[-8:] == ucoin.settings['user']:
ucoin.settings.update(keys[idx]) ucoin.settings.update(secret_keys[idx])
break break
ucoin.settings['list_keys'] = __list_keys = {} ucoin.settings['secret_keys'] = __secret_keys = {}
for k in keys: __list_keys[k['fingerprint']] = k ucoin.settings['public_keys'] = __public_keys = {}
for k in secret_keys: __secret_keys[k['fingerprint']] = k
for k in public_keys: __public_keys[k['fingerprint']] = k
else: else:
ucoin.settings['gpg'] = gpg = gnupg.GPG() ucoin.settings['gpg'] = gpg = gnupg.GPG()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment