diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..bac6100 --- /dev/null +++ b/__init__.py @@ -0,0 +1,38 @@ +import asyncio + +from fastapi import APIRouter +from starlette.staticfiles import StaticFiles + +from lnbits.db import Database +from lnbits.helpers import template_renderer +from lnbits.tasks import catch_everything_and_restart + +db = Database("ext_nostrmarket") + +market_ext: APIRouter = APIRouter(prefix="/nostrmarket", tags=["nostrmarket"]) + +market_static_files = [ + { + "path": "/nostrmarket/static", + "app": StaticFiles(directory="lnbits/extensions/nostrmarket/static"), + "name": "nostrmarket_static", + } +] + + +def market_renderer(): + return template_renderer(["lnbits/extensions/nostrmarket/templates"]) + + +scheduled_tasks: List[asyncio.Task] = [] + +from .tasks import subscribe_nostrclient_ws, wait_for_paid_invoices +from .views import * # noqa +from .views_api import * # noqa + + +def nostrmarket_start(): + loop = asyncio.get_event_loop() + task1 = loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) + task2 = loop.create_task(catch_everything_and_restart(subscribe_nostrclient_ws)) + scheduled_tasks.append([task1, task2]) diff --git a/config.json b/config.json index e69de29..078ffd9 100644 --- a/config.json +++ b/config.json @@ -0,0 +1,6 @@ +{ + "name": "Nostr Market", + "short_description": "Nostr Webshop/market on LNbits", + "tile": "", + "contributors": [] +} diff --git a/migrations.py b/migrations.py index f7ce7d0..e69de29 100644 --- a/migrations.py +++ b/migrations.py @@ -1,302 +0,0 @@ -async def m001_initial(db): - """ - Initial Market settings table. - """ - await db.execute( - """ - CREATE TABLE market.settings ( - "user" TEXT PRIMARY KEY, - currency TEXT DEFAULT 'sat', - fiat_base_multiplier INTEGER DEFAULT 1 - ); - """ - ) - - """ - Initial stalls table. - """ - await db.execute( - """ - CREATE TABLE market.stalls ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - name TEXT NOT NULL, - currency TEXT, - publickey TEXT, - relays TEXT, - shippingzones TEXT NOT NULL, - rating INTEGER DEFAULT 0 - ); - """ - ) - - """ - Initial products table. - """ - await db.execute( - f""" - CREATE TABLE market.products ( - id TEXT PRIMARY KEY, - stall TEXT NOT NULL REFERENCES {db.references_schema}stalls (id) ON DELETE CASCADE, - product TEXT NOT NULL, - categories TEXT, - description TEXT, - image TEXT, - price INTEGER NOT NULL, - quantity INTEGER NOT NULL, - rating INTEGER DEFAULT 0 - ); - """ - ) - - """ - Initial zones table. - """ - await db.execute( - """ - CREATE TABLE market.zones ( - id TEXT PRIMARY KEY, - "user" TEXT NOT NULL, - cost TEXT NOT NULL, - countries TEXT NOT NULL - ); - """ - ) - - """ - Initial orders table. - """ - await db.execute( - f""" - CREATE TABLE market.orders ( - id {db.serial_primary_key}, - wallet TEXT NOT NULL, - username TEXT, - pubkey TEXT, - shippingzone TEXT NOT NULL, - address TEXT NOT NULL, - email TEXT NOT NULL, - total INTEGER NOT NULL, - invoiceid TEXT NOT NULL, - paid BOOLEAN NOT NULL, - shipped BOOLEAN NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - """ - Initial order details table. - """ - await db.execute( - f""" - CREATE TABLE market.order_details ( - id TEXT PRIMARY KEY, - order_id INTEGER NOT NULL REFERENCES {db.references_schema}orders (id) ON DELETE CASCADE, - product_id TEXT NOT NULL REFERENCES {db.references_schema}products (id) ON DELETE CASCADE, - quantity INTEGER NOT NULL - ); - """ - ) - - """ - Initial market table. - """ - await db.execute( - """ - CREATE TABLE market.markets ( - id TEXT PRIMARY KEY, - usr TEXT NOT NULL, - name TEXT - ); - """ - ) - - """ - Initial market stalls table. - """ - await db.execute( - f""" - CREATE TABLE market.market_stalls ( - id TEXT PRIMARY KEY, - marketid TEXT NOT NULL REFERENCES {db.references_schema}markets (id) ON DELETE CASCADE, - stallid TEXT NOT NULL REFERENCES {db.references_schema}stalls (id) ON DELETE CASCADE - ); - """ - ) - - """ - Initial chat messages table. - """ - await db.execute( - f""" - CREATE TABLE market.messages ( - id {db.serial_primary_key}, - msg TEXT NOT NULL, - pubkey TEXT NOT NULL, - id_conversation TEXT NOT NULL, - timestamp TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - if db.type != "SQLITE": - """ - Create indexes for message fetching - """ - await db.execute( - "CREATE INDEX idx_messages_timestamp ON market.messages (timestamp DESC)" - ) - await db.execute( - "CREATE INDEX idx_messages_conversations ON market.messages (id_conversation)" - ) - - -async def m002_add_custom_relays(db): - """ - Add custom relays to stores - """ - await db.execute("ALTER TABLE market.stalls ADD COLUMN crelays TEXT;") - - -async def m003_fiat_base_multiplier(db): - """ - Store the multiplier for fiat prices. We store the price in cents and - remember to multiply by 100 when we use it to convert to Dollars. - """ - await db.execute( - "ALTER TABLE market.stalls ADD COLUMN fiat_base_multiplier INTEGER DEFAULT 1;" - ) - - await db.execute( - "UPDATE market.stalls SET fiat_base_multiplier = 100 WHERE NOT currency = 'sat';" - ) - - -async def m004_add_privkey_to_stalls(db): - await db.execute("ALTER TABLE market.stalls ADD COLUMN privatekey TEXT") - - -async def m005_add_currency_to_zones(db): - await db.execute("ALTER TABLE market.zones ADD COLUMN stall TEXT") - await db.execute("ALTER TABLE market.zones ADD COLUMN currency TEXT DEFAULT 'sat'") - - -async def m006_delete_market_settings(db): - await db.execute("DROP TABLE market.settings") - - -async def m007_order_id_to_UUID(db): - """ - Migrate ID column type to string for UUIDs and migrate existing data - """ - - await db.execute("ALTER TABLE market.orders RENAME TO orders_old") - await db.execute( - f""" - CREATE TABLE market.orders ( - id TEXT PRIMARY KEY, - wallet TEXT NOT NULL, - username TEXT, - pubkey TEXT, - shippingzone TEXT NOT NULL, - address TEXT NOT NULL, - email TEXT NOT NULL, - total INTEGER NOT NULL, - invoiceid TEXT NOT NULL, - paid BOOLEAN NOT NULL, - shipped BOOLEAN NOT NULL, - time TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - for row in [ - list(row) for row in await db.fetchall("SELECT * FROM market.orders_old") - ]: - await db.execute( - """ - INSERT INTO market.orders ( - id, - wallet, - username, - pubkey, - shippingzone, - address, - email, - total, - invoiceid, - paid, - shipped, - time - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - str(row[0]), - row[1], - row[2], - row[3], - row[4], - row[5], - row[6], - row[7], - row[8], - row[9], - row[10], - int(row[11]), - ), - ) - - await db.execute("DROP TABLE market.orders_old") - - -async def m008_message_id_to_TEXT(db): - """ - Migrate ID column type to string for UUIDs and migrate existing data - """ - - await db.execute("ALTER TABLE market.messages RENAME TO messages_old") - await db.execute( - f""" - CREATE TABLE market.messages ( - id TEXT PRIMARY KEY, - msg TEXT NOT NULL, - pubkey TEXT NOT NULL, - id_conversation TEXT NOT NULL, - timestamp TIMESTAMP NOT NULL DEFAULT """ - + db.timestamp_now - + """ - ); - """ - ) - - for row in [ - list(row) for row in await db.fetchall("SELECT * FROM market.messages_old") - ]: - await db.execute( - """ - INSERT INTO market.messages( - id, - msg, - pubkey, - id_conversation, - timestamp - ) VALUES (?, ?, ?, ?, ?) - """, - ( - str(row[0]), - row[1], - row[2], - row[3], - int(row[4]), - ), - ) - - await db.execute("DROP TABLE market.messages_old") diff --git a/views.py b/views.py new file mode 100644 index 0000000..568d515 --- /dev/null +++ b/views.py @@ -0,0 +1,22 @@ +import json +from http import HTTPStatus + +from fastapi import Depends, Request, HTMLResponse +from fastapi.templating import Jinja2Templates +from loguru import logger + +from lnbits.core.models import User +from lnbits.decorators import check_user_exists + +from . import nostrmarket_ext, nostrmarket_renderer + + +templates = Jinja2Templates(directory="templates") + + +@nostrmarket_ext.get("/", response_class=HTMLResponse) +async def index(request: Request, user: User = Depends(check_user_exists)): + return nostrmarket_renderer().TemplateResponse( + "nostrmarket/index.html", + {"request": request, "user": user.dict()}, + )