migrate from flask to quart.
also remove all flaskiness from static file serving. and reference all vendored scripts on the base tempĺate for simplicity.
This commit is contained in:
+21
-39
@@ -1,27 +1,28 @@
|
||||
import importlib
|
||||
|
||||
from flask import Flask, g
|
||||
from flask_assets import Bundle # type: ignore
|
||||
from flask_cors import CORS # type: ignore
|
||||
from flask_talisman import Talisman # type: ignore
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
from quart import Quart, g
|
||||
from quart_cors import cors # type: ignore
|
||||
from quart_compress import Compress # type: ignore
|
||||
from secure import SecureHeaders # type: ignore
|
||||
|
||||
from .commands import flask_migrate
|
||||
from .commands import db_migrate
|
||||
from .core import core_app
|
||||
from .db import open_db
|
||||
from .ext import assets, compress
|
||||
from .helpers import get_valid_extensions
|
||||
|
||||
secure_headers = SecureHeaders(hsts=False)
|
||||
|
||||
def create_app(config_object="lnbits.settings") -> Flask:
|
||||
"""Create application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/.
|
||||
|
||||
def create_app(config_object="lnbits.settings") -> Quart:
|
||||
"""Create application factory.
|
||||
:param config_object: The configuration object to use.
|
||||
"""
|
||||
app = Flask(__name__, static_folder="static")
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1) # type: ignore
|
||||
app = Quart(__name__, static_folder="static")
|
||||
app.config.from_object(config_object)
|
||||
|
||||
register_flask_extensions(app)
|
||||
cors(app)
|
||||
Compress(app)
|
||||
|
||||
register_blueprints(app)
|
||||
register_filters(app)
|
||||
register_commands(app)
|
||||
@@ -44,35 +45,11 @@ def register_blueprints(app) -> None:
|
||||
|
||||
def register_commands(app):
|
||||
"""Register Click commands."""
|
||||
app.cli.add_command(flask_migrate)
|
||||
|
||||
|
||||
def register_flask_extensions(app):
|
||||
"""Register Flask extensions."""
|
||||
"""If possible we use the .init_app() option so that Blueprints can also use extensions."""
|
||||
CORS(app)
|
||||
Talisman(
|
||||
app,
|
||||
force_https=app.config["FORCE_HTTPS"],
|
||||
content_security_policy={
|
||||
"default-src": [
|
||||
"'self'",
|
||||
"'unsafe-eval'",
|
||||
"'unsafe-inline'",
|
||||
"blob:",
|
||||
"api.opennode.co",
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
assets.init_app(app)
|
||||
assets.register("base_css", Bundle("scss/base.scss", filters="pyscss", output="css/base.css"))
|
||||
compress.init_app(app)
|
||||
app.cli.add_command(db_migrate)
|
||||
|
||||
|
||||
def register_filters(app):
|
||||
"""Jinja filters."""
|
||||
app.jinja_env.globals["DEBUG"] = app.config["DEBUG"]
|
||||
app.jinja_env.globals["EXTENSIONS"] = get_valid_extensions()
|
||||
app.jinja_env.globals["SITE_TITLE"] = app.config["LNBITS_SITE_TITLE"]
|
||||
|
||||
@@ -81,9 +58,14 @@ def register_request_hooks(app):
|
||||
"""Open the core db for each request so everything happens in a big transaction"""
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
async def before_request():
|
||||
g.db = open_db()
|
||||
|
||||
@app.after_request
|
||||
async def set_secure_headers(response):
|
||||
secure_headers.quart(response)
|
||||
return response
|
||||
|
||||
@app.teardown_request
|
||||
def after_request(exc):
|
||||
async def after_request(exc):
|
||||
g.db.__exit__(type(exc), exc, None)
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ from .helpers import get_valid_extensions
|
||||
|
||||
|
||||
@click.command("migrate")
|
||||
def flask_migrate():
|
||||
def db_migrate():
|
||||
migrate_databases()
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
core_app: Blueprint = Blueprint("core", __name__, template_folder="templates", static_folder="static")
|
||||
core_app: Blueprint = Blueprint(
|
||||
"core", __name__, template_folder="templates", static_folder="static", static_url_path="/core/static"
|
||||
)
|
||||
|
||||
|
||||
from .views.api import * # noqa
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import json
|
||||
import datetime
|
||||
from uuid import uuid4
|
||||
from typing import List, Optional, Dict
|
||||
from flask import g
|
||||
from quart import g
|
||||
|
||||
from lnbits import bolt11
|
||||
from lnbits.settings import DEFAULT_WALLET_NAME
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from typing import Optional, Tuple, Dict
|
||||
from flask import g
|
||||
from quart import g
|
||||
|
||||
try:
|
||||
from typing import TypedDict # type: ignore
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
|
||||
%} {% block scripts %} {{ window_vars(user) }} {% assets filters='rjsmin',
|
||||
output='__bundle__/core/extensions.js', 'core/js/extensions.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% endblock %} {% block page %}
|
||||
%} {% block scripts %} {{ window_vars(user) }}
|
||||
<script src="/static/core/js/extensions.js"></script>
|
||||
{% endblock %} {% block page %}
|
||||
<div class="row q-col-gutter-md">
|
||||
<div
|
||||
class="col-6 col-md-4 col-lg-3"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{% extends "public.html" %} {% block scripts %} {% assets filters='rjsmin',
|
||||
output='__bundle__/core/index.js', 'core/js/index.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% endblock %} {% block page %}
|
||||
{% extends "public.html" %} {% block scripts %}
|
||||
<script src="/core/static/js/index.js"></script>
|
||||
{% endblock %} {% block page %}
|
||||
<div class="row q-col-gutter-md justify-center">
|
||||
<div class="col-12 col-md-7 col-lg-6 q-gutter-y-md">
|
||||
<q-card>
|
||||
|
||||
@@ -1,21 +1,7 @@
|
||||
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
|
||||
%} {% block styles %}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="{{ url_for('static', filename='vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.css') }}"
|
||||
/>
|
||||
{% endblock %} {% block scripts %} {{ window_vars(user, wallet) }}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
{% assets filters='rjsmin', output='__bundle__/core/chart.js',
|
||||
'vendor/moment@2.27.0/moment.min.js', 'vendor/chart.js@2.9.3/chart.min.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% assets filters='rjsmin', output='__bundle__/core/wallet.js',
|
||||
'vendor/bolt11/utils.js', 'vendor/bolt11/decoder.js',
|
||||
'vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.js', 'core/js/wallet.js'
|
||||
%}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% endblock %} {% block page %}
|
||||
%} {% block scripts %} {{ window_vars(user, wallet) }}
|
||||
<script src="/core/static/js/wallet.js"></script>
|
||||
{% endblock %} {% block page %}
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-7 q-gutter-y-md">
|
||||
<q-card>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
from binascii import unhexlify
|
||||
|
||||
@@ -12,7 +12,7 @@ from lnbits.settings import WALLET
|
||||
|
||||
@core_app.route("/api/v1/payments", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_payments():
|
||||
async def api_payments():
|
||||
if "check_pending" in request.args:
|
||||
delete_expired_invoices()
|
||||
|
||||
@@ -33,7 +33,7 @@ def api_payments():
|
||||
"description_hash": {"type": "string", "empty": False, "required": True, "excludes": "memo"},
|
||||
}
|
||||
)
|
||||
def api_payments_create_invoice():
|
||||
async def api_payments_create_invoice():
|
||||
if "description_hash" in g.data:
|
||||
description_hash = unhexlify(g.data["description_hash"])
|
||||
memo = ""
|
||||
@@ -65,7 +65,7 @@ def api_payments_create_invoice():
|
||||
|
||||
@api_check_wallet_key("admin")
|
||||
@api_validate_post_request(schema={"bolt11": {"type": "string", "empty": False, "required": True}})
|
||||
def api_payments_pay_invoice():
|
||||
async def api_payments_pay_invoice():
|
||||
try:
|
||||
payment_hash = pay_invoice(wallet_id=g.wallet.id, payment_request=g.data["bolt11"])
|
||||
except ValueError as e:
|
||||
@@ -91,15 +91,15 @@ def api_payments_pay_invoice():
|
||||
|
||||
@core_app.route("/api/v1/payments", methods=["POST"])
|
||||
@api_validate_post_request(schema={"out": {"type": "boolean", "required": True}})
|
||||
def api_payments_create():
|
||||
async def api_payments_create():
|
||||
if g.data["out"] is True:
|
||||
return api_payments_pay_invoice()
|
||||
return api_payments_create_invoice()
|
||||
return await api_payments_pay_invoice()
|
||||
return await api_payments_create_invoice()
|
||||
|
||||
|
||||
@core_app.route("/api/v1/payments/<payment_hash>", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_payment(payment_hash):
|
||||
async def api_payment(payment_hash):
|
||||
payment = g.wallet.get_payment(payment_hash)
|
||||
|
||||
if not payment:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, redirect, request, render_template, send_from_directory, url_for
|
||||
from quart import g, abort, redirect, request, render_template, send_from_directory, url_for
|
||||
from http import HTTPStatus
|
||||
from os import path
|
||||
|
||||
@@ -16,19 +16,19 @@ from ..crud import (
|
||||
|
||||
|
||||
@core_app.route("/favicon.ico")
|
||||
def favicon():
|
||||
return send_from_directory(path.join(core_app.root_path, "static"), "favicon.ico")
|
||||
async def favicon():
|
||||
return await send_from_directory(path.join(core_app.root_path, "static"), "favicon.ico")
|
||||
|
||||
|
||||
@core_app.route("/")
|
||||
def home():
|
||||
return render_template("core/index.html", lnurl=request.args.get("lightning", None))
|
||||
async def home():
|
||||
return await render_template("core/index.html", lnurl=request.args.get("lightning", None))
|
||||
|
||||
|
||||
@core_app.route("/extensions")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def extensions():
|
||||
async def extensions():
|
||||
extension_to_enable = request.args.get("enable", type=str)
|
||||
extension_to_disable = request.args.get("disable", type=str)
|
||||
|
||||
@@ -40,12 +40,12 @@ def extensions():
|
||||
elif extension_to_disable:
|
||||
update_user_extension(user_id=g.user.id, extension=extension_to_disable, active=0)
|
||||
|
||||
return render_template("core/extensions.html", user=get_user(g.user.id))
|
||||
return await render_template("core/extensions.html", user=get_user(g.user.id))
|
||||
|
||||
|
||||
@core_app.route("/wallet")
|
||||
@validate_uuids(["usr", "wal"])
|
||||
def wallet():
|
||||
async def wallet():
|
||||
user_id = request.args.get("usr", type=str)
|
||||
wallet_id = request.args.get("wal", type=str)
|
||||
wallet_name = request.args.get("nme", type=str)
|
||||
@@ -76,13 +76,15 @@ def wallet():
|
||||
if wallet_id not in user.wallet_ids:
|
||||
abort(HTTPStatus.FORBIDDEN, "Not your wallet.")
|
||||
|
||||
return render_template("core/wallet.html", user=user, wallet=user.get_wallet(wallet_id), service_fee=service_fee)
|
||||
return await render_template(
|
||||
"core/wallet.html", user=user, wallet=user.get_wallet(wallet_id), service_fee=service_fee
|
||||
)
|
||||
|
||||
|
||||
@core_app.route("/deletewallet")
|
||||
@validate_uuids(["usr", "wal"], required=True)
|
||||
@check_user_exists()
|
||||
def deletewallet():
|
||||
async def deletewallet():
|
||||
wallet_id = request.args.get("wal", type=str)
|
||||
user_wallet_ids = g.user.wallet_ids
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import requests
|
||||
|
||||
from flask import abort, redirect, request, url_for
|
||||
from quart import abort, redirect, request, url_for
|
||||
from http import HTTPStatus
|
||||
from lnurl import LnurlWithdrawResponse, handle as handle_lnurl # type: ignore
|
||||
from lnurl.exceptions import LnurlException # type: ignore
|
||||
@@ -13,7 +13,7 @@ from ..crud import create_account, get_user, create_wallet, create_payment
|
||||
|
||||
|
||||
@core_app.route("/lnurlwallet")
|
||||
def lnurlwallet():
|
||||
async def lnurlwallet():
|
||||
memo = "LNbits LNURL funding"
|
||||
|
||||
try:
|
||||
|
||||
+11
-10
@@ -1,5 +1,5 @@
|
||||
from cerberus import Validator # type: ignore
|
||||
from flask import g, abort, jsonify, request
|
||||
from quart import g, abort, jsonify, request
|
||||
from functools import wraps
|
||||
from http import HTTPStatus
|
||||
from typing import List, Union
|
||||
@@ -12,7 +12,7 @@ from lnbits.settings import LNBITS_ALLOWED_USERS
|
||||
def api_check_wallet_key(key_type: str = "invoice"):
|
||||
def wrap(view):
|
||||
@wraps(view)
|
||||
def wrapped_view(**kwargs):
|
||||
async def wrapped_view(**kwargs):
|
||||
try:
|
||||
g.wallet = get_wallet_for_key(request.headers["X-Api-Key"], key_type)
|
||||
except KeyError:
|
||||
@@ -24,7 +24,7 @@ def api_check_wallet_key(key_type: str = "invoice"):
|
||||
if not g.wallet:
|
||||
return jsonify({"message": "Wrong keys."}), HTTPStatus.UNAUTHORIZED
|
||||
|
||||
return view(**kwargs)
|
||||
return await view(**kwargs)
|
||||
|
||||
return wrapped_view
|
||||
|
||||
@@ -34,7 +34,7 @@ def api_check_wallet_key(key_type: str = "invoice"):
|
||||
def api_validate_post_request(*, schema: dict):
|
||||
def wrap(view):
|
||||
@wraps(view)
|
||||
def wrapped_view(**kwargs):
|
||||
async def wrapped_view(**kwargs):
|
||||
if "application/json" not in request.headers["Content-Type"]:
|
||||
return (
|
||||
jsonify({"message": "Content-Type must be `application/json`."}),
|
||||
@@ -42,7 +42,8 @@ def api_validate_post_request(*, schema: dict):
|
||||
)
|
||||
|
||||
v = Validator(schema)
|
||||
g.data = {key: request.json[key] for key in schema.keys() if key in request.json}
|
||||
data = await request.get_json()
|
||||
g.data = {key: data[key] for key in schema.keys() if key in data}
|
||||
|
||||
if not v.validate(g.data):
|
||||
return (
|
||||
@@ -50,7 +51,7 @@ def api_validate_post_request(*, schema: dict):
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
)
|
||||
|
||||
return view(**kwargs)
|
||||
return await view(**kwargs)
|
||||
|
||||
return wrapped_view
|
||||
|
||||
@@ -60,13 +61,13 @@ def api_validate_post_request(*, schema: dict):
|
||||
def check_user_exists(param: str = "usr"):
|
||||
def wrap(view):
|
||||
@wraps(view)
|
||||
def wrapped_view(**kwargs):
|
||||
async def wrapped_view(**kwargs):
|
||||
g.user = get_user(request.args.get(param, type=str)) or abort(HTTPStatus.NOT_FOUND, "User does not exist.")
|
||||
|
||||
if LNBITS_ALLOWED_USERS and g.user.id not in LNBITS_ALLOWED_USERS:
|
||||
abort(HTTPStatus.UNAUTHORIZED, "User not authorized.")
|
||||
|
||||
return view(**kwargs)
|
||||
return await view(**kwargs)
|
||||
|
||||
return wrapped_view
|
||||
|
||||
@@ -76,7 +77,7 @@ def check_user_exists(param: str = "usr"):
|
||||
def validate_uuids(params: List[str], *, required: Union[bool, List[str]] = False, version: int = 4):
|
||||
def wrap(view):
|
||||
@wraps(view)
|
||||
def wrapped_view(**kwargs):
|
||||
async def wrapped_view(**kwargs):
|
||||
query_params = {param: request.args.get(param, type=str) for param in params}
|
||||
|
||||
for param, value in query_params.items():
|
||||
@@ -89,7 +90,7 @@ def validate_uuids(params: List[str], *, required: Union[bool, List[str]] = Fals
|
||||
except ValueError:
|
||||
abort(HTTPStatus.BAD_REQUEST, f"`{param}` is not a valid UUID.")
|
||||
|
||||
return view(**kwargs)
|
||||
return await view(**kwargs)
|
||||
|
||||
return wrapped_view
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
from flask_assets import Environment # type: ignore
|
||||
from flask_compress import Compress # type: ignore
|
||||
|
||||
|
||||
assets = Environment()
|
||||
compress = Compress()
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
amilk_ext: Blueprint = Blueprint("amilk", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, render_template
|
||||
from quart import g, abort, render_template
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
@@ -10,12 +10,11 @@ from .crud import get_amilk
|
||||
@amilk_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("amilk/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("amilk/index.html", user=g.user)
|
||||
|
||||
|
||||
@amilk_ext.route("/<amilk_id>")
|
||||
def wall(amilk_id):
|
||||
async def wall(amilk_id):
|
||||
amilk = get_amilk(amilk_id) or abort(HTTPStatus.NOT_FOUND, "AMilk does not exist.")
|
||||
|
||||
return render_template("amilk/wall.html", amilk=amilk)
|
||||
return await render_template("amilk/wall.html", amilk=amilk)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import requests
|
||||
from flask import g, jsonify, request, abort
|
||||
from quart import g, jsonify, request, abort
|
||||
from http import HTTPStatus
|
||||
from lnurl import LnurlWithdrawResponse, handle as handle_lnurl
|
||||
from lnurl.exceptions import LnurlException
|
||||
@@ -15,7 +15,7 @@ from .crud import create_amilk, get_amilk, get_amilks, delete_amilk
|
||||
|
||||
@amilk_ext.route("/api/v1/amilk", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_amilks():
|
||||
async def api_amilks():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -25,7 +25,7 @@ def api_amilks():
|
||||
|
||||
|
||||
@amilk_ext.route("/api/v1/amilk/milk/<amilk_id>", methods=["GET"])
|
||||
def api_amilkit(amilk_id):
|
||||
async def api_amilkit(amilk_id):
|
||||
milk = get_amilk(amilk_id)
|
||||
memo = milk.id
|
||||
|
||||
@@ -66,7 +66,7 @@ def api_amilkit(amilk_id):
|
||||
"amount": {"type": "integer", "min": 0, "required": True},
|
||||
}
|
||||
)
|
||||
def api_amilk_create():
|
||||
async def api_amilk_create():
|
||||
amilk = create_amilk(wallet_id=g.wallet.id, lnurl=g.data["lnurl"], atime=g.data["atime"], amount=g.data["amount"])
|
||||
|
||||
return jsonify(amilk._asdict()), HTTPStatus.CREATED
|
||||
@@ -74,7 +74,7 @@ def api_amilk_create():
|
||||
|
||||
@amilk_ext.route("/api/v1/amilk/<amilk_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_amilk_delete(amilk_id):
|
||||
async def api_amilk_delete(amilk_id):
|
||||
amilk = get_amilk(amilk_id)
|
||||
|
||||
if not amilk:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
diagonalley_ext: Blueprint = Blueprint("diagonalley", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import json
|
||||
|
||||
from flask import g, abort, render_template, jsonify
|
||||
from quart import g, render_template
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
from lnbits.extensions.diagonalley import diagonalley_ext
|
||||
from lnbits.db import open_ext_db
|
||||
|
||||
|
||||
@diagonalley_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
|
||||
return render_template("diagonalley/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("diagonalley/index.html", user=g.user)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.core.crud import get_user
|
||||
@@ -18,19 +18,19 @@ from .crud import (
|
||||
create_diagonalleys_order,
|
||||
get_diagonalleys_order,
|
||||
get_diagonalleys_orders,
|
||||
delete_diagonalleys_order,
|
||||
update_diagonalleys_product,
|
||||
)
|
||||
from lnbits.core.services import create_invoice
|
||||
from base64 import urlsafe_b64encode
|
||||
from uuid import uuid4
|
||||
from lnbits.db import open_ext_db
|
||||
|
||||
###Products
|
||||
### Products
|
||||
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/products", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalley_products():
|
||||
async def api_diagonalley_products():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -52,7 +52,7 @@ def api_diagonalley_products():
|
||||
"quantity": {"type": "integer", "min": 0, "required": True},
|
||||
}
|
||||
)
|
||||
def api_diagonalley_product_create(product_id=None):
|
||||
async def api_diagonalley_product_create(product_id=None):
|
||||
|
||||
if product_id:
|
||||
product = get_diagonalleys_indexer(product_id)
|
||||
@@ -72,7 +72,7 @@ def api_diagonalley_product_create(product_id=None):
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/products/<product_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalley_products_delete(product_id):
|
||||
async def api_diagonalley_products_delete(product_id):
|
||||
product = get_diagonalleys_product(product_id)
|
||||
|
||||
if not product:
|
||||
@@ -91,7 +91,7 @@ def api_diagonalley_products_delete(product_id):
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/indexers", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalley_indexers():
|
||||
async def api_diagonalley_indexers():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -114,7 +114,7 @@ def api_diagonalley_indexers():
|
||||
"zone2cost": {"type": "integer", "min": 0, "required": True},
|
||||
}
|
||||
)
|
||||
def api_diagonalley_indexer_create(indexer_id=None):
|
||||
async def api_diagonalley_indexer_create(indexer_id=None):
|
||||
|
||||
if indexer_id:
|
||||
indexer = get_diagonalleys_indexer(indexer_id)
|
||||
@@ -134,7 +134,7 @@ def api_diagonalley_indexer_create(indexer_id=None):
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/indexers/<indexer_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalley_indexer_delete(indexer_id):
|
||||
async def api_diagonalley_indexer_delete(indexer_id):
|
||||
indexer = get_diagonalleys_indexer(indexer_id)
|
||||
|
||||
if not indexer:
|
||||
@@ -153,7 +153,7 @@ def api_diagonalley_indexer_delete(indexer_id):
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/orders", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalley_orders():
|
||||
async def api_diagonalley_orders():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -173,14 +173,14 @@ def api_diagonalley_orders():
|
||||
"shippingzone": {"type": "integer", "empty": False, "required": True},
|
||||
}
|
||||
)
|
||||
def api_diagonalley_order_create():
|
||||
async def api_diagonalley_order_create():
|
||||
order = create_diagonalleys_order(wallet_id=g.wallet.id, **g.data)
|
||||
return jsonify(order._asdict()), HTTPStatus.CREATED
|
||||
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/orders/<order_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalley_order_delete(order_id):
|
||||
async def api_diagonalley_order_delete(order_id):
|
||||
order = get_diagonalleys_order(order_id)
|
||||
|
||||
if not order:
|
||||
@@ -196,7 +196,7 @@ def api_diagonalley_order_delete(order_id):
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/orders/paid/<order_id>", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalleys_order_paid(order_id):
|
||||
async def api_diagonalleys_order_paid(order_id):
|
||||
with open_ext_db("diagonalley") as db:
|
||||
db.execute(
|
||||
"UPDATE orders SET paid = ? WHERE id = ?",
|
||||
@@ -210,7 +210,7 @@ def api_diagonalleys_order_paid(order_id):
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/orders/shipped/<order_id>", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_diagonalleys_order_shipped(order_id):
|
||||
async def api_diagonalleys_order_shipped(order_id):
|
||||
with open_ext_db("diagonalley") as db:
|
||||
db.execute(
|
||||
"UPDATE orders SET shipped = ? WHERE id = ?",
|
||||
@@ -228,7 +228,7 @@ def api_diagonalleys_order_shipped(order_id):
|
||||
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/stall/products/<indexer_id>", methods=["GET"])
|
||||
def api_diagonalleys_stall_products(indexer_id):
|
||||
async def api_diagonalleys_stall_products(indexer_id):
|
||||
with open_ext_db("diagonalley") as db:
|
||||
rows = db.fetchone("SELECT * FROM indexers WHERE id = ?", (indexer_id,))
|
||||
print(rows[1])
|
||||
@@ -246,7 +246,7 @@ def api_diagonalleys_stall_products(indexer_id):
|
||||
|
||||
|
||||
@diagonalley_ext.route("/api/v1/diagonalley/stall/checkshipped/<checking_id>", methods=["GET"])
|
||||
def api_diagonalleys_stall_checkshipped(checking_id):
|
||||
async def api_diagonalleys_stall_checkshipped(checking_id):
|
||||
with open_ext_db("diagonalley") as db:
|
||||
rows = db.fetchone("SELECT * FROM orders WHERE invoiceid = ?", (checking_id,))
|
||||
|
||||
@@ -266,7 +266,7 @@ def api_diagonalleys_stall_checkshipped(checking_id):
|
||||
"shippingzone": {"type": "integer", "empty": False, "required": True},
|
||||
}
|
||||
)
|
||||
def api_diagonalley_stall_order(indexer_id):
|
||||
async def api_diagonalley_stall_order(indexer_id):
|
||||
product = get_diagonalleys_product(g.data["id"])
|
||||
shipping = get_diagonalleys_indexer(indexer_id)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
events_ext: Blueprint = Blueprint("events", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
</div>
|
||||
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
console.log('{{ form_costpword }}')
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
@@ -78,24 +78,7 @@
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
{% endblock %} {% block styles %}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="{{ url_for('static', filename='vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.css') }}"
|
||||
/>
|
||||
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
{% assets filters='rjsmin', output='__bundle__/core/chart.js',
|
||||
'vendor/moment@2.27.0/moment.min.js', 'vendor/chart.js@2.9.3/chart.min.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% assets filters='rjsmin', output='__bundle__/core/wallet.js',
|
||||
'vendor/bolt11/utils.js', 'vendor/bolt11/decoder.js',
|
||||
'vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
Vue.use(VueQrcodeReader)
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
new Vue({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, render_template
|
||||
from quart import g, abort, render_template
|
||||
from datetime import date, datetime
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
@@ -11,22 +11,24 @@ from .crud import get_ticket, get_event
|
||||
@events_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("events/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("events/index.html", user=g.user)
|
||||
|
||||
|
||||
@events_ext.route("/<event_id>")
|
||||
def display(event_id):
|
||||
async def display(event_id):
|
||||
event = get_event(event_id) or abort(HTTPStatus.NOT_FOUND, "Event does not exist.")
|
||||
if event.amount_tickets < 1:
|
||||
return render_template("events/error.html", event_name=event.name, event_error="Sorry, tickets are sold out :(")
|
||||
return await render_template(
|
||||
"events/error.html", event_name=event.name, event_error="Sorry, tickets are sold out :("
|
||||
)
|
||||
datetime_object = datetime.strptime(event.closing_date, "%Y-%m-%d").date()
|
||||
if date.today() > datetime_object:
|
||||
return render_template(
|
||||
return await render_template(
|
||||
"events/error.html", event_name=event.name, event_error="Sorry, ticket closing date has passed :("
|
||||
)
|
||||
|
||||
return render_template(
|
||||
return await render_template(
|
||||
"events/display.html",
|
||||
event_id=event_id,
|
||||
event_name=event.name,
|
||||
@@ -36,14 +38,18 @@ def display(event_id):
|
||||
|
||||
|
||||
@events_ext.route("/ticket/<ticket_id>")
|
||||
def ticket(ticket_id):
|
||||
async def ticket(ticket_id):
|
||||
ticket = get_ticket(ticket_id) or abort(HTTPStatus.NOT_FOUND, "Ticket does not exist.")
|
||||
event = get_event(ticket.event) or abort(HTTPStatus.NOT_FOUND, "Event does not exist.")
|
||||
return render_template("events/ticket.html", ticket_id=ticket_id, ticket_name=event.name, ticket_info=event.info)
|
||||
return await render_template(
|
||||
"events/ticket.html", ticket_id=ticket_id, ticket_name=event.name, ticket_info=event.info
|
||||
)
|
||||
|
||||
|
||||
@events_ext.route("/register/<event_id>")
|
||||
def register(event_id):
|
||||
async def register(event_id):
|
||||
event = get_event(event_id) or abort(HTTPStatus.NOT_FOUND, "Event does not exist.")
|
||||
|
||||
return render_template("events/register.html", event_id=event_id, event_name=event.name, wallet_id=event.wallet)
|
||||
return await render_template(
|
||||
"events/register.html", event_id=event_id, event_name=event.name, wallet_id=event.wallet
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.core.crud import get_user, get_wallet
|
||||
@@ -27,7 +27,7 @@ from .crud import (
|
||||
|
||||
@events_ext.route("/api/v1/events", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_events():
|
||||
async def api_events():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -51,7 +51,7 @@ def api_events():
|
||||
"price_per_ticket": {"type": "integer", "min": 0, "required": True},
|
||||
}
|
||||
)
|
||||
def api_event_create(event_id=None):
|
||||
async def api_event_create(event_id=None):
|
||||
if event_id:
|
||||
event = get_event(event_id)
|
||||
print(g.data)
|
||||
@@ -71,7 +71,7 @@ def api_event_create(event_id=None):
|
||||
|
||||
@events_ext.route("/api/v1/events/<event_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_form_delete(event_id):
|
||||
async def api_form_delete(event_id):
|
||||
event = get_event(event_id)
|
||||
|
||||
if not event:
|
||||
@@ -90,7 +90,7 @@ def api_form_delete(event_id):
|
||||
|
||||
@events_ext.route("/api/v1/tickets", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_tickets():
|
||||
async def api_tickets():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -106,7 +106,7 @@ def api_tickets():
|
||||
"email": {"type": "string", "empty": False, "required": True},
|
||||
}
|
||||
)
|
||||
def api_ticket_make_ticket(event_id, sats):
|
||||
async def api_ticket_make_ticket(event_id, sats):
|
||||
event = get_event(event_id)
|
||||
if not event:
|
||||
return jsonify({"message": "Event does not exist."}), HTTPStatus.NOT_FOUND
|
||||
@@ -126,7 +126,7 @@ def api_ticket_make_ticket(event_id, sats):
|
||||
|
||||
|
||||
@events_ext.route("/api/v1/tickets/<payment_hash>", methods=["GET"])
|
||||
def api_ticket_send_ticket(payment_hash):
|
||||
async def api_ticket_send_ticket(payment_hash):
|
||||
ticket = get_ticket(payment_hash)
|
||||
try:
|
||||
is_paid = not check_invoice_status(ticket.wallet, payment_hash).pending
|
||||
@@ -146,7 +146,7 @@ def api_ticket_send_ticket(payment_hash):
|
||||
|
||||
@events_ext.route("/api/v1/tickets/<ticket_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_ticket_delete(ticket_id):
|
||||
async def api_ticket_delete(ticket_id):
|
||||
ticket = get_ticket(ticket_id)
|
||||
|
||||
if not ticket:
|
||||
@@ -164,7 +164,7 @@ def api_ticket_delete(ticket_id):
|
||||
|
||||
|
||||
@events_ext.route("/api/v1/eventtickets/<wallet_id>/<event_id>", methods=["GET"])
|
||||
def api_event_tickets(wallet_id, event_id):
|
||||
async def api_event_tickets(wallet_id, event_id):
|
||||
|
||||
return (
|
||||
jsonify([ticket._asdict() for ticket in get_event_tickets(wallet_id=wallet_id, event_id=event_id)]),
|
||||
@@ -173,7 +173,7 @@ def api_event_tickets(wallet_id, event_id):
|
||||
|
||||
|
||||
@events_ext.route("/api/v1/register/ticket/<ticket_id>", methods=["GET"])
|
||||
def api_event_register_ticket(ticket_id):
|
||||
async def api_event_register_ticket(ticket_id):
|
||||
|
||||
ticket = get_ticket(ticket_id)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
example_ext: Blueprint = Blueprint("example", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, render_template
|
||||
from quart import g, render_template
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
from lnbits.extensions.example import example_ext
|
||||
@@ -7,5 +7,5 @@ from lnbits.extensions.example import example_ext
|
||||
@example_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("example/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("example/index.html", user=g.user)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# import json
|
||||
# import requests
|
||||
|
||||
from flask import jsonify
|
||||
from quart import jsonify
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.extensions.example import example_ext
|
||||
@@ -15,7 +15,7 @@ from lnbits.extensions.example import example_ext
|
||||
|
||||
|
||||
@example_ext.route("/api/v1/tools", methods=["GET"])
|
||||
def api_example():
|
||||
async def api_example():
|
||||
"""Try to add descriptions for others."""
|
||||
tools = [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
lndhub_ext: Blueprint = Blueprint("lndhub", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from base64 import b64decode
|
||||
from flask import jsonify, g, request
|
||||
from quart import jsonify, g, request
|
||||
from functools import wraps
|
||||
|
||||
from lnbits.core.crud import get_wallet_for_key
|
||||
@@ -8,7 +8,7 @@ from lnbits.core.crud import get_wallet_for_key
|
||||
def check_wallet(requires_admin=False):
|
||||
def wrap(view):
|
||||
@wraps(view)
|
||||
def wrapped_view(**kwargs):
|
||||
async def wrapped_view(**kwargs):
|
||||
token = request.headers["Authorization"].split("Bearer ")[1]
|
||||
key_type, key = b64decode(token).decode("utf-8").split(":")
|
||||
|
||||
@@ -18,7 +18,7 @@ def check_wallet(requires_admin=False):
|
||||
g.wallet = get_wallet_for_key(key, key_type)
|
||||
if not g.wallet:
|
||||
return jsonify({"error": True, "code": 2, "message": "insufficient permissions"})
|
||||
return view(**kwargs)
|
||||
return await view(**kwargs)
|
||||
|
||||
return wrapped_view
|
||||
|
||||
|
||||
@@ -67,25 +67,26 @@
|
||||
</div>
|
||||
|
||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
var wallets = ({{ g.user.wallets | tojson }}).map(LNbits.map.wallet).map(wallet => ({
|
||||
label: wallet.name,
|
||||
admin: `lndhub://admin:${wallet.adminkey}@${location.protocol}//${location.host}/lndhub/ext/`,
|
||||
invoice: `lndhub://invoice:${wallet.inkey}@${location.protocol}//${location.host}/lndhub/ext/`
|
||||
}))
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
var wallets = JSON.parse('{{ g.user.wallets | tojson }}')
|
||||
.map(LNbits.map.wallet)
|
||||
.map(wallet => ({
|
||||
label: wallet.name,
|
||||
admin: `lndhub://admin:${wallet.adminkey}@${location.protocol}//${location.host}/lndhub/ext/`,
|
||||
invoice: `lndhub://invoice:${wallet.inkey}@${location.protocol}//${location.host}/lndhub/ext/`
|
||||
}))
|
||||
|
||||
return {
|
||||
wallets: wallets,
|
||||
selectedWallet: wallets[0]
|
||||
}
|
||||
},
|
||||
})
|
||||
return {
|
||||
wallets: wallets,
|
||||
selectedWallet: wallets[0]
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import render_template, g
|
||||
from quart import render_template, g
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
from lnbits.extensions.lndhub import lndhub_ext
|
||||
@@ -7,5 +7,5 @@ from lnbits.extensions.lndhub import lndhub_ext
|
||||
@lndhub_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def lndhub_index():
|
||||
return render_template("lndhub/index.html", user=g.user)
|
||||
async def lndhub_index():
|
||||
return await render_template("lndhub/index.html", user=g.user)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import time
|
||||
from base64 import urlsafe_b64encode
|
||||
from flask import jsonify, g, request
|
||||
from quart import jsonify, g, request
|
||||
|
||||
from lnbits.core.services import pay_invoice, create_invoice
|
||||
from lnbits.core.crud import delete_expired_invoices
|
||||
@@ -14,7 +14,7 @@ from .utils import to_buffer, decoded_as_lndhub
|
||||
|
||||
|
||||
@lndhub_ext.route("/ext/getinfo", methods=["GET"])
|
||||
def lndhub_getinfo():
|
||||
async def lndhub_getinfo():
|
||||
return jsonify({"error": True, "code": 1, "message": "bad auth"})
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ def lndhub_getinfo():
|
||||
"refresh_token": {"type": "string", "required": True, "excludes": ["login", "password"]},
|
||||
}
|
||||
)
|
||||
def lndhub_auth():
|
||||
async def lndhub_auth():
|
||||
token = (
|
||||
g.data["token"]
|
||||
if "token" in g.data and g.data["token"]
|
||||
@@ -44,7 +44,7 @@ def lndhub_auth():
|
||||
"preimage": {"type": "string", "required": False},
|
||||
}
|
||||
)
|
||||
def lndhub_addinvoice():
|
||||
async def lndhub_addinvoice():
|
||||
try:
|
||||
_, pr = create_invoice(
|
||||
wallet_id=g.wallet.id,
|
||||
@@ -76,7 +76,7 @@ def lndhub_addinvoice():
|
||||
@lndhub_ext.route("/ext/payinvoice", methods=["POST"])
|
||||
@check_wallet(requires_admin=True)
|
||||
@api_validate_post_request(schema={"invoice": {"type": "string", "required": True}})
|
||||
def lndhub_payinvoice():
|
||||
async def lndhub_payinvoice():
|
||||
try:
|
||||
pay_invoice(
|
||||
wallet_id=g.wallet.id,
|
||||
@@ -112,13 +112,13 @@ def lndhub_payinvoice():
|
||||
|
||||
@lndhub_ext.route("/ext/balance", methods=["GET"])
|
||||
@check_wallet()
|
||||
def lndhub_balance():
|
||||
async def lndhub_balance():
|
||||
return jsonify({"BTC": {"AvailableBalance": g.wallet.balance}})
|
||||
|
||||
|
||||
@lndhub_ext.route("/ext/gettxs", methods=["GET"])
|
||||
@check_wallet()
|
||||
def lndhub_gettxs():
|
||||
async def lndhub_gettxs():
|
||||
for payment in g.wallet.get_payments(
|
||||
complete=False, pending=True, outgoing=True, incoming=False, exclude_uncheckable=True
|
||||
):
|
||||
@@ -146,7 +146,7 @@ def lndhub_gettxs():
|
||||
|
||||
@lndhub_ext.route("/ext/getuserinvoices", methods=["GET"])
|
||||
@check_wallet()
|
||||
def lndhub_getuserinvoices():
|
||||
async def lndhub_getuserinvoices():
|
||||
delete_expired_invoices()
|
||||
for invoice in g.wallet.get_payments(
|
||||
complete=False, pending=True, outgoing=False, incoming=True, exclude_uncheckable=True
|
||||
@@ -177,26 +177,26 @@ def lndhub_getuserinvoices():
|
||||
|
||||
@lndhub_ext.route("/ext/getbtc", methods=["GET"])
|
||||
@check_wallet()
|
||||
def lndhub_getbtc():
|
||||
async def lndhub_getbtc():
|
||||
"load an address for incoming onchain btc"
|
||||
return jsonify([])
|
||||
|
||||
|
||||
@lndhub_ext.route("/ext/getpending", methods=["GET"])
|
||||
@check_wallet()
|
||||
def lndhub_getpending():
|
||||
async def lndhub_getpending():
|
||||
"pending onchain transactions"
|
||||
return jsonify([])
|
||||
|
||||
|
||||
@lndhub_ext.route("/ext/decodeinvoice", methods=["GET"])
|
||||
def lndhub_decodeinvoice():
|
||||
async def lndhub_decodeinvoice():
|
||||
invoice = request.args.get("invoice")
|
||||
inv = bolt11.decode(invoice)
|
||||
return jsonify(decoded_as_lndhub(inv))
|
||||
|
||||
|
||||
@lndhub_ext.route("/ext/checkrouteinvoice", methods=["GET"])
|
||||
def lndhub_checkrouteinvoice():
|
||||
async def lndhub_checkrouteinvoice():
|
||||
"not implemented on canonical lndhub"
|
||||
pass
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
lnticket_ext: Blueprint = Blueprint("lnticket", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
</div>
|
||||
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
console.log('{{ form_costpword }}')
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, render_template
|
||||
from quart import g, abort, render_template
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
from http import HTTPStatus
|
||||
@@ -10,16 +10,16 @@ from .crud import get_form
|
||||
@lnticket_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("lnticket/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("lnticket/index.html", user=g.user)
|
||||
|
||||
|
||||
@lnticket_ext.route("/<form_id>")
|
||||
def display(form_id):
|
||||
async def display(form_id):
|
||||
form = get_form(form_id) or abort(HTTPStatus.NOT_FOUND, "LNTicket does not exist.")
|
||||
print(form.id)
|
||||
|
||||
return render_template(
|
||||
return await render_template(
|
||||
"lnticket/display.html",
|
||||
form_id=form.id,
|
||||
form_name=form.name,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.core.crud import get_user, get_wallet
|
||||
@@ -26,7 +26,7 @@ from .crud import (
|
||||
|
||||
@lnticket_ext.route("/api/v1/forms", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_forms():
|
||||
async def api_forms():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -46,7 +46,7 @@ def api_forms():
|
||||
"costpword": {"type": "integer", "min": 0, "required": True},
|
||||
}
|
||||
)
|
||||
def api_form_create(form_id=None):
|
||||
async def api_form_create(form_id=None):
|
||||
if form_id:
|
||||
form = get_form(form_id)
|
||||
|
||||
@@ -64,7 +64,7 @@ def api_form_create(form_id=None):
|
||||
|
||||
@lnticket_ext.route("/api/v1/forms/<form_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_form_delete(form_id):
|
||||
async def api_form_delete(form_id):
|
||||
form = get_form(form_id)
|
||||
|
||||
if not form:
|
||||
@@ -83,7 +83,7 @@ def api_form_delete(form_id):
|
||||
|
||||
@lnticket_ext.route("/api/v1/tickets", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_tickets():
|
||||
async def api_tickets():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -101,7 +101,7 @@ def api_tickets():
|
||||
"ltext": {"type": "string", "empty": False, "required": True},
|
||||
}
|
||||
)
|
||||
def api_ticket_make_ticket(form_id):
|
||||
async def api_ticket_make_ticket(form_id):
|
||||
form = get_form(form_id)
|
||||
if not form:
|
||||
return jsonify({"message": "LNTicket does not exist."}), HTTPStatus.NOT_FOUND
|
||||
@@ -126,7 +126,7 @@ def api_ticket_make_ticket(form_id):
|
||||
|
||||
|
||||
@lnticket_ext.route("/api/v1/tickets/<payment_hash>", methods=["GET"])
|
||||
def api_ticket_send_ticket(payment_hash):
|
||||
async def api_ticket_send_ticket(payment_hash):
|
||||
ticket = get_ticket(payment_hash)
|
||||
try:
|
||||
is_paid = not check_invoice_status(ticket.wallet, payment_hash).pending
|
||||
@@ -145,7 +145,7 @@ def api_ticket_send_ticket(payment_hash):
|
||||
|
||||
@lnticket_ext.route("/api/v1/tickets/<ticket_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_ticket_delete(ticket_id):
|
||||
async def api_ticket_delete(ticket_id):
|
||||
ticket = get_ticket(ticket_id)
|
||||
|
||||
if not ticket:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
lnurlp_ext: Blueprint = Blueprint("lnurlp", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import json
|
||||
from flask import url_for
|
||||
from quart import url_for
|
||||
from lnurl import Lnurl, encode as lnurl_encode
|
||||
from lnurl.types import LnurlPayMetadata
|
||||
from sqlite3 import Row
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
|
||||
@@ -205,7 +205,6 @@
|
||||
</q-dialog>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
}
|
||||
</style>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, render_template
|
||||
from quart import g, abort, render_template
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
@@ -10,19 +10,17 @@ from .crud import get_pay_link
|
||||
@lnurlp_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("lnurlp/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("lnurlp/index.html", user=g.user)
|
||||
|
||||
|
||||
@lnurlp_ext.route("/<link_id>")
|
||||
def display(link_id):
|
||||
async def display(link_id):
|
||||
link = get_pay_link(link_id) or abort(HTTPStatus.NOT_FOUND, "Pay link does not exist.")
|
||||
|
||||
return render_template("lnurlp/display.html", link=link)
|
||||
return await render_template("lnurlp/display.html", link=link)
|
||||
|
||||
|
||||
@lnurlp_ext.route("/print/<link_id>")
|
||||
def print_qr(link_id):
|
||||
async def print_qr(link_id):
|
||||
link = get_pay_link(link_id) or abort(HTTPStatus.NOT_FOUND, "Pay link does not exist.")
|
||||
|
||||
return render_template("lnurlp/print_qr.html", link=link)
|
||||
return await render_template("lnurlp/print_qr.html", link=link)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import hashlib
|
||||
from flask import g, jsonify, request, url_for
|
||||
from quart import g, jsonify, request, url_for
|
||||
from http import HTTPStatus
|
||||
from lnurl import LnurlPayResponse, LnurlPayActionResponse
|
||||
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl
|
||||
@@ -22,7 +22,7 @@ from .crud import (
|
||||
|
||||
@lnurlp_ext.route("/api/v1/links", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_links():
|
||||
async def api_links():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -42,7 +42,7 @@ def api_links():
|
||||
|
||||
@lnurlp_ext.route("/api/v1/links/<link_id>", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_link_retrieve(link_id):
|
||||
async def api_link_retrieve(link_id):
|
||||
link = get_pay_link(link_id)
|
||||
|
||||
if not link:
|
||||
@@ -63,7 +63,7 @@ def api_link_retrieve(link_id):
|
||||
"amount": {"type": "integer", "min": 1, "required": True},
|
||||
}
|
||||
)
|
||||
def api_link_create_or_update(link_id=None):
|
||||
async def api_link_create_or_update(link_id=None):
|
||||
if link_id:
|
||||
link = get_pay_link(link_id)
|
||||
|
||||
@@ -82,7 +82,7 @@ def api_link_create_or_update(link_id=None):
|
||||
|
||||
@lnurlp_ext.route("/api/v1/links/<link_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_link_delete(link_id):
|
||||
async def api_link_delete(link_id):
|
||||
link = get_pay_link(link_id)
|
||||
|
||||
if not link:
|
||||
@@ -97,7 +97,7 @@ def api_link_delete(link_id):
|
||||
|
||||
|
||||
@lnurlp_ext.route("/api/v1/lnurl/<link_id>", methods=["GET"])
|
||||
def api_lnurl_response(link_id):
|
||||
async def api_lnurl_response(link_id):
|
||||
link = increment_pay_link(link_id, served_meta=1)
|
||||
if not link:
|
||||
return jsonify({"status": "ERROR", "reason": "LNURL-pay not found."}), HTTPStatus.OK
|
||||
@@ -116,7 +116,7 @@ def api_lnurl_response(link_id):
|
||||
|
||||
|
||||
@lnurlp_ext.route("/api/v1/lnurl/cb/<link_id>", methods=["GET"])
|
||||
def api_lnurl_callback(link_id):
|
||||
async def api_lnurl_callback(link_id):
|
||||
link = increment_pay_link(link_id, served_pr=1)
|
||||
if not link:
|
||||
return jsonify({"status": "ERROR", "reason": "LNURL-pay not found."}), HTTPStatus.OK
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
paywall_ext: Blueprint = Blueprint("paywall", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, render_template
|
||||
from quart import g, abort, render_template
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
@@ -10,12 +10,11 @@ from .crud import get_paywall
|
||||
@paywall_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("paywall/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("paywall/index.html", user=g.user)
|
||||
|
||||
|
||||
@paywall_ext.route("/<paywall_id>")
|
||||
def display(paywall_id):
|
||||
async def display(paywall_id):
|
||||
paywall = get_paywall(paywall_id) or abort(HTTPStatus.NOT_FOUND, "Paywall does not exist.")
|
||||
|
||||
return render_template("paywall/display.html", paywall=paywall)
|
||||
return await render_template("paywall/display.html", paywall=paywall)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.core.crud import get_user, get_wallet
|
||||
@@ -11,7 +11,7 @@ from .crud import create_paywall, get_paywall, get_paywalls, delete_paywall
|
||||
|
||||
@paywall_ext.route("/api/v1/paywalls", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_paywalls():
|
||||
async def api_paywalls():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -31,7 +31,7 @@ def api_paywalls():
|
||||
"remembers": {"type": "boolean", "required": True},
|
||||
}
|
||||
)
|
||||
def api_paywall_create():
|
||||
async def api_paywall_create():
|
||||
paywall = create_paywall(wallet_id=g.wallet.id, **g.data)
|
||||
|
||||
return jsonify(paywall._asdict()), HTTPStatus.CREATED
|
||||
@@ -39,7 +39,7 @@ def api_paywall_create():
|
||||
|
||||
@paywall_ext.route("/api/v1/paywalls/<paywall_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_paywall_delete(paywall_id):
|
||||
async def api_paywall_delete(paywall_id):
|
||||
paywall = get_paywall(paywall_id)
|
||||
|
||||
if not paywall:
|
||||
@@ -55,7 +55,7 @@ def api_paywall_delete(paywall_id):
|
||||
|
||||
@paywall_ext.route("/api/v1/paywalls/<paywall_id>/invoice", methods=["POST"])
|
||||
@api_validate_post_request(schema={"amount": {"type": "integer", "min": 1, "required": True}})
|
||||
def api_paywall_create_invoice(paywall_id):
|
||||
async def api_paywall_create_invoice(paywall_id):
|
||||
paywall = get_paywall(paywall_id)
|
||||
|
||||
if g.data["amount"] < paywall.amount:
|
||||
@@ -74,7 +74,7 @@ def api_paywall_create_invoice(paywall_id):
|
||||
|
||||
@paywall_ext.route("/api/v1/paywalls/<paywall_id>/check_invoice", methods=["POST"])
|
||||
@api_validate_post_request(schema={"payment_hash": {"type": "string", "empty": False, "required": True}})
|
||||
def api_paywal_check_invoice(paywall_id):
|
||||
async def api_paywal_check_invoice(paywall_id):
|
||||
paywall = get_paywall(paywall_id)
|
||||
|
||||
if not paywall:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
tpos_ext: Blueprint = Blueprint("tpos", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -152,7 +152,6 @@
|
||||
}
|
||||
</style>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, render_template
|
||||
from quart import g, abort, render_template
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
@@ -10,12 +10,12 @@ from .crud import get_tpos
|
||||
@tpos_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("tpos/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("tpos/index.html", user=g.user)
|
||||
|
||||
|
||||
@tpos_ext.route("/<tpos_id>")
|
||||
def tpos(tpos_id):
|
||||
async def tpos(tpos_id):
|
||||
tpos = get_tpos(tpos_id) or abort(HTTPStatus.NOT_FOUND, "TPoS does not exist.")
|
||||
|
||||
return render_template("tpos/tpos.html", tpos=tpos)
|
||||
return await render_template("tpos/tpos.html", tpos=tpos)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.core.crud import get_user, get_wallet
|
||||
@@ -11,7 +11,7 @@ from .crud import create_tpos, get_tpos, get_tposs, delete_tpos
|
||||
|
||||
@tpos_ext.route("/api/v1/tposs", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_tposs():
|
||||
async def api_tposs():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -28,7 +28,7 @@ def api_tposs():
|
||||
"currency": {"type": "string", "empty": False, "required": True},
|
||||
}
|
||||
)
|
||||
def api_tpos_create():
|
||||
async def api_tpos_create():
|
||||
tpos = create_tpos(wallet_id=g.wallet.id, **g.data)
|
||||
|
||||
return jsonify(tpos._asdict()), HTTPStatus.CREATED
|
||||
@@ -36,7 +36,7 @@ def api_tpos_create():
|
||||
|
||||
@tpos_ext.route("/api/v1/tposs/<tpos_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("admin")
|
||||
def api_tpos_delete(tpos_id):
|
||||
async def api_tpos_delete(tpos_id):
|
||||
tpos = get_tpos(tpos_id)
|
||||
|
||||
if not tpos:
|
||||
@@ -52,7 +52,7 @@ def api_tpos_delete(tpos_id):
|
||||
|
||||
@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):
|
||||
async def api_tpos_create_invoice(tpos_id):
|
||||
tpos = get_tpos(tpos_id)
|
||||
|
||||
if not tpos:
|
||||
@@ -69,7 +69,7 @@ def api_tpos_create_invoice(tpos_id):
|
||||
|
||||
|
||||
@tpos_ext.route("/api/v1/tposs/<tpos_id>/invoices/<payment_hash>", methods=["GET"])
|
||||
def api_tpos_check_invoice(tpos_id, payment_hash):
|
||||
async def api_tpos_check_invoice(tpos_id, payment_hash):
|
||||
tpos = get_tpos(tpos_id)
|
||||
|
||||
if not tpos:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
usermanager_ext: Blueprint = Blueprint("usermanager", __name__, static_folder="static", template_folder="templates")
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
from flask import g, abort, render_template, jsonify
|
||||
import json
|
||||
from quart import g, render_template
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
from lnbits.extensions.usermanager import usermanager_ext
|
||||
from lnbits.db import open_ext_db
|
||||
|
||||
|
||||
@usermanager_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
|
||||
return render_template("usermanager/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("usermanager/index.html", user=g.user)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.core.crud import get_user
|
||||
@@ -17,20 +17,15 @@ from .crud import (
|
||||
get_usermanager_wallets,
|
||||
delete_usermanager_wallet,
|
||||
)
|
||||
from lnbits.core.services import create_invoice
|
||||
from base64 import urlsafe_b64encode
|
||||
from uuid import uuid4
|
||||
from lnbits.db import open_ext_db
|
||||
|
||||
from ...core import update_user_extension
|
||||
from lnbits.core import update_user_extension
|
||||
|
||||
|
||||
###Users
|
||||
### Users
|
||||
|
||||
|
||||
@usermanager_ext.route("/api/v1/users", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_usermanager_users():
|
||||
async def api_usermanager_users():
|
||||
user_id = g.wallet.user
|
||||
return jsonify([user._asdict() for user in get_usermanager_users(user_id)]), HTTPStatus.OK
|
||||
|
||||
@@ -44,14 +39,14 @@ def api_usermanager_users():
|
||||
"wallet_name": {"type": "string", "empty": False, "required": True},
|
||||
}
|
||||
)
|
||||
def api_usermanager_users_create():
|
||||
async def api_usermanager_users_create():
|
||||
user = create_usermanager_user(g.data["user_name"], g.data["wallet_name"], g.data["admin_id"])
|
||||
return jsonify(user._asdict()), HTTPStatus.CREATED
|
||||
|
||||
|
||||
@usermanager_ext.route("/api/v1/users/<user_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_usermanager_users_delete(user_id):
|
||||
async def api_usermanager_users_delete(user_id):
|
||||
user = get_usermanager_user(user_id)
|
||||
if not user:
|
||||
return jsonify({"message": "User does not exist."}), HTTPStatus.NOT_FOUND
|
||||
@@ -71,7 +66,7 @@ def api_usermanager_users_delete(user_id):
|
||||
"active": {"type": "boolean", "required": True},
|
||||
}
|
||||
)
|
||||
def api_usermanager_activate_extension():
|
||||
async def api_usermanager_activate_extension():
|
||||
user = get_user(g.data["userid"])
|
||||
if not user:
|
||||
return jsonify({"error": "no such user"}), HTTPStatus.NO_CONTENT
|
||||
@@ -84,7 +79,7 @@ def api_usermanager_activate_extension():
|
||||
|
||||
@usermanager_ext.route("/api/v1/wallets", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_usermanager_wallets():
|
||||
async def api_usermanager_wallets():
|
||||
user_id = g.wallet.user
|
||||
return jsonify([wallet._asdict() for wallet in get_usermanager_wallets(user_id)]), HTTPStatus.OK
|
||||
|
||||
@@ -98,27 +93,27 @@ def api_usermanager_wallets():
|
||||
"admin_id": {"type": "string", "empty": False, "required": True},
|
||||
}
|
||||
)
|
||||
def api_usermanager_wallets_create():
|
||||
async def api_usermanager_wallets_create():
|
||||
user = create_usermanager_wallet(g.data["user_id"], g.data["wallet_name"], g.data["admin_id"])
|
||||
return jsonify(user._asdict()), HTTPStatus.CREATED
|
||||
|
||||
|
||||
@usermanager_ext.route("/api/v1/wallets<wallet_id>", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_usermanager_wallet_transactions(wallet_id):
|
||||
async def api_usermanager_wallet_transactions(wallet_id):
|
||||
|
||||
return jsonify(get_usermanager_wallet_transactions(wallet_id)), HTTPStatus.OK
|
||||
|
||||
|
||||
@usermanager_ext.route("/api/v1/wallets/<user_id>", methods=["GET"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_usermanager_wallet_balances(user_id):
|
||||
async def api_usermanager_wallet_balances(user_id):
|
||||
return jsonify(get_usermanager_wallet_balances(user_id)), HTTPStatus.OK
|
||||
|
||||
|
||||
@usermanager_ext.route("/api/v1/wallets/<wallet_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key(key_type="invoice")
|
||||
def api_usermanager_wallets_delete(wallet_id):
|
||||
async def api_usermanager_wallets_delete(wallet_id):
|
||||
wallet = get_usermanager_wallet(wallet_id)
|
||||
print(wallet.id)
|
||||
if not wallet:
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from flask import Blueprint
|
||||
from quart import Blueprint
|
||||
|
||||
|
||||
withdraw_ext: Blueprint = Blueprint("withdraw", __name__, static_folder="static", template_folder="templates")
|
||||
withdraw_ext: Blueprint = Blueprint(
|
||||
"withdraw", __name__, static_folder="static", template_folder="templates", static_url_path="/static"
|
||||
)
|
||||
|
||||
|
||||
from .views_api import * # noqa
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import url_for
|
||||
from quart import url_for
|
||||
from lnurl import Lnurl, LnurlWithdrawResponse, encode as lnurl_encode
|
||||
from sqlite3 import Row
|
||||
from typing import NamedTuple
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %}
|
||||
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
|
||||
%} {% block scripts %} {{ window_vars(user) }}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
{% assets filters='rjsmin', output='__bundle__/withdraw/index.js',
|
||||
'withdraw/js/index.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% endblock %} {% block page %}
|
||||
<script type="text/javascript" src="/withdraw/static/js/index.js"></script>
|
||||
{% endblock %} {% block page %}
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-7 q-gutter-y-md">
|
||||
<q-card>
|
||||
@@ -273,7 +270,7 @@
|
||||
color="deep-purple"
|
||||
:disable="
|
||||
simpleformDialog.data.wallet == null ||
|
||||
|
||||
|
||||
simpleformDialog.data.max_withdrawable == null ||
|
||||
simpleformDialog.data.max_withdrawable < 1 ||
|
||||
simpleformDialog.data.uses == null"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
{% block page %}
|
||||
{% extends "print.html" %} {% block page %}
|
||||
|
||||
<div class="row justify-center">
|
||||
<div class="col-12 col-sm-8 col-lg-6 text-center" id="vue">
|
||||
@@ -50,15 +49,6 @@
|
||||
}
|
||||
</style>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue@2.6.12/vue.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='vendor/vuex@3.5.1/vuex.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='vendor/vue-router@3.4.3/vue-router.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='vendor/quasar@1.13.2/quasar.umd.js') }}"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/static/__bundle__/base.js?a52a989e"
|
||||
></script>
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import g, abort, render_template
|
||||
from quart import g, abort, render_template
|
||||
from http import HTTPStatus
|
||||
|
||||
from lnbits.decorators import check_user_exists, validate_uuids
|
||||
@@ -10,21 +10,21 @@ from .crud import get_withdraw_link, chunks
|
||||
@withdraw_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
def index():
|
||||
return render_template("withdraw/index.html", user=g.user)
|
||||
async def index():
|
||||
return await render_template("withdraw/index.html", user=g.user)
|
||||
|
||||
|
||||
@withdraw_ext.route("/<link_id>")
|
||||
def display(link_id):
|
||||
async def display(link_id):
|
||||
link = get_withdraw_link(link_id, 0) or abort(HTTPStatus.NOT_FOUND, "Withdraw link does not exist.")
|
||||
return render_template("withdraw/display.html", link=link, unique=True)
|
||||
return await render_template("withdraw/display.html", link=link, unique=True)
|
||||
|
||||
|
||||
@withdraw_ext.route("/print/<link_id>")
|
||||
def print_qr(link_id):
|
||||
async def print_qr(link_id):
|
||||
link = get_withdraw_link(link_id) or abort(HTTPStatus.NOT_FOUND, "Withdraw link does not exist.")
|
||||
if link.uses == 0:
|
||||
return render_template("withdraw/print_qr.html", link=link, unique=False)
|
||||
return await render_template("withdraw/print_qr.html", link=link, unique=False)
|
||||
links = []
|
||||
count = 0
|
||||
for x in link.usescsv.split(","):
|
||||
@@ -33,4 +33,4 @@ def print_qr(link_id):
|
||||
count = count + 1
|
||||
page_link = list(chunks(links, 2))
|
||||
linked = list(chunks(page_link, 5))
|
||||
return render_template("withdraw/print_qr.html", link=linked, unique=True)
|
||||
return await render_template("withdraw/print_qr.html", link=linked, unique=True)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
from flask import g, jsonify, request
|
||||
from quart import g, jsonify, request
|
||||
from http import HTTPStatus
|
||||
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl
|
||||
import shortuuid # type: ignore
|
||||
@@ -21,7 +21,7 @@ from .crud import (
|
||||
|
||||
@withdraw_ext.route("/api/v1/links", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_links():
|
||||
async def api_links():
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
if "all_wallets" in request.args:
|
||||
@@ -40,7 +40,7 @@ def api_links():
|
||||
|
||||
@withdraw_ext.route("/api/v1/links/<link_id>", methods=["GET"])
|
||||
@api_check_wallet_key("invoice")
|
||||
def api_link_retrieve(link_id):
|
||||
async def api_link_retrieve(link_id):
|
||||
link = get_withdraw_link(link_id, 0)
|
||||
|
||||
if not link:
|
||||
@@ -65,7 +65,7 @@ def api_link_retrieve(link_id):
|
||||
"is_unique": {"type": "boolean", "required": True},
|
||||
}
|
||||
)
|
||||
def api_link_create_or_update(link_id=None):
|
||||
async def api_link_create_or_update(link_id=None):
|
||||
if g.data["max_withdrawable"] < g.data["min_withdrawable"]:
|
||||
return (
|
||||
jsonify({"message": "`max_withdrawable` needs to be at least `min_withdrawable`."}),
|
||||
@@ -95,7 +95,7 @@ def api_link_create_or_update(link_id=None):
|
||||
|
||||
@withdraw_ext.route("/api/v1/links/<link_id>", methods=["DELETE"])
|
||||
@api_check_wallet_key("admin")
|
||||
def api_link_delete(link_id):
|
||||
async def api_link_delete(link_id):
|
||||
link = get_withdraw_link(link_id)
|
||||
|
||||
if not link:
|
||||
@@ -113,7 +113,7 @@ def api_link_delete(link_id):
|
||||
|
||||
|
||||
@withdraw_ext.route("/api/v1/lnurl/<unique_hash>", methods=["GET"])
|
||||
def api_lnurl_response(unique_hash):
|
||||
async def api_lnurl_response(unique_hash):
|
||||
link = get_withdraw_link_by_hash(unique_hash)
|
||||
|
||||
if not link:
|
||||
@@ -134,7 +134,7 @@ def api_lnurl_response(unique_hash):
|
||||
|
||||
|
||||
@withdraw_ext.route("/api/v1/lnurl/<unique_hash>/<id_unique_hash>", methods=["GET"])
|
||||
def api_lnurl_multi_response(unique_hash, id_unique_hash):
|
||||
async def api_lnurl_multi_response(unique_hash, id_unique_hash):
|
||||
link = get_withdraw_link_by_hash(unique_hash)
|
||||
|
||||
if not link:
|
||||
@@ -163,7 +163,7 @@ def api_lnurl_multi_response(unique_hash, id_unique_hash):
|
||||
|
||||
|
||||
@withdraw_ext.route("/api/v1/lnurl/cb/<unique_hash>", methods=["GET"])
|
||||
def api_lnurl_callback(unique_hash):
|
||||
async def api_lnurl_callback(unique_hash):
|
||||
link = get_withdraw_link_by_hash(unique_hash)
|
||||
k1 = request.args.get("k1", type=str)
|
||||
payment_request = request.args.get("pr", type=str)
|
||||
|
||||
@@ -11,9 +11,6 @@ env.read_env()
|
||||
wallets_module = importlib.import_module("lnbits.wallets")
|
||||
wallet_class = getattr(wallets_module, env.str("LNBITS_BACKEND_WALLET_CLASS", default="VoidWallet"))
|
||||
|
||||
ENV = env.str("FLASK_ENV", default="production")
|
||||
DEBUG = ENV == "development"
|
||||
|
||||
LNBITS_PATH = path.dirname(path.realpath(__file__))
|
||||
LNBITS_DATA_FOLDER = env.str("LNBITS_DATA_FOLDER", default=path.join(LNBITS_PATH, "data"))
|
||||
LNBITS_ALLOWED_USERS: List[str] = env.list("LNBITS_ALLOWED_USERS", default=[], subcast=str)
|
||||
|
||||
@@ -1,77 +1 @@
|
||||
[v-cloak] {
|
||||
display: none; }
|
||||
|
||||
.bg-lnbits-dark {
|
||||
background-color: #1f2234; }
|
||||
|
||||
body.body--dark, body.body--dark .q-drawer--dark, body.body--dark .q-menu--dark {
|
||||
background: #1f2234; }
|
||||
|
||||
body.body--dark .q-card--dark {
|
||||
background: #333646; }
|
||||
|
||||
body.body--dark .q-table--dark {
|
||||
background: transparent; }
|
||||
|
||||
body.body--light, body.body--light .q-drawer {
|
||||
background: whitesmoke; }
|
||||
|
||||
body.body--dark .q-field--error .text-negative,
|
||||
body.body--dark .q-field--error .q-field__messages {
|
||||
color: yellow !important; }
|
||||
|
||||
.lnbits-drawer__q-list .q-item {
|
||||
padding-top: 5px !important;
|
||||
padding-bottom: 5px !important;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px; }
|
||||
.lnbits-drawer__q-list .q-item.q-item--active {
|
||||
color: inherit;
|
||||
font-weight: bold; }
|
||||
|
||||
.lnbits__dialog-card {
|
||||
width: 500px; }
|
||||
|
||||
.q-table--dense th:first-child, .q-table--dense td:first-child,
|
||||
.q-table--dense .q-table__bottom {
|
||||
padding-left: 6px !important; }
|
||||
.q-table--dense th:last-child, .q-table--dense td:last-child,
|
||||
.q-table--dense .q-table__bottom {
|
||||
padding-right: 6px !important; }
|
||||
|
||||
a.inherit {
|
||||
color: inherit;
|
||||
text-decoration: none; }
|
||||
|
||||
video {
|
||||
border-radius: 3px; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(../fonts/material-icons-v50.woff2) format('woff2'); }
|
||||
|
||||
.material-icons {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-moz-font-feature-settings: 'liga';
|
||||
-moz-osx-font-smoothing: grayscale; }
|
||||
|
||||
.text-wrap {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: monospace;
|
||||
}
|
||||
[v-cloak]{display:none}.bg-lnbits-dark{background-color:#1f2234}body.body--dark,body.body--dark .q-drawer--dark,body.body--dark .q-menu--dark{background:#1f2234}body.body--dark .q-card--dark{background:#333646}body.body--dark .q-table--dark{background:transparent}body.body--light,body.body--light .q-drawer{background:#f5f5f5}body.body--dark .q-field--error .text-negative,body.body--dark .q-field--error .q-field__messages{color:#ff0 !important}.lnbits-drawer__q-list .q-item{padding-top:5px !important;padding-bottom:5px !important;border-top-right-radius:3px;border-bottom-right-radius:3px}.lnbits-drawer__q-list .q-item.q-item--active{color:inherit;font-weight:bold}.lnbits__dialog-card{width:500px}.q-table--dense th:first-child,.q-table--dense td:first-child,.q-table--dense .q-table__bottom{padding-left:6px !important}.q-table--dense th:last-child,.q-table--dense td:last-child,.q-table--dense .q-table__bottom{padding-right:6px !important}a.inherit{color:inherit;text-decoration:none}video{border-radius:3px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(../fonts/material-icons-v50.woff2) format('woff2')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-moz-font-feature-settings:'liga';-moz-osx-font-smoothing:grayscale}
|
||||
|
||||
+24
-20
@@ -5,11 +5,15 @@
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="{{ url_for('static', filename='vendor/quasar@1.13.2/quasar.min.css') }}"
|
||||
href="/static/vendor/quasar@1.13.2/quasar.min.css"
|
||||
/>
|
||||
{% assets 'base_css' %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}" />
|
||||
{% endassets %} {% block styles %}{% endblock %}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="/static/vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/base.css" />
|
||||
{% block styles %}{% endblock %}
|
||||
<title>
|
||||
{% block title %} {% if SITE_TITLE != 'LNbits' %}{{ SITE_TITLE }}{% else
|
||||
%}LNbits{% endif %} {% endblock %}
|
||||
@@ -108,21 +112,21 @@
|
||||
{% endblock %}
|
||||
</q-layout>
|
||||
|
||||
{% block vue_templates %}{% endblock %} {% if DEBUG %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue@2.6.12/vue.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='vendor/vuex@3.5.1/vuex.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='vendor/vue-router@3.4.3/vue-router.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='vendor/quasar@1.13.2/quasar.umd.js') }}"></script>
|
||||
{% else %} {% assets output='__bundle__/vue.js',
|
||||
'vendor/quasar@1.13.2/quasar.ie.polyfills.umd.min.js',
|
||||
'vendor/vue@2.6.12/vue.min.js', 'vendor/vue-router@3.4.3/vue-router.min.js',
|
||||
'vendor/vuex@3.5.1/vuex.min.js', 'vendor/quasar@1.13.2/quasar.umd.min.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% endif %} {% assets filters='rjsmin',
|
||||
output='__bundle__/base.js', 'vendor/axios@0.20.0/axios.min.js',
|
||||
'vendor/underscore@1.10.2/underscore.min.js', 'js/base.js',
|
||||
'js/components.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% block scripts %}{% endblock %}
|
||||
{% block vue_templates %}{% endblock %}
|
||||
<script src="/static/vendor/vue@2.6.12/vue.js"></script>
|
||||
<script src="/static/vendor/vuex@3.5.1/vuex.js"></script>
|
||||
<script src="/static/vendor/vue-router@3.4.3/vue-router.js"></script>
|
||||
<script src="/static/vendor/quasar@1.13.2/quasar.umd.js"></script>
|
||||
<script src="/static/vendor/axios@0.20.0/axios.min.js"></script>
|
||||
<script src="/static/vendor/underscore@1.10.2/underscore.min.js"></script>
|
||||
<script src="/static/vendor/vue-qrcode@1.0.2/vue-qrcode.min.js"></script>
|
||||
<script src="/static/vendor/moment@2.27.0/moment.min.js"></script>
|
||||
<script src="/static/vendor/chart.js@2.9.3/chart.min.js"></script>
|
||||
<script src="/static/vendor/bolt11/utils.js"></script>
|
||||
<script src="/static/vendor/bolt11/decoder.js"></script>
|
||||
<script src="/static/vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.js"></script>
|
||||
<script src="/static/js/base.js"></script>
|
||||
<script src="/static/js/components.js"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -38,13 +38,12 @@
|
||||
</q-page-container>
|
||||
</q-layout>
|
||||
|
||||
{% if DEBUG %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue@2.6.12/vue.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='vendor/quasar@1.13.2/quasar.umd.js') }}"></script>
|
||||
{% else %} {% assets output='__bundle__/vue-print.js',
|
||||
'vendor/quasar@1.13.2/quasar.ie.polyfills.umd.min.js',
|
||||
'vendor/vue@2.6.12/vue.min.js', 'vendor/quasar@1.13.2/quasar.umd.min.js' %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %} {% endif %} {% block scripts %}{% endblock %}
|
||||
<script src="/static/vendor/quasar@1.13.2/quasar.ie.polyfills.umd.min.js"></script>
|
||||
<script src="/static/vendor/vue@2.6.12/vue.min.js"></script>
|
||||
<script src="/static/vendor/vuex@3.5.1/vuex.js"></script>
|
||||
<script src="/static/vendor/vue-router@3.4.3/vue-router.js"></script>
|
||||
<script src="/static/vendor/quasar@1.13.2/quasar.umd.min.js"></script>
|
||||
<script src="/static/vendor/vue-qrcode@1.0.2/vue-qrcode.min.js"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user