Merge pull request #1361 from lnbits/tinyurl

Adds universal tinyurl redirect for lnurls and the like
This commit is contained in:
Arc 2023-01-24 21:40:07 +00:00 committed by GitHub
commit 0de2a62159
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 147 additions and 2 deletions

View file

@ -4,12 +4,14 @@ from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
from uuid import uuid4
import shortuuid
from lnbits import bolt11
from lnbits.db import COCKROACH, POSTGRES, Connection
from lnbits.settings import AdminSettings, EditableSettings, SuperSettings, settings
from . import db
from .models import BalanceCheck, Payment, User, Wallet
from .models import BalanceCheck, Payment, TinyURL, User, Wallet
# accounts
# --------
@ -620,3 +622,44 @@ async def create_admin_settings(super_user: str, new_settings: dict):
sql = f"INSERT INTO settings (super_user, editable_settings) VALUES (?, ?)"
await db.execute(sql, (super_user, json.dumps(new_settings)))
return await get_super_settings()
# tinyurl
# -------
async def create_tinyurl(domain: str, endless: bool, wallet: str):
tinyurl_id = shortuuid.uuid()[:8]
await db.execute(
f"INSERT INTO tiny_url (id, url, endless, wallet) VALUES (?, ?, ?, ?)",
(
tinyurl_id,
domain,
endless,
wallet,
),
)
return await get_tinyurl(tinyurl_id)
async def get_tinyurl(tinyurl_id: str) -> Optional[TinyURL]:
row = await db.fetchone(
f"SELECT * FROM tiny_url WHERE id = ?",
(tinyurl_id,),
)
return TinyURL.from_row(row) if row else None
async def get_tinyurl_by_url(url: str) -> List[TinyURL]:
rows = await db.fetchall(
f"SELECT * FROM tiny_url WHERE url = ?",
(url,),
)
return [TinyURL.from_row(row) for row in rows]
async def delete_tinyurl(tinyurl_id: str):
row = await db.execute(
f"DELETE FROM tiny_url WHERE id = ?",
(tinyurl_id,),
)

View file

@ -269,3 +269,17 @@ async def m008_create_admin_settings_table(db):
);
"""
)
async def m009_create_tinyurl_table(db):
await db.execute(
f"""
CREATE TABLE IF NOT EXISTS tiny_url (
id TEXT PRIMARY KEY,
url TEXT,
endless BOOL NOT NULL DEFAULT false,
wallet TEXT,
time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
);
"""
)

View file

@ -213,3 +213,15 @@ class BalanceCheck(BaseModel):
@classmethod
def from_row(cls, row: Row):
return cls(wallet=row["wallet"], service=row["service"], url=row["url"])
class TinyURL(BaseModel):
id: str
url: str
endless: bool
wallet: str
time: float
@classmethod
def from_row(cls, row: Row):
return cls(**dict(row))

View file

@ -26,7 +26,7 @@ from loguru import logger
from pydantic import BaseModel
from pydantic.fields import Field
from sse_starlette.sse import EventSourceResponse
from starlette.responses import StreamingResponse
from starlette.responses import RedirectResponse, StreamingResponse
from lnbits import bolt11, lnurl
from lnbits.core.models import Payment, Wallet
@ -47,8 +47,12 @@ from lnbits.utils.exchange_rates import (
from .. import core_app, db
from ..crud import (
create_tinyurl,
delete_tinyurl,
get_payments,
get_standalone_payment,
get_tinyurl,
get_tinyurl_by_url,
get_total_balance,
get_wallet_for_key,
save_balance_check,
@ -706,3 +710,75 @@ async def websocket_update_get(item_id: str, data: str):
return {"sent": True, "data": data}
except:
return {"sent": False, "data": data}
############################TINYURL##################################
@core_app.post("/api/v1/tinyurl")
async def api_create_tinyurl(
url: str, endless: bool = False, wallet: WalletTypeInfo = Depends(get_key_type)
):
tinyurls = await get_tinyurl_by_url(url)
try:
for tinyurl in tinyurls:
if tinyurl:
if tinyurl.wallet == wallet.wallet.inkey:
return tinyurl
return await create_tinyurl(url, endless, wallet.wallet.inkey)
except:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="Unable to create tinyurl"
)
@core_app.get("/api/v1/tinyurl/{tinyurl_id}")
async def api_get_tinyurl(
tinyurl_id: str, wallet: WalletTypeInfo = Depends(get_key_type)
):
try:
tinyurl = await get_tinyurl(tinyurl_id)
if tinyurl:
if tinyurl.wallet == wallet.wallet.inkey:
return tinyurl
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN, detail="Wrong key provided."
)
except:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Unable to fetch tinyurl"
)
@core_app.delete("/api/v1/tinyurl/{tinyurl_id}")
async def api_delete_tinyurl(
tinyurl_id: str, wallet: WalletTypeInfo = Depends(get_key_type)
):
try:
tinyurl = await get_tinyurl(tinyurl_id)
if tinyurl:
if tinyurl.wallet == wallet.wallet.inkey:
await delete_tinyurl(tinyurl_id)
return {"deleted": True}
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN, detail="Wrong key provided."
)
except:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="Unable to delete"
)
@core_app.get("/t/{tinyurl_id}")
async def api_tinyurl(tinyurl_id: str):
try:
tinyurl = await get_tinyurl(tinyurl_id)
if tinyurl:
response = RedirectResponse(url=tinyurl.url)
return response
else:
return
except:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="unable to find tinyurl"
)