migrate to sqlalchemy-aio.

a big refactor that:

- fixes some issues that might have happened (or not) with asynchronous
    reactions to payments;
- paves the way to https://github.com/lnbits/lnbits/issues/121;
- uses more async/await notation which just looks nice; and
- makes it simple(r?) for one extension to modify stuff from other extensions.
This commit is contained in:
fiatjaf
2020-11-21 23:02:14 -03:00
parent f877dde2b0
commit d3fc52cd49
68 changed files with 971 additions and 1075 deletions
@@ -1,5 +1,7 @@
from quart import Blueprint
from lnbits.db import Database
db = Database("ext_usermanager")
usermanager_ext: Blueprint = Blueprint("usermanager", __name__, static_folder="static", template_folder="templates")
+65 -81
View File
@@ -1,8 +1,7 @@
from lnbits.db import open_ext_db
from .models import Users, Wallets
from typing import Optional
from typing import Optional, List
from ...core.crud import (
from lnbits.core.models import Payment
from lnbits.core.crud import (
create_account,
get_user,
get_wallet_payments,
@@ -10,106 +9,91 @@ from ...core.crud import (
delete_wallet,
)
###Users
from . import db
from .models import Users, Wallets
def create_usermanager_user(user_name: str, wallet_name: str, admin_id: str) -> Users:
user = get_user(create_account().id)
wallet = create_wallet(user_id=user.id, wallet_name=wallet_name)
with open_ext_db("usermanager") as db:
db.execute(
"""
INSERT INTO users (id, name, admin)
VALUES (?, ?, ?)
""",
(user.id, user_name, admin_id),
)
db.execute(
"""
INSERT INTO wallets (id, admin, name, user, adminkey, inkey)
VALUES (?, ?, ?, ?, ?, ?)
""",
(wallet.id, admin_id, wallet_name, user.id, wallet.adminkey, wallet.inkey),
)
return get_usermanager_user(user.id)
### Users
def get_usermanager_user(user_id: str) -> Users:
with open_ext_db("usermanager") as db:
async def create_usermanager_user(user_name: str, wallet_name: str, admin_id: str) -> Users:
account = await create_account()
user = await get_user(account.id)
assert user, "Newly created user couldn't be retrieved"
row = db.fetchone("SELECT * FROM users WHERE id = ?", (user_id,))
wallet = await create_wallet(user_id=user.id, wallet_name=wallet_name)
await db.execute(
"""
INSERT INTO users (id, name, admin)
VALUES (?, ?, ?)
""",
(user.id, user_name, admin_id),
)
await db.execute(
"""
INSERT INTO wallets (id, admin, name, user, adminkey, inkey)
VALUES (?, ?, ?, ?, ?, ?)
""",
(wallet.id, admin_id, wallet_name, user.id, wallet.adminkey, wallet.inkey),
)
user_created = await get_usermanager_user(user.id)
assert user_created, "Newly created user couldn't be retrieved"
return user_created
async def get_usermanager_user(user_id: str) -> Optional[Users]:
row = await db.fetchone("SELECT * FROM users WHERE id = ?", (user_id,))
return Users(**row) if row else None
def get_usermanager_users(user_id: str) -> Users:
with open_ext_db("usermanager") as db:
rows = db.fetchall("SELECT * FROM users WHERE admin = ?", (user_id,))
async def get_usermanager_users(user_id: str) -> List[Users]:
rows = await db.fetchall("SELECT * FROM users WHERE admin = ?", (user_id,))
return [Users(**row) for row in rows]
def delete_usermanager_user(user_id: str) -> None:
row = get_usermanager_wallets(user_id)
print("test")
with open_ext_db("usermanager") as db:
db.execute("DELETE FROM users WHERE id = ?", (user_id,))
row
for r in row:
delete_wallet(user_id=user_id, wallet_id=r.id)
with open_ext_db("usermanager") as dbb:
dbb.execute("DELETE FROM wallets WHERE user = ?", (user_id,))
async def delete_usermanager_user(user_id: str) -> None:
wallets = await get_usermanager_wallets(user_id)
for wallet in wallets:
await delete_wallet(user_id=user_id, wallet_id=wallet.id)
await db.execute("DELETE FROM users WHERE id = ?", (user_id,))
await db.execute("DELETE FROM wallets WHERE user = ?", (user_id,))
###Wallets
### Wallets
def create_usermanager_wallet(user_id: str, wallet_name: str, admin_id: str) -> Wallets:
wallet = create_wallet(user_id=user_id, wallet_name=wallet_name)
with open_ext_db("usermanager") as db:
db.execute(
"""
INSERT INTO wallets (id, admin, name, user, adminkey, inkey)
VALUES (?, ?, ?, ?, ?, ?)
""",
(wallet.id, admin_id, wallet_name, user_id, wallet.adminkey, wallet.inkey),
)
return get_usermanager_wallet(wallet.id)
async def create_usermanager_wallet(user_id: str, wallet_name: str, admin_id: str) -> Wallets:
wallet = await create_wallet(user_id=user_id, wallet_name=wallet_name)
await db.execute(
"""
INSERT INTO wallets (id, admin, name, user, adminkey, inkey)
VALUES (?, ?, ?, ?, ?, ?)
""",
(wallet.id, admin_id, wallet_name, user_id, wallet.adminkey, wallet.inkey),
)
wallet_created = await get_usermanager_wallet(wallet.id)
assert wallet_created, "Newly created wallet couldn't be retrieved"
return wallet_created
def get_usermanager_wallet(wallet_id: str) -> Optional[Wallets]:
with open_ext_db("usermanager") as db:
row = db.fetchone("SELECT * FROM wallets WHERE id = ?", (wallet_id,))
async def get_usermanager_wallet(wallet_id: str) -> Optional[Wallets]:
row = await db.fetchone("SELECT * FROM wallets WHERE id = ?", (wallet_id,))
return Wallets(**row) if row else None
def get_usermanager_wallets(user_id: str) -> Wallets:
with open_ext_db("usermanager") as db:
rows = db.fetchall("SELECT * FROM wallets WHERE admin = ?", (user_id,))
async def get_usermanager_wallets(user_id: str) -> List[Wallets]:
rows = await db.fetchall("SELECT * FROM wallets WHERE admin = ?", (user_id,))
return [Wallets(**row) for row in rows]
def get_usermanager_wallet_transactions(wallet_id: str) -> Users:
return get_wallet_payments(wallet_id=wallet_id, complete=True, pending=False, outgoing=True, incoming=True)
async def get_usermanager_wallet_transactions(wallet_id: str) -> List[Payment]:
return await get_wallet_payments(wallet_id=wallet_id, complete=True, pending=False, outgoing=True, incoming=True)
def get_usermanager_wallet_balances(user_id: str) -> Users:
user = get_user(user_id)
return user.wallets
def delete_usermanager_wallet(wallet_id: str, user_id: str) -> None:
delete_wallet(user_id=user_id, wallet_id=wallet_id)
with open_ext_db("usermanager") as db:
db.execute("DELETE FROM wallets WHERE id = ?", (wallet_id,))
async def delete_usermanager_wallet(wallet_id: str, user_id: str) -> None:
await delete_wallet(user_id=user_id, wallet_id=wallet_id)
await db.execute("DELETE FROM wallets WHERE id = ?", (wallet_id,))
+3 -3
View File
@@ -1,8 +1,8 @@
def m001_initial(db):
async def m001_initial(db):
"""
Initial users table.
"""
db.execute(
await db.execute(
"""
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
@@ -17,7 +17,7 @@ def m001_initial(db):
"""
Initial wallets table.
"""
db.execute(
await db.execute(
"""
CREATE TABLE IF NOT EXISTS wallets (
id TEXT PRIMARY KEY,
+3 -1
View File
@@ -1,6 +1,8 @@
from quart import g, render_template
from lnbits.decorators import check_user_exists, validate_uuids
from lnbits.extensions.usermanager import usermanager_ext
from . import usermanager_ext
@usermanager_ext.route("/")
+13 -17
View File
@@ -4,13 +4,12 @@ from http import HTTPStatus
from lnbits.core.crud import get_user
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
from lnbits.extensions.usermanager import usermanager_ext
from . import usermanager_ext
from .crud import (
create_usermanager_user,
get_usermanager_user,
get_usermanager_users,
get_usermanager_wallet_transactions,
get_usermanager_wallet_balances,
delete_usermanager_user,
create_usermanager_wallet,
get_usermanager_wallet,
@@ -27,7 +26,7 @@ from lnbits.core import update_user_extension
@api_check_wallet_key(key_type="invoice")
async def api_usermanager_users():
user_id = g.wallet.user
return jsonify([user._asdict() for user in get_usermanager_users(user_id)]), HTTPStatus.OK
return jsonify([user._asdict() for user in await get_usermanager_users(user_id)]), HTTPStatus.OK
@usermanager_ext.route("/api/v1/users", methods=["POST"])
@@ -40,17 +39,17 @@ async def api_usermanager_users():
}
)
async def api_usermanager_users_create():
user = create_usermanager_user(g.data["user_name"], g.data["wallet_name"], g.data["admin_id"])
user = await 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")
async def api_usermanager_users_delete(user_id):
user = get_usermanager_user(user_id)
user = await get_usermanager_user(user_id)
if not user:
return jsonify({"message": "User does not exist."}), HTTPStatus.NOT_FOUND
delete_usermanager_user(user_id)
await delete_usermanager_user(user_id)
return "", HTTPStatus.NO_CONTENT
@@ -67,7 +66,7 @@ async def api_usermanager_users_delete(user_id):
}
)
async def api_usermanager_activate_extension():
user = get_user(g.data["userid"])
user = await get_user(g.data["userid"])
if not user:
return jsonify({"message": "no such user"}), HTTPStatus.NOT_FOUND
update_user_extension(user_id=g.data["userid"], extension=g.data["extension"], active=g.data["active"])
@@ -81,7 +80,7 @@ async def api_usermanager_activate_extension():
@api_check_wallet_key(key_type="invoice")
async def api_usermanager_wallets():
user_id = g.wallet.user
return jsonify([wallet._asdict() for wallet in get_usermanager_wallets(user_id)]), HTTPStatus.OK
return jsonify([wallet._asdict() for wallet in await get_usermanager_wallets(user_id)]), HTTPStatus.OK
@usermanager_ext.route("/api/v1/wallets", methods=["POST"])
@@ -94,31 +93,28 @@ async def api_usermanager_wallets():
}
)
async def api_usermanager_wallets_create():
user = create_usermanager_wallet(g.data["user_id"], g.data["wallet_name"], g.data["admin_id"])
user = await 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")
async def api_usermanager_wallet_transactions(wallet_id):
return jsonify(get_usermanager_wallet_transactions(wallet_id)), HTTPStatus.OK
return jsonify(await 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")
async def api_usermanager_wallet_balances(user_id):
return jsonify(get_usermanager_wallet_balances(user_id)), HTTPStatus.OK
async def api_usermanager_wallet(user_id):
return jsonify(await get_usermanager_wallets(user_id)), HTTPStatus.OK
@usermanager_ext.route("/api/v1/wallets/<wallet_id>", methods=["DELETE"])
@api_check_wallet_key(key_type="invoice")
async def api_usermanager_wallets_delete(wallet_id):
wallet = get_usermanager_wallet(wallet_id)
print(wallet.id)
wallet = await get_usermanager_wallet(wallet_id)
if not wallet:
return jsonify({"message": "Wallet does not exist."}), HTTPStatus.NOT_FOUND
delete_usermanager_wallet(wallet_id, wallet.user)
await delete_usermanager_wallet(wallet_id, wallet.user)
return "", HTTPStatus.NO_CONTENT