From d0f38346e361e38d2303b52736c15bc67937acea Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Wed, 15 Feb 2023 14:17:01 +0200 Subject: [PATCH] feat: basic account UI --- crud.py | 12 ++++ migrations.py | 1 + models.py | 10 ++- .../relay-details/relay-details.html | 4 +- .../components/relay-details/relay-details.js | 26 +++++++- tasks.py | 14 ++-- views_api.py | 65 ++++++++++++++++++- 7 files changed, 116 insertions(+), 16 deletions(-) diff --git a/crud.py b/crud.py index 5b986c4..82c1cca 100644 --- a/crud.py +++ b/crud.py @@ -374,3 +374,15 @@ async def get_account( ) return NostrAccount.from_row(row) if row else None + +async def get_accounts( + relay_id: str, + allowed = True, + blocked = False, +) -> List[NostrAccount]: + rows = await db.fetchall( + "SELECT * FROM nostrrelay.accounts WHERE relay_id = ? AND allowed = ? AND blocked = ?", + (relay_id, allowed, blocked), + ) + + return [NostrAccount.from_row(row) for row in rows] diff --git a/migrations.py b/migrations.py index e69c350..6b81a94 100644 --- a/migrations.py +++ b/migrations.py @@ -52,6 +52,7 @@ async def m001_initial(db): CREATE TABLE nostrrelay.accounts ( relay_id TEXT NOT NULL, pubkey TEXT NOT NULL, + sats {db.big_int} DEFAULT 0, storage {db.big_int} DEFAULT 0, paid_to_join BOOLEAN DEFAULT false, allowed BOOLEAN DEFAULT false, diff --git a/models.py b/models.py index f9879bb..611901a 100644 --- a/models.py +++ b/models.py @@ -344,14 +344,18 @@ class BuyOrder(BaseModel): def is_valid_action(self): return self.action in ["join", "storage"] - +class NostrPartialAccount(BaseModel): + relay_id: str + pubkey: str + allowed: Optional[bool] + blocked: Optional[bool] class NostrAccount(BaseModel): pubkey: str + allowed = False + blocked = False sats = 0 storage = 0 paid_to_join = False - allowed = False - blocked = False @classmethod def null_account(cls) -> "NostrAccount": diff --git a/static/components/relay-details/relay-details.html b/static/components/relay-details/relay-details.html index d999f48..c211444 100644 --- a/static/components/relay-details/relay-details.html +++ b/static/components/relay-details/relay-details.html @@ -3,7 +3,7 @@ - + @@ -527,7 +527,7 @@ - +
Public Key:
diff --git a/static/components/relay-details/relay-details.js b/static/components/relay-details/relay-details.js index 99f75c4..31662f2 100644 --- a/static/components/relay-details/relay-details.js +++ b/static/components/relay-details/relay-details.js @@ -114,9 +114,29 @@ async function relayDetails(path) { this.relay.config.wallet = this.relay.config.wallet || this.walletOptions[0].value }, - allowPublicKey: function () { - this.relay.config.allowedPublicKeys.push(this.allowedPubkey) - this.allowedPubkey = '' + allowPublicKey: async function () { + try { + const {data} = await LNbits.api.request( + 'PUT', + '/nostrrelay/api/v1/account', + this.adminkey, + { + pubkey: this.allowedPubkey, + allowed: true + } + ) + this.relay = data + this.$emit('relay-updated', this.relay) + this.$q.notify({ + type: 'positive', + message: 'Account Updated', + timeout: 5000 + }) + this.allowedPubkey = '' + } catch (error) { + LNbits.utils.notifyApiError(error) + } + }, blockPublicKey: function () { this.relay.config.blockedPublicKeys.push(this.blockedPubkey) diff --git a/tasks.py b/tasks.py index 88c21fc..b902dbb 100644 --- a/tasks.py +++ b/tasks.py @@ -27,21 +27,21 @@ async def on_invoice_paid(payment: Payment): pubkey = payment.extra.get("pubkey") if payment.extra.get("action") == "join": - await invoice_paid_to_join(relay_id, pubkey) + await invoice_paid_to_join(relay_id, pubkey, payment.amount) return if payment.extra.get("action") == "storage": storage_to_buy = payment.extra.get("storage_to_buy") - await invoice_paid_for_storage(relay_id, pubkey, storage_to_buy) + await invoice_paid_for_storage(relay_id, pubkey, storage_to_buy, payment.amount) return -async def invoice_paid_to_join(relay_id: str, pubkey: str): +async def invoice_paid_to_join(relay_id: str, pubkey: str, amount: int): try: account = await get_account(relay_id, pubkey) if not account: await create_account( - relay_id, NostrAccount(pubkey=pubkey, paid_to_join=True) + relay_id, NostrAccount(pubkey=pubkey, paid_to_join=True, sats=amount) ) return @@ -49,18 +49,19 @@ async def invoice_paid_to_join(relay_id: str, pubkey: str): return account.paid_to_join = True + account.sats += amount await update_account(relay_id, account) except Exception as ex: logger.warning(ex) -async def invoice_paid_for_storage(relay_id: str, pubkey: str, storage_to_buy: int): +async def invoice_paid_for_storage(relay_id: str, pubkey: str, storage_to_buy: int, amount: str): try: account = await get_account(relay_id, pubkey) if not account: await create_account( - relay_id, NostrAccount(pubkey=pubkey, storage=storage_to_buy) + relay_id, NostrAccount(pubkey=pubkey, storage=storage_to_buy, sats=amount) ) return @@ -68,6 +69,7 @@ async def invoice_paid_for_storage(relay_id: str, pubkey: str, storage_to_buy: i return account.storage = storage_to_buy + account.sats += amount await update_account(relay_id, account) except Exception as ex: diff --git a/views_api.py b/views_api.py index ca45aa1..3e1ae0b 100644 --- a/views_api.py +++ b/views_api.py @@ -18,16 +18,20 @@ from lnbits.helpers import urlsafe_short_hash from . import nostrrelay_ext from .client_manager import NostrClientConnection, NostrClientManager from .crud import ( + create_account, create_relay, delete_all_events, delete_relay, + get_account, + get_accounts, get_relay, get_relay_by_id, get_relays, + update_account, update_relay, ) from .helpers import extract_domain, normalize_public_key -from .models import BuyOrder, NostrRelay +from .models import BuyOrder, NostrAccount, NostrPartialAccount, NostrRelay client_manager = NostrClientManager() @@ -141,6 +145,64 @@ async def api_get_relay( return relay +@nostrrelay_ext.put("/api/v1/account") +async def api_create_or_update_account( + data: NostrPartialAccount, + wallet: WalletTypeInfo = Depends(require_admin_key), +) -> NostrAccount: + + try: + data.pubkey = normalize_public_key(data.pubkey) + account = await get_account(data.relay_id, data.pubkey) + if not account: + return await create_account(data.relay_id, NostrAccount.parse_obj(data.dict())) + + if data.blocked is not None: + account.blocked = data.blocked + if data.allowed is not None: + account.allowed = data.allowed + return await update_account(data.relay_id, account) + + except ValueError as ex: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=str(ex), + ) + except HTTPException as ex: + raise ex + except Exception as ex: + logger.warning(ex) + raise HTTPException( + status_code=HTTPStatus.INTERNAL_SERVER_ERROR, + detail="Cannot create account", + ) + + +@nostrrelay_ext.get("/api/v1/account") +async def api_get_accounts( + relay_id: str, allowed: bool, blocked: bool, wallet: WalletTypeInfo = Depends(require_invoice_key) +) -> List[NostrAccount]: + try: + # make sure the user has access to the relay + relay = await get_relay(wallet.wallet.user, relay_id) + accounts = await get_accounts(relay.id, allowed, blocked) + return accounts + except ValueError as ex: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=str(ex), + ) + except HTTPException as ex: + raise ex + except Exception as ex: + logger.warning(ex) + raise HTTPException( + status_code=HTTPStatus.INTERNAL_SERVER_ERROR, + detail="Cannot fetch accounts", + ) + + + @nostrrelay_ext.delete("/api/v1/relay/{relay_id}") async def api_delete_relay( relay_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) @@ -193,7 +255,6 @@ async def api_pay_to_join(data: BuyOrder): "storage_to_buy": storage_to_buy, }, ) - print("### payment_request", payment_request) return {"invoice": payment_request} except ValueError as ex: raise HTTPException(