formatting

This commit is contained in:
Lee Salminen 2022-12-20 07:15:54 -06:00
parent 9e857e6329
commit 048ccd6d65
8 changed files with 123 additions and 89 deletions

View file

@ -3,12 +3,7 @@ from typing import List, Optional, Union
from lnbits.helpers import urlsafe_short_hash
from . import db
from .models import (
CreateDomainData,
Domain,
Address,
CreateAddressData,
)
from .models import Address, CreateAddressData, CreateDomainData, Domain
async def get_domain(domain_id: str) -> Optional[Domain]:
@ -17,12 +12,14 @@ async def get_domain(domain_id: str) -> Optional[Domain]:
)
return Domain.from_row(row) if row else None
async def get_domain_by_name(domain: str) -> Optional[Domain]:
row = await db.fetchone(
"SELECT * FROM nostrnip5.domains WHERE domain = ?", (domain,)
)
return Domain.from_row(row) if row else None
async def get_domains(wallet_ids: Union[str, List[str]]) -> List[Domain]:
if isinstance(wallet_ids, str):
wallet_ids = [wallet_ids]
@ -34,18 +31,31 @@ async def get_domains(wallet_ids: Union[str, List[str]]) -> List[Domain]:
return [Domain.from_row(row) for row in rows]
async def get_address(domain_id: str, address_id: str) -> Optional[Address]:
row = await db.fetchone(
"SELECT * FROM nostrnip5.addresses WHERE domain_id = ? AND id = ?", (domain_id,address_id,)
"SELECT * FROM nostrnip5.addresses WHERE domain_id = ? AND id = ?",
(
domain_id,
address_id,
),
)
return Address.from_row(row) if row else None
async def get_address_by_local_part(domain_id: str, local_part: str) -> Optional[Address]:
async def get_address_by_local_part(
domain_id: str, local_part: str
) -> Optional[Address]:
row = await db.fetchone(
"SELECT * FROM nostrnip5.addresses WHERE domain_id = ? AND local_part = ?", (domain_id,local_part,)
"SELECT * FROM nostrnip5.addresses WHERE domain_id = ? AND local_part = ?",
(
domain_id,
local_part,
),
)
return Address.from_row(row) if row else None
async def get_addresses(domain_id: str) -> List[Address]:
rows = await db.fetchall(
f"SELECT * FROM nostrnip5.addresses WHERE domain_id = ?", (domain_id,)
@ -53,6 +63,7 @@ async def get_addresses(domain_id: str) -> List[Address]:
return [Address.from_row(row) for row in rows]
async def get_all_addresses(wallet_ids: Union[str, List[str]]) -> List[Address]:
if isinstance(wallet_ids, str):
wallet_ids = [wallet_ids]
@ -65,11 +76,12 @@ async def get_all_addresses(wallet_ids: Union[str, List[str]]) -> List[Address]:
JOIN nostrnip5.domains d ON d.id = a.domain_id
WHERE d.wallet IN ({q})
""",
(*wallet_ids,)
(*wallet_ids,),
)
return [Address.from_row(row) for row in rows]
async def activate_domain(domain_id: str, address_id: str) -> Address:
await db.execute(
"""
@ -88,37 +100,34 @@ async def activate_domain(domain_id: str, address_id: str) -> Address:
assert address, "Newly updated address couldn't be retrieved"
return address
async def delete_domain(domain_id) -> bool:
await db.execute(
"""
DELETE FROM nostrnip5.addresses WHERE domain_id = ?
""",
(
domain_id,
),
(domain_id,),
)
await db.execute(
"""
DELETE FROM nostrnip5.domains WHERE id = ?
""",
(
domain_id,
),
(domain_id,),
)
return True
async def delete_address(address_id) -> bool:
await db.execute(
"""
DELETE FROM nostrnip5.addresses WHERE id = ?
""",
(
address_id,
),
(address_id,),
)
async def create_address_internal(domain_id: str, data: CreateAddressData) -> Address:
address_id = urlsafe_short_hash()
@ -140,6 +149,7 @@ async def create_address_internal(domain_id: str, data: CreateAddressData) -> Ad
assert address, "Newly created address couldn't be retrieved"
return address
async def create_domain_internal(wallet_id: str, data: CreateDomainData) -> Domain:
domain_id = urlsafe_short_hash()
@ -148,13 +158,7 @@ async def create_domain_internal(wallet_id: str, data: CreateDomainData) -> Doma
INSERT INTO nostrnip5.domains (id, wallet, currency, amount, domain)
VALUES (?, ?, ?, ?, ?)
""",
(
domain_id,
wallet_id,
data.currency,
int(data.amount * 100),
data.domain
),
(domain_id, wallet_id, data.currency, int(data.amount * 100), data.domain),
)
domain = await get_domain(domain_id)

View file

@ -5,18 +5,21 @@ from typing import List, Optional
from fastapi.param_functions import Query
from pydantic import BaseModel
class CreateAddressData(BaseModel):
domain_id: str
local_part: str
pubkey: str
active: bool = False
class CreateDomainData(BaseModel):
wallet: str
currency: str
amount: float = Query(..., ge=0.01)
domain: str
class Domain(BaseModel):
id: str
wallet: str
@ -29,6 +32,7 @@ class Domain(BaseModel):
def from_row(cls, row: Row) -> "Domain":
return cls(**dict(row))
class Address(BaseModel):
id: str
domain_id: str

View file

@ -5,10 +5,7 @@ from lnbits.core.models import Payment
from lnbits.helpers import urlsafe_short_hash
from lnbits.tasks import internal_invoice_queue, register_invoice_listener
from .crud import (
get_domain,
activate_domain,
)
from .crud import activate_domain, get_domain
async def wait_for_paid_invoices():

View file

@ -78,7 +78,9 @@
<h5 class="text-subtitle1 q-my-none">Addresses</h5>
</div>
<div class="col-auto">
<q-btn flat color="grey" @click="exportAddressesCSV">Export to CSV</q-btn>
<q-btn flat color="grey" @click="exportAddressesCSV"
>Export to CSV</q-btn
>
</div>
</div>
<q-table
@ -140,7 +142,6 @@
<q-dialog v-model="formDialog.show" position="top" @hide="closeFormDialog">
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
<q-form @submit="saveDomain" class="q-gutter-md">
<q-select
filled
dense
@ -387,9 +388,14 @@
columns: [
{name: 'id', align: 'left', label: 'ID', field: 'id'},
{name: 'domain', align: 'left', label: 'Domain', field: 'domain'},
{name: 'currency', align: 'left', label: 'Currency', field: 'currency'},
{
name: 'currency',
align: 'left',
label: 'Currency',
field: 'currency'
},
{name: 'amount', align: 'left', label: 'Amount', field: 'amount'},
{name: 'time', align: 'left', label: "Created At", field: 'time'},
{name: 'time', align: 'left', label: 'Created At', field: 'time'}
],
pagination: {
rowsPerPage: 10
@ -398,11 +404,21 @@
addressesTable: {
columns: [
{name: 'id', align: 'left', label: 'ID', field: 'id'},
{name: 'active', align: 'left', label: "Active", field: 'active'},
{name: 'domain_id', align: 'left', label: 'Domain', field: 'domain_id'},
{name: 'local_part', align: 'left', label: 'Local Part', field: 'local_part'},
{name: 'active', align: 'left', label: 'Active', field: 'active'},
{
name: 'domain_id',
align: 'left',
label: 'Domain',
field: 'domain_id'
},
{
name: 'local_part',
align: 'left',
label: 'Local Part',
field: 'local_part'
},
{name: 'pubkey', align: 'left', label: 'Pubkey', field: 'pubkey'},
{name: 'time', align: 'left', label: "Created At", field: 'time'},
{name: 'time', align: 'left', label: 'Created At', field: 'time'}
],
pagination: {
rowsPerPage: 10
@ -410,7 +426,7 @@
},
formDialog: {
show: false,
data: {},
data: {}
}
}
},

View file

@ -1,13 +1,21 @@
{% extends "public.html" %} {% block toolbar_title %} Verify NIP-5 For {{ domain.domain }}
{% endblock %} {% from "macros.jinja" import window_vars with context %} {%
block page %}
{% extends "public.html" %} {% block toolbar_title %} Verify NIP-5 For {{
domain.domain }} {% endblock %} {% from "macros.jinja" import window_vars with
context %} {% block page %}
<link rel="stylesheet" href="/nostrnip5/static/css/signup.css" />
<div>
<q-card class="q-pa-lg q-pt-lg">
<q-form @submit="createAddress" class="q-gutter-md">
<p>You can use this page to get NIP-5 verified on the nostr protocol under the {{ domain.domain }} domain.</p>
<p>The current price is <b>{{ "{:0,.2f}".format(domain.amount / 100) }} {{ domain.currency }}</b> for a <b>lifetime</b> account.</p>
<p>
You can use this page to get NIP-5 verified on the nostr protocol under
the {{ domain.domain }} domain.
</p>
<p>
The current price is
<b
>{{ "{:0,.2f}".format(domain.amount / 100) }} {{ domain.currency }}</b
>
for a <b>lifetime</b> account.
</p>
<p>After submitting payment, your address will be</p>
@ -43,9 +51,7 @@ block page %}
type="submit"
>Create Address</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
</div>
</q-form>
</q-card>
@ -91,19 +97,19 @@ block page %}
amount: '{{ domain.amount }}',
qrCodeDialog: {
data: {
payment_request: null,
payment_request: null
},
show: false,
show: false
},
formDialog: {
data: {
local_part: null,
pubkey: null,
},
pubkey: null
}
},
urlDialog: {
show: false,
},
show: false
}
}
},
methods: {
@ -118,7 +124,10 @@ block page %}
var localPart = formDialog.data.local_part
axios
.post('/nostrnip5/api/v1/domain/' + this.domain_id + '/address', formDialog.data)
.post(
'/nostrnip5/api/v1/domain/' + this.domain_id + '/address',
formDialog.data
)
.then(function (response) {
formDialog.data = {}
@ -147,7 +156,9 @@ block page %}
qrCodeDialog.show = false
setTimeout(function () {
alert(`Success! Your username is now active at ${localPart}@${self.domain}. Please add this to your nostr profile accordingly.`)
alert(
`Success! Your username is now active at ${localPart}@${self.domain}. Please add this to your nostr profile accordingly.`
)
}, 500)
}
})
@ -156,14 +167,10 @@ block page %}
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
},
computed: {
},
created: function () {
}
},
computed: {},
created: function () {}
})
</script>
{% endblock %}

View file

@ -11,9 +11,7 @@ from lnbits.core.models import User
from lnbits.decorators import check_user_exists
from . import nostrnip5_ext, nostrnip5_renderer
from .crud import (
get_domain,
)
from .crud import get_domain
templates = Jinja2Templates(directory="templates")

View file

@ -1,10 +1,10 @@
from http import HTTPStatus
from typing import Optional
from fastapi import Query, Request, Response
from fastapi.params import Depends
from loguru import logger
from starlette.exceptions import HTTPException
from typing import Optional
from lnbits.core.crud import get_user
from lnbits.core.services import create_invoice
@ -14,18 +14,18 @@ from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
from . import nostrnip5_ext
from .crud import (
get_domains,
get_domain,
create_domain_internal,
create_address_internal,
create_domain_internal,
delete_address,
delete_domain,
get_domain_by_name,
get_address_by_local_part,
get_addresses,
get_all_addresses,
delete_address,
get_domain,
get_domain_by_name,
get_domains,
)
from .models import CreateDomainData, CreateAddressData
from .models import CreateAddressData, CreateDomainData
@nostrnip5_ext.get("/api/v1/domains", status_code=HTTPStatus.OK)
@ -38,6 +38,7 @@ async def api_domains(
return [domain.dict() for domain in await get_domains(wallet_ids)]
@nostrnip5_ext.get("/api/v1/addresses", status_code=HTTPStatus.OK)
async def api_addresses(
all_wallets: bool = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)
@ -85,6 +86,7 @@ async def api_domain_delete(
return True
@nostrnip5_ext.delete("/api/v1/address/{address_id}", status_code=HTTPStatus.CREATED)
async def api_address_delete(
address_id: str,
@ -95,7 +97,9 @@ async def api_address_delete(
return True
@nostrnip5_ext.post("/api/v1/domain/{domain_id}/address", status_code=HTTPStatus.CREATED)
@nostrnip5_ext.post(
"/api/v1/domain/{domain_id}/address", status_code=HTTPStatus.CREATED
)
async def api_address_create(
data: CreateAddressData,
domain_id: str,
@ -127,7 +131,11 @@ async def api_address_create(
wallet_id=domain.wallet,
amount=price_in_sats,
memo=f"Payment for domain {domain_id}",
extra={"tag": "nostrnip5", "domain_id": domain_id, "address_id": address.id,},
extra={
"tag": "nostrnip5",
"domain_id": domain_id,
"address_id": address.id,
},
)
except Exception as e:
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
@ -154,7 +162,9 @@ async def api_nostrnip5_check_payment(domain_id: str, payment_hash: str):
@nostrnip5_ext.get("/api/v1/domain/{domain_id}/nostr.json", status_code=HTTPStatus.OK)
async def api_get_nostr_json(response: Response, domain_id: str, name: str = Query(None)):
async def api_get_nostr_json(
response: Response, domain_id: str, name: str = Query(None)
):
addresses = [address.dict() for address in await get_addresses(domain_id)]
output = {}
@ -170,6 +180,4 @@ async def api_get_nostr_json(response: Response, domain_id: str, name: str = Que
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET,OPTIONS"
return {
"names": output
}
return {"names": output}