Browse Source

Merge pull request #12 from arcbtc/lnbitsevents

Lnbitsevents
fee_issues
Arc 5 years ago
committed by GitHub
parent
commit
f24b1a5d19
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      lnbits/extensions/events/example.config.json
  2. 13
      lnbits/extensions/events/schema.sql
  3. 182
      lnbits/extensions/events/templates/events/index.html
  4. 92
      lnbits/extensions/events/views.py
  5. 4
      lnbits/extensions/example/README.md
  6. 8
      lnbits/extensions/example/__init__.py
  7. 5
      lnbits/extensions/example/example.config.json
  8. 7
      lnbits/extensions/example/schema.sql
  9. 102
      lnbits/extensions/example/templates/example/index.html
  10. 14
      lnbits/extensions/example/views.py
  11. 18
      lnbits/extensions/example/views_api.py
  12. 6
      lnbits/extensions/withdraw/README.md
  13. 64
      lnbits/extensions/withdraw/views_api.py
  14. 7
      lnbits/static/bootstrap/css/datepicker.min.css
  15. 8
      lnbits/static/bootstrap/js/datepicker.min.js
  16. 13
      lnbits/templates/base.html

2
lnbits/extensions/events/config.json → lnbits/extensions/events/example.config.json

@ -1,5 +1,5 @@
{
"name": "LNEVENTS",
"short_description": "Make LNURL withdraw links.",
"ion_icon": "calendar-outline"
"ion_icon": "calendar"
}

13
lnbits/extensions/events/schema.sql

@ -6,15 +6,16 @@ CREATE TABLE IF NOT EXISTS events (
walinvkey INTEGER,
uni TEXT,
tit TEXT,
amt INTEGER,
sold INTEGER,
dat TEXT,
tme TEXT,
price INTEGER
cldate TEXT,
notickets INTEGER,
sold INTEGER DEFAULT 0,
prtick INTEGER
);
CREATE TABLE IF NOT EXISTS eventssold (
key INTEGER PRIMARY KEY AUTOINCREMENT,
uni TEXT,
email TEXT,
name TEXT,
hash TEXT
);
);

182
lnbits/extensions/events/templates/events/index.html

@ -53,8 +53,8 @@
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
Withdraw link maker
<small>powered by LNURL</small>
Events
<small>bitcoin tickets</small>
</h1>
<ol class="breadcrumb">
@ -70,7 +70,14 @@
</ol>
<br /><br />
</section>
<style>
#ui-datepicker-div{
background-color: #1f2234;
padding: 0 10px 10px 10px;
}
</style>
<!-- Main content -->
<section class="content">
<!-- Small boxes (Stat box) -->
@ -80,7 +87,7 @@
<!-- general form elements -->
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"> Make a wave</h3>
<h3 class="box-title"> Make a eve</h3>
</div><!-- /.box-header -->
<!-- form start -->
<form role="form">
@ -104,17 +111,24 @@
<div class="form-group">
<label for="nooftickets">No. of tickets</label>
<input id="notickets" type="number" class="form-control" placeholder="1" max="86400"></input>
<input id="notickets" type="number" class="form-control" placeholder="10" max="86400"></input>
</div>
<div class="form-group">
<label for="nooftickets">Date</label>
<input type="text" class="form-control" data-inputmask="'alias': 'dd/mm/yyyy'" data-mask/>
</div><!-- /.input group -->
<div class="form-group">
<label>Close date:</label>
<div class="input-group date">
<div class="input-group-addon">
<i class="fa fa-calendar"></i>
</div>
<input type="text" class="form-control pull-right" id="datepicker">
</div>
<!-- /.input group -->
</div>
<div class="form-group">
<label for="prpertick">Price per ticket</label>
<input id="prtickets" type="number" class="form-control" placeholder="1"></input>
<input id="prtickets" type="number" class="form-control" placeholder="10"></input>
</div>
@ -122,7 +136,7 @@
<div class="box-footer">
<button onclick="postwave()" type="button" class="btn btn-info">Create wave</button><p style="color:red;" id="error"></p>
<button onclick="postev()" type="button" class="btn btn-info">Create Wave</button><p style="color:red;" id="error"></p>
</div>
</form>
</div><!-- /.box -->
@ -136,7 +150,7 @@
<div class="col-md-6">
<div class="box">
<div class="box-header">
<h3 class="box-title">Ticket waves<b id="withdraws"></b></h3>
<h3 class="box-title">Ticket Waves<b id="withdraws"></b></h3>
</div>
<!-- /.box-header -->
<div class="box-body no-padding">
@ -145,7 +159,7 @@
<th>Title</th>
<th style="width:15%">Amt</th>
<th style="width:15%">Sold</th>
<th style="width:15%">Date</th>
<th style="width:15%">Closing</th>
<th style="width:15%">Price</th>
<th style="width:15%">Wallet</th>
<th style="width:10%">Edit</th>
@ -168,36 +182,46 @@
</section>
<script>
//Date picker
$('#datepicker').datepicker({
autoclose: true
})
window.user = {{ user | megajson | safe }}
window.user_wallets = {{ user_wallets | megajson | safe }}
window.user_ext = {{ user_ext | megajson | safe }}
window.user_wav = {{ user_fau | megajson | safe }}
window.user_ev = {{ user_ev | megajson | safe }}
const user_wav = window.user_wav
console.log(user_wav)
const user_ev = window.user_ev
console.log(user_ev)
function drawChart(user_wav) {
function drawChart(user_ev) {
var transactionsHTML = ''
for (var i = 0; i < user_wav.length; i++) {
var wv = user_wav[i]
for (var i = 0; i < user_ev.length; i++) {
var ev = user_ev[i]
transactionsHTML =
"<tr><td style='width: 50%'>" +
wv.tit +
ev.tit +
'</td><td>' +
wv.nosold +
ev.notickets +
'</td><td>' +
wv.noavail +
ev.sold +
'</td><td>' +
wv.prpertick +
ev.cldate +
'</td><td>' +
"<a href='{{ url_for('wallet') }}?usr="+ user +"'>" + wv.uni.substring(0, 4) + "...</a>" +
ev.prtick +
'</td><td>' +
"<a href='{{ url_for('wallet') }}?usr="+ ev.usr +"'>" + ev.wal.substring(0, 4) + "...</a>" +
'</td><td>' +
"<i onclick='editlink("+ i +")'' class='fa fa-edit'></i>" +
'</td><td>' +
"<b><a style='color:red;' href='" + "{{ url_for('withdraw.index') }}?del=" + wv.uni + "&usr=" + user +"'>" + "<i class='fa fa-trash'></i>" + "</a></b>" +
"<b><a style='color:red;' href='" + "{{ url_for('withdraw.index') }}?del=" + ev.uni + "&usr=" + ev.usr +"'>" + "<i class='fa fa-trash'></i>" + "</a></b>" +
'</td></tr>' +
transactionsHTML
document.getElementById('ticketwaves').innerHTML = transactionsHTML
@ -205,12 +229,17 @@ function drawChart(user_wav) {
}
}
function postwav(){
if (user_ev.length) {
drawChart(user_ev)
}
function postev(){
wal = document.getElementById('wal').value
tit = document.getElementById('tit').value
nooftickets = document.getElementById('nooftickets').value
prtick = document.getElementById('prtick').value
cldate = document.getElementById('datepicker').value
notickets = document.getElementById('notickets').value
prtickets = document.getElementById('prtickets').value
if (tit == "") {
document.getElementById("error").innerHTML = "Only use letters in title"
@ -220,36 +249,40 @@ function postwav(){
document.getElementById("error").innerHTML = "No wallet selected"
return amt
}
if (cldate == "") {
document.getElementById("error").innerHTML = "No date selected"
return amt
}
if (isNaN(notickets) || notickets < 1) {
document.getElementById("error").innerHTML = "Must be more than 1"
return amt
}
if (isNaN(prpertickets) || prpertickets < 10) {
if (isNaN(prtickets) || prtickets < 10) {
document.getElementById("error").innerHTML = "Must be higher 10"
return amt
}
postAjax(
"{{ url_for('wave.create') }}",
JSON.stringify({"tit": tit, "nooftickets": nooftickets, "nooftickets": nooftickets, "prtick": prtick}),
"{{ url_for('events.create') }}",
JSON.stringify({"tit": tit, "usr": user, "wal": wal, "notickets": notickets,"cldate": cldate, "prtickets": prtickets}),
"filla",
function(data) { location.replace("{{ url_for('wav.index') }}?usr=" + user)
function(data) { location.replace("{{ url_for('events.index') }}?usr=" + user)
})
}
function editlink(wavnum){
function editlink(evnum){
wavdetails = user_wav[wavnum]
evdetails = user_ev[evnum]
console.log(wavdetails)
console.log(evdetails)
wallpick = ""
checkbox = ""
if (wavdetails.uniq == 1){
if (evdetails.uniq == 1){
checkbox = "checked"}
document.getElementById('editlink').innerHTML = "<div class='row'>"+
@ -257,7 +290,7 @@ document.getElementById('editlink').innerHTML = "<div class='row'>"+
" <!-- general form elements -->"+
"<div class='box box-primary'>"+
"<div class='box-header'>"+
"<h3 class='box-title'> Edit: <i id='unid'>" + wavdetails.tit + "-" + wavdetails.uni + "</i> </h3>"+
"<h3 class='box-title'> Edit: <i id='unid'>" + evdetails.tit + "-" + evdetails.uni + "</i> </h3>"+
"<div class='box-tools pull-right'>" +
"<button class='btn btn-box-tool' data-widget='remove'><i class='fa fa-times'></i></button>" +
"</div>" +
@ -269,7 +302,7 @@ document.getElementById('editlink').innerHTML = "<div class='row'>"+
"<div class='form-group'>"+
"<label for='exampleInputEmail1'>Link title</label>"+
"<input id='edittit' type='text' class='form-control' value='"+
wavdetails.tit +
evdetails.tit +
"'></input> </div>"+
" </div>"+
" <div class='col-sm-4 col-md-4'>"+
@ -277,7 +310,7 @@ document.getElementById('editlink').innerHTML = "<div class='row'>"+
" <div class='form-group'>"+
" <label>Select a wallet</label>"+
"<select id='editwal' class='form-control'>"+
" <option>" + wavdetails.walnme + "-" + wavdetails.wal + "</option>"+
" <option>" + evdetails.walnme + "-" + evdetails.wal + "</option>"+
" {% for w in user_wallets %}"+
" <option>{{w.name}}-{{w.id}}</option>"+
@ -289,58 +322,48 @@ document.getElementById('editlink').innerHTML = "<div class='row'>"+
" <div class='col-sm-3 col-md-4'>"+
"<div class='form-group'>"+
" <label for='exampleInputPassword1'>No of tickets:</label>"+
" <input id='edittme' type='number' class='form-control' placeholder='0' max='86400' value='"+
wavdetails.notickets +
" <input id='editnooftickets' type='number' class='form-control' placeholder='0' max='86400' value='"+
evdetails.notickets +
"'></input>"+
"</div> </div>"+
" <div class='col-sm-3 col-md-4'>"+
"<div class='form-group'>"+
"<label for='exampleInputEmail1'>Price per ticket:</label>"+
" <input id='editmaxamt' type='number' class='form-control' placeholder='1' value='"+
wavdetails.prperticket +
" <input id='editprtick' type='number' class='form-control' placeholder='1' value='"+
evdetails.prtick +
"'></input>"+
" </div></div>"+
" <div class='col-sm-3 col-md-4'>"+
" <div class='form-group'>"+
" <div class='input-group date'>"+
" <label for='exampleInputEmail1'>Close date:</label>"+
" <input id='editminamt' type='number' class='form-control' placeholder='1' value='"+
wavdetails.minamt +
" <input id='datepicker2' type='text' class='form-control' placeholder='1' value='"+
evdetails.cldate +
"'></input>"+
" </div></div>"+
" <div class='col-sm-3 col-md-4'>"+
"<div class='form-group'>"+
" <label for='exampleInputPassword1'>Amount of uses:</label>"+
" <input id='editamt' type='number' class='form-control' placeholder='1' value='"+
wavdetails.inc +
"'></input>"+
" </div> </div>"+
" <div class='col-sm-3 col-md-4'>"+
" <div class='checkbox'>"+
"<label data-toggle='tooltip' title='Some tooltip text!'><input id='edituniq' type='checkbox' "+
checkbox +
">"+
"Unique links</label>"+
"</div></div><!-- /.box-body -->"+
"</div><!-- /.box-body -->"+
" </div><br/>"+
" <div class='box-footer'>"+
" <button onclick='editlinkcont()' type='button' class='btn btn-info'>Edit link(s)</button><p style='color:red;' id='error2'></p>"+
" <button onclick='editlinkcont()' type='button' style='margin: 24px;' class='btn btn-info'>Edit link(s)</button><p style='color:red;' id='error2'></p>"+
" </div></form></div><!-- /.box --></div></div>"
}
//Date picker
$('#datepicker2').datepicker({
autoclose: true
})
function editlinkcont(){
unid = document.getElementById('unid').innerHTML
wal = document.getElementById('editwal').value
tit = document.getElementById('edittit').value
amt = document.getElementById('editamt').value
maxamt = document.getElementById('editmaxamt').value
minamt = document.getElementById('editminamt').value
tme = document.getElementById('edittme').value
uniq = document.getElementById('edituniq').checked
nooftickets = document.getElementById('editnooftickets').value
prtick = document.getElementById('editprtick').value
cldate = document.getElementById('datepicker2').value
uni = unid.split("-")[1]
if (tit == "") {
document.getElementById("error2").innerHTML = "Only use letters in title"
@ -351,37 +374,28 @@ function editlinkcont(){
return amt
}
if (isNaN(maxamt) || maxamt < 10 || maxamt > 1000000) {
document.getElementById("error2").innerHTML = "Max 10 - 1000000 and must be higher than min"
if (isNaN(nooftickets) || nooftickets < 1 || nooftickets > 1000000) {
document.getElementById("error2").innerHTML = "No. of tickets must be between 1 - 1000000"
return amt
}
if (isNaN(minamt) || minamt < 1 || minamt > 1000000 || minamt > maxamt) {
document.getElementById("error2").innerHTML = "Min 1 - 1000000 and must be lower than max"
return amt
}
if (isNaN(amt) || amt < 1 || amt > 1000) {
document.getElementById("error2").innerHTML = "Amount of uses must be between 1 - 1000"
return amt
}
if (isNaN(tme) || tme < 1 || tme > 86400) {
document.getElementById("error2").innerHTML = "Max waiting time 1 day (86400 secs)"
if (isNaN(prtick) || prtick < 10 ) {
document.getElementById("error2").innerHTML = "Ticket pricket must be higher than 10"
return amt
}
postAjax(
"{{ url_for('withdraw.create') }}",
JSON.stringify({"id": unid, "tit": tit, "amt": amt, "maxamt": maxamt, "minamt": minamt, "tme": tme, "wal": wal, "usr": user, "uniq": uniq}),
"{{ url_for('events.create') }}",
JSON.stringify({"tit": tit, "usr": user, "wal": wal, "notickets": nooftickets,"cldate": cldate, "prtickets": prtick, "id": unid}),
"filla",
function(data) { location.replace("{{ url_for('withdraw.index') }}?usr=" + user)
function(data) { location.replace("{{ url_for('events.index') }}?usr=" + user)
})
}
}
</script>
</div>

92
lnbits/extensions/events/views.py

@ -10,8 +10,98 @@ from lnbits.extensions.events import events_ext
@events_ext.route("/")
def index():
"""Main events link page."""
usr = request.args.get("usr")
if usr:
if not len(usr) > 20:
return redirect(url_for("home"))
# Get all the data
with open_db() as db:
user_wallets = db.fetchall("SELECT * FROM wallets WHERE user = ?", (usr,))
user_ext = db.fetchall("SELECT * FROM extensions WHERE user = ?", (usr,))
user_ext = [v[0] for v in user_ext]
with open_ext_db("events") as events_ext_db:
user_ev = events_ext_db.fetchall("SELECT * FROM events WHERE usr = ?", (usr,))
# If del is selected by user from events page, the event link is to be deleted
evdel = request.args.get("del")
if evdel:
events_ext_db.execute("DELETE FROM events WHERE uni = ?", (evdel,))
user_ev = events_ext_db.fetchall("SELECT * FROM events WHERE usr = ?", (usr,))
print(user_ext)
return render_template(
"events/index.html"
"events/index.html", user_wallets=user_wallets, user=usr, user_ext=user_ext, user_ev=user_ev
)
@events_ext.route("/create", methods=["GET", "POST"])
def create():
"""."""
data = request.json
tit = data["tit"]
wal = data["wal"]
cldate = data["cldate"]
notickets = data["notickets"]
prtick = data["prtickets"]
usr = data["usr"]
wall = wal.split("-")
# Form validation
if (
not tit.replace(" ", "").isalnum()
or wal == ""
or int(notickets) < 0
or int(prtick) < 0
):
return jsonify({"ERROR": "FORM ERROR"}), 401
# If id that means its a link being edited, delete the record first
if "id" in data:
unid = data["id"].split("-")
uni = unid[1]
with open_ext_db("events") as events_ext_db:
events_ext_db.execute("DELETE FROM events WHERE uni = ?", (unid[1],))
else:
uni = uuid.uuid4().hex
with open_db() as dbb:
user_wallets = dbb.fetchall("SELECT * FROM wallets WHERE user = ? AND id = ?", (usr, wall[1],))
if not user_wallets:
return jsonify({"ERROR": "NO WALLET USER"}), 401
with open_db() as db:
user_ext = db.fetchall("SELECT * FROM extensions WHERE user = ?", (usr,))
user_ext = [v[0] for v in user_ext]
# Add to DB
with open_ext_db("events") as events_ext_db:
events_ext_db.execute(
"""
INSERT OR IGNORE INTO events
(usr, wal, walnme, walinvkey, uni, tit, cldate, notickets, prtick)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
usr,
wall[1],
user_wallets[0][1],
user_wallets[0][4],
uni,
tit,
cldate,
notickets,
prtick,
),
)
user_ev = events_ext_db.fetchall("SELECT * FROM events WHERE usr = ?", (usr,))
if not user_ev:
return jsonify({"ERROR": "NO WALLET USER"}), 401
return render_template(
"events/index.html", user_wallets=user_wallets, user=usr, user_ext=user_ext, user_ev=user_ev
)

4
lnbits/extensions/example/README.md

@ -5,5 +5,7 @@ This is an example extension to help you organise and build you own.
Try to include an image
<img src="https://i.imgur.com/9i4xcQB.png">
<h2>If your extension has API endpoints, include any useful ones here</h2>
<h2>If your extension has API endpoints, include useful ones here</h2>
<code>curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/YOUR-EXTENSION/api/v1/EXAMPLE -d '{"amount":"100","memo":"example"}' -H "Grpc-Metadata-macaroon: YOUR_WALLET-ADMIN/INVOICE-KEY"</code>

8
lnbits/extensions/example/__init__.py

@ -0,0 +1,8 @@
from flask import Blueprint
example_ext = Blueprint("example", __name__, static_folder="static", template_folder="templates")
from .views_api import * # noqa
from .views import * # noqa

5
lnbits/extensions/example/example.config.json

@ -0,0 +1,5 @@
{
"name": "SHORT-NAME-FOR-EXTENSIONS-PAGE",
"short_description": "BLah blah blah.",
"ion_icon": "calendar"
}

7
lnbits/extensions/example/schema.sql

@ -0,0 +1,7 @@
/* create your extensions table and the variables needed here */
CREATE TABLE IF NOT EXISTS example (
key INTEGER PRIMARY KEY AUTOINCREMENT,
usr TEXT,
wal TEXT,
walnme TEXT
);

102
lnbits/extensions/example/templates/example/index.html

@ -0,0 +1,102 @@
<!-- @format -->
{% extends "base.html" %} {% block messages %}
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-bell-o"></i>
<span class="label label-danger">!</span>
</a>
<ul class="dropdown-menu">
<li class="header"><b>Instant wallet, bookmark to save</b></li>
<li></li>
</ul>
{% endblock %} {% block menuitems %}
<li class="treeview">
<a href="#">
<i class="fa fa-bitcoin"></i> <span>Wallets</span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
{% for w in user_wallets %}
<li>
<a href="{{ url_for('wallet') }}?wal={{ w.id }}&usr={{ w.user }}"
><i class="fa fa-bolt"></i> {{ w.name }}</a
>
</li>
{% endfor %}
<li><a onclick="sidebarmake()">Add a wallet +</a></li>
<div id="sidebarmake"></div>
</ul>
</li>
<li class="active treeview">
<a href="#">
<i class="fa fa-th"></i> <span>Extensions</span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
{% for extension in EXTENSIONS %}
{% if extension.code in user_ext %}
<li>
<a href="{{ url_for(extension.code + '.index') }}?usr={{ user }}"><i class="fa fa-plus"></i> {{ extension.name }}</a>
</li>
{% endif %}
{% endfor %}
<li>
<a href="{{ url_for('extensions') }}?usr={{ user }}">Manager </a></li>
</ul>
</li>
{% endblock %} {% block body %}
<!-- Right side column. Contains the navbar and content of the page -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
Withdraw link maker
<small>powered by LNURL</small>
</h1>
<ol class="breadcrumb">
<li>
<a href="{{ url_for('wallet') }}?usr={{ user }}"><i class="fa fa-dashboard"></i> Home</a>
</li>
<li>
<a href="{{ url_for('extensions') }}?usr={{ user }}"><li class="fa fa-dashboard">Extensions</li></a>
</li>
<li>
<i class="active" class="fa fa-dashboard">example</i>
</li>
</ol>
<br /><br />
<!-- DOWNLOAD AND SEARCH ADMINLITE2 FOR HTML-->
</section>
<!-- Main content -->
<section class="content">
<!-- Small boxes (Stat box) -->
<div class="row">
<div class="col-md-6">
<!-- general form elements -->
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"> EXAMPLE BOX HEADING</h3>
</div><!-- /.box-header -->
<div class="box-body">
<p>*Some content in here</p>
</div>
</div><!-- /.box -->
</div>
</div>
</section>
<script>
//ADD YOUR JAVASCIPT HERE//
</script>
</div>
{% endblock %}

14
lnbits/extensions/example/views.py

@ -0,0 +1,14 @@
#add your dependencies here
from flask import jsonify, render_template, request, redirect, url_for
from lnbits.db import open_db, open_ext_db
from lnbits.extensions.example import example_ext
#add your endpoints here
@example_ext.route("/")
def index():
"""Try to add descriptions for others."""
return render_template(
"example/index.html"
)

18
lnbits/extensions/example/views_api.py

@ -0,0 +1,18 @@
#views_api.py is for you API endpoints that could be hit by another service
#add your dependencies here
import json
import requests
from flask import jsonify, render_template, request, redirect, url_for
from lnbits.db import open_db, open_ext_db
from lnbits.extensions.example import example_ext
#add your endpoints here
@example_ext.route("/api/v1/example", methods=["GET","POST"])
def api_example():
"""Try to add descriptions for others."""
#YOUR-CODE
return jsonify({"status": "TRUE"}), 200

6
lnbits/extensions/withdraw/README.md

@ -6,3 +6,9 @@ https://github.com/btcontract/lnurl-rfc/blob/master/spec.md#3-lnurl-withdraw
With this extension to can create/edit LNURL withdraws, set a min/max amount, set time (useful for subscription services)
![lnurl](https://i.imgur.com/qHi7ExL.png)
## API endpoint - /withdraw/api/v1/lnurlmaker
Easily fetch one-off LNURLw
curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/withdraw/api/v1/lnurlmaker -d '{"amount":"100","memo":"ATM"}' -H "Grpc-Metadata-macaroon: YOUR-WALLET-ADMIN-KEY"

64
lnbits/extensions/withdraw/views_api.py

@ -6,7 +6,8 @@ from flask import jsonify, request, url_for
from lnurl import LnurlWithdrawResponse, encode as lnurl_encode
from datetime import datetime
from lnbits.db import open_ext_db
from lnbits.db import open_ext_db, open_db
from lnbits.extensions.withdraw import withdraw_ext
@ -117,3 +118,64 @@ def api_lnurlwithdraw(rand):
user_fau = withdraw_ext_db.fetchall("SELECT * FROM withdraws WHERE withdrawals = ?", (k1,))
return jsonify({"status": "OK"}), 200
@withdraw_ext.route("/api/v1/lnurlmaker", methods=["GET","POST"])
def api_lnurlmaker():
if request.headers["Content-Type"] != "application/json":
return jsonify({"ERROR": "MUST BE JSON"}), 400
with open_db() as db:
wallet = db.fetchall(
"SELECT * FROM wallets WHERE adminkey = ?",
(request.headers["Grpc-Metadata-macaroon"],),
)
if not wallet:
return jsonify({"ERROR": "NO KEY"}), 200
balance = db.fetchone("SELECT balance/1000 FROM balances WHERE wallet = ?", (wallet[0][0],))[0]
print(balance)
postedjson = request.json
print(postedjson["amount"])
if balance < int(postedjson["amount"]):
return jsonify({"ERROR": "NOT ENOUGH FUNDS"}), 200
uni = uuid.uuid4().hex
rand = uuid.uuid4().hex[0:5]
with open_ext_db("withdraw") as withdraw_ext_db:
withdraw_ext_db.execute(
"""
INSERT OR IGNORE INTO withdraws
(usr, wal, walnme, adm, uni, tit, maxamt, minamt, spent, inc, tme, uniq, withdrawals, tmestmp, rand)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
wallet[0][2],
wallet[0][0],
wallet[0][1],
wallet[0][3],
uni,
postedjson["memo"],
postedjson["amount"],
postedjson["amount"],
0,
1,
1,
0,
0,
1,
rand,
),
)
user_fau = withdraw_ext_db.fetchone("SELECT * FROM withdraws WHERE uni = ?", (uni,))
if not user_fau:
return jsonify({"ERROR": "WITHDRAW NOT MADE"}), 401
url = url_for("withdraw.api_lnurlfetch", _external=True, urlstr=request.host, parstr=uni, rand=rand)
return jsonify({"status": "TRUE", "lnurl": lnurl_encode(url.replace("http://", "https://"))}), 200

7
lnbits/static/bootstrap/css/datepicker.min.css

File diff suppressed because one or more lines are too long

8
lnbits/static/bootstrap/js/datepicker.min.js

File diff suppressed because one or more lines are too long

13
lnbits/templates/base.html

@ -9,6 +9,13 @@
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
name="viewport"
/>
<!-- Date picker -->
<link
rel="stylesheet"
media="screen"
href="{{ url_for('static', filename='bootstrap/css/bootstrap-datepicker.min.css') }}"
/>
<!-- Bootstrap 3.3.2 -->
<link
rel="stylesheet"
@ -115,6 +122,12 @@
<script>
$.widget.bridge('uibutton', $.ui.button)
</script>
<!-- Datepicker 3.3.2 JS -->
<script
src="{{ url_for('static', filename='bootstrap/js/bootstrap-datepicker.min.js') }}"
type="text/javascript"
></script>
<!-- Bootstrap 3.3.2 JS -->
<script
src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"

Loading…
Cancel
Save