formatting
This commit is contained in:
parent
9e857e6329
commit
048ccd6d65
8 changed files with 123 additions and 89 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue