refactor(tpos): migrate extension
This commit is contained in:
parent
2d694c6b8a
commit
a455379ee1
|
@ -30,6 +30,7 @@ Talisman(
|
|||
"cdnjs.cloudflare.com",
|
||||
"code.ionicframework.com",
|
||||
"code.jquery.com",
|
||||
"api.opennode.co",
|
||||
"fonts.googleapis.com",
|
||||
"fonts.gstatic.com",
|
||||
"maxcdn.bootstrapcdn.com",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "TPOS",
|
||||
"short_description": "A shareable POS!",
|
||||
"icon": "dialpad",
|
||||
"contributors": ["talvasconcelos", "arcbtc"]
|
||||
"name": "TPoS",
|
||||
"short_description": "A shareable PoS terminal!",
|
||||
"icon": "dialpad",
|
||||
"contributors": ["talvasconcelos", "arcbtc"]
|
||||
}
|
||||
|
|
|
@ -5,14 +5,16 @@ def m001_initial(db):
|
|||
"""
|
||||
Initial tposs table.
|
||||
"""
|
||||
db.execute("""
|
||||
db.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS tposs (
|
||||
id TEXT PRIMARY KEY,
|
||||
wallet TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
currency TEXT NOT NULL
|
||||
);
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def migrate():
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<q-btn unelevated color="deep-purple" @click="tposDialog.show = true">New TPoS</q-btn>
|
||||
<q-btn unelevated color="deep-purple" @click="formDialog.show = true">New TPoS</q-btn>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
|||
<template v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
<q-th auto-width></q-th>
|
||||
|
||||
<q-th
|
||||
v-for="col in props.cols"
|
||||
:key="col.name"
|
||||
|
@ -39,17 +38,15 @@
|
|||
>
|
||||
{{ col.label }}
|
||||
</q-th>
|
||||
|
||||
<q-th auto-width></q-th>
|
||||
|
||||
</q-tr>
|
||||
</template>
|
||||
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props">
|
||||
<q-td auto-width>
|
||||
<q-btn unelevated dense size="xs" icon="vpn_lock" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" type="a" :href="props.row.tpos" target="_blank"></q-btn>
|
||||
</q-td>
|
||||
<q-btn unelevated dense size="xs" icon="launch" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" type="a" :href="props.row.tpos" target="_blank"></q-btn>
|
||||
</q-td>
|
||||
<q-td
|
||||
v-for="col in props.cols"
|
||||
:key="col.name"
|
||||
|
@ -77,47 +74,43 @@
|
|||
<q-separator></q-separator>
|
||||
<q-list>
|
||||
<q-expansion-item
|
||||
group="extras"
|
||||
icon="swap_vertical_circle"
|
||||
label="Info"
|
||||
:content-inset-level="0.5"
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<h5 class="text-subtitle1 q-my-none">Tiago's Point of Sale</h5>
|
||||
<p>Is an instant and secure point of sale terminal. A merchant can use the PoS to accept payments to their LNbits wallet, without having to expose the wallet itself, which means it can even be shared with others. <br/>For example, a merchant could setup multiple TPoSs for each one of their colleagues, and use TPoS to track which colleague has taken sales. The terminal is optimized for mobile use, and is easily shared as a QR code, via the # share function on the TPoS. <br/>
|
||||
<small> Created by, <a href="https://github.com/talvasconcelos">Tiago Vasconcelos</a></small></p>
|
||||
group="extras"
|
||||
icon="info"
|
||||
label="Info">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<h5 class="text-subtitle1 q-mt-none q-mb-sm">Tiago's Point of Sale</h5>
|
||||
<p>Is an instant and secure point of sale terminal. A merchant can use the PoS to accept payments to their LNbits wallet, without having to expose the wallet itself, which means it can even be shared with others.</p>
|
||||
<p>For example, a merchant could setup multiple TPoSs for each one of their colleagues, and use TPoS to track which colleague has taken sales. The terminal is optimized for mobile use, and is easily shared as a QR code, via the "#" share function on the TPoS.</p>
|
||||
<small>Created by <a href="https://github.com/talvasconcelos" target="_blank">Tiago Vasconcelos</a>.</small>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-card-section>
|
||||
|
||||
</q-expansion-item>
|
||||
</q-expansion-item>
|
||||
</q-list>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<q-dialog v-model="tposDialog.show" position="top">
|
||||
<q-dialog v-model="formDialog.show" position="top" @hide="closeFormDialog">
|
||||
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
||||
<q-form class="q-gutter-md">
|
||||
|
||||
<q-input filled dense
|
||||
v-model.trim="tposDialog.data.name"
|
||||
label="Name"
|
||||
placeholder="Tiago's PoS"></q-input>
|
||||
|
||||
<q-select filled dense emit-value v-model="tposDialog.data.wallet" :options="g.user.walletOptions" label="Wallet *">
|
||||
</q-select>
|
||||
|
||||
<q-select filled dense emit-value v-model="tposDialog.data.currency" :options="currencyOptions" label="Currency *">
|
||||
</q-select>
|
||||
|
||||
|
||||
<q-btn unelevated
|
||||
color="deep-purple"
|
||||
:disable="tposDialog.data.currency == null || tposDialog.data.name == null"
|
||||
@click="createTPoS">Create TPoS</q-btn>
|
||||
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
v-model.trim="formDialog.data.name"
|
||||
label="Name"
|
||||
placeholder="Tiago's PoS"></q-input>
|
||||
<q-select filled dense
|
||||
emit-value v-model="formDialog.data.wallet"
|
||||
:options="g.user.walletOptions"
|
||||
label="Wallet *"></q-select>
|
||||
<q-select filled dense
|
||||
emit-value v-model="formDialog.data.currency"
|
||||
:options="currencyOptions"
|
||||
label="Currency *"></q-select>
|
||||
<q-btn unelevated
|
||||
color="deep-purple"
|
||||
:disable="formDialog.data.currency == null || formDialog.data.name == null"
|
||||
@click="createTPoS">Create TPoS</q-btn>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
@ -141,9 +134,13 @@
|
|||
return {
|
||||
tposs: [],
|
||||
currencyOptions: [
|
||||
'USD', 'EUR', 'GBP', 'DZD', 'ARP', 'AUD', 'ATS', 'BSD', 'BBD', 'BEF', 'BMD', 'BRL', 'BGL', 'CAD', 'CLP', 'CNY', 'CYP', 'CSK', 'DKK', 'NLG', 'XCD', 'EGP', 'FJD', 'FIM', 'FRF', 'DEM', 'XAU', 'GRD', 'HKD', 'HUF', 'ISK', 'INR', 'IDR', 'IEP', 'ILS', 'ITL', 'JMD', 'JPY', 'JOD', 'KRW', 'LBP', 'LUF', 'MYR', 'MXP', 'NLG', 'NZD', 'NOK', 'PKR', 'XPD', 'PHP', 'XPT', 'PLZ', 'PTE', 'ROL', 'RUR', 'SAR', 'XAG', 'SGD', 'SKK', 'ZAR', 'KRW', 'ESP', 'XDR', 'SDD', 'SEK', 'CHF', 'TWD', 'THB', 'TTD', 'TRL', 'VEB', 'ZMK', 'EUR', 'XCD', 'XDR', 'XAG', 'XAU', 'XPD', 'XPT',
|
||||
],
|
||||
|
||||
'USD', 'EUR', 'GBP', 'DZD', 'ARP', 'AUD', 'ATS', 'BSD', 'BBD', 'BEF', 'BMD', 'BRL', 'BGL', 'CAD', 'CLP',
|
||||
'CNY', 'CYP', 'CSK', 'DKK', 'NLG', 'XCD', 'EGP', 'FJD', 'FIM', 'FRF', 'DEM', 'XAU', 'GRD', 'HKD', 'HUF',
|
||||
'ISK', 'INR', 'IDR', 'IEP', 'ILS', 'ITL', 'JMD', 'JPY', 'JOD', 'KRW', 'LBP', 'LUF', 'MYR', 'MXP', 'NLG',
|
||||
'NZD', 'NOK', 'PKR', 'XPD', 'PHP', 'XPT', 'PLZ', 'PTE', 'ROL', 'RUR', 'SAR', 'XAG', 'SGD', 'SKK', 'ZAR',
|
||||
'KRW', 'ESP', 'XDR', 'SDD', 'SEK', 'CHF', 'TWD', 'THB', 'TTD', 'TRL', 'VEB', 'ZMK', 'EUR', 'XCD', 'XDR',
|
||||
'XAG', 'XAU', 'XPD', 'XPT'
|
||||
],
|
||||
tpossTable: {
|
||||
columns: [
|
||||
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
||||
|
@ -154,13 +151,16 @@
|
|||
rowsPerPage: 10
|
||||
}
|
||||
},
|
||||
tposDialog: {
|
||||
formDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
closeFormDialog: function () {
|
||||
this.formDialog.data = {};
|
||||
},
|
||||
getTPoSs: function () {
|
||||
var self = this;
|
||||
|
||||
|
@ -170,29 +170,25 @@
|
|||
this.g.user.wallets[0].inkey
|
||||
).then(function (response) {
|
||||
self.tposs = response.data.map(function (obj) {
|
||||
console.log(obj)
|
||||
return mapTPoS(obj);
|
||||
});
|
||||
});
|
||||
},
|
||||
createTPoS: function () {
|
||||
var data = {
|
||||
name: this.tposDialog.data.name,
|
||||
currency: this.tposDialog.data.currency
|
||||
name: this.formDialog.data.name,
|
||||
currency: this.formDialog.data.currency
|
||||
};
|
||||
var self = this;
|
||||
|
||||
console.log(this.tposDialog.data.wallet);
|
||||
|
||||
LNbits.api.request(
|
||||
'POST',
|
||||
'/tpos/api/v1/tposs',
|
||||
_.findWhere(this.g.user.wallets, {id: this.tposDialog.data.wallet}).inkey,
|
||||
_.findWhere(this.g.user.wallets, {id: this.formDialog.data.wallet}).inkey,
|
||||
data
|
||||
).then(function (response) {
|
||||
self.tposs.push(mapTPoS(response.data));
|
||||
self.tposDialog.show = false;
|
||||
self.tposDialog.data = {};
|
||||
self.formDialog.show = false;
|
||||
}).catch(function (error) {
|
||||
LNbits.utils.notifyApiError(error);
|
||||
});
|
||||
|
@ -202,7 +198,7 @@
|
|||
var tpos = _.findWhere(this.tposs, {id: tposId});
|
||||
|
||||
this.$q.dialog({
|
||||
message: 'Are you sure you want to delete this TPoS link?',
|
||||
message: 'Are you sure you want to delete this TPoS?',
|
||||
ok: {
|
||||
flat: true,
|
||||
color: 'orange'
|
||||
|
@ -235,5 +231,3 @@
|
|||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,8 +1,5 @@
|
|||
import requests
|
||||
|
||||
from flask import g, abort, render_template
|
||||
|
||||
from lnbits.core.crud import get_wallet
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
from lnbits.helpers import Status
|
||||
|
||||
|
@ -19,8 +16,6 @@ def index():
|
|||
|
||||
@tpos_ext.route("/<tpos_id>")
|
||||
def tpos(tpos_id):
|
||||
tpos = get_tpos(tpos_id) or abort(Status.NOT_FOUND, "tpos does not exist.")
|
||||
r = requests.get("https://api.opennode.co/v1/rates")
|
||||
r_json = r.json()
|
||||
rr = get_wallet(tpos.wallet)
|
||||
return render_template("tpos/tpos.html", tpos=tpos.id, inkey=rr.inkey, rate=r_json["data"]["BTC" + tpos.currency][tpos.currency], curr=tpos.currency)
|
||||
tpos = get_tpos(tpos_id) or abort(Status.NOT_FOUND, "TPoS does not exist.")
|
||||
|
||||
return render_template("tpos/tpos.html", tpos=tpos)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from flask import g, jsonify, request
|
||||
|
||||
from lnbits.core.crud import get_user
|
||||
from lnbits.core.crud import get_user, get_wallet
|
||||
from lnbits.core.services import create_invoice
|
||||
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
||||
from lnbits.helpers import Status
|
||||
|
@ -30,9 +30,7 @@ def api_tposs():
|
|||
}
|
||||
)
|
||||
def api_tpos_create():
|
||||
print("poo")
|
||||
|
||||
tpos = create_tpos(wallet_id=g.wallet.id, name=g.data["name"], currency=g.data["currency"])
|
||||
tpos = create_tpos(wallet_id=g.wallet.id, **g.data)
|
||||
|
||||
return jsonify(tpos._asdict()), Status.CREATED
|
||||
|
||||
|
@ -50,31 +48,44 @@ def api_tpos_delete(tpos_id):
|
|||
|
||||
delete_tpos(tpos_id)
|
||||
|
||||
return '', Status.NO_CONTENT
|
||||
return "", Status.NO_CONTENT
|
||||
|
||||
|
||||
@tpos_ext.route("/api/v1/tposs/invoice/<tpos_id>", methods=["POST"])
|
||||
@tpos_ext.route("/api/v1/tposs/<tpos_id>/invoices/", methods=["POST"])
|
||||
@api_validate_post_request(schema={"amount": {"type": "integer", "min": 1, "required": True}})
|
||||
def api_tpos_create_invoice(tpos_id):
|
||||
|
||||
tpos = get_tpos(tpos_id)
|
||||
|
||||
if not tpos:
|
||||
return jsonify({"message": "TPoS does not exist."}), Status.NOT_FOUND
|
||||
try:
|
||||
memo = f"TPoS {tpos_id}"
|
||||
checking_id, payment_request = create_invoice(wallet_id=tpos.wallet, amount=g.data["amount"], memo=memo)
|
||||
|
||||
try:
|
||||
checking_id, payment_request = create_invoice(
|
||||
wallet_id=tpos.wallet, amount=g.data["amount"], memo=f"#tpos {tpos.name}"
|
||||
)
|
||||
except Exception as e:
|
||||
return jsonify({"message": str(e)}), Status.INTERNAL_SERVER_ERROR
|
||||
|
||||
return jsonify({"checking_id": checking_id, "payment_request": payment_request}), Status.OK
|
||||
return jsonify({"checking_id": checking_id, "payment_request": payment_request}), Status.CREATED
|
||||
|
||||
@tpos_ext.route("/api/v1/tposs/invoice/<checking_id>", methods=["GET"])
|
||||
def api_tpos_check_invoice(checking_id):
|
||||
print(checking_id)
|
||||
PAID = WALLET.get_invoice_status(checking_id).paid
|
||||
|
||||
if PAID == True:
|
||||
return jsonify({"PAID": True}), Status.OK
|
||||
return jsonify({"PAID": False}), Status.OK
|
||||
@tpos_ext.route("/api/v1/tposs/<tpos_id>/invoices/<checking_id>", methods=["GET"])
|
||||
def api_tpos_check_invoice(tpos_id, checking_id):
|
||||
tpos = get_tpos(tpos_id)
|
||||
|
||||
if not tpos:
|
||||
return jsonify({"message": "TPoS does not exist."}), Status.NOT_FOUND
|
||||
|
||||
try:
|
||||
is_paid = not WALLET.get_invoice_status(checking_id).pending
|
||||
except Exception:
|
||||
return jsonify({"paid": False}), Status.OK
|
||||
|
||||
if is_paid:
|
||||
wallet = get_wallet(tpos.wallet)
|
||||
payment = wallet.get_payment(checking_id)
|
||||
payment.set_pending(False)
|
||||
|
||||
return jsonify({"paid": True}), Status.OK
|
||||
|
||||
return jsonify({"paid": False}), Status.OK
|
||||
|
|
|
@ -26,11 +26,15 @@
|
|||
{% block drawer_toggle %}
|
||||
<q-btn dense flat round icon="menu" @click="g.visibleDrawer = !g.visibleDrawer"></q-btn>
|
||||
{% endblock %}
|
||||
{% if SITE_TITLE != 'LNbits' %}
|
||||
<q-toolbar-title>{{ SITE_TITLE }}</q-toolbar-title>
|
||||
{% else %}
|
||||
<q-toolbar-title><strong>LN</strong>bits</q-toolbar-title>
|
||||
{% endif %}
|
||||
<q-toolbar-title>
|
||||
{% block toolbar_title %}
|
||||
{% if SITE_TITLE != 'LNbits' %}
|
||||
{{ SITE_TITLE }}
|
||||
{% else %}
|
||||
<strong>LN</strong>bits
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</q-toolbar-title>
|
||||
{% block beta %}
|
||||
<q-badge color="yellow" text-color="black">
|
||||
<span><span v-show="$q.screen.gt.sm">USE WITH CAUTION - LNbits wallet is still in </span>BETA</span>
|
||||
|
@ -49,23 +53,27 @@
|
|||
</q-drawer>
|
||||
{% endblock %}
|
||||
|
||||
<q-page-container>
|
||||
<q-page class="q-px-md q-py-lg" :class="{'q-px-lg': $q.screen.gt.xs}">
|
||||
{% block page %}{% endblock %}
|
||||
</q-page>
|
||||
</q-page-container>
|
||||
{% block page_container %}
|
||||
<q-page-container>
|
||||
<q-page class="q-px-md q-py-lg" :class="{'q-px-lg': $q.screen.gt.xs}">
|
||||
{% block page %}{% endblock %}
|
||||
</q-page>
|
||||
</q-page-container>
|
||||
{% endblock %}
|
||||
|
||||
<q-footer class="bg-transparent q-px-lg q-py-md" :class="{'text-dark': !$q.dark.isActive}">
|
||||
<q-toolbar>
|
||||
<q-toolbar-title class="text-caption">
|
||||
<strong>LN</strong>bits, free and open-source lightning wallet
|
||||
</q-toolbar-title>
|
||||
<q-space></q-space>
|
||||
<q-btn flat dense :color="($q.dark.isActive) ? 'white' : 'deep-purple'" icon="code" type="a" href="https://github.com/arcbtc/lnbits" target="_blank" rel="noopener">
|
||||
<q-tooltip>View project in GitHub</q-tooltip>
|
||||
</q-btn>
|
||||
</q-toolbar>
|
||||
</q-footer>
|
||||
{% block footer %}
|
||||
<q-footer class="bg-transparent q-px-lg q-py-md" :class="{'text-dark': !$q.dark.isActive}">
|
||||
<q-toolbar>
|
||||
<q-toolbar-title class="text-caption">
|
||||
<strong>LN</strong>bits, free and open-source lightning wallet
|
||||
</q-toolbar-title>
|
||||
<q-space></q-space>
|
||||
<q-btn flat dense :color="($q.dark.isActive) ? 'white' : 'deep-purple'" icon="code" type="a" href="https://github.com/arcbtc/lnbits" target="_blank" rel="noopener">
|
||||
<q-tooltip>View project in GitHub</q-tooltip>
|
||||
</q-btn>
|
||||
</q-toolbar>
|
||||
</q-footer>
|
||||
{% endblock %}
|
||||
|
||||
</q-layout>
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user