summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPiotr Dobrowolski <admin@tastycode.pl>2017-04-12 01:21:52 +0200
committerPiotr Dobrowolski <admin@tastycode.pl>2017-04-12 01:21:52 +0200
commitc64de735c7f097de01ead0036f6001a56b49c227 (patch)
tree1cff6dae292ace2cd95e447612d7732b7ef94024
parent24da996fe635bc1887ce5f45d7d7a6003d0fd4de (diff)
downloadbitvend-c64de735c7f097de01ead0036f6001a56b49c227.tar.gz
bitvend-c64de735c7f097de01ead0036f6001a56b49c227.tar.bz2
bitvend-c64de735c7f097de01ead0036f6001a56b49c227.tar.xz
bitvend-c64de735c7f097de01ead0036f6001a56b49c227.zip
Initial admin interface
-rw-r--r--bitvend/__init__.py2
-rw-r--r--bitvend/admin.py31
-rw-r--r--bitvend/auth.py3
-rw-r--r--bitvend/forms.py5
-rw-r--r--bitvend/models.py4
-rw-r--r--bitvend/templates/admin/manual.html15
-rw-r--r--bitvend/templates/admin/transactions.html46
-rw-r--r--bitvend/templates/index.html4
8 files changed, 110 insertions, 0 deletions
diff --git a/bitvend/__init__.py b/bitvend/__init__.py
index 0696395..e318cd4 100644
--- a/bitvend/__init__.py
+++ b/bitvend/__init__.py
@@ -12,6 +12,7 @@ from bitvend.models import db, Transaction
from bitvend.auth import login_manager
import bitvend.views
+import bitvend.admin
def create_app():
@@ -24,6 +25,7 @@ def create_app():
proc.init_app(app)
app.register_blueprint(bitvend.views.bp)
+ app.register_blueprint(bitvend.admin.bp, url_prefix='/admin')
@app.context_processor
def ctx_utils():
diff --git a/bitvend/admin.py b/bitvend/admin.py
new file mode 100644
index 0000000..fdbab1a
--- /dev/null
+++ b/bitvend/admin.py
@@ -0,0 +1,31 @@
+from flask import Blueprint, render_template, redirect, request, flash, url_for
+from flask_login import current_user
+
+from bitvend.models import db, Transaction
+from bitvend.forms import ManualForm
+from bitvend.auth import cap_required
+
+
+admin_required = cap_required('staff')
+bp = Blueprint('admin', __name__)
+
+@bp.route('/manual', methods=['GET', 'POST'])
+@admin_required
+def manual():
+ form = ManualForm()
+ if form.validate_on_submit():
+ current_user.transactions.append(Transaction(
+ amount=form.amount.data
+ ))
+ db.session.commit()
+ flash('Operation successful.', 'success')
+
+ return render_template('admin/manual.html', form=form)
+
+@bp.route('/transactions/', defaults={'page': 1})
+@bp.route('/transactions/p/<int:page>')
+@admin_required
+def transactions(page):
+ return render_template('admin/transactions.html',
+ transactions=Transaction.query.paginate(page)
+ )
diff --git a/bitvend/auth.py b/bitvend/auth.py
index 8f7f71b..f3a8552 100644
--- a/bitvend/auth.py
+++ b/bitvend/auth.py
@@ -34,6 +34,9 @@ def try_login(username, password):
def cap_check(capability, user=None):
+ if not current_user.is_authenticated:
+ return False
+
user = user or current_user.get_id()
if session.get('_caps', {}).get(capability, 0) > time.time():
diff --git a/bitvend/forms.py b/bitvend/forms.py
index 212f3d2..203b3d5 100644
--- a/bitvend/forms.py
+++ b/bitvend/forms.py
@@ -42,3 +42,8 @@ class TransferForm(FlaskForm):
amount = DecimalUnityField("Amount", default=0, validators=[
NumberRange(min=1),
])
+
+class ManualForm(FlaskForm):
+ amount = DecimalUnityField("Amount", default=0, validators=[
+ NumberRange(min=1),
+ ])
diff --git a/bitvend/models.py b/bitvend/models.py
index 21a9891..89856aa 100644
--- a/bitvend/models.py
+++ b/bitvend/models.py
@@ -89,3 +89,7 @@ class Transaction(db.Model):
@hybrid_property
def finished(self):
return (self.type != 'purchase') | (self.product_id != None)
+
+ __mapper_args__ = {
+ "order_by": created.desc()
+ }
diff --git a/bitvend/templates/admin/manual.html b/bitvend/templates/admin/manual.html
new file mode 100644
index 0000000..51d8a82
--- /dev/null
+++ b/bitvend/templates/admin/manual.html
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+
+{% from "_helpers.html" import render_field, render_submit %}
+
+{% block content %}
+ <h1 class="page-header">Manual transaction </h1>
+ <p class="text-muted">Creates manual transaction for current user. Use this when filling machine with money.</p>
+ <div class="row">
+ <form action="{{ url_for('.manual') }}" method="POST" class="form-horizontal col-md-6 col-md-offset-3">
+ {{ form.hidden_tag() }}
+ {{ render_field(form.amount) }}
+ {{ render_submit() }}
+ </form>
+ </div>
+{% endblock %}
diff --git a/bitvend/templates/admin/transactions.html b/bitvend/templates/admin/transactions.html
new file mode 100644
index 0000000..74c69d8
--- /dev/null
+++ b/bitvend/templates/admin/transactions.html
@@ -0,0 +1,46 @@
+{% extends "base.html" %}
+
+{% from "_helpers.html" import format_currency, render_pagination %}
+{% set _tx_styles = {
+ 'transfer': 'primary',
+ 'bitcoin': 'warning',
+ 'purchase': 'info',
+} %}
+{% block content %}
+ <table class="table table-hover table-striped">
+ <thead>
+ <tr>
+ <th class="text-right">User</th>
+ <th>Type</th>
+ <th class="text-right">Amount</th>
+ <th>Date</th>
+ </tr>
+ </thead>
+
+ {% for tx in transactions.items %}
+ <tr{% if not tx.finished %} style="opacity: 0.5"{% endif %}>
+ <td class="text-right">{{ tx.user }}</td>
+ <td>
+ <span class="label label-{{ _tx_styles[tx.type]|default('default') }}">{{ tx.type }}</span> {% if not tx.finished %}<i>(processing)</i>{% endif %}
+ <small>
+ {% if tx.type == 'transfer' and tx.amount > 0 %}
+ from <b>{{ tx.related_user }}</b>
+ {% elif tx.type == 'transfer' and tx.amount < 0 %}
+ to <b>{{ tx.related }}</b>
+ {% elif tx.type == 'purchase' and tx.product_id %}
+ of product <b>{{ tx.product_id }}</b>
+ {% elif tx.type == 'bitcoin' %}
+ <a href="https://live.blockcypher.com/btc/tx/{{ tx.tx_hash }}">{{ tx.tx_hash|truncate(9) }}</a>
+ {% endif %}
+ </small>
+ </td>
+ <td class="text-right">{{ format_currency(tx.amount) }}</td>
+ <td>{{ tx.created }}</td>
+ </tr>
+ {% else %}
+ <tr><td colspan=3 class="placeholder">Nothing to see here...</td></tr>
+ {% endfor %}
+ </table>
+
+ {{ render_pagination(transactions) }}
+{% endblock %}
diff --git a/bitvend/templates/index.html b/bitvend/templates/index.html
index 2c2cbe6..562c45f 100644
--- a/bitvend/templates/index.html
+++ b/bitvend/templates/index.html
@@ -134,4 +134,8 @@
</div>
{% endfor %}
</div>
+ <blockquote class="blockquote-reverse">
+ <p>Kowalski czuje zapach pieniędzy.</p>
+ <small>Someone famous</small>
+ </blockquote>
{% endblock %}