Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update to lnbits 1.0.0 #7

Merged
merged 4 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 10 additions & 19 deletions cloudflare.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,41 @@
import httpx

from .models import Domains
from .models import Domain


async def cloudflare_create_subdomain(
domain: Domains, subdomain: str, record_type: str, ip: str
domain: Domain, subdomain: str, record_type: str, ip: str
):
# Call to cloudflare sort of a dry-run
# if success delete the domain and wait for payment
### SEND REQUEST TO CLOUDFLARE
url = (
"https://api.cloudflare.com/client/v4/zones/"
+ domain.cf_zone_id
+ "/dns_records"
)
url = f"https://api.cloudflare.com/client/v4/zones/{domain.cf_zone_id}/dns_records"
header = {
"Authorization": "Bearer " + domain.cf_token,
"Authorization": f"Bearer {domain.cf_token}",
"Content-Type": "application/json",
}
a_record = subdomain + "." + domain.domain
async with httpx.AsyncClient() as client:
r = await client.post(
url,
headers=header,
json={
"type": record_type,
"name": a_record,
"name": f"{subdomain}.{domain.domain}",
"content": ip,
"ttl": 0,
"proxied": False,
},
timeout=40,
timeout=6,
)
r.raise_for_status()
return r.json()


async def cloudflare_deletesubdomain(domain: Domains, domain_id: str):
url = (
"https://api.cloudflare.com/client/v4/zones/"
+ domain.cf_zone_id
+ "/dns_records"
)
async def cloudflare_deletesubdomain(domain: Domain, domain_id: str):
url = f"https://api.cloudflare.com/client/v4/zones/{domain.cf_zone_id}/dns_records/{domain_id}"
header = {
"Authorization": "Bearer " + domain.cf_token,
"Authorization": f"Bearer {domain.cf_token}",
"Content-Type": "application/json",
}
async with httpx.AsyncClient() as client:
await client.delete(url + "/" + domain_id, headers=header, timeout=40)
await client.delete(url, headers=header, timeout=6)
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Subdomains",
"short_description": "Sell subdomains of your domain",
"tile": "/subdomains/static/image/subdomains.png",
"min_lnbits_version": "0.12.5",
"min_lnbits_version": "1.0.0",
"contributors": [
{
"name": "grmkris",
Expand Down
196 changes: 64 additions & 132 deletions crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,178 +3,110 @@
from lnbits.db import Database
from lnbits.helpers import urlsafe_short_hash

from .models import CreateDomain, CreateSubdomain, Domains, Subdomains
from .models import CreateDomain, CreateSubdomain, Domain, Subdomain

db = Database("ext_subdomains")


async def create_subdomain(payment_hash, wallet, data: CreateSubdomain) -> Subdomains:
await db.execute(
"""
INSERT INTO subdomains.subdomain
(id, domain, email, subdomain, ip, wallet, sats, duration, paid, record_type)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
payment_hash,
data.domain,
data.email,
data.subdomain,
data.ip,
wallet,
data.sats,
data.duration,
False,
data.record_type,
),
async def create_subdomain(payment_hash, wallet, data: CreateSubdomain) -> Subdomain:
subdomain = Subdomain(
id=payment_hash,
wallet=wallet,
**data.dict(),
)
await db.insert("subdomains.subdomain", subdomain)
return subdomain

new_subdomain = await get_subdomain(payment_hash)
assert new_subdomain, "Newly created subdomain couldn't be retrieved"
return new_subdomain

async def set_subdomain_paid(payment_hash: str) -> Subdomain:
subdomain = await db.fetchone(
"SELECT * FROM subdomains.subdomain WHERE id = :id",
{"id": payment_hash},
Subdomain,
)
if subdomain.paid is False:
subdomain.paid = True
await db.update("subdomains.subdomain", subdomain)
domain = await get_domain(subdomain.domain)
assert domain, "Couldn't get domain from paid subdomain"
domain.amountmade += subdomain.sats
await db.update("subdomains.domain", domain)

async def set_subdomain_paid(payment_hash: str) -> Subdomains:
row = await db.fetchone(
return subdomain


async def get_subdomain(subdomain_id: str) -> Optional[Subdomain]:
return await db.fetchone(
"""
SELECT s.*, d.domain as domain_name FROM subdomains.subdomain s
INNER JOIN subdomains.domain d ON (s.domain = d.id) WHERE s.id = ?
INNER JOIN subdomains.domain d ON (s.domain = d.id) WHERE s.id = :id
""",
(payment_hash,),
{"id": subdomain_id},
Subdomain,
)
if row[8] is False:
await db.execute(
"""
UPDATE subdomains.subdomain
SET paid = true
WHERE id = ?
""",
(payment_hash,),
)

domaindata = await get_domain(row[1])
assert domaindata, "Couldn't get domain from paid subdomain"

amount = domaindata.amountmade + row[8]
await db.execute(
"""
UPDATE subdomains.domain
SET amountmade = ?
WHERE id = ?
""",
(amount, row[1]),
)

new_subdomain = await get_subdomain(payment_hash)
assert new_subdomain, "Newly paid subdomain couldn't be retrieved"
return new_subdomain


async def get_subdomain(subdomain_id: str) -> Optional[Subdomains]:
row = await db.fetchone(
"""
SELECT s.*, d.domain as domain_name FROM subdomains.subdomain s
INNER JOIN subdomains.domain d ON (s.domain = d.id) WHERE s.id = ?
""",
(subdomain_id,),
)
return Subdomains(**row) if row else None


async def get_subdomain_by_subdomain(subdomain: str) -> Optional[Subdomains]:
row = await db.fetchone(
async def get_subdomain_by_subdomain(subdomain: str) -> Optional[Subdomain]:
return await db.fetchone(
"""
SELECT s.*, d.domain as domain_name FROM subdomains.subdomain s
INNER JOIN subdomains.domain d ON (s.domain = d.id) WHERE s.subdomain = ?
INNER JOIN subdomains.domain d ON (s.domain = d.id) WHERE s.subdomain = :id
""",
(subdomain,),
{"id": subdomain},
Subdomain,
)
return Subdomains(**row) if row else None


async def get_subdomains(wallet_ids: Union[str, list[str]]) -> list[Subdomains]:
async def get_subdomains(wallet_ids: Union[str, list[str]]) -> list[Subdomain]:
if isinstance(wallet_ids, str):
wallet_ids = [wallet_ids]

q = ",".join(["?"] * len(wallet_ids))
rows = await db.fetchall(
q = ",".join([f"'{w}'" for w in wallet_ids])
return await db.fetchall(
f"""
SELECT s.*, d.domain as domain_name FROM subdomains.subdomain s
INNER JOIN subdomains.domain d ON (s.domain = d.id) WHERE s.wallet IN ({q})
""",
(*wallet_ids,),
SELECT s.*, d.domain as domain_name FROM subdomains.subdomain s
INNER JOIN subdomains.domain d ON (s.domain = d.id) WHERE s.wallet IN ({q})
""",
model=Subdomain,
)

return [Subdomains(**row) for row in rows]


async def delete_subdomain(subdomain_id: str) -> None:
await db.execute("DELETE FROM subdomains.subdomain WHERE id = ?", (subdomain_id,))


# Domains


async def create_domain(data: CreateDomain) -> Domains:
domain_id = urlsafe_short_hash()
await db.execute(
"""
INSERT INTO subdomains.domain
(
id, wallet, domain, webhook, cf_token, cf_zone_id,
description, cost, amountmade, allowed_record_types
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
domain_id,
data.wallet,
data.domain,
data.webhook,
data.cf_token,
data.cf_zone_id,
data.description,
data.cost,
0,
data.allowed_record_types,
),
"DELETE FROM subdomains.subdomain WHERE id = :id",
{"id": subdomain_id},
)

new_domain = await get_domain(domain_id)
assert new_domain, "Newly created domain couldn't be retrieved"
return new_domain


async def update_domain(domain_id: str, **kwargs) -> Domains:
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
await db.execute(
f"UPDATE subdomains.domain SET {q} WHERE id = ?", (*kwargs.values(), domain_id)
)
row = await db.fetchone(
"SELECT * FROM subdomains.domain WHERE id = ?", (domain_id,)
async def create_domain(data: CreateDomain) -> Domain:
domain = Domain(
id=urlsafe_short_hash(),
**data.dict(),
)
assert row, "Newly updated domain couldn't be retrieved"
return Domains(**row)
await db.insert("subdomains.domain", domain)
return domain


async def update_domain(domain: Domain) -> Domain:
await db.update("subdomains.domain", domain)
return domain

async def get_domain(domain_id: str) -> Optional[Domains]:
row = await db.fetchone(
"SELECT * FROM subdomains.domain WHERE id = ?", (domain_id,)

async def get_domain(domain_id: str) -> Optional[Domain]:
return await db.fetchone(
"SELECT * FROM subdomains.domain WHERE id = :id",
{"id": domain_id},
Domain,
)
return Domains(**row) if row else None


async def get_domains(wallet_ids: Union[str, list[str]]) -> list[Domains]:
async def get_domains(wallet_ids: Union[str, list[str]]) -> list[Domain]:
if isinstance(wallet_ids, str):
wallet_ids = [wallet_ids]

q = ",".join(["?"] * len(wallet_ids))
rows = await db.fetchall(
f"SELECT * FROM subdomains.domain WHERE wallet IN ({q})", (*wallet_ids,)
q = ",".join([f"'{w}'" for w in wallet_ids])
return await db.fetchall(
f"SELECT * FROM subdomains.domain WHERE wallet IN ({q})", model=Domain
)

return [Domains(**row) for row in rows]


async def delete_domain(domain_id: str) -> None:
await db.execute("DELETE FROM subdomains.domain WHERE id = ?", (domain_id,))
await db.execute("DELETE FROM subdomains.domain WHERE id = :id", {"id": domain_id})
16 changes: 6 additions & 10 deletions migrations.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
async def m001_initial(db):

await db.execute(
"""
f"""
CREATE TABLE subdomains.domain (
id TEXT PRIMARY KEY,
wallet TEXT NOT NULL,
Expand All @@ -13,15 +13,13 @@ async def m001_initial(db):
cost INTEGER NOT NULL,
amountmade INTEGER NOT NULL,
allowed_record_types TEXT NOT NULL,
time TIMESTAMP NOT NULL DEFAULT """
+ db.timestamp_now
+ """
time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
);
"""
"""
)

await db.execute(
"""
f"""
CREATE TABLE subdomains.subdomain (
id TEXT PRIMARY KEY,
domain TEXT NOT NULL,
Expand All @@ -33,9 +31,7 @@ async def m001_initial(db):
duration INTEGER NOT NULL,
paid BOOLEAN NOT NULL,
record_type TEXT NOT NULL,
time TIMESTAMP NOT NULL DEFAULT """
+ db.timestamp_now
+ """
time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
);
"""
"""
)
14 changes: 8 additions & 6 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from datetime import datetime, timezone

from fastapi import Query
from pydantic import BaseModel

Expand All @@ -23,7 +25,7 @@ class CreateSubdomain(BaseModel):
record_type: str = Query(...)


class Domains(BaseModel):
class Domain(BaseModel):
id: str
wallet: str
domain: str
Expand All @@ -32,12 +34,12 @@ class Domains(BaseModel):
webhook: str
description: str
cost: int
amountmade: int
time: int
allowed_record_types: str
amountmade: int = 0
time: datetime = datetime.now(timezone.utc)


class Subdomains(BaseModel):
class Subdomain(BaseModel):
id: str
wallet: str
domain: str
Expand All @@ -47,6 +49,6 @@ class Subdomains(BaseModel):
ip: str
sats: int
duration: int
paid: bool
time: int
record_type: str
paid: bool = False
time: datetime = datetime.now(timezone.utc)
Loading