feat: basic account UI

This commit is contained in:
Vlad Stan 2023-02-15 14:17:01 +02:00
parent 2099a8b7bb
commit d0f38346e3
7 changed files with 116 additions and 16 deletions

12
crud.py
View file

@ -374,3 +374,15 @@ async def get_account(
) )
return NostrAccount.from_row(row) if row else None 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]

View file

@ -52,6 +52,7 @@ async def m001_initial(db):
CREATE TABLE nostrrelay.accounts ( CREATE TABLE nostrrelay.accounts (
relay_id TEXT NOT NULL, relay_id TEXT NOT NULL,
pubkey TEXT NOT NULL, pubkey TEXT NOT NULL,
sats {db.big_int} DEFAULT 0,
storage {db.big_int} DEFAULT 0, storage {db.big_int} DEFAULT 0,
paid_to_join BOOLEAN DEFAULT false, paid_to_join BOOLEAN DEFAULT false,
allowed BOOLEAN DEFAULT false, allowed BOOLEAN DEFAULT false,

View file

@ -344,14 +344,18 @@ class BuyOrder(BaseModel):
def is_valid_action(self): def is_valid_action(self):
return self.action in ["join", "storage"] return self.action in ["join", "storage"]
class NostrPartialAccount(BaseModel):
relay_id: str
pubkey: str
allowed: Optional[bool]
blocked: Optional[bool]
class NostrAccount(BaseModel): class NostrAccount(BaseModel):
pubkey: str pubkey: str
allowed = False
blocked = False
sats = 0 sats = 0
storage = 0 storage = 0
paid_to_join = False paid_to_join = False
allowed = False
blocked = False
@classmethod @classmethod
def null_account(cls) -> "NostrAccount": def null_account(cls) -> "NostrAccount":

View file

@ -3,7 +3,7 @@
<q-tab name="info" label="Relay Info"></q-tab> <q-tab name="info" label="Relay Info"></q-tab>
<q-tab name="payment" label="Payment"></q-tab> <q-tab name="payment" label="Payment"></q-tab>
<q-tab name="config" label="Config"></q-tab> <q-tab name="config" label="Config"></q-tab>
<q-tab name="access" label="Access"></q-tab> <q-tab name="accounts" label="Accounts"></q-tab>
</q-tabs> </q-tabs>
<q-tab-panels v-model="tab"> <q-tab-panels v-model="tab">
<q-tab-panel name="info"> <q-tab-panel name="info">
@ -527,7 +527,7 @@
</div> </div>
</div> </div>
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="access"> <q-tab-panel name="accounts">
<div v-if="relay"> <div v-if="relay">
<div class="row items-center no-wrap q-mb-md"> <div class="row items-center no-wrap q-mb-md">
<div class="col-2 q-pr-lg">Public Key: </div> <div class="col-2 q-pr-lg">Public Key: </div>

View file

@ -114,9 +114,29 @@ async function relayDetails(path) {
this.relay.config.wallet = this.relay.config.wallet =
this.relay.config.wallet || this.walletOptions[0].value this.relay.config.wallet || this.walletOptions[0].value
}, },
allowPublicKey: function () { allowPublicKey: async function () {
this.relay.config.allowedPublicKeys.push(this.allowedPubkey) try {
this.allowedPubkey = '' 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 () { blockPublicKey: function () {
this.relay.config.blockedPublicKeys.push(this.blockedPubkey) this.relay.config.blockedPublicKeys.push(this.blockedPubkey)

View file

@ -27,21 +27,21 @@ async def on_invoice_paid(payment: Payment):
pubkey = payment.extra.get("pubkey") pubkey = payment.extra.get("pubkey")
if payment.extra.get("action") == "join": 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 return
if payment.extra.get("action") == "storage": if payment.extra.get("action") == "storage":
storage_to_buy = payment.extra.get("storage_to_buy") 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 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: try:
account = await get_account(relay_id, pubkey) account = await get_account(relay_id, pubkey)
if not account: if not account:
await create_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 return
@ -49,18 +49,19 @@ async def invoice_paid_to_join(relay_id: str, pubkey: str):
return return
account.paid_to_join = True account.paid_to_join = True
account.sats += amount
await update_account(relay_id, account) await update_account(relay_id, account)
except Exception as ex: except Exception as ex:
logger.warning(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: try:
account = await get_account(relay_id, pubkey) account = await get_account(relay_id, pubkey)
if not account: if not account:
await create_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 return
@ -68,6 +69,7 @@ async def invoice_paid_for_storage(relay_id: str, pubkey: str, storage_to_buy: i
return return
account.storage = storage_to_buy account.storage = storage_to_buy
account.sats += amount
await update_account(relay_id, account) await update_account(relay_id, account)
except Exception as ex: except Exception as ex:

View file

@ -18,16 +18,20 @@ from lnbits.helpers import urlsafe_short_hash
from . import nostrrelay_ext from . import nostrrelay_ext
from .client_manager import NostrClientConnection, NostrClientManager from .client_manager import NostrClientConnection, NostrClientManager
from .crud import ( from .crud import (
create_account,
create_relay, create_relay,
delete_all_events, delete_all_events,
delete_relay, delete_relay,
get_account,
get_accounts,
get_relay, get_relay,
get_relay_by_id, get_relay_by_id,
get_relays, get_relays,
update_account,
update_relay, update_relay,
) )
from .helpers import extract_domain, normalize_public_key from .helpers import extract_domain, normalize_public_key
from .models import BuyOrder, NostrRelay from .models import BuyOrder, NostrAccount, NostrPartialAccount, NostrRelay
client_manager = NostrClientManager() client_manager = NostrClientManager()
@ -141,6 +145,64 @@ async def api_get_relay(
return 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}") @nostrrelay_ext.delete("/api/v1/relay/{relay_id}")
async def api_delete_relay( async def api_delete_relay(
relay_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) 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, "storage_to_buy": storage_to_buy,
}, },
) )
print("### payment_request", payment_request)
return {"invoice": payment_request} return {"invoice": payment_request}
except ValueError as ex: except ValueError as ex:
raise HTTPException( raise HTTPException(