From 6b2f3d05d51d7aabe8a00dac10f9dfc3d96134a9 Mon Sep 17 00:00:00 2001
From: benarc
Date: Thu, 27 Jan 2022 12:24:38 +0000
Subject: [PATCH 001/226] initial
---
lnbits/extensions/diagonalley/README.md | 9 +
lnbits/extensions/diagonalley/__init__.py | 16 +
lnbits/extensions/diagonalley/config.json | 6 +
lnbits/extensions/diagonalley/crud.py | 395 +++++++++
lnbits/extensions/diagonalley/migrations.py | 69 ++
lnbits/extensions/diagonalley/models.py | 57 ++
.../extensions/diagonalley/static/js/index.js | 824 ++++++++++++++++++
lnbits/extensions/diagonalley/tasks.py | 29 +
.../templates/diagonalley/_api_docs.html | 129 +++
.../templates/diagonalley/index.html | 634 ++++++++++++++
.../templates/diagonalley/stall.html | 9 +
lnbits/extensions/diagonalley/views.py | 44 +
lnbits/extensions/diagonalley/views_api.py | 348 ++++++++
13 files changed, 2569 insertions(+)
create mode 100644 lnbits/extensions/diagonalley/README.md
create mode 100644 lnbits/extensions/diagonalley/__init__.py
create mode 100644 lnbits/extensions/diagonalley/config.json
create mode 100644 lnbits/extensions/diagonalley/crud.py
create mode 100644 lnbits/extensions/diagonalley/migrations.py
create mode 100644 lnbits/extensions/diagonalley/models.py
create mode 100644 lnbits/extensions/diagonalley/static/js/index.js
create mode 100644 lnbits/extensions/diagonalley/tasks.py
create mode 100644 lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html
create mode 100644 lnbits/extensions/diagonalley/templates/diagonalley/index.html
create mode 100644 lnbits/extensions/diagonalley/templates/diagonalley/stall.html
create mode 100644 lnbits/extensions/diagonalley/views.py
create mode 100644 lnbits/extensions/diagonalley/views_api.py
diff --git a/lnbits/extensions/diagonalley/README.md b/lnbits/extensions/diagonalley/README.md
new file mode 100644
index 00000000..e8035b74
--- /dev/null
+++ b/lnbits/extensions/diagonalley/README.md
@@ -0,0 +1,9 @@
+Diagon Alley
+A movable market stand
+Make a list of products to sell, point the list to an relay (or many), stack sats.
+Diagon Alley is a movable market stand, for anon transactions. You then give permission for an relay to list those products. Delivery addresses are sent through the Lightning Network.
+
+
+API endpoints
+
+curl -X GET http://YOUR-TOR-ADDRESS
diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py
new file mode 100644
index 00000000..720c55c8
--- /dev/null
+++ b/lnbits/extensions/diagonalley/__init__.py
@@ -0,0 +1,16 @@
+from quart import Blueprint
+from lnbits.db import Database
+
+db = Database("ext_diagonalley")
+
+diagonalley_ext: Blueprint = Blueprint(
+ "diagonalley", __name__, static_folder="static", template_folder="templates"
+)
+
+from .views_api import * # noqa
+from .views import * # noqa
+
+from .tasks import register_listeners
+from lnbits.tasks import record_async
+
+diagonalley_ext.record(record_async(register_listeners))
diff --git a/lnbits/extensions/diagonalley/config.json b/lnbits/extensions/diagonalley/config.json
new file mode 100644
index 00000000..99e92e9b
--- /dev/null
+++ b/lnbits/extensions/diagonalley/config.json
@@ -0,0 +1,6 @@
+{
+ "name": "Diagon Alley",
+ "short_description": "Movable anonymous market stand",
+ "icon": "add_shopping_cart",
+ "contributors": ["benarc","DeanH"]
+}
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
new file mode 100644
index 00000000..c6ce8222
--- /dev/null
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -0,0 +1,395 @@
+from base64 import urlsafe_b64encode
+from uuid import uuid4
+from typing import List, Optional, Union
+
+from lnbits.settings import WALLET
+
+# from lnbits.db import open_ext_db
+from lnbits.db import SQLITE
+from . import db
+from .models import Products, Orders, Stalls, Zones
+
+import httpx
+from lnbits.helpers import urlsafe_short_hash
+import re
+
+regex = re.compile(
+ r"^(?:http|ftp)s?://" # http:// or https://
+ r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|"
+ r"localhost|"
+ r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
+ r"(?::\d+)?"
+ r"(?:/?|[/?]\S+)$",
+ re.IGNORECASE,
+)
+
+
+###Products
+
+
+async def create_diagonalley_product(
+ *,
+ stall_id: str,
+ product: str,
+ categories: str,
+ description: str,
+ image: Optional[str] = None,
+ price: int,
+ quantity: int,
+ shippingzones: str,
+) -> Products:
+ returning = "" if db.type == SQLITE else "RETURNING ID"
+ method = db.execute if db.type == SQLITE else db.fetchone
+ product_id = urlsafe_short_hash()
+ # with open_ext_db("diagonalley") as db:
+ result = await (method)(
+ f"""
+ INSERT INTO diagonalley.products (id, stall, product, categories, description, image, price, quantity, shippingzones)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ {returning}
+ """,
+ (
+ product_id,
+ stall_id,
+ product,
+ categories,
+ description,
+ image,
+ price,
+ quantity,
+ ),
+ )
+ product = await get_diagonalley_product(product_id)
+ assert product, "Newly created product couldn't be retrieved"
+ return product
+
+
+async def update_diagonalley_product(product_id: str, **kwargs) -> Optional[Stalls]:
+ q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
+
+ # with open_ext_db("diagonalley") as db:
+ await db.execute(
+ f"UPDATE diagonalley.products SET {q} WHERE id = ?",
+ (*kwargs.values(), product_id),
+ )
+ row = await db.fetchone(
+ "SELECT * FROM diagonalley.products WHERE id = ?", (product_id,)
+ )
+
+ return get_diagonalley_stall(product_id)
+
+
+async def get_diagonalley_product(product_id: str) -> Optional[Products]:
+ row = await db.fetchone(
+ "SELECT * FROM diagonalley.products WHERE id = ?", (product_id,)
+ )
+ return Products.from_row(row) if row else None
+
+
+async def get_diagonalley_products(wallet_ids: Union[str, List[str]]) -> List[Products]:
+ if isinstance(wallet_ids, str):
+ wallet_ids = [wallet_ids]
+
+ # with open_ext_db("diagonalley") as db:
+ q = ",".join(["?"] * len(wallet_ids))
+ rows = await db.fetchall(
+ f"""
+ SELECT * FROM diagonalley.products WHERE stall IN ({q})
+ """,
+ (*wallet_ids,),
+ )
+ return [Products.from_row(row) for row in rows]
+
+
+async def delete_diagonalley_product(product_id: str) -> None:
+ await db.execute("DELETE FROM diagonalley.products WHERE id = ?", (product_id,))
+
+
+###zones
+
+
+async def create_diagonalley_zone(
+ *,
+ wallet: Optional[str] = None,
+ cost: Optional[int] = 0,
+ countries: Optional[str] = None,
+) -> Zones:
+
+ returning = "" if db.type == SQLITE else "RETURNING ID"
+ method = db.execute if db.type == SQLITE else db.fetchone
+
+ zone_id = urlsafe_short_hash()
+ result = await (method)(
+ f"""
+ INSERT INTO diagonalley.zones (
+ id,
+ wallet,
+ cost,
+ countries
+
+ )
+ VALUES (?, ?, ?, ?)
+ {returning}
+ """,
+ (zone_id, wallet, cost, countries),
+ )
+
+ zone = await get_diagonalley_zone(zone_id)
+ assert zone, "Newly created zone couldn't be retrieved"
+ return zone
+
+
+async def update_diagonalley_zone(zone_id: str, **kwargs) -> Optional[Zones]:
+ q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
+ await db.execute(
+ f"UPDATE diagonalley.zones SET {q} WHERE id = ?",
+ (*kwargs.values(), zone_id),
+ )
+ row = await db.fetchone("SELECT * FROM diagonalley.zones WHERE id = ?", (zone_id,))
+ return Zones.from_row(row) if row else None
+
+
+async def get_diagonalley_zone(zone_id: str) -> Optional[Zones]:
+ row = await db.fetchone("SELECT * FROM diagonalley.zones WHERE id = ?", (zone_id,))
+ return Zones.from_row(row) if row else None
+
+
+async def get_diagonalley_zones(wallet_ids: Union[str, List[str]]) -> List[Zones]:
+ if isinstance(wallet_ids, str):
+ wallet_ids = [wallet_ids]
+ print(wallet_ids)
+
+ q = ",".join(["?"] * len(wallet_ids))
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
+ )
+
+ for r in rows:
+ try:
+ x = httpx.get(r["zoneaddress"] + "/" + r["ratingkey"])
+ if x.status_code == 200:
+ await db.execute(
+ "UPDATE diagonalley.zones SET online = ? WHERE id = ?",
+ (
+ True,
+ r["id"],
+ ),
+ )
+ else:
+ await db.execute(
+ "UPDATE diagonalley.zones SET online = ? WHERE id = ?",
+ (
+ False,
+ r["id"],
+ ),
+ )
+ except:
+ print("An exception occurred")
+ q = ",".join(["?"] * len(wallet_ids))
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
+ )
+ return [Zones.from_row(row) for row in rows]
+
+
+async def delete_diagonalley_zone(zone_id: str) -> None:
+ await db.execute("DELETE FROM diagonalley.zones WHERE id = ?", (zone_id,))
+
+
+###Stalls
+
+
+async def create_diagonalley_stall(
+ *,
+ wallet: str,
+ name: str,
+ publickey: str,
+ privatekey: str,
+ relays: str,
+ shippingzones: str,
+) -> Stalls:
+
+ returning = "" if db.type == SQLITE else "RETURNING ID"
+ method = db.execute if db.type == SQLITE else db.fetchone
+
+ stall_id = urlsafe_short_hash()
+ result = await (method)(
+ f"""
+ INSERT INTO diagonalley.stalls (
+ id,
+ wallet,
+ name,
+ publickey,
+ privatekey,
+ relays,
+ shippingzones
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ {returning}
+ """,
+ (stall_id, wallet, name, publickey, privatekey, relays, shippingzones),
+ )
+
+ stall = await get_diagonalley_stall(stall_id)
+ assert stall, "Newly created stall couldn't be retrieved"
+ return stall
+
+
+async def update_diagonalley_stall(stall_id: str, **kwargs) -> Optional[Stalls]:
+ q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
+ await db.execute(
+ f"UPDATE diagonalley.stalls SET {q} WHERE id = ?",
+ (*kwargs.values(), stall_id),
+ )
+ row = await db.fetchone(
+ "SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
+ )
+ return Stalls.from_row(row) if row else None
+
+
+async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
+ roww = await db.fetchone(
+ "SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
+ )
+
+ try:
+ x = httpx.get(roww["stalladdress"] + "/" + roww["ratingkey"])
+ if x.status_code == 200:
+ await db.execute(
+ "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
+ (
+ True,
+ stall_id,
+ ),
+ )
+ else:
+ await db.execute(
+ "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
+ (
+ False,
+ stall_id,
+ ),
+ )
+ except:
+ print("An exception occurred")
+
+ # with open_ext_db("diagonalley") as db:
+ row = await db.fetchone(
+ "SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
+ )
+ return Stalls.from_row(row) if row else None
+
+
+async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]:
+ if isinstance(wallet_ids, str):
+ wallet_ids = [wallet_ids]
+
+ q = ",".join(["?"] * len(wallet_ids))
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
+ )
+
+ for r in rows:
+ try:
+ x = httpx.get(r["stalladdress"] + "/" + r["ratingkey"])
+ if x.status_code == 200:
+ await db.execute(
+ "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
+ (
+ True,
+ r["id"],
+ ),
+ )
+ else:
+ await db.execute(
+ "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
+ (
+ False,
+ r["id"],
+ ),
+ )
+ except:
+ print("An exception occurred")
+ q = ",".join(["?"] * len(wallet_ids))
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
+ )
+ return [Stalls.from_row(row) for row in rows]
+
+
+async def delete_diagonalley_stall(stall_id: str) -> None:
+ await db.execute("DELETE FROM diagonalley.stalls WHERE id = ?", (stall_id,))
+
+
+###Orders
+
+
+async def create_diagonalley_order(
+ *,
+ productid: str,
+ wallet: str,
+ product: str,
+ quantity: int,
+ shippingzone: str,
+ address: str,
+ email: str,
+ invoiceid: str,
+ paid: bool,
+ shipped: bool,
+) -> Orders:
+ returning = "" if db.type == SQLITE else "RETURNING ID"
+ method = db.execute if db.type == SQLITE else db.fetchone
+
+ order_id = urlsafe_short_hash()
+ result = await (method)(
+ f"""
+ INSERT INTO diagonalley.orders (id, productid, wallet, product,
+ quantity, shippingzone, address, email, invoiceid, paid, shipped)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ {returning}
+ """,
+ (
+ order_id,
+ productid,
+ wallet,
+ product,
+ quantity,
+ shippingzone,
+ address,
+ email,
+ invoiceid,
+ False,
+ False,
+ ),
+ )
+ if db.type == SQLITE:
+ order_id = result._result_proxy.lastrowid
+ else:
+ order_id = result[0]
+
+ link = await get_diagonalley_order(order_id)
+ assert link, "Newly created link couldn't be retrieved"
+ return link
+
+
+async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
+ row = await db.fetchone(
+ "SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
+ )
+ return Orders.from_row(row) if row else None
+
+
+async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
+ if isinstance(wallet_ids, str):
+ wallet_ids = [wallet_ids]
+
+ q = ",".join(["?"] * len(wallet_ids))
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.orders WHERE wallet IN ({q})", (*wallet_ids,)
+ )
+ #
+ return [Orders.from_row(row) for row in rows]
+
+
+async def delete_diagonalley_order(order_id: str) -> None:
+ await db.execute("DELETE FROM diagonalley.orders WHERE id = ?", (order_id,))
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
new file mode 100644
index 00000000..1523f398
--- /dev/null
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -0,0 +1,69 @@
+async def m001_initial(db):
+ """
+ Initial products table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE diagonalley.products (
+ id TEXT PRIMARY KEY,
+ stall TEXT NOT NULL,
+ product TEXT NOT NULL,
+ categories TEXT NOT NULL,
+ description TEXT NOT NULL,
+ image TEXT NOT NULL,
+ price INTEGER NOT NULL,
+ quantity INTEGER NOT NULL
+ );
+ """
+ )
+
+ """
+ Initial stalls table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE diagonalley.stalls (
+ id TEXT PRIMARY KEY,
+ wallet TEXT NOT NULL,
+ name TEXT NOT NULL,
+ publickey TEXT NOT NULL,
+ privatekey TEXT NOT NULL,
+ relays TEXT NOT NULL
+ );
+ """
+ )
+
+ """
+ Initial zones table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE diagonalley.zones (
+ id TEXT PRIMARY KEY,
+ wallet TEXT NOT NULL,
+ cost TEXT NOT NULL,
+ countries TEXT NOT NULL
+ );
+ """
+ )
+
+ """
+ Initial orders table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE diagonalley.orders (
+ id TEXT PRIMARY KEY,
+ productid TEXT NOT NULL,
+ wallet TEXT NOT NULL,
+ product TEXT NOT NULL,
+ quantity INTEGER NOT NULL,
+ shippingzone INTEGER NOT NULL,
+ address TEXT NOT NULL,
+ email TEXT NOT NULL,
+ invoiceid TEXT NOT NULL,
+ paid BOOLEAN NOT NULL,
+ shipped BOOLEAN NOT NULL
+ );
+ """
+ )
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
new file mode 100644
index 00000000..0f2a1d78
--- /dev/null
+++ b/lnbits/extensions/diagonalley/models.py
@@ -0,0 +1,57 @@
+from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult
+from starlette.requests import Request
+from fastapi.param_functions import Query
+from typing import Optional, Dict
+from lnbits.lnurl import encode as lnurl_encode # type: ignore
+from lnurl.types import LnurlPayMetadata # type: ignore
+from pydantic import BaseModel
+import json
+from sqlite3 import Row
+
+
+class Stalls(BaseModel):
+ id: str = Query(None)
+ wallet: str = Query(None)
+ name: str = Query(None)
+ publickey: str = Query(None)
+ privatekey: str = Query(None)
+ relays: str = Query(None)
+
+class createStalls(BaseModel):
+ wallet: str = Query(None)
+ name: str = Query(None)
+ publickey: str = Query(None)
+ privatekey: str = Query(None)
+ relays: str = Query(None)
+ shippingzones: str = Query(None)
+
+class Products(BaseModel):
+ id: str = Query(None)
+ stall: str = Query(None)
+ product: str = Query(None)
+ categories: str = Query(None)
+ description: str = Query(None)
+ image: str = Query(None)
+ price: int = Query(0)
+ quantity: int = Query(0)
+
+
+class Zones(BaseModel):
+ id: str = Query(None)
+ wallet: str = Query(None)
+ cost: str = Query(None)
+ countries: str = Query(None)
+
+
+class Orders(BaseModel):
+ id: str = Query(None)
+ productid: str = Query(None)
+ stall: str = Query(None)
+ product: str = Query(None)
+ quantity: int = Query(0)
+ shippingzone: int = Query(0)
+ address: str = Query(None)
+ email: str = Query(None)
+ invoiceid: str = Query(None)
+ paid: bool
+ shipped: bool
diff --git a/lnbits/extensions/diagonalley/static/js/index.js b/lnbits/extensions/diagonalley/static/js/index.js
new file mode 100644
index 00000000..1a25edaa
--- /dev/null
+++ b/lnbits/extensions/diagonalley/static/js/index.js
@@ -0,0 +1,824 @@
+/* globals Quasar, Vue, _, VueQrcode, windowMixin, LNbits, LOCALE */
+
+Vue.component(VueQrcode.name, VueQrcode)
+
+const pica = window.pica()
+
+new Vue({
+ el: '#vue',
+ mixins: [windowMixin],
+ data: function () {
+ return {
+ products: [],
+ orders: [],
+ stalls: [],
+ zones: [],
+ shippedModel: false,
+ shippingZoneOptions: [
+ 'Australia',
+ 'Austria',
+ 'Belgium',
+ 'Brazil',
+ 'Canada',
+ 'Denmark',
+ 'Finland',
+ 'France*',
+ 'Germany',
+ 'Greece',
+ 'Hong Kong',
+ 'Hungary',
+ 'Ireland',
+ 'Indonesia',
+ 'Israel',
+ 'Italy',
+ 'Japan',
+ 'Kazakhstan',
+ 'Korea',
+ 'Luxembourg',
+ 'Malaysia',
+ 'Mexico',
+ 'Netherlands',
+ 'New Zealand',
+ 'Norway',
+ 'Poland',
+ 'Portugal',
+ 'Russia',
+ 'Saudi Arabia',
+ 'Singapore',
+ 'Spain',
+ 'Sweden',
+ 'Switzerland',
+ 'Thailand',
+ 'Turkey',
+ 'Ukraine',
+ 'United Kingdom**',
+ 'United States***',
+ 'Vietnam',
+ 'China'
+ ],
+ categories: [
+ 'Fashion (clothing and accessories)',
+ 'Health (and beauty)',
+ 'Toys (and baby equipment)',
+ 'Media (Books and CDs)',
+ 'Groceries (Food and Drink)',
+ 'Technology (Phones and Computers)',
+ 'Home (furniture and accessories)',
+ 'Gifts (flowers, cards, etc)'
+ ],
+ relayOptions: [
+ 'wss://nostr-relay.herokuapp.com/ws',
+ 'wss://nostr-relay.bigsun.xyz/ws',
+ 'wss://freedom-relay.herokuapp.com/ws'
+ ],
+ label: '',
+ ordersTable: {
+ columns: [
+ {
+ name: 'product',
+ align: 'left',
+ label: 'Product',
+ field: 'product'
+ },
+ {
+ name: 'quantity',
+ align: 'left',
+ label: 'Quantity',
+ field: 'quantity'
+ },
+ {
+ name: 'address',
+ align: 'left',
+ label: 'Address',
+ field: 'address'
+ },
+ {
+ name: 'invoiceid',
+ align: 'left',
+ label: 'InvoiceID',
+ field: 'invoiceid'
+ },
+ {name: 'paid', align: 'left', label: 'Paid', field: 'paid'},
+ {name: 'shipped', align: 'left', label: 'Shipped', field: 'shipped'}
+ ],
+ pagination: {
+ rowsPerPage: 10
+ }
+ },
+ productsTable: {
+ columns: [
+ {
+ name: 'stall',
+ align: 'left',
+ label: 'Stall',
+ field: 'stall'
+ },
+ {
+ name: 'product',
+ align: 'left',
+ label: 'Product',
+ field: 'product'
+ },
+ {
+ name: 'description',
+ align: 'left',
+ label: 'Description',
+ field: 'description'
+ },
+ {
+ name: 'categories',
+ align: 'left',
+ label: 'Categories',
+ field: 'categories'
+ },
+ {name: 'price', align: 'left', label: 'Price', field: 'price'},
+ {
+ name: 'quantity',
+ align: 'left',
+ label: 'Quantity',
+ field: 'quantity'
+ },
+ {name: 'id', align: 'left', label: 'ID', field: 'id'}
+ ],
+ pagination: {
+ rowsPerPage: 10
+ }
+ },
+ stallTable: {
+ columns: [
+ {
+ name: 'id',
+ align: 'left',
+ label: 'ID',
+ field: 'id'
+ },
+ {
+ name: 'name',
+ align: 'left',
+ label: 'Name',
+ field: 'name'
+ },
+ {
+ name: 'wallet',
+ align: 'left',
+ label: 'Wallet',
+ field: 'wallet'
+ },
+ {
+ name: 'publickey',
+ align: 'left',
+ label: 'Public key',
+ field: 'publickey'
+ },
+ {
+ name: 'privatekey',
+ align: 'left',
+ label: 'Private key',
+ field: 'privatekey'
+ }
+ ],
+ pagination: {
+ rowsPerPage: 10
+ }
+ },
+ zonesTable: {
+ columns: [
+ {
+ name: 'id',
+ align: 'left',
+ label: 'ID',
+ field: 'id'
+ },
+ {
+ name: 'countries',
+ align: 'left',
+ label: 'Countries',
+ field: 'countries'
+ },
+ {
+ name: 'cost',
+ align: 'left',
+ label: 'Cost',
+ field: 'cost'
+ }
+ ],
+ pagination: {
+ rowsPerPage: 10
+ }
+ },
+ productDialog: {
+ show: false,
+ data: {}
+ },
+ stallDialog: {
+ show: false,
+ data: {}
+ },
+ zoneDialog: {
+ show: false,
+ data: {}
+ },
+ shopDialog: {
+ show: false,
+ data: {activate: false}
+ },
+ orderDialog: {
+ show: false,
+ data: {}
+ },
+ relayDialog: {
+ show: false,
+ data: {}
+ }
+ }
+ },
+ computed: {
+ categoryOther: function () {
+ cats = trim(this.productDialog.data.categories.split(','))
+ for (let i = 0; i < cats.length; i++) {
+ if (cats[i] == 'Others') {
+ return true
+ }
+ }
+ return false
+ }
+ },
+ methods: {
+ ////////////////////////////////////////
+ ////////////////STALLS//////////////////
+ ////////////////////////////////////////
+ getStalls: function () {
+ var self = this
+ LNbits.api
+ .request(
+ 'GET',
+ '/diagonalley/api/v1/stalls?all_wallets',
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+ self.stalls = response.data.map(function (obj) {
+ console.log(obj)
+ return mapDiagonAlley(obj)
+ })
+ })
+ },
+ openStallUpdateDialog: function (linkId) {
+ var self = this
+ var link = _.findWhere(self.stalls, {id: linkId})
+
+ this.stallDialog.data = _.clone(link._data)
+ this.stallDialog.show = true
+ },
+ sendStallFormData: function () {
+ if (this.stallDialog.data.id) {
+ } else {
+ var data = {
+ name: this.stallDialog.data.name,
+ wallet: this.stallDialog.data.wallet,
+ publickey: this.stallDialog.data.publickey,
+ privatekey: this.stallDialog.data.privatekey,
+ relays: this.stallDialog.data.relays
+ }
+ }
+
+ if (this.stallDialog.data.id) {
+ this.updateStall(this.stallDialog.data)
+ } else {
+ this.createStall(data)
+ }
+ },
+ updateStall: function (data) {
+ var self = this
+ LNbits.api
+ .request(
+ 'PUT',
+ '/diagonalley/api/v1/stalls' + data.id,
+ _.findWhere(self.g.user.wallets, {
+ id: self.stallDialog.data.wallet
+ }).inkey,
+ _.pick(data, 'name', 'wallet', 'publickey', 'privatekey')
+ )
+ .then(function (response) {
+ self.stalls = _.reject(self.stalls, function (obj) {
+ return obj.id == data.id
+ })
+ self.stalls.push(mapDiagonAlley(response.data))
+ self.stallDialog.show = false
+ self.stallDialog.data = {}
+ data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ createStall: function (data) {
+ var self = this
+ LNbits.api
+ .request(
+ 'POST',
+ '/diagonalley/api/v1/stalls',
+ _.findWhere(self.g.user.wallets, {
+ id: self.stallDialog.data.wallet
+ }).inkey,
+ data
+ )
+ .then(function (response) {
+ self.stalls.push(mapDiagonAlley(response.data))
+ self.stallDialog.show = false
+ self.stallDialog.data = {}
+ data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ deleteStall: function (stallId) {
+ var self = this
+ var stall = _.findWhere(self.stalls, {id: stallId})
+
+ LNbits.utils
+ .confirmDialog('Are you sure you want to delete this Stall link?')
+ .onOk(function () {
+ LNbits.api
+ .request(
+ 'DELETE',
+ '/diagonalley/api/v1/stalls/' + stallId,
+ _.findWhere(self.g.user.wallets, {id: stall.wallet}).inkey
+ )
+ .then(function (response) {
+ self.stalls = _.reject(self.stalls, function (obj) {
+ return obj.id == stallId
+ })
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ })
+ },
+ exportStallsCSV: function () {
+ LNbits.utils.exportCSV(this.stallsTable.columns, this.stalls)
+ },
+ ////////////////////////////////////////
+ ///////////////PRODUCTS/////////////////
+ ////////////////////////////////////////
+ getProducts: function () {
+ var self = this
+
+ LNbits.api
+ .request(
+ 'GET',
+ '/diagonalley/api/v1/products?all_stalls',
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+ self.products = response.data.map(function (obj) {
+ return mapDiagonAlley(obj)
+ })
+ })
+ },
+ openProductUpdateDialog: function (linkId) {
+ var self = this
+ var link = _.findWhere(self.products, {id: linkId})
+
+ self.productDialog.data = _.clone(link._data)
+ self.productDialog.show = true
+ },
+ sendProductFormData: function () {
+ if (this.productDialog.data.id) {
+ } else {
+ var data = {
+ product: this.productDialog.data.product,
+ categories:
+ this.productDialog.data.categories +
+ this.productDialog.categoriesextra,
+ description: this.productDialog.data.description,
+ image: this.productDialog.data.image,
+ price: this.productDialog.data.price,
+ quantity: this.productDialog.data.quantity
+ }
+ }
+ if (this.productDialog.data.id) {
+ this.updateProduct(this.productDialog.data)
+ } else {
+ this.createProduct(data)
+ }
+ },
+ imageAdded(file) {
+ let blobURL = URL.createObjectURL(file)
+ let image = new Image()
+ image.src = blobURL
+ image.onload = async () => {
+ let canvas = document.createElement('canvas')
+ canvas.setAttribute('width', 100)
+ canvas.setAttribute('height', 100)
+ await pica.resize(image, canvas, {
+ quality: 0,
+ alpha: true,
+ unsharpAmount: 95,
+ unsharpRadius: 0.9,
+ unsharpThreshold: 70
+ })
+ this.productDialog.data.image = canvas.toDataURL()
+ this.productDialog = {...this.productDialog}
+ }
+ },
+ imageCleared() {
+ this.productDialog.data.image = null
+ this.productDialog = {...this.productDialog}
+ },
+ updateProduct: function (data) {
+ var self = this
+ LNbits.api
+ .request(
+ 'PUT',
+ '/diagonalley/api/v1/products' + data.id,
+ _.findWhere(self.g.user.wallets, {
+ id: self.productDialog.data.wallet
+ }).inkey,
+ _.pick(
+ data,
+ 'shopname',
+ 'relayaddress',
+ 'shippingzone1',
+ 'zone1cost',
+ 'shippingzone2',
+ 'zone2cost',
+ 'email'
+ )
+ )
+ .then(function (response) {
+ self.products = _.reject(self.products, function (obj) {
+ return obj.id == data.id
+ })
+ self.products.push(mapDiagonAlley(response.data))
+ self.productDialog.show = false
+ self.productDialog.data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ createProduct: function (data) {
+ var self = this
+ LNbits.api
+ .request(
+ 'POST',
+ '/diagonalley/api/v1/products',
+ _.findWhere(self.g.user.wallets, {
+ id: self.productDialog.data.wallet
+ }).inkey,
+ data
+ )
+ .then(function (response) {
+ self.products.push(mapDiagonAlley(response.data))
+ self.productDialog.show = false
+ self.productDialog.data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ deleteProduct: function (productId) {
+ var self = this
+ var product = _.findWhere(this.products, {id: productId})
+
+ LNbits.utils
+ .confirmDialog('Are you sure you want to delete this products link?')
+ .onOk(function () {
+ LNbits.api
+ .request(
+ 'DELETE',
+ '/diagonalley/api/v1/products/' + productId,
+ _.findWhere(self.g.user.wallets, {id: product.wallet}).inkey
+ )
+ .then(function (response) {
+ self.products = _.reject(self.products, function (obj) {
+ return obj.id == productId
+ })
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ })
+ },
+ exportProductsCSV: function () {
+ LNbits.utils.exportCSV(this.productsTable.columns, this.products)
+ },
+ ////////////////////////////////////////
+ //////////////////ZONE//////////////////
+ ////////////////////////////////////////
+ getZones: function () {
+ var self = this
+
+ LNbits.api
+ .request(
+ 'GET',
+ '/diagonalley/api/v1/zones?all_wallets',
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+ self.zones = response.data.map(function (obj) {
+ return mapDiagonAlley(obj)
+ })
+ })
+ },
+ openZoneUpdateDialog: function (linkId) {
+ var self = this
+ var link = _.findWhere(self.zones, {id: linkId})
+
+ this.zoneDialog.data = _.clone(link._data)
+ this.zoneDialog.show = true
+ },
+ sendZoneFormData: function () {
+ if (this.zoneDialog.data.id) {
+ } else {
+ var data = {
+ countries: toString(this.zoneDialog.data.countries),
+ cost: parseInt(this.zoneDialog.data.cost)
+ }
+ }
+
+ if (this.zoneDialog.data.id) {
+ this.updateZone(this.zoneDialog.data)
+ } else {
+ this.createZone(data)
+ }
+ },
+ updateZone: function (data) {
+ var self = this
+ LNbits.api
+ .request(
+ 'PUT',
+ '/diagonalley/api/v1/zones' + data.id,
+ _.findWhere(self.g.user.wallets, {
+ id: self.zoneDialog.data.wallet
+ }).inkey,
+ _.pick(data, 'countries', 'cost')
+ )
+ .then(function (response) {
+ self.zones = _.reject(self.zones, function (obj) {
+ return obj.id == data.id
+ })
+ self.zones.push(mapDiagonAlley(response.data))
+ self.zoneDialog.show = false
+ self.zoneDialog.data = {}
+ data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ createZone: function (data) {
+ var self = this
+ console.log(self.g.user.wallets[0])
+ console.log(data)
+ LNbits.api
+ .request(
+ 'POST',
+ '/diagonalley/api/v1/zones',
+ self.g.user.wallets[0].inkey,
+ data
+ )
+ .then(function (response) {
+ self.zones.push(mapDiagonAlley(response.data))
+ self.zoneDialog.show = false
+ self.zoneDialog.data = {}
+ data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ deleteZone: function (zoneId) {
+ var self = this
+ var zone = _.findWhere(self.zones, {id: zoneId})
+
+ LNbits.utils
+ .confirmDialog('Are you sure you want to delete this Zone link?')
+ .onOk(function () {
+ LNbits.api
+ .request(
+ 'DELETE',
+ '/diagonalley/api/v1/zones/' + zoneId,
+ _.findWhere(self.g.user.wallets, {id: zone.wallet}).inkey
+ )
+ .then(function (response) {
+ self.zones = _.reject(self.zones, function (obj) {
+ return obj.id == zoneId
+ })
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ })
+ },
+ exportZonesCSV: function () {
+ LNbits.utils.exportCSV(this.zonesTable.columns, this.zones)
+ },
+ ////////////////////////////////////////
+ //////////////////SHOP//////////////////
+ ////////////////////////////////////////
+ getShops: function () {
+ var self = this
+
+ LNbits.api
+ .request(
+ 'GET',
+ '/diagonalley/api/v1/shops?all_wallets',
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+ self.shops = response.data.map(function (obj) {
+ return mapDiagonAlley(obj)
+ })
+ })
+ },
+ openShopUpdateDialog: function (linkId) {
+ var self = this
+ var link = _.findWhere(self.shops, {id: linkId})
+
+ this.shopDialog.data = _.clone(link._data)
+ this.shopDialog.show = true
+ },
+ sendShopFormData: function () {
+ if (this.shopDialog.data.id) {
+ } else {
+ var data = {
+ countries: this.shopDialog.data.countries,
+ cost: this.shopDialog.data.cost
+ }
+ }
+
+ if (this.shopDialog.data.id) {
+ this.updateZone(this.shopDialog.data)
+ } else {
+ this.createZone(data)
+ }
+ },
+ updateShop: function (data) {
+ var self = this
+ LNbits.api
+ .request(
+ 'PUT',
+ '/diagonalley/api/v1/shops' + data.id,
+ _.findWhere(self.g.user.wallets, {
+ id: self.shopDialog.data.wallet
+ }).inkey,
+ _.pick(data, 'countries', 'cost')
+ )
+ .then(function (response) {
+ self.shops = _.reject(self.shops, function (obj) {
+ return obj.id == data.id
+ })
+ self.shops.push(mapDiagonAlley(response.data))
+ self.shopDialog.show = false
+ self.shopDialog.data = {}
+ data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ createShop: function (data) {
+ var self = this
+ console.log('cuntywoo')
+ LNbits.api
+ .request(
+ 'POST',
+ '/diagonalley/api/v1/shops',
+ _.findWhere(self.g.user.wallets, {
+ id: self.shopDialog.data.wallet
+ }).inkey,
+ data
+ )
+ .then(function (response) {
+ self.shops.push(mapDiagonAlley(response.data))
+ self.shopDialog.show = false
+ self.shopDialog.data = {}
+ data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ deleteShop: function (shopId) {
+ var self = this
+ var shop = _.findWhere(self.shops, {id: shopId})
+
+ LNbits.utils
+ .confirmDialog('Are you sure you want to delete this Shop link?')
+ .onOk(function () {
+ LNbits.api
+ .request(
+ 'DELETE',
+ '/diagonalley/api/v1/shops/' + shopId,
+ _.findWhere(self.g.user.wallets, {id: shop.wallet}).inkey
+ )
+ .then(function (response) {
+ self.shops = _.reject(self.shops, function (obj) {
+ return obj.id == shopId
+ })
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ })
+ },
+ exportShopsCSV: function () {
+ LNbits.utils.exportCSV(this.shopsTable.columns, this.shops)
+ },
+ ////////////////////////////////////////
+ ////////////////ORDERS//////////////////
+ ////////////////////////////////////////
+ getOrders: function () {
+ var self = this
+
+ LNbits.api
+ .request(
+ 'GET',
+ '/diagonalley/api/v1/orders?all_wallets',
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+ self.orders = response.data.map(function (obj) {
+ return mapDiagonAlley(obj)
+ })
+ })
+ },
+ createOrder: function () {
+ var data = {
+ address: this.orderDialog.data.address,
+ email: this.orderDialog.data.email,
+ quantity: this.orderDialog.data.quantity,
+ shippingzone: this.orderDialog.data.shippingzone
+ }
+ var self = this
+
+ LNbits.api
+ .request(
+ 'POST',
+ '/diagonalley/api/v1/orders',
+ _.findWhere(self.g.user.wallets, {id: self.orderDialog.data.wallet})
+ .inkey,
+ data
+ )
+ .then(function (response) {
+ self.orders.push(mapDiagonAlley(response.data))
+ self.orderDialog.show = false
+ self.orderDialog.data = {}
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ deleteOrder: function (orderId) {
+ var self = this
+ var order = _.findWhere(self.orders, {id: orderId})
+
+ LNbits.utils
+ .confirmDialog('Are you sure you want to delete this order link?')
+ .onOk(function () {
+ LNbits.api
+ .request(
+ 'DELETE',
+ '/diagonalley/api/v1/orders/' + orderId,
+ _.findWhere(self.g.user.wallets, {id: order.wallet}).inkey
+ )
+ .then(function (response) {
+ self.orders = _.reject(self.orders, function (obj) {
+ return obj.id == orderId
+ })
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ })
+ },
+ shipOrder: function (order_id) {
+ var self = this
+
+ LNbits.api
+ .request(
+ 'GET',
+ '/diagonalley/api/v1/orders/shipped/' + order_id,
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+ self.orders = response.data.map(function (obj) {
+ return mapDiagonAlley(obj)
+ })
+ })
+ },
+ exportOrdersCSV: function () {
+ LNbits.utils.exportCSV(this.ordersTable.columns, this.orders)
+ }
+ },
+ created: function () {
+ if (this.g.user.wallets.length) {
+ this.getStalls()
+ this.getProducts()
+ this.getZones()
+ this.getOrders()
+ }
+ }
+})
diff --git a/lnbits/extensions/diagonalley/tasks.py b/lnbits/extensions/diagonalley/tasks.py
new file mode 100644
index 00000000..3fee63d9
--- /dev/null
+++ b/lnbits/extensions/diagonalley/tasks.py
@@ -0,0 +1,29 @@
+import asyncio
+
+from lnbits.core.models import Payment
+from lnbits.tasks import register_invoice_listener
+
+from .crud import get_ticket, set_ticket_paid
+
+
+async def wait_for_paid_invoices():
+ invoice_queue = asyncio.Queue()
+ register_invoice_listener(invoice_queue)
+
+ while True:
+ payment = await invoice_queue.get()
+ await on_invoice_paid(payment)
+
+
+async def on_invoice_paid(payment: Payment) -> None:
+ if "lnticket" != payment.extra.get("tag"):
+ # not a lnticket invoice
+ return
+
+ ticket = await get_ticket(payment.checking_id)
+ if not ticket:
+ print("this should never happen", payment)
+ return
+
+ await payment.set_pending(False)
+ await set_ticket_paid(payment.payment_hash)
\ No newline at end of file
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html b/lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html
new file mode 100644
index 00000000..530c89e8
--- /dev/null
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html
@@ -0,0 +1,129 @@
+
+
+
+
+ Diagon Alley: Decentralised Market-Stalls
+
+
+ Each Stall has its own keys!
+
+ Create Shipping Zones you're willing to ship to
+ Create a Stall to list yiur products on
+ Create products to put on the Stall
+ List stalls on a simple frontend shop page, or point at Nostr shop client key
+
+ Make a list of products to sell, point your list of products at a public
+ relay. Buyers browse your products on the relay, and pay you directly.
+ Ratings are managed by the relay. Your stall can be listed in multiple
+ relays, even over TOR, if you wish to be anonymous.
+ More information on the
+ Diagon Alley Protocol
+
+ Created by, Ben Arc
+
+
+
+
+
+
+
+
+
+ GET
+ /diagonalley/api/v1/stall/products/<relay_id>
+ Body (application/json)
+
+ Returns 201 CREATED (application/json)
+
+ Product JSON list
+ Curl example
+ curl -X GET {{ request.url_root
+ }}api/v1/stall/products/<relay_id>
+
+
+
+
+
+
+ POST
+ /diagonalley/api/v1/stall/order/<relay_id>
+ Body (application/json)
+ {"id": <string>, "address": <string>, "shippingzone":
+ <integer>, "email": <string>, "quantity":
+ <integer>}
+
+ Returns 201 CREATED (application/json)
+
+ {"checking_id": <string>,"payment_request":
+ <string>}
+ Curl example
+ curl -X POST {{ request.url_root
+ }}api/v1/stall/order/<relay_id> -d '{"id": <product_id&>,
+ "email": <customer_email>, "address": <customer_address>,
+ "quantity": 2, "shippingzone": 1}' -H "Content-type: application/json"
+
+
+
+
+
+
+
+ GET
+ /diagonalley/api/v1/stall/checkshipped/<checking_id>
+ Headers
+
+ Returns 200 OK (application/json)
+
+ {"shipped": <boolean>}
+ Curl example
+ curl -X GET {{ request.url_root
+ }}api/v1/stall/checkshipped/<checking_id> -H "Content-type:
+ application/json"
+
+
+
+
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
new file mode 100644
index 00000000..98405f6d
--- /dev/null
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -0,0 +1,634 @@
+{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
+%} {% block page %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Update Product
+
+ Create Product
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
+ Update Shipping Zone
+ Create Shipping Zone
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
+
+ Update Relay
+ Launch
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Generate keys
+
+
+ Restore keys
+
+
+
+
+
+
+
+
+
+
+ Update Stall
+ Create Stall
+ Cancel
+
+
+
+
+
+
+
+
+ + Product List a product
+ + Shipping Zone Create a shipping zone
+ + Stall
+ Create a stall to list products on
+ Launch frontend shop (not Nostr)
+ Makes a simple frontend shop for your stalls
+
+
+
+
+
+
+
+
Orders
+
+
+ Export to CSV
+
+
+
+ {% raw %}
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+ {{ col.value }}
+
+
+
+
+ Product shipped?
+
+
+
+
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
Products
+
+
+ Export to CSV
+
+
+
+ {% raw %}
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+ Link to pass to stall relay
+
+
+ {{ col.value }}
+
+
+
+
+
+
+
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
Stalls
+
+
+ Export to CSV
+
+
+
+ {% raw %}
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+ {{ col.value }}
+
+
+
+
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
Shipping Zones
+
+
+ Export to CSV
+
+
+
+ {% raw %}
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+ {{ col.value }}
+
+
+
+
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
+ LNbits Diagon Alley Extension, powered by Nostr
+
+
+
+
+ {% include "diagonalley/_api_docs.html" %}
+
+
+
+
+ Messages (example)
+
+
+
+
+
+
+ OrderID:87h87h KJBIBYBUYBUF90898....
+ OrderID:NIUHB7 79867KJGJHGVFYFV....
+
+
+
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }}
+
+
+{% endblock %}
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
new file mode 100644
index 00000000..768bedfe
--- /dev/null
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -0,0 +1,9 @@
+
+
+
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
new file mode 100644
index 00000000..2deed72b
--- /dev/null
+++ b/lnbits/extensions/diagonalley/views.py
@@ -0,0 +1,44 @@
+
+from typing import List
+
+from fastapi import Request, WebSocket, WebSocketDisconnect
+from fastapi.params import Depends
+from fastapi.templating import Jinja2Templates
+from starlette.responses import HTMLResponse # type: ignore
+
+from http import HTTPStatus
+import json
+from lnbits.decorators import check_user_exists, validate_uuids
+from lnbits.extensions.diagonalley import diagonalley_ext
+
+from .crud import (
+ create_diagonalley_product,
+ get_diagonalley_product,
+ get_diagonalley_products,
+ delete_diagonalley_product,
+ create_diagonalley_order,
+ get_diagonalley_order,
+ get_diagonalley_orders,
+ update_diagonalley_product,
+)
+
+
+@diagonalley_ext.get("/", response_class=HTMLResponse)
+@validate_uuids(["usr"], required=True)
+@check_user_exists(request: Request)
+async def index():
+ return await render_template("diagonalley/index.html", user=g.user)
+
+
+@diagonalley_ext.get("/", response_class=HTMLResponse)
+async def display(request: Request, stall_id):
+ product = await get_diagonalley_products(stall_id)
+ if not product:
+ abort(HTTPStatus.NOT_FOUND, "Stall does not exist.")
+
+ return await render_template(
+ "diagonalley/stall.html",
+ stall=json.dumps(
+ [product._asdict() for product in await get_diagonalley_products(stall_id)]
+ ),
+ )
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
new file mode 100644
index 00000000..4de2799e
--- /dev/null
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -0,0 +1,348 @@
+from http import HTTPStatus
+
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from starlette.exceptions import HTTPException
+
+from lnbits.core.crud import get_user
+from lnbits.decorators import api_check_wallet_key, api_validate_post_request
+
+from . import diagonalley_ext
+from .crud import (
+ create_diagonalley_product,
+ get_diagonalley_product,
+ get_diagonalley_products,
+ delete_diagonalley_product,
+ create_diagonalley_zone,
+ update_diagonalley_zone,
+ get_diagonalley_zone,
+ get_diagonalley_zones,
+ delete_diagonalley_zone,
+ create_diagonalley_stall,
+ update_diagonalley_stall,
+ get_diagonalley_stall,
+ get_diagonalley_stalls,
+ delete_diagonalley_stall,
+ create_diagonalley_order,
+ get_diagonalley_order,
+ get_diagonalley_orders,
+ update_diagonalley_product,
+ delete_diagonalley_order,
+)
+from lnbits.core.services import create_invoice
+from base64 import urlsafe_b64encode
+from uuid import uuid4
+
+# from lnbits.db import open_ext_db
+
+from . import db
+from .models import Products, Orders, Stalls
+
+### Products
+
+@copilot_ext.get("/api/v1/copilot/{copilot_id}")
+async def api_copilot_retrieve(
+ req: Request,
+ copilot_id: str = Query(None),
+ wallet: WalletTypeInfo = Depends(get_key_type),
+):
+ copilot = await get_copilot(copilot_id)
+ if not copilot:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Copilot not found"
+ )
+ if not copilot.lnurl_toggle:
+ return copilot.dict()
+ return {**copilot.dict(), **{"lnurl": copilot.lnurl(req)}}
+
+
+@diagonalley_ext.get("/api/v1/products")
+async def api_diagonalley_products(
+ req: Request,
+ wallet: WalletTypeInfo = Depends(get_key_type),
+):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_stalls" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ return ([product._asdict() for product in await get_diagonalley_products(wallet_ids)])
+
+
+@diagonalley_ext.post("/api/v1/products")
+@diagonalley_ext.put("/api/v1/products/{product_id}")
+async def api_diagonalley_product_create(
+ data: Products,
+ product_id=: str = Query(None),
+ wallet: WalletTypeInfo = Depends(get_key_type)
+ ):
+
+ if product_id:
+ product = await get_diagonalley_product(product_id)
+
+ if not product:
+ return ({"message": "Withdraw product does not exist."}))
+
+ if product.wallet != wallet.wallet.id:
+ return ({"message": "Not your withdraw product."}))
+
+ product = await update_diagonalley_product(product_id, data)
+ else:
+ product = await create_diagonalley_product(wallet_id=wallet.wallet.id, data)
+
+ return ({**product._asdict()}))
+
+
+@diagonalley_ext.route("/api/v1/products/{product_id}")
+async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
+ product = await get_diagonalley_product(product_id)
+
+ if not product:
+ return ({"message": "Product does not exist."})
+
+ if product.wallet != wallet.wallet.id:
+ return ({"message": "Not your Diagon Alley."})
+
+ await delete_diagonalley_product(product_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+# # # Shippingzones
+
+
+@diagonalley_ext.get("/api/v1/zones")
+async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_wallets" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ return ([zone._asdict() for zone in await get_diagonalley_zones(wallet_ids)]))
+
+
+@diagonalley_ext.post("/api/v1/zones")
+@diagonalley_ext.put("/api/v1/zones/{zone_id}")
+async def api_diagonalley_zone_create(
+ data: Zones,
+ zone_id: str = Query(None),
+ wallet: WalletTypeInfo = Depends(get_key_type)
+ ):
+ if zone_id:
+ zone = await get_diagonalley_zone(zone_id)
+
+ if not zone:
+ return ({"message": "Zone does not exist."}))
+
+ if zone.wallet != walley.wallet.id:
+ return ({"message": "Not your record."}))
+
+ zone = await update_diagonalley_zone(zone_id, data)
+ else:
+ zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data)
+
+ return ({**zone._asdict()}))
+
+
+@diagonalley_ext.delete("/api/v1/zones/{zone_id}")
+async def api_diagonalley_zone_delete(zone_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+ zone = await get_diagonalley_zone(zone_id)
+
+ if not zone:
+ return ({"message": "zone does not exist."})
+
+ if zone.wallet != wallet.wallet.id:
+ return ({"message": "Not your zone."})
+
+ await delete_diagonalley_zone(zone_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+# # # Stalls
+
+
+@diagonalley_ext.get("/api/v1/stalls")
+async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_wallets" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ return ([stall._asdict() for stall in await get_diagonalley_stalls(wallet_ids)])
+
+
+@diagonalley_ext.post("/api/v1/stalls")
+@diagonalley_ext.put("/api/v1/stalls/{stall_id}")
+async def api_diagonalley_stall_create(data: createStalls, stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+
+ if stall_id:
+ stall = await get_diagonalley_stall(stall_id)
+
+ if not stall:
+ return ({"message": "Withdraw stall does not exist."}))
+
+ if stall.wallet != wallet.wallet.id:
+ return ({"message": "Not your withdraw stall."}))
+
+ stall = await update_diagonalley_stall(stall_id, data)
+ else:
+ stall = await create_diagonalley_stall(wallet_id=wallet.wallet.id, data)
+
+ return ({**stall._asdict()}))
+
+
+@diagonalley_ext.delete("/api/v1/stalls/{stall_id}")
+async def api_diagonalley_stall_delete(stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+ stall = await get_diagonalley_stall(stall_id)
+
+ if not stall:
+ return ({"message": "Stall does not exist."})
+
+ if stall.wallet != wallet.wallet.id:
+ return ({"message": "Not your Stall."})
+
+ await delete_diagonalley_stall(stall_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+###Orders
+
+
+@diagonalley_ext.get("/api/v1/orders")
+async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_wallets" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ try:
+ return ([order._asdict() for order in await get_diagonalley_orders(wallet_ids)])
+ except:
+ return ({"message": "We could not retrieve the orders."}))
+
+
+@diagonalley_ext.post("/api/v1/orders")
+
+async def api_diagonalley_order_create(data: createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
+ order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data)
+ return ({**order._asdict()})
+
+
+@diagonalley_ext.delete("/api/v1/orders/{order_id}")
+async def api_diagonalley_order_delete(order_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+ order = await get_diagonalley_order(order_id)
+
+ if not order:
+ return ({"message": "Order does not exist."})
+
+ if order.wallet != wallet.wallet.id:
+ return ({"message": "Not your Order."})
+
+ await delete_diagonalley_order(order_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+@diagonalley_ext.get("/api/v1/orders/paid/{order_id}")
+async def api_diagonalley_order_paid(order_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+ await db.execute(
+ "UPDATE diagonalley.orders SET paid = ? WHERE id = ?",
+ (
+ True,
+ order_id,
+ ),
+ )
+ return "", HTTPStatus.OK
+
+
+@diagonalley_ext.get("/api/v1/orders/shipped/{order_id}")
+async def api_diagonalley_order_shipped(order_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+ await db.execute(
+ "UPDATE diagonalley.orders SET shipped = ? WHERE id = ?",
+ (
+ True,
+ order_id,
+ ),
+ )
+ order = await db.fetchone(
+ "SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
+ )
+
+ return ([order._asdict() for order in get_diagonalley_orders(order["wallet"])]))
+
+
+###List products based on stall id
+
+
+@diagonalley_ext.get("/api/v1/stall/products/{stall_id}")
+async def api_diagonalley_stall_products(stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+
+ rows = await db.fetchone(
+ "SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
+ )
+ print(rows[1])
+ if not rows:
+ return ({"message": "Stall does not exist."})
+
+ products = db.fetchone(
+ "SELECT * FROM diagonalley.products WHERE wallet = ?", (rows[1],)
+ )
+ if not products:
+ return ({"message": "No products"})
+
+ return ([products._asdict() for products in await get_diagonalley_products(rows[1])])
+
+
+###Check a product has been shipped
+
+
+@diagonalley_ext.get("/api/v1/stall/checkshipped/{checking_id}")
+async def api_diagonalley_stall_checkshipped(checking_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+ rows = await db.fetchone(
+ "SELECT * FROM diagonalley.orders WHERE invoiceid = ?", (checking_id,)
+ )
+ return ({"shipped": rows["shipped"]})
+
+
+###Place order
+
+
+@diagonalley_ext.post("/api/v1/stall/order/{stall_id}")
+async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
+ product = await get_diagonalley_product(data.id)
+ shipping = await get_diagonalley_stall(stall_id)
+
+ if data.shippingzone == 1:
+ shippingcost = shipping.zone1cost
+ else:
+ shippingcost = shipping.zone2cost
+
+ checking_id, payment_request = await create_invoice(
+ wallet_id=product.wallet,
+ amount=shippingcost + (data.quantity * product.price),
+ memo=data.id,
+ )
+ selling_id = urlsafe_b64encode(uuid4().bytes_le).decode("utf-8")
+ await db.execute(
+ """
+ INSERT INTO diagonalley.orders (id, productid, wallet, product, quantity, shippingzone, address, email, invoiceid, paid, shipped)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ """,
+ (
+ selling_id,
+ data.id,
+ product.wallet,
+ product.product,
+ data.quantity,
+ data.shippingzone,
+ data.address,
+ data.email,
+ checking_id,
+ False,
+ False,
+ ),
+ )
+ return ({"checking_id": checking_id, "payment_request": payment_request}))
From 903e0d5b0b2f2f4ead59a3a769585c91bf8354c2 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 27 Jan 2022 14:58:58 +0000
Subject: [PATCH 002/226] products
---
lnbits/extensions/diagonalley/views_api.py | 75 ++++++++++++----------
1 file changed, 40 insertions(+), 35 deletions(-)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 4de2799e..9df2c1d8 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -1,4 +1,6 @@
+from base64 import urlsafe_b64encode
from http import HTTPStatus
+from uuid import uuid4
from fastapi import Request
from fastapi.param_functions import Query
@@ -6,41 +8,44 @@ from fastapi.params import Depends
from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
-from lnbits.decorators import api_check_wallet_key, api_validate_post_request
+from lnbits.core.services import create_invoice
+from lnbits.decorators import (
+ WalletTypeInfo,
+ api_check_wallet_key,
+ api_validate_post_request,
+ get_key_type,
+ require_admin_key,
+)
-from . import diagonalley_ext
+from . import db, diagonalley_ext
from .crud import (
- create_diagonalley_product,
- get_diagonalley_product,
- get_diagonalley_products,
- delete_diagonalley_product,
- create_diagonalley_zone,
- update_diagonalley_zone,
- get_diagonalley_zone,
- get_diagonalley_zones,
- delete_diagonalley_zone,
- create_diagonalley_stall,
- update_diagonalley_stall,
- get_diagonalley_stall,
- get_diagonalley_stalls,
- delete_diagonalley_stall,
create_diagonalley_order,
+ create_diagonalley_product,
+ create_diagonalley_stall,
+ create_diagonalley_zone,
+ delete_diagonalley_order,
+ delete_diagonalley_product,
+ delete_diagonalley_stall,
+ delete_diagonalley_zone,
get_diagonalley_order,
get_diagonalley_orders,
+ get_diagonalley_product,
+ get_diagonalley_products,
+ get_diagonalley_stall,
+ get_diagonalley_stalls,
+ get_diagonalley_zone,
+ get_diagonalley_zones,
update_diagonalley_product,
- delete_diagonalley_order,
+ update_diagonalley_stall,
+ update_diagonalley_zone,
)
-from lnbits.core.services import create_invoice
-from base64 import urlsafe_b64encode
-from uuid import uuid4
+from .models import Orders, Products, Stalls
# from lnbits.db import open_ext_db
-from . import db
-from .models import Products, Orders, Stalls
### Products
-
+"""
@copilot_ext.get("/api/v1/copilot/{copilot_id}")
async def api_copilot_retrieve(
req: Request,
@@ -55,26 +60,27 @@ async def api_copilot_retrieve(
if not copilot.lnurl_toggle:
return copilot.dict()
return {**copilot.dict(), **{"lnurl": copilot.lnurl(req)}}
-
+"""
@diagonalley_ext.get("/api/v1/products")
async def api_diagonalley_products(
req: Request,
wallet: WalletTypeInfo = Depends(get_key_type),
+ all_stalls: bool = Query(False)
):
wallet_ids = [wallet.wallet.id]
- if "all_stalls" in request.args:
+ if all_stalls:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- return ([product._asdict() for product in await get_diagonalley_products(wallet_ids)])
+ return ([product.dict() for product in await get_diagonalley_products(wallet_ids)])
@diagonalley_ext.post("/api/v1/products")
@diagonalley_ext.put("/api/v1/products/{product_id}")
async def api_diagonalley_product_create(
data: Products,
- product_id=: str = Query(None),
+ product_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -82,19 +88,19 @@ async def api_diagonalley_product_create(
product = await get_diagonalley_product(product_id)
if not product:
- return ({"message": "Withdraw product does not exist."}))
+ return ({"message": "Withdraw product does not exist."})
if product.wallet != wallet.wallet.id:
- return ({"message": "Not your withdraw product."}))
+ return ({"message": "Not your withdraw product."})
product = await update_diagonalley_product(product_id, data)
else:
product = await create_diagonalley_product(wallet_id=wallet.wallet.id, data)
- return ({**product._asdict()}))
+ return product.dict()
-@diagonalley_ext.route("/api/v1/products/{product_id}")
+@diagonalley_ext.delete("/api/v1/products/{product_id}")
async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
product = await get_diagonalley_product(product_id)
@@ -105,7 +111,6 @@ async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = D
return ({"message": "Not your Diagon Alley."})
await delete_diagonalley_product(product_id)
-
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
@@ -113,13 +118,13 @@ async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = D
@diagonalley_ext.get("/api/v1/zones")
-async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
wallet_ids = [wallet.wallet.id]
- if "all_wallets" in request.args:
+ if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- return ([zone._asdict() for zone in await get_diagonalley_zones(wallet_ids)]))
+ return ([zone.dict() for zone in await get_diagonalley_zones(wallet_ids)])
@diagonalley_ext.post("/api/v1/zones")
From 8db457bd423b000d123e91f0c031b02bea0e8d69 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 27 Jan 2022 15:26:55 +0000
Subject: [PATCH 003/226] zones
---
lnbits/extensions/diagonalley/crud.py | 63 +++++++++-------------
lnbits/extensions/diagonalley/models.py | 41 +++++++++-----
lnbits/extensions/diagonalley/views_api.py | 26 +++++----
3 files changed, 64 insertions(+), 66 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index c6ce8222..7dc02cd4 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -1,17 +1,17 @@
+import re
from base64 import urlsafe_b64encode
-from uuid import uuid4
from typing import List, Optional, Union
+from uuid import uuid4
-from lnbits.settings import WALLET
+import httpx
# from lnbits.db import open_ext_db
from lnbits.db import SQLITE
-from . import db
-from .models import Products, Orders, Stalls, Zones
-
-import httpx
from lnbits.helpers import urlsafe_short_hash
-import re
+from lnbits.settings import WALLET
+
+from . import db
+from .models import Orders, Products, Stalls, Zones, createProduct, createZones
regex = re.compile(
r"^(?:http|ftp)s?://" # http:// or https://
@@ -28,35 +28,27 @@ regex = re.compile(
async def create_diagonalley_product(
- *,
- stall_id: str,
- product: str,
- categories: str,
- description: str,
- image: Optional[str] = None,
- price: int,
- quantity: int,
- shippingzones: str,
+ data: createProduct
) -> Products:
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
+ # returning = "" if db.type == SQLITE else "RETURNING ID"
+ # method = db.execute if db.type == SQLITE else db.fetchone
product_id = urlsafe_short_hash()
# with open_ext_db("diagonalley") as db:
- result = await (method)(
+ # result = await (method)(
+ await db.execute(
f"""
- INSERT INTO diagonalley.products (id, stall, product, categories, description, image, price, quantity, shippingzones)
+ INSERT INTO diagonalley.products (id, stall, product, categories, description, image, price, quantity)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- {returning}
""",
(
product_id,
- stall_id,
- product,
- categories,
- description,
- image,
- price,
- quantity,
+ data.stall,
+ data.product,
+ data.categories,
+ data.description,
+ data.image,
+ data.price,
+ data.quantity,
),
)
product = await get_diagonalley_product(product_id)
@@ -109,17 +101,11 @@ async def delete_diagonalley_product(product_id: str) -> None:
async def create_diagonalley_zone(
- *,
- wallet: Optional[str] = None,
- cost: Optional[int] = 0,
- countries: Optional[str] = None,
+ wallet,
+ data: createZones
) -> Zones:
-
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
-
zone_id = urlsafe_short_hash()
- result = await (method)(
+ await db.execute(
f"""
INSERT INTO diagonalley.zones (
id,
@@ -129,9 +115,8 @@ async def create_diagonalley_zone(
)
VALUES (?, ?, ?, ?)
- {returning}
""",
- (zone_id, wallet, cost, countries),
+ (zone_id, wallet, data.cost, data.countries),
)
zone = await get_diagonalley_zone(zone_id)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 0f2a1d78..bd667a2f 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -1,12 +1,15 @@
-from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult
-from starlette.requests import Request
+import json
+from lib2to3.pytree import Base
+from sqlite3 import Row
+from typing import Dict, Optional
+from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse
+
from fastapi.param_functions import Query
-from typing import Optional, Dict
-from lnbits.lnurl import encode as lnurl_encode # type: ignore
from lnurl.types import LnurlPayMetadata # type: ignore
from pydantic import BaseModel
-import json
-from sqlite3 import Row
+from starlette.requests import Request
+
+from lnbits.lnurl import encode as lnurl_encode # type: ignore
class Stalls(BaseModel):
@@ -25,23 +28,35 @@ class createStalls(BaseModel):
relays: str = Query(None)
shippingzones: str = Query(None)
-class Products(BaseModel):
- id: str = Query(None)
+class createProduct(BaseModel):
stall: str = Query(None)
product: str = Query(None)
categories: str = Query(None)
description: str = Query(None)
image: str = Query(None)
- price: int = Query(0)
- quantity: int = Query(0)
+ price: int = Query(0, ge=0)
+ quantity: int = Query(0, ge=0)
+class Products(BaseModel):
+ id: str
+ stall: str
+ product: str
+ categories: str
+ description: str
+ image: str
+ price: int
+ quantity: int
-class Zones(BaseModel):
- id: str = Query(None)
- wallet: str = Query(None)
+class createZones(BaseModel):
cost: str = Query(None)
countries: str = Query(None)
+class Zones(BaseModel):
+ id: str
+ wallet: str
+ cost: str
+ countries: str
+
class Orders(BaseModel):
id: str = Query(None)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 9df2c1d8..1ad83936 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -39,7 +39,7 @@ from .crud import (
update_diagonalley_stall,
update_diagonalley_zone,
)
-from .models import Orders, Products, Stalls
+from .models import Orders, Products, Stalls, Zones, createProduct, createZones
# from lnbits.db import open_ext_db
@@ -79,7 +79,7 @@ async def api_diagonalley_products(
@diagonalley_ext.post("/api/v1/products")
@diagonalley_ext.put("/api/v1/products/{product_id}")
async def api_diagonalley_product_create(
- data: Products,
+ data: createProduct,
product_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -93,9 +93,9 @@ async def api_diagonalley_product_create(
if product.wallet != wallet.wallet.id:
return ({"message": "Not your withdraw product."})
- product = await update_diagonalley_product(product_id, data)
+ product = await update_diagonalley_product(product_id, **data.dict())
else:
- product = await create_diagonalley_product(wallet_id=wallet.wallet.id, data)
+ product = await create_diagonalley_product(data=data)
return product.dict()
@@ -126,11 +126,10 @@ async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type),
return ([zone.dict() for zone in await get_diagonalley_zones(wallet_ids)])
-
@diagonalley_ext.post("/api/v1/zones")
@diagonalley_ext.put("/api/v1/zones/{zone_id}")
async def api_diagonalley_zone_create(
- data: Zones,
+ data: createZones,
zone_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -138,20 +137,20 @@ async def api_diagonalley_zone_create(
zone = await get_diagonalley_zone(zone_id)
if not zone:
- return ({"message": "Zone does not exist."}))
+ return ({"message": "Zone does not exist."})
- if zone.wallet != walley.wallet.id:
- return ({"message": "Not your record."}))
+ if zone.wallet != wallet.wallet.id:
+ return ({"message": "Not your record."})
- zone = await update_diagonalley_zone(zone_id, data)
+ zone = await update_diagonalley_zone(zone_id, **data.dict())
else:
- zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data)
+ zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data=data)
- return ({**zone._asdict()}))
+ return zone.dict()
@diagonalley_ext.delete("/api/v1/zones/{zone_id}")
-async def api_diagonalley_zone_delete(zone_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
zone = await get_diagonalley_zone(zone_id)
if not zone:
@@ -161,7 +160,6 @@ async def api_diagonalley_zone_delete(zone_id: str = Query(None), wallet: Walle
return ({"message": "Not your zone."})
await delete_diagonalley_zone(zone_id)
-
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
From d6d33c6a22c1e5ed9c336ec1337018407eb1562e Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 27 Jan 2022 16:18:12 +0000
Subject: [PATCH 004/226] stalls
---
lnbits/extensions/diagonalley/crud.py | 34 ++++++++++++----------
lnbits/extensions/diagonalley/models.py | 25 ++++++++--------
lnbits/extensions/diagonalley/views_api.py | 29 +++++++++++-------
3 files changed, 50 insertions(+), 38 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 7dc02cd4..3b58b129 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -11,7 +11,15 @@ from lnbits.helpers import urlsafe_short_hash
from lnbits.settings import WALLET
from . import db
-from .models import Orders, Products, Stalls, Zones, createProduct, createZones
+from .models import (
+ Orders,
+ Products,
+ Stalls,
+ Zones,
+ createProduct,
+ createStalls,
+ createZones,
+)
regex = re.compile(
r"^(?:http|ftp)s?://" # http:// or https://
@@ -185,20 +193,10 @@ async def delete_diagonalley_zone(zone_id: str) -> None:
async def create_diagonalley_stall(
- *,
- wallet: str,
- name: str,
- publickey: str,
- privatekey: str,
- relays: str,
- shippingzones: str,
+ data: createStalls
) -> Stalls:
-
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
-
stall_id = urlsafe_short_hash()
- result = await (method)(
+ await db.execute(
f"""
INSERT INTO diagonalley.stalls (
id,
@@ -210,9 +208,15 @@ async def create_diagonalley_stall(
shippingzones
)
VALUES (?, ?, ?, ?, ?, ?, ?)
- {returning}
""",
- (stall_id, wallet, name, publickey, privatekey, relays, shippingzones),
+ (
+ stall_id,
+ data.wallet,
+ data.name,
+ data.publickey,
+ data.privatekey,
+ data.relays,
+ data.shippingzones),
)
stall = await get_diagonalley_stall(stall_id)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index bd667a2f..4c674c8a 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -13,20 +13,21 @@ from lnbits.lnurl import encode as lnurl_encode # type: ignore
class Stalls(BaseModel):
- id: str = Query(None)
- wallet: str = Query(None)
- name: str = Query(None)
- publickey: str = Query(None)
- privatekey: str = Query(None)
- relays: str = Query(None)
+ id: str
+ wallet: str
+ name: str
+ publickey: str
+ privatekey: str
+ relays: str
+ shippingzones: str
class createStalls(BaseModel):
- wallet: str = Query(None)
- name: str = Query(None)
- publickey: str = Query(None)
- privatekey: str = Query(None)
- relays: str = Query(None)
- shippingzones: str = Query(None)
+ wallet: str = Query(...)
+ name: str = Query(...)
+ publickey: str = Query(...)
+ privatekey: str = Query(...)
+ relays: str = Query(...)
+ shippingzones: str = Query(...)
class createProduct(BaseModel):
stall: str = Query(None)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 1ad83936..ccac9b24 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -39,7 +39,15 @@ from .crud import (
update_diagonalley_stall,
update_diagonalley_zone,
)
-from .models import Orders, Products, Stalls, Zones, createProduct, createZones
+from .models import (
+ Orders,
+ Products,
+ Stalls,
+ Zones,
+ createProduct,
+ createStalls,
+ createZones,
+)
# from lnbits.db import open_ext_db
@@ -167,33 +175,33 @@ async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(
@diagonalley_ext.get("/api/v1/stalls")
-async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
wallet_ids = [wallet.wallet.id]
- if "all_wallets" in request.args:
+ if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- return ([stall._asdict() for stall in await get_diagonalley_stalls(wallet_ids)])
+ return ([stall.dict() for stall in await get_diagonalley_stalls(wallet_ids)])
@diagonalley_ext.post("/api/v1/stalls")
@diagonalley_ext.put("/api/v1/stalls/{stall_id}")
-async def api_diagonalley_stall_create(data: createStalls, stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stall_create(data: createStalls, stall_id = None, wallet: WalletTypeInfo = Depends(get_key_type)):
if stall_id:
stall = await get_diagonalley_stall(stall_id)
if not stall:
- return ({"message": "Withdraw stall does not exist."}))
+ return ({"message": "Withdraw stall does not exist."})
if stall.wallet != wallet.wallet.id:
- return ({"message": "Not your withdraw stall."}))
+ return ({"message": "Not your withdraw stall."})
- stall = await update_diagonalley_stall(stall_id, data)
+ stall = await update_diagonalley_stall(stall_id, **data.dict())
else:
- stall = await create_diagonalley_stall(wallet_id=wallet.wallet.id, data)
+ stall = await create_diagonalley_stall(data=data)
- return ({**stall._asdict()}))
+ return stall.dict()
@diagonalley_ext.delete("/api/v1/stalls/{stall_id}")
@@ -207,7 +215,6 @@ async def api_diagonalley_stall_delete(stall_id: str = Query(None), wallet: Wall
return ({"message": "Not your Stall."})
await delete_diagonalley_stall(stall_id)
-
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
From cad896f909645e2dedfd31e45f5494648aebb7e3 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 28 Jan 2022 15:11:31 +0000
Subject: [PATCH 005/226] orders
---
lnbits/extensions/diagonalley/crud.py | 62 +++++++++-------------
lnbits/extensions/diagonalley/models.py | 28 ++++++----
lnbits/extensions/diagonalley/views_api.py | 42 +++++++--------
3 files changed, 65 insertions(+), 67 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 3b58b129..4cf14014 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -16,6 +16,7 @@ from .models import (
Products,
Stalls,
Zones,
+ createOrder,
createProduct,
createStalls,
createZones,
@@ -83,7 +84,7 @@ async def get_diagonalley_product(product_id: str) -> Optional[Products]:
row = await db.fetchone(
"SELECT * FROM diagonalley.products WHERE id = ?", (product_id,)
)
- return Products.from_row(row) if row else None
+ return Products(**row) if row else None
async def get_diagonalley_products(wallet_ids: Union[str, List[str]]) -> List[Products]:
@@ -98,7 +99,7 @@ async def get_diagonalley_products(wallet_ids: Union[str, List[str]]) -> List[Pr
""",
(*wallet_ids,),
)
- return [Products.from_row(row) for row in rows]
+ return [Products(**row) for row in rows]
async def delete_diagonalley_product(product_id: str) -> None:
@@ -139,12 +140,12 @@ async def update_diagonalley_zone(zone_id: str, **kwargs) -> Optional[Zones]:
(*kwargs.values(), zone_id),
)
row = await db.fetchone("SELECT * FROM diagonalley.zones WHERE id = ?", (zone_id,))
- return Zones.from_row(row) if row else None
+ return Zones(**row) if row else None
async def get_diagonalley_zone(zone_id: str) -> Optional[Zones]:
row = await db.fetchone("SELECT * FROM diagonalley.zones WHERE id = ?", (zone_id,))
- return Zones.from_row(row) if row else None
+ return Zones(**row) if row else None
async def get_diagonalley_zones(wallet_ids: Union[str, List[str]]) -> List[Zones]:
@@ -182,7 +183,7 @@ async def get_diagonalley_zones(wallet_ids: Union[str, List[str]]) -> List[Zones
rows = await db.fetchall(
f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
)
- return [Zones.from_row(row) for row in rows]
+ return [Zones(**row) for row in rows]
async def delete_diagonalley_zone(zone_id: str) -> None:
@@ -233,7 +234,7 @@ async def update_diagonalley_stall(stall_id: str, **kwargs) -> Optional[Stalls]:
row = await db.fetchone(
"SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
)
- return Stalls.from_row(row) if row else None
+ return Stalls(**row) if row else None
async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
@@ -266,7 +267,7 @@ async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
row = await db.fetchone(
"SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
)
- return Stalls.from_row(row) if row else None
+ return Stalls(**row) if row else None
async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]:
@@ -303,7 +304,7 @@ async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stal
rows = await db.fetchall(
f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
)
- return [Stalls.from_row(row) for row in rows]
+ return [Stalls(**row) for row in rows]
async def delete_diagonalley_stall(stall_id: str) -> None:
@@ -314,47 +315,34 @@ async def delete_diagonalley_stall(stall_id: str) -> None:
async def create_diagonalley_order(
- *,
- productid: str,
- wallet: str,
- product: str,
- quantity: int,
- shippingzone: str,
- address: str,
- email: str,
- invoiceid: str,
- paid: bool,
- shipped: bool,
+ data: createOrder
) -> Orders:
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
order_id = urlsafe_short_hash()
- result = await (method)(
+ await db.execute(
f"""
INSERT INTO diagonalley.orders (id, productid, wallet, product,
quantity, shippingzone, address, email, invoiceid, paid, shipped)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- {returning}
""",
(
order_id,
- productid,
- wallet,
- product,
- quantity,
- shippingzone,
- address,
- email,
- invoiceid,
+ data.productid,
+ data.wallet,
+ data.product,
+ data.quantity,
+ data.shippingzone,
+ data.address,
+ data.email,
+ data.invoiceid,
False,
False,
),
)
- if db.type == SQLITE:
- order_id = result._result_proxy.lastrowid
- else:
- order_id = result[0]
+ # if db.type == SQLITE:
+ # order_id = result._result_proxy.lastrowid
+ # else:
+ # order_id = result[0]
link = await get_diagonalley_order(order_id)
assert link, "Newly created link couldn't be retrieved"
@@ -365,7 +353,7 @@ async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
row = await db.fetchone(
"SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
)
- return Orders.from_row(row) if row else None
+ return Orders(**row) if row else None
async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
@@ -377,7 +365,7 @@ async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orde
f"SELECT * FROM diagonalley.orders WHERE wallet IN ({q})", (*wallet_ids,)
)
#
- return [Orders.from_row(row) for row in rows]
+ return [Orders(**row) for row in rows]
async def delete_diagonalley_order(order_id: str) -> None:
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 4c674c8a..1a975e10 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -59,15 +59,25 @@ class Zones(BaseModel):
countries: str
+class createOrder(BaseModel):
+ productid: str = Query(...)
+ stall: str = Query(...)
+ product: str = Query(...)
+ quantity: int = Query(..., ge=1)
+ shippingzone: int = Query(...)
+ address: str = Query(...)
+ email: str = Query(...)
+ invoiceid: str = Query(...)
+
class Orders(BaseModel):
- id: str = Query(None)
- productid: str = Query(None)
- stall: str = Query(None)
- product: str = Query(None)
- quantity: int = Query(0)
- shippingzone: int = Query(0)
- address: str = Query(None)
- email: str = Query(None)
- invoiceid: str = Query(None)
+ id: str
+ productid: str
+ stall: str
+ product: str
+ quantity: int
+ shippingzone: int
+ address: str
+ email: str
+ invoiceid: str
paid: bool
shipped: bool
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index ccac9b24..165d2a0c 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -44,6 +44,7 @@ from .models import (
Products,
Stalls,
Zones,
+ createOrder,
createProduct,
createStalls,
createZones,
@@ -87,8 +88,8 @@ async def api_diagonalley_products(
@diagonalley_ext.post("/api/v1/products")
@diagonalley_ext.put("/api/v1/products/{product_id}")
async def api_diagonalley_product_create(
+ product_id,
data: createProduct,
- product_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -186,7 +187,7 @@ async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type),
@diagonalley_ext.post("/api/v1/stalls")
@diagonalley_ext.put("/api/v1/stalls/{stall_id}")
-async def api_diagonalley_stall_create(data: createStalls, stall_id = None, wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stall_create(data: createStalls, stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
if stall_id:
stall = await get_diagonalley_stall(stall_id)
@@ -222,23 +223,22 @@ async def api_diagonalley_stall_delete(stall_id: str = Query(None), wallet: Wall
@diagonalley_ext.get("/api/v1/orders")
-async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
wallet_ids = [wallet.wallet.id]
- if "all_wallets" in request.args:
+ if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
try:
- return ([order._asdict() for order in await get_diagonalley_orders(wallet_ids)])
+ return ([order.dict() for order in await get_diagonalley_orders(wallet_ids)])
except:
- return ({"message": "We could not retrieve the orders."}))
+ return ({"message": "We could not retrieve the orders."})
@diagonalley_ext.post("/api/v1/orders")
-
-async def api_diagonalley_order_create(data: createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
- order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data)
- return ({**order._asdict()})
+async def api_diagonalley_order_create(data: createOrder, wallet: WalletTypeInfo = Depends(get_key_type)):
+ order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data=data)
+ return order.dict()
@diagonalley_ext.delete("/api/v1/orders/{order_id}")
@@ -281,7 +281,7 @@ async def api_diagonalley_order_shipped(order_id: str = Query(None), wallet: Wal
"SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
)
- return ([order._asdict() for order in get_diagonalley_orders(order["wallet"])]))
+ return ([order.dict() for order in get_diagonalley_orders(order["wallet"])])
###List products based on stall id
@@ -303,14 +303,14 @@ async def api_diagonalley_stall_products(stall_id: str = Query(None), wallet: Wa
if not products:
return ({"message": "No products"})
- return ([products._asdict() for products in await get_diagonalley_products(rows[1])])
+ return ([products.dict() for products in await get_diagonalley_products(rows[1])])
###Check a product has been shipped
@diagonalley_ext.get("/api/v1/stall/checkshipped/{checking_id}")
-async def api_diagonalley_stall_checkshipped(checking_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stall_checkshipped(checking_id, wallet: WalletTypeInfo = Depends(get_key_type)):
rows = await db.fetchone(
"SELECT * FROM diagonalley.orders WHERE invoiceid = ?", (checking_id,)
)
@@ -321,19 +321,19 @@ async def api_diagonalley_stall_checkshipped(checking_id: str = Query(None), wal
@diagonalley_ext.post("/api/v1/stall/order/{stall_id}")
-async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
- product = await get_diagonalley_product(data.id)
+async def api_diagonalley_stall_order(stall_id, data: createOrder, wallet: WalletTypeInfo = Depends(get_key_type)):
+ product = await get_diagonalley_product(data.productid)
shipping = await get_diagonalley_stall(stall_id)
if data.shippingzone == 1:
- shippingcost = shipping.zone1cost
+ shippingcost = shipping.zone1cost #missing in model
else:
- shippingcost = shipping.zone2cost
+ shippingcost = shipping.zone2cost #missing in model
checking_id, payment_request = await create_invoice(
wallet_id=product.wallet,
amount=shippingcost + (data.quantity * product.price),
- memo=data.id,
+ memo=shipping.wallet,
)
selling_id = urlsafe_b64encode(uuid4().bytes_le).decode("utf-8")
await db.execute(
@@ -343,8 +343,8 @@ async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo
""",
(
selling_id,
- data.id,
- product.wallet,
+ data.productid,
+ product.wallet, #doesn't exist in model
product.product,
data.quantity,
data.shippingzone,
@@ -355,4 +355,4 @@ async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo
False,
),
)
- return ({"checking_id": checking_id, "payment_request": payment_request}))
+ return ({"checking_id": checking_id, "payment_request": payment_request})
From 5048080ff671799a363e19c055ffa443c23c8f03 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 28 Jan 2022 16:22:54 +0000
Subject: [PATCH 006/226] UI fires up
---
lnbits/extensions/diagonalley/__init__.py | 35 +++++++++++---
lnbits/extensions/diagonalley/tasks.py | 6 +--
lnbits/extensions/diagonalley/views.py | 55 +++++++++-------------
lnbits/extensions/diagonalley/views_api.py | 8 +---
4 files changed, 55 insertions(+), 49 deletions(-)
diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py
index 720c55c8..cab65685 100644
--- a/lnbits/extensions/diagonalley/__init__.py
+++ b/lnbits/extensions/diagonalley/__init__.py
@@ -1,16 +1,37 @@
-from quart import Blueprint
+import asyncio
+
+from fastapi import APIRouter
+from fastapi.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_diagonalley")
-diagonalley_ext: Blueprint = Blueprint(
- "diagonalley", __name__, static_folder="static", template_folder="templates"
+diagonalley_static_files = [
+ {
+ "path": "/diagonalley/static",
+ "app": StaticFiles(directory="lnbits/extensions/diagonalley/static"),
+ "name": "diagonalley_static",
+ }
+]
+
+diagonalley_ext: APIRouter = APIRouter(
+ prefix="/diagonalley", tags=["diagonalley"]
+ # "diagonalley", __name__, static_folder="static", template_folder="templates"
)
-from .views_api import * # noqa
+def diagonalley_renderer():
+ return template_renderer(["lnbits/extensions/diagonalley/templates"])
+
+
+from .tasks import wait_for_paid_invoices
from .views import * # noqa
+from .views_api import * # noqa
-from .tasks import register_listeners
-from lnbits.tasks import record_async
-diagonalley_ext.record(record_async(register_listeners))
+def diagonalley_start():
+ loop = asyncio.get_event_loop()
+ loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
+
diff --git a/lnbits/extensions/diagonalley/tasks.py b/lnbits/extensions/diagonalley/tasks.py
index 3fee63d9..bcbb7025 100644
--- a/lnbits/extensions/diagonalley/tasks.py
+++ b/lnbits/extensions/diagonalley/tasks.py
@@ -3,8 +3,6 @@ import asyncio
from lnbits.core.models import Payment
from lnbits.tasks import register_invoice_listener
-from .crud import get_ticket, set_ticket_paid
-
async def wait_for_paid_invoices():
invoice_queue = asyncio.Queue()
@@ -16,6 +14,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None:
+ """
if "lnticket" != payment.extra.get("tag"):
# not a lnticket invoice
return
@@ -26,4 +25,5 @@ async def on_invoice_paid(payment: Payment) -> None:
return
await payment.set_pending(False)
- await set_ticket_paid(payment.payment_hash)
\ No newline at end of file
+ await set_ticket_paid(payment.payment_hash)
+ """
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 2deed72b..ae0899ca 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -1,44 +1,35 @@
-from typing import List
-
-from fastapi import Request, WebSocket, WebSocketDisconnect
-from fastapi.params import Depends
-from fastapi.templating import Jinja2Templates
-from starlette.responses import HTMLResponse # type: ignore
-
from http import HTTPStatus
-import json
-from lnbits.decorators import check_user_exists, validate_uuids
-from lnbits.extensions.diagonalley import diagonalley_ext
-from .crud import (
- create_diagonalley_product,
- get_diagonalley_product,
- get_diagonalley_products,
- delete_diagonalley_product,
- create_diagonalley_order,
- get_diagonalley_order,
- get_diagonalley_orders,
- update_diagonalley_product,
-)
+from fastapi import Request
+from fastapi.params import Depends
+from fastapi.templating import Jinja2Templates
+from starlette.exceptions import HTTPException
+from starlette.responses import HTMLResponse
+from lnbits.core.models import User
+from lnbits.decorators import check_user_exists # type: ignore
+from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
+
+from .crud import get_diagonalley_products
+
+templates = Jinja2Templates(directory="templates")
@diagonalley_ext.get("/", response_class=HTMLResponse)
-@validate_uuids(["usr"], required=True)
-@check_user_exists(request: Request)
-async def index():
- return await render_template("diagonalley/index.html", user=g.user)
+async def index(request: Request, user: User = Depends(check_user_exists)):
+ return diagonalley_renderer().TemplateResponse(
+ "diagonalley/index.html", {"request": request, "user": user.dict()}
+ )
-
-@diagonalley_ext.get("/", response_class=HTMLResponse)
+@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
product = await get_diagonalley_products(stall_id)
+
if not product:
- abort(HTTPStatus.NOT_FOUND, "Stall does not exist.")
-
- return await render_template(
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
+ )
+ return diagonalley_renderer().TemplateResponse(
"diagonalley/stall.html",
- stall=json.dumps(
- [product._asdict() for product in await get_diagonalley_products(stall_id)]
- ),
+ {"stall": [product.dict() for product in await get_diagonalley_products(stall_id)]}
)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 165d2a0c..43232841 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -9,13 +9,7 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.core.services import create_invoice
-from lnbits.decorators import (
- WalletTypeInfo,
- api_check_wallet_key,
- api_validate_post_request,
- get_key_type,
- require_admin_key,
-)
+from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
from . import db, diagonalley_ext
from .crud import (
From 301135d0064d378843ad997124fcfbb169520e0c Mon Sep 17 00:00:00 2001
From: benarc
Date: Thu, 3 Feb 2022 21:19:24 +0000
Subject: [PATCH 007/226] Message ui working
---
.../extensions/diagonalley/static/js/index.js | 83 ++++++++++++-------
.../templates/diagonalley/index.html | 47 ++++++-----
2 files changed, 78 insertions(+), 52 deletions(-)
diff --git a/lnbits/extensions/diagonalley/static/js/index.js b/lnbits/extensions/diagonalley/static/js/index.js
index 1a25edaa..af81db2a 100644
--- a/lnbits/extensions/diagonalley/static/js/index.js
+++ b/lnbits/extensions/diagonalley/static/js/index.js
@@ -2,7 +2,24 @@
Vue.component(VueQrcode.name, VueQrcode)
-const pica = window.pica()
+//const pica = window.pica()
+
+var mapStalls = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
+var mapProducts = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
+var mapZone = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
+var mapOrders = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
new Vue({
el: '#vue',
@@ -13,6 +30,9 @@ new Vue({
orders: [],
stalls: [],
zones: [],
+ customerKeys: [],
+ customerKey: '',
+ customerMessages: {},
shippedModel: false,
shippingZoneOptions: [
'Australia',
@@ -64,7 +84,8 @@ new Vue({
'Groceries (Food and Drink)',
'Technology (Phones and Computers)',
'Home (furniture and accessories)',
- 'Gifts (flowers, cards, etc)'
+ 'Gifts (flowers, cards, etc)',
+ 'Adult'
],
relayOptions: [
'wss://nostr-relay.herokuapp.com/ws',
@@ -244,6 +265,17 @@ new Vue({
}
},
methods: {
+ ////////////////////////////////////////
+ ///////////SUPPORT MESSAGES/////////////
+ ////////////////////////////////////////
+ getMessages: function (customerKey) {
+ var self = this
+ console.log('fuck')
+ messages = []
+ messages.push(['in', 'blah blah'])
+ messages.push(['out', 'blah blah'])
+ self.customerMessages = messages
+ },
////////////////////////////////////////
////////////////STALLS//////////////////
////////////////////////////////////////
@@ -256,10 +288,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.stalls = response.data.map(function (obj) {
- console.log(obj)
- return mapDiagonAlley(obj)
- })
+ self.stalls.push(mapStalls(response.data))
})
},
openStallUpdateDialog: function (linkId) {
@@ -302,7 +331,7 @@ new Vue({
self.stalls = _.reject(self.stalls, function (obj) {
return obj.id == data.id
})
- self.stalls.push(mapDiagonAlley(response.data))
+ self.stalls.push(mapStalls(response.data))
self.stallDialog.show = false
self.stallDialog.data = {}
data = {}
@@ -323,7 +352,7 @@ new Vue({
data
)
.then(function (response) {
- self.stalls.push(mapDiagonAlley(response.data))
+ self.stalls.push(mapStalls(response.data))
self.stallDialog.show = false
self.stallDialog.data = {}
data = {}
@@ -371,9 +400,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.products = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.products.push(mapProducts(response.data))
})
},
openProductUpdateDialog: function (linkId) {
@@ -450,7 +477,7 @@ new Vue({
self.products = _.reject(self.products, function (obj) {
return obj.id == data.id
})
- self.products.push(mapDiagonAlley(response.data))
+ self.products.push(mapProducts(response.data))
self.productDialog.show = false
self.productDialog.data = {}
})
@@ -470,7 +497,7 @@ new Vue({
data
)
.then(function (response) {
- self.products.push(mapDiagonAlley(response.data))
+ self.products.push(mapProducts(response.data))
self.productDialog.show = false
self.productDialog.data = {}
})
@@ -517,9 +544,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.zones = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.zones.push(mapZone(response.data))
})
},
openZoneUpdateDialog: function (linkId) {
@@ -559,7 +584,7 @@ new Vue({
self.zones = _.reject(self.zones, function (obj) {
return obj.id == data.id
})
- self.zones.push(mapDiagonAlley(response.data))
+ self.zones.push(mapZone(response.data))
self.zoneDialog.show = false
self.zoneDialog.data = {}
data = {}
@@ -580,7 +605,7 @@ new Vue({
data
)
.then(function (response) {
- self.zones.push(mapDiagonAlley(response.data))
+ self.zones.push(mapZone(response.data))
self.zoneDialog.show = false
self.zoneDialog.data = {}
data = {}
@@ -628,9 +653,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.shops = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.shops.push(mapShops(response.data))
})
},
openShopUpdateDialog: function (linkId) {
@@ -670,7 +693,7 @@ new Vue({
self.shops = _.reject(self.shops, function (obj) {
return obj.id == data.id
})
- self.shops.push(mapDiagonAlley(response.data))
+ self.shops.push(mapShops(response.data))
self.shopDialog.show = false
self.shopDialog.data = {}
data = {}
@@ -692,7 +715,7 @@ new Vue({
data
)
.then(function (response) {
- self.shops.push(mapDiagonAlley(response.data))
+ self.shops.push(mapShops(response.data))
self.shopDialog.show = false
self.shopDialog.data = {}
data = {}
@@ -740,9 +763,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.orders = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.orders.push(mapOrders(response.data))
})
},
createOrder: function () {
@@ -763,7 +784,7 @@ new Vue({
data
)
.then(function (response) {
- self.orders.push(mapDiagonAlley(response.data))
+ self.orders.push(mapOrders(response.data))
self.orderDialog.show = false
self.orderDialog.data = {}
})
@@ -804,9 +825,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.orders = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.orders.push(mapOrders(response.data))
})
},
exportOrdersCSV: function () {
@@ -819,6 +838,10 @@ new Vue({
this.getProducts()
this.getZones()
this.getOrders()
+ this.customerKeys = [
+ 'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
+ 'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
+ ]
}
}
})
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 98405f6d..a89c8b5e 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -594,34 +594,37 @@
- Messages (example)
+ Messages
-
-
-
OrderID:87h87h KJBIBYBUYBUF90898....
-
OrderID:NIUHB7 79867KJGJHGVFYFV....
+
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
From ecaea51a1ce5f98c585b58caf2b0c16f2eb8a75b Mon Sep 17 00:00:00 2001
From: benarc
Date: Thu, 3 Feb 2022 22:30:53 +0000
Subject: [PATCH 008/226] Added error messages
---
lnbits/extensions/diagonalley/static/js/index.js | 6 ++++++
.../diagonalley/templates/diagonalley/index.html | 13 ++++++++++---
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/lnbits/extensions/diagonalley/static/js/index.js b/lnbits/extensions/diagonalley/static/js/index.js
index af81db2a..d101bfcf 100644
--- a/lnbits/extensions/diagonalley/static/js/index.js
+++ b/lnbits/extensions/diagonalley/static/js/index.js
@@ -265,6 +265,12 @@ new Vue({
}
},
methods: {
+ errorMessage: function (error) {
+ this.$q.notify({
+ color: 'primary',
+ message: error
+ })
+ },
////////////////////////////////////////
///////////SUPPORT MESSAGES/////////////
////////////////////////////////////////
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index a89c8b5e..d14d7cee 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -300,13 +300,20 @@
- + Product List a product
+ + Product List a product
+ Shipping Zone Create a shipping zone
- + Stall
+ Create a stall to list products on
+ + Stall
Create a stall to list products on
@@ -618,7 +625,7 @@
>
-
+
From 44f7fae2d4035f9757d9f6836e59be68b09c987c Mon Sep 17 00:00:00 2001
From: benarc
Date: Fri, 4 Feb 2022 13:05:48 +0000
Subject: [PATCH 009/226] Zones are saving/updating
---
lnbits/extensions/diagonalley/__init__.py | 11 +-
lnbits/extensions/diagonalley/crud.py | 116 +--
lnbits/extensions/diagonalley/migrations.py | 8 +-
lnbits/extensions/diagonalley/models.py | 7 +-
.../extensions/diagonalley/static/js/index.js | 853 -----------------
.../templates/diagonalley/index.html | 895 +++++++++++++++++-
lnbits/extensions/diagonalley/views_api.py | 40 +-
7 files changed, 924 insertions(+), 1006 deletions(-)
delete mode 100644 lnbits/extensions/diagonalley/static/js/index.js
diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py
index cab65685..388c08db 100644
--- a/lnbits/extensions/diagonalley/__init__.py
+++ b/lnbits/extensions/diagonalley/__init__.py
@@ -9,17 +9,9 @@ from lnbits.tasks import catch_everything_and_restart
db = Database("ext_diagonalley")
-diagonalley_static_files = [
- {
- "path": "/diagonalley/static",
- "app": StaticFiles(directory="lnbits/extensions/diagonalley/static"),
- "name": "diagonalley_static",
- }
-]
diagonalley_ext: APIRouter = APIRouter(
prefix="/diagonalley", tags=["diagonalley"]
- # "diagonalley", __name__, static_folder="static", template_folder="templates"
)
def diagonalley_renderer():
@@ -33,5 +25,4 @@ from .views_api import * # noqa
def diagonalley_start():
loop = asyncio.get_event_loop()
- loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
-
+ loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
\ No newline at end of file
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 4cf14014..d2df427c 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -22,28 +22,12 @@ from .models import (
createZones,
)
-regex = re.compile(
- r"^(?:http|ftp)s?://" # http:// or https://
- r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|"
- r"localhost|"
- r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
- r"(?::\d+)?"
- r"(?:/?|[/?]\S+)$",
- re.IGNORECASE,
-)
-
-
###Products
-
async def create_diagonalley_product(
data: createProduct
) -> Products:
- # returning = "" if db.type == SQLITE else "RETURNING ID"
- # method = db.execute if db.type == SQLITE else db.fetchone
product_id = urlsafe_short_hash()
- # with open_ext_db("diagonalley") as db:
- # result = await (method)(
await db.execute(
f"""
INSERT INTO diagonalley.products (id, stall, product, categories, description, image, price, quantity)
@@ -110,7 +94,7 @@ async def delete_diagonalley_product(product_id: str) -> None:
async def create_diagonalley_zone(
- wallet,
+ user,
data: createZones
) -> Zones:
zone_id = urlsafe_short_hash()
@@ -118,14 +102,14 @@ async def create_diagonalley_zone(
f"""
INSERT INTO diagonalley.zones (
id,
- wallet,
+ user,
cost,
countries
)
VALUES (?, ?, ?, ?)
""",
- (zone_id, wallet, data.cost, data.countries),
+ (zone_id, user, data.cost, data.countries.lower()),
)
zone = await get_diagonalley_zone(zone_id)
@@ -148,41 +132,8 @@ async def get_diagonalley_zone(zone_id: str) -> Optional[Zones]:
return Zones(**row) if row else None
-async def get_diagonalley_zones(wallet_ids: Union[str, List[str]]) -> List[Zones]:
- if isinstance(wallet_ids, str):
- wallet_ids = [wallet_ids]
- print(wallet_ids)
-
- q = ",".join(["?"] * len(wallet_ids))
- rows = await db.fetchall(
- f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
- )
-
- for r in rows:
- try:
- x = httpx.get(r["zoneaddress"] + "/" + r["ratingkey"])
- if x.status_code == 200:
- await db.execute(
- "UPDATE diagonalley.zones SET online = ? WHERE id = ?",
- (
- True,
- r["id"],
- ),
- )
- else:
- await db.execute(
- "UPDATE diagonalley.zones SET online = ? WHERE id = ?",
- (
- False,
- r["id"],
- ),
- )
- except:
- print("An exception occurred")
- q = ",".join(["?"] * len(wallet_ids))
- rows = await db.fetchall(
- f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
- )
+async def get_diagonalley_zones(user: str) -> List[Zones]:
+ rows = await db.fetchall("SELECT * FROM diagonalley.zones WHERE user = ?", (user,))
return [Zones(**row) for row in rows]
@@ -217,7 +168,7 @@ async def create_diagonalley_stall(
data.publickey,
data.privatekey,
data.relays,
- data.shippingzones),
+ repr(data.shippingzones)),
)
stall = await get_diagonalley_stall(stall_id)
@@ -238,32 +189,6 @@ async def update_diagonalley_stall(stall_id: str, **kwargs) -> Optional[Stalls]:
async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
- roww = await db.fetchone(
- "SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
- )
-
- try:
- x = httpx.get(roww["stalladdress"] + "/" + roww["ratingkey"])
- if x.status_code == 200:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- True,
- stall_id,
- ),
- )
- else:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- False,
- stall_id,
- ),
- )
- except:
- print("An exception occurred")
-
- # with open_ext_db("diagonalley") as db:
row = await db.fetchone(
"SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
)
@@ -271,35 +196,6 @@ async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]:
- if isinstance(wallet_ids, str):
- wallet_ids = [wallet_ids]
-
- q = ",".join(["?"] * len(wallet_ids))
- rows = await db.fetchall(
- f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
- )
-
- for r in rows:
- try:
- x = httpx.get(r["stalladdress"] + "/" + r["ratingkey"])
- if x.status_code == 200:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- True,
- r["id"],
- ),
- )
- else:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- False,
- r["id"],
- ),
- )
- except:
- print("An exception occurred")
q = ",".join(["?"] * len(wallet_ids))
rows = await db.fetchall(
f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index 1523f398..29a84419 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -28,7 +28,8 @@ async def m001_initial(db):
name TEXT NOT NULL,
publickey TEXT NOT NULL,
privatekey TEXT NOT NULL,
- relays TEXT NOT NULL
+ relays TEXT NOT NULL,
+ shippingzones TEXT NOT NULL
);
"""
)
@@ -40,7 +41,7 @@ async def m001_initial(db):
"""
CREATE TABLE diagonalley.zones (
id TEXT PRIMARY KEY,
- wallet TEXT NOT NULL,
+ user TEXT NOT NULL,
cost TEXT NOT NULL,
countries TEXT NOT NULL
);
@@ -55,7 +56,8 @@ async def m001_initial(db):
CREATE TABLE diagonalley.orders (
id TEXT PRIMARY KEY,
productid TEXT NOT NULL,
- wallet TEXT NOT NULL,
+ usr TEXT NOT NULL,
+ pubkey TEXT NOT NULL,
product TEXT NOT NULL,
quantity INTEGER NOT NULL,
shippingzone INTEGER NOT NULL,
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 1a975e10..743c2068 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -49,13 +49,13 @@ class Products(BaseModel):
quantity: int
class createZones(BaseModel):
- cost: str = Query(None)
+ cost: int = Query(0, ge=0)
countries: str = Query(None)
class Zones(BaseModel):
id: str
- wallet: str
- cost: str
+ user: str
+ cost: int
countries: str
@@ -73,6 +73,7 @@ class Orders(BaseModel):
id: str
productid: str
stall: str
+ pubkey: str
product: str
quantity: int
shippingzone: int
diff --git a/lnbits/extensions/diagonalley/static/js/index.js b/lnbits/extensions/diagonalley/static/js/index.js
deleted file mode 100644
index d101bfcf..00000000
--- a/lnbits/extensions/diagonalley/static/js/index.js
+++ /dev/null
@@ -1,853 +0,0 @@
-/* globals Quasar, Vue, _, VueQrcode, windowMixin, LNbits, LOCALE */
-
-Vue.component(VueQrcode.name, VueQrcode)
-
-//const pica = window.pica()
-
-var mapStalls = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-var mapProducts = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-var mapZone = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-var mapOrders = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-
-new Vue({
- el: '#vue',
- mixins: [windowMixin],
- data: function () {
- return {
- products: [],
- orders: [],
- stalls: [],
- zones: [],
- customerKeys: [],
- customerKey: '',
- customerMessages: {},
- shippedModel: false,
- shippingZoneOptions: [
- 'Australia',
- 'Austria',
- 'Belgium',
- 'Brazil',
- 'Canada',
- 'Denmark',
- 'Finland',
- 'France*',
- 'Germany',
- 'Greece',
- 'Hong Kong',
- 'Hungary',
- 'Ireland',
- 'Indonesia',
- 'Israel',
- 'Italy',
- 'Japan',
- 'Kazakhstan',
- 'Korea',
- 'Luxembourg',
- 'Malaysia',
- 'Mexico',
- 'Netherlands',
- 'New Zealand',
- 'Norway',
- 'Poland',
- 'Portugal',
- 'Russia',
- 'Saudi Arabia',
- 'Singapore',
- 'Spain',
- 'Sweden',
- 'Switzerland',
- 'Thailand',
- 'Turkey',
- 'Ukraine',
- 'United Kingdom**',
- 'United States***',
- 'Vietnam',
- 'China'
- ],
- categories: [
- 'Fashion (clothing and accessories)',
- 'Health (and beauty)',
- 'Toys (and baby equipment)',
- 'Media (Books and CDs)',
- 'Groceries (Food and Drink)',
- 'Technology (Phones and Computers)',
- 'Home (furniture and accessories)',
- 'Gifts (flowers, cards, etc)',
- 'Adult'
- ],
- relayOptions: [
- 'wss://nostr-relay.herokuapp.com/ws',
- 'wss://nostr-relay.bigsun.xyz/ws',
- 'wss://freedom-relay.herokuapp.com/ws'
- ],
- label: '',
- ordersTable: {
- columns: [
- {
- name: 'product',
- align: 'left',
- label: 'Product',
- field: 'product'
- },
- {
- name: 'quantity',
- align: 'left',
- label: 'Quantity',
- field: 'quantity'
- },
- {
- name: 'address',
- align: 'left',
- label: 'Address',
- field: 'address'
- },
- {
- name: 'invoiceid',
- align: 'left',
- label: 'InvoiceID',
- field: 'invoiceid'
- },
- {name: 'paid', align: 'left', label: 'Paid', field: 'paid'},
- {name: 'shipped', align: 'left', label: 'Shipped', field: 'shipped'}
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- productsTable: {
- columns: [
- {
- name: 'stall',
- align: 'left',
- label: 'Stall',
- field: 'stall'
- },
- {
- name: 'product',
- align: 'left',
- label: 'Product',
- field: 'product'
- },
- {
- name: 'description',
- align: 'left',
- label: 'Description',
- field: 'description'
- },
- {
- name: 'categories',
- align: 'left',
- label: 'Categories',
- field: 'categories'
- },
- {name: 'price', align: 'left', label: 'Price', field: 'price'},
- {
- name: 'quantity',
- align: 'left',
- label: 'Quantity',
- field: 'quantity'
- },
- {name: 'id', align: 'left', label: 'ID', field: 'id'}
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- stallTable: {
- columns: [
- {
- name: 'id',
- align: 'left',
- label: 'ID',
- field: 'id'
- },
- {
- name: 'name',
- align: 'left',
- label: 'Name',
- field: 'name'
- },
- {
- name: 'wallet',
- align: 'left',
- label: 'Wallet',
- field: 'wallet'
- },
- {
- name: 'publickey',
- align: 'left',
- label: 'Public key',
- field: 'publickey'
- },
- {
- name: 'privatekey',
- align: 'left',
- label: 'Private key',
- field: 'privatekey'
- }
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- zonesTable: {
- columns: [
- {
- name: 'id',
- align: 'left',
- label: 'ID',
- field: 'id'
- },
- {
- name: 'countries',
- align: 'left',
- label: 'Countries',
- field: 'countries'
- },
- {
- name: 'cost',
- align: 'left',
- label: 'Cost',
- field: 'cost'
- }
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- productDialog: {
- show: false,
- data: {}
- },
- stallDialog: {
- show: false,
- data: {}
- },
- zoneDialog: {
- show: false,
- data: {}
- },
- shopDialog: {
- show: false,
- data: {activate: false}
- },
- orderDialog: {
- show: false,
- data: {}
- },
- relayDialog: {
- show: false,
- data: {}
- }
- }
- },
- computed: {
- categoryOther: function () {
- cats = trim(this.productDialog.data.categories.split(','))
- for (let i = 0; i < cats.length; i++) {
- if (cats[i] == 'Others') {
- return true
- }
- }
- return false
- }
- },
- methods: {
- errorMessage: function (error) {
- this.$q.notify({
- color: 'primary',
- message: error
- })
- },
- ////////////////////////////////////////
- ///////////SUPPORT MESSAGES/////////////
- ////////////////////////////////////////
- getMessages: function (customerKey) {
- var self = this
- console.log('fuck')
- messages = []
- messages.push(['in', 'blah blah'])
- messages.push(['out', 'blah blah'])
- self.customerMessages = messages
- },
- ////////////////////////////////////////
- ////////////////STALLS//////////////////
- ////////////////////////////////////////
- getStalls: function () {
- var self = this
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/stalls?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.stalls.push(mapStalls(response.data))
- })
- },
- openStallUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.stalls, {id: linkId})
-
- this.stallDialog.data = _.clone(link._data)
- this.stallDialog.show = true
- },
- sendStallFormData: function () {
- if (this.stallDialog.data.id) {
- } else {
- var data = {
- name: this.stallDialog.data.name,
- wallet: this.stallDialog.data.wallet,
- publickey: this.stallDialog.data.publickey,
- privatekey: this.stallDialog.data.privatekey,
- relays: this.stallDialog.data.relays
- }
- }
-
- if (this.stallDialog.data.id) {
- this.updateStall(this.stallDialog.data)
- } else {
- this.createStall(data)
- }
- },
- updateStall: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/stalls' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.stallDialog.data.wallet
- }).inkey,
- _.pick(data, 'name', 'wallet', 'publickey', 'privatekey')
- )
- .then(function (response) {
- self.stalls = _.reject(self.stalls, function (obj) {
- return obj.id == data.id
- })
- self.stalls.push(mapStalls(response.data))
- self.stallDialog.show = false
- self.stallDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createStall: function (data) {
- var self = this
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/stalls',
- _.findWhere(self.g.user.wallets, {
- id: self.stallDialog.data.wallet
- }).inkey,
- data
- )
- .then(function (response) {
- self.stalls.push(mapStalls(response.data))
- self.stallDialog.show = false
- self.stallDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteStall: function (stallId) {
- var self = this
- var stall = _.findWhere(self.stalls, {id: stallId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this Stall link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/stalls/' + stallId,
- _.findWhere(self.g.user.wallets, {id: stall.wallet}).inkey
- )
- .then(function (response) {
- self.stalls = _.reject(self.stalls, function (obj) {
- return obj.id == stallId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportStallsCSV: function () {
- LNbits.utils.exportCSV(this.stallsTable.columns, this.stalls)
- },
- ////////////////////////////////////////
- ///////////////PRODUCTS/////////////////
- ////////////////////////////////////////
- getProducts: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/products?all_stalls',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.products.push(mapProducts(response.data))
- })
- },
- openProductUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.products, {id: linkId})
-
- self.productDialog.data = _.clone(link._data)
- self.productDialog.show = true
- },
- sendProductFormData: function () {
- if (this.productDialog.data.id) {
- } else {
- var data = {
- product: this.productDialog.data.product,
- categories:
- this.productDialog.data.categories +
- this.productDialog.categoriesextra,
- description: this.productDialog.data.description,
- image: this.productDialog.data.image,
- price: this.productDialog.data.price,
- quantity: this.productDialog.data.quantity
- }
- }
- if (this.productDialog.data.id) {
- this.updateProduct(this.productDialog.data)
- } else {
- this.createProduct(data)
- }
- },
- imageAdded(file) {
- let blobURL = URL.createObjectURL(file)
- let image = new Image()
- image.src = blobURL
- image.onload = async () => {
- let canvas = document.createElement('canvas')
- canvas.setAttribute('width', 100)
- canvas.setAttribute('height', 100)
- await pica.resize(image, canvas, {
- quality: 0,
- alpha: true,
- unsharpAmount: 95,
- unsharpRadius: 0.9,
- unsharpThreshold: 70
- })
- this.productDialog.data.image = canvas.toDataURL()
- this.productDialog = {...this.productDialog}
- }
- },
- imageCleared() {
- this.productDialog.data.image = null
- this.productDialog = {...this.productDialog}
- },
- updateProduct: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/products' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.productDialog.data.wallet
- }).inkey,
- _.pick(
- data,
- 'shopname',
- 'relayaddress',
- 'shippingzone1',
- 'zone1cost',
- 'shippingzone2',
- 'zone2cost',
- 'email'
- )
- )
- .then(function (response) {
- self.products = _.reject(self.products, function (obj) {
- return obj.id == data.id
- })
- self.products.push(mapProducts(response.data))
- self.productDialog.show = false
- self.productDialog.data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createProduct: function (data) {
- var self = this
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/products',
- _.findWhere(self.g.user.wallets, {
- id: self.productDialog.data.wallet
- }).inkey,
- data
- )
- .then(function (response) {
- self.products.push(mapProducts(response.data))
- self.productDialog.show = false
- self.productDialog.data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteProduct: function (productId) {
- var self = this
- var product = _.findWhere(this.products, {id: productId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this products link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/products/' + productId,
- _.findWhere(self.g.user.wallets, {id: product.wallet}).inkey
- )
- .then(function (response) {
- self.products = _.reject(self.products, function (obj) {
- return obj.id == productId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportProductsCSV: function () {
- LNbits.utils.exportCSV(this.productsTable.columns, this.products)
- },
- ////////////////////////////////////////
- //////////////////ZONE//////////////////
- ////////////////////////////////////////
- getZones: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/zones?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.zones.push(mapZone(response.data))
- })
- },
- openZoneUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.zones, {id: linkId})
-
- this.zoneDialog.data = _.clone(link._data)
- this.zoneDialog.show = true
- },
- sendZoneFormData: function () {
- if (this.zoneDialog.data.id) {
- } else {
- var data = {
- countries: toString(this.zoneDialog.data.countries),
- cost: parseInt(this.zoneDialog.data.cost)
- }
- }
-
- if (this.zoneDialog.data.id) {
- this.updateZone(this.zoneDialog.data)
- } else {
- this.createZone(data)
- }
- },
- updateZone: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/zones' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.zoneDialog.data.wallet
- }).inkey,
- _.pick(data, 'countries', 'cost')
- )
- .then(function (response) {
- self.zones = _.reject(self.zones, function (obj) {
- return obj.id == data.id
- })
- self.zones.push(mapZone(response.data))
- self.zoneDialog.show = false
- self.zoneDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createZone: function (data) {
- var self = this
- console.log(self.g.user.wallets[0])
- console.log(data)
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/zones',
- self.g.user.wallets[0].inkey,
- data
- )
- .then(function (response) {
- self.zones.push(mapZone(response.data))
- self.zoneDialog.show = false
- self.zoneDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteZone: function (zoneId) {
- var self = this
- var zone = _.findWhere(self.zones, {id: zoneId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this Zone link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/zones/' + zoneId,
- _.findWhere(self.g.user.wallets, {id: zone.wallet}).inkey
- )
- .then(function (response) {
- self.zones = _.reject(self.zones, function (obj) {
- return obj.id == zoneId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportZonesCSV: function () {
- LNbits.utils.exportCSV(this.zonesTable.columns, this.zones)
- },
- ////////////////////////////////////////
- //////////////////SHOP//////////////////
- ////////////////////////////////////////
- getShops: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/shops?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.shops.push(mapShops(response.data))
- })
- },
- openShopUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.shops, {id: linkId})
-
- this.shopDialog.data = _.clone(link._data)
- this.shopDialog.show = true
- },
- sendShopFormData: function () {
- if (this.shopDialog.data.id) {
- } else {
- var data = {
- countries: this.shopDialog.data.countries,
- cost: this.shopDialog.data.cost
- }
- }
-
- if (this.shopDialog.data.id) {
- this.updateZone(this.shopDialog.data)
- } else {
- this.createZone(data)
- }
- },
- updateShop: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/shops' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.shopDialog.data.wallet
- }).inkey,
- _.pick(data, 'countries', 'cost')
- )
- .then(function (response) {
- self.shops = _.reject(self.shops, function (obj) {
- return obj.id == data.id
- })
- self.shops.push(mapShops(response.data))
- self.shopDialog.show = false
- self.shopDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createShop: function (data) {
- var self = this
- console.log('cuntywoo')
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/shops',
- _.findWhere(self.g.user.wallets, {
- id: self.shopDialog.data.wallet
- }).inkey,
- data
- )
- .then(function (response) {
- self.shops.push(mapShops(response.data))
- self.shopDialog.show = false
- self.shopDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteShop: function (shopId) {
- var self = this
- var shop = _.findWhere(self.shops, {id: shopId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this Shop link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/shops/' + shopId,
- _.findWhere(self.g.user.wallets, {id: shop.wallet}).inkey
- )
- .then(function (response) {
- self.shops = _.reject(self.shops, function (obj) {
- return obj.id == shopId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportShopsCSV: function () {
- LNbits.utils.exportCSV(this.shopsTable.columns, this.shops)
- },
- ////////////////////////////////////////
- ////////////////ORDERS//////////////////
- ////////////////////////////////////////
- getOrders: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/orders?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
- })
- },
- createOrder: function () {
- var data = {
- address: this.orderDialog.data.address,
- email: this.orderDialog.data.email,
- quantity: this.orderDialog.data.quantity,
- shippingzone: this.orderDialog.data.shippingzone
- }
- var self = this
-
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/orders',
- _.findWhere(self.g.user.wallets, {id: self.orderDialog.data.wallet})
- .inkey,
- data
- )
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
- self.orderDialog.show = false
- self.orderDialog.data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteOrder: function (orderId) {
- var self = this
- var order = _.findWhere(self.orders, {id: orderId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this order link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/orders/' + orderId,
- _.findWhere(self.g.user.wallets, {id: order.wallet}).inkey
- )
- .then(function (response) {
- self.orders = _.reject(self.orders, function (obj) {
- return obj.id == orderId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- shipOrder: function (order_id) {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/orders/shipped/' + order_id,
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
- })
- },
- exportOrdersCSV: function () {
- LNbits.utils.exportCSV(this.ordersTable.columns, this.orders)
- }
- },
- created: function () {
- if (this.g.user.wallets.length) {
- this.getStalls()
- this.getProducts()
- this.getZones()
- this.getOrders()
- this.customerKeys = [
- 'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
- 'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
- ]
- }
- }
-})
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index d14d7cee..7b8f8e6a 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -300,8 +300,9 @@
- + Product List a product + Product List a produc
+ Product List a product + Shipping Zone Create a shipping zone
- + Stall
Create a stall to list products on
@@ -321,6 +322,7 @@
>Launch frontend shop (not Nostr)
Makes a simple frontend shop for your stalls
+
@@ -638,7 +640,890 @@
+
{% endblock %} {% block scripts %} {{ window_vars(user) }}
-
-
+
+
{% endblock %}
+
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 43232841..6363dc97 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -121,36 +121,32 @@ async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = D
@diagonalley_ext.get("/api/v1/zones")
-async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
- wallet_ids = [wallet.wallet.id]
+async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type)):
- if all_wallets:
- wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
-
- return ([zone.dict() for zone in await get_diagonalley_zones(wallet_ids)])
+ return await get_diagonalley_zones(wallet.wallet.user)
@diagonalley_ext.post("/api/v1/zones")
-@diagonalley_ext.put("/api/v1/zones/{zone_id}")
async def api_diagonalley_zone_create(
data: createZones,
- zone_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
- if zone_id:
- zone = await get_diagonalley_zone(zone_id)
-
- if not zone:
- return ({"message": "Zone does not exist."})
-
- if zone.wallet != wallet.wallet.id:
- return ({"message": "Not your record."})
-
- zone = await update_diagonalley_zone(zone_id, **data.dict())
- else:
- zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data=data)
-
+ zone = await create_diagonalley_zone(user=wallet.wallet.user, data=data)
return zone.dict()
+@diagonalley_ext.post("/api/v1/zones/{zone_id}")
+async def api_diagonalley_zone_update(
+ data: createZones,
+ zone_id: str = Query(None),
+ wallet: WalletTypeInfo = Depends(require_admin_key)
+ ):
+ zone = await get_diagonalley_zone(zone_id)
+ if not zone:
+ return ({"message": "Zone does not exist."})
+ if zone.user != wallet.wallet.user:
+ return ({"message": "Not your record."})
+ zone = await update_diagonalley_zone(zone_id, **data.dict())
+ return zone
+
@diagonalley_ext.delete("/api/v1/zones/{zone_id}")
async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
@@ -159,7 +155,7 @@ async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(
if not zone:
return ({"message": "zone does not exist."})
- if zone.wallet != wallet.wallet.id:
+ if zone.user != wallet.wallet.user:
return ({"message": "Not your zone."})
await delete_diagonalley_zone(zone_id)
From 80b73e7aba1b1dff80693265dadd96946b27375e Mon Sep 17 00:00:00 2001
From: benarc
Date: Sun, 6 Feb 2022 22:40:51 +0000
Subject: [PATCH 010/226] small fix
---
.../templates/diagonalley/index.html | 25 +++++++++++++------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 7b8f8e6a..6d6ea872 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -244,7 +244,7 @@
label="Private Key"
>
@@ -270,7 +270,7 @@
filled
dense
v-model.trim="stallDialog.data.nostrShops"
- label="Stall public keys (seperate by comma)"
+ label="Nostr shop public keys (seperate by comma)"
>
- + Product List a produc 1" color="primary" @click="productDialog.show = true"
+ >+ Product List a product
+ Product List a product + Shipping Zone
Create a shipping zone
-
+ Stall
Create a stall to list products on
@@ -675,6 +675,7 @@ new Vue({
orders: [],
stalls: [],
zones: [],
+ zoneOptions: [],
customerKeys: [],
customerKey: '',
customerMessages: {},
@@ -949,10 +950,19 @@ new Vue({
LNbits.utils.notifyApiError(error)
})
},
+ openStallDialog: function () {
+ console.log(this.zones[0]['id'])
+ for(let i = 0; i < this.zones.length; i ++){
+ this.zoneOptions.push(this.zones[i]['id'])
+ }
+ this.stallDialog.show = true
+ },
openStallUpdateDialog: function (linkId) {
var self = this
var link = _.findWhere(self.stalls, {id: linkId})
-
+ for(let i = 0; i < this.zones.length; i ++){
+ this.zoneOptions.push(this.stalls[i][0])
+ }
this.stallDialog.data = _.clone(link._data)
this.stallDialog.show = true
},
@@ -1210,6 +1220,7 @@ new Vue({
if (response.data) {
console.log(response)
self.zones = response.data.map(mapZone)
+
}
})
.catch(function (error) {
From f38492a9209f27cf587946c0359c5ae047d9463c Mon Sep 17 00:00:00 2001
From: benarc
Date: Mon, 7 Feb 2022 13:22:43 +0000
Subject: [PATCH 011/226] Added nostr ext
---
lnbits/extensions/nostr/README.md | 3 +
lnbits/extensions/nostr/__init__.py | 17 +
lnbits/extensions/nostr/config.json | 6 +
lnbits/extensions/nostr/crud.py | 134 +++++
lnbits/extensions/nostr/migrations.py | 47 ++
lnbits/extensions/nostr/models.py | 34 ++
.../templates/lnurldevice/_api_docs.html | 169 ++++++
.../nostr/templates/lnurldevice/error.html | 34 ++
.../nostr/templates/lnurldevice/index.html | 534 ++++++++++++++++++
.../nostr/templates/lnurldevice/paid.html | 27 +
lnbits/extensions/nostr/views.py | 24 +
lnbits/extensions/nostr/views_api.py | 48 ++
12 files changed, 1077 insertions(+)
create mode 100644 lnbits/extensions/nostr/README.md
create mode 100644 lnbits/extensions/nostr/__init__.py
create mode 100644 lnbits/extensions/nostr/config.json
create mode 100644 lnbits/extensions/nostr/crud.py
create mode 100644 lnbits/extensions/nostr/migrations.py
create mode 100644 lnbits/extensions/nostr/models.py
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/error.html
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/index.html
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/paid.html
create mode 100644 lnbits/extensions/nostr/views.py
create mode 100644 lnbits/extensions/nostr/views_api.py
diff --git a/lnbits/extensions/nostr/README.md b/lnbits/extensions/nostr/README.md
new file mode 100644
index 00000000..596cce9d
--- /dev/null
+++ b/lnbits/extensions/nostr/README.md
@@ -0,0 +1,3 @@
+# Nostr
+
+Opens a Nostr daemon
diff --git a/lnbits/extensions/nostr/__init__.py b/lnbits/extensions/nostr/__init__.py
new file mode 100644
index 00000000..775960e3
--- /dev/null
+++ b/lnbits/extensions/nostr/__init__.py
@@ -0,0 +1,17 @@
+from fastapi import APIRouter
+
+from lnbits.db import Database
+from lnbits.helpers import template_renderer
+
+db = Database("ext_nostr")
+
+nostr_ext: APIRouter = APIRouter(prefix="/nostr", tags=["nostr"])
+
+
+def nostr_renderer():
+ return template_renderer(["lnbits/extensions/nostr/templates"])
+
+
+from .lnurl import * # noqa
+from .views import * # noqa
+from .views_api import * # noqa
diff --git a/lnbits/extensions/nostr/config.json b/lnbits/extensions/nostr/config.json
new file mode 100644
index 00000000..a32e39a1
--- /dev/null
+++ b/lnbits/extensions/nostr/config.json
@@ -0,0 +1,6 @@
+{
+ "name": "Nostr",
+ "short_description": "Daemon for Nostr",
+ "icon": "swap_horizontal_circle",
+ "contributors": ["arcbtc"]
+}
diff --git a/lnbits/extensions/nostr/crud.py b/lnbits/extensions/nostr/crud.py
new file mode 100644
index 00000000..55e99ec6
--- /dev/null
+++ b/lnbits/extensions/nostr/crud.py
@@ -0,0 +1,134 @@
+from typing import List, Optional, Union
+
+from lnbits.helpers import urlsafe_short_hash
+
+from . import db
+from .models import nostrKeys, nostrNotes, nostrRelays, nostrConnections
+
+###############KEYS##################
+
+async def create_nostrkeys(
+ data: nostrKeys
+) -> nostrKeys:
+ nostrkey_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO nostr.keys (
+ id,
+ pubkey,
+ privkey
+ )
+ VALUES (?, ?, ?)
+ """,
+ (nostrkey_id, data.pubkey, data.privkey),
+ )
+ return await get_nostrkeys(nostrkey_id)
+
+async def get_nostrkeys(nostrkey_id: str) -> nostrKeys:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.keys WHERE id = ?",
+ (lnurldevicepayment_id,),
+ )
+ return nostrKeys(**row) if row else None
+
+
+###############NOTES##################
+
+async def create_nostrnotes(
+ data: nostrNotes
+) -> nostrNotes:
+ await db.execute(
+ """
+ INSERT INTO nostr.notes (
+ id,
+ pubkey,
+ created_at,
+ kind,
+ tags,
+ content,
+ sig
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ """,
+ (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
+ )
+ return await get_nostrnotes(data.id)
+
+async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.notes WHERE id = ?",
+ (nostrnote_id,),
+ )
+ return nostrNotes(**row) if row else None
+
+###############RELAYS##################
+
+async def create_nostrrelays(
+ relay: str
+) -> nostrRelays:
+ nostrrelay_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO nostr.relays (
+ id,
+ relay
+ )
+ VALUES (?, ?)
+ """,
+ (nostrrelay_id, relay),
+ )
+ return await get_nostrnotes(nostrrelay_id)
+
+async def get_nostrrelays(nostrrelay_id: str) -> nostrRelays:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.relays WHERE id = ?",
+ (nostrnote_id,),
+ )
+ return nostrRelays(**row) if row else None
+
+
+###############CONNECTIONS##################
+
+async def create_nostrconnections(
+ data: nostrNotes
+) -> nostrNotes:
+ nostrkey_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO nostr.notes (
+ id,
+ pubkey,
+ created_at,
+ kind,
+ tags,
+ content,
+ sig
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ """,
+ (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
+ )
+ return await get_nostrnotes(data.id)
+
+async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.notes WHERE id = ?",
+ (nostrnote_id,),
+ )
+ return nostrNotes(**row) if row else None
+
+
+
+async def update_lnurldevicepayment(
+ lnurldevicepayment_id: str, **kwargs
+) -> Optional[lnurldevicepayment]:
+ q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
+ await db.execute(
+ f"UPDATE lnurldevice.lnurldevicepayment SET {q} WHERE id = ?",
+ (*kwargs.values(), lnurldevicepayment_id),
+ )
+ row = await db.fetchone(
+ "SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?",
+ (lnurldevicepayment_id,),
+ )
+ return lnurldevicepayment(**row) if row else None
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/migrations.py b/lnbits/extensions/nostr/migrations.py
new file mode 100644
index 00000000..de32a578
--- /dev/null
+++ b/lnbits/extensions/nostr/migrations.py
@@ -0,0 +1,47 @@
+from lnbits.db import Database
+
+db2 = Database("ext_nostr")
+
+
+async def m001_initial(db):
+ """
+ Initial nostr table.
+ """
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.keys (
+ pubkey TEXT NOT NULL PRIMARY KEY,
+ privkey TEXT NOT NULL
+ );
+ """
+ )
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.notes (
+ id TEXT NOT NULL PRIMARY KEY,
+ pubkey TEXT NOT NULL,
+ created_at TEXT NOT NULL,
+ kind INT NOT NULL,
+ tags TEXT NOT NULL,
+ content TEXT NOT NULL,
+ sig TEXT NOT NULL,
+ );
+ """
+ )
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.relays (
+ id TEXT NOT NULL PRIMARY KEY,
+ relay TEXT NOT NULL
+ );
+ """
+ )
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.connections (
+ id TEXT NOT NULL PRIMARY KEY,
+ publickey TEXT NOT NULL,
+ relayid TEXT NOT NULL
+ );
+ """
+ )
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/models.py b/lnbits/extensions/nostr/models.py
new file mode 100644
index 00000000..ba0c87a5
--- /dev/null
+++ b/lnbits/extensions/nostr/models.py
@@ -0,0 +1,34 @@
+import json
+from sqlite3 import Row
+from typing import Optional
+
+from fastapi import Request
+from lnurl import Lnurl
+from lnurl import encode as lnurl_encode # type: ignore
+from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
+from lnurl.types import LnurlPayMetadata # type: ignore
+from pydantic import BaseModel
+from pydantic.main import BaseModel
+
+class nostrKeys(BaseModel):
+ id: str
+ pubkey: str
+ privkey: str
+
+class nostrNotes(BaseModel):
+ id: str
+ pubkey: str
+ created_at: str
+ kind: int
+ tags: str
+ content: str
+ sig: str
+
+class nostrRelays(BaseModel):
+ id: str
+ relay: str
+
+class nostrConnections(BaseModel):
+ id: str
+ pubkey: str
+ relayid: str
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html b/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
new file mode 100644
index 00000000..af69b76e
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
@@ -0,0 +1,169 @@
+
+
+
+ Register LNURLDevice devices to receive payments in your LNbits wallet.
+ Build your own here
+ https://github.com/arcbtc/bitcoinpos
+
+ Created by, Ben Arc
+
+
+
+
+
+
+ /lnurldevice/api/v1/lnurlpos
+ Headers
+ {"X-Api-Key": <admin_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X POST {{ request.base_url }}api/v1/lnurldevice -d '{"title":
+ <string>, "message":<string>, "currency":
+ <integer>}' -H "Content-type: application/json" -H "X-Api-Key:
+ {{user.wallets[0].adminkey }}"
+
+
+
+
+
+
+
+ PUT
+ /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
+ Headers
+ {"X-Api-Key": <admin_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X POST {{ request.base_url
+ }}api/v1/lnurlpos/<lnurldevice_id> -d ''{"title":
+ <string>, "message":<string>, "currency":
+ <integer>} -H "Content-type: application/json" -H "X-Api-Key:
+ {{user.wallets[0].adminkey }}"
+
+
+
+
+
+
+
+
+ GET
+ /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
+ Headers
+ {"X-Api-Key": <invoice_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X GET {{ request.base_url
+ }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
+ user.wallets[0].inkey }}"
+
+
+
+
+
+
+
+ GET
+ /lnurldevice/api/v1/lnurlposs
+ Headers
+ {"X-Api-Key": <invoice_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X GET {{ request.base_url }}api/v1/lnurldevices -H
+ "X-Api-Key: {{ user.wallets[0].inkey }}"
+
+
+
+
+
+
+
+ DELETE
+ /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
+ Headers
+ {"X-Api-Key": <admin_key>}
+ Returns 204 NO CONTENT
+
+ Curl example
+ curl -X DELETE {{ request.base_url
+ }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
+ user.wallets[0].adminkey }}"
+
+
+
+
+
+
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/error.html b/lnbits/extensions/nostr/templates/lnurldevice/error.html
new file mode 100644
index 00000000..d8e41832
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/error.html
@@ -0,0 +1,34 @@
+{% extends "public.html" %} {% block page %}
+
+
+
+
+
+ LNURL-pay not paid
+
+
+
+
+
+
+
+
+
+ {% endblock %} {% block scripts %}
+
+
+
+ {% endblock %}
+
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/index.html b/lnbits/extensions/nostr/templates/lnurldevice/index.html
new file mode 100644
index 00000000..b51e2556
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/index.html
@@ -0,0 +1,534 @@
+{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
+%} {% block page %}
+
+
+
+
+ {% raw %}
+ New LNURLDevice instance
+
+
+
+
+
+
+
+
+
lNURLdevice
+
+
+
+
+
+
+
+
+ Export to CSV
+
+
+
+
+
+
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+
+ Delete LNURLDevice
+
+
+
+
+ LNURLDevice Settings
+
+
+
+
+ {{ col.value }}
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
+ {{SITE_TITLE}} LNURLDevice Extension
+
+
+
+
+ {% include "lnurldevice/_api_docs.html" %}
+
+
+
+
+
+
+ LNURLDevice device string
+ {% raw
+ %}{{location}}/lnurldevice/api/v1/lnurl/{{settingsDialog.data.id}},
+ {{settingsDialog.data.key}}, {{settingsDialog.data.currency}}{% endraw
+ %} Click to copy URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Update lnurldevice
+ Create lnurldevice
+ Cancel
+
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }}
+
+
+{% endblock %}
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/paid.html b/lnbits/extensions/nostr/templates/lnurldevice/paid.html
new file mode 100644
index 00000000..c185ecce
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/paid.html
@@ -0,0 +1,27 @@
+{% extends "public.html" %} {% block page %}
+
+
+
+
+
+ {{ pin }}
+
+
+
+
+
+
+ {% endblock %} {% block scripts %}
+
+
+
+ {% endblock %}
+
diff --git a/lnbits/extensions/nostr/views.py b/lnbits/extensions/nostr/views.py
new file mode 100644
index 00000000..1dfc07da
--- /dev/null
+++ b/lnbits/extensions/nostr/views.py
@@ -0,0 +1,24 @@
+from http import HTTPStatus
+
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from fastapi.templating import Jinja2Templates
+from starlette.exceptions import HTTPException
+from starlette.responses import HTMLResponse
+
+from lnbits.core.crud import update_payment_status
+from lnbits.core.models import User
+from lnbits.core.views.api import api_payment
+from lnbits.decorators import check_user_exists
+
+from . import nostr_ext, nostr_renderer
+
+templates = Jinja2Templates(directory="templates")
+
+
+@nostr_ext.get("/", response_class=HTMLResponse)
+async def index(request: Request, user: User = Depends(check_user_exists)):
+ return nostr_renderer().TemplateResponse(
+ "nostr/index.html", {"request": request, "user": user.dict()}
+ )
diff --git a/lnbits/extensions/nostr/views_api.py b/lnbits/extensions/nostr/views_api.py
new file mode 100644
index 00000000..a479cad8
--- /dev/null
+++ b/lnbits/extensions/nostr/views_api.py
@@ -0,0 +1,48 @@
+from http import HTTPStatus
+
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from starlette.exceptions import HTTPException
+
+from lnbits.core.crud import get_user
+from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
+from lnbits.extensions.lnurldevice import lnurldevice_ext
+from lnbits.utils.exchange_rates import currencies
+
+from . import lnurldevice_ext
+from .crud import (
+ create_lnurldevice,
+ delete_lnurldevice,
+ get_lnurldevice,
+ get_lnurldevices,
+ update_lnurldevice,
+)
+from .models import createLnurldevice
+
+
+@nostr_ext.get("/api/v1/lnurlpos")
+async def api_check_daemon(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+ try:
+ return [
+ {**lnurldevice.dict()} for lnurldevice in await get_lnurldevices(wallet_ids)
+ ]
+ except:
+ return ""
+
+@nostr_ext.delete("/api/v1/lnurlpos/{lnurldevice_id}")
+async def api_lnurldevice_delete(
+ wallet: WalletTypeInfo = Depends(require_admin_key),
+ lnurldevice_id: str = Query(None),
+):
+ lnurldevice = await get_lnurldevice(lnurldevice_id)
+
+ if not lnurldevice:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Wallet link does not exist."
+ )
+
+ await delete_lnurldevice(lnurldevice_id)
+
+ return "", HTTPStatus.NO_CONTENT
\ No newline at end of file
From da1025a625b75dc842efb2baf7582cfb5682a191 Mon Sep 17 00:00:00 2001
From: benarc
Date: Mon, 7 Feb 2022 20:01:01 +0000
Subject: [PATCH 012/226] extension loading
---
lnbits/extensions/nostr/__init__.py | 2 -
lnbits/extensions/nostr/crud.py | 71 +--
lnbits/extensions/nostr/migrations.py | 2 +-
lnbits/extensions/nostr/models.py | 12 +-
.../templates/lnurldevice/_api_docs.html | 169 ------
.../nostr/templates/lnurldevice/error.html | 34 --
.../nostr/templates/lnurldevice/index.html | 534 ------------------
.../nostr/templates/lnurldevice/paid.html | 27 -
.../nostr/templates/nostr/index.html | 159 ++++++
lnbits/extensions/nostr/views_api.py | 46 +-
10 files changed, 204 insertions(+), 852 deletions(-)
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/error.html
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/index.html
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/paid.html
create mode 100644 lnbits/extensions/nostr/templates/nostr/index.html
diff --git a/lnbits/extensions/nostr/__init__.py b/lnbits/extensions/nostr/__init__.py
index 775960e3..9774a279 100644
--- a/lnbits/extensions/nostr/__init__.py
+++ b/lnbits/extensions/nostr/__init__.py
@@ -11,7 +11,5 @@ nostr_ext: APIRouter = APIRouter(prefix="/nostr", tags=["nostr"])
def nostr_renderer():
return template_renderer(["lnbits/extensions/nostr/templates"])
-
-from .lnurl import * # noqa
from .views import * # noqa
from .views_api import * # noqa
diff --git a/lnbits/extensions/nostr/crud.py b/lnbits/extensions/nostr/crud.py
index 55e99ec6..0b30bc9a 100644
--- a/lnbits/extensions/nostr/crud.py
+++ b/lnbits/extensions/nostr/crud.py
@@ -1,33 +1,31 @@
from typing import List, Optional, Union
from lnbits.helpers import urlsafe_short_hash
-
+import shortuuid
from . import db
-from .models import nostrKeys, nostrNotes, nostrRelays, nostrConnections
+from .models import nostrKeys, nostrNotes, nostrCreateRelays, nostrRelays, nostrConnections, nostrCreateConnections
###############KEYS##################
async def create_nostrkeys(
data: nostrKeys
) -> nostrKeys:
- nostrkey_id = urlsafe_short_hash()
await db.execute(
"""
INSERT INTO nostr.keys (
- id,
pubkey,
privkey
)
- VALUES (?, ?, ?)
+ VALUES (?, ?)
""",
- (nostrkey_id, data.pubkey, data.privkey),
+ (data.pubkey, data.privkey),
)
return await get_nostrkeys(nostrkey_id)
-async def get_nostrkeys(nostrkey_id: str) -> nostrKeys:
+async def get_nostrkeys(pubkey: str) -> nostrKeys:
row = await db.fetchone(
- "SELECT * FROM nostr.keys WHERE id = ?",
- (lnurldevicepayment_id,),
+ "SELECT * FROM nostr.keys WHERE pubkey = ?",
+ (pubkey,),
)
return nostrKeys(**row) if row else None
@@ -64,9 +62,12 @@ async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
###############RELAYS##################
async def create_nostrrelays(
- relay: str
-) -> nostrRelays:
- nostrrelay_id = urlsafe_short_hash()
+ data: nostrCreateRelays
+) -> nostrCreateRelays:
+ nostrrelay_id = shortuuid.uuid(name=relay)
+
+ if await get_nostrrelays(nostrrelay_id):
+ return "error"
await db.execute(
"""
INSERT INTO nostr.relays (
@@ -75,7 +76,7 @@ async def create_nostrrelays(
)
VALUES (?, ?)
""",
- (nostrrelay_id, relay),
+ (nostrrelay_id, data.relay),
)
return await get_nostrnotes(nostrrelay_id)
@@ -90,45 +91,25 @@ async def get_nostrrelays(nostrrelay_id: str) -> nostrRelays:
###############CONNECTIONS##################
async def create_nostrconnections(
- data: nostrNotes
-) -> nostrNotes:
- nostrkey_id = urlsafe_short_hash()
+ data: nostrCreateConnections
+) -> nostrCreateConnections:
+ nostrrelay_id = shortuuid.uuid(name=data.relayid + data.pubkey)
await db.execute(
"""
- INSERT INTO nostr.notes (
+ INSERT INTO nostr.connections (
id,
pubkey,
- created_at,
- kind,
- tags,
- content,
- sig
+ relayid
)
- VALUES (?, ?, ?, ?, ?, ?, ?)
+ VALUES (?, ?, ?)
""",
- (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
+ (data.id, data.pubkey, data.relayid),
)
- return await get_nostrnotes(data.id)
+ return await get_nostrconnections(data.id)
-async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+async def get_nostrconnections(nostrconnections_id: str) -> nostrConnections:
row = await db.fetchone(
- "SELECT * FROM nostr.notes WHERE id = ?",
- (nostrnote_id,),
+ "SELECT * FROM nostr.connections WHERE id = ?",
+ (nostrconnections_id,),
)
- return nostrNotes(**row) if row else None
-
-
-
-async def update_lnurldevicepayment(
- lnurldevicepayment_id: str, **kwargs
-) -> Optional[lnurldevicepayment]:
- q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
- await db.execute(
- f"UPDATE lnurldevice.lnurldevicepayment SET {q} WHERE id = ?",
- (*kwargs.values(), lnurldevicepayment_id),
- )
- row = await db.fetchone(
- "SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?",
- (lnurldevicepayment_id,),
- )
- return lnurldevicepayment(**row) if row else None
\ No newline at end of file
+ return nostrConnections(**row) if row else None
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/migrations.py b/lnbits/extensions/nostr/migrations.py
index de32a578..0c616110 100644
--- a/lnbits/extensions/nostr/migrations.py
+++ b/lnbits/extensions/nostr/migrations.py
@@ -24,7 +24,7 @@ async def m001_initial(db):
kind INT NOT NULL,
tags TEXT NOT NULL,
content TEXT NOT NULL,
- sig TEXT NOT NULL,
+ sig TEXT NOT NULL
);
"""
)
diff --git a/lnbits/extensions/nostr/models.py b/lnbits/extensions/nostr/models.py
index ba0c87a5..e21e5d76 100644
--- a/lnbits/extensions/nostr/models.py
+++ b/lnbits/extensions/nostr/models.py
@@ -3,15 +3,10 @@ from sqlite3 import Row
from typing import Optional
from fastapi import Request
-from lnurl import Lnurl
-from lnurl import encode as lnurl_encode # type: ignore
-from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
-from lnurl.types import LnurlPayMetadata # type: ignore
from pydantic import BaseModel
from pydantic.main import BaseModel
class nostrKeys(BaseModel):
- id: str
pubkey: str
privkey: str
@@ -24,6 +19,13 @@ class nostrNotes(BaseModel):
content: str
sig: str
+class nostrCreateRelays(BaseModel):
+ relay: str
+
+class nostrCreateConnections(BaseModel):
+ pubkey: str
+ relayid: str
+
class nostrRelays(BaseModel):
id: str
relay: str
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html b/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
deleted file mode 100644
index af69b76e..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
+++ /dev/null
@@ -1,169 +0,0 @@
-
-
-
- Register LNURLDevice devices to receive payments in your LNbits wallet.
- Build your own here
- https://github.com/arcbtc/bitcoinpos
-
- Created by, Ben Arc
-
-
-
-
-
-
- /lnurldevice/api/v1/lnurlpos
- Headers
- {"X-Api-Key": <admin_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X POST {{ request.base_url }}api/v1/lnurldevice -d '{"title":
- <string>, "message":<string>, "currency":
- <integer>}' -H "Content-type: application/json" -H "X-Api-Key:
- {{user.wallets[0].adminkey }}"
-
-
-
-
-
-
-
- PUT
- /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
- Headers
- {"X-Api-Key": <admin_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X POST {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -d ''{"title":
- <string>, "message":<string>, "currency":
- <integer>} -H "Content-type: application/json" -H "X-Api-Key:
- {{user.wallets[0].adminkey }}"
-
-
-
-
-
-
-
-
- GET
- /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
- Headers
- {"X-Api-Key": <invoice_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X GET {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
- user.wallets[0].inkey }}"
-
-
-
-
-
-
-
- GET
- /lnurldevice/api/v1/lnurlposs
- Headers
- {"X-Api-Key": <invoice_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X GET {{ request.base_url }}api/v1/lnurldevices -H
- "X-Api-Key: {{ user.wallets[0].inkey }}"
-
-
-
-
-
-
-
- DELETE
- /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
- Headers
- {"X-Api-Key": <admin_key>}
- Returns 204 NO CONTENT
-
- Curl example
- curl -X DELETE {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
- user.wallets[0].adminkey }}"
-
-
-
-
-
-
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/error.html b/lnbits/extensions/nostr/templates/lnurldevice/error.html
deleted file mode 100644
index d8e41832..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/error.html
+++ /dev/null
@@ -1,34 +0,0 @@
-{% extends "public.html" %} {% block page %}
-
-
-
-
-
- LNURL-pay not paid
-
-
-
-
-
-
-
-
-
- {% endblock %} {% block scripts %}
-
-
-
- {% endblock %}
-
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/index.html b/lnbits/extensions/nostr/templates/lnurldevice/index.html
deleted file mode 100644
index b51e2556..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/index.html
+++ /dev/null
@@ -1,534 +0,0 @@
-{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
-%} {% block page %}
-
-
-
-
- {% raw %}
- New LNURLDevice instance
-
-
-
-
-
-
-
-
-
lNURLdevice
-
-
-
-
-
-
-
-
- Export to CSV
-
-
-
-
-
-
-
-
-
-
- {{ col.label }}
-
-
-
-
-
-
-
-
-
- Delete LNURLDevice
-
-
-
-
- LNURLDevice Settings
-
-
-
-
- {{ col.value }}
-
-
-
- {% endraw %}
-
-
-
-
-
-
-
-
-
- {{SITE_TITLE}} LNURLDevice Extension
-
-
-
-
- {% include "lnurldevice/_api_docs.html" %}
-
-
-
-
-
-
- LNURLDevice device string
- {% raw
- %}{{location}}/lnurldevice/api/v1/lnurl/{{settingsDialog.data.id}},
- {{settingsDialog.data.key}}, {{settingsDialog.data.currency}}{% endraw
- %} Click to copy URL
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Update lnurldevice
- Create lnurldevice
- Cancel
-
-
-
-
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }}
-
-
-{% endblock %}
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/paid.html b/lnbits/extensions/nostr/templates/lnurldevice/paid.html
deleted file mode 100644
index c185ecce..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/paid.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{% extends "public.html" %} {% block page %}
-
-
-
-
-
- {{ pin }}
-
-
-
-
-
-
- {% endblock %} {% block scripts %}
-
-
-
- {% endblock %}
-
diff --git a/lnbits/extensions/nostr/templates/nostr/index.html b/lnbits/extensions/nostr/templates/nostr/index.html
new file mode 100644
index 00000000..f17d0243
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/nostr/index.html
@@ -0,0 +1,159 @@
+{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
+%} {% block page %}
+
+
+
+
+
+
+
Nostr
+
+
+
+
+
+
+
+
+ Export to CSV
+
+
+
+ {% raw %}
+
+
+
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+
+ {{ col.value }}
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+ {{SITE_TITLE}} Nostr Extension
+
+ Okay
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }}
+
+
+{% endblock %}
diff --git a/lnbits/extensions/nostr/views_api.py b/lnbits/extensions/nostr/views_api.py
index a479cad8..9e7ccfff 100644
--- a/lnbits/extensions/nostr/views_api.py
+++ b/lnbits/extensions/nostr/views_api.py
@@ -7,42 +7,18 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
-from lnbits.extensions.lnurldevice import lnurldevice_ext
+from lnbits.extensions.nostr import nostr_ext
from lnbits.utils.exchange_rates import currencies
-from . import lnurldevice_ext
+from . import nostr_ext
from .crud import (
- create_lnurldevice,
- delete_lnurldevice,
- get_lnurldevice,
- get_lnurldevices,
- update_lnurldevice,
+ create_nostrkeys,
+ get_nostrkeys,
+ create_nostrnotes,
+ get_nostrnotes,
+ create_nostrrelays,
+ get_nostrrelays,
+ create_nostrconnections,
+ get_nostrconnections,
)
-from .models import createLnurldevice
-
-
-@nostr_ext.get("/api/v1/lnurlpos")
-async def api_check_daemon(wallet: WalletTypeInfo = Depends(get_key_type)):
- wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- try:
- return [
- {**lnurldevice.dict()} for lnurldevice in await get_lnurldevices(wallet_ids)
- ]
- except:
- return ""
-
-@nostr_ext.delete("/api/v1/lnurlpos/{lnurldevice_id}")
-async def api_lnurldevice_delete(
- wallet: WalletTypeInfo = Depends(require_admin_key),
- lnurldevice_id: str = Query(None),
-):
- lnurldevice = await get_lnurldevice(lnurldevice_id)
-
- if not lnurldevice:
- raise HTTPException(
- status_code=HTTPStatus.NOT_FOUND, detail="Wallet link does not exist."
- )
-
- await delete_lnurldevice(lnurldevice_id)
-
- return "", HTTPStatus.NO_CONTENT
\ No newline at end of file
+from .models import nostrKeys
\ No newline at end of file
From 29bd8d9ce963b4a9876120fbe4354121680ca32e Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 10:35:20 +0000
Subject: [PATCH 013/226] Chnaged nostr to nostradmin
---
.env.example | 2 +-
lnbits/extensions/nostr/config.json | 6 -
lnbits/extensions/nostr/crud.py | 115 -------------
lnbits/extensions/nostr/views_api.py | 24 ---
.../{nostr => nostradmin}/README.md | 0
.../{nostr => nostradmin}/__init__.py | 7 +-
lnbits/extensions/nostradmin/config.json | 6 +
lnbits/extensions/nostradmin/crud.py | 156 ++++++++++++++++++
.../{nostr => nostradmin}/migrations.py | 32 +++-
.../{nostr => nostradmin}/models.py | 14 +-
.../templates/nostradmin}/index.html | 130 ++++++++++++++-
.../extensions/{nostr => nostradmin}/views.py | 2 +-
lnbits/extensions/nostradmin/views_api.py | 87 ++++++++++
13 files changed, 421 insertions(+), 160 deletions(-)
delete mode 100644 lnbits/extensions/nostr/config.json
delete mode 100644 lnbits/extensions/nostr/crud.py
delete mode 100644 lnbits/extensions/nostr/views_api.py
rename lnbits/extensions/{nostr => nostradmin}/README.md (100%)
rename lnbits/extensions/{nostr => nostradmin}/__init__.py (51%)
create mode 100644 lnbits/extensions/nostradmin/config.json
create mode 100644 lnbits/extensions/nostradmin/crud.py
rename lnbits/extensions/{nostr => nostradmin}/migrations.py (54%)
rename lnbits/extensions/{nostr => nostradmin}/models.py (73%)
rename lnbits/extensions/{nostr/templates/nostr => nostradmin/templates/nostradmin}/index.html (50%)
rename lnbits/extensions/{nostr => nostradmin}/views.py (90%)
create mode 100644 lnbits/extensions/nostradmin/views_api.py
diff --git a/.env.example b/.env.example
index 060748a9..0d5b497e 100644
--- a/.env.example
+++ b/.env.example
@@ -8,7 +8,7 @@ PORT=5000
LNBITS_ALLOWED_USERS=""
LNBITS_ADMIN_USERS=""
# Extensions only admin can access
-LNBITS_ADMIN_EXTENSIONS="ngrok"
+LNBITS_ADMIN_EXTENSIONS="nostradmin"
LNBITS_DEFAULT_WALLET_NAME="LNbits wallet"
# Disable extensions for all users, use "all" to disable all extensions
diff --git a/lnbits/extensions/nostr/config.json b/lnbits/extensions/nostr/config.json
deleted file mode 100644
index a32e39a1..00000000
--- a/lnbits/extensions/nostr/config.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Nostr",
- "short_description": "Daemon for Nostr",
- "icon": "swap_horizontal_circle",
- "contributors": ["arcbtc"]
-}
diff --git a/lnbits/extensions/nostr/crud.py b/lnbits/extensions/nostr/crud.py
deleted file mode 100644
index 0b30bc9a..00000000
--- a/lnbits/extensions/nostr/crud.py
+++ /dev/null
@@ -1,115 +0,0 @@
-from typing import List, Optional, Union
-
-from lnbits.helpers import urlsafe_short_hash
-import shortuuid
-from . import db
-from .models import nostrKeys, nostrNotes, nostrCreateRelays, nostrRelays, nostrConnections, nostrCreateConnections
-
-###############KEYS##################
-
-async def create_nostrkeys(
- data: nostrKeys
-) -> nostrKeys:
- await db.execute(
- """
- INSERT INTO nostr.keys (
- pubkey,
- privkey
- )
- VALUES (?, ?)
- """,
- (data.pubkey, data.privkey),
- )
- return await get_nostrkeys(nostrkey_id)
-
-async def get_nostrkeys(pubkey: str) -> nostrKeys:
- row = await db.fetchone(
- "SELECT * FROM nostr.keys WHERE pubkey = ?",
- (pubkey,),
- )
- return nostrKeys(**row) if row else None
-
-
-###############NOTES##################
-
-async def create_nostrnotes(
- data: nostrNotes
-) -> nostrNotes:
- await db.execute(
- """
- INSERT INTO nostr.notes (
- id,
- pubkey,
- created_at,
- kind,
- tags,
- content,
- sig
- )
- VALUES (?, ?, ?, ?, ?, ?, ?)
- """,
- (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
- )
- return await get_nostrnotes(data.id)
-
-async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
- row = await db.fetchone(
- "SELECT * FROM nostr.notes WHERE id = ?",
- (nostrnote_id,),
- )
- return nostrNotes(**row) if row else None
-
-###############RELAYS##################
-
-async def create_nostrrelays(
- data: nostrCreateRelays
-) -> nostrCreateRelays:
- nostrrelay_id = shortuuid.uuid(name=relay)
-
- if await get_nostrrelays(nostrrelay_id):
- return "error"
- await db.execute(
- """
- INSERT INTO nostr.relays (
- id,
- relay
- )
- VALUES (?, ?)
- """,
- (nostrrelay_id, data.relay),
- )
- return await get_nostrnotes(nostrrelay_id)
-
-async def get_nostrrelays(nostrrelay_id: str) -> nostrRelays:
- row = await db.fetchone(
- "SELECT * FROM nostr.relays WHERE id = ?",
- (nostrnote_id,),
- )
- return nostrRelays(**row) if row else None
-
-
-###############CONNECTIONS##################
-
-async def create_nostrconnections(
- data: nostrCreateConnections
-) -> nostrCreateConnections:
- nostrrelay_id = shortuuid.uuid(name=data.relayid + data.pubkey)
- await db.execute(
- """
- INSERT INTO nostr.connections (
- id,
- pubkey,
- relayid
- )
- VALUES (?, ?, ?)
- """,
- (data.id, data.pubkey, data.relayid),
- )
- return await get_nostrconnections(data.id)
-
-async def get_nostrconnections(nostrconnections_id: str) -> nostrConnections:
- row = await db.fetchone(
- "SELECT * FROM nostr.connections WHERE id = ?",
- (nostrconnections_id,),
- )
- return nostrConnections(**row) if row else None
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/views_api.py b/lnbits/extensions/nostr/views_api.py
deleted file mode 100644
index 9e7ccfff..00000000
--- a/lnbits/extensions/nostr/views_api.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from http import HTTPStatus
-
-from fastapi import Request
-from fastapi.param_functions import Query
-from fastapi.params import Depends
-from starlette.exceptions import HTTPException
-
-from lnbits.core.crud import get_user
-from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
-from lnbits.extensions.nostr import nostr_ext
-from lnbits.utils.exchange_rates import currencies
-
-from . import nostr_ext
-from .crud import (
- create_nostrkeys,
- get_nostrkeys,
- create_nostrnotes,
- get_nostrnotes,
- create_nostrrelays,
- get_nostrrelays,
- create_nostrconnections,
- get_nostrconnections,
-)
-from .models import nostrKeys
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/README.md b/lnbits/extensions/nostradmin/README.md
similarity index 100%
rename from lnbits/extensions/nostr/README.md
rename to lnbits/extensions/nostradmin/README.md
diff --git a/lnbits/extensions/nostr/__init__.py b/lnbits/extensions/nostradmin/__init__.py
similarity index 51%
rename from lnbits/extensions/nostr/__init__.py
rename to lnbits/extensions/nostradmin/__init__.py
index 9774a279..7034ca46 100644
--- a/lnbits/extensions/nostr/__init__.py
+++ b/lnbits/extensions/nostradmin/__init__.py
@@ -3,13 +3,14 @@ from fastapi import APIRouter
from lnbits.db import Database
from lnbits.helpers import template_renderer
-db = Database("ext_nostr")
+db = Database("ext_nostradmin")
-nostr_ext: APIRouter = APIRouter(prefix="/nostr", tags=["nostr"])
+nostr_ext: APIRouter = APIRouter(prefix="/nostradmin", tags=["nostradmin"])
def nostr_renderer():
- return template_renderer(["lnbits/extensions/nostr/templates"])
+ return template_renderer(["lnbits/extensions/nostradmin/templates"])
+
from .views import * # noqa
from .views_api import * # noqa
diff --git a/lnbits/extensions/nostradmin/config.json b/lnbits/extensions/nostradmin/config.json
new file mode 100644
index 00000000..2c4f76d3
--- /dev/null
+++ b/lnbits/extensions/nostradmin/config.json
@@ -0,0 +1,6 @@
+{
+ "name": "NostrAdmin",
+ "short_description": "Admin daemon for Nostr",
+ "icon": "swap_horizontal_circle",
+ "contributors": ["arcbtc"]
+}
diff --git a/lnbits/extensions/nostradmin/crud.py b/lnbits/extensions/nostradmin/crud.py
new file mode 100644
index 00000000..08908e85
--- /dev/null
+++ b/lnbits/extensions/nostradmin/crud.py
@@ -0,0 +1,156 @@
+from typing import List, Optional, Union
+
+from lnbits.helpers import urlsafe_short_hash
+import shortuuid
+from . import db
+from .models import (
+ nostrKeys,
+ nostrNotes,
+ nostrCreateRelays,
+ nostrRelays,
+ nostrConnections,
+ nostrCreateConnections,
+ nostrRelayList,
+)
+
+###############KEYS##################
+
+
+async def create_nostrkeys(data: nostrKeys) -> nostrKeys:
+ await db.execute(
+ """
+ INSERT INTO nostradmin.keys (
+ pubkey,
+ privkey
+ )
+ VALUES (?, ?)
+ """,
+ (data.pubkey, data.privkey),
+ )
+ return await get_nostrkeys(nostrkey_id)
+
+
+async def get_nostrkeys(pubkey: str) -> nostrKeys:
+ row = await db.fetchone("SELECT * FROM nostradmin.keys WHERE pubkey = ?", (pubkey,))
+ return nostrKeys(**row) if row else None
+
+
+###############NOTES##################
+
+
+async def create_nostrnotes(data: nostrNotes) -> nostrNotes:
+ await db.execute(
+ """
+ INSERT INTO nostradmin.notes (
+ id,
+ pubkey,
+ created_at,
+ kind,
+ tags,
+ content,
+ sig
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ """,
+ (
+ data.id,
+ data.pubkey,
+ data.created_at,
+ data.kind,
+ data.tags,
+ data.content,
+ data.sig,
+ ),
+ )
+ return await get_nostrnotes(data.id)
+
+
+async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+ row = await db.fetchone("SELECT * FROM nostradmin.notes WHERE id = ?", (nostrnote_id,))
+ return nostrNotes(**row) if row else None
+
+
+###############RELAYS##################
+
+
+async def create_nostrrelays(data: nostrCreateRelays) -> nostrCreateRelays:
+ nostrrelay_id = shortuuid.uuid(name=data.relay)
+
+ if await get_nostrrelay(nostrrelay_id):
+ return "error"
+ await db.execute(
+ """
+ INSERT INTO nostradmin.relays (
+ id,
+ relay
+ )
+ VALUES (?, ?)
+ """,
+ (nostrrelay_id, data.relay),
+ )
+ return await get_nostrrelay(nostrrelay_id)
+
+
+async def get_nostrrelays() -> nostrRelays:
+ rows = await db.fetchall("SELECT * FROM nostradmin.relays")
+ return [nostrRelays(**row) for row in rows]
+
+
+async def get_nostrrelay(nostrrelay_id: str) -> nostrRelays:
+ row = await db.fetchone("SELECT * FROM nostradmin.relays WHERE id = ?", (nostrrelay_id,))
+ return nostrRelays(**row) if row else None
+
+
+async def update_nostrrelayallowlist(allowlist: str) -> nostrRelayList:
+ await db.execute(
+ """
+ UPDATE nostradmin.relaylist SET
+ allowlist = ?
+ WHERE id = ?
+ """,
+ (allowlist, 1),
+ )
+ return await get_nostrrelaylist()
+
+async def update_nostrrelaydenylist(denylist: str) -> nostrRelayList:
+ await db.execute(
+ """
+ UPDATE nostradmin.relaylist SET
+ denylist = ?
+ WHERE id = ?
+ """,
+ (denylist, 1),
+ )
+ return await get_nostrrelaylist()
+
+async def get_nostrrelaylist() -> nostrRelayList:
+ row = await db.fetchone("SELECT * FROM nostradmin.relaylist WHERE id = ?", (1,))
+ return nostrRelayList(**row) if row else None
+
+
+###############CONNECTIONS##################
+
+
+async def create_nostrconnections(
+ data: nostrCreateConnections
+) -> nostrCreateConnections:
+ nostrrelay_id = shortuuid.uuid(name=data.relayid + data.pubkey)
+ await db.execute(
+ """
+ INSERT INTO nostradmin.connections (
+ id,
+ pubkey,
+ relayid
+ )
+ VALUES (?, ?, ?)
+ """,
+ (data.id, data.pubkey, data.relayid),
+ )
+ return await get_nostrconnections(data.id)
+
+
+async def get_nostrconnections(nostrconnections_id: str) -> nostrConnections:
+ row = await db.fetchone(
+ "SELECT * FROM nostradmin.connections WHERE id = ?", (nostrconnections_id,)
+ )
+ return nostrConnections(**row) if row else None
diff --git a/lnbits/extensions/nostr/migrations.py b/lnbits/extensions/nostradmin/migrations.py
similarity index 54%
rename from lnbits/extensions/nostr/migrations.py
rename to lnbits/extensions/nostradmin/migrations.py
index 0c616110..09b28117 100644
--- a/lnbits/extensions/nostr/migrations.py
+++ b/lnbits/extensions/nostradmin/migrations.py
@@ -9,7 +9,7 @@ async def m001_initial(db):
"""
await db.execute(
f"""
- CREATE TABLE nostr.keys (
+ CREATE TABLE nostradmin.keys (
pubkey TEXT NOT NULL PRIMARY KEY,
privkey TEXT NOT NULL
);
@@ -17,7 +17,7 @@ async def m001_initial(db):
)
await db.execute(
f"""
- CREATE TABLE nostr.notes (
+ CREATE TABLE nostradmin.notes (
id TEXT NOT NULL PRIMARY KEY,
pubkey TEXT NOT NULL,
created_at TEXT NOT NULL,
@@ -30,7 +30,7 @@ async def m001_initial(db):
)
await db.execute(
f"""
- CREATE TABLE nostr.relays (
+ CREATE TABLE nostradmin.relays (
id TEXT NOT NULL PRIMARY KEY,
relay TEXT NOT NULL
);
@@ -38,10 +38,32 @@ async def m001_initial(db):
)
await db.execute(
f"""
- CREATE TABLE nostr.connections (
+ CREATE TABLE nostradmin.relaylists (
+ id TEXT NOT NULL PRIMARY KEY DEFAULT 1,
+ allowlist TEXT NOT NULL,
+ denylist TEXT NOT NULL
+ );
+ """
+ )
+ try:
+ await db.execute(
+ """
+ INSERT INTO nostradmin.relaylist (
+ id,
+ denylist
+ )
+ VALUES (?, ?,)
+ """,
+ (1, "\n".join(["wss://zucks-meta-relay.com", "wss://nostradmin.cia.gov"])),
+ )
+ except:
+ return
+ await db.execute(
+ f"""
+ CREATE TABLE nostradmin.connections (
id TEXT NOT NULL PRIMARY KEY,
publickey TEXT NOT NULL,
relayid TEXT NOT NULL
);
"""
- )
\ No newline at end of file
+ )
diff --git a/lnbits/extensions/nostr/models.py b/lnbits/extensions/nostradmin/models.py
similarity index 73%
rename from lnbits/extensions/nostr/models.py
rename to lnbits/extensions/nostradmin/models.py
index e21e5d76..fd89f515 100644
--- a/lnbits/extensions/nostr/models.py
+++ b/lnbits/extensions/nostradmin/models.py
@@ -6,6 +6,7 @@ from fastapi import Request
from pydantic import BaseModel
from pydantic.main import BaseModel
+
class nostrKeys(BaseModel):
pubkey: str
privkey: str
@@ -30,7 +31,18 @@ class nostrRelays(BaseModel):
id: str
relay: str
+class nostrRelayList(BaseModel):
+ id: str
+ allowlist: str
+ denylist: str
+
+class nostrRelayDenyList(BaseModel):
+ denylist: str
+
+class nostrRelayAllowList(BaseModel):
+ allowlist: str
+
class nostrConnections(BaseModel):
id: str
pubkey: str
- relayid: str
\ No newline at end of file
+ relayid: str
diff --git a/lnbits/extensions/nostr/templates/nostr/index.html b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
similarity index 50%
rename from lnbits/extensions/nostr/templates/nostr/index.html
rename to lnbits/extensions/nostradmin/templates/nostradmin/index.html
index f17d0243..adab98e2 100644
--- a/lnbits/extensions/nostr/templates/nostr/index.html
+++ b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
@@ -71,12 +71,77 @@
+
+
+
+
+
+
+
+
+
+
+
+ Deny List (denys use of relays in this list)
+
+
+
+
+
+
+
+
+ Update Deny List
+
+ Reset
+
+
+
+
+
+
+
+ Allow List (denys any relays not in this list)
+
+
+
+
+
+
+
+
+ Update Allow List
+
+ Reset
+
+
+
+
+
+
{{SITE_TITLE}} Nostr Extension
+ Only Admin users can manage this extension
Okay
@@ -109,6 +174,9 @@
mixins: [windowMixin],
data: function () {
return {
+ listSelection: 'denylist',
+ allowList: [],
+ denyList: [],
nostrTable: {
columns: [
{
@@ -136,12 +204,66 @@
LNbits.api
.request(
'GET',
- '/nostr/api/v1/relays',
+ '/nostradmin/api/v1/relays',
self.g.user.wallets[0].adminkey
)
.then(function (response) {
if (response.data) {
- self.lnurldeviceLinks = response.data.map(maplnurldevice)
+ self.nostrrelayLinks = response.data.map(maprelays)
+ }
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ setAllowList: function () {
+ var self = this
+ LNbits.api
+ .request(
+ 'POST',
+ '/nostradmin/api/v1/allowlist',
+ self.g.user.wallets[0].adminkey,
+ self.allowList
+ )
+ .then(function (response) {
+ if (response.data) {
+ self.allowList = response.data
+ }
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ setDenyList: function () {
+ var self = this
+ LNbits.api
+ .request(
+ 'POST',
+ '/nostradmin/api/v1/denylist',
+ self.g.user.wallets[0].adminkey,
+ self.allowList
+ )
+ .then(function (response) {
+ if (response.data) {
+ self.denyList = response.data
+ }
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ getLists: function () {
+ var self = this
+ LNbits.api
+ .request(
+ 'GET',
+ '/nostradmin/api/v1/relaylist',
+ self.g.user.wallets[0].adminkey
+ )
+ .then(function (response) {
+ if (response.data) {
+ self.denyList = response.data.denylist
+ self.allowList = response.data.allowlist
}
})
.catch(function (error) {
@@ -151,8 +273,8 @@
},
created: function () {
var self = this
- var getrelays = this.getrelays
- getrelays()
+ this.getrelays()
+ this.getLists()
}
})
diff --git a/lnbits/extensions/nostr/views.py b/lnbits/extensions/nostradmin/views.py
similarity index 90%
rename from lnbits/extensions/nostr/views.py
rename to lnbits/extensions/nostradmin/views.py
index 1dfc07da..5609c218 100644
--- a/lnbits/extensions/nostr/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -20,5 +20,5 @@ templates = Jinja2Templates(directory="templates")
@nostr_ext.get("/", response_class=HTMLResponse)
async def index(request: Request, user: User = Depends(check_user_exists)):
return nostr_renderer().TemplateResponse(
- "nostr/index.html", {"request": request, "user": user.dict()}
+ "nostradmin/index.html", {"request": request, "user": user.dict()}
)
diff --git a/lnbits/extensions/nostradmin/views_api.py b/lnbits/extensions/nostradmin/views_api.py
new file mode 100644
index 00000000..da6e140b
--- /dev/null
+++ b/lnbits/extensions/nostradmin/views_api.py
@@ -0,0 +1,87 @@
+from http import HTTPStatus
+import asyncio
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from starlette.exceptions import HTTPException
+
+from lnbits.core.crud import get_user
+from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
+from lnbits.extensions.nostr import nostr_ext
+from lnbits.utils.exchange_rates import currencies
+
+from . import nostr_ext
+from lnbits.settings import LNBITS_ADMIN_USERS
+from .crud import (
+ create_nostrkeys,
+ get_nostrkeys,
+ create_nostrnotes,
+ get_nostrnotes,
+ create_nostrrelays,
+ get_nostrrelays,
+ get_nostrrelaylist,
+ update_nostrrelayallowlist,
+ update_nostrrelaydenylist,
+ create_nostrconnections,
+ get_nostrconnections,
+)
+from .models import nostrKeys, nostrCreateRelays, nostrRelayAllowList, nostrRelayDenyList
+
+
+# while True:
+async def nostr_subscribe():
+ return
+ # for the relays:
+ # async with websockets.connect("ws://localhost:8765") as websocket:
+ # for the public keys:
+ # await websocket.send("subscribe to events")
+ # await websocket.recv()
+
+
+websocket_queue = asyncio.Queue(1000)
+
+
+async def internal_invoice_listener():
+ while True:
+ checking_id = await internal_invoice_queue.get()
+ asyncio.create_task(invoice_callback_dispatcher(checking_id))
+
+
+@nostr_ext.get("/api/v1/relays")
+async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
+
+ relays = await get_nostrrelays()
+ if not relays:
+ await create_nostrrelays(nostrCreateRelays(relay="wss://relayer.fiatjaf.com"))
+ await create_nostrrelays(
+ nostrCreateRelays(relay="wss://nostr-pub.wellorder.net")
+ )
+ relays = await get_nostrrelays()
+ try:
+ return [{**relays.dict()} for relays in await relays]
+ except:
+ None
+
+@nostr_ext.get("/api/v1/relaylist")
+async def api_relaylist(wallet: WalletTypeInfo = Depends(get_key_type)):
+ if wallet.wallet.user not in LNBITS_ADMIN_USERS:
+ raise HTTPException(
+ status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
+ )
+ return await get_nostrrelaylist()
+
+@nostr_ext.post("/api/v1/allowlist")
+async def api_relaysallowed(data: nostrRelayAllowList, wallet: WalletTypeInfo = Depends(get_key_type)):
+ if wallet.wallet.user not in LNBITS_ADMIN_USERS:
+ raise HTTPException(
+ status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
+ )
+ return await update_nostrrelayallowlist(data)
+
+@nostr_ext.post("/api/v1/denylist")
+async def api_relaysdenyed(data: nostrRelayDenyList, wallet: WalletTypeInfo = Depends(get_key_type)):
+ if wallet.wallet.user not in LNBITS_ADMIN_USERS:
+ raise HTTPException(
+ status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
+ )
+ return await update_nostrrelaydenylist(data)
\ No newline at end of file
From 2083ecbc27b00ad4aca605425a183b8122e7d995 Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 13:13:36 +0000
Subject: [PATCH 014/226] models decided
---
lnbits/extensions/nostradmin/__init__.py | 2 +-
lnbits/extensions/nostradmin/crud.py | 22 ++----
lnbits/extensions/nostradmin/migrations.py | 41 ++++++-----
lnbits/extensions/nostradmin/models.py | 33 +++++----
.../templates/nostradmin/index.html | 71 +++++++++++--------
lnbits/extensions/nostradmin/views.py | 5 +-
lnbits/extensions/nostradmin/views_api.py | 33 +++------
7 files changed, 100 insertions(+), 107 deletions(-)
diff --git a/lnbits/extensions/nostradmin/__init__.py b/lnbits/extensions/nostradmin/__init__.py
index 7034ca46..797542c4 100644
--- a/lnbits/extensions/nostradmin/__init__.py
+++ b/lnbits/extensions/nostradmin/__init__.py
@@ -5,7 +5,7 @@ from lnbits.helpers import template_renderer
db = Database("ext_nostradmin")
-nostr_ext: APIRouter = APIRouter(prefix="/nostradmin", tags=["nostradmin"])
+nostradmin_ext: APIRouter = APIRouter(prefix="/nostradmin", tags=["nostradmin"])
def nostr_renderer():
diff --git a/lnbits/extensions/nostradmin/crud.py b/lnbits/extensions/nostradmin/crud.py
index 08908e85..1e1bf810 100644
--- a/lnbits/extensions/nostradmin/crud.py
+++ b/lnbits/extensions/nostradmin/crud.py
@@ -12,6 +12,7 @@ from .models import (
nostrCreateConnections,
nostrRelayList,
)
+from .models import nostrKeys, nostrCreateRelays, nostrRelaySetList
###############KEYS##################
@@ -100,31 +101,20 @@ async def get_nostrrelay(nostrrelay_id: str) -> nostrRelays:
row = await db.fetchone("SELECT * FROM nostradmin.relays WHERE id = ?", (nostrrelay_id,))
return nostrRelays(**row) if row else None
-
-async def update_nostrrelayallowlist(allowlist: str) -> nostrRelayList:
+async def update_nostrrelaysetlist(data: nostrRelaySetList) -> nostrRelayList:
await db.execute(
"""
- UPDATE nostradmin.relaylist SET
+ UPDATE nostradmin.relaylists SET
+ denylist = ?,
allowlist = ?
WHERE id = ?
""",
- (allowlist, 1),
- )
- return await get_nostrrelaylist()
-
-async def update_nostrrelaydenylist(denylist: str) -> nostrRelayList:
- await db.execute(
- """
- UPDATE nostradmin.relaylist SET
- denylist = ?
- WHERE id = ?
- """,
- (denylist, 1),
+ (data.denylist, data.allowlist, 1),
)
return await get_nostrrelaylist()
async def get_nostrrelaylist() -> nostrRelayList:
- row = await db.fetchone("SELECT * FROM nostradmin.relaylist WHERE id = ?", (1,))
+ row = await db.fetchone("SELECT * FROM nostradmin.relaylists WHERE id = ?", (1,))
return nostrRelayList(**row) if row else None
diff --git a/lnbits/extensions/nostradmin/migrations.py b/lnbits/extensions/nostradmin/migrations.py
index 09b28117..590f72ea 100644
--- a/lnbits/extensions/nostradmin/migrations.py
+++ b/lnbits/extensions/nostradmin/migrations.py
@@ -1,11 +1,8 @@
from lnbits.db import Database
-db2 = Database("ext_nostr")
-
-
async def m001_initial(db):
"""
- Initial nostr table.
+ Initial nostradmin table.
"""
await db.execute(
f"""
@@ -40,24 +37,23 @@ async def m001_initial(db):
f"""
CREATE TABLE nostradmin.relaylists (
id TEXT NOT NULL PRIMARY KEY DEFAULT 1,
- allowlist TEXT NOT NULL,
- denylist TEXT NOT NULL
+ allowlist TEXT,
+ denylist TEXT
);
"""
)
- try:
- await db.execute(
- """
- INSERT INTO nostradmin.relaylist (
- id,
- denylist
- )
- VALUES (?, ?,)
- """,
- (1, "\n".join(["wss://zucks-meta-relay.com", "wss://nostradmin.cia.gov"])),
+
+ await db.execute(
+ """
+ INSERT INTO nostradmin.relaylists (
+ id,
+ denylist
)
- except:
- return
+ VALUES (?, ?)
+ """,
+ ("1", "wss://zucks-meta-relay.com\nwss://nostr.cia.gov",),
+ )
+
await db.execute(
f"""
CREATE TABLE nostradmin.connections (
@@ -67,3 +63,12 @@ async def m001_initial(db):
);
"""
)
+ await db.execute(
+ f"""
+ CREATE TABLE nostradmin.subscribed (
+ id TEXT NOT NULL PRIMARY KEY,
+ userPubkey TEXT NOT NULL,
+ subscribedPubkey TEXT NOT NULL
+ );
+ """
+ )
\ No newline at end of file
diff --git a/lnbits/extensions/nostradmin/models.py b/lnbits/extensions/nostradmin/models.py
index fd89f515..1968567f 100644
--- a/lnbits/extensions/nostradmin/models.py
+++ b/lnbits/extensions/nostradmin/models.py
@@ -5,7 +5,7 @@ from typing import Optional
from fastapi import Request
from pydantic import BaseModel
from pydantic.main import BaseModel
-
+from fastapi.param_functions import Query
class nostrKeys(BaseModel):
pubkey: str
@@ -21,28 +21,31 @@ class nostrNotes(BaseModel):
sig: str
class nostrCreateRelays(BaseModel):
- relay: str
+ relay: str = Query(None)
class nostrCreateConnections(BaseModel):
- pubkey: str
- relayid: str
+ pubkey: str = Query(None)
+ relayid: str = Query(None)
class nostrRelays(BaseModel):
- id: str
- relay: str
+ id: Optional[str]
+ relay: Optional[str]
class nostrRelayList(BaseModel):
id: str
- allowlist: str
- denylist: str
+ allowlist: Optional[str]
+ denylist: Optional[str]
-class nostrRelayDenyList(BaseModel):
- denylist: str
-
-class nostrRelayAllowList(BaseModel):
- allowlist: str
+class nostrRelaySetList(BaseModel):
+ allowlist: Optional[str]
+ denylist: Optional[str]
class nostrConnections(BaseModel):
id: str
- pubkey: str
- relayid: str
+ pubkey: Optional[str]
+ relayid: Optional[str]
+
+class nostrSubscriptions(BaseModel):
+ id: str
+ userPubkey: Optional[str]
+ subscribedPubkey: Optional[str]
\ No newline at end of file
diff --git a/lnbits/extensions/nostradmin/templates/nostradmin/index.html b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
index adab98e2..27decdc8 100644
--- a/lnbits/extensions/nostradmin/templates/nostradmin/index.html
+++ b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
@@ -6,7 +6,7 @@
-
Nostr
+ NOSTR RELAYS ONLINE
@@ -29,7 +29,7 @@
-
-
+
+
-
+
-
+
-
- Deny List (denys use of relays in this list)
-
-
+ Relays in this list will NOT be used
+
-
+
Update Deny List
- Reset
-
- Allow List (denys any relays not in this list)
-
-
+ ONLY relays in this list will be used
+
-
+
Update Allow List
- Reset
@@ -175,8 +175,12 @@
data: function () {
return {
listSelection: 'denylist',
- allowList: [],
- denyList: [],
+ setList: {
+ allowlist: '',
+ denylist: ''
+ },
+ nostrLinks: [],
+ filter: '',
nostrTable: {
columns: [
{
@@ -234,18 +238,20 @@
LNbits.utils.notifyApiError(error)
})
},
- setDenyList: function () {
+ setRelayList: function () {
var self = this
+ console.log(self.setList)
LNbits.api
.request(
'POST',
- '/nostradmin/api/v1/denylist',
+ '/nostradmin/api/v1/setlist',
self.g.user.wallets[0].adminkey,
- self.allowList
+ self.setList
)
.then(function (response) {
if (response.data) {
- self.denyList = response.data
+ console.log(response.data)
+ // self.denyList = response.data
}
})
.catch(function (error) {
@@ -262,13 +268,18 @@
)
.then(function (response) {
if (response.data) {
- self.denyList = response.data.denylist
- self.allowList = response.data.allowlist
+ console.log(response.data)
+ self.setList.denylist = response.data.denylist
+ self.setList.allowlist = response.data.allowlist
}
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
+ },
+ exportlnurldeviceCSV: function () {
+ var self = this
+ LNbits.utils.exportCSV(self.nostrTable.columns, this.nostrLinks)
}
},
created: function () {
diff --git a/lnbits/extensions/nostradmin/views.py b/lnbits/extensions/nostradmin/views.py
index 5609c218..51297320 100644
--- a/lnbits/extensions/nostradmin/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -6,18 +6,19 @@ from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse
+from . import nostradmin_ext, nostr_renderer
from lnbits.core.crud import update_payment_status
from lnbits.core.models import User
from lnbits.core.views.api import api_payment
from lnbits.decorators import check_user_exists
-from . import nostr_ext, nostr_renderer
+
templates = Jinja2Templates(directory="templates")
-@nostr_ext.get("/", response_class=HTMLResponse)
+@nostradmin_ext.get("/", response_class=HTMLResponse)
async def index(request: Request, user: User = Depends(check_user_exists)):
return nostr_renderer().TemplateResponse(
"nostradmin/index.html", {"request": request, "user": user.dict()}
diff --git a/lnbits/extensions/nostradmin/views_api.py b/lnbits/extensions/nostradmin/views_api.py
index da6e140b..d79315ac 100644
--- a/lnbits/extensions/nostradmin/views_api.py
+++ b/lnbits/extensions/nostradmin/views_api.py
@@ -7,11 +7,10 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
-from lnbits.extensions.nostr import nostr_ext
from lnbits.utils.exchange_rates import currencies
-from . import nostr_ext
from lnbits.settings import LNBITS_ADMIN_USERS
+from . import nostradmin_ext
from .crud import (
create_nostrkeys,
get_nostrkeys,
@@ -20,13 +19,11 @@ from .crud import (
create_nostrrelays,
get_nostrrelays,
get_nostrrelaylist,
- update_nostrrelayallowlist,
- update_nostrrelaydenylist,
+ update_nostrrelaysetlist,
create_nostrconnections,
get_nostrconnections,
)
-from .models import nostrKeys, nostrCreateRelays, nostrRelayAllowList, nostrRelayDenyList
-
+from .models import nostrKeys, nostrCreateRelays, nostrRelaySetList
# while True:
async def nostr_subscribe():
@@ -41,13 +38,7 @@ async def nostr_subscribe():
websocket_queue = asyncio.Queue(1000)
-async def internal_invoice_listener():
- while True:
- checking_id = await internal_invoice_queue.get()
- asyncio.create_task(invoice_callback_dispatcher(checking_id))
-
-
-@nostr_ext.get("/api/v1/relays")
+@nostradmin_ext.get("/api/v1/relays")
async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
relays = await get_nostrrelays()
@@ -62,7 +53,7 @@ async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
except:
None
-@nostr_ext.get("/api/v1/relaylist")
+@nostradmin_ext.get("/api/v1/relaylist")
async def api_relaylist(wallet: WalletTypeInfo = Depends(get_key_type)):
if wallet.wallet.user not in LNBITS_ADMIN_USERS:
raise HTTPException(
@@ -70,18 +61,10 @@ async def api_relaylist(wallet: WalletTypeInfo = Depends(get_key_type)):
)
return await get_nostrrelaylist()
-@nostr_ext.post("/api/v1/allowlist")
-async def api_relaysallowed(data: nostrRelayAllowList, wallet: WalletTypeInfo = Depends(get_key_type)):
+@nostradmin_ext.post("/api/v1/setlist")
+async def api_relayssetlist(data: nostrRelaySetList, wallet: WalletTypeInfo = Depends(get_key_type)):
if wallet.wallet.user not in LNBITS_ADMIN_USERS:
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
)
- return await update_nostrrelayallowlist(data)
-
-@nostr_ext.post("/api/v1/denylist")
-async def api_relaysdenyed(data: nostrRelayDenyList, wallet: WalletTypeInfo = Depends(get_key_type)):
- if wallet.wallet.user not in LNBITS_ADMIN_USERS:
- raise HTTPException(
- status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
- )
- return await update_nostrrelaydenylist(data)
\ No newline at end of file
+ return await update_nostrrelaysetlist(data)
\ No newline at end of file
From 21c316293b4c8986854ade1421e4119fc6e4e5bb Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 13:52:19 +0000
Subject: [PATCH 015/226] Started planning websocket daemon
---
lnbits/extensions/nostradmin/views.py | 70 ++++++++++++++++++++++-
lnbits/extensions/nostradmin/views_api.py | 12 ----
2 files changed, 68 insertions(+), 14 deletions(-)
diff --git a/lnbits/extensions/nostradmin/views.py b/lnbits/extensions/nostradmin/views.py
index 51297320..235ec7e9 100644
--- a/lnbits/extensions/nostradmin/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -1,5 +1,6 @@
from http import HTTPStatus
-
+import asyncio
+import asyncio
from fastapi import Request
from fastapi.param_functions import Query
from fastapi.params import Depends
@@ -7,13 +8,14 @@ from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse
from . import nostradmin_ext, nostr_renderer
+from fastapi import Request, WebSocket, WebSocketDisconnect
from lnbits.core.crud import update_payment_status
from lnbits.core.models import User
from lnbits.core.views.api import api_payment
from lnbits.decorators import check_user_exists
-
+from .crud import get_nostrkeys
templates = Jinja2Templates(directory="templates")
@@ -23,3 +25,67 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
return nostr_renderer().TemplateResponse(
"nostradmin/index.html", {"request": request, "user": user.dict()}
)
+
+#####################################################################
+#################### NOSTR WEBSOCKET THREAD #########################
+##### THE QUEUE LOOP THREAD THING THAT LISTENS TO BUNCH OF ##########
+### WEBSOCKET CONNECTIONS, STORING DATA IN DB/PUSHING TO FRONTEND ###
+################### VIA updater() FUNCTION ##########################
+#####################################################################
+
+websocket_queue = asyncio.Queue(1000)
+
+# while True:
+async def nostr_subscribe():
+ return
+ # for the relays:
+ # async with websockets.connect("ws://localhost:8765") as websocket:
+ # for the public keys:
+ # await websocket.send("subscribe to events")
+ # await websocket.recv()
+
+#####################################################################
+################### LNBITS WEBSOCKET ROUTES #########################
+#### HERE IS WHERE LNBITS FRONTEND CAN RECEIVE AND SEND MESSAGES ####
+#####################################################################
+
+class ConnectionManager:
+ def __init__(self):
+ self.active_connections: List[WebSocket] = []
+
+ async def connect(self, websocket: WebSocket, nostr_id: str):
+ await websocket.accept()
+ websocket.id = nostr_id
+ self.active_connections.append(websocket)
+
+ def disconnect(self, websocket: WebSocket):
+ self.active_connections.remove(websocket)
+
+ async def send_personal_message(self, message: str, nostr_id: str):
+ for connection in self.active_connections:
+ if connection.id == nostr_id:
+ await connection.send_text(message)
+
+ async def broadcast(self, message: str):
+ for connection in self.active_connections:
+ await connection.send_text(message)
+
+
+manager = ConnectionManager()
+
+
+@nostradmin_ext.websocket("/nostradmin/ws/{nostr_id}", name="copilot.websocket_by_id")
+async def websocket_endpoint(websocket: WebSocket, copilot_id: str):
+ await manager.connect(websocket, nostr_id)
+ try:
+ while True:
+ data = await websocket.receive_text()
+ except WebSocketDisconnect:
+ manager.disconnect(websocket)
+
+
+async def updater(nostr_id, message):
+ copilot = await get_copilot(nostr_id)
+ if not copilot:
+ return
+ await manager.send_personal_message(f"{message}", nostr_id)
\ No newline at end of file
diff --git a/lnbits/extensions/nostradmin/views_api.py b/lnbits/extensions/nostradmin/views_api.py
index d79315ac..ad8bcf17 100644
--- a/lnbits/extensions/nostradmin/views_api.py
+++ b/lnbits/extensions/nostradmin/views_api.py
@@ -25,18 +25,6 @@ from .crud import (
)
from .models import nostrKeys, nostrCreateRelays, nostrRelaySetList
-# while True:
-async def nostr_subscribe():
- return
- # for the relays:
- # async with websockets.connect("ws://localhost:8765") as websocket:
- # for the public keys:
- # await websocket.send("subscribe to events")
- # await websocket.recv()
-
-
-websocket_queue = asyncio.Queue(1000)
-
@nostradmin_ext.get("/api/v1/relays")
async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
From 0a5495f185a87a2aee8a2efd78b7dff0ad5d2384 Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 14:02:50 +0000
Subject: [PATCH 016/226] typo
---
lnbits/extensions/nostradmin/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lnbits/extensions/nostradmin/views.py b/lnbits/extensions/nostradmin/views.py
index 235ec7e9..f00c43a3 100644
--- a/lnbits/extensions/nostradmin/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -74,7 +74,7 @@ class ConnectionManager:
manager = ConnectionManager()
-@nostradmin_ext.websocket("/nostradmin/ws/{nostr_id}", name="copilot.websocket_by_id")
+@nostradmin_ext.websocket("/nostradmin/ws/{nostr_id}", name="nostr_id.websocket_by_id")
async def websocket_endpoint(websocket: WebSocket, copilot_id: str):
await manager.connect(websocket, nostr_id)
try:
From 6917813e2af357138bebb2df31d00be6148b7553 Mon Sep 17 00:00:00 2001
From: benarc
Date: Thu, 10 Feb 2022 09:58:50 +0000
Subject: [PATCH 017/226] Working, looking good
---
lnbits/extensions/nostradmin/models.py | 1 +
.../templates/nostradmin/index.html | 39 ++++++++++++-------
lnbits/extensions/nostradmin/views.py | 21 +++++++---
lnbits/extensions/nostradmin/views_api.py | 17 +++++---
4 files changed, 53 insertions(+), 25 deletions(-)
diff --git a/lnbits/extensions/nostradmin/models.py b/lnbits/extensions/nostradmin/models.py
index 1968567f..dc99b083 100644
--- a/lnbits/extensions/nostradmin/models.py
+++ b/lnbits/extensions/nostradmin/models.py
@@ -30,6 +30,7 @@ class nostrCreateConnections(BaseModel):
class nostrRelays(BaseModel):
id: Optional[str]
relay: Optional[str]
+ status: Optional[bool] = False
class nostrRelayList(BaseModel):
id: str
diff --git a/lnbits/extensions/nostradmin/templates/nostradmin/index.html b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
index 27decdc8..57552bf2 100644
--- a/lnbits/extensions/nostradmin/templates/nostradmin/index.html
+++ b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
@@ -29,7 +29,7 @@
-
-
-
- {{ col.value }}
+
+
+ {{ col.value }}
+
+
{{ col.value }}
+
@@ -143,7 +145,7 @@
{{SITE_TITLE}} Nostr Extension
Only Admin users can manage this extension
- Okay
+
@@ -153,7 +155,7 @@
+
+{% endblock %}
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
new file mode 100644
index 00000000..768bedfe
--- /dev/null
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -0,0 +1,9 @@
+
+
+
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
new file mode 100644
index 00000000..2deed72b
--- /dev/null
+++ b/lnbits/extensions/diagonalley/views.py
@@ -0,0 +1,44 @@
+
+from typing import List
+
+from fastapi import Request, WebSocket, WebSocketDisconnect
+from fastapi.params import Depends
+from fastapi.templating import Jinja2Templates
+from starlette.responses import HTMLResponse # type: ignore
+
+from http import HTTPStatus
+import json
+from lnbits.decorators import check_user_exists, validate_uuids
+from lnbits.extensions.diagonalley import diagonalley_ext
+
+from .crud import (
+ create_diagonalley_product,
+ get_diagonalley_product,
+ get_diagonalley_products,
+ delete_diagonalley_product,
+ create_diagonalley_order,
+ get_diagonalley_order,
+ get_diagonalley_orders,
+ update_diagonalley_product,
+)
+
+
+@diagonalley_ext.get("/", response_class=HTMLResponse)
+@validate_uuids(["usr"], required=True)
+@check_user_exists(request: Request)
+async def index():
+ return await render_template("diagonalley/index.html", user=g.user)
+
+
+@diagonalley_ext.get("/
", response_class=HTMLResponse)
+async def display(request: Request, stall_id):
+ product = await get_diagonalley_products(stall_id)
+ if not product:
+ abort(HTTPStatus.NOT_FOUND, "Stall does not exist.")
+
+ return await render_template(
+ "diagonalley/stall.html",
+ stall=json.dumps(
+ [product._asdict() for product in await get_diagonalley_products(stall_id)]
+ ),
+ )
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
new file mode 100644
index 00000000..4de2799e
--- /dev/null
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -0,0 +1,348 @@
+from http import HTTPStatus
+
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from starlette.exceptions import HTTPException
+
+from lnbits.core.crud import get_user
+from lnbits.decorators import api_check_wallet_key, api_validate_post_request
+
+from . import diagonalley_ext
+from .crud import (
+ create_diagonalley_product,
+ get_diagonalley_product,
+ get_diagonalley_products,
+ delete_diagonalley_product,
+ create_diagonalley_zone,
+ update_diagonalley_zone,
+ get_diagonalley_zone,
+ get_diagonalley_zones,
+ delete_diagonalley_zone,
+ create_diagonalley_stall,
+ update_diagonalley_stall,
+ get_diagonalley_stall,
+ get_diagonalley_stalls,
+ delete_diagonalley_stall,
+ create_diagonalley_order,
+ get_diagonalley_order,
+ get_diagonalley_orders,
+ update_diagonalley_product,
+ delete_diagonalley_order,
+)
+from lnbits.core.services import create_invoice
+from base64 import urlsafe_b64encode
+from uuid import uuid4
+
+# from lnbits.db import open_ext_db
+
+from . import db
+from .models import Products, Orders, Stalls
+
+### Products
+
+@copilot_ext.get("/api/v1/copilot/{copilot_id}")
+async def api_copilot_retrieve(
+ req: Request,
+ copilot_id: str = Query(None),
+ wallet: WalletTypeInfo = Depends(get_key_type),
+):
+ copilot = await get_copilot(copilot_id)
+ if not copilot:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Copilot not found"
+ )
+ if not copilot.lnurl_toggle:
+ return copilot.dict()
+ return {**copilot.dict(), **{"lnurl": copilot.lnurl(req)}}
+
+
+@diagonalley_ext.get("/api/v1/products")
+async def api_diagonalley_products(
+ req: Request,
+ wallet: WalletTypeInfo = Depends(get_key_type),
+):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_stalls" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ return ([product._asdict() for product in await get_diagonalley_products(wallet_ids)])
+
+
+@diagonalley_ext.post("/api/v1/products")
+@diagonalley_ext.put("/api/v1/products/{product_id}")
+async def api_diagonalley_product_create(
+ data: Products,
+ product_id=: str = Query(None),
+ wallet: WalletTypeInfo = Depends(get_key_type)
+ ):
+
+ if product_id:
+ product = await get_diagonalley_product(product_id)
+
+ if not product:
+ return ({"message": "Withdraw product does not exist."}))
+
+ if product.wallet != wallet.wallet.id:
+ return ({"message": "Not your withdraw product."}))
+
+ product = await update_diagonalley_product(product_id, data)
+ else:
+ product = await create_diagonalley_product(wallet_id=wallet.wallet.id, data)
+
+ return ({**product._asdict()}))
+
+
+@diagonalley_ext.route("/api/v1/products/{product_id}")
+async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
+ product = await get_diagonalley_product(product_id)
+
+ if not product:
+ return ({"message": "Product does not exist."})
+
+ if product.wallet != wallet.wallet.id:
+ return ({"message": "Not your Diagon Alley."})
+
+ await delete_diagonalley_product(product_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+# # # Shippingzones
+
+
+@diagonalley_ext.get("/api/v1/zones")
+async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_wallets" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ return ([zone._asdict() for zone in await get_diagonalley_zones(wallet_ids)]))
+
+
+@diagonalley_ext.post("/api/v1/zones")
+@diagonalley_ext.put("/api/v1/zones/{zone_id}")
+async def api_diagonalley_zone_create(
+ data: Zones,
+ zone_id: str = Query(None),
+ wallet: WalletTypeInfo = Depends(get_key_type)
+ ):
+ if zone_id:
+ zone = await get_diagonalley_zone(zone_id)
+
+ if not zone:
+ return ({"message": "Zone does not exist."}))
+
+ if zone.wallet != walley.wallet.id:
+ return ({"message": "Not your record."}))
+
+ zone = await update_diagonalley_zone(zone_id, data)
+ else:
+ zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data)
+
+ return ({**zone._asdict()}))
+
+
+@diagonalley_ext.delete("/api/v1/zones/{zone_id}")
+async def api_diagonalley_zone_delete(zone_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+ zone = await get_diagonalley_zone(zone_id)
+
+ if not zone:
+ return ({"message": "zone does not exist."})
+
+ if zone.wallet != wallet.wallet.id:
+ return ({"message": "Not your zone."})
+
+ await delete_diagonalley_zone(zone_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+# # # Stalls
+
+
+@diagonalley_ext.get("/api/v1/stalls")
+async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_wallets" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ return ([stall._asdict() for stall in await get_diagonalley_stalls(wallet_ids)])
+
+
+@diagonalley_ext.post("/api/v1/stalls")
+@diagonalley_ext.put("/api/v1/stalls/{stall_id}")
+async def api_diagonalley_stall_create(data: createStalls, stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+
+ if stall_id:
+ stall = await get_diagonalley_stall(stall_id)
+
+ if not stall:
+ return ({"message": "Withdraw stall does not exist."}))
+
+ if stall.wallet != wallet.wallet.id:
+ return ({"message": "Not your withdraw stall."}))
+
+ stall = await update_diagonalley_stall(stall_id, data)
+ else:
+ stall = await create_diagonalley_stall(wallet_id=wallet.wallet.id, data)
+
+ return ({**stall._asdict()}))
+
+
+@diagonalley_ext.delete("/api/v1/stalls/{stall_id}")
+async def api_diagonalley_stall_delete(stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+ stall = await get_diagonalley_stall(stall_id)
+
+ if not stall:
+ return ({"message": "Stall does not exist."})
+
+ if stall.wallet != wallet.wallet.id:
+ return ({"message": "Not your Stall."})
+
+ await delete_diagonalley_stall(stall_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+###Orders
+
+
+@diagonalley_ext.get("/api/v1/orders")
+async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = [wallet.wallet.id]
+
+ if "all_wallets" in request.args:
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+
+ try:
+ return ([order._asdict() for order in await get_diagonalley_orders(wallet_ids)])
+ except:
+ return ({"message": "We could not retrieve the orders."}))
+
+
+@diagonalley_ext.post("/api/v1/orders")
+
+async def api_diagonalley_order_create(data: createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
+ order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data)
+ return ({**order._asdict()})
+
+
+@diagonalley_ext.delete("/api/v1/orders/{order_id}")
+async def api_diagonalley_order_delete(order_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+ order = await get_diagonalley_order(order_id)
+
+ if not order:
+ return ({"message": "Order does not exist."})
+
+ if order.wallet != wallet.wallet.id:
+ return ({"message": "Not your Order."})
+
+ await delete_diagonalley_order(order_id)
+
+ raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+
+
+@diagonalley_ext.get("/api/v1/orders/paid/{order_id}")
+async def api_diagonalley_order_paid(order_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+ await db.execute(
+ "UPDATE diagonalley.orders SET paid = ? WHERE id = ?",
+ (
+ True,
+ order_id,
+ ),
+ )
+ return "", HTTPStatus.OK
+
+
+@diagonalley_ext.get("/api/v1/orders/shipped/{order_id}")
+async def api_diagonalley_order_shipped(order_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+ await db.execute(
+ "UPDATE diagonalley.orders SET shipped = ? WHERE id = ?",
+ (
+ True,
+ order_id,
+ ),
+ )
+ order = await db.fetchone(
+ "SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
+ )
+
+ return ([order._asdict() for order in get_diagonalley_orders(order["wallet"])]))
+
+
+###List products based on stall id
+
+
+@diagonalley_ext.get("/api/v1/stall/products/{stall_id}")
+async def api_diagonalley_stall_products(stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+
+ rows = await db.fetchone(
+ "SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
+ )
+ print(rows[1])
+ if not rows:
+ return ({"message": "Stall does not exist."})
+
+ products = db.fetchone(
+ "SELECT * FROM diagonalley.products WHERE wallet = ?", (rows[1],)
+ )
+ if not products:
+ return ({"message": "No products"})
+
+ return ([products._asdict() for products in await get_diagonalley_products(rows[1])])
+
+
+###Check a product has been shipped
+
+
+@diagonalley_ext.get("/api/v1/stall/checkshipped/{checking_id}")
+async def api_diagonalley_stall_checkshipped(checking_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+ rows = await db.fetchone(
+ "SELECT * FROM diagonalley.orders WHERE invoiceid = ?", (checking_id,)
+ )
+ return ({"shipped": rows["shipped"]})
+
+
+###Place order
+
+
+@diagonalley_ext.post("/api/v1/stall/order/{stall_id}")
+async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
+ product = await get_diagonalley_product(data.id)
+ shipping = await get_diagonalley_stall(stall_id)
+
+ if data.shippingzone == 1:
+ shippingcost = shipping.zone1cost
+ else:
+ shippingcost = shipping.zone2cost
+
+ checking_id, payment_request = await create_invoice(
+ wallet_id=product.wallet,
+ amount=shippingcost + (data.quantity * product.price),
+ memo=data.id,
+ )
+ selling_id = urlsafe_b64encode(uuid4().bytes_le).decode("utf-8")
+ await db.execute(
+ """
+ INSERT INTO diagonalley.orders (id, productid, wallet, product, quantity, shippingzone, address, email, invoiceid, paid, shipped)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ """,
+ (
+ selling_id,
+ data.id,
+ product.wallet,
+ product.product,
+ data.quantity,
+ data.shippingzone,
+ data.address,
+ data.email,
+ checking_id,
+ False,
+ False,
+ ),
+ )
+ return ({"checking_id": checking_id, "payment_request": payment_request}))
From 5cc39930e5c0e0957596362dbbe95f16f475d3b4 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 27 Jan 2022 14:58:58 +0000
Subject: [PATCH 032/226] products
---
lnbits/extensions/diagonalley/views_api.py | 75 ++++++++++++----------
1 file changed, 40 insertions(+), 35 deletions(-)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 4de2799e..9df2c1d8 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -1,4 +1,6 @@
+from base64 import urlsafe_b64encode
from http import HTTPStatus
+from uuid import uuid4
from fastapi import Request
from fastapi.param_functions import Query
@@ -6,41 +8,44 @@ from fastapi.params import Depends
from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
-from lnbits.decorators import api_check_wallet_key, api_validate_post_request
+from lnbits.core.services import create_invoice
+from lnbits.decorators import (
+ WalletTypeInfo,
+ api_check_wallet_key,
+ api_validate_post_request,
+ get_key_type,
+ require_admin_key,
+)
-from . import diagonalley_ext
+from . import db, diagonalley_ext
from .crud import (
- create_diagonalley_product,
- get_diagonalley_product,
- get_diagonalley_products,
- delete_diagonalley_product,
- create_diagonalley_zone,
- update_diagonalley_zone,
- get_diagonalley_zone,
- get_diagonalley_zones,
- delete_diagonalley_zone,
- create_diagonalley_stall,
- update_diagonalley_stall,
- get_diagonalley_stall,
- get_diagonalley_stalls,
- delete_diagonalley_stall,
create_diagonalley_order,
+ create_diagonalley_product,
+ create_diagonalley_stall,
+ create_diagonalley_zone,
+ delete_diagonalley_order,
+ delete_diagonalley_product,
+ delete_diagonalley_stall,
+ delete_diagonalley_zone,
get_diagonalley_order,
get_diagonalley_orders,
+ get_diagonalley_product,
+ get_diagonalley_products,
+ get_diagonalley_stall,
+ get_diagonalley_stalls,
+ get_diagonalley_zone,
+ get_diagonalley_zones,
update_diagonalley_product,
- delete_diagonalley_order,
+ update_diagonalley_stall,
+ update_diagonalley_zone,
)
-from lnbits.core.services import create_invoice
-from base64 import urlsafe_b64encode
-from uuid import uuid4
+from .models import Orders, Products, Stalls
# from lnbits.db import open_ext_db
-from . import db
-from .models import Products, Orders, Stalls
### Products
-
+"""
@copilot_ext.get("/api/v1/copilot/{copilot_id}")
async def api_copilot_retrieve(
req: Request,
@@ -55,26 +60,27 @@ async def api_copilot_retrieve(
if not copilot.lnurl_toggle:
return copilot.dict()
return {**copilot.dict(), **{"lnurl": copilot.lnurl(req)}}
-
+"""
@diagonalley_ext.get("/api/v1/products")
async def api_diagonalley_products(
req: Request,
wallet: WalletTypeInfo = Depends(get_key_type),
+ all_stalls: bool = Query(False)
):
wallet_ids = [wallet.wallet.id]
- if "all_stalls" in request.args:
+ if all_stalls:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- return ([product._asdict() for product in await get_diagonalley_products(wallet_ids)])
+ return ([product.dict() for product in await get_diagonalley_products(wallet_ids)])
@diagonalley_ext.post("/api/v1/products")
@diagonalley_ext.put("/api/v1/products/{product_id}")
async def api_diagonalley_product_create(
data: Products,
- product_id=: str = Query(None),
+ product_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -82,19 +88,19 @@ async def api_diagonalley_product_create(
product = await get_diagonalley_product(product_id)
if not product:
- return ({"message": "Withdraw product does not exist."}))
+ return ({"message": "Withdraw product does not exist."})
if product.wallet != wallet.wallet.id:
- return ({"message": "Not your withdraw product."}))
+ return ({"message": "Not your withdraw product."})
product = await update_diagonalley_product(product_id, data)
else:
product = await create_diagonalley_product(wallet_id=wallet.wallet.id, data)
- return ({**product._asdict()}))
+ return product.dict()
-@diagonalley_ext.route("/api/v1/products/{product_id}")
+@diagonalley_ext.delete("/api/v1/products/{product_id}")
async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
product = await get_diagonalley_product(product_id)
@@ -105,7 +111,6 @@ async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = D
return ({"message": "Not your Diagon Alley."})
await delete_diagonalley_product(product_id)
-
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
@@ -113,13 +118,13 @@ async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = D
@diagonalley_ext.get("/api/v1/zones")
-async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
wallet_ids = [wallet.wallet.id]
- if "all_wallets" in request.args:
+ if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- return ([zone._asdict() for zone in await get_diagonalley_zones(wallet_ids)]))
+ return ([zone.dict() for zone in await get_diagonalley_zones(wallet_ids)])
@diagonalley_ext.post("/api/v1/zones")
From ebaf0c990f32cd545c40e1ae1c645b53a9cdd0bc Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 27 Jan 2022 15:26:55 +0000
Subject: [PATCH 033/226] zones
---
lnbits/extensions/diagonalley/crud.py | 63 +++++++++-------------
lnbits/extensions/diagonalley/models.py | 41 +++++++++-----
lnbits/extensions/diagonalley/views_api.py | 26 +++++----
3 files changed, 64 insertions(+), 66 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index c6ce8222..7dc02cd4 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -1,17 +1,17 @@
+import re
from base64 import urlsafe_b64encode
-from uuid import uuid4
from typing import List, Optional, Union
+from uuid import uuid4
-from lnbits.settings import WALLET
+import httpx
# from lnbits.db import open_ext_db
from lnbits.db import SQLITE
-from . import db
-from .models import Products, Orders, Stalls, Zones
-
-import httpx
from lnbits.helpers import urlsafe_short_hash
-import re
+from lnbits.settings import WALLET
+
+from . import db
+from .models import Orders, Products, Stalls, Zones, createProduct, createZones
regex = re.compile(
r"^(?:http|ftp)s?://" # http:// or https://
@@ -28,35 +28,27 @@ regex = re.compile(
async def create_diagonalley_product(
- *,
- stall_id: str,
- product: str,
- categories: str,
- description: str,
- image: Optional[str] = None,
- price: int,
- quantity: int,
- shippingzones: str,
+ data: createProduct
) -> Products:
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
+ # returning = "" if db.type == SQLITE else "RETURNING ID"
+ # method = db.execute if db.type == SQLITE else db.fetchone
product_id = urlsafe_short_hash()
# with open_ext_db("diagonalley") as db:
- result = await (method)(
+ # result = await (method)(
+ await db.execute(
f"""
- INSERT INTO diagonalley.products (id, stall, product, categories, description, image, price, quantity, shippingzones)
+ INSERT INTO diagonalley.products (id, stall, product, categories, description, image, price, quantity)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- {returning}
""",
(
product_id,
- stall_id,
- product,
- categories,
- description,
- image,
- price,
- quantity,
+ data.stall,
+ data.product,
+ data.categories,
+ data.description,
+ data.image,
+ data.price,
+ data.quantity,
),
)
product = await get_diagonalley_product(product_id)
@@ -109,17 +101,11 @@ async def delete_diagonalley_product(product_id: str) -> None:
async def create_diagonalley_zone(
- *,
- wallet: Optional[str] = None,
- cost: Optional[int] = 0,
- countries: Optional[str] = None,
+ wallet,
+ data: createZones
) -> Zones:
-
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
-
zone_id = urlsafe_short_hash()
- result = await (method)(
+ await db.execute(
f"""
INSERT INTO diagonalley.zones (
id,
@@ -129,9 +115,8 @@ async def create_diagonalley_zone(
)
VALUES (?, ?, ?, ?)
- {returning}
""",
- (zone_id, wallet, cost, countries),
+ (zone_id, wallet, data.cost, data.countries),
)
zone = await get_diagonalley_zone(zone_id)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 0f2a1d78..bd667a2f 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -1,12 +1,15 @@
-from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult
-from starlette.requests import Request
+import json
+from lib2to3.pytree import Base
+from sqlite3 import Row
+from typing import Dict, Optional
+from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse
+
from fastapi.param_functions import Query
-from typing import Optional, Dict
-from lnbits.lnurl import encode as lnurl_encode # type: ignore
from lnurl.types import LnurlPayMetadata # type: ignore
from pydantic import BaseModel
-import json
-from sqlite3 import Row
+from starlette.requests import Request
+
+from lnbits.lnurl import encode as lnurl_encode # type: ignore
class Stalls(BaseModel):
@@ -25,23 +28,35 @@ class createStalls(BaseModel):
relays: str = Query(None)
shippingzones: str = Query(None)
-class Products(BaseModel):
- id: str = Query(None)
+class createProduct(BaseModel):
stall: str = Query(None)
product: str = Query(None)
categories: str = Query(None)
description: str = Query(None)
image: str = Query(None)
- price: int = Query(0)
- quantity: int = Query(0)
+ price: int = Query(0, ge=0)
+ quantity: int = Query(0, ge=0)
+class Products(BaseModel):
+ id: str
+ stall: str
+ product: str
+ categories: str
+ description: str
+ image: str
+ price: int
+ quantity: int
-class Zones(BaseModel):
- id: str = Query(None)
- wallet: str = Query(None)
+class createZones(BaseModel):
cost: str = Query(None)
countries: str = Query(None)
+class Zones(BaseModel):
+ id: str
+ wallet: str
+ cost: str
+ countries: str
+
class Orders(BaseModel):
id: str = Query(None)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 9df2c1d8..1ad83936 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -39,7 +39,7 @@ from .crud import (
update_diagonalley_stall,
update_diagonalley_zone,
)
-from .models import Orders, Products, Stalls
+from .models import Orders, Products, Stalls, Zones, createProduct, createZones
# from lnbits.db import open_ext_db
@@ -79,7 +79,7 @@ async def api_diagonalley_products(
@diagonalley_ext.post("/api/v1/products")
@diagonalley_ext.put("/api/v1/products/{product_id}")
async def api_diagonalley_product_create(
- data: Products,
+ data: createProduct,
product_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -93,9 +93,9 @@ async def api_diagonalley_product_create(
if product.wallet != wallet.wallet.id:
return ({"message": "Not your withdraw product."})
- product = await update_diagonalley_product(product_id, data)
+ product = await update_diagonalley_product(product_id, **data.dict())
else:
- product = await create_diagonalley_product(wallet_id=wallet.wallet.id, data)
+ product = await create_diagonalley_product(data=data)
return product.dict()
@@ -126,11 +126,10 @@ async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type),
return ([zone.dict() for zone in await get_diagonalley_zones(wallet_ids)])
-
@diagonalley_ext.post("/api/v1/zones")
@diagonalley_ext.put("/api/v1/zones/{zone_id}")
async def api_diagonalley_zone_create(
- data: Zones,
+ data: createZones,
zone_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -138,20 +137,20 @@ async def api_diagonalley_zone_create(
zone = await get_diagonalley_zone(zone_id)
if not zone:
- return ({"message": "Zone does not exist."}))
+ return ({"message": "Zone does not exist."})
- if zone.wallet != walley.wallet.id:
- return ({"message": "Not your record."}))
+ if zone.wallet != wallet.wallet.id:
+ return ({"message": "Not your record."})
- zone = await update_diagonalley_zone(zone_id, data)
+ zone = await update_diagonalley_zone(zone_id, **data.dict())
else:
- zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data)
+ zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data=data)
- return ({**zone._asdict()}))
+ return zone.dict()
@diagonalley_ext.delete("/api/v1/zones/{zone_id}")
-async def api_diagonalley_zone_delete(zone_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)):
+async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
zone = await get_diagonalley_zone(zone_id)
if not zone:
@@ -161,7 +160,6 @@ async def api_diagonalley_zone_delete(zone_id: str = Query(None), wallet: Walle
return ({"message": "Not your zone."})
await delete_diagonalley_zone(zone_id)
-
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
From 8b373021641674d7875afb6b002e7b26c7afae55 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 27 Jan 2022 16:18:12 +0000
Subject: [PATCH 034/226] stalls
---
lnbits/extensions/diagonalley/crud.py | 34 ++++++++++++----------
lnbits/extensions/diagonalley/models.py | 25 ++++++++--------
lnbits/extensions/diagonalley/views_api.py | 29 +++++++++++-------
3 files changed, 50 insertions(+), 38 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 7dc02cd4..3b58b129 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -11,7 +11,15 @@ from lnbits.helpers import urlsafe_short_hash
from lnbits.settings import WALLET
from . import db
-from .models import Orders, Products, Stalls, Zones, createProduct, createZones
+from .models import (
+ Orders,
+ Products,
+ Stalls,
+ Zones,
+ createProduct,
+ createStalls,
+ createZones,
+)
regex = re.compile(
r"^(?:http|ftp)s?://" # http:// or https://
@@ -185,20 +193,10 @@ async def delete_diagonalley_zone(zone_id: str) -> None:
async def create_diagonalley_stall(
- *,
- wallet: str,
- name: str,
- publickey: str,
- privatekey: str,
- relays: str,
- shippingzones: str,
+ data: createStalls
) -> Stalls:
-
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
-
stall_id = urlsafe_short_hash()
- result = await (method)(
+ await db.execute(
f"""
INSERT INTO diagonalley.stalls (
id,
@@ -210,9 +208,15 @@ async def create_diagonalley_stall(
shippingzones
)
VALUES (?, ?, ?, ?, ?, ?, ?)
- {returning}
""",
- (stall_id, wallet, name, publickey, privatekey, relays, shippingzones),
+ (
+ stall_id,
+ data.wallet,
+ data.name,
+ data.publickey,
+ data.privatekey,
+ data.relays,
+ data.shippingzones),
)
stall = await get_diagonalley_stall(stall_id)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index bd667a2f..4c674c8a 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -13,20 +13,21 @@ from lnbits.lnurl import encode as lnurl_encode # type: ignore
class Stalls(BaseModel):
- id: str = Query(None)
- wallet: str = Query(None)
- name: str = Query(None)
- publickey: str = Query(None)
- privatekey: str = Query(None)
- relays: str = Query(None)
+ id: str
+ wallet: str
+ name: str
+ publickey: str
+ privatekey: str
+ relays: str
+ shippingzones: str
class createStalls(BaseModel):
- wallet: str = Query(None)
- name: str = Query(None)
- publickey: str = Query(None)
- privatekey: str = Query(None)
- relays: str = Query(None)
- shippingzones: str = Query(None)
+ wallet: str = Query(...)
+ name: str = Query(...)
+ publickey: str = Query(...)
+ privatekey: str = Query(...)
+ relays: str = Query(...)
+ shippingzones: str = Query(...)
class createProduct(BaseModel):
stall: str = Query(None)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 1ad83936..ccac9b24 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -39,7 +39,15 @@ from .crud import (
update_diagonalley_stall,
update_diagonalley_zone,
)
-from .models import Orders, Products, Stalls, Zones, createProduct, createZones
+from .models import (
+ Orders,
+ Products,
+ Stalls,
+ Zones,
+ createProduct,
+ createStalls,
+ createZones,
+)
# from lnbits.db import open_ext_db
@@ -167,33 +175,33 @@ async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(
@diagonalley_ext.get("/api/v1/stalls")
-async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
wallet_ids = [wallet.wallet.id]
- if "all_wallets" in request.args:
+ if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- return ([stall._asdict() for stall in await get_diagonalley_stalls(wallet_ids)])
+ return ([stall.dict() for stall in await get_diagonalley_stalls(wallet_ids)])
@diagonalley_ext.post("/api/v1/stalls")
@diagonalley_ext.put("/api/v1/stalls/{stall_id}")
-async def api_diagonalley_stall_create(data: createStalls, stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stall_create(data: createStalls, stall_id = None, wallet: WalletTypeInfo = Depends(get_key_type)):
if stall_id:
stall = await get_diagonalley_stall(stall_id)
if not stall:
- return ({"message": "Withdraw stall does not exist."}))
+ return ({"message": "Withdraw stall does not exist."})
if stall.wallet != wallet.wallet.id:
- return ({"message": "Not your withdraw stall."}))
+ return ({"message": "Not your withdraw stall."})
- stall = await update_diagonalley_stall(stall_id, data)
+ stall = await update_diagonalley_stall(stall_id, **data.dict())
else:
- stall = await create_diagonalley_stall(wallet_id=wallet.wallet.id, data)
+ stall = await create_diagonalley_stall(data=data)
- return ({**stall._asdict()}))
+ return stall.dict()
@diagonalley_ext.delete("/api/v1/stalls/{stall_id}")
@@ -207,7 +215,6 @@ async def api_diagonalley_stall_delete(stall_id: str = Query(None), wallet: Wall
return ({"message": "Not your Stall."})
await delete_diagonalley_stall(stall_id)
-
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
From c41f6033be1066bae9f13f66d414a6bc07c3734b Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 28 Jan 2022 15:11:31 +0000
Subject: [PATCH 035/226] orders
---
lnbits/extensions/diagonalley/crud.py | 62 +++++++++-------------
lnbits/extensions/diagonalley/models.py | 28 ++++++----
lnbits/extensions/diagonalley/views_api.py | 42 +++++++--------
3 files changed, 65 insertions(+), 67 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 3b58b129..4cf14014 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -16,6 +16,7 @@ from .models import (
Products,
Stalls,
Zones,
+ createOrder,
createProduct,
createStalls,
createZones,
@@ -83,7 +84,7 @@ async def get_diagonalley_product(product_id: str) -> Optional[Products]:
row = await db.fetchone(
"SELECT * FROM diagonalley.products WHERE id = ?", (product_id,)
)
- return Products.from_row(row) if row else None
+ return Products(**row) if row else None
async def get_diagonalley_products(wallet_ids: Union[str, List[str]]) -> List[Products]:
@@ -98,7 +99,7 @@ async def get_diagonalley_products(wallet_ids: Union[str, List[str]]) -> List[Pr
""",
(*wallet_ids,),
)
- return [Products.from_row(row) for row in rows]
+ return [Products(**row) for row in rows]
async def delete_diagonalley_product(product_id: str) -> None:
@@ -139,12 +140,12 @@ async def update_diagonalley_zone(zone_id: str, **kwargs) -> Optional[Zones]:
(*kwargs.values(), zone_id),
)
row = await db.fetchone("SELECT * FROM diagonalley.zones WHERE id = ?", (zone_id,))
- return Zones.from_row(row) if row else None
+ return Zones(**row) if row else None
async def get_diagonalley_zone(zone_id: str) -> Optional[Zones]:
row = await db.fetchone("SELECT * FROM diagonalley.zones WHERE id = ?", (zone_id,))
- return Zones.from_row(row) if row else None
+ return Zones(**row) if row else None
async def get_diagonalley_zones(wallet_ids: Union[str, List[str]]) -> List[Zones]:
@@ -182,7 +183,7 @@ async def get_diagonalley_zones(wallet_ids: Union[str, List[str]]) -> List[Zones
rows = await db.fetchall(
f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
)
- return [Zones.from_row(row) for row in rows]
+ return [Zones(**row) for row in rows]
async def delete_diagonalley_zone(zone_id: str) -> None:
@@ -233,7 +234,7 @@ async def update_diagonalley_stall(stall_id: str, **kwargs) -> Optional[Stalls]:
row = await db.fetchone(
"SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
)
- return Stalls.from_row(row) if row else None
+ return Stalls(**row) if row else None
async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
@@ -266,7 +267,7 @@ async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
row = await db.fetchone(
"SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
)
- return Stalls.from_row(row) if row else None
+ return Stalls(**row) if row else None
async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]:
@@ -303,7 +304,7 @@ async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stal
rows = await db.fetchall(
f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
)
- return [Stalls.from_row(row) for row in rows]
+ return [Stalls(**row) for row in rows]
async def delete_diagonalley_stall(stall_id: str) -> None:
@@ -314,47 +315,34 @@ async def delete_diagonalley_stall(stall_id: str) -> None:
async def create_diagonalley_order(
- *,
- productid: str,
- wallet: str,
- product: str,
- quantity: int,
- shippingzone: str,
- address: str,
- email: str,
- invoiceid: str,
- paid: bool,
- shipped: bool,
+ data: createOrder
) -> Orders:
- returning = "" if db.type == SQLITE else "RETURNING ID"
- method = db.execute if db.type == SQLITE else db.fetchone
order_id = urlsafe_short_hash()
- result = await (method)(
+ await db.execute(
f"""
INSERT INTO diagonalley.orders (id, productid, wallet, product,
quantity, shippingzone, address, email, invoiceid, paid, shipped)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- {returning}
""",
(
order_id,
- productid,
- wallet,
- product,
- quantity,
- shippingzone,
- address,
- email,
- invoiceid,
+ data.productid,
+ data.wallet,
+ data.product,
+ data.quantity,
+ data.shippingzone,
+ data.address,
+ data.email,
+ data.invoiceid,
False,
False,
),
)
- if db.type == SQLITE:
- order_id = result._result_proxy.lastrowid
- else:
- order_id = result[0]
+ # if db.type == SQLITE:
+ # order_id = result._result_proxy.lastrowid
+ # else:
+ # order_id = result[0]
link = await get_diagonalley_order(order_id)
assert link, "Newly created link couldn't be retrieved"
@@ -365,7 +353,7 @@ async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
row = await db.fetchone(
"SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
)
- return Orders.from_row(row) if row else None
+ return Orders(**row) if row else None
async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
@@ -377,7 +365,7 @@ async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orde
f"SELECT * FROM diagonalley.orders WHERE wallet IN ({q})", (*wallet_ids,)
)
#
- return [Orders.from_row(row) for row in rows]
+ return [Orders(**row) for row in rows]
async def delete_diagonalley_order(order_id: str) -> None:
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 4c674c8a..1a975e10 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -59,15 +59,25 @@ class Zones(BaseModel):
countries: str
+class createOrder(BaseModel):
+ productid: str = Query(...)
+ stall: str = Query(...)
+ product: str = Query(...)
+ quantity: int = Query(..., ge=1)
+ shippingzone: int = Query(...)
+ address: str = Query(...)
+ email: str = Query(...)
+ invoiceid: str = Query(...)
+
class Orders(BaseModel):
- id: str = Query(None)
- productid: str = Query(None)
- stall: str = Query(None)
- product: str = Query(None)
- quantity: int = Query(0)
- shippingzone: int = Query(0)
- address: str = Query(None)
- email: str = Query(None)
- invoiceid: str = Query(None)
+ id: str
+ productid: str
+ stall: str
+ product: str
+ quantity: int
+ shippingzone: int
+ address: str
+ email: str
+ invoiceid: str
paid: bool
shipped: bool
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index ccac9b24..165d2a0c 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -44,6 +44,7 @@ from .models import (
Products,
Stalls,
Zones,
+ createOrder,
createProduct,
createStalls,
createZones,
@@ -87,8 +88,8 @@ async def api_diagonalley_products(
@diagonalley_ext.post("/api/v1/products")
@diagonalley_ext.put("/api/v1/products/{product_id}")
async def api_diagonalley_product_create(
+ product_id,
data: createProduct,
- product_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
@@ -186,7 +187,7 @@ async def api_diagonalley_stalls(wallet: WalletTypeInfo = Depends(get_key_type),
@diagonalley_ext.post("/api/v1/stalls")
@diagonalley_ext.put("/api/v1/stalls/{stall_id}")
-async def api_diagonalley_stall_create(data: createStalls, stall_id = None, wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stall_create(data: createStalls, stall_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
if stall_id:
stall = await get_diagonalley_stall(stall_id)
@@ -222,23 +223,22 @@ async def api_diagonalley_stall_delete(stall_id: str = Query(None), wallet: Wall
@diagonalley_ext.get("/api/v1/orders")
-async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
wallet_ids = [wallet.wallet.id]
- if "all_wallets" in request.args:
+ if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
try:
- return ([order._asdict() for order in await get_diagonalley_orders(wallet_ids)])
+ return ([order.dict() for order in await get_diagonalley_orders(wallet_ids)])
except:
- return ({"message": "We could not retrieve the orders."}))
+ return ({"message": "We could not retrieve the orders."})
@diagonalley_ext.post("/api/v1/orders")
-
-async def api_diagonalley_order_create(data: createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
- order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data)
- return ({**order._asdict()})
+async def api_diagonalley_order_create(data: createOrder, wallet: WalletTypeInfo = Depends(get_key_type)):
+ order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data=data)
+ return order.dict()
@diagonalley_ext.delete("/api/v1/orders/{order_id}")
@@ -281,7 +281,7 @@ async def api_diagonalley_order_shipped(order_id: str = Query(None), wallet: Wal
"SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
)
- return ([order._asdict() for order in get_diagonalley_orders(order["wallet"])]))
+ return ([order.dict() for order in get_diagonalley_orders(order["wallet"])])
###List products based on stall id
@@ -303,14 +303,14 @@ async def api_diagonalley_stall_products(stall_id: str = Query(None), wallet: Wa
if not products:
return ({"message": "No products"})
- return ([products._asdict() for products in await get_diagonalley_products(rows[1])])
+ return ([products.dict() for products in await get_diagonalley_products(rows[1])])
###Check a product has been shipped
@diagonalley_ext.get("/api/v1/stall/checkshipped/{checking_id}")
-async def api_diagonalley_stall_checkshipped(checking_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_stall_checkshipped(checking_id, wallet: WalletTypeInfo = Depends(get_key_type)):
rows = await db.fetchone(
"SELECT * FROM diagonalley.orders WHERE invoiceid = ?", (checking_id,)
)
@@ -321,19 +321,19 @@ async def api_diagonalley_stall_checkshipped(checking_id: str = Query(None), wal
@diagonalley_ext.post("/api/v1/stall/order/{stall_id}")
-async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo = Depends(get_key_type)):
- product = await get_diagonalley_product(data.id)
+async def api_diagonalley_stall_order(stall_id, data: createOrder, wallet: WalletTypeInfo = Depends(get_key_type)):
+ product = await get_diagonalley_product(data.productid)
shipping = await get_diagonalley_stall(stall_id)
if data.shippingzone == 1:
- shippingcost = shipping.zone1cost
+ shippingcost = shipping.zone1cost #missing in model
else:
- shippingcost = shipping.zone2cost
+ shippingcost = shipping.zone2cost #missing in model
checking_id, payment_request = await create_invoice(
wallet_id=product.wallet,
amount=shippingcost + (data.quantity * product.price),
- memo=data.id,
+ memo=shipping.wallet,
)
selling_id = urlsafe_b64encode(uuid4().bytes_le).decode("utf-8")
await db.execute(
@@ -343,8 +343,8 @@ async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo
""",
(
selling_id,
- data.id,
- product.wallet,
+ data.productid,
+ product.wallet, #doesn't exist in model
product.product,
data.quantity,
data.shippingzone,
@@ -355,4 +355,4 @@ async def api_diagonalley_stall_order(data:createOrders, wallet: WalletTypeInfo
False,
),
)
- return ({"checking_id": checking_id, "payment_request": payment_request}))
+ return ({"checking_id": checking_id, "payment_request": payment_request})
From a55dd18528ef5a91782352972d6c59d02d5c46c9 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 28 Jan 2022 16:22:54 +0000
Subject: [PATCH 036/226] UI fires up
---
lnbits/extensions/diagonalley/__init__.py | 35 +++++++++++---
lnbits/extensions/diagonalley/tasks.py | 6 +--
lnbits/extensions/diagonalley/views.py | 55 +++++++++-------------
lnbits/extensions/diagonalley/views_api.py | 8 +---
4 files changed, 55 insertions(+), 49 deletions(-)
diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py
index 720c55c8..cab65685 100644
--- a/lnbits/extensions/diagonalley/__init__.py
+++ b/lnbits/extensions/diagonalley/__init__.py
@@ -1,16 +1,37 @@
-from quart import Blueprint
+import asyncio
+
+from fastapi import APIRouter
+from fastapi.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_diagonalley")
-diagonalley_ext: Blueprint = Blueprint(
- "diagonalley", __name__, static_folder="static", template_folder="templates"
+diagonalley_static_files = [
+ {
+ "path": "/diagonalley/static",
+ "app": StaticFiles(directory="lnbits/extensions/diagonalley/static"),
+ "name": "diagonalley_static",
+ }
+]
+
+diagonalley_ext: APIRouter = APIRouter(
+ prefix="/diagonalley", tags=["diagonalley"]
+ # "diagonalley", __name__, static_folder="static", template_folder="templates"
)
-from .views_api import * # noqa
+def diagonalley_renderer():
+ return template_renderer(["lnbits/extensions/diagonalley/templates"])
+
+
+from .tasks import wait_for_paid_invoices
from .views import * # noqa
+from .views_api import * # noqa
-from .tasks import register_listeners
-from lnbits.tasks import record_async
-diagonalley_ext.record(record_async(register_listeners))
+def diagonalley_start():
+ loop = asyncio.get_event_loop()
+ loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
+
diff --git a/lnbits/extensions/diagonalley/tasks.py b/lnbits/extensions/diagonalley/tasks.py
index 3fee63d9..bcbb7025 100644
--- a/lnbits/extensions/diagonalley/tasks.py
+++ b/lnbits/extensions/diagonalley/tasks.py
@@ -3,8 +3,6 @@ import asyncio
from lnbits.core.models import Payment
from lnbits.tasks import register_invoice_listener
-from .crud import get_ticket, set_ticket_paid
-
async def wait_for_paid_invoices():
invoice_queue = asyncio.Queue()
@@ -16,6 +14,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None:
+ """
if "lnticket" != payment.extra.get("tag"):
# not a lnticket invoice
return
@@ -26,4 +25,5 @@ async def on_invoice_paid(payment: Payment) -> None:
return
await payment.set_pending(False)
- await set_ticket_paid(payment.payment_hash)
\ No newline at end of file
+ await set_ticket_paid(payment.payment_hash)
+ """
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 2deed72b..ae0899ca 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -1,44 +1,35 @@
-from typing import List
-
-from fastapi import Request, WebSocket, WebSocketDisconnect
-from fastapi.params import Depends
-from fastapi.templating import Jinja2Templates
-from starlette.responses import HTMLResponse # type: ignore
-
from http import HTTPStatus
-import json
-from lnbits.decorators import check_user_exists, validate_uuids
-from lnbits.extensions.diagonalley import diagonalley_ext
-from .crud import (
- create_diagonalley_product,
- get_diagonalley_product,
- get_diagonalley_products,
- delete_diagonalley_product,
- create_diagonalley_order,
- get_diagonalley_order,
- get_diagonalley_orders,
- update_diagonalley_product,
-)
+from fastapi import Request
+from fastapi.params import Depends
+from fastapi.templating import Jinja2Templates
+from starlette.exceptions import HTTPException
+from starlette.responses import HTMLResponse
+from lnbits.core.models import User
+from lnbits.decorators import check_user_exists # type: ignore
+from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
+
+from .crud import get_diagonalley_products
+
+templates = Jinja2Templates(directory="templates")
@diagonalley_ext.get("/", response_class=HTMLResponse)
-@validate_uuids(["usr"], required=True)
-@check_user_exists(request: Request)
-async def index():
- return await render_template("diagonalley/index.html", user=g.user)
+async def index(request: Request, user: User = Depends(check_user_exists)):
+ return diagonalley_renderer().TemplateResponse(
+ "diagonalley/index.html", {"request": request, "user": user.dict()}
+ )
-
-@diagonalley_ext.get("/", response_class=HTMLResponse)
+@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
product = await get_diagonalley_products(stall_id)
+
if not product:
- abort(HTTPStatus.NOT_FOUND, "Stall does not exist.")
-
- return await render_template(
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
+ )
+ return diagonalley_renderer().TemplateResponse(
"diagonalley/stall.html",
- stall=json.dumps(
- [product._asdict() for product in await get_diagonalley_products(stall_id)]
- ),
+ {"stall": [product.dict() for product in await get_diagonalley_products(stall_id)]}
)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 165d2a0c..43232841 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -9,13 +9,7 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.core.services import create_invoice
-from lnbits.decorators import (
- WalletTypeInfo,
- api_check_wallet_key,
- api_validate_post_request,
- get_key_type,
- require_admin_key,
-)
+from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
from . import db, diagonalley_ext
from .crud import (
From 80a5d26dce583e1b10d104dde9554576dadb85a5 Mon Sep 17 00:00:00 2001
From: benarc
Date: Thu, 3 Feb 2022 21:19:24 +0000
Subject: [PATCH 037/226] Message ui working
---
.../extensions/diagonalley/static/js/index.js | 83 ++++++++++++-------
.../templates/diagonalley/index.html | 47 ++++++-----
2 files changed, 78 insertions(+), 52 deletions(-)
diff --git a/lnbits/extensions/diagonalley/static/js/index.js b/lnbits/extensions/diagonalley/static/js/index.js
index 1a25edaa..af81db2a 100644
--- a/lnbits/extensions/diagonalley/static/js/index.js
+++ b/lnbits/extensions/diagonalley/static/js/index.js
@@ -2,7 +2,24 @@
Vue.component(VueQrcode.name, VueQrcode)
-const pica = window.pica()
+//const pica = window.pica()
+
+var mapStalls = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
+var mapProducts = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
+var mapZone = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
+var mapOrders = obj => {
+ obj._data = _.clone(obj)
+ return obj
+}
new Vue({
el: '#vue',
@@ -13,6 +30,9 @@ new Vue({
orders: [],
stalls: [],
zones: [],
+ customerKeys: [],
+ customerKey: '',
+ customerMessages: {},
shippedModel: false,
shippingZoneOptions: [
'Australia',
@@ -64,7 +84,8 @@ new Vue({
'Groceries (Food and Drink)',
'Technology (Phones and Computers)',
'Home (furniture and accessories)',
- 'Gifts (flowers, cards, etc)'
+ 'Gifts (flowers, cards, etc)',
+ 'Adult'
],
relayOptions: [
'wss://nostr-relay.herokuapp.com/ws',
@@ -244,6 +265,17 @@ new Vue({
}
},
methods: {
+ ////////////////////////////////////////
+ ///////////SUPPORT MESSAGES/////////////
+ ////////////////////////////////////////
+ getMessages: function (customerKey) {
+ var self = this
+ console.log('fuck')
+ messages = []
+ messages.push(['in', 'blah blah'])
+ messages.push(['out', 'blah blah'])
+ self.customerMessages = messages
+ },
////////////////////////////////////////
////////////////STALLS//////////////////
////////////////////////////////////////
@@ -256,10 +288,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.stalls = response.data.map(function (obj) {
- console.log(obj)
- return mapDiagonAlley(obj)
- })
+ self.stalls.push(mapStalls(response.data))
})
},
openStallUpdateDialog: function (linkId) {
@@ -302,7 +331,7 @@ new Vue({
self.stalls = _.reject(self.stalls, function (obj) {
return obj.id == data.id
})
- self.stalls.push(mapDiagonAlley(response.data))
+ self.stalls.push(mapStalls(response.data))
self.stallDialog.show = false
self.stallDialog.data = {}
data = {}
@@ -323,7 +352,7 @@ new Vue({
data
)
.then(function (response) {
- self.stalls.push(mapDiagonAlley(response.data))
+ self.stalls.push(mapStalls(response.data))
self.stallDialog.show = false
self.stallDialog.data = {}
data = {}
@@ -371,9 +400,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.products = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.products.push(mapProducts(response.data))
})
},
openProductUpdateDialog: function (linkId) {
@@ -450,7 +477,7 @@ new Vue({
self.products = _.reject(self.products, function (obj) {
return obj.id == data.id
})
- self.products.push(mapDiagonAlley(response.data))
+ self.products.push(mapProducts(response.data))
self.productDialog.show = false
self.productDialog.data = {}
})
@@ -470,7 +497,7 @@ new Vue({
data
)
.then(function (response) {
- self.products.push(mapDiagonAlley(response.data))
+ self.products.push(mapProducts(response.data))
self.productDialog.show = false
self.productDialog.data = {}
})
@@ -517,9 +544,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.zones = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.zones.push(mapZone(response.data))
})
},
openZoneUpdateDialog: function (linkId) {
@@ -559,7 +584,7 @@ new Vue({
self.zones = _.reject(self.zones, function (obj) {
return obj.id == data.id
})
- self.zones.push(mapDiagonAlley(response.data))
+ self.zones.push(mapZone(response.data))
self.zoneDialog.show = false
self.zoneDialog.data = {}
data = {}
@@ -580,7 +605,7 @@ new Vue({
data
)
.then(function (response) {
- self.zones.push(mapDiagonAlley(response.data))
+ self.zones.push(mapZone(response.data))
self.zoneDialog.show = false
self.zoneDialog.data = {}
data = {}
@@ -628,9 +653,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.shops = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.shops.push(mapShops(response.data))
})
},
openShopUpdateDialog: function (linkId) {
@@ -670,7 +693,7 @@ new Vue({
self.shops = _.reject(self.shops, function (obj) {
return obj.id == data.id
})
- self.shops.push(mapDiagonAlley(response.data))
+ self.shops.push(mapShops(response.data))
self.shopDialog.show = false
self.shopDialog.data = {}
data = {}
@@ -692,7 +715,7 @@ new Vue({
data
)
.then(function (response) {
- self.shops.push(mapDiagonAlley(response.data))
+ self.shops.push(mapShops(response.data))
self.shopDialog.show = false
self.shopDialog.data = {}
data = {}
@@ -740,9 +763,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.orders = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.orders.push(mapOrders(response.data))
})
},
createOrder: function () {
@@ -763,7 +784,7 @@ new Vue({
data
)
.then(function (response) {
- self.orders.push(mapDiagonAlley(response.data))
+ self.orders.push(mapOrders(response.data))
self.orderDialog.show = false
self.orderDialog.data = {}
})
@@ -804,9 +825,7 @@ new Vue({
this.g.user.wallets[0].inkey
)
.then(function (response) {
- self.orders = response.data.map(function (obj) {
- return mapDiagonAlley(obj)
- })
+ self.orders.push(mapOrders(response.data))
})
},
exportOrdersCSV: function () {
@@ -819,6 +838,10 @@ new Vue({
this.getProducts()
this.getZones()
this.getOrders()
+ this.customerKeys = [
+ 'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
+ 'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
+ ]
}
}
})
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 98405f6d..a89c8b5e 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -594,34 +594,37 @@
- Messages (example)
+ Messages
-
-
-
OrderID:87h87h KJBIBYBUYBUF90898....
-
OrderID:NIUHB7 79867KJGJHGVFYFV....
+
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
From 1988a9d5d769ed1d2fc72471cb790ec0b4f2fefd Mon Sep 17 00:00:00 2001
From: benarc
Date: Thu, 3 Feb 2022 22:30:53 +0000
Subject: [PATCH 038/226] Added error messages
---
lnbits/extensions/diagonalley/static/js/index.js | 6 ++++++
.../diagonalley/templates/diagonalley/index.html | 13 ++++++++++---
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/lnbits/extensions/diagonalley/static/js/index.js b/lnbits/extensions/diagonalley/static/js/index.js
index af81db2a..d101bfcf 100644
--- a/lnbits/extensions/diagonalley/static/js/index.js
+++ b/lnbits/extensions/diagonalley/static/js/index.js
@@ -265,6 +265,12 @@ new Vue({
}
},
methods: {
+ errorMessage: function (error) {
+ this.$q.notify({
+ color: 'primary',
+ message: error
+ })
+ },
////////////////////////////////////////
///////////SUPPORT MESSAGES/////////////
////////////////////////////////////////
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index a89c8b5e..d14d7cee 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -300,13 +300,20 @@
- + Product List a product
+ + Product List a product
+ Shipping Zone Create a shipping zone
- + Stall
+ Create a stall to list products on
+ + Stall
Create a stall to list products on
@@ -618,7 +625,7 @@
>
-
+
From 40fd894cced11135332b187939a52f787bcd1fab Mon Sep 17 00:00:00 2001
From: benarc
Date: Fri, 4 Feb 2022 13:05:48 +0000
Subject: [PATCH 039/226] Zones are saving/updating
---
lnbits/extensions/diagonalley/__init__.py | 11 +-
lnbits/extensions/diagonalley/crud.py | 116 +--
lnbits/extensions/diagonalley/migrations.py | 8 +-
lnbits/extensions/diagonalley/models.py | 7 +-
.../extensions/diagonalley/static/js/index.js | 853 -----------------
.../templates/diagonalley/index.html | 895 +++++++++++++++++-
lnbits/extensions/diagonalley/views_api.py | 40 +-
7 files changed, 924 insertions(+), 1006 deletions(-)
delete mode 100644 lnbits/extensions/diagonalley/static/js/index.js
diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py
index cab65685..388c08db 100644
--- a/lnbits/extensions/diagonalley/__init__.py
+++ b/lnbits/extensions/diagonalley/__init__.py
@@ -9,17 +9,9 @@ from lnbits.tasks import catch_everything_and_restart
db = Database("ext_diagonalley")
-diagonalley_static_files = [
- {
- "path": "/diagonalley/static",
- "app": StaticFiles(directory="lnbits/extensions/diagonalley/static"),
- "name": "diagonalley_static",
- }
-]
diagonalley_ext: APIRouter = APIRouter(
prefix="/diagonalley", tags=["diagonalley"]
- # "diagonalley", __name__, static_folder="static", template_folder="templates"
)
def diagonalley_renderer():
@@ -33,5 +25,4 @@ from .views_api import * # noqa
def diagonalley_start():
loop = asyncio.get_event_loop()
- loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
-
+ loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
\ No newline at end of file
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 4cf14014..d2df427c 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -22,28 +22,12 @@ from .models import (
createZones,
)
-regex = re.compile(
- r"^(?:http|ftp)s?://" # http:// or https://
- r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|"
- r"localhost|"
- r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
- r"(?::\d+)?"
- r"(?:/?|[/?]\S+)$",
- re.IGNORECASE,
-)
-
-
###Products
-
async def create_diagonalley_product(
data: createProduct
) -> Products:
- # returning = "" if db.type == SQLITE else "RETURNING ID"
- # method = db.execute if db.type == SQLITE else db.fetchone
product_id = urlsafe_short_hash()
- # with open_ext_db("diagonalley") as db:
- # result = await (method)(
await db.execute(
f"""
INSERT INTO diagonalley.products (id, stall, product, categories, description, image, price, quantity)
@@ -110,7 +94,7 @@ async def delete_diagonalley_product(product_id: str) -> None:
async def create_diagonalley_zone(
- wallet,
+ user,
data: createZones
) -> Zones:
zone_id = urlsafe_short_hash()
@@ -118,14 +102,14 @@ async def create_diagonalley_zone(
f"""
INSERT INTO diagonalley.zones (
id,
- wallet,
+ user,
cost,
countries
)
VALUES (?, ?, ?, ?)
""",
- (zone_id, wallet, data.cost, data.countries),
+ (zone_id, user, data.cost, data.countries.lower()),
)
zone = await get_diagonalley_zone(zone_id)
@@ -148,41 +132,8 @@ async def get_diagonalley_zone(zone_id: str) -> Optional[Zones]:
return Zones(**row) if row else None
-async def get_diagonalley_zones(wallet_ids: Union[str, List[str]]) -> List[Zones]:
- if isinstance(wallet_ids, str):
- wallet_ids = [wallet_ids]
- print(wallet_ids)
-
- q = ",".join(["?"] * len(wallet_ids))
- rows = await db.fetchall(
- f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
- )
-
- for r in rows:
- try:
- x = httpx.get(r["zoneaddress"] + "/" + r["ratingkey"])
- if x.status_code == 200:
- await db.execute(
- "UPDATE diagonalley.zones SET online = ? WHERE id = ?",
- (
- True,
- r["id"],
- ),
- )
- else:
- await db.execute(
- "UPDATE diagonalley.zones SET online = ? WHERE id = ?",
- (
- False,
- r["id"],
- ),
- )
- except:
- print("An exception occurred")
- q = ",".join(["?"] * len(wallet_ids))
- rows = await db.fetchall(
- f"SELECT * FROM diagonalley.zones WHERE wallet IN ({q})", (*wallet_ids,)
- )
+async def get_diagonalley_zones(user: str) -> List[Zones]:
+ rows = await db.fetchall("SELECT * FROM diagonalley.zones WHERE user = ?", (user,))
return [Zones(**row) for row in rows]
@@ -217,7 +168,7 @@ async def create_diagonalley_stall(
data.publickey,
data.privatekey,
data.relays,
- data.shippingzones),
+ repr(data.shippingzones)),
)
stall = await get_diagonalley_stall(stall_id)
@@ -238,32 +189,6 @@ async def update_diagonalley_stall(stall_id: str, **kwargs) -> Optional[Stalls]:
async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
- roww = await db.fetchone(
- "SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
- )
-
- try:
- x = httpx.get(roww["stalladdress"] + "/" + roww["ratingkey"])
- if x.status_code == 200:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- True,
- stall_id,
- ),
- )
- else:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- False,
- stall_id,
- ),
- )
- except:
- print("An exception occurred")
-
- # with open_ext_db("diagonalley") as db:
row = await db.fetchone(
"SELECT * FROM diagonalley.stalls WHERE id = ?", (stall_id,)
)
@@ -271,35 +196,6 @@ async def get_diagonalley_stall(stall_id: str) -> Optional[Stalls]:
async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]:
- if isinstance(wallet_ids, str):
- wallet_ids = [wallet_ids]
-
- q = ",".join(["?"] * len(wallet_ids))
- rows = await db.fetchall(
- f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
- )
-
- for r in rows:
- try:
- x = httpx.get(r["stalladdress"] + "/" + r["ratingkey"])
- if x.status_code == 200:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- True,
- r["id"],
- ),
- )
- else:
- await db.execute(
- "UPDATE diagonalley.stalls SET online = ? WHERE id = ?",
- (
- False,
- r["id"],
- ),
- )
- except:
- print("An exception occurred")
q = ",".join(["?"] * len(wallet_ids))
rows = await db.fetchall(
f"SELECT * FROM diagonalley.stalls WHERE wallet IN ({q})", (*wallet_ids,)
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index 1523f398..29a84419 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -28,7 +28,8 @@ async def m001_initial(db):
name TEXT NOT NULL,
publickey TEXT NOT NULL,
privatekey TEXT NOT NULL,
- relays TEXT NOT NULL
+ relays TEXT NOT NULL,
+ shippingzones TEXT NOT NULL
);
"""
)
@@ -40,7 +41,7 @@ async def m001_initial(db):
"""
CREATE TABLE diagonalley.zones (
id TEXT PRIMARY KEY,
- wallet TEXT NOT NULL,
+ user TEXT NOT NULL,
cost TEXT NOT NULL,
countries TEXT NOT NULL
);
@@ -55,7 +56,8 @@ async def m001_initial(db):
CREATE TABLE diagonalley.orders (
id TEXT PRIMARY KEY,
productid TEXT NOT NULL,
- wallet TEXT NOT NULL,
+ usr TEXT NOT NULL,
+ pubkey TEXT NOT NULL,
product TEXT NOT NULL,
quantity INTEGER NOT NULL,
shippingzone INTEGER NOT NULL,
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 1a975e10..743c2068 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -49,13 +49,13 @@ class Products(BaseModel):
quantity: int
class createZones(BaseModel):
- cost: str = Query(None)
+ cost: int = Query(0, ge=0)
countries: str = Query(None)
class Zones(BaseModel):
id: str
- wallet: str
- cost: str
+ user: str
+ cost: int
countries: str
@@ -73,6 +73,7 @@ class Orders(BaseModel):
id: str
productid: str
stall: str
+ pubkey: str
product: str
quantity: int
shippingzone: int
diff --git a/lnbits/extensions/diagonalley/static/js/index.js b/lnbits/extensions/diagonalley/static/js/index.js
deleted file mode 100644
index d101bfcf..00000000
--- a/lnbits/extensions/diagonalley/static/js/index.js
+++ /dev/null
@@ -1,853 +0,0 @@
-/* globals Quasar, Vue, _, VueQrcode, windowMixin, LNbits, LOCALE */
-
-Vue.component(VueQrcode.name, VueQrcode)
-
-//const pica = window.pica()
-
-var mapStalls = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-var mapProducts = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-var mapZone = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-var mapOrders = obj => {
- obj._data = _.clone(obj)
- return obj
-}
-
-new Vue({
- el: '#vue',
- mixins: [windowMixin],
- data: function () {
- return {
- products: [],
- orders: [],
- stalls: [],
- zones: [],
- customerKeys: [],
- customerKey: '',
- customerMessages: {},
- shippedModel: false,
- shippingZoneOptions: [
- 'Australia',
- 'Austria',
- 'Belgium',
- 'Brazil',
- 'Canada',
- 'Denmark',
- 'Finland',
- 'France*',
- 'Germany',
- 'Greece',
- 'Hong Kong',
- 'Hungary',
- 'Ireland',
- 'Indonesia',
- 'Israel',
- 'Italy',
- 'Japan',
- 'Kazakhstan',
- 'Korea',
- 'Luxembourg',
- 'Malaysia',
- 'Mexico',
- 'Netherlands',
- 'New Zealand',
- 'Norway',
- 'Poland',
- 'Portugal',
- 'Russia',
- 'Saudi Arabia',
- 'Singapore',
- 'Spain',
- 'Sweden',
- 'Switzerland',
- 'Thailand',
- 'Turkey',
- 'Ukraine',
- 'United Kingdom**',
- 'United States***',
- 'Vietnam',
- 'China'
- ],
- categories: [
- 'Fashion (clothing and accessories)',
- 'Health (and beauty)',
- 'Toys (and baby equipment)',
- 'Media (Books and CDs)',
- 'Groceries (Food and Drink)',
- 'Technology (Phones and Computers)',
- 'Home (furniture and accessories)',
- 'Gifts (flowers, cards, etc)',
- 'Adult'
- ],
- relayOptions: [
- 'wss://nostr-relay.herokuapp.com/ws',
- 'wss://nostr-relay.bigsun.xyz/ws',
- 'wss://freedom-relay.herokuapp.com/ws'
- ],
- label: '',
- ordersTable: {
- columns: [
- {
- name: 'product',
- align: 'left',
- label: 'Product',
- field: 'product'
- },
- {
- name: 'quantity',
- align: 'left',
- label: 'Quantity',
- field: 'quantity'
- },
- {
- name: 'address',
- align: 'left',
- label: 'Address',
- field: 'address'
- },
- {
- name: 'invoiceid',
- align: 'left',
- label: 'InvoiceID',
- field: 'invoiceid'
- },
- {name: 'paid', align: 'left', label: 'Paid', field: 'paid'},
- {name: 'shipped', align: 'left', label: 'Shipped', field: 'shipped'}
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- productsTable: {
- columns: [
- {
- name: 'stall',
- align: 'left',
- label: 'Stall',
- field: 'stall'
- },
- {
- name: 'product',
- align: 'left',
- label: 'Product',
- field: 'product'
- },
- {
- name: 'description',
- align: 'left',
- label: 'Description',
- field: 'description'
- },
- {
- name: 'categories',
- align: 'left',
- label: 'Categories',
- field: 'categories'
- },
- {name: 'price', align: 'left', label: 'Price', field: 'price'},
- {
- name: 'quantity',
- align: 'left',
- label: 'Quantity',
- field: 'quantity'
- },
- {name: 'id', align: 'left', label: 'ID', field: 'id'}
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- stallTable: {
- columns: [
- {
- name: 'id',
- align: 'left',
- label: 'ID',
- field: 'id'
- },
- {
- name: 'name',
- align: 'left',
- label: 'Name',
- field: 'name'
- },
- {
- name: 'wallet',
- align: 'left',
- label: 'Wallet',
- field: 'wallet'
- },
- {
- name: 'publickey',
- align: 'left',
- label: 'Public key',
- field: 'publickey'
- },
- {
- name: 'privatekey',
- align: 'left',
- label: 'Private key',
- field: 'privatekey'
- }
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- zonesTable: {
- columns: [
- {
- name: 'id',
- align: 'left',
- label: 'ID',
- field: 'id'
- },
- {
- name: 'countries',
- align: 'left',
- label: 'Countries',
- field: 'countries'
- },
- {
- name: 'cost',
- align: 'left',
- label: 'Cost',
- field: 'cost'
- }
- ],
- pagination: {
- rowsPerPage: 10
- }
- },
- productDialog: {
- show: false,
- data: {}
- },
- stallDialog: {
- show: false,
- data: {}
- },
- zoneDialog: {
- show: false,
- data: {}
- },
- shopDialog: {
- show: false,
- data: {activate: false}
- },
- orderDialog: {
- show: false,
- data: {}
- },
- relayDialog: {
- show: false,
- data: {}
- }
- }
- },
- computed: {
- categoryOther: function () {
- cats = trim(this.productDialog.data.categories.split(','))
- for (let i = 0; i < cats.length; i++) {
- if (cats[i] == 'Others') {
- return true
- }
- }
- return false
- }
- },
- methods: {
- errorMessage: function (error) {
- this.$q.notify({
- color: 'primary',
- message: error
- })
- },
- ////////////////////////////////////////
- ///////////SUPPORT MESSAGES/////////////
- ////////////////////////////////////////
- getMessages: function (customerKey) {
- var self = this
- console.log('fuck')
- messages = []
- messages.push(['in', 'blah blah'])
- messages.push(['out', 'blah blah'])
- self.customerMessages = messages
- },
- ////////////////////////////////////////
- ////////////////STALLS//////////////////
- ////////////////////////////////////////
- getStalls: function () {
- var self = this
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/stalls?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.stalls.push(mapStalls(response.data))
- })
- },
- openStallUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.stalls, {id: linkId})
-
- this.stallDialog.data = _.clone(link._data)
- this.stallDialog.show = true
- },
- sendStallFormData: function () {
- if (this.stallDialog.data.id) {
- } else {
- var data = {
- name: this.stallDialog.data.name,
- wallet: this.stallDialog.data.wallet,
- publickey: this.stallDialog.data.publickey,
- privatekey: this.stallDialog.data.privatekey,
- relays: this.stallDialog.data.relays
- }
- }
-
- if (this.stallDialog.data.id) {
- this.updateStall(this.stallDialog.data)
- } else {
- this.createStall(data)
- }
- },
- updateStall: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/stalls' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.stallDialog.data.wallet
- }).inkey,
- _.pick(data, 'name', 'wallet', 'publickey', 'privatekey')
- )
- .then(function (response) {
- self.stalls = _.reject(self.stalls, function (obj) {
- return obj.id == data.id
- })
- self.stalls.push(mapStalls(response.data))
- self.stallDialog.show = false
- self.stallDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createStall: function (data) {
- var self = this
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/stalls',
- _.findWhere(self.g.user.wallets, {
- id: self.stallDialog.data.wallet
- }).inkey,
- data
- )
- .then(function (response) {
- self.stalls.push(mapStalls(response.data))
- self.stallDialog.show = false
- self.stallDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteStall: function (stallId) {
- var self = this
- var stall = _.findWhere(self.stalls, {id: stallId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this Stall link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/stalls/' + stallId,
- _.findWhere(self.g.user.wallets, {id: stall.wallet}).inkey
- )
- .then(function (response) {
- self.stalls = _.reject(self.stalls, function (obj) {
- return obj.id == stallId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportStallsCSV: function () {
- LNbits.utils.exportCSV(this.stallsTable.columns, this.stalls)
- },
- ////////////////////////////////////////
- ///////////////PRODUCTS/////////////////
- ////////////////////////////////////////
- getProducts: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/products?all_stalls',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.products.push(mapProducts(response.data))
- })
- },
- openProductUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.products, {id: linkId})
-
- self.productDialog.data = _.clone(link._data)
- self.productDialog.show = true
- },
- sendProductFormData: function () {
- if (this.productDialog.data.id) {
- } else {
- var data = {
- product: this.productDialog.data.product,
- categories:
- this.productDialog.data.categories +
- this.productDialog.categoriesextra,
- description: this.productDialog.data.description,
- image: this.productDialog.data.image,
- price: this.productDialog.data.price,
- quantity: this.productDialog.data.quantity
- }
- }
- if (this.productDialog.data.id) {
- this.updateProduct(this.productDialog.data)
- } else {
- this.createProduct(data)
- }
- },
- imageAdded(file) {
- let blobURL = URL.createObjectURL(file)
- let image = new Image()
- image.src = blobURL
- image.onload = async () => {
- let canvas = document.createElement('canvas')
- canvas.setAttribute('width', 100)
- canvas.setAttribute('height', 100)
- await pica.resize(image, canvas, {
- quality: 0,
- alpha: true,
- unsharpAmount: 95,
- unsharpRadius: 0.9,
- unsharpThreshold: 70
- })
- this.productDialog.data.image = canvas.toDataURL()
- this.productDialog = {...this.productDialog}
- }
- },
- imageCleared() {
- this.productDialog.data.image = null
- this.productDialog = {...this.productDialog}
- },
- updateProduct: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/products' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.productDialog.data.wallet
- }).inkey,
- _.pick(
- data,
- 'shopname',
- 'relayaddress',
- 'shippingzone1',
- 'zone1cost',
- 'shippingzone2',
- 'zone2cost',
- 'email'
- )
- )
- .then(function (response) {
- self.products = _.reject(self.products, function (obj) {
- return obj.id == data.id
- })
- self.products.push(mapProducts(response.data))
- self.productDialog.show = false
- self.productDialog.data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createProduct: function (data) {
- var self = this
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/products',
- _.findWhere(self.g.user.wallets, {
- id: self.productDialog.data.wallet
- }).inkey,
- data
- )
- .then(function (response) {
- self.products.push(mapProducts(response.data))
- self.productDialog.show = false
- self.productDialog.data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteProduct: function (productId) {
- var self = this
- var product = _.findWhere(this.products, {id: productId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this products link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/products/' + productId,
- _.findWhere(self.g.user.wallets, {id: product.wallet}).inkey
- )
- .then(function (response) {
- self.products = _.reject(self.products, function (obj) {
- return obj.id == productId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportProductsCSV: function () {
- LNbits.utils.exportCSV(this.productsTable.columns, this.products)
- },
- ////////////////////////////////////////
- //////////////////ZONE//////////////////
- ////////////////////////////////////////
- getZones: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/zones?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.zones.push(mapZone(response.data))
- })
- },
- openZoneUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.zones, {id: linkId})
-
- this.zoneDialog.data = _.clone(link._data)
- this.zoneDialog.show = true
- },
- sendZoneFormData: function () {
- if (this.zoneDialog.data.id) {
- } else {
- var data = {
- countries: toString(this.zoneDialog.data.countries),
- cost: parseInt(this.zoneDialog.data.cost)
- }
- }
-
- if (this.zoneDialog.data.id) {
- this.updateZone(this.zoneDialog.data)
- } else {
- this.createZone(data)
- }
- },
- updateZone: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/zones' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.zoneDialog.data.wallet
- }).inkey,
- _.pick(data, 'countries', 'cost')
- )
- .then(function (response) {
- self.zones = _.reject(self.zones, function (obj) {
- return obj.id == data.id
- })
- self.zones.push(mapZone(response.data))
- self.zoneDialog.show = false
- self.zoneDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createZone: function (data) {
- var self = this
- console.log(self.g.user.wallets[0])
- console.log(data)
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/zones',
- self.g.user.wallets[0].inkey,
- data
- )
- .then(function (response) {
- self.zones.push(mapZone(response.data))
- self.zoneDialog.show = false
- self.zoneDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteZone: function (zoneId) {
- var self = this
- var zone = _.findWhere(self.zones, {id: zoneId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this Zone link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/zones/' + zoneId,
- _.findWhere(self.g.user.wallets, {id: zone.wallet}).inkey
- )
- .then(function (response) {
- self.zones = _.reject(self.zones, function (obj) {
- return obj.id == zoneId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportZonesCSV: function () {
- LNbits.utils.exportCSV(this.zonesTable.columns, this.zones)
- },
- ////////////////////////////////////////
- //////////////////SHOP//////////////////
- ////////////////////////////////////////
- getShops: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/shops?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.shops.push(mapShops(response.data))
- })
- },
- openShopUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.shops, {id: linkId})
-
- this.shopDialog.data = _.clone(link._data)
- this.shopDialog.show = true
- },
- sendShopFormData: function () {
- if (this.shopDialog.data.id) {
- } else {
- var data = {
- countries: this.shopDialog.data.countries,
- cost: this.shopDialog.data.cost
- }
- }
-
- if (this.shopDialog.data.id) {
- this.updateZone(this.shopDialog.data)
- } else {
- this.createZone(data)
- }
- },
- updateShop: function (data) {
- var self = this
- LNbits.api
- .request(
- 'PUT',
- '/diagonalley/api/v1/shops' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.shopDialog.data.wallet
- }).inkey,
- _.pick(data, 'countries', 'cost')
- )
- .then(function (response) {
- self.shops = _.reject(self.shops, function (obj) {
- return obj.id == data.id
- })
- self.shops.push(mapShops(response.data))
- self.shopDialog.show = false
- self.shopDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- createShop: function (data) {
- var self = this
- console.log('cuntywoo')
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/shops',
- _.findWhere(self.g.user.wallets, {
- id: self.shopDialog.data.wallet
- }).inkey,
- data
- )
- .then(function (response) {
- self.shops.push(mapShops(response.data))
- self.shopDialog.show = false
- self.shopDialog.data = {}
- data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteShop: function (shopId) {
- var self = this
- var shop = _.findWhere(self.shops, {id: shopId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this Shop link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/shops/' + shopId,
- _.findWhere(self.g.user.wallets, {id: shop.wallet}).inkey
- )
- .then(function (response) {
- self.shops = _.reject(self.shops, function (obj) {
- return obj.id == shopId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- exportShopsCSV: function () {
- LNbits.utils.exportCSV(this.shopsTable.columns, this.shops)
- },
- ////////////////////////////////////////
- ////////////////ORDERS//////////////////
- ////////////////////////////////////////
- getOrders: function () {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/orders?all_wallets',
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
- })
- },
- createOrder: function () {
- var data = {
- address: this.orderDialog.data.address,
- email: this.orderDialog.data.email,
- quantity: this.orderDialog.data.quantity,
- shippingzone: this.orderDialog.data.shippingzone
- }
- var self = this
-
- LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/orders',
- _.findWhere(self.g.user.wallets, {id: self.orderDialog.data.wallet})
- .inkey,
- data
- )
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
- self.orderDialog.show = false
- self.orderDialog.data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },
- deleteOrder: function (orderId) {
- var self = this
- var order = _.findWhere(self.orders, {id: orderId})
-
- LNbits.utils
- .confirmDialog('Are you sure you want to delete this order link?')
- .onOk(function () {
- LNbits.api
- .request(
- 'DELETE',
- '/diagonalley/api/v1/orders/' + orderId,
- _.findWhere(self.g.user.wallets, {id: order.wallet}).inkey
- )
- .then(function (response) {
- self.orders = _.reject(self.orders, function (obj) {
- return obj.id == orderId
- })
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- })
- },
- shipOrder: function (order_id) {
- var self = this
-
- LNbits.api
- .request(
- 'GET',
- '/diagonalley/api/v1/orders/shipped/' + order_id,
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
- })
- },
- exportOrdersCSV: function () {
- LNbits.utils.exportCSV(this.ordersTable.columns, this.orders)
- }
- },
- created: function () {
- if (this.g.user.wallets.length) {
- this.getStalls()
- this.getProducts()
- this.getZones()
- this.getOrders()
- this.customerKeys = [
- 'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
- 'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
- ]
- }
- }
-})
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index d14d7cee..7b8f8e6a 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -300,8 +300,9 @@
- + Product List a product + Product List a produc
+ Product List a product + Shipping Zone Create a shipping zone
- + Stall
Create a stall to list products on
@@ -321,6 +322,7 @@
>Launch frontend shop (not Nostr)
Makes a simple frontend shop for your stalls
+
@@ -638,7 +640,890 @@
+
{% endblock %} {% block scripts %} {{ window_vars(user) }}
-
-
+
+
{% endblock %}
+
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 43232841..6363dc97 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -121,36 +121,32 @@ async def api_diagonalley_products_delete(product_id, wallet: WalletTypeInfo = D
@diagonalley_ext.get("/api/v1/zones")
-async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
- wallet_ids = [wallet.wallet.id]
+async def api_diagonalley_zones(wallet: WalletTypeInfo = Depends(get_key_type)):
- if all_wallets:
- wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
-
- return ([zone.dict() for zone in await get_diagonalley_zones(wallet_ids)])
+ return await get_diagonalley_zones(wallet.wallet.user)
@diagonalley_ext.post("/api/v1/zones")
-@diagonalley_ext.put("/api/v1/zones/{zone_id}")
async def api_diagonalley_zone_create(
data: createZones,
- zone_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type)
):
- if zone_id:
- zone = await get_diagonalley_zone(zone_id)
-
- if not zone:
- return ({"message": "Zone does not exist."})
-
- if zone.wallet != wallet.wallet.id:
- return ({"message": "Not your record."})
-
- zone = await update_diagonalley_zone(zone_id, **data.dict())
- else:
- zone = await create_diagonalley_zone(wallet=wallet.wallet.id, data=data)
-
+ zone = await create_diagonalley_zone(user=wallet.wallet.user, data=data)
return zone.dict()
+@diagonalley_ext.post("/api/v1/zones/{zone_id}")
+async def api_diagonalley_zone_update(
+ data: createZones,
+ zone_id: str = Query(None),
+ wallet: WalletTypeInfo = Depends(require_admin_key)
+ ):
+ zone = await get_diagonalley_zone(zone_id)
+ if not zone:
+ return ({"message": "Zone does not exist."})
+ if zone.user != wallet.wallet.user:
+ return ({"message": "Not your record."})
+ zone = await update_diagonalley_zone(zone_id, **data.dict())
+ return zone
+
@diagonalley_ext.delete("/api/v1/zones/{zone_id}")
async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
@@ -159,7 +155,7 @@ async def api_diagonalley_zone_delete(zone_id, wallet: WalletTypeInfo = Depends(
if not zone:
return ({"message": "zone does not exist."})
- if zone.wallet != wallet.wallet.id:
+ if zone.user != wallet.wallet.user:
return ({"message": "Not your zone."})
await delete_diagonalley_zone(zone_id)
From 671ac08a046052615fa0366578d9e3365f9de5f1 Mon Sep 17 00:00:00 2001
From: benarc
Date: Sun, 6 Feb 2022 22:40:51 +0000
Subject: [PATCH 040/226] small fix
---
.../templates/diagonalley/index.html | 25 +++++++++++++------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 7b8f8e6a..6d6ea872 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -244,7 +244,7 @@
label="Private Key"
>
@@ -270,7 +270,7 @@
filled
dense
v-model.trim="stallDialog.data.nostrShops"
- label="Stall public keys (seperate by comma)"
+ label="Nostr shop public keys (seperate by comma)"
>
- + Product List a produc 1" color="primary" @click="productDialog.show = true"
+ >+ Product List a product
+ Product List a product + Shipping Zone
Create a shipping zone
-
+ Stall
Create a stall to list products on
@@ -675,6 +675,7 @@ new Vue({
orders: [],
stalls: [],
zones: [],
+ zoneOptions: [],
customerKeys: [],
customerKey: '',
customerMessages: {},
@@ -949,10 +950,19 @@ new Vue({
LNbits.utils.notifyApiError(error)
})
},
+ openStallDialog: function () {
+ console.log(this.zones[0]['id'])
+ for(let i = 0; i < this.zones.length; i ++){
+ this.zoneOptions.push(this.zones[i]['id'])
+ }
+ this.stallDialog.show = true
+ },
openStallUpdateDialog: function (linkId) {
var self = this
var link = _.findWhere(self.stalls, {id: linkId})
-
+ for(let i = 0; i < this.zones.length; i ++){
+ this.zoneOptions.push(this.stalls[i][0])
+ }
this.stallDialog.data = _.clone(link._data)
this.stallDialog.show = true
},
@@ -1210,6 +1220,7 @@ new Vue({
if (response.data) {
console.log(response)
self.zones = response.data.map(mapZone)
+
}
})
.catch(function (error) {
From 61cf79de691221ed631c58f77c25c76f522e9c85 Mon Sep 17 00:00:00 2001
From: benarc
Date: Mon, 7 Feb 2022 13:22:43 +0000
Subject: [PATCH 041/226] Added nostr ext
---
lnbits/extensions/nostr/README.md | 3 +
lnbits/extensions/nostr/__init__.py | 17 +
lnbits/extensions/nostr/config.json | 6 +
lnbits/extensions/nostr/crud.py | 134 +++++
lnbits/extensions/nostr/migrations.py | 47 ++
lnbits/extensions/nostr/models.py | 34 ++
.../templates/lnurldevice/_api_docs.html | 169 ++++++
.../nostr/templates/lnurldevice/error.html | 34 ++
.../nostr/templates/lnurldevice/index.html | 534 ++++++++++++++++++
.../nostr/templates/lnurldevice/paid.html | 27 +
lnbits/extensions/nostr/views.py | 24 +
lnbits/extensions/nostr/views_api.py | 48 ++
12 files changed, 1077 insertions(+)
create mode 100644 lnbits/extensions/nostr/README.md
create mode 100644 lnbits/extensions/nostr/__init__.py
create mode 100644 lnbits/extensions/nostr/config.json
create mode 100644 lnbits/extensions/nostr/crud.py
create mode 100644 lnbits/extensions/nostr/migrations.py
create mode 100644 lnbits/extensions/nostr/models.py
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/error.html
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/index.html
create mode 100644 lnbits/extensions/nostr/templates/lnurldevice/paid.html
create mode 100644 lnbits/extensions/nostr/views.py
create mode 100644 lnbits/extensions/nostr/views_api.py
diff --git a/lnbits/extensions/nostr/README.md b/lnbits/extensions/nostr/README.md
new file mode 100644
index 00000000..596cce9d
--- /dev/null
+++ b/lnbits/extensions/nostr/README.md
@@ -0,0 +1,3 @@
+# Nostr
+
+Opens a Nostr daemon
diff --git a/lnbits/extensions/nostr/__init__.py b/lnbits/extensions/nostr/__init__.py
new file mode 100644
index 00000000..775960e3
--- /dev/null
+++ b/lnbits/extensions/nostr/__init__.py
@@ -0,0 +1,17 @@
+from fastapi import APIRouter
+
+from lnbits.db import Database
+from lnbits.helpers import template_renderer
+
+db = Database("ext_nostr")
+
+nostr_ext: APIRouter = APIRouter(prefix="/nostr", tags=["nostr"])
+
+
+def nostr_renderer():
+ return template_renderer(["lnbits/extensions/nostr/templates"])
+
+
+from .lnurl import * # noqa
+from .views import * # noqa
+from .views_api import * # noqa
diff --git a/lnbits/extensions/nostr/config.json b/lnbits/extensions/nostr/config.json
new file mode 100644
index 00000000..a32e39a1
--- /dev/null
+++ b/lnbits/extensions/nostr/config.json
@@ -0,0 +1,6 @@
+{
+ "name": "Nostr",
+ "short_description": "Daemon for Nostr",
+ "icon": "swap_horizontal_circle",
+ "contributors": ["arcbtc"]
+}
diff --git a/lnbits/extensions/nostr/crud.py b/lnbits/extensions/nostr/crud.py
new file mode 100644
index 00000000..55e99ec6
--- /dev/null
+++ b/lnbits/extensions/nostr/crud.py
@@ -0,0 +1,134 @@
+from typing import List, Optional, Union
+
+from lnbits.helpers import urlsafe_short_hash
+
+from . import db
+from .models import nostrKeys, nostrNotes, nostrRelays, nostrConnections
+
+###############KEYS##################
+
+async def create_nostrkeys(
+ data: nostrKeys
+) -> nostrKeys:
+ nostrkey_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO nostr.keys (
+ id,
+ pubkey,
+ privkey
+ )
+ VALUES (?, ?, ?)
+ """,
+ (nostrkey_id, data.pubkey, data.privkey),
+ )
+ return await get_nostrkeys(nostrkey_id)
+
+async def get_nostrkeys(nostrkey_id: str) -> nostrKeys:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.keys WHERE id = ?",
+ (lnurldevicepayment_id,),
+ )
+ return nostrKeys(**row) if row else None
+
+
+###############NOTES##################
+
+async def create_nostrnotes(
+ data: nostrNotes
+) -> nostrNotes:
+ await db.execute(
+ """
+ INSERT INTO nostr.notes (
+ id,
+ pubkey,
+ created_at,
+ kind,
+ tags,
+ content,
+ sig
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ """,
+ (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
+ )
+ return await get_nostrnotes(data.id)
+
+async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.notes WHERE id = ?",
+ (nostrnote_id,),
+ )
+ return nostrNotes(**row) if row else None
+
+###############RELAYS##################
+
+async def create_nostrrelays(
+ relay: str
+) -> nostrRelays:
+ nostrrelay_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO nostr.relays (
+ id,
+ relay
+ )
+ VALUES (?, ?)
+ """,
+ (nostrrelay_id, relay),
+ )
+ return await get_nostrnotes(nostrrelay_id)
+
+async def get_nostrrelays(nostrrelay_id: str) -> nostrRelays:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.relays WHERE id = ?",
+ (nostrnote_id,),
+ )
+ return nostrRelays(**row) if row else None
+
+
+###############CONNECTIONS##################
+
+async def create_nostrconnections(
+ data: nostrNotes
+) -> nostrNotes:
+ nostrkey_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO nostr.notes (
+ id,
+ pubkey,
+ created_at,
+ kind,
+ tags,
+ content,
+ sig
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ """,
+ (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
+ )
+ return await get_nostrnotes(data.id)
+
+async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+ row = await db.fetchone(
+ "SELECT * FROM nostr.notes WHERE id = ?",
+ (nostrnote_id,),
+ )
+ return nostrNotes(**row) if row else None
+
+
+
+async def update_lnurldevicepayment(
+ lnurldevicepayment_id: str, **kwargs
+) -> Optional[lnurldevicepayment]:
+ q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
+ await db.execute(
+ f"UPDATE lnurldevice.lnurldevicepayment SET {q} WHERE id = ?",
+ (*kwargs.values(), lnurldevicepayment_id),
+ )
+ row = await db.fetchone(
+ "SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?",
+ (lnurldevicepayment_id,),
+ )
+ return lnurldevicepayment(**row) if row else None
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/migrations.py b/lnbits/extensions/nostr/migrations.py
new file mode 100644
index 00000000..de32a578
--- /dev/null
+++ b/lnbits/extensions/nostr/migrations.py
@@ -0,0 +1,47 @@
+from lnbits.db import Database
+
+db2 = Database("ext_nostr")
+
+
+async def m001_initial(db):
+ """
+ Initial nostr table.
+ """
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.keys (
+ pubkey TEXT NOT NULL PRIMARY KEY,
+ privkey TEXT NOT NULL
+ );
+ """
+ )
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.notes (
+ id TEXT NOT NULL PRIMARY KEY,
+ pubkey TEXT NOT NULL,
+ created_at TEXT NOT NULL,
+ kind INT NOT NULL,
+ tags TEXT NOT NULL,
+ content TEXT NOT NULL,
+ sig TEXT NOT NULL,
+ );
+ """
+ )
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.relays (
+ id TEXT NOT NULL PRIMARY KEY,
+ relay TEXT NOT NULL
+ );
+ """
+ )
+ await db.execute(
+ f"""
+ CREATE TABLE nostr.connections (
+ id TEXT NOT NULL PRIMARY KEY,
+ publickey TEXT NOT NULL,
+ relayid TEXT NOT NULL
+ );
+ """
+ )
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/models.py b/lnbits/extensions/nostr/models.py
new file mode 100644
index 00000000..ba0c87a5
--- /dev/null
+++ b/lnbits/extensions/nostr/models.py
@@ -0,0 +1,34 @@
+import json
+from sqlite3 import Row
+from typing import Optional
+
+from fastapi import Request
+from lnurl import Lnurl
+from lnurl import encode as lnurl_encode # type: ignore
+from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
+from lnurl.types import LnurlPayMetadata # type: ignore
+from pydantic import BaseModel
+from pydantic.main import BaseModel
+
+class nostrKeys(BaseModel):
+ id: str
+ pubkey: str
+ privkey: str
+
+class nostrNotes(BaseModel):
+ id: str
+ pubkey: str
+ created_at: str
+ kind: int
+ tags: str
+ content: str
+ sig: str
+
+class nostrRelays(BaseModel):
+ id: str
+ relay: str
+
+class nostrConnections(BaseModel):
+ id: str
+ pubkey: str
+ relayid: str
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html b/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
new file mode 100644
index 00000000..af69b76e
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
@@ -0,0 +1,169 @@
+
+
+
+ Register LNURLDevice devices to receive payments in your LNbits wallet.
+ Build your own here
+ https://github.com/arcbtc/bitcoinpos
+
+ Created by, Ben Arc
+
+
+
+
+
+
+ /lnurldevice/api/v1/lnurlpos
+ Headers
+ {"X-Api-Key": <admin_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X POST {{ request.base_url }}api/v1/lnurldevice -d '{"title":
+ <string>, "message":<string>, "currency":
+ <integer>}' -H "Content-type: application/json" -H "X-Api-Key:
+ {{user.wallets[0].adminkey }}"
+
+
+
+
+
+
+
+ PUT
+ /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
+ Headers
+ {"X-Api-Key": <admin_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X POST {{ request.base_url
+ }}api/v1/lnurlpos/<lnurldevice_id> -d ''{"title":
+ <string>, "message":<string>, "currency":
+ <integer>} -H "Content-type: application/json" -H "X-Api-Key:
+ {{user.wallets[0].adminkey }}"
+
+
+
+
+
+
+
+
+ GET
+ /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
+ Headers
+ {"X-Api-Key": <invoice_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X GET {{ request.base_url
+ }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
+ user.wallets[0].inkey }}"
+
+
+
+
+
+
+
+ GET
+ /lnurldevice/api/v1/lnurlposs
+ Headers
+ {"X-Api-Key": <invoice_key>}
+
+ Body (application/json)
+
+
+ Returns 200 OK (application/json)
+
+ [<lnurldevice_object>, ...]
+ Curl example
+ curl -X GET {{ request.base_url }}api/v1/lnurldevices -H
+ "X-Api-Key: {{ user.wallets[0].inkey }}"
+
+
+
+
+
+
+
+ DELETE
+ /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
+ Headers
+ {"X-Api-Key": <admin_key>}
+ Returns 204 NO CONTENT
+
+ Curl example
+ curl -X DELETE {{ request.base_url
+ }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
+ user.wallets[0].adminkey }}"
+
+
+
+
+
+
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/error.html b/lnbits/extensions/nostr/templates/lnurldevice/error.html
new file mode 100644
index 00000000..d8e41832
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/error.html
@@ -0,0 +1,34 @@
+{% extends "public.html" %} {% block page %}
+
+
+
+
+
+ LNURL-pay not paid
+
+
+
+
+
+
+
+
+
+ {% endblock %} {% block scripts %}
+
+
+
+ {% endblock %}
+
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/index.html b/lnbits/extensions/nostr/templates/lnurldevice/index.html
new file mode 100644
index 00000000..b51e2556
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/index.html
@@ -0,0 +1,534 @@
+{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
+%} {% block page %}
+
+
+
+
+ {% raw %}
+ New LNURLDevice instance
+
+
+
+
+
+
+
+
+
lNURLdevice
+
+
+
+
+
+
+
+
+ Export to CSV
+
+
+
+
+
+
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+
+ Delete LNURLDevice
+
+
+
+
+ LNURLDevice Settings
+
+
+
+
+ {{ col.value }}
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
+ {{SITE_TITLE}} LNURLDevice Extension
+
+
+
+
+ {% include "lnurldevice/_api_docs.html" %}
+
+
+
+
+
+
+ LNURLDevice device string
+ {% raw
+ %}{{location}}/lnurldevice/api/v1/lnurl/{{settingsDialog.data.id}},
+ {{settingsDialog.data.key}}, {{settingsDialog.data.currency}}{% endraw
+ %} Click to copy URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Update lnurldevice
+ Create lnurldevice
+ Cancel
+
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }}
+
+
+{% endblock %}
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/paid.html b/lnbits/extensions/nostr/templates/lnurldevice/paid.html
new file mode 100644
index 00000000..c185ecce
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/lnurldevice/paid.html
@@ -0,0 +1,27 @@
+{% extends "public.html" %} {% block page %}
+
+
+
+
+
+ {{ pin }}
+
+
+
+
+
+
+ {% endblock %} {% block scripts %}
+
+
+
+ {% endblock %}
+
diff --git a/lnbits/extensions/nostr/views.py b/lnbits/extensions/nostr/views.py
new file mode 100644
index 00000000..1dfc07da
--- /dev/null
+++ b/lnbits/extensions/nostr/views.py
@@ -0,0 +1,24 @@
+from http import HTTPStatus
+
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from fastapi.templating import Jinja2Templates
+from starlette.exceptions import HTTPException
+from starlette.responses import HTMLResponse
+
+from lnbits.core.crud import update_payment_status
+from lnbits.core.models import User
+from lnbits.core.views.api import api_payment
+from lnbits.decorators import check_user_exists
+
+from . import nostr_ext, nostr_renderer
+
+templates = Jinja2Templates(directory="templates")
+
+
+@nostr_ext.get("/", response_class=HTMLResponse)
+async def index(request: Request, user: User = Depends(check_user_exists)):
+ return nostr_renderer().TemplateResponse(
+ "nostr/index.html", {"request": request, "user": user.dict()}
+ )
diff --git a/lnbits/extensions/nostr/views_api.py b/lnbits/extensions/nostr/views_api.py
new file mode 100644
index 00000000..a479cad8
--- /dev/null
+++ b/lnbits/extensions/nostr/views_api.py
@@ -0,0 +1,48 @@
+from http import HTTPStatus
+
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from starlette.exceptions import HTTPException
+
+from lnbits.core.crud import get_user
+from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
+from lnbits.extensions.lnurldevice import lnurldevice_ext
+from lnbits.utils.exchange_rates import currencies
+
+from . import lnurldevice_ext
+from .crud import (
+ create_lnurldevice,
+ delete_lnurldevice,
+ get_lnurldevice,
+ get_lnurldevices,
+ update_lnurldevice,
+)
+from .models import createLnurldevice
+
+
+@nostr_ext.get("/api/v1/lnurlpos")
+async def api_check_daemon(wallet: WalletTypeInfo = Depends(get_key_type)):
+ wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
+ try:
+ return [
+ {**lnurldevice.dict()} for lnurldevice in await get_lnurldevices(wallet_ids)
+ ]
+ except:
+ return ""
+
+@nostr_ext.delete("/api/v1/lnurlpos/{lnurldevice_id}")
+async def api_lnurldevice_delete(
+ wallet: WalletTypeInfo = Depends(require_admin_key),
+ lnurldevice_id: str = Query(None),
+):
+ lnurldevice = await get_lnurldevice(lnurldevice_id)
+
+ if not lnurldevice:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Wallet link does not exist."
+ )
+
+ await delete_lnurldevice(lnurldevice_id)
+
+ return "", HTTPStatus.NO_CONTENT
\ No newline at end of file
From d60d5c928cf7b7479c8232b06b9430ad21d189bf Mon Sep 17 00:00:00 2001
From: benarc
Date: Mon, 7 Feb 2022 20:01:01 +0000
Subject: [PATCH 042/226] extension loading
---
lnbits/extensions/nostr/__init__.py | 2 -
lnbits/extensions/nostr/crud.py | 71 +--
lnbits/extensions/nostr/migrations.py | 2 +-
lnbits/extensions/nostr/models.py | 12 +-
.../templates/lnurldevice/_api_docs.html | 169 ------
.../nostr/templates/lnurldevice/error.html | 34 --
.../nostr/templates/lnurldevice/index.html | 534 ------------------
.../nostr/templates/lnurldevice/paid.html | 27 -
.../nostr/templates/nostr/index.html | 159 ++++++
lnbits/extensions/nostr/views_api.py | 46 +-
10 files changed, 204 insertions(+), 852 deletions(-)
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/error.html
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/index.html
delete mode 100644 lnbits/extensions/nostr/templates/lnurldevice/paid.html
create mode 100644 lnbits/extensions/nostr/templates/nostr/index.html
diff --git a/lnbits/extensions/nostr/__init__.py b/lnbits/extensions/nostr/__init__.py
index 775960e3..9774a279 100644
--- a/lnbits/extensions/nostr/__init__.py
+++ b/lnbits/extensions/nostr/__init__.py
@@ -11,7 +11,5 @@ nostr_ext: APIRouter = APIRouter(prefix="/nostr", tags=["nostr"])
def nostr_renderer():
return template_renderer(["lnbits/extensions/nostr/templates"])
-
-from .lnurl import * # noqa
from .views import * # noqa
from .views_api import * # noqa
diff --git a/lnbits/extensions/nostr/crud.py b/lnbits/extensions/nostr/crud.py
index 55e99ec6..0b30bc9a 100644
--- a/lnbits/extensions/nostr/crud.py
+++ b/lnbits/extensions/nostr/crud.py
@@ -1,33 +1,31 @@
from typing import List, Optional, Union
from lnbits.helpers import urlsafe_short_hash
-
+import shortuuid
from . import db
-from .models import nostrKeys, nostrNotes, nostrRelays, nostrConnections
+from .models import nostrKeys, nostrNotes, nostrCreateRelays, nostrRelays, nostrConnections, nostrCreateConnections
###############KEYS##################
async def create_nostrkeys(
data: nostrKeys
) -> nostrKeys:
- nostrkey_id = urlsafe_short_hash()
await db.execute(
"""
INSERT INTO nostr.keys (
- id,
pubkey,
privkey
)
- VALUES (?, ?, ?)
+ VALUES (?, ?)
""",
- (nostrkey_id, data.pubkey, data.privkey),
+ (data.pubkey, data.privkey),
)
return await get_nostrkeys(nostrkey_id)
-async def get_nostrkeys(nostrkey_id: str) -> nostrKeys:
+async def get_nostrkeys(pubkey: str) -> nostrKeys:
row = await db.fetchone(
- "SELECT * FROM nostr.keys WHERE id = ?",
- (lnurldevicepayment_id,),
+ "SELECT * FROM nostr.keys WHERE pubkey = ?",
+ (pubkey,),
)
return nostrKeys(**row) if row else None
@@ -64,9 +62,12 @@ async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
###############RELAYS##################
async def create_nostrrelays(
- relay: str
-) -> nostrRelays:
- nostrrelay_id = urlsafe_short_hash()
+ data: nostrCreateRelays
+) -> nostrCreateRelays:
+ nostrrelay_id = shortuuid.uuid(name=relay)
+
+ if await get_nostrrelays(nostrrelay_id):
+ return "error"
await db.execute(
"""
INSERT INTO nostr.relays (
@@ -75,7 +76,7 @@ async def create_nostrrelays(
)
VALUES (?, ?)
""",
- (nostrrelay_id, relay),
+ (nostrrelay_id, data.relay),
)
return await get_nostrnotes(nostrrelay_id)
@@ -90,45 +91,25 @@ async def get_nostrrelays(nostrrelay_id: str) -> nostrRelays:
###############CONNECTIONS##################
async def create_nostrconnections(
- data: nostrNotes
-) -> nostrNotes:
- nostrkey_id = urlsafe_short_hash()
+ data: nostrCreateConnections
+) -> nostrCreateConnections:
+ nostrrelay_id = shortuuid.uuid(name=data.relayid + data.pubkey)
await db.execute(
"""
- INSERT INTO nostr.notes (
+ INSERT INTO nostr.connections (
id,
pubkey,
- created_at,
- kind,
- tags,
- content,
- sig
+ relayid
)
- VALUES (?, ?, ?, ?, ?, ?, ?)
+ VALUES (?, ?, ?)
""",
- (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
+ (data.id, data.pubkey, data.relayid),
)
- return await get_nostrnotes(data.id)
+ return await get_nostrconnections(data.id)
-async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+async def get_nostrconnections(nostrconnections_id: str) -> nostrConnections:
row = await db.fetchone(
- "SELECT * FROM nostr.notes WHERE id = ?",
- (nostrnote_id,),
+ "SELECT * FROM nostr.connections WHERE id = ?",
+ (nostrconnections_id,),
)
- return nostrNotes(**row) if row else None
-
-
-
-async def update_lnurldevicepayment(
- lnurldevicepayment_id: str, **kwargs
-) -> Optional[lnurldevicepayment]:
- q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
- await db.execute(
- f"UPDATE lnurldevice.lnurldevicepayment SET {q} WHERE id = ?",
- (*kwargs.values(), lnurldevicepayment_id),
- )
- row = await db.fetchone(
- "SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?",
- (lnurldevicepayment_id,),
- )
- return lnurldevicepayment(**row) if row else None
\ No newline at end of file
+ return nostrConnections(**row) if row else None
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/migrations.py b/lnbits/extensions/nostr/migrations.py
index de32a578..0c616110 100644
--- a/lnbits/extensions/nostr/migrations.py
+++ b/lnbits/extensions/nostr/migrations.py
@@ -24,7 +24,7 @@ async def m001_initial(db):
kind INT NOT NULL,
tags TEXT NOT NULL,
content TEXT NOT NULL,
- sig TEXT NOT NULL,
+ sig TEXT NOT NULL
);
"""
)
diff --git a/lnbits/extensions/nostr/models.py b/lnbits/extensions/nostr/models.py
index ba0c87a5..e21e5d76 100644
--- a/lnbits/extensions/nostr/models.py
+++ b/lnbits/extensions/nostr/models.py
@@ -3,15 +3,10 @@ from sqlite3 import Row
from typing import Optional
from fastapi import Request
-from lnurl import Lnurl
-from lnurl import encode as lnurl_encode # type: ignore
-from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
-from lnurl.types import LnurlPayMetadata # type: ignore
from pydantic import BaseModel
from pydantic.main import BaseModel
class nostrKeys(BaseModel):
- id: str
pubkey: str
privkey: str
@@ -24,6 +19,13 @@ class nostrNotes(BaseModel):
content: str
sig: str
+class nostrCreateRelays(BaseModel):
+ relay: str
+
+class nostrCreateConnections(BaseModel):
+ pubkey: str
+ relayid: str
+
class nostrRelays(BaseModel):
id: str
relay: str
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html b/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
deleted file mode 100644
index af69b76e..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/_api_docs.html
+++ /dev/null
@@ -1,169 +0,0 @@
-
-
-
- Register LNURLDevice devices to receive payments in your LNbits wallet.
- Build your own here
- https://github.com/arcbtc/bitcoinpos
-
- Created by, Ben Arc
-
-
-
-
-
-
- /lnurldevice/api/v1/lnurlpos
- Headers
- {"X-Api-Key": <admin_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X POST {{ request.base_url }}api/v1/lnurldevice -d '{"title":
- <string>, "message":<string>, "currency":
- <integer>}' -H "Content-type: application/json" -H "X-Api-Key:
- {{user.wallets[0].adminkey }}"
-
-
-
-
-
-
-
- PUT
- /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
- Headers
- {"X-Api-Key": <admin_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X POST {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -d ''{"title":
- <string>, "message":<string>, "currency":
- <integer>} -H "Content-type: application/json" -H "X-Api-Key:
- {{user.wallets[0].adminkey }}"
-
-
-
-
-
-
-
-
- GET
- /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
- Headers
- {"X-Api-Key": <invoice_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X GET {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
- user.wallets[0].inkey }}"
-
-
-
-
-
-
-
- GET
- /lnurldevice/api/v1/lnurlposs
- Headers
- {"X-Api-Key": <invoice_key>}
-
- Body (application/json)
-
-
- Returns 200 OK (application/json)
-
- [<lnurldevice_object>, ...]
- Curl example
- curl -X GET {{ request.base_url }}api/v1/lnurldevices -H
- "X-Api-Key: {{ user.wallets[0].inkey }}"
-
-
-
-
-
-
-
- DELETE
- /lnurldevice/api/v1/lnurlpos/<lnurldevice_id>
- Headers
- {"X-Api-Key": <admin_key>}
- Returns 204 NO CONTENT
-
- Curl example
- curl -X DELETE {{ request.base_url
- }}api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: {{
- user.wallets[0].adminkey }}"
-
-
-
-
-
-
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/error.html b/lnbits/extensions/nostr/templates/lnurldevice/error.html
deleted file mode 100644
index d8e41832..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/error.html
+++ /dev/null
@@ -1,34 +0,0 @@
-{% extends "public.html" %} {% block page %}
-
-
-
-
-
- LNURL-pay not paid
-
-
-
-
-
-
-
-
-
- {% endblock %} {% block scripts %}
-
-
-
- {% endblock %}
-
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/index.html b/lnbits/extensions/nostr/templates/lnurldevice/index.html
deleted file mode 100644
index b51e2556..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/index.html
+++ /dev/null
@@ -1,534 +0,0 @@
-{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
-%} {% block page %}
-
-
-
-
- {% raw %}
- New LNURLDevice instance
-
-
-
-
-
-
-
-
-
lNURLdevice
-
-
-
-
-
-
-
-
- Export to CSV
-
-
-
-
-
-
-
-
-
-
- {{ col.label }}
-
-
-
-
-
-
-
-
-
- Delete LNURLDevice
-
-
-
-
- LNURLDevice Settings
-
-
-
-
- {{ col.value }}
-
-
-
- {% endraw %}
-
-
-
-
-
-
-
-
-
- {{SITE_TITLE}} LNURLDevice Extension
-
-
-
-
- {% include "lnurldevice/_api_docs.html" %}
-
-
-
-
-
-
- LNURLDevice device string
- {% raw
- %}{{location}}/lnurldevice/api/v1/lnurl/{{settingsDialog.data.id}},
- {{settingsDialog.data.key}}, {{settingsDialog.data.currency}}{% endraw
- %} Click to copy URL
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Update lnurldevice
- Create lnurldevice
- Cancel
-
-
-
-
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }}
-
-
-{% endblock %}
diff --git a/lnbits/extensions/nostr/templates/lnurldevice/paid.html b/lnbits/extensions/nostr/templates/lnurldevice/paid.html
deleted file mode 100644
index c185ecce..00000000
--- a/lnbits/extensions/nostr/templates/lnurldevice/paid.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{% extends "public.html" %} {% block page %}
-
-
-
-
-
- {{ pin }}
-
-
-
-
-
-
- {% endblock %} {% block scripts %}
-
-
-
- {% endblock %}
-
diff --git a/lnbits/extensions/nostr/templates/nostr/index.html b/lnbits/extensions/nostr/templates/nostr/index.html
new file mode 100644
index 00000000..f17d0243
--- /dev/null
+++ b/lnbits/extensions/nostr/templates/nostr/index.html
@@ -0,0 +1,159 @@
+{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
+%} {% block page %}
+
+
+
+
+
+
+
Nostr
+
+
+
+
+
+
+
+
+ Export to CSV
+
+
+
+ {% raw %}
+
+
+
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+
+ {{ col.value }}
+
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+ {{SITE_TITLE}} Nostr Extension
+
+ Okay
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }}
+
+
+{% endblock %}
diff --git a/lnbits/extensions/nostr/views_api.py b/lnbits/extensions/nostr/views_api.py
index a479cad8..9e7ccfff 100644
--- a/lnbits/extensions/nostr/views_api.py
+++ b/lnbits/extensions/nostr/views_api.py
@@ -7,42 +7,18 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
-from lnbits.extensions.lnurldevice import lnurldevice_ext
+from lnbits.extensions.nostr import nostr_ext
from lnbits.utils.exchange_rates import currencies
-from . import lnurldevice_ext
+from . import nostr_ext
from .crud import (
- create_lnurldevice,
- delete_lnurldevice,
- get_lnurldevice,
- get_lnurldevices,
- update_lnurldevice,
+ create_nostrkeys,
+ get_nostrkeys,
+ create_nostrnotes,
+ get_nostrnotes,
+ create_nostrrelays,
+ get_nostrrelays,
+ create_nostrconnections,
+ get_nostrconnections,
)
-from .models import createLnurldevice
-
-
-@nostr_ext.get("/api/v1/lnurlpos")
-async def api_check_daemon(wallet: WalletTypeInfo = Depends(get_key_type)):
- wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
- try:
- return [
- {**lnurldevice.dict()} for lnurldevice in await get_lnurldevices(wallet_ids)
- ]
- except:
- return ""
-
-@nostr_ext.delete("/api/v1/lnurlpos/{lnurldevice_id}")
-async def api_lnurldevice_delete(
- wallet: WalletTypeInfo = Depends(require_admin_key),
- lnurldevice_id: str = Query(None),
-):
- lnurldevice = await get_lnurldevice(lnurldevice_id)
-
- if not lnurldevice:
- raise HTTPException(
- status_code=HTTPStatus.NOT_FOUND, detail="Wallet link does not exist."
- )
-
- await delete_lnurldevice(lnurldevice_id)
-
- return "", HTTPStatus.NO_CONTENT
\ No newline at end of file
+from .models import nostrKeys
\ No newline at end of file
From 30f9c3d290e9198e6585109d2fb5d19479b214e1 Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 10:35:20 +0000
Subject: [PATCH 043/226] Chnaged nostr to nostradmin
---
.env.example | 2 +-
lnbits/extensions/nostr/config.json | 6 -
lnbits/extensions/nostr/crud.py | 115 -------------
lnbits/extensions/nostr/views_api.py | 24 ---
.../{nostr => nostradmin}/README.md | 0
.../{nostr => nostradmin}/__init__.py | 7 +-
lnbits/extensions/nostradmin/config.json | 6 +
lnbits/extensions/nostradmin/crud.py | 156 ++++++++++++++++++
.../{nostr => nostradmin}/migrations.py | 32 +++-
.../{nostr => nostradmin}/models.py | 14 +-
.../templates/nostradmin}/index.html | 130 ++++++++++++++-
.../extensions/{nostr => nostradmin}/views.py | 2 +-
lnbits/extensions/nostradmin/views_api.py | 87 ++++++++++
13 files changed, 421 insertions(+), 160 deletions(-)
delete mode 100644 lnbits/extensions/nostr/config.json
delete mode 100644 lnbits/extensions/nostr/crud.py
delete mode 100644 lnbits/extensions/nostr/views_api.py
rename lnbits/extensions/{nostr => nostradmin}/README.md (100%)
rename lnbits/extensions/{nostr => nostradmin}/__init__.py (51%)
create mode 100644 lnbits/extensions/nostradmin/config.json
create mode 100644 lnbits/extensions/nostradmin/crud.py
rename lnbits/extensions/{nostr => nostradmin}/migrations.py (54%)
rename lnbits/extensions/{nostr => nostradmin}/models.py (73%)
rename lnbits/extensions/{nostr/templates/nostr => nostradmin/templates/nostradmin}/index.html (50%)
rename lnbits/extensions/{nostr => nostradmin}/views.py (90%)
create mode 100644 lnbits/extensions/nostradmin/views_api.py
diff --git a/.env.example b/.env.example
index 6ef60bc1..5926ee65 100644
--- a/.env.example
+++ b/.env.example
@@ -6,7 +6,7 @@ DEBUG=false
LNBITS_ALLOWED_USERS=""
LNBITS_ADMIN_USERS=""
# Extensions only admin can access
-LNBITS_ADMIN_EXTENSIONS="ngrok"
+LNBITS_ADMIN_EXTENSIONS="nostradmin"
LNBITS_DEFAULT_WALLET_NAME="LNbits wallet"
LNBITS_AD_SPACE="" # csv ad image filepaths or urls, extensions can choose to honor
diff --git a/lnbits/extensions/nostr/config.json b/lnbits/extensions/nostr/config.json
deleted file mode 100644
index a32e39a1..00000000
--- a/lnbits/extensions/nostr/config.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Nostr",
- "short_description": "Daemon for Nostr",
- "icon": "swap_horizontal_circle",
- "contributors": ["arcbtc"]
-}
diff --git a/lnbits/extensions/nostr/crud.py b/lnbits/extensions/nostr/crud.py
deleted file mode 100644
index 0b30bc9a..00000000
--- a/lnbits/extensions/nostr/crud.py
+++ /dev/null
@@ -1,115 +0,0 @@
-from typing import List, Optional, Union
-
-from lnbits.helpers import urlsafe_short_hash
-import shortuuid
-from . import db
-from .models import nostrKeys, nostrNotes, nostrCreateRelays, nostrRelays, nostrConnections, nostrCreateConnections
-
-###############KEYS##################
-
-async def create_nostrkeys(
- data: nostrKeys
-) -> nostrKeys:
- await db.execute(
- """
- INSERT INTO nostr.keys (
- pubkey,
- privkey
- )
- VALUES (?, ?)
- """,
- (data.pubkey, data.privkey),
- )
- return await get_nostrkeys(nostrkey_id)
-
-async def get_nostrkeys(pubkey: str) -> nostrKeys:
- row = await db.fetchone(
- "SELECT * FROM nostr.keys WHERE pubkey = ?",
- (pubkey,),
- )
- return nostrKeys(**row) if row else None
-
-
-###############NOTES##################
-
-async def create_nostrnotes(
- data: nostrNotes
-) -> nostrNotes:
- await db.execute(
- """
- INSERT INTO nostr.notes (
- id,
- pubkey,
- created_at,
- kind,
- tags,
- content,
- sig
- )
- VALUES (?, ?, ?, ?, ?, ?, ?)
- """,
- (data.id, data.pubkey, data.created_at, data.kind, data.tags, data.content, data.sig),
- )
- return await get_nostrnotes(data.id)
-
-async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
- row = await db.fetchone(
- "SELECT * FROM nostr.notes WHERE id = ?",
- (nostrnote_id,),
- )
- return nostrNotes(**row) if row else None
-
-###############RELAYS##################
-
-async def create_nostrrelays(
- data: nostrCreateRelays
-) -> nostrCreateRelays:
- nostrrelay_id = shortuuid.uuid(name=relay)
-
- if await get_nostrrelays(nostrrelay_id):
- return "error"
- await db.execute(
- """
- INSERT INTO nostr.relays (
- id,
- relay
- )
- VALUES (?, ?)
- """,
- (nostrrelay_id, data.relay),
- )
- return await get_nostrnotes(nostrrelay_id)
-
-async def get_nostrrelays(nostrrelay_id: str) -> nostrRelays:
- row = await db.fetchone(
- "SELECT * FROM nostr.relays WHERE id = ?",
- (nostrnote_id,),
- )
- return nostrRelays(**row) if row else None
-
-
-###############CONNECTIONS##################
-
-async def create_nostrconnections(
- data: nostrCreateConnections
-) -> nostrCreateConnections:
- nostrrelay_id = shortuuid.uuid(name=data.relayid + data.pubkey)
- await db.execute(
- """
- INSERT INTO nostr.connections (
- id,
- pubkey,
- relayid
- )
- VALUES (?, ?, ?)
- """,
- (data.id, data.pubkey, data.relayid),
- )
- return await get_nostrconnections(data.id)
-
-async def get_nostrconnections(nostrconnections_id: str) -> nostrConnections:
- row = await db.fetchone(
- "SELECT * FROM nostr.connections WHERE id = ?",
- (nostrconnections_id,),
- )
- return nostrConnections(**row) if row else None
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/views_api.py b/lnbits/extensions/nostr/views_api.py
deleted file mode 100644
index 9e7ccfff..00000000
--- a/lnbits/extensions/nostr/views_api.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from http import HTTPStatus
-
-from fastapi import Request
-from fastapi.param_functions import Query
-from fastapi.params import Depends
-from starlette.exceptions import HTTPException
-
-from lnbits.core.crud import get_user
-from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
-from lnbits.extensions.nostr import nostr_ext
-from lnbits.utils.exchange_rates import currencies
-
-from . import nostr_ext
-from .crud import (
- create_nostrkeys,
- get_nostrkeys,
- create_nostrnotes,
- get_nostrnotes,
- create_nostrrelays,
- get_nostrrelays,
- create_nostrconnections,
- get_nostrconnections,
-)
-from .models import nostrKeys
\ No newline at end of file
diff --git a/lnbits/extensions/nostr/README.md b/lnbits/extensions/nostradmin/README.md
similarity index 100%
rename from lnbits/extensions/nostr/README.md
rename to lnbits/extensions/nostradmin/README.md
diff --git a/lnbits/extensions/nostr/__init__.py b/lnbits/extensions/nostradmin/__init__.py
similarity index 51%
rename from lnbits/extensions/nostr/__init__.py
rename to lnbits/extensions/nostradmin/__init__.py
index 9774a279..7034ca46 100644
--- a/lnbits/extensions/nostr/__init__.py
+++ b/lnbits/extensions/nostradmin/__init__.py
@@ -3,13 +3,14 @@ from fastapi import APIRouter
from lnbits.db import Database
from lnbits.helpers import template_renderer
-db = Database("ext_nostr")
+db = Database("ext_nostradmin")
-nostr_ext: APIRouter = APIRouter(prefix="/nostr", tags=["nostr"])
+nostr_ext: APIRouter = APIRouter(prefix="/nostradmin", tags=["nostradmin"])
def nostr_renderer():
- return template_renderer(["lnbits/extensions/nostr/templates"])
+ return template_renderer(["lnbits/extensions/nostradmin/templates"])
+
from .views import * # noqa
from .views_api import * # noqa
diff --git a/lnbits/extensions/nostradmin/config.json b/lnbits/extensions/nostradmin/config.json
new file mode 100644
index 00000000..2c4f76d3
--- /dev/null
+++ b/lnbits/extensions/nostradmin/config.json
@@ -0,0 +1,6 @@
+{
+ "name": "NostrAdmin",
+ "short_description": "Admin daemon for Nostr",
+ "icon": "swap_horizontal_circle",
+ "contributors": ["arcbtc"]
+}
diff --git a/lnbits/extensions/nostradmin/crud.py b/lnbits/extensions/nostradmin/crud.py
new file mode 100644
index 00000000..08908e85
--- /dev/null
+++ b/lnbits/extensions/nostradmin/crud.py
@@ -0,0 +1,156 @@
+from typing import List, Optional, Union
+
+from lnbits.helpers import urlsafe_short_hash
+import shortuuid
+from . import db
+from .models import (
+ nostrKeys,
+ nostrNotes,
+ nostrCreateRelays,
+ nostrRelays,
+ nostrConnections,
+ nostrCreateConnections,
+ nostrRelayList,
+)
+
+###############KEYS##################
+
+
+async def create_nostrkeys(data: nostrKeys) -> nostrKeys:
+ await db.execute(
+ """
+ INSERT INTO nostradmin.keys (
+ pubkey,
+ privkey
+ )
+ VALUES (?, ?)
+ """,
+ (data.pubkey, data.privkey),
+ )
+ return await get_nostrkeys(nostrkey_id)
+
+
+async def get_nostrkeys(pubkey: str) -> nostrKeys:
+ row = await db.fetchone("SELECT * FROM nostradmin.keys WHERE pubkey = ?", (pubkey,))
+ return nostrKeys(**row) if row else None
+
+
+###############NOTES##################
+
+
+async def create_nostrnotes(data: nostrNotes) -> nostrNotes:
+ await db.execute(
+ """
+ INSERT INTO nostradmin.notes (
+ id,
+ pubkey,
+ created_at,
+ kind,
+ tags,
+ content,
+ sig
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ """,
+ (
+ data.id,
+ data.pubkey,
+ data.created_at,
+ data.kind,
+ data.tags,
+ data.content,
+ data.sig,
+ ),
+ )
+ return await get_nostrnotes(data.id)
+
+
+async def get_nostrnotes(nostrnote_id: str) -> nostrNotes:
+ row = await db.fetchone("SELECT * FROM nostradmin.notes WHERE id = ?", (nostrnote_id,))
+ return nostrNotes(**row) if row else None
+
+
+###############RELAYS##################
+
+
+async def create_nostrrelays(data: nostrCreateRelays) -> nostrCreateRelays:
+ nostrrelay_id = shortuuid.uuid(name=data.relay)
+
+ if await get_nostrrelay(nostrrelay_id):
+ return "error"
+ await db.execute(
+ """
+ INSERT INTO nostradmin.relays (
+ id,
+ relay
+ )
+ VALUES (?, ?)
+ """,
+ (nostrrelay_id, data.relay),
+ )
+ return await get_nostrrelay(nostrrelay_id)
+
+
+async def get_nostrrelays() -> nostrRelays:
+ rows = await db.fetchall("SELECT * FROM nostradmin.relays")
+ return [nostrRelays(**row) for row in rows]
+
+
+async def get_nostrrelay(nostrrelay_id: str) -> nostrRelays:
+ row = await db.fetchone("SELECT * FROM nostradmin.relays WHERE id = ?", (nostrrelay_id,))
+ return nostrRelays(**row) if row else None
+
+
+async def update_nostrrelayallowlist(allowlist: str) -> nostrRelayList:
+ await db.execute(
+ """
+ UPDATE nostradmin.relaylist SET
+ allowlist = ?
+ WHERE id = ?
+ """,
+ (allowlist, 1),
+ )
+ return await get_nostrrelaylist()
+
+async def update_nostrrelaydenylist(denylist: str) -> nostrRelayList:
+ await db.execute(
+ """
+ UPDATE nostradmin.relaylist SET
+ denylist = ?
+ WHERE id = ?
+ """,
+ (denylist, 1),
+ )
+ return await get_nostrrelaylist()
+
+async def get_nostrrelaylist() -> nostrRelayList:
+ row = await db.fetchone("SELECT * FROM nostradmin.relaylist WHERE id = ?", (1,))
+ return nostrRelayList(**row) if row else None
+
+
+###############CONNECTIONS##################
+
+
+async def create_nostrconnections(
+ data: nostrCreateConnections
+) -> nostrCreateConnections:
+ nostrrelay_id = shortuuid.uuid(name=data.relayid + data.pubkey)
+ await db.execute(
+ """
+ INSERT INTO nostradmin.connections (
+ id,
+ pubkey,
+ relayid
+ )
+ VALUES (?, ?, ?)
+ """,
+ (data.id, data.pubkey, data.relayid),
+ )
+ return await get_nostrconnections(data.id)
+
+
+async def get_nostrconnections(nostrconnections_id: str) -> nostrConnections:
+ row = await db.fetchone(
+ "SELECT * FROM nostradmin.connections WHERE id = ?", (nostrconnections_id,)
+ )
+ return nostrConnections(**row) if row else None
diff --git a/lnbits/extensions/nostr/migrations.py b/lnbits/extensions/nostradmin/migrations.py
similarity index 54%
rename from lnbits/extensions/nostr/migrations.py
rename to lnbits/extensions/nostradmin/migrations.py
index 0c616110..09b28117 100644
--- a/lnbits/extensions/nostr/migrations.py
+++ b/lnbits/extensions/nostradmin/migrations.py
@@ -9,7 +9,7 @@ async def m001_initial(db):
"""
await db.execute(
f"""
- CREATE TABLE nostr.keys (
+ CREATE TABLE nostradmin.keys (
pubkey TEXT NOT NULL PRIMARY KEY,
privkey TEXT NOT NULL
);
@@ -17,7 +17,7 @@ async def m001_initial(db):
)
await db.execute(
f"""
- CREATE TABLE nostr.notes (
+ CREATE TABLE nostradmin.notes (
id TEXT NOT NULL PRIMARY KEY,
pubkey TEXT NOT NULL,
created_at TEXT NOT NULL,
@@ -30,7 +30,7 @@ async def m001_initial(db):
)
await db.execute(
f"""
- CREATE TABLE nostr.relays (
+ CREATE TABLE nostradmin.relays (
id TEXT NOT NULL PRIMARY KEY,
relay TEXT NOT NULL
);
@@ -38,10 +38,32 @@ async def m001_initial(db):
)
await db.execute(
f"""
- CREATE TABLE nostr.connections (
+ CREATE TABLE nostradmin.relaylists (
+ id TEXT NOT NULL PRIMARY KEY DEFAULT 1,
+ allowlist TEXT NOT NULL,
+ denylist TEXT NOT NULL
+ );
+ """
+ )
+ try:
+ await db.execute(
+ """
+ INSERT INTO nostradmin.relaylist (
+ id,
+ denylist
+ )
+ VALUES (?, ?,)
+ """,
+ (1, "\n".join(["wss://zucks-meta-relay.com", "wss://nostradmin.cia.gov"])),
+ )
+ except:
+ return
+ await db.execute(
+ f"""
+ CREATE TABLE nostradmin.connections (
id TEXT NOT NULL PRIMARY KEY,
publickey TEXT NOT NULL,
relayid TEXT NOT NULL
);
"""
- )
\ No newline at end of file
+ )
diff --git a/lnbits/extensions/nostr/models.py b/lnbits/extensions/nostradmin/models.py
similarity index 73%
rename from lnbits/extensions/nostr/models.py
rename to lnbits/extensions/nostradmin/models.py
index e21e5d76..fd89f515 100644
--- a/lnbits/extensions/nostr/models.py
+++ b/lnbits/extensions/nostradmin/models.py
@@ -6,6 +6,7 @@ from fastapi import Request
from pydantic import BaseModel
from pydantic.main import BaseModel
+
class nostrKeys(BaseModel):
pubkey: str
privkey: str
@@ -30,7 +31,18 @@ class nostrRelays(BaseModel):
id: str
relay: str
+class nostrRelayList(BaseModel):
+ id: str
+ allowlist: str
+ denylist: str
+
+class nostrRelayDenyList(BaseModel):
+ denylist: str
+
+class nostrRelayAllowList(BaseModel):
+ allowlist: str
+
class nostrConnections(BaseModel):
id: str
pubkey: str
- relayid: str
\ No newline at end of file
+ relayid: str
diff --git a/lnbits/extensions/nostr/templates/nostr/index.html b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
similarity index 50%
rename from lnbits/extensions/nostr/templates/nostr/index.html
rename to lnbits/extensions/nostradmin/templates/nostradmin/index.html
index f17d0243..adab98e2 100644
--- a/lnbits/extensions/nostr/templates/nostr/index.html
+++ b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
@@ -71,12 +71,77 @@
+
+
+
+
+
+
+
+
+
+
+
+ Deny List (denys use of relays in this list)
+
+
+
+
+
+
+
+
+ Update Deny List
+
+ Reset
+
+
+
+
+
+
+
+ Allow List (denys any relays not in this list)
+
+
+
+
+
+
+
+
+ Update Allow List
+
+ Reset
+
+
+
+
+
+
{{SITE_TITLE}} Nostr Extension
+ Only Admin users can manage this extension
Okay
@@ -109,6 +174,9 @@
mixins: [windowMixin],
data: function () {
return {
+ listSelection: 'denylist',
+ allowList: [],
+ denyList: [],
nostrTable: {
columns: [
{
@@ -136,12 +204,66 @@
LNbits.api
.request(
'GET',
- '/nostr/api/v1/relays',
+ '/nostradmin/api/v1/relays',
self.g.user.wallets[0].adminkey
)
.then(function (response) {
if (response.data) {
- self.lnurldeviceLinks = response.data.map(maplnurldevice)
+ self.nostrrelayLinks = response.data.map(maprelays)
+ }
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ setAllowList: function () {
+ var self = this
+ LNbits.api
+ .request(
+ 'POST',
+ '/nostradmin/api/v1/allowlist',
+ self.g.user.wallets[0].adminkey,
+ self.allowList
+ )
+ .then(function (response) {
+ if (response.data) {
+ self.allowList = response.data
+ }
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ setDenyList: function () {
+ var self = this
+ LNbits.api
+ .request(
+ 'POST',
+ '/nostradmin/api/v1/denylist',
+ self.g.user.wallets[0].adminkey,
+ self.allowList
+ )
+ .then(function (response) {
+ if (response.data) {
+ self.denyList = response.data
+ }
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ getLists: function () {
+ var self = this
+ LNbits.api
+ .request(
+ 'GET',
+ '/nostradmin/api/v1/relaylist',
+ self.g.user.wallets[0].adminkey
+ )
+ .then(function (response) {
+ if (response.data) {
+ self.denyList = response.data.denylist
+ self.allowList = response.data.allowlist
}
})
.catch(function (error) {
@@ -151,8 +273,8 @@
},
created: function () {
var self = this
- var getrelays = this.getrelays
- getrelays()
+ this.getrelays()
+ this.getLists()
}
})
diff --git a/lnbits/extensions/nostr/views.py b/lnbits/extensions/nostradmin/views.py
similarity index 90%
rename from lnbits/extensions/nostr/views.py
rename to lnbits/extensions/nostradmin/views.py
index 1dfc07da..5609c218 100644
--- a/lnbits/extensions/nostr/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -20,5 +20,5 @@ templates = Jinja2Templates(directory="templates")
@nostr_ext.get("/", response_class=HTMLResponse)
async def index(request: Request, user: User = Depends(check_user_exists)):
return nostr_renderer().TemplateResponse(
- "nostr/index.html", {"request": request, "user": user.dict()}
+ "nostradmin/index.html", {"request": request, "user": user.dict()}
)
diff --git a/lnbits/extensions/nostradmin/views_api.py b/lnbits/extensions/nostradmin/views_api.py
new file mode 100644
index 00000000..da6e140b
--- /dev/null
+++ b/lnbits/extensions/nostradmin/views_api.py
@@ -0,0 +1,87 @@
+from http import HTTPStatus
+import asyncio
+from fastapi import Request
+from fastapi.param_functions import Query
+from fastapi.params import Depends
+from starlette.exceptions import HTTPException
+
+from lnbits.core.crud import get_user
+from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
+from lnbits.extensions.nostr import nostr_ext
+from lnbits.utils.exchange_rates import currencies
+
+from . import nostr_ext
+from lnbits.settings import LNBITS_ADMIN_USERS
+from .crud import (
+ create_nostrkeys,
+ get_nostrkeys,
+ create_nostrnotes,
+ get_nostrnotes,
+ create_nostrrelays,
+ get_nostrrelays,
+ get_nostrrelaylist,
+ update_nostrrelayallowlist,
+ update_nostrrelaydenylist,
+ create_nostrconnections,
+ get_nostrconnections,
+)
+from .models import nostrKeys, nostrCreateRelays, nostrRelayAllowList, nostrRelayDenyList
+
+
+# while True:
+async def nostr_subscribe():
+ return
+ # for the relays:
+ # async with websockets.connect("ws://localhost:8765") as websocket:
+ # for the public keys:
+ # await websocket.send("subscribe to events")
+ # await websocket.recv()
+
+
+websocket_queue = asyncio.Queue(1000)
+
+
+async def internal_invoice_listener():
+ while True:
+ checking_id = await internal_invoice_queue.get()
+ asyncio.create_task(invoice_callback_dispatcher(checking_id))
+
+
+@nostr_ext.get("/api/v1/relays")
+async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
+
+ relays = await get_nostrrelays()
+ if not relays:
+ await create_nostrrelays(nostrCreateRelays(relay="wss://relayer.fiatjaf.com"))
+ await create_nostrrelays(
+ nostrCreateRelays(relay="wss://nostr-pub.wellorder.net")
+ )
+ relays = await get_nostrrelays()
+ try:
+ return [{**relays.dict()} for relays in await relays]
+ except:
+ None
+
+@nostr_ext.get("/api/v1/relaylist")
+async def api_relaylist(wallet: WalletTypeInfo = Depends(get_key_type)):
+ if wallet.wallet.user not in LNBITS_ADMIN_USERS:
+ raise HTTPException(
+ status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
+ )
+ return await get_nostrrelaylist()
+
+@nostr_ext.post("/api/v1/allowlist")
+async def api_relaysallowed(data: nostrRelayAllowList, wallet: WalletTypeInfo = Depends(get_key_type)):
+ if wallet.wallet.user not in LNBITS_ADMIN_USERS:
+ raise HTTPException(
+ status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
+ )
+ return await update_nostrrelayallowlist(data)
+
+@nostr_ext.post("/api/v1/denylist")
+async def api_relaysdenyed(data: nostrRelayDenyList, wallet: WalletTypeInfo = Depends(get_key_type)):
+ if wallet.wallet.user not in LNBITS_ADMIN_USERS:
+ raise HTTPException(
+ status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
+ )
+ return await update_nostrrelaydenylist(data)
\ No newline at end of file
From 2c435ee9d906b214fbcc6b19541898dcab01d4a4 Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 13:13:36 +0000
Subject: [PATCH 044/226] models decided
---
lnbits/extensions/nostradmin/__init__.py | 2 +-
lnbits/extensions/nostradmin/crud.py | 22 ++----
lnbits/extensions/nostradmin/migrations.py | 41 ++++++-----
lnbits/extensions/nostradmin/models.py | 33 +++++----
.../templates/nostradmin/index.html | 71 +++++++++++--------
lnbits/extensions/nostradmin/views.py | 5 +-
lnbits/extensions/nostradmin/views_api.py | 33 +++------
7 files changed, 100 insertions(+), 107 deletions(-)
diff --git a/lnbits/extensions/nostradmin/__init__.py b/lnbits/extensions/nostradmin/__init__.py
index 7034ca46..797542c4 100644
--- a/lnbits/extensions/nostradmin/__init__.py
+++ b/lnbits/extensions/nostradmin/__init__.py
@@ -5,7 +5,7 @@ from lnbits.helpers import template_renderer
db = Database("ext_nostradmin")
-nostr_ext: APIRouter = APIRouter(prefix="/nostradmin", tags=["nostradmin"])
+nostradmin_ext: APIRouter = APIRouter(prefix="/nostradmin", tags=["nostradmin"])
def nostr_renderer():
diff --git a/lnbits/extensions/nostradmin/crud.py b/lnbits/extensions/nostradmin/crud.py
index 08908e85..1e1bf810 100644
--- a/lnbits/extensions/nostradmin/crud.py
+++ b/lnbits/extensions/nostradmin/crud.py
@@ -12,6 +12,7 @@ from .models import (
nostrCreateConnections,
nostrRelayList,
)
+from .models import nostrKeys, nostrCreateRelays, nostrRelaySetList
###############KEYS##################
@@ -100,31 +101,20 @@ async def get_nostrrelay(nostrrelay_id: str) -> nostrRelays:
row = await db.fetchone("SELECT * FROM nostradmin.relays WHERE id = ?", (nostrrelay_id,))
return nostrRelays(**row) if row else None
-
-async def update_nostrrelayallowlist(allowlist: str) -> nostrRelayList:
+async def update_nostrrelaysetlist(data: nostrRelaySetList) -> nostrRelayList:
await db.execute(
"""
- UPDATE nostradmin.relaylist SET
+ UPDATE nostradmin.relaylists SET
+ denylist = ?,
allowlist = ?
WHERE id = ?
""",
- (allowlist, 1),
- )
- return await get_nostrrelaylist()
-
-async def update_nostrrelaydenylist(denylist: str) -> nostrRelayList:
- await db.execute(
- """
- UPDATE nostradmin.relaylist SET
- denylist = ?
- WHERE id = ?
- """,
- (denylist, 1),
+ (data.denylist, data.allowlist, 1),
)
return await get_nostrrelaylist()
async def get_nostrrelaylist() -> nostrRelayList:
- row = await db.fetchone("SELECT * FROM nostradmin.relaylist WHERE id = ?", (1,))
+ row = await db.fetchone("SELECT * FROM nostradmin.relaylists WHERE id = ?", (1,))
return nostrRelayList(**row) if row else None
diff --git a/lnbits/extensions/nostradmin/migrations.py b/lnbits/extensions/nostradmin/migrations.py
index 09b28117..590f72ea 100644
--- a/lnbits/extensions/nostradmin/migrations.py
+++ b/lnbits/extensions/nostradmin/migrations.py
@@ -1,11 +1,8 @@
from lnbits.db import Database
-db2 = Database("ext_nostr")
-
-
async def m001_initial(db):
"""
- Initial nostr table.
+ Initial nostradmin table.
"""
await db.execute(
f"""
@@ -40,24 +37,23 @@ async def m001_initial(db):
f"""
CREATE TABLE nostradmin.relaylists (
id TEXT NOT NULL PRIMARY KEY DEFAULT 1,
- allowlist TEXT NOT NULL,
- denylist TEXT NOT NULL
+ allowlist TEXT,
+ denylist TEXT
);
"""
)
- try:
- await db.execute(
- """
- INSERT INTO nostradmin.relaylist (
- id,
- denylist
- )
- VALUES (?, ?,)
- """,
- (1, "\n".join(["wss://zucks-meta-relay.com", "wss://nostradmin.cia.gov"])),
+
+ await db.execute(
+ """
+ INSERT INTO nostradmin.relaylists (
+ id,
+ denylist
)
- except:
- return
+ VALUES (?, ?)
+ """,
+ ("1", "wss://zucks-meta-relay.com\nwss://nostr.cia.gov",),
+ )
+
await db.execute(
f"""
CREATE TABLE nostradmin.connections (
@@ -67,3 +63,12 @@ async def m001_initial(db):
);
"""
)
+ await db.execute(
+ f"""
+ CREATE TABLE nostradmin.subscribed (
+ id TEXT NOT NULL PRIMARY KEY,
+ userPubkey TEXT NOT NULL,
+ subscribedPubkey TEXT NOT NULL
+ );
+ """
+ )
\ No newline at end of file
diff --git a/lnbits/extensions/nostradmin/models.py b/lnbits/extensions/nostradmin/models.py
index fd89f515..1968567f 100644
--- a/lnbits/extensions/nostradmin/models.py
+++ b/lnbits/extensions/nostradmin/models.py
@@ -5,7 +5,7 @@ from typing import Optional
from fastapi import Request
from pydantic import BaseModel
from pydantic.main import BaseModel
-
+from fastapi.param_functions import Query
class nostrKeys(BaseModel):
pubkey: str
@@ -21,28 +21,31 @@ class nostrNotes(BaseModel):
sig: str
class nostrCreateRelays(BaseModel):
- relay: str
+ relay: str = Query(None)
class nostrCreateConnections(BaseModel):
- pubkey: str
- relayid: str
+ pubkey: str = Query(None)
+ relayid: str = Query(None)
class nostrRelays(BaseModel):
- id: str
- relay: str
+ id: Optional[str]
+ relay: Optional[str]
class nostrRelayList(BaseModel):
id: str
- allowlist: str
- denylist: str
+ allowlist: Optional[str]
+ denylist: Optional[str]
-class nostrRelayDenyList(BaseModel):
- denylist: str
-
-class nostrRelayAllowList(BaseModel):
- allowlist: str
+class nostrRelaySetList(BaseModel):
+ allowlist: Optional[str]
+ denylist: Optional[str]
class nostrConnections(BaseModel):
id: str
- pubkey: str
- relayid: str
+ pubkey: Optional[str]
+ relayid: Optional[str]
+
+class nostrSubscriptions(BaseModel):
+ id: str
+ userPubkey: Optional[str]
+ subscribedPubkey: Optional[str]
\ No newline at end of file
diff --git a/lnbits/extensions/nostradmin/templates/nostradmin/index.html b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
index adab98e2..27decdc8 100644
--- a/lnbits/extensions/nostradmin/templates/nostradmin/index.html
+++ b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
@@ -6,7 +6,7 @@
-
Nostr
+ NOSTR RELAYS ONLINE
@@ -29,7 +29,7 @@
-
-
+
+
-
+
-
+
-
- Deny List (denys use of relays in this list)
-
-
+ Relays in this list will NOT be used
+
-
+
Update Deny List
- Reset
-
- Allow List (denys any relays not in this list)
-
-
+ ONLY relays in this list will be used
+
-
+
Update Allow List
- Reset
@@ -175,8 +175,12 @@
data: function () {
return {
listSelection: 'denylist',
- allowList: [],
- denyList: [],
+ setList: {
+ allowlist: '',
+ denylist: ''
+ },
+ nostrLinks: [],
+ filter: '',
nostrTable: {
columns: [
{
@@ -234,18 +238,20 @@
LNbits.utils.notifyApiError(error)
})
},
- setDenyList: function () {
+ setRelayList: function () {
var self = this
+ console.log(self.setList)
LNbits.api
.request(
'POST',
- '/nostradmin/api/v1/denylist',
+ '/nostradmin/api/v1/setlist',
self.g.user.wallets[0].adminkey,
- self.allowList
+ self.setList
)
.then(function (response) {
if (response.data) {
- self.denyList = response.data
+ console.log(response.data)
+ // self.denyList = response.data
}
})
.catch(function (error) {
@@ -262,13 +268,18 @@
)
.then(function (response) {
if (response.data) {
- self.denyList = response.data.denylist
- self.allowList = response.data.allowlist
+ console.log(response.data)
+ self.setList.denylist = response.data.denylist
+ self.setList.allowlist = response.data.allowlist
}
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
+ },
+ exportlnurldeviceCSV: function () {
+ var self = this
+ LNbits.utils.exportCSV(self.nostrTable.columns, this.nostrLinks)
}
},
created: function () {
diff --git a/lnbits/extensions/nostradmin/views.py b/lnbits/extensions/nostradmin/views.py
index 5609c218..51297320 100644
--- a/lnbits/extensions/nostradmin/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -6,18 +6,19 @@ from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse
+from . import nostradmin_ext, nostr_renderer
from lnbits.core.crud import update_payment_status
from lnbits.core.models import User
from lnbits.core.views.api import api_payment
from lnbits.decorators import check_user_exists
-from . import nostr_ext, nostr_renderer
+
templates = Jinja2Templates(directory="templates")
-@nostr_ext.get("/", response_class=HTMLResponse)
+@nostradmin_ext.get("/", response_class=HTMLResponse)
async def index(request: Request, user: User = Depends(check_user_exists)):
return nostr_renderer().TemplateResponse(
"nostradmin/index.html", {"request": request, "user": user.dict()}
diff --git a/lnbits/extensions/nostradmin/views_api.py b/lnbits/extensions/nostradmin/views_api.py
index da6e140b..d79315ac 100644
--- a/lnbits/extensions/nostradmin/views_api.py
+++ b/lnbits/extensions/nostradmin/views_api.py
@@ -7,11 +7,10 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
-from lnbits.extensions.nostr import nostr_ext
from lnbits.utils.exchange_rates import currencies
-from . import nostr_ext
from lnbits.settings import LNBITS_ADMIN_USERS
+from . import nostradmin_ext
from .crud import (
create_nostrkeys,
get_nostrkeys,
@@ -20,13 +19,11 @@ from .crud import (
create_nostrrelays,
get_nostrrelays,
get_nostrrelaylist,
- update_nostrrelayallowlist,
- update_nostrrelaydenylist,
+ update_nostrrelaysetlist,
create_nostrconnections,
get_nostrconnections,
)
-from .models import nostrKeys, nostrCreateRelays, nostrRelayAllowList, nostrRelayDenyList
-
+from .models import nostrKeys, nostrCreateRelays, nostrRelaySetList
# while True:
async def nostr_subscribe():
@@ -41,13 +38,7 @@ async def nostr_subscribe():
websocket_queue = asyncio.Queue(1000)
-async def internal_invoice_listener():
- while True:
- checking_id = await internal_invoice_queue.get()
- asyncio.create_task(invoice_callback_dispatcher(checking_id))
-
-
-@nostr_ext.get("/api/v1/relays")
+@nostradmin_ext.get("/api/v1/relays")
async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
relays = await get_nostrrelays()
@@ -62,7 +53,7 @@ async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
except:
None
-@nostr_ext.get("/api/v1/relaylist")
+@nostradmin_ext.get("/api/v1/relaylist")
async def api_relaylist(wallet: WalletTypeInfo = Depends(get_key_type)):
if wallet.wallet.user not in LNBITS_ADMIN_USERS:
raise HTTPException(
@@ -70,18 +61,10 @@ async def api_relaylist(wallet: WalletTypeInfo = Depends(get_key_type)):
)
return await get_nostrrelaylist()
-@nostr_ext.post("/api/v1/allowlist")
-async def api_relaysallowed(data: nostrRelayAllowList, wallet: WalletTypeInfo = Depends(get_key_type)):
+@nostradmin_ext.post("/api/v1/setlist")
+async def api_relayssetlist(data: nostrRelaySetList, wallet: WalletTypeInfo = Depends(get_key_type)):
if wallet.wallet.user not in LNBITS_ADMIN_USERS:
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
)
- return await update_nostrrelayallowlist(data)
-
-@nostr_ext.post("/api/v1/denylist")
-async def api_relaysdenyed(data: nostrRelayDenyList, wallet: WalletTypeInfo = Depends(get_key_type)):
- if wallet.wallet.user not in LNBITS_ADMIN_USERS:
- raise HTTPException(
- status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
- )
- return await update_nostrrelaydenylist(data)
\ No newline at end of file
+ return await update_nostrrelaysetlist(data)
\ No newline at end of file
From 3f356f9de8d48995db0e301aa27015b2827fa70e Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 13:52:19 +0000
Subject: [PATCH 045/226] Started planning websocket daemon
---
lnbits/extensions/nostradmin/views.py | 70 ++++++++++++++++++++++-
lnbits/extensions/nostradmin/views_api.py | 12 ----
2 files changed, 68 insertions(+), 14 deletions(-)
diff --git a/lnbits/extensions/nostradmin/views.py b/lnbits/extensions/nostradmin/views.py
index 51297320..235ec7e9 100644
--- a/lnbits/extensions/nostradmin/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -1,5 +1,6 @@
from http import HTTPStatus
-
+import asyncio
+import asyncio
from fastapi import Request
from fastapi.param_functions import Query
from fastapi.params import Depends
@@ -7,13 +8,14 @@ from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse
from . import nostradmin_ext, nostr_renderer
+from fastapi import Request, WebSocket, WebSocketDisconnect
from lnbits.core.crud import update_payment_status
from lnbits.core.models import User
from lnbits.core.views.api import api_payment
from lnbits.decorators import check_user_exists
-
+from .crud import get_nostrkeys
templates = Jinja2Templates(directory="templates")
@@ -23,3 +25,67 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
return nostr_renderer().TemplateResponse(
"nostradmin/index.html", {"request": request, "user": user.dict()}
)
+
+#####################################################################
+#################### NOSTR WEBSOCKET THREAD #########################
+##### THE QUEUE LOOP THREAD THING THAT LISTENS TO BUNCH OF ##########
+### WEBSOCKET CONNECTIONS, STORING DATA IN DB/PUSHING TO FRONTEND ###
+################### VIA updater() FUNCTION ##########################
+#####################################################################
+
+websocket_queue = asyncio.Queue(1000)
+
+# while True:
+async def nostr_subscribe():
+ return
+ # for the relays:
+ # async with websockets.connect("ws://localhost:8765") as websocket:
+ # for the public keys:
+ # await websocket.send("subscribe to events")
+ # await websocket.recv()
+
+#####################################################################
+################### LNBITS WEBSOCKET ROUTES #########################
+#### HERE IS WHERE LNBITS FRONTEND CAN RECEIVE AND SEND MESSAGES ####
+#####################################################################
+
+class ConnectionManager:
+ def __init__(self):
+ self.active_connections: List[WebSocket] = []
+
+ async def connect(self, websocket: WebSocket, nostr_id: str):
+ await websocket.accept()
+ websocket.id = nostr_id
+ self.active_connections.append(websocket)
+
+ def disconnect(self, websocket: WebSocket):
+ self.active_connections.remove(websocket)
+
+ async def send_personal_message(self, message: str, nostr_id: str):
+ for connection in self.active_connections:
+ if connection.id == nostr_id:
+ await connection.send_text(message)
+
+ async def broadcast(self, message: str):
+ for connection in self.active_connections:
+ await connection.send_text(message)
+
+
+manager = ConnectionManager()
+
+
+@nostradmin_ext.websocket("/nostradmin/ws/{nostr_id}", name="copilot.websocket_by_id")
+async def websocket_endpoint(websocket: WebSocket, copilot_id: str):
+ await manager.connect(websocket, nostr_id)
+ try:
+ while True:
+ data = await websocket.receive_text()
+ except WebSocketDisconnect:
+ manager.disconnect(websocket)
+
+
+async def updater(nostr_id, message):
+ copilot = await get_copilot(nostr_id)
+ if not copilot:
+ return
+ await manager.send_personal_message(f"{message}", nostr_id)
\ No newline at end of file
diff --git a/lnbits/extensions/nostradmin/views_api.py b/lnbits/extensions/nostradmin/views_api.py
index d79315ac..ad8bcf17 100644
--- a/lnbits/extensions/nostradmin/views_api.py
+++ b/lnbits/extensions/nostradmin/views_api.py
@@ -25,18 +25,6 @@ from .crud import (
)
from .models import nostrKeys, nostrCreateRelays, nostrRelaySetList
-# while True:
-async def nostr_subscribe():
- return
- # for the relays:
- # async with websockets.connect("ws://localhost:8765") as websocket:
- # for the public keys:
- # await websocket.send("subscribe to events")
- # await websocket.recv()
-
-
-websocket_queue = asyncio.Queue(1000)
-
@nostradmin_ext.get("/api/v1/relays")
async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
From 4e65c39b362921b81488f9a1212cb57714b879fe Mon Sep 17 00:00:00 2001
From: benarc
Date: Tue, 8 Feb 2022 14:02:50 +0000
Subject: [PATCH 046/226] typo
---
lnbits/extensions/nostradmin/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lnbits/extensions/nostradmin/views.py b/lnbits/extensions/nostradmin/views.py
index 235ec7e9..f00c43a3 100644
--- a/lnbits/extensions/nostradmin/views.py
+++ b/lnbits/extensions/nostradmin/views.py
@@ -74,7 +74,7 @@ class ConnectionManager:
manager = ConnectionManager()
-@nostradmin_ext.websocket("/nostradmin/ws/{nostr_id}", name="copilot.websocket_by_id")
+@nostradmin_ext.websocket("/nostradmin/ws/{nostr_id}", name="nostr_id.websocket_by_id")
async def websocket_endpoint(websocket: WebSocket, copilot_id: str):
await manager.connect(websocket, nostr_id)
try:
From dbc47332ee71508ea39861ef2d8cef9cf3236b25 Mon Sep 17 00:00:00 2001
From: benarc
Date: Thu, 10 Feb 2022 09:58:50 +0000
Subject: [PATCH 047/226] Working, looking good
---
lnbits/extensions/nostradmin/models.py | 1 +
.../templates/nostradmin/index.html | 39 ++++++++++++-------
lnbits/extensions/nostradmin/views.py | 21 +++++++---
lnbits/extensions/nostradmin/views_api.py | 17 +++++---
4 files changed, 53 insertions(+), 25 deletions(-)
diff --git a/lnbits/extensions/nostradmin/models.py b/lnbits/extensions/nostradmin/models.py
index 1968567f..dc99b083 100644
--- a/lnbits/extensions/nostradmin/models.py
+++ b/lnbits/extensions/nostradmin/models.py
@@ -30,6 +30,7 @@ class nostrCreateConnections(BaseModel):
class nostrRelays(BaseModel):
id: Optional[str]
relay: Optional[str]
+ status: Optional[bool] = False
class nostrRelayList(BaseModel):
id: str
diff --git a/lnbits/extensions/nostradmin/templates/nostradmin/index.html b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
index 27decdc8..57552bf2 100644
--- a/lnbits/extensions/nostradmin/templates/nostradmin/index.html
+++ b/lnbits/extensions/nostradmin/templates/nostradmin/index.html
@@ -29,7 +29,7 @@
-
-
-
- {{ col.value }}
+
+
+ {{ col.value }}
+
+
{{ col.value }}
+
@@ -143,7 +145,7 @@
{{SITE_TITLE}} Nostr Extension
Only Admin users can manage this extension
- Okay
+
@@ -153,7 +155,7 @@
+{% endblock %}
+
+
+
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index c38f8d51..70d5c146 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -3,14 +3,13 @@ from http import HTTPStatus
from fastapi import Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
-from starlette.exceptions import HTTPException
-from starlette.responses import HTMLResponse
-
from lnbits.core.models import User
from lnbits.decorators import check_user_exists # type: ignore
from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
+from starlette.exceptions import HTTPException
+from starlette.responses import HTMLResponse
-from .crud import get_diagonalley_products
+from .crud import get_diagonalley_products, get_diagonalley_stall
templates = Jinja2Templates(directory="templates")
@@ -24,17 +23,18 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
- product = await get_diagonalley_products(stall_id)
+ stall = await get_diagonalley_stall(stall_id)
+ products = await get_diagonalley_products(stall_id)
- if not product:
+ if not stall:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
)
return diagonalley_renderer().TemplateResponse(
"diagonalley/stall.html",
{
- "stall": [
- product.dict() for product in await get_diagonalley_products(stall_id)
- ]
+ "request": request,
+ "stall": stall.dict(),
+ "products": [product.dict() for product in products]
},
)
From 6965459f5d8860343be25f16c434652425c6d5cb Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 20 Jul 2022 11:46:20 +0100
Subject: [PATCH 063/226] add StaticFiles
---
lnbits/extensions/diagonalley/__init__.py | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py
index db88bdbd..23c02a5f 100644
--- a/lnbits/extensions/diagonalley/__init__.py
+++ b/lnbits/extensions/diagonalley/__init__.py
@@ -1,18 +1,23 @@
import asyncio
-from http import HTTPStatus
-
-from fastapi import APIRouter, Request
-from fastapi.staticfiles import StaticFiles
-from starlette.exceptions import HTTPException
-from starlette.responses import HTMLResponse
+from fastapi import APIRouter
from lnbits.db import Database
from lnbits.helpers import template_renderer
-from lnbits.settings import LNBITS_ADMIN_EXTENSIONS
from lnbits.tasks import catch_everything_and_restart
+from starlette.staticfiles import StaticFiles
+
+db = Database("ext_diagonalley")
diagonalley_ext: APIRouter = APIRouter(prefix="/diagonalley", tags=["diagonalley"])
-db = Database("ext_diagonalley")
+
+diagonalley_static_files = [
+ {
+ "path": "/diagonalley/static",
+ "app": StaticFiles(directory="lnbits/extensions/diagonalley/static"),
+ "name": "diagonalley_static",
+ }
+]
+
# if 'nostradmin' not in LNBITS_ADMIN_EXTENSIONS:
# @diagonalley_ext.get("/", response_class=HTMLResponse)
# async def index(request: Request):
@@ -20,8 +25,10 @@ db = Database("ext_diagonalley")
# "error.html", {"request": request, "err": "Ask system admin to enable NostrAdmin!"}
# )
# else:
+
def diagonalley_renderer():
return template_renderer(["lnbits/extensions/diagonalley/templates"])
+ # return template_renderer(["lnbits/extensions/diagonalley/templates"])
from .tasks import wait_for_paid_invoices
From b15134114885f41338157895316e035c3780c64e Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 20 Jul 2022 11:46:48 +0100
Subject: [PATCH 064/226] add a placeholder img for no photo product
---
.../diagonalley/static/images/placeholder.png | Bin 0 -> 2840 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 lnbits/extensions/diagonalley/static/images/placeholder.png
diff --git a/lnbits/extensions/diagonalley/static/images/placeholder.png b/lnbits/extensions/diagonalley/static/images/placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..c7d3a94729f5835b922f71f2b57ccdb7c0ca6672
GIT binary patch
literal 2840
zcmds3i&qn879ST|5~PX^h=_`!hV_7P09PAOTM$I#Aqqv2wKxL7XCn_m1W_@-VHL4U
zg@A|(mFkfKf)tV08g_YPCP2tLkU$_0NJ2m&un3y{qT8PBIo*Gtb7s!m@80kJ?)`rE
zPHwV;0)0L+TV)18&}Y8;ybeK-2_1s|RD&}Cnyk=kXTWQ5j7NY61U<`LvVeR7*6Sko
z9SVS;OGF5|N`s)cKy`H#f-b-iq&^NoZUDggeDTYJJ0WP1dys#K_v?vCtwz(?*~w%w
zxm+#}JRA;>%bOV2>9pfwk$6xd?ds~nFpR_Dh=ig+>7ZLxT}>i+(I6h+6i+L7Ur-kzSW&aQrO|Ipx&N}<%MHSFGAHk++ctAzpq
zr;pRkVvTFG1N{R^g_6Z$p-d(VV@>FE@{y4-)u@0kP>jfXdwcu9#b)>P^e7bysYJr*
z>r=?(T8$P%QOSUW&*Mv_QXY?|9v#z->w0^7`8=LbAXLf~>aj5)Uoar<9~<P)r~Y
zh=jtP?j8Y;-_7b4353ip=J1fLkKHF0isZv1%&snWFMCKj$mMW{WiqKmiZW4+TB9CQ
zk88bQ7|nAr^)i42G28sviNri%$6Yc%4MgzOe@j(*)lDZ_^QTYrMUMOy>kB$JP0I
zd4yaPk4xs0I0-BNArl6Pzxs5fG_ug@Hmf1*UIF=ax^-0PMGps;t!Ld{PZ=(E}XBhp70nlnvg
zN&F%b7{(@YfIC2RB~apqH|OEL+vBT)W~y}1n|>5O9c
z3zyzwqIlK)%awH&O9;gE*peGvZP#mO`t;A>_2=pLR1sgiWs3ggSCD}(!_|^Q=wmmU
zC-%iX+Tf47&|Vy_n^ik*#S<8`hPQEs0%{eW;7MyJkvFH!6vGeS!-w-05dv`p^-}#E
z-2=SH8S!jJ67x-SkAztexvP{e?dHRkZ+u}Z%jT$4+^JKo5IfT
z_cKaWEACC@!w)Or5msriIG#Z(Vicohxyj-5pkTW7-*QEt6S1*PoSB%e*)
zRv+Hh6flr>F?EL(P_LwvInPc{9h!R39i_NCcXv;-PwJa%cROg=uwz#8=#2YeYHDNR
zJFdFD`mio_wsSH7f^HmY;#zTHFUI7LEu17y1*_%mkBsrOiPxB7fiLH
zmc(Eiit9;weQuhf59DE<*1j_~p>a0C8pvyuc?E4d0HG#X4SIRber5~U&sbeIaY-vM
z?zN>HwaA
zWSZ%9p{-U)!64zUke0sL%`Y75jj=N35)Esv81XHYp@ub8pfH*E+C06mT3!jjZo^lY
z;WeB5X*L_N0UyFUCm`8l?!MB$OKt)4Rrr946t=KG5x}y2sS0X?BWRH;^wy1Y;h@0~
zzMXQ~e+de5Yd3cNY0B)=vu}OCDagYxRrkK|>;C7x)K&oL
zm+D%xE&b~xz=@BQQo=8s7wrq(GF7n{gt$iPaMyQ@CN?{O!;!J;({qo$(_IRr<7!XP
z-DCPij|+BLfbOwWK8Z3%bsw58-s#xh7=YzSBbSiM=54_V_GFRENo6OGfxLup2R}Mt
zFOWLn4uN85Fb$N5FI5Z~P%|J5Mn4CPlfj|KT~6Bp8cT|+No5s4mmJ4exokT6~
z!Lggrgtkp5t&JGliny2{l=`WSgldCbZq@gA?SVXt&4xcEkNS
z3RrGR@II0dg(O6~MaD&g7vusvleaj#Y;kc7fyr*J+uWSDJHoIV3}5BEd-)rObJVC)
zl;r>K@cNdwkxLt6gkUNqAqk0#hCHIEC!*K+oReByz
F{|^ymw<7=m
literal 0
HcmV?d00001
From e56b26146ad8bb583951b4869a7d99bcf3f35b5e Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 20 Jul 2022 11:47:03 +0100
Subject: [PATCH 065/226] toolbar
---
.../templates/diagonalley/stall.html | 208 ++++++++++--------
1 file changed, 114 insertions(+), 94 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index 640a2428..a7a4ddca 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -1,101 +1,116 @@
{% extends "public.html" %} {% block page %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Benling C200-BLK Smartwatch (Black Strap Free Size)
-
-
-
-
-
-
-
-
-
-
-
-
-
- Special Price
-
-
₹3,149 ₹3,699
-
20% off
-
-
-
-
-
-
-
-
-
-
-
-
-
- View details
-
-
-
-
+
+
+
+
+ {{ stall.name }}
+
+
+
+
+
+
+
+
+
+
-
-
- {{ item.product }}
- {{ item.description }}
+
+
+
+ Special Price
+
+
{{ item.price }} sats BTC {{ (item.price / 1e8).toFixed(8) }}
+
{{item.quantity}} left
+
+
+ {{cat}}
+
+
+ {{ item.description }}
+
- {{ lorem }}
+
+
+
+
+ View details
+
+
{% endraw %}
-
-->
+
{% endblock %} {% block scripts %}
-{% endblock %}
+{% endblock %}
+
+
+
+
+
+
+
+
+ Update Product
+
+ Create Product
+
+ Cancel
+
+
+
+
{% endblock %} {% block scripts %}
{% endblock %}
From 6d5e9aba39d2e3ecc93219859bc01172a51efb66 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 27 Jul 2022 15:28:58 +0100
Subject: [PATCH 068/226] initial launch market
---
lnbits/extensions/diagonalley/crud.py | 25 ++++++++++++
lnbits/extensions/diagonalley/migrations.py | 26 +++++++++++++
lnbits/extensions/diagonalley/models.py | 12 +++++-
.../templates/diagonalley/index.html | 18 ++++-----
lnbits/extensions/diagonalley/views.py | 18 +++++++++
lnbits/extensions/diagonalley/views_api.py | 39 +++++++++++++++++++
6 files changed, 127 insertions(+), 11 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 67ef15c9..fbc1d332 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -12,6 +12,7 @@ from lnbits.settings import WALLET
from . import db
from .models import (
+ Market,
Orders,
Products,
Stalls,
@@ -261,3 +262,27 @@ async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orde
async def delete_diagonalley_order(order_id: str) -> None:
await db.execute("DELETE FROM diagonalley.orders WHERE id = ?", (order_id,))
+
+### Market/Marketplace
+
+async def get_diagonalley_markets(user: str) -> List[Market]:
+ rows = await db.fetchall(
+ 'SELECT * FROM diagonalley.markets WHERE usr = ?', (user,)
+ )
+ return [Market(**row) for row in rows]
+
+
+async def get_diagonalley_market(market_id: str) -> Optional[Market]:
+ row = await db.fetchone(
+ 'SELECT * FROM diagonalley.markets WHERE id = ?', (market_id,)
+ )
+ Market(**row) if row else None
+
+
+async def get_diagonalley_market_stalls(market_id: str):
+ rows = await db.fetchall(
+ "SELECT * FROM diagonalley.market_stalls WHERE marketid = ?", (market_id,)
+ )
+ return [Stalls(**row) for row in rows]
+
+
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index 0ad308b8..e994d723 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -86,4 +86,30 @@ async def m001_initial(db):
);
"""
)
+
+ """
+ Initial market table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE diagonalley.markets (
+ id TEXT PRIMARY KEY,
+ usr TEXT NOT NULL,
+ name TEXT
+ );
+ """
+ )
+
+ """
+ Initial market stalls table.
+ """
+ await db.execute(
+ """
+ CREATE TABLE diagonalley.market_stalls (
+ id TEXT PRIMARY KEY,
+ marketid TEXT NOT NULL REFERENCES {db.references_schema}markets (id),
+ stallid TEXT NOT NULL REFERENCES {db.references_schema}stalls (id)
+ );
+ """
+ )
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 2132d72f..4fbf04ff 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -1,4 +1,4 @@
-from typing import Optional
+from typing import List, Optional
from fastapi.param_functions import Query
from pydantic import BaseModel
@@ -81,3 +81,13 @@ class Orders(BaseModel):
paid: bool
shipped: bool
time: int
+
+class CreateMarket(BaseModel):
+ usr: str = Query(...)
+ name: str = Query(None)
+ stalls: List[str] = Query(...)
+
+class Market(BaseModel):
+ id: str
+ usr: str
+ name: Optional[str]
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 0a56408d..dbe443eb 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -816,7 +816,7 @@ new Vue({
{
name: 'stall',
align: 'left',
- label: 'Stall',
+ label: 'Store',
field: 'stall'
},
{
@@ -1384,23 +1384,21 @@ new Vue({
LNbits.utils.exportCSV(this.zonesTable.columns, this.zones)
},
////////////////////////////////////////
- //////////////////SHOP//////////////////
+ //////////////////MARKET//////////////////
////////////////////////////////////////
- getShops: function () {
- var self = this
-
+ getMarkets(){
LNbits.api
.request(
'GET',
- '/diagonalley/api/v1/shops?all_wallets=true',
+ '/diagonalley/api/v1/markets',
this.g.user.wallets[0].inkey
)
- .then(function (response) {
+ .then((response) => {
if (response.data) {
- self.shops = response.data.map(mapShops)
+ this.shops = response.data.map(mapShops)
}
})
- .catch(function (error) {
+ .catch((error) => {
LNbits.utils.notifyApiError(error)
})
},
@@ -1451,7 +1449,6 @@ new Vue({
})
},
createShop: function (data) {
- var self = this
console.log('cuntywoo')
LNbits.api
.request(
@@ -1591,6 +1588,7 @@ new Vue({
this.getProducts()
this.getZones()
this.getOrders()
+ this.getMarkets()
this.customerKeys = [
'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 70d5c146..2ec75589 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -38,3 +38,21 @@ async def display(request: Request, stall_id):
"products": [product.dict() for product in products]
},
)
+
+@diagonalley_ext.get("/{market_id}", response_class=HTMLResponse)
+async def display(request: Request, stall_id):
+ stalls = await get_diagonalley_stall(stall_id)
+ products = await get_diagonalley_products(stall_id)
+
+ if not stall:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
+ )
+ return diagonalley_renderer().TemplateResponse(
+ "diagonalley/stall.html",
+ {
+ "request": request,
+ "stall": stall.dict(),
+ "products": [product.dict() for product in products]
+ },
+ )
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index c57eeaa3..b2fb5a47 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -25,6 +25,8 @@ from .crud import (
delete_diagonalley_product,
delete_diagonalley_stall,
delete_diagonalley_zone,
+ get_diagonalley_market,
+ get_diagonalley_markets,
get_diagonalley_order,
get_diagonalley_orders,
get_diagonalley_product,
@@ -38,6 +40,7 @@ from .crud import (
update_diagonalley_zone,
)
from .models import (
+ CreateMarket,
Orders,
Products,
Stalls,
@@ -383,3 +386,39 @@ async def api_diagonalley_stall_order(
),
)
return {"checking_id": checking_id, "payment_request": payment_request}
+
+
+##
+# MARKETS
+##
+
+@diagonalley_ext.get("/api/v1/markets")
+async def api_diagonalley_orders(
+ wallet: WalletTypeInfo = Depends(get_key_type)
+):
+ try:
+ return [market.dict() for market in await get_diagonalley_markets(wallet.wallet.user)]
+ except:
+ return {"message": "We could not retrieve the markets."}
+
+@diagonalley_ext.post("/api/v1/markets")
+@diagonalley_ext.put("/api/v1/markets/{market_id}")
+async def api_diagonalley_stall_create(
+ data: CreateMarket,
+ market_id: str = None,
+ wallet: WalletTypeInfo = Depends(require_invoice_key),
+):
+
+ if market_id:
+ market = await get_diagonalley_market(market_id)
+ if not market:
+ return {"message": "Market does not exist."}
+
+ if market.usr != wallet.wallet.user:
+ return {"message": "Not your market."}
+
+ market = await update_diagonalley_market(market_id, **data.dict())
+ else:
+ market = await create_diagonalley_market(data=data)
+
+ return market.dict()
From 3f58676849ef28b03c9ef05ac0537010e6d7b8f9 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 27 Jul 2022 16:46:27 +0100
Subject: [PATCH 069/226] rename shop to market and create market
---
.../templates/diagonalley/index.html | 52 +++++++++----------
1 file changed, 24 insertions(+), 28 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index dbe443eb..893830a9 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -170,13 +170,13 @@
-
+
Launch
- Cancel
@@ -924,7 +924,7 @@ new Vue({
show: false,
data: {countries:[]}
},
- shopDialog: {
+ marketDialog: {
show: false,
data: {activate: false}
},
@@ -1410,16 +1410,14 @@ new Vue({
this.shopDialog.show = true
},
sendShopFormData: function () {
- if (this.shopDialog.data.id) {
- } else {
- var data = {
- countries: this.shopDialog.data.countries,
- cost: this.shopDialog.data.cost
- }
- }
+ let data = {...this.marketDialog.data}
- if (this.shopDialog.data.id) {
- this.updateZone(this.shopDialog.data)
+ if(!data.usr) {
+ data.usr = this.g.user.id
+ }
+
+ if (data.id) {
+ this.updateZone(data)
} else {
this.createZone(data)
}
@@ -1448,24 +1446,22 @@ new Vue({
LNbits.utils.notifyApiError(error)
})
},
- createShop: function (data) {
- console.log('cuntywoo')
+ createShop(data) {
+ console.log('data')
LNbits.api
.request(
'POST',
- '/diagonalley/api/v1/shops',
- _.findWhere(self.g.user.wallets, {
- id: self.shopDialog.data.wallet
- }).inkey,
+ '/diagonalley/api/v1/markets',
+ this.g.user.wallets[0].inkey,
data
)
- .then(function (response) {
- self.shops.push(mapShops(response.data))
- self.shopDialog.show = false
- self.shopDialog.data = {}
+ .then((response) => {
+ this.shops.push(mapShops(response.data))
+ this.shopDialog.show = false
+ this.shopDialog.data = {}
data = {}
})
- .catch(function (error) {
+ .catch((error) => {
LNbits.utils.notifyApiError(error)
})
},
From c4509d726aef79e772f4e773fc2c920f067149e5 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:07:04 +0100
Subject: [PATCH 070/226] UI and checkout
---
coverage.xml | 13560 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 13560 insertions(+)
create mode 100644 coverage.xml
diff --git a/coverage.xml b/coverage.xml
new file mode 100644
index 00000000..dd7ec7b1
--- /dev/null
+++ b/coverage.xml
@@ -0,0 +1,13560 @@
+
+
+
+
+
+ /home/tvasconcelos/Work/lnbits/lnbits
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 0a54fe6db8349c36d1121cb446d0859133d799fb Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:07:23 +0100
Subject: [PATCH 071/226] ui and checkout
---
.../templates/diagonalley/stall.html | 36 ++++++++-----------
1 file changed, 14 insertions(+), 22 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index 226ecd2b..5638bc3d 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -112,9 +112,9 @@
-
- {{ item.stall }}
-
+
{{ item.price }} sats BTC {{ (item.price / 1e8).toFixed(8) }}
-
+
+ >
Update Product
-
-
Create Product Checkout
stall_ids.add(p.stall))
- console.log(stall_ids)
+ //let stall_ids = new Set()
+ //this.products.map(p => stall_ids.add(p.stall))
+
+ console.log(this.stall)
}
})
From d9242ddd5be6edc5d91e49828d4abcf789202c04 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:07:56 +0100
Subject: [PATCH 072/226] remove privatekey from stall
---
lnbits/extensions/diagonalley/views.py | 43 ++++++++++++++------------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 2ec75589..08c30428 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -3,11 +3,12 @@ from http import HTTPStatus
from fastapi import Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
+from starlette.exceptions import HTTPException
+from starlette.responses import HTMLResponse
+
from lnbits.core.models import User
from lnbits.decorators import check_user_exists # type: ignore
from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
-from starlette.exceptions import HTTPException
-from starlette.responses import HTMLResponse
from .crud import get_diagonalley_products, get_diagonalley_stall
@@ -30,29 +31,33 @@ async def display(request: Request, stall_id):
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
)
+
+ stall = stall.dict()
+ del stall["privatekey"]
+
return diagonalley_renderer().TemplateResponse(
"diagonalley/stall.html",
{
"request": request,
- "stall": stall.dict(),
+ "stall": stall,
"products": [product.dict() for product in products]
},
)
-@diagonalley_ext.get("/{market_id}", response_class=HTMLResponse)
-async def display(request: Request, stall_id):
- stalls = await get_diagonalley_stall(stall_id)
- products = await get_diagonalley_products(stall_id)
+# @diagonalley_ext.get("/market/{market_id}", response_class=HTMLResponse)
+# async def display(request: Request, stall_id):
+# stalls = await get_diagonalley_stall(stall_id)
+# products = await get_diagonalley_products(stall_id)
- if not stall:
- raise HTTPException(
- status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
- )
- return diagonalley_renderer().TemplateResponse(
- "diagonalley/stall.html",
- {
- "request": request,
- "stall": stall.dict(),
- "products": [product.dict() for product in products]
- },
- )
+# if not stall:
+# raise HTTPException(
+# status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
+# )
+# return diagonalley_renderer().TemplateResponse(
+# "diagonalley/stall.html",
+# {
+# "request": request,
+# "stall": stall.dict(),
+# "products": [product.dict() for product in products]
+# },
+# )
From 8032566f4491a3cf5caaf5e8d719e0de3b30be34 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:08:27 +0100
Subject: [PATCH 073/226] place order flow WIP
---
lnbits/extensions/diagonalley/crud.py | 45 +++++++++++++++------
lnbits/extensions/diagonalley/migrations.py | 9 ++---
lnbits/extensions/diagonalley/models.py | 21 ++++++++--
3 files changed, 53 insertions(+), 22 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index fbc1d332..b915c81d 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -13,11 +13,13 @@ from lnbits.settings import WALLET
from . import db
from .models import (
Market,
+ OrderDetail,
Orders,
Products,
Stalls,
Zones,
createOrder,
+ createOrderDetails,
createProduct,
createStalls,
createZones,
@@ -208,38 +210,55 @@ async def delete_diagonalley_stall(stall_id: str) -> None:
###Orders
-async def create_diagonalley_order(data: createOrder) -> Orders:
+async def create_diagonalley_order(wallet_id: str, data: createOrder) -> Orders:
order_id = urlsafe_short_hash()
await db.execute(
f"""
- INSERT INTO diagonalley.orders (id, productid, wallet, product,
- quantity, shippingzone, address, email, invoiceid, paid, shipped)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ INSERT INTO diagonalley.orders (id, wallet, shippingzone, address, email, total, invoiceid, paid, shipped)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
order_id,
- data.productid,
- data.wallet,
- data.product,
- data.quantity,
+ wallet_id,
data.shippingzone,
data.address,
data.email,
+ data.total,
data.invoiceid,
False,
False,
),
)
- # if db.type == SQLITE:
- # order_id = result._result_proxy.lastrowid
- # else:
- # order_id = result[0]
-
+
link = await get_diagonalley_order(order_id)
assert link, "Newly created link couldn't be retrieved"
return link
+async def create_diagonalley_order_details(order_id: str, data: List[createOrderDetails]):
+ for item in data:
+ item_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO diagonalley.order_details (id, orderid, productid, quantity)
+ VALUES (?, ?, ?, ?)
+ """,
+ (
+ item_id,
+ order_id,
+ item.product_id,
+ item.quantity,
+ ),
+ )
+ order_details = await get_diagonalley_order_details(order_id)
+ return order_details
+
+async def get_diagonalley_order_details(order_id: str) -> List[OrderDetail]:
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.order_details WHERE order_id = ?", (order_id,)
+ )
+
+ return [OrderDetail(**row) for row in rows]
async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
row = await db.fetchone(
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index e994d723..8a65df8a 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -56,12 +56,12 @@ async def m001_initial(db):
"""
CREATE TABLE diagonalley.orders (
id {db.serial_primary_key},
- productid TEXT NOT NULL,
- usr TEXT NOT NULL,
- pubkey TEXT NOT NULL,
+ wallet TEXT NOT NULL,
+ pubkey TEXT,
shippingzone INTEGER 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,
@@ -81,8 +81,7 @@ async def m001_initial(db):
id TEXT PRIMARY KEY,
orderid INTEGER NOT NULL REFERENCES {db.references_schema}orders (id)
productid TEXT NOT NULL REFERENCES {db.references_schema}products (id),
- quantity INTEGER NOT NULL,
- total INTEGER NOT NULL
+ quantity INTEGER NOT NULL
);
"""
)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 4fbf04ff..737f2b4b 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -55,16 +55,29 @@ class Zones(BaseModel):
cost: int
countries: str
+class OrderDetail(BaseModel):
+ id: str
+ order_id: str
+ product_id: str
+ quantity: int
+
+class createOrderDetails(BaseModel):
+ product_id: str = Query(...)
+ quantity: int = Query(..., ge=1)
+
class createOrder(BaseModel):
- productid: str = Query(...)
- stall: str = Query(...)
- product: str = Query(...)
- quantity: int = Query(..., ge=1)
+ wallet: str = Query(...)
+ pubkey: str = Query(None)
shippingzone: int = Query(...)
address: str = Query(...)
email: str = Query(...)
+ total: int = Query(...)
invoiceid: str = Query(...)
+ products: List[createOrderDetails]
+ # stall: str = Query(...)
+ # product: str = Query(...)
+ # quantity: int = Query(..., ge=1)
class Orders(BaseModel):
From 25d0309ff31d2e5563a02c4aa0f2fc1bbb09d3fc Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:07:23 +0100
Subject: [PATCH 074/226] ui and checkout
---
.../templates/diagonalley/stall.html | 36 ++++++++-----------
1 file changed, 14 insertions(+), 22 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index 226ecd2b..5638bc3d 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -112,9 +112,9 @@
-
- {{ item.stall }}
-
+
{{ item.price }} sats BTC {{ (item.price / 1e8).toFixed(8) }}
-
+
+ >
Update Product
-
-
Create Product Checkout
stall_ids.add(p.stall))
- console.log(stall_ids)
+ //let stall_ids = new Set()
+ //this.products.map(p => stall_ids.add(p.stall))
+
+ console.log(this.stall)
}
})
From 35cf441d91f46828069f0d10fc0af50a61281173 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:07:56 +0100
Subject: [PATCH 075/226] remove privatekey from stall
---
lnbits/extensions/diagonalley/views.py | 43 ++++++++++++++------------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 2ec75589..08c30428 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -3,11 +3,12 @@ from http import HTTPStatus
from fastapi import Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
+from starlette.exceptions import HTTPException
+from starlette.responses import HTMLResponse
+
from lnbits.core.models import User
from lnbits.decorators import check_user_exists # type: ignore
from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
-from starlette.exceptions import HTTPException
-from starlette.responses import HTMLResponse
from .crud import get_diagonalley_products, get_diagonalley_stall
@@ -30,29 +31,33 @@ async def display(request: Request, stall_id):
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
)
+
+ stall = stall.dict()
+ del stall["privatekey"]
+
return diagonalley_renderer().TemplateResponse(
"diagonalley/stall.html",
{
"request": request,
- "stall": stall.dict(),
+ "stall": stall,
"products": [product.dict() for product in products]
},
)
-@diagonalley_ext.get("/{market_id}", response_class=HTMLResponse)
-async def display(request: Request, stall_id):
- stalls = await get_diagonalley_stall(stall_id)
- products = await get_diagonalley_products(stall_id)
+# @diagonalley_ext.get("/market/{market_id}", response_class=HTMLResponse)
+# async def display(request: Request, stall_id):
+# stalls = await get_diagonalley_stall(stall_id)
+# products = await get_diagonalley_products(stall_id)
- if not stall:
- raise HTTPException(
- status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
- )
- return diagonalley_renderer().TemplateResponse(
- "diagonalley/stall.html",
- {
- "request": request,
- "stall": stall.dict(),
- "products": [product.dict() for product in products]
- },
- )
+# if not stall:
+# raise HTTPException(
+# status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
+# )
+# return diagonalley_renderer().TemplateResponse(
+# "diagonalley/stall.html",
+# {
+# "request": request,
+# "stall": stall.dict(),
+# "products": [product.dict() for product in products]
+# },
+# )
From 777b9bef1ba4a8b16658a05f6a02d0e9e6bc1060 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:08:27 +0100
Subject: [PATCH 076/226] place order flow WIP
---
lnbits/extensions/diagonalley/crud.py | 45 +++++++++++++++------
lnbits/extensions/diagonalley/migrations.py | 9 ++---
lnbits/extensions/diagonalley/models.py | 21 ++++++++--
3 files changed, 53 insertions(+), 22 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index fbc1d332..b915c81d 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -13,11 +13,13 @@ from lnbits.settings import WALLET
from . import db
from .models import (
Market,
+ OrderDetail,
Orders,
Products,
Stalls,
Zones,
createOrder,
+ createOrderDetails,
createProduct,
createStalls,
createZones,
@@ -208,38 +210,55 @@ async def delete_diagonalley_stall(stall_id: str) -> None:
###Orders
-async def create_diagonalley_order(data: createOrder) -> Orders:
+async def create_diagonalley_order(wallet_id: str, data: createOrder) -> Orders:
order_id = urlsafe_short_hash()
await db.execute(
f"""
- INSERT INTO diagonalley.orders (id, productid, wallet, product,
- quantity, shippingzone, address, email, invoiceid, paid, shipped)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ INSERT INTO diagonalley.orders (id, wallet, shippingzone, address, email, total, invoiceid, paid, shipped)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
order_id,
- data.productid,
- data.wallet,
- data.product,
- data.quantity,
+ wallet_id,
data.shippingzone,
data.address,
data.email,
+ data.total,
data.invoiceid,
False,
False,
),
)
- # if db.type == SQLITE:
- # order_id = result._result_proxy.lastrowid
- # else:
- # order_id = result[0]
-
+
link = await get_diagonalley_order(order_id)
assert link, "Newly created link couldn't be retrieved"
return link
+async def create_diagonalley_order_details(order_id: str, data: List[createOrderDetails]):
+ for item in data:
+ item_id = urlsafe_short_hash()
+ await db.execute(
+ """
+ INSERT INTO diagonalley.order_details (id, orderid, productid, quantity)
+ VALUES (?, ?, ?, ?)
+ """,
+ (
+ item_id,
+ order_id,
+ item.product_id,
+ item.quantity,
+ ),
+ )
+ order_details = await get_diagonalley_order_details(order_id)
+ return order_details
+
+async def get_diagonalley_order_details(order_id: str) -> List[OrderDetail]:
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.order_details WHERE order_id = ?", (order_id,)
+ )
+
+ return [OrderDetail(**row) for row in rows]
async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
row = await db.fetchone(
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index e994d723..8a65df8a 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -56,12 +56,12 @@ async def m001_initial(db):
"""
CREATE TABLE diagonalley.orders (
id {db.serial_primary_key},
- productid TEXT NOT NULL,
- usr TEXT NOT NULL,
- pubkey TEXT NOT NULL,
+ wallet TEXT NOT NULL,
+ pubkey TEXT,
shippingzone INTEGER 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,
@@ -81,8 +81,7 @@ async def m001_initial(db):
id TEXT PRIMARY KEY,
orderid INTEGER NOT NULL REFERENCES {db.references_schema}orders (id)
productid TEXT NOT NULL REFERENCES {db.references_schema}products (id),
- quantity INTEGER NOT NULL,
- total INTEGER NOT NULL
+ quantity INTEGER NOT NULL
);
"""
)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 4fbf04ff..737f2b4b 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -55,16 +55,29 @@ class Zones(BaseModel):
cost: int
countries: str
+class OrderDetail(BaseModel):
+ id: str
+ order_id: str
+ product_id: str
+ quantity: int
+
+class createOrderDetails(BaseModel):
+ product_id: str = Query(...)
+ quantity: int = Query(..., ge=1)
+
class createOrder(BaseModel):
- productid: str = Query(...)
- stall: str = Query(...)
- product: str = Query(...)
- quantity: int = Query(..., ge=1)
+ wallet: str = Query(...)
+ pubkey: str = Query(None)
shippingzone: int = Query(...)
address: str = Query(...)
email: str = Query(...)
+ total: int = Query(...)
invoiceid: str = Query(...)
+ products: List[createOrderDetails]
+ # stall: str = Query(...)
+ # product: str = Query(...)
+ # quantity: int = Query(..., ge=1)
class Orders(BaseModel):
From 58b046254ff1bfef39f6e8f4395f762247c8def1 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 16 Aug 2022 12:19:31 +0100
Subject: [PATCH 077/226] make format diagonalley
---
lnbits/extensions/diagonalley/__init__.py | 4 +-
lnbits/extensions/diagonalley/crud.py | 19 +-
lnbits/extensions/diagonalley/migrations.py | 1 -
lnbits/extensions/diagonalley/models.py | 4 +
.../templates/diagonalley/_api_docs.html | 42 +-
.../templates/diagonalley/index.html | 1916 +++++++++--------
lnbits/extensions/diagonalley/views.py | 5 +-
lnbits/extensions/diagonalley/views_api.py | 24 +-
8 files changed, 1037 insertions(+), 978 deletions(-)
diff --git a/lnbits/extensions/diagonalley/__init__.py b/lnbits/extensions/diagonalley/__init__.py
index 23c02a5f..ec193e3a 100644
--- a/lnbits/extensions/diagonalley/__init__.py
+++ b/lnbits/extensions/diagonalley/__init__.py
@@ -1,10 +1,11 @@
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
-from starlette.staticfiles import StaticFiles
db = Database("ext_diagonalley")
@@ -26,6 +27,7 @@ diagonalley_static_files = [
# )
# else:
+
def diagonalley_renderer():
return template_renderer(["lnbits/extensions/diagonalley/templates"])
# return template_renderer(["lnbits/extensions/diagonalley/templates"])
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index b915c81d..8016fd07 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -230,12 +230,15 @@ async def create_diagonalley_order(wallet_id: str, data: createOrder) -> Orders:
False,
),
)
-
+
link = await get_diagonalley_order(order_id)
assert link, "Newly created link couldn't be retrieved"
return link
-async def create_diagonalley_order_details(order_id: str, data: List[createOrderDetails]):
+
+async def create_diagonalley_order_details(
+ order_id: str, data: List[createOrderDetails]
+):
for item in data:
item_id = urlsafe_short_hash()
await db.execute(
@@ -253,6 +256,7 @@ async def create_diagonalley_order_details(order_id: str, data: List[createOrder
order_details = await get_diagonalley_order_details(order_id)
return order_details
+
async def get_diagonalley_order_details(order_id: str) -> List[OrderDetail]:
rows = await db.fetchall(
f"SELECT * FROM diagonalley.order_details WHERE order_id = ?", (order_id,)
@@ -260,6 +264,7 @@ async def get_diagonalley_order_details(order_id: str) -> List[OrderDetail]:
return [OrderDetail(**row) for row in rows]
+
async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
row = await db.fetchone(
"SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
@@ -282,18 +287,18 @@ async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orde
async def delete_diagonalley_order(order_id: str) -> None:
await db.execute("DELETE FROM diagonalley.orders WHERE id = ?", (order_id,))
+
### Market/Marketplace
+
async def get_diagonalley_markets(user: str) -> List[Market]:
- rows = await db.fetchall(
- 'SELECT * FROM diagonalley.markets WHERE usr = ?', (user,)
- )
+ rows = await db.fetchall("SELECT * FROM diagonalley.markets WHERE usr = ?", (user,))
return [Market(**row) for row in rows]
async def get_diagonalley_market(market_id: str) -> Optional[Market]:
row = await db.fetchone(
- 'SELECT * FROM diagonalley.markets WHERE id = ?', (market_id,)
+ "SELECT * FROM diagonalley.markets WHERE id = ?", (market_id,)
)
Market(**row) if row else None
@@ -303,5 +308,3 @@ async def get_diagonalley_market_stalls(market_id: str):
"SELECT * FROM diagonalley.market_stalls WHERE marketid = ?", (market_id,)
)
return [Stalls(**row) for row in rows]
-
-
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index 8a65df8a..a7380b65 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -111,4 +111,3 @@ async def m001_initial(db):
);
"""
)
-
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 737f2b4b..f07e9c80 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -55,12 +55,14 @@ class Zones(BaseModel):
cost: int
countries: str
+
class OrderDetail(BaseModel):
id: str
order_id: str
product_id: str
quantity: int
+
class createOrderDetails(BaseModel):
product_id: str = Query(...)
quantity: int = Query(..., ge=1)
@@ -95,11 +97,13 @@ class Orders(BaseModel):
shipped: bool
time: int
+
class CreateMarket(BaseModel):
usr: str = Query(...)
name: str = Query(None)
stalls: List[str] = Query(...)
+
class Market(BaseModel):
id: str
usr: str
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html b/lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html
index 530c89e8..5418deba 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/_api_docs.html
@@ -9,26 +9,28 @@
Diagon Alley: Decentralised Market-Stalls
-
- Each Stall has its own keys!
-
- Create Shipping Zones you're willing to ship to
- Create a Stall to list yiur products on
- Create products to put on the Stall
- List stalls on a simple frontend shop page, or point at Nostr shop client key
-
- Make a list of products to sell, point your list of products at a public
- relay. Buyers browse your products on the relay, and pay you directly.
- Ratings are managed by the relay. Your stall can be listed in multiple
- relays, even over TOR, if you wish to be anonymous.
- More information on the
- Diagon Alley Protocol
-
- Created by, Ben Arc
-
+ Each Stall has its own keys!
+
+
+ Create Shipping Zones you're willing to ship to
+ Create a Stall to list yiur products on
+ Create products to put on the Stall
+
+ List stalls on a simple frontend shop page, or point at Nostr shop
+ client key
+
+
+ Make a list of products to sell, point your list of products at a public
+ relay. Buyers browse your products on the relay, and pay you directly.
+ Ratings are managed by the relay. Your stall can be listed in multiple
+ relays, even over TOR, if you wish to be anonymous.
+ More information on the
+ Diagon Alley Protocol
+
+ Created by, Ben Arc
+
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 893830a9..5482cd3f 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -28,7 +28,7 @@
label="Description"
>
-
-
-
-
+
+
+
Create Product
-
Cancel
@@ -162,7 +167,12 @@
>Create Shipping Zone
- Cancel
@@ -174,10 +184,10 @@
+ label="Activate shop"
+ color="primary"
+ v-model="marketDialog.data.activate"
+ >
Launch
-
Cancel
@@ -284,7 +299,9 @@
v-model.trim="stallDialog.data.nostrShops"
label="Nostr shop public keys (seperate by comma)"
> -->
- Nostr support coming soon!
+
+ Nostr support coming soon!
+
Create Store
- Cancel
@@ -313,33 +335,50 @@
-
- + Product List a product
- + Product List a product
+ Shipping Zone Create a shipping zone
- + Store
Create a stall to list products on
- + Store
Create a store to list products on
Launch frontend shop (not Nostr)
- Makes a simple frontend shop for your stalls
+ Makes a simple frontend shop for your stalls
-
-
-
+
+
+
@@ -403,7 +442,8 @@
-
+
+
@@ -482,8 +522,9 @@
-
-
+
+
+
@@ -555,8 +596,9 @@
-
-
+
+
+
@@ -632,14 +674,18 @@
Messages
-
+
-
+
-
+
@@ -648,14 +694,11 @@
:text="[message[1]]"
sent
>
-
-
+
+
-
+
@@ -665,934 +708,935 @@
-
-
+
{% endblock %} {% block scripts %} {{ window_vars(user) }}
{% endblock %}
-
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 08c30428..30dbebe7 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -34,16 +34,17 @@ async def display(request: Request, stall_id):
stall = stall.dict()
del stall["privatekey"]
-
+
return diagonalley_renderer().TemplateResponse(
"diagonalley/stall.html",
{
"request": request,
"stall": stall,
- "products": [product.dict() for product in products]
+ "products": [product.dict() for product in products],
},
)
+
# @diagonalley_ext.get("/market/{market_id}", response_class=HTMLResponse)
# async def display(request: Request, stall_id):
# stalls = await get_diagonalley_stall(stall_id)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index b2fb5a47..cedd1d42 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -5,6 +5,8 @@ from uuid import uuid4
from fastapi import Request
from fastapi.param_functions import Query
from fastapi.params import Depends
+from starlette.exceptions import HTTPException
+
from lnbits.core.crud import get_user
from lnbits.core.services import create_invoice
from lnbits.decorators import (
@@ -13,7 +15,6 @@ from lnbits.decorators import (
require_admin_key,
require_invoice_key,
)
-from starlette.exceptions import HTTPException
from . import db, diagonalley_ext
from .crud import (
@@ -94,22 +95,22 @@ async def api_diagonalley_products(
@diagonalley_ext.post("/api/v1/products")
@diagonalley_ext.put("/api/v1/products/{product_id}")
async def api_diagonalley_product_create(
- data: createProduct, product_id = None, wallet: WalletTypeInfo = Depends(get_key_type)
+ data: createProduct, product_id=None, wallet: WalletTypeInfo = Depends(get_key_type)
):
if product_id:
- product = await get_diagonalley_product(product_id)
+ product = await get_diagonalley_product(product_id)
if not product:
return {"message": "Withdraw product does not exist."}
-
- stall = await get_diagonalley_stall(stall_id = product.stall)
+
+ stall = await get_diagonalley_stall(stall_id=product.stall)
if stall.wallet != wallet.wallet.id:
return {"message": "Not your withdraw product."}
product = await update_diagonalley_product(product_id, **data.dict())
else:
product = await create_diagonalley_product(data=data)
-
+
return product.dict()
@@ -392,15 +393,18 @@ async def api_diagonalley_stall_order(
# MARKETS
##
+
@diagonalley_ext.get("/api/v1/markets")
-async def api_diagonalley_orders(
- wallet: WalletTypeInfo = Depends(get_key_type)
-):
+async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
try:
- return [market.dict() for market in await get_diagonalley_markets(wallet.wallet.user)]
+ return [
+ market.dict()
+ for market in await get_diagonalley_markets(wallet.wallet.user)
+ ]
except:
return {"message": "We could not retrieve the markets."}
+
@diagonalley_ext.post("/api/v1/markets")
@diagonalley_ext.put("/api/v1/markets/{market_id}")
async def api_diagonalley_stall_create(
From 4cd86d0dafb8b989ccdd601f9891a14e1991a433 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 18 Aug 2022 10:49:04 +0100
Subject: [PATCH 078/226] create order
---
lnbits/extensions/diagonalley/crud.py | 30 ++++----
lnbits/extensions/diagonalley/migrations.py | 20 ++---
lnbits/extensions/diagonalley/models.py | 8 +-
.../templates/diagonalley/stall.html | 75 ++++++++++++++-----
lnbits/extensions/diagonalley/views.py | 16 +++-
lnbits/extensions/diagonalley/views_api.py | 25 ++++++-
6 files changed, 124 insertions(+), 50 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 8016fd07..798705bf 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -210,30 +210,34 @@ async def delete_diagonalley_stall(stall_id: str) -> None:
###Orders
-async def create_diagonalley_order(wallet_id: str, data: createOrder) -> Orders:
+async def create_diagonalley_order(data: createOrder, invoiceid: str) -> Orders:
+ returning = "" if db.type == SQLITE else "RETURNING ID"
+ method = db.execute if db.type == SQLITE else db.fetchone
- order_id = urlsafe_short_hash()
- await db.execute(
+ result = await (method)(
f"""
- INSERT INTO diagonalley.orders (id, wallet, shippingzone, address, email, total, invoiceid, paid, shipped)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ INSERT INTO diagonalley.orders (wallet, shippingzone, address, email, total, invoiceid, paid, shipped)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ {returning}
""",
(
- order_id,
- wallet_id,
+ data.wallet,
data.shippingzone,
data.address,
data.email,
data.total,
- data.invoiceid,
+ invoiceid,
False,
False,
),
)
-
- link = await get_diagonalley_order(order_id)
- assert link, "Newly created link couldn't be retrieved"
- return link
+ if db.type == SQLITE:
+ return result._result_proxy.lastrowid
+ else:
+ return result[0]
+ # link = await get_diagonalley_order(link.id)
+ # assert link, "Newly created link couldn't be retrieved"
+ # return link
async def create_diagonalley_order_details(
@@ -243,7 +247,7 @@ async def create_diagonalley_order_details(
item_id = urlsafe_short_hash()
await db.execute(
"""
- INSERT INTO diagonalley.order_details (id, orderid, productid, quantity)
+ INSERT INTO diagonalley.order_details (id, order_id, product_id, quantity)
VALUES (?, ?, ?, ?)
""",
(
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index a7380b65..6e1510a7 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -11,7 +11,8 @@ async def m001_initial(db):
publickey TEXT,
privatekey TEXT,
relays TEXT,
- shippingzones TEXT NOT NULL
+ shippingzones TEXT NOT NULL,
+ rating INTEGER DEFAULT 0
);
"""
)
@@ -20,7 +21,7 @@ async def m001_initial(db):
Initial products table.
"""
await db.execute(
- """
+ f"""
CREATE TABLE diagonalley.products (
id TEXT PRIMARY KEY,
stall TEXT NOT NULL REFERENCES {db.references_schema}stalls (id),
@@ -30,7 +31,7 @@ async def m001_initial(db):
image TEXT,
price INTEGER NOT NULL,
quantity INTEGER NOT NULL,
- rating INTEGER NOT NULL
+ rating INTEGER DEFAULT 0
);
"""
)
@@ -53,12 +54,13 @@ async def m001_initial(db):
Initial orders table.
"""
await db.execute(
- """
+ f"""
CREATE TABLE diagonalley.orders (
id {db.serial_primary_key},
wallet TEXT NOT NULL,
+ username TEXT,
pubkey TEXT,
- shippingzone INTEGER NOT NULL,
+ shippingzone TEXT NOT NULL,
address TEXT NOT NULL,
email TEXT NOT NULL,
total INTEGER NOT NULL,
@@ -76,11 +78,11 @@ async def m001_initial(db):
Initial order details table.
"""
await db.execute(
- """
+ f"""
CREATE TABLE diagonalley.order_details (
id TEXT PRIMARY KEY,
- orderid INTEGER NOT NULL REFERENCES {db.references_schema}orders (id)
- productid TEXT NOT NULL REFERENCES {db.references_schema}products (id),
+ order_id INTEGER NOT NULL REFERENCES {db.references_schema}orders (id),
+ product_id TEXT NOT NULL REFERENCES {db.references_schema}products (id),
quantity INTEGER NOT NULL
);
"""
@@ -103,7 +105,7 @@ async def m001_initial(db):
Initial market stalls table.
"""
await db.execute(
- """
+ f"""
CREATE TABLE diagonalley.market_stalls (
id TEXT PRIMARY KEY,
marketid TEXT NOT NULL REFERENCES {db.references_schema}markets (id),
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index f07e9c80..82115be9 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -71,15 +71,11 @@ class createOrderDetails(BaseModel):
class createOrder(BaseModel):
wallet: str = Query(...)
pubkey: str = Query(None)
- shippingzone: int = Query(...)
+ shippingzone: str = Query(...)
address: str = Query(...)
email: str = Query(...)
total: int = Query(...)
- invoiceid: str = Query(...)
products: List[createOrderDetails]
- # stall: str = Query(...)
- # product: str = Query(...)
- # quantity: int = Query(..., ge=1)
class Orders(BaseModel):
@@ -89,7 +85,7 @@ class Orders(BaseModel):
pubkey: str
product: str
quantity: int
- shippingzone: int
+ shippingzone: str
address: str
email: str
invoiceid: str
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index 5638bc3d..28f6ad22 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -80,7 +80,7 @@
alt="Product Image"
loading="lazy"
spinner-color="white"
- fit="cover"
+ fit="contain"
height="300px"
>
@@ -166,15 +166,15 @@
-
+ > -->
+ Select the shipping zone:
+
+
+
+
+ {% raw %} Total: {{ finalCost }} {% endraw %}
+
Checkout
-
z.value == this.checkoutDialog.data.shippingzone
+ )
+
+ return this.cart.total + zoneCost.cost
}
},
methods: {
+ resetCart() {
+ this.cart = {
+ total: 0,
+ size: 0,
+ products: new Map()
+ }
+ },
addToCart(item) {
let prod = this.cart.products
if (prod.has(item.id)) {
@@ -266,17 +294,28 @@
this.cartMenu = Array.from(this.cart.products, item => {
return {id: item[0], ...item[1]}
})
- console.log(this.cartMenu)
+ console.log(this.cartMenu, this.cart)
},
placeOrder() {
- // productid: str = Query(...)
- // stall: str = Query(...)
- // product: str = Query(...)
- // quantity: int = Query(..., ge=1)
- // shippingzone: int = Query(...)
- // address: str = Query(...)
- // email: str = Query(...)
- // invoiceid: str = Query(...)
+ let dialog = this.checkoutDialog.data
+ let data = {
+ ...this.checkoutDialog.data,
+ wallet: this.stall.wallet,
+ total: this.finalCost,
+ products: Array.from(this.cart.products, p => {
+ return {product_id: p[0], quantity: p[1].quantity}
+ })
+ }
+
+ LNbits.api
+ .request('POST', '/diagonalley/api/v1/orders', null, data)
+ .then(res => {
+ this.checkoutDialog = {show: false, data: {}}
+ this.resetCart()
+ console.log(res.data)
+ })
+ .catch(error => LNbits.utils.notifyApiError(error))
+
return
}
},
@@ -287,7 +326,7 @@
//let stall_ids = new Set()
//this.products.map(p => stall_ids.add(p.stall))
- console.log(this.stall)
+ console.log(this.stall, this.products)
}
})
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 30dbebe7..f4446482 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -3,6 +3,7 @@ from http import HTTPStatus
from fastapi import Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
+from loguru import logger
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse
@@ -10,7 +11,12 @@ from lnbits.core.models import User
from lnbits.decorators import check_user_exists # type: ignore
from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
-from .crud import get_diagonalley_products, get_diagonalley_stall
+from .crud import (
+ get_diagonalley_products,
+ get_diagonalley_stall,
+ get_diagonalley_zone,
+ get_diagonalley_zones,
+)
templates = Jinja2Templates(directory="templates")
@@ -26,6 +32,13 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
async def display(request: Request, stall_id):
stall = await get_diagonalley_stall(stall_id)
products = await get_diagonalley_products(stall_id)
+ zones = []
+ for id in stall.shippingzones.split(","):
+ z = await get_diagonalley_zone(id)
+ z = z.dict()
+ zones.append({"label": z["countries"], "cost": z["cost"], "value": z["id"]})
+
+ logger.debug(f"ZONES {zones}")
if not stall:
raise HTTPException(
@@ -34,6 +47,7 @@ async def display(request: Request, stall_id):
stall = stall.dict()
del stall["privatekey"]
+ stall["zones"] = zones
return diagonalley_renderer().TemplateResponse(
"diagonalley/stall.html",
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index cedd1d42..fd474f4a 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -5,6 +5,7 @@ from uuid import uuid4
from fastapi import Request
from fastapi.param_functions import Query
from fastapi.params import Depends
+from loguru import logger
from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
@@ -16,9 +17,11 @@ from lnbits.decorators import (
require_invoice_key,
)
+from ...helpers import urlsafe_short_hash
from . import db, diagonalley_ext
from .crud import (
create_diagonalley_order,
+ create_diagonalley_order_details,
create_diagonalley_product,
create_diagonalley_stall,
create_diagonalley_zone,
@@ -254,10 +257,26 @@ async def api_diagonalley_orders(
@diagonalley_ext.post("/api/v1/orders")
async def api_diagonalley_order_create(
- data: createOrder, wallet: WalletTypeInfo = Depends(get_key_type)
+ data: createOrder
):
- order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data=data)
- return order.dict()
+ ref = urlsafe_short_hash()
+
+ payment_hash, payment_request = await create_invoice(
+ wallet_id=data.wallet,
+ amount=data.total,
+ memo=f"New order on Diagon alley",
+ extra={
+ "tag": "diagonalley",
+ "reference": ref,
+ }
+ )
+ order_id = await create_diagonalley_order(invoiceid=payment_hash, data=data)
+ logger.debug(f"ORDER ID {order_id}")
+ logger.debug(f"PRODUCTS {data.products}")
+ await create_diagonalley_order_details(order_id=order_id, data=data.products)
+ return {"payment_hash": payment_hash, "payment_request": payment_request, "order_reference": ref}
+ # order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data=data)
+ # return order.dict()
@diagonalley_ext.delete("/api/v1/orders/{order_id}")
From d6fe562067e7b827531d1a824b19d7fcf97a71e1 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 18 Aug 2022 16:18:07 +0100
Subject: [PATCH 079/226] have orders show on user page and invoice init
---
lnbits/extensions/diagonalley/models.py | 9 +-
.../templates/diagonalley/index.html | 99 +++++++++++++++----
.../templates/diagonalley/stall.html | 85 +++++++++++++++-
lnbits/extensions/diagonalley/views.py | 3 +
lnbits/extensions/diagonalley/views_api.py | 29 ++----
5 files changed, 178 insertions(+), 47 deletions(-)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 82115be9..e6516037 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -80,14 +80,13 @@ class createOrder(BaseModel):
class Orders(BaseModel):
id: str
- productid: str
- stall: str
- pubkey: str
- product: str
- quantity: int
+ wallet: str
+ username: Optional[str]
+ pubkey: Optional[str]
shippingzone: str
address: str
email: str
+ total: int
invoiceid: str
paid: bool
shipped: bool
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 5482cd3f..516544ea 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -401,6 +401,7 @@
{% raw %}
+
{{ col.label }}
@@ -409,6 +410,16 @@
+
+
+
{{ col.value }}
@@ -436,6 +447,61 @@
>
+
+
+
+
+
+ Order Details
+
+
+
+ Products
+ {{ products.length && (_.findWhere(products, {id:
+ col.product_id})).product }}
+ Quantity: {{ col.quantity }}
+
+
+
+
+
+ Shipping to
+ {{ props.row.address }}
+
+
+
+
+
+ User info
+ {{ props.row.username }}
+ {{ props.row.email }}
+ {{ props.row.pubkey }}
+
+
+
+
+ Total
+ {{ props.row.total }}
+
+
+
+
+
+
+
+
{% endraw %}
@@ -724,7 +790,6 @@
}
const mapProducts = obj => {
obj._data = _.clone(obj)
- console.log(obj)
return obj
}
const mapZone = obj => {
@@ -733,6 +798,10 @@
}
const mapOrders = obj => {
obj._data = _.clone(obj)
+ obj.time = Quasar.utils.date.formatDate(
+ new Date(obj.time * 1000),
+ 'YYYY-MM-DD HH:mm'
+ )
return obj
}
const mapKeys = obj => {
@@ -822,7 +891,7 @@
label: '',
ordersTable: {
columns: [
- {
+ /*{
name: 'product',
align: 'left',
label: 'Product',
@@ -833,12 +902,18 @@
align: 'left',
label: 'Quantity',
field: 'quantity'
+ },*/
+ {
+ name: 'id',
+ align: 'left',
+ label: 'ID',
+ field: 'id'
},
{
- name: 'address',
+ name: 'time',
align: 'left',
- label: 'Address',
- field: 'address'
+ label: 'Date',
+ field: 'time'
},
{
name: 'invoiceid',
@@ -1037,7 +1112,6 @@
////////////////STALLS//////////////////
////////////////////////////////////////
getStalls: function () {
- console.log(this.g.user)
var self = this
LNbits.api
.request(
@@ -1048,7 +1122,6 @@
.then(function (response) {
if (response.data) {
self.stalls = response.data.map(mapStalls)
- console.log(self.stalls)
}
})
.catch(function (error) {
@@ -1072,7 +1145,6 @@
this.stallDialog.data.shippingzones = shippingzones //this.stallDialog.data.shippingzones.split(",")
- console.log(this.stallDialog.data)
//let zones = this.zoneOptions
// .filter(z => z.id == )
this.stallDialog.show = true
@@ -1096,7 +1168,6 @@
}
},
updateStall: function (data) {
- console.log(data)
var self = this
LNbits.api
.request(
@@ -1179,7 +1250,6 @@
self.g.user.wallets[0].inkey
)
.then(function (response) {
- console.log('RESP DATA', response.data)
if (response.data) {
self.products = response.data.map(mapProducts)
}
@@ -1271,7 +1341,6 @@
let self = this
const walletId = _.findWhere(this.stalls, {id: data.stall}).wallet
- console.log('DATA', walletId, data)
LNbits.api
.request(
'POST',
@@ -1280,7 +1349,6 @@
data
)
.then(response => {
- console.log(response)
self.products.push(mapProducts(response.data))
self.resetDialog('productDialog')
})
@@ -1328,7 +1396,6 @@
)
.then(function (response) {
if (response.data) {
- console.log(response)
self.zones = response.data.map(mapZone)
}
})
@@ -1360,7 +1427,6 @@
}
},
updateZone: function (data) {
- console.log(data)
var self = this
LNbits.api
.request(
@@ -1370,7 +1436,6 @@
data
)
.then(function (response) {
- console.log(response)
self.zones = _.reject(self.zones, function (obj) {
return obj.id == data.id
})
@@ -1492,7 +1557,6 @@
})
},
createShop(data) {
- console.log('data')
LNbits.api
.request(
'POST',
@@ -1551,6 +1615,7 @@
.then(function (response) {
if (response.data) {
self.orders = response.data.map(mapOrders)
+ console.log(self.orders)
}
})
.catch(function (error) {
@@ -1629,7 +1694,7 @@
this.getProducts()
this.getZones()
this.getOrders()
- this.getMarkets()
+ //this.getMarkets() # NOT YET IMPLEMENTED
this.customerKeys = [
'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index 28f6ad22..b33feb2a 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -216,6 +216,31 @@
+
+
+
+
+
+
+
+
+
+ Copy Invoice
+
+
{% endblock %} {% block scripts %}
-{% endblock %}
diff --git a/lnbits/extensions/nostradmin/views.py b/lnbits/extensions/nostradmin/views.py
deleted file mode 100644
index 705feba7..00000000
--- a/lnbits/extensions/nostradmin/views.py
+++ /dev/null
@@ -1,110 +0,0 @@
-from http import HTTPStatus
-import asyncio
-from fastapi import Request
-from fastapi.param_functions import Query
-from fastapi.params import Depends
-from fastapi.templating import Jinja2Templates
-from starlette.exceptions import HTTPException
-from starlette.responses import HTMLResponse
-from . import nostradmin_ext, nostr_renderer
-# FastAPI good for incoming
-from fastapi import Request, WebSocket, WebSocketDisconnect
-# Websockets needed for outgoing
-import websockets
-
-from lnbits.core.crud import update_payment_status
-from lnbits.core.models import User
-from lnbits.core.views.api import api_payment
-from lnbits.decorators import check_user_exists
-
-from .crud import get_nostrkeys, get_nostrrelay
-from .relay_manager import RelayManager, Relay
-
-templates = Jinja2Templates(directory="templates")
-
-nostradmin = True
-
-@nostradmin_ext.get("/", response_class=HTMLResponse)
-async def index(request: Request, user: User = Depends(check_user_exists)):
- return nostr_renderer().TemplateResponse(
- "nostradmin/index.html", {"request": request, "user": user.dict()}
- )
-
-#####################################################################
-#################### NOSTR WEBSOCKET THREAD #########################
-##### THE QUEUE LOOP THREAD THING THAT LISTENS TO BUNCH OF ##########
-### WEBSOCKET CONNECTIONS, STORING DATA IN DB/PUSHING TO FRONTEND ###
-################### VIA updater() FUNCTION ##########################
-#####################################################################
-
-websocket_queue = asyncio.Queue(1000)
-
-
-mgr: RelayManager = RelayManager(enable_ws_debugger=False)
-
-# listen for events coming from relays
-
-
-async def connectToNostr():
- while True:
- e = await mgr.msg_channel.get()
- print(e)
-connectToNostr
-#####################################################################
-################### LNBITS WEBSOCKET ROUTES #########################
-#### HERE IS WHERE LNBITS FRONTEND CAN RECEIVE AND SEND MESSAGES ####
-#####################################################################
-
-class ConnectionManager:
- def __init__(self):
- self.active_connections: List[WebSocket] = []
-
- async def connect(self, websocket: WebSocket, nostr_id: str):
- await websocket.accept()
- websocket.id = nostr_id
- self.active_connections.append(websocket)
-
- def disconnect(self, websocket: WebSocket):
- self.active_connections.remove(websocket)
-
- async def send_personal_message(self, message: str, nostr_id: str):
- for connection in self.active_connections:
- if connection.id == nostr_id:
- await connection.send_text(message)
-
- async def broadcast(self, message: str):
- for connection in self.active_connections:
- await connection.send_text(message)
-
-
-manager = ConnectionManager()
-
-
-@nostradmin_ext.websocket("/nostradmin/ws/relayevents/{nostr_id}", name="nostr_id.websocket_by_id")
-async def websocket_endpoint(websocket: WebSocket, nostr_id: str):
- await manager.connect(websocket, nostr_id)
- try:
- while True:
- data = await websocket.receive_text()
- except WebSocketDisconnect:
- manager.disconnect(websocket)
-
-
-async def updater(nostr_id, message):
- copilot = await get_copilot(nostr_id)
- if not copilot:
- return
- await manager.send_personal_message(f"{message}", nostr_id)
-
-
-async def relay_check(relay: str):
- async with websockets.connect(relay) as websocket:
- if str(websocket.state) == "State.OPEN":
- r = Relay(url=relay, read=True, write=True, active=True)
- try:
- await mgr.add_relay(r)
- except:
- None
- return True
- else:
- return False
\ No newline at end of file
diff --git a/lnbits/extensions/nostradmin/views_api.py b/lnbits/extensions/nostradmin/views_api.py
deleted file mode 100644
index 4ff89704..00000000
--- a/lnbits/extensions/nostradmin/views_api.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from http import HTTPStatus
-import asyncio
-from fastapi import Request
-from fastapi.param_functions import Query
-from fastapi.params import Depends
-from starlette.exceptions import HTTPException
-
-from lnbits.core.crud import get_user
-from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
-from lnbits.utils.exchange_rates import currencies
-
-from lnbits.settings import LNBITS_ADMIN_USERS
-from . import nostradmin_ext
-from .crud import (
- create_nostrkeys,
- get_nostrkeys,
- create_nostrnotes,
- get_nostrnotes,
- create_nostrrelays,
- get_nostrrelays,
- get_nostrrelaylist,
- update_nostrrelaysetlist,
- create_nostrconnections,
- get_nostrconnections,
-)
-from .models import nostrKeys, nostrCreateRelays, nostrRelaySetList
-from .views import relay_check
-
-@nostradmin_ext.get("/api/v1/relays")
-async def api_relays_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
- relays = await get_nostrrelays()
- if not relays:
- await create_nostrrelays(nostrCreateRelays(relay="wss://relayer.fiatjaf.com"))
- await create_nostrrelays(
- nostrCreateRelays(relay="wss://nostr-pub.wellorder.net")
- )
- relays = await get_nostrrelays()
- if not relays:
- raise HTTPException(
- status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
- )
- else:
- for relay in relays:
- relay.status = await relay_check(relay.relay)
- return relays
-
-
-
-@nostradmin_ext.get("/api/v1/relaylist")
-async def api_relaylist(wallet: WalletTypeInfo = Depends(get_key_type)):
- if wallet.wallet.user not in LNBITS_ADMIN_USERS:
- raise HTTPException(
- status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
- )
- return await get_nostrrelaylist()
-
-@nostradmin_ext.post("/api/v1/setlist")
-async def api_relayssetlist(data: nostrRelaySetList, wallet: WalletTypeInfo = Depends(get_key_type)):
- if wallet.wallet.user not in LNBITS_ADMIN_USERS:
- raise HTTPException(
- status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
- )
- return await update_nostrrelaysetlist(data)
\ No newline at end of file
From a5c6b1135c77930315a211a822ee2638a53217d3 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 19 Aug 2022 11:19:45 +0100
Subject: [PATCH 082/226] order paying works
---
lnbits/extensions/diagonalley/crud.py | 15 ++
lnbits/extensions/diagonalley/tasks.py | 19 +++
.../templates/diagonalley/stall.html | 146 +++++++++---------
lnbits/extensions/diagonalley/views.py | 4 -
lnbits/extensions/diagonalley/views_api.py | 17 ++
5 files changed, 123 insertions(+), 78 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 798705bf..0a825ca3 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -275,6 +275,21 @@ async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
)
return Orders(**row) if row else None
+async def get_diagonalley_order_invoiceid(invoice_id: str) -> Optional[Orders]:
+ row = await db.fetchone(
+ "SELECT * FROM diagonalley.orders WHERE invoiceid = ?", (invoice_id,)
+ )
+ return Orders(**row) if row else None
+
+async def set_diagonalley_order_paid(payment_hash: str) -> Orders:
+ await db.execute(
+ """
+ UPDATE diagonalley.orders
+ SET paid = true
+ WHERE invoiceid = ?
+ """,
+ (payment_hash,),
+ )
async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
if isinstance(wallet_ids, str):
diff --git a/lnbits/extensions/diagonalley/tasks.py b/lnbits/extensions/diagonalley/tasks.py
index bcbb7025..6b64203e 100644
--- a/lnbits/extensions/diagonalley/tasks.py
+++ b/lnbits/extensions/diagonalley/tasks.py
@@ -1,8 +1,12 @@
import asyncio
+from loguru import logger
+
from lnbits.core.models import Payment
from lnbits.tasks import register_invoice_listener
+from .crud import get_diagonalley_order_invoiceid, set_diagonalley_order_paid
+
async def wait_for_paid_invoices():
invoice_queue = asyncio.Queue()
@@ -14,6 +18,21 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None:
+ if payment.extra.get("tag") != "diagonalley":
+ return
+
+ order = await get_diagonalley_order_invoiceid(payment.payment_hash)
+ if not order:
+ logger.error("this should never happen", payment)
+ return
+
+ # set order as paid
+ await set_diagonalley_order_paid(payment.payment_hash)
+
+ # deduct items sold from stock
+ # TODO
+
+
"""
if "lnticket" != payment.extra.get("tag"):
# not a lnticket invoice
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index b33feb2a..f6333cfe 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -220,25 +220,41 @@
-
-
-
-
-
-
-
- Copy Invoice
+
+
+
+
+
+ Copy invoice
+ Close
+
@@ -252,9 +268,6 @@
return {
stall: null,
products: [],
- wallet: {
- inkey: null
- },
searchText: null,
cart: {
total: 0,
@@ -271,8 +284,7 @@
payment_request: null
},
show: false
- },
- cancelListener: () => {}
+ }
}
},
computed: {
@@ -297,6 +309,10 @@
}
},
methods: {
+ closeQrCodeDialog() {
+ this.qrCodeDialog.dismissMsg()
+ this.qrCodeDialog.show = false
+ },
resetCart() {
this.cart = {
total: 0,
@@ -341,16 +357,10 @@
return {product_id: p[0], quantity: p[1].quantity}
})
}
-
LNbits.api
- .request(
- 'POST',
- '/diagonalley/api/v1/orders',
- this.wallet.inkey,
- data
- )
+ .request('POST', '/diagonalley/api/v1/orders', null, data)
.then(res => {
- this.checkoutDialog = {show: false}
+ this.checkoutDialog = {show: false, data: {}}
return res.data
})
@@ -358,48 +368,46 @@
this.qrCodeDialog.data = data
this.qrCodeDialog.show = true
- qrCodeDialog.dismissMsg = this.$q.notify({
+ this.qrCodeDialog.dismissMsg = this.$q.notify({
timeout: 0,
message: 'Waiting for payment...'
})
+ return data
+ })
+ .then(data => {
+ this.qrCodeDialog.paymentChecker = setInterval(() => {
+ LNbits.api
+ .request(
+ 'GET',
+ `/diagonalley/api/v1/orders/payments/${this.qrCodeDialog.data.payment_hash}`
+ )
+ .then(res => {
+ if (res.data.paid) {
+ this.$q.notify({
+ type: 'positive',
+ message: 'Sats received, thanks!',
+ icon: 'thumb_up'
+ })
+ clearInterval(this.qrCodeDialog.paymentChecker)
+ this.resetCart()
+ this.closeQrCodeDialog()
+ }
+ })
+ .catch(error => {
+ console.error(error)
+ LNbits.utils.notifyApiError(error)
+ })
+ }, 3000)
+ })
+ .catch(error => {
+ console.error(error)
+ LNbits.utils.notifyApiError(error)
})
- .catch(error => LNbits.utils.notifyApiError(error))
-
- return
- },
- startPaymentNotifier() {
- this.cancelListener()
-
- this.cancelListener = LNbits.events.onInvoicePaid(
- this.wallet,
- payment => {
- this.qrCodeDialog = {
- show: false,
- data: {
- payment_request: null
- }
- }
-
- this.checkoutDialog = {data: {}}
- this.resetCart()
-
- this.$q.notify({
- type: 'positive',
- message: 'Sent, thank you!',
- icon: 'thumb_up'
- })
- }
- )
}
},
created() {
this.stall = JSON.parse('{{ stall | tojson }}')
this.products = JSON.parse('{{ products | tojson }}')
- this.wallet.inkey = '{{ inkey }}'
-
- this.startPaymentNotifier()
- //let stall_ids = new Set()
- //this.products.map(p => stall_ids.add(p.stall))
console.log(this.stall, this.products)
}
@@ -410,13 +418,3 @@
}
{% endblock %}
-
-
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index c440d2ae..af93d60c 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -33,15 +33,12 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
async def display(request: Request, stall_id):
stall = await get_diagonalley_stall(stall_id)
products = await get_diagonalley_products(stall_id)
- wallet = await get_wallet(stall.wallet)
zones = []
for id in stall.shippingzones.split(","):
z = await get_diagonalley_zone(id)
z = z.dict()
zones.append({"label": z["countries"], "cost": z["cost"], "value": z["id"]})
- logger.debug(f"ZONES {zones}")
-
if not stall:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
@@ -57,7 +54,6 @@ async def display(request: Request, stall_id):
"request": request,
"stall": stall,
"products": [product.dict() for product in products],
- "inkey": wallet.inkey,
},
)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 5bdd3c2a..4236d742 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -10,6 +10,7 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.core.services import create_invoice
+from lnbits.core.views.api import api_payment
from lnbits.decorators import (
WalletTypeInfo,
get_key_type,
@@ -33,6 +34,7 @@ from .crud import (
get_diagonalley_markets,
get_diagonalley_order,
get_diagonalley_order_details,
+ get_diagonalley_order_invoiceid,
get_diagonalley_orders,
get_diagonalley_product,
get_diagonalley_products,
@@ -270,6 +272,21 @@ async def api_diagonalley_order_create(data: createOrder):
# return order.dict()
+@diagonalley_ext.get("/api/v1/orders/payments/{payment_hash}")
+async def api_diagonalley_check_payment(payment_hash: str):
+ order = await get_diagonalley_order_invoiceid(payment_hash)
+ if not order:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Order does not exist."
+ )
+ try:
+ status = await api_payment(payment_hash)
+
+ except Exception as exc:
+ logger.error(exc)
+ return {"paid": False}
+ return status
+
@diagonalley_ext.delete("/api/v1/orders/{order_id}")
async def api_diagonalley_order_delete(
order_id: str, wallet: WalletTypeInfo = Depends(get_key_type)
From 7c8e3de261d49f5600e4b900249528c3dcdafc10 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 19 Aug 2022 13:24:18 +0100
Subject: [PATCH 083/226] update product stock tests
---
lnbits/extensions/diagonalley/crud.py | 19 ++++++++++++++++---
lnbits/extensions/diagonalley/tasks.py | 15 +--------------
lnbits/extensions/diagonalley/views.py | 10 +++++++++-
3 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 0a825ca3..402fb1f5 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -1,10 +1,7 @@
-import re
from base64 import urlsafe_b64encode
from typing import List, Optional, Union
from uuid import uuid4
-import httpx
-
# from lnbits.db import open_ext_db
from lnbits.db import SQLITE
from lnbits.helpers import urlsafe_short_hash
@@ -291,6 +288,22 @@ async def set_diagonalley_order_paid(payment_hash: str) -> Orders:
(payment_hash,),
)
+async def update_diagonalley_product_stock(products):
+
+ q = "\n".join([f"""WHEN id='{p["product_id"]}' THEN {p["quantity"]}""" for p in products])
+ v = ",".join(["?"] * len(products))
+
+ await db.execute(
+ f"""
+ UPDATE diagonalley.products
+ SET quantity=(CASE
+ {q}
+ END)
+ WHERE id IN ({v});
+ """,
+ (*[p["product_id"] for p in products],)
+ )
+
async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
if isinstance(wallet_ids, str):
wallet_ids = [wallet_ids]
diff --git a/lnbits/extensions/diagonalley/tasks.py b/lnbits/extensions/diagonalley/tasks.py
index 6b64203e..22ce0819 100644
--- a/lnbits/extensions/diagonalley/tasks.py
+++ b/lnbits/extensions/diagonalley/tasks.py
@@ -30,19 +30,6 @@ async def on_invoice_paid(payment: Payment) -> None:
await set_diagonalley_order_paid(payment.payment_hash)
# deduct items sold from stock
+
# TODO
-
- """
- if "lnticket" != payment.extra.get("tag"):
- # not a lnticket invoice
- return
-
- ticket = await get_ticket(payment.checking_id)
- if not ticket:
- print("this should never happen", payment)
- return
-
- await payment.set_pending(False)
- await set_ticket_paid(payment.payment_hash)
- """
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index af93d60c..df65c541 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -17,6 +17,7 @@ from .crud import (
get_diagonalley_stall,
get_diagonalley_zone,
get_diagonalley_zones,
+ update_diagonalley_product_stock,
)
templates = Jinja2Templates(directory="templates")
@@ -31,6 +32,13 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
+ # test_qty = 99
+ # test = [
+ # {"product_id": "55vpVjWAuQExHsJxT28MYe", "quantity": test_qty},
+ # {"product_id": "f2eGNsEWgbLJbfAApd3Jw5", "quantity": test_qty},
+ # {"product_id": "FVqZLZdemWCsiqe9gafvsC", "quantity": test_qty},
+ # ]
+ # await update_diagonalley_product_stock(test)
stall = await get_diagonalley_stall(stall_id)
products = await get_diagonalley_products(stall_id)
zones = []
@@ -43,7 +51,7 @@ async def display(request: Request, stall_id):
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
)
-
+
stall = stall.dict()
del stall["privatekey"]
stall["zones"] = zones
From c9884e512bbd1d4414b705e23b6787c683d61c12 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Sat, 20 Aug 2022 08:18:28 +0100
Subject: [PATCH 084/226] stock values update
---
lnbits/extensions/diagonalley/crud.py | 4 ++--
lnbits/extensions/diagonalley/tasks.py | 10 ++++++++--
lnbits/extensions/diagonalley/views.py | 2 +-
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 402fb1f5..557b45d2 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -290,7 +290,7 @@ async def set_diagonalley_order_paid(payment_hash: str) -> Orders:
async def update_diagonalley_product_stock(products):
- q = "\n".join([f"""WHEN id='{p["product_id"]}' THEN {p["quantity"]}""" for p in products])
+ q = "\n".join([f"""WHEN id='{p.product_id}' THEN quantity - {p.quantity}""" for p in products])
v = ",".join(["?"] * len(products))
await db.execute(
@@ -301,7 +301,7 @@ async def update_diagonalley_product_stock(products):
END)
WHERE id IN ({v});
""",
- (*[p["product_id"] for p in products],)
+ (*[p.product_id for p in products],)
)
async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
diff --git a/lnbits/extensions/diagonalley/tasks.py b/lnbits/extensions/diagonalley/tasks.py
index 22ce0819..b913ae60 100644
--- a/lnbits/extensions/diagonalley/tasks.py
+++ b/lnbits/extensions/diagonalley/tasks.py
@@ -5,7 +5,12 @@ from loguru import logger
from lnbits.core.models import Payment
from lnbits.tasks import register_invoice_listener
-from .crud import get_diagonalley_order_invoiceid, set_diagonalley_order_paid
+from .crud import (
+ get_diagonalley_order_details,
+ get_diagonalley_order_invoiceid,
+ set_diagonalley_order_paid,
+ update_diagonalley_product_stock,
+)
async def wait_for_paid_invoices():
@@ -30,6 +35,7 @@ async def on_invoice_paid(payment: Payment) -> None:
await set_diagonalley_order_paid(payment.payment_hash)
# deduct items sold from stock
+ details = await get_diagonalley_order_details(order.id)
+ await update_diagonalley_product_stock(details)
- # TODO
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index df65c541..e2905b62 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -32,7 +32,7 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
- # test_qty = 99
+ # test_qty = 10
# test = [
# {"product_id": "55vpVjWAuQExHsJxT28MYe", "quantity": test_qty},
# {"product_id": "f2eGNsEWgbLJbfAApd3Jw5", "quantity": test_qty},
From 108e2f579db3d9e0ed6af32fa69d6dca994e0588 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Mon, 12 Sep 2022 10:20:58 +0100
Subject: [PATCH 085/226] ui cosmetic on cards
---
lnbits/extensions/diagonalley/templates/diagonalley/stall.html | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index f6333cfe..9396d663 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -130,11 +130,10 @@
>
- {{ item.description }}
+
{{ item.description }}
From 6ef7411999d43565a7a3f597e66dc541b512aa84 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Mon, 12 Sep 2022 10:21:17 +0100
Subject: [PATCH 086/226] clean up
---
lnbits/extensions/diagonalley/views.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index e2905b62..0388c285 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -32,13 +32,6 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
- # test_qty = 10
- # test = [
- # {"product_id": "55vpVjWAuQExHsJxT28MYe", "quantity": test_qty},
- # {"product_id": "f2eGNsEWgbLJbfAApd3Jw5", "quantity": test_qty},
- # {"product_id": "FVqZLZdemWCsiqe9gafvsC", "quantity": test_qty},
- # ]
- # await update_diagonalley_product_stock(test)
stall = await get_diagonalley_stall(stall_id)
products = await get_diagonalley_products(stall_id)
zones = []
From f429037d636fd9e6a1d3f7f2100339afe6db9690 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Mon, 12 Sep 2022 16:58:56 +0100
Subject: [PATCH 087/226] create marketplace with stalls
---
lnbits/extensions/diagonalley/crud.py | 50 ++++++++++++++-
lnbits/extensions/diagonalley/models.py | 3 +
.../templates/diagonalley/index.html | 61 +++++++++++--------
lnbits/extensions/diagonalley/views_api.py | 5 +-
4 files changed, 91 insertions(+), 28 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 557b45d2..664dcb06 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -9,6 +9,8 @@ from lnbits.settings import WALLET
from . import db
from .models import (
+ CreateMarket,
+ CreateMarketStalls,
Market,
OrderDetail,
Orders,
@@ -332,11 +334,55 @@ async def get_diagonalley_market(market_id: str) -> Optional[Market]:
row = await db.fetchone(
"SELECT * FROM diagonalley.markets WHERE id = ?", (market_id,)
)
- Market(**row) if row else None
+ return Market(**row) if row else None
async def get_diagonalley_market_stalls(market_id: str):
rows = await db.fetchall(
"SELECT * FROM diagonalley.market_stalls WHERE marketid = ?", (market_id,)
)
- return [Stalls(**row) for row in rows]
+
+ return [{**row} for row in rows]
+
+async def create_diagonalley_market(data: CreateMarket):
+ market_id = urlsafe_short_hash()
+
+ await db.execute(
+ """
+ INSERT INTO diagonalley.markets (id, usr, name)
+ VALUES (?, ?, ?)
+ """,
+ (
+ market_id,
+ data.usr,
+ data.name,
+ ),
+ )
+ market = await get_diagonalley_market(market_id)
+ assert market, "Newly created market couldn't be retrieved"
+ return market
+
+
+async def create_diagonalley_market_stalls(
+ market_id: str, data: List[CreateMarketStalls]
+):
+ for stallid in data:
+ id = urlsafe_short_hash()
+
+ await db.execute(
+ """
+ INSERT INTO diagonalley.market_stalls (id, marketid, stallid)
+ VALUES (?, ?, ?)
+ """,
+ (
+ id,
+ market_id,
+ stallid,
+ ),
+ )
+ market_stalls = await get_diagonalley_market_stalls(market_id)
+ return market_stalls
+
+
+async def update_diagonalley_market(market_id):
+ pass
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index e6516037..0c32798c 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -103,3 +103,6 @@ class Market(BaseModel):
id: str
usr: str
name: Optional[str]
+
+class CreateMarketStalls(BaseModel):
+ stallid: str
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 516544ea..8d812a4a 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -179,12 +179,12 @@
-
+
-
+
@@ -197,13 +197,19 @@
label="Stalls"
v-model.trim="marketDialog.data.stalls"
>
+
Update Relay Update Marketplace
Launch Launch Marketplace
+ Store
Create a store to list products on
-
Launch frontend shop (not Nostr)
Makes a simple frontend shop for your stalls {
+ obj._data = _.clone(obj)
+ return obj
+ }
+
const humanReadableZones = zones => {
return zones.map(z => `${z.id} - ${z.countries}`)
}
@@ -1505,7 +1516,7 @@
)
.then(response => {
if (response.data) {
- this.shops = response.data.map(mapShops)
+ this.markets = response.data.map(mapMarkets)
}
})
.catch(error => {
@@ -1514,12 +1525,12 @@
},
openShopUpdateDialog: function (linkId) {
var self = this
- var link = _.findWhere(self.shops, {id: linkId})
+ var link = _.findWhere(self.markets, {id: linkId})
- this.shopDialog.data = _.clone(link._data)
- this.shopDialog.show = true
+ this.marketDialog.data = _.clone(link._data)
+ this.marketDialog.show = true
},
- sendShopFormData: function () {
+ sendMarketplaceFormData: function () {
let data = {...this.marketDialog.data}
if (!data.usr) {
@@ -1529,7 +1540,7 @@
if (data.id) {
this.updateZone(data)
} else {
- this.createZone(data)
+ this.createMarketplace(data)
}
},
updateShop: function (data) {
@@ -1539,24 +1550,24 @@
'PUT',
'/diagonalley/api/v1/shops' + data.id,
_.findWhere(self.g.user.wallets, {
- id: self.shopDialog.data.wallet
+ id: self.marketDialog.data.wallet
}).inkey,
_.pick(data, 'countries', 'cost')
)
.then(function (response) {
- self.shops = _.reject(self.shops, function (obj) {
+ self.markets = _.reject(self.markets, function (obj) {
return obj.id == data.id
})
- self.shops.push(mapShops(response.data))
- self.shopDialog.show = false
- self.shopDialog.data = {}
+ self.markets.push(mapShops(response.data))
+ self.marketDialog.show = false
+ self.marketDialog.data = {}
data = {}
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
- createShop(data) {
+ createMarketplace(data) {
LNbits.api
.request(
'POST',
@@ -1565,9 +1576,9 @@
data
)
.then(response => {
- this.shops.push(mapShops(response.data))
- this.shopDialog.show = false
- this.shopDialog.data = {}
+ this.markets.push(mapMarkets(response.data))
+ this.marketDialog.show = false
+ this.marketDialog.data = {}
data = {}
})
.catch(error => {
@@ -1576,7 +1587,7 @@
},
deleteShop: function (shopId) {
var self = this
- var shop = _.findWhere(self.shops, {id: shopId})
+ var shop = _.findWhere(self.markets, {id: shopId})
LNbits.utils
.confirmDialog('Are you sure you want to delete this Shop link?')
@@ -1588,7 +1599,7 @@
_.findWhere(self.g.user.wallets, {id: shop.wallet}).inkey
)
.then(function (response) {
- self.shops = _.reject(self.shops, function (obj) {
+ self.markets = _.reject(self.markets, function (obj) {
return obj.id == shopId
})
})
@@ -1598,7 +1609,7 @@
})
},
exportShopsCSV: function () {
- LNbits.utils.exportCSV(this.shopsTable.columns, this.shops)
+ LNbits.utils.exportCSV(this.shopsTable.columns, this.markets)
},
////////////////////////////////////////
////////////////ORDERS//////////////////
@@ -1694,7 +1705,7 @@
this.getProducts()
this.getZones()
this.getOrders()
- //this.getMarkets() # NOT YET IMPLEMENTED
+ this.getMarkets() // NOT YET IMPLEMENTED
this.customerKeys = [
'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 4236d742..6226e28b 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -21,6 +21,8 @@ from lnbits.decorators import (
from ...helpers import urlsafe_short_hash
from . import db, diagonalley_ext
from .crud import (
+ create_diagonalley_market,
+ create_diagonalley_market_stalls,
create_diagonalley_order,
create_diagonalley_order_details,
create_diagonalley_product,
@@ -42,6 +44,7 @@ from .crud import (
get_diagonalley_stalls,
get_diagonalley_zone,
get_diagonalley_zones,
+ update_diagonalley_market,
update_diagonalley_product,
update_diagonalley_stall,
update_diagonalley_zone,
@@ -439,7 +442,6 @@ async def api_diagonalley_stall_create(
market_id: str = None,
wallet: WalletTypeInfo = Depends(require_invoice_key),
):
-
if market_id:
market = await get_diagonalley_market(market_id)
if not market:
@@ -451,5 +453,6 @@ async def api_diagonalley_stall_create(
market = await update_diagonalley_market(market_id, **data.dict())
else:
market = await create_diagonalley_market(data=data)
+ await create_diagonalley_market_stalls(market_id=market.id, data=data.stalls)
return market.dict()
From 418cc7bf863b27f1d999375b21b64493feb81750 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Mon, 12 Sep 2022 17:01:41 +0100
Subject: [PATCH 088/226] make format
---
lnbits/extensions/diagonalley/crud.py | 35 +++++++++++++---------
lnbits/extensions/diagonalley/models.py | 1 +
lnbits/extensions/diagonalley/tasks.py | 4 +--
lnbits/extensions/diagonalley/views.py | 2 +-
lnbits/extensions/diagonalley/views_api.py | 1 +
5 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 664dcb06..49a64fc7 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -274,27 +274,32 @@ async def get_diagonalley_order(order_id: str) -> Optional[Orders]:
)
return Orders(**row) if row else None
+
async def get_diagonalley_order_invoiceid(invoice_id: str) -> Optional[Orders]:
row = await db.fetchone(
"SELECT * FROM diagonalley.orders WHERE invoiceid = ?", (invoice_id,)
)
return Orders(**row) if row else None
+
async def set_diagonalley_order_paid(payment_hash: str) -> Orders:
await db.execute(
- """
+ """
UPDATE diagonalley.orders
SET paid = true
WHERE invoiceid = ?
""",
- (payment_hash,),
- )
+ (payment_hash,),
+ )
+
async def update_diagonalley_product_stock(products):
-
- q = "\n".join([f"""WHEN id='{p.product_id}' THEN quantity - {p.quantity}""" for p in products])
+
+ q = "\n".join(
+ [f"""WHEN id='{p.product_id}' THEN quantity - {p.quantity}""" for p in products]
+ )
v = ",".join(["?"] * len(products))
-
+
await db.execute(
f"""
UPDATE diagonalley.products
@@ -303,9 +308,10 @@ async def update_diagonalley_product_stock(products):
END)
WHERE id IN ({v});
""",
- (*[p.product_id for p in products],)
+ (*[p.product_id for p in products],),
)
+
async def get_diagonalley_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
if isinstance(wallet_ids, str):
wallet_ids = [wallet_ids]
@@ -344,20 +350,21 @@ async def get_diagonalley_market_stalls(market_id: str):
return [{**row} for row in rows]
+
async def create_diagonalley_market(data: CreateMarket):
market_id = urlsafe_short_hash()
await db.execute(
- """
+ """
INSERT INTO diagonalley.markets (id, usr, name)
VALUES (?, ?, ?)
""",
- (
- market_id,
- data.usr,
- data.name,
- ),
- )
+ (
+ market_id,
+ data.usr,
+ data.name,
+ ),
+ )
market = await get_diagonalley_market(market_id)
assert market, "Newly created market couldn't be retrieved"
return market
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index 0c32798c..c3234bb6 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -104,5 +104,6 @@ class Market(BaseModel):
usr: str
name: Optional[str]
+
class CreateMarketStalls(BaseModel):
stallid: str
diff --git a/lnbits/extensions/diagonalley/tasks.py b/lnbits/extensions/diagonalley/tasks.py
index b913ae60..cd9e18a8 100644
--- a/lnbits/extensions/diagonalley/tasks.py
+++ b/lnbits/extensions/diagonalley/tasks.py
@@ -33,9 +33,7 @@ async def on_invoice_paid(payment: Payment) -> None:
# set order as paid
await set_diagonalley_order_paid(payment.payment_hash)
-
+
# deduct items sold from stock
details = await get_diagonalley_order_details(order.id)
await update_diagonalley_product_stock(details)
-
-
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 0388c285..5a94d993 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -44,7 +44,7 @@ async def display(request: Request, stall_id):
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
)
-
+
stall = stall.dict()
del stall["privatekey"]
stall["zones"] = zones
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 6226e28b..0e69e637 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -290,6 +290,7 @@ async def api_diagonalley_check_payment(payment_hash: str):
return {"paid": False}
return status
+
@diagonalley_ext.delete("/api/v1/orders/{order_id}")
async def api_diagonalley_order_delete(
order_id: str, wallet: WalletTypeInfo = Depends(get_key_type)
From 6a5c0bd8ee3bcb66acbb79292e1aca997b49ffd9 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 13 Sep 2022 12:52:26 +0100
Subject: [PATCH 089/226] list marketplaces with stalls in index.html
---
lnbits/extensions/diagonalley/crud.py | 13 +-
.../templates/diagonalley/index.html | 113 ++++++++++++++++++
lnbits/extensions/diagonalley/views_api.py | 12 +-
3 files changed, 135 insertions(+), 3 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 49a64fc7..b2689f21 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -201,6 +201,13 @@ async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stal
)
return [Stalls(**row) for row in rows]
+async def get_diagonalley_stalls_by_ids(stall_ids: Union[str, List[str]]) -> List[Stalls]:
+ q = ",".join(["?"] * len(stall_ids))
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.stalls WHERE id IN ({q})", (*stall_ids,)
+ )
+ return [Stalls(**row) for row in rows]
+
async def delete_diagonalley_stall(stall_id: str) -> None:
await db.execute("DELETE FROM diagonalley.stalls WHERE id = ?", (stall_id,))
@@ -346,9 +353,11 @@ async def get_diagonalley_market(market_id: str) -> Optional[Market]:
async def get_diagonalley_market_stalls(market_id: str):
rows = await db.fetchall(
"SELECT * FROM diagonalley.market_stalls WHERE marketid = ?", (market_id,)
- )
+ )
- return [{**row} for row in rows]
+ ids = [row["stallid"] for row in rows]
+
+ return await get_diagonalley_stalls_by_ids(ids)
async def create_diagonalley_market(data: CreateMarket):
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 8d812a4a..a8062910 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -669,6 +669,80 @@
+
+
+
+
+
+
Marketplaces
+
+
+ Export to CSV
+
+
+
+ {% raw %}
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+ Link to pass to stall relay
+
+
+ {{ col.value }}
+
+
+
+
+
+
+
+ {% endraw %}
+
+
+
+
@@ -817,6 +891,17 @@
const mapMarkets = obj => {
obj._data = _.clone(obj)
+ obj.stores = []
+ LNbits.api
+ .request('GET', `/diagonalley/api/v1/markets/${obj.id}/stalls`, null)
+ .then(response => {
+ if (response.data) {
+ obj.stores = response.data.map(s => s.name).toString()
+ }
+ })
+ .catch(error => {
+ LNbits.utils.notifyApiError(error)
+ })
return obj
}
@@ -832,6 +917,7 @@
products: [],
orders: [],
stalls: [],
+ markets: [],
zones: [],
zoneOptions: [],
customerKeys: [],
@@ -1015,6 +1101,31 @@
rowsPerPage: 10
}
},
+ marketTable: {
+ columns: [
+ {
+ name: 'id',
+ align: 'left',
+ label: 'ID',
+ field: 'id'
+ },
+ {
+ name: 'name',
+ align: 'left',
+ label: 'Name',
+ field: 'name'
+ },
+ {
+ name: 'stores',
+ align: 'left',
+ label: 'Stores',
+ field: 'stores'
+ }
+ ],
+ pagination: {
+ rowsPerPage: 10
+ }
+ },
zonesTable: {
columns: [
{
@@ -1517,12 +1628,14 @@
.then(response => {
if (response.data) {
this.markets = response.data.map(mapMarkets)
+ console.log(this.markets)
}
})
.catch(error => {
LNbits.utils.notifyApiError(error)
})
},
+
openShopUpdateDialog: function (linkId) {
var self = this
var link = _.findWhere(self.markets, {id: linkId})
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 0e69e637..947538c8 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -1,5 +1,6 @@
from base64 import urlsafe_b64encode
from http import HTTPStatus
+from typing import List
from uuid import uuid4
from fastapi import Request
@@ -33,6 +34,7 @@ from .crud import (
delete_diagonalley_stall,
delete_diagonalley_zone,
get_diagonalley_market,
+ get_diagonalley_market_stalls,
get_diagonalley_markets,
get_diagonalley_order,
get_diagonalley_order_details,
@@ -42,6 +44,7 @@ from .crud import (
get_diagonalley_products,
get_diagonalley_stall,
get_diagonalley_stalls,
+ get_diagonalley_stalls_by_ids,
get_diagonalley_zone,
get_diagonalley_zones,
update_diagonalley_market,
@@ -426,7 +429,8 @@ async def api_diagonalley_stall_order(
@diagonalley_ext.get("/api/v1/markets")
-async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
+async def api_diagonalley_markets(wallet: WalletTypeInfo = Depends(get_key_type)):
+ # await get_diagonalley_market_stalls(market_id="FzpWnMyHQMcRppiGVua4eY")
try:
return [
market.dict()
@@ -436,6 +440,12 @@ async def api_diagonalley_orders(wallet: WalletTypeInfo = Depends(get_key_type))
return {"message": "We could not retrieve the markets."}
+@diagonalley_ext.get("/api/v1/markets/{market_id}/stalls")
+async def api_diagonalley_market_stalls(market_id: str):
+ stall_ids = await get_diagonalley_market_stalls(market_id)
+ return stall_ids
+
+
@diagonalley_ext.post("/api/v1/markets")
@diagonalley_ext.put("/api/v1/markets/{market_id}")
async def api_diagonalley_stall_create(
From ad98cb0d45dd466e2009f5921f4d31dc1b18f14f Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 15 Sep 2022 15:51:12 +0100
Subject: [PATCH 090/226] marketplace html skeleton
---
.../templates/diagonalley/index.html | 2 +-
.../templates/diagonalley/market.html | 419 ++++++++++++++++++
lnbits/extensions/diagonalley/views.py | 39 +-
3 files changed, 443 insertions(+), 17 deletions(-)
create mode 100644 lnbits/extensions/diagonalley/templates/diagonalley/market.html
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index a8062910..c951fb0a 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -1818,7 +1818,7 @@
this.getProducts()
this.getZones()
this.getOrders()
- this.getMarkets() // NOT YET IMPLEMENTED
+ this.getMarkets()
this.customerKeys = [
'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/market.html b/lnbits/extensions/diagonalley/templates/diagonalley/market.html
new file mode 100644
index 00000000..b1a3ce88
--- /dev/null
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/market.html
@@ -0,0 +1,419 @@
+{% extends "public.html" %} {% block page %}
+
+
+
+
+ {{ market.name }}
+
+
+
+
+
+
+
+
+
+ {% raw %}
+
+ {{ cart.size }}
+
+ {% endraw %}
+
+
+ {% raw %}
+
+
+ {{p.quantity}} x
+
+
+
+
+
+
+
+
+ {{ p.name }}
+
+
+
+ {{p.price}} sats
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% raw %}
+
+
+
+ Add to cart
+
+
+
+ {{ item.product }}
+
+
+
+
+
+
+
+
+
+ {{ item.price }} sats BTC {{ (item.price / 1e8).toFixed(8) }}
+ {{item.quantity}} left
+
+
+ {{cat}}
+
+
+
{{ item.description }}
+
+
+
+
+
+
+
+ View details
+
+
+ {% endraw %}
+
+
+
+
+
+
+
+
+
+
+ Select the shipping zone:
+
+
+
+
+ {% raw %} Total: {{ finalCost }} {% endraw %}
+
+
+ Checkout
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
+ Copy invoice
+ Close
+
+
+
+
+{% endblock %} {% block scripts %}
+
+
+{% endblock %}
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 5a94d993..4e1db476 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -13,6 +13,8 @@ from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
from ...core.crud import get_wallet
from .crud import (
+ get_diagonalley_market,
+ get_diagonalley_market_stalls,
get_diagonalley_products,
get_diagonalley_stall,
get_diagonalley_zone,
@@ -59,20 +61,25 @@ async def display(request: Request, stall_id):
)
-# @diagonalley_ext.get("/market/{market_id}", response_class=HTMLResponse)
-# async def display(request: Request, stall_id):
-# stalls = await get_diagonalley_stall(stall_id)
-# products = await get_diagonalley_products(stall_id)
+@diagonalley_ext.get("/market/{market_id}", response_class=HTMLResponse)
+async def display(request: Request, market_id):
+ market = await get_diagonalley_market(market_id)
+
+ if not market:
+ raise HTTPException(
+ status_code=HTTPStatus.NOT_FOUND, detail="Marketplace doesn't exist."
+ )
+
+ stalls = await get_diagonalley_market_stalls(market_id)
+ stalls_ids = [stall.id for stall in stalls]
+ products = [product.dict() for product in await get_diagonalley_products(stalls_ids)]
-# if not stall:
-# raise HTTPException(
-# status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist."
-# )
-# return diagonalley_renderer().TemplateResponse(
-# "diagonalley/stall.html",
-# {
-# "request": request,
-# "stall": stall.dict(),
-# "products": [product.dict() for product in products]
-# },
-# )
+ return diagonalley_renderer().TemplateResponse(
+ "diagonalley/market.html",
+ {
+ "request": request,
+ "market": market,
+ "stalls": [stall.dict() for stall in stalls],
+ "products": products
+ },
+ )
From ee4757543123c6b96772b4862a01dd0216ce2381 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Thu, 15 Sep 2022 15:52:08 +0100
Subject: [PATCH 091/226] format
---
lnbits/extensions/diagonalley/crud.py | 13 ++++++++-----
lnbits/extensions/diagonalley/views.py | 10 ++++++----
lnbits/extensions/diagonalley/views_api.py | 2 +-
3 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index b2689f21..8f053de1 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -201,12 +201,15 @@ async def get_diagonalley_stalls(wallet_ids: Union[str, List[str]]) -> List[Stal
)
return [Stalls(**row) for row in rows]
-async def get_diagonalley_stalls_by_ids(stall_ids: Union[str, List[str]]) -> List[Stalls]:
+
+async def get_diagonalley_stalls_by_ids(
+ stall_ids: Union[str, List[str]]
+) -> List[Stalls]:
q = ",".join(["?"] * len(stall_ids))
rows = await db.fetchall(
f"SELECT * FROM diagonalley.stalls WHERE id IN ({q})", (*stall_ids,)
)
- return [Stalls(**row) for row in rows]
+ return [Stalls(**row) for row in rows]
async def delete_diagonalley_stall(stall_id: str) -> None:
@@ -353,10 +356,10 @@ async def get_diagonalley_market(market_id: str) -> Optional[Market]:
async def get_diagonalley_market_stalls(market_id: str):
rows = await db.fetchall(
"SELECT * FROM diagonalley.market_stalls WHERE marketid = ?", (market_id,)
- )
+ )
+
+ ids = [row["stallid"] for row in rows]
- ids = [row["stallid"] for row in rows]
-
return await get_diagonalley_stalls_by_ids(ids)
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 4e1db476..d0fee249 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -64,15 +64,17 @@ async def display(request: Request, stall_id):
@diagonalley_ext.get("/market/{market_id}", response_class=HTMLResponse)
async def display(request: Request, market_id):
market = await get_diagonalley_market(market_id)
-
+
if not market:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Marketplace doesn't exist."
)
-
+
stalls = await get_diagonalley_market_stalls(market_id)
stalls_ids = [stall.id for stall in stalls]
- products = [product.dict() for product in await get_diagonalley_products(stalls_ids)]
+ products = [
+ product.dict() for product in await get_diagonalley_products(stalls_ids)
+ ]
return diagonalley_renderer().TemplateResponse(
"diagonalley/market.html",
@@ -80,6 +82,6 @@ async def display(request: Request, market_id):
"request": request,
"market": market,
"stalls": [stall.dict() for stall in stalls],
- "products": products
+ "products": products,
},
)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 947538c8..f5751553 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -444,7 +444,7 @@ async def api_diagonalley_markets(wallet: WalletTypeInfo = Depends(get_key_type)
async def api_diagonalley_market_stalls(market_id: str):
stall_ids = await get_diagonalley_market_stalls(market_id)
return stall_ids
-
+
@diagonalley_ext.post("/api/v1/markets")
@diagonalley_ext.put("/api/v1/markets/{market_id}")
From e80daf27957b315676f51f39059e4f3488029e03 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 23 Sep 2022 10:25:57 +0100
Subject: [PATCH 092/226] rename stores to stalls
---
.../templates/diagonalley/index.html | 28 +++++++++++--------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index c951fb0a..eb290a92 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -314,7 +314,7 @@
unelevated
color="primary"
type="submit"
- >Update Store Update Stall
Create Store Create Stall
+ Store
- Create a stall to list products on + Stall
+
+ Create a market stall to list products on
+
+ Store
- Create a store to list products on + Stall
+
+ Create a market stall to list products on
+
Launch frontend shop (not Nostr)
+ >Create Market
- Makes a simple frontend shop for your stalls
@@ -596,11 +600,11 @@
-
+
-
Stores
+ Market Stalls
Date: Wed, 28 Sep 2022 11:11:52 +0100
Subject: [PATCH 093/226] WIP added keys to merchant
---
.../templates/diagonalley/index.html | 50 ++++++++++++++-----
lnbits/extensions/diagonalley/views_api.py | 13 +++++
2 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index eb290a92..cd03e6f3 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -253,28 +253,32 @@
>
-
+ >
-->
{% endblock %} {% block scripts %} {{ window_vars(user) }}
+
+
+{% endblock %}
From e0b93fbd49df489bc8dcea3ec1cab41650b2a49f Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 28 Sep 2022 11:12:34 +0100
Subject: [PATCH 095/226] chat and WS initial commit
---
lnbits/extensions/diagonalley/views.py | 49 ++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index d0fee249..d6e701a0 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -1,6 +1,7 @@
from http import HTTPStatus
+from typing import List
-from fastapi import Request
+from fastapi import Query, Request, WebSocket, WebSocketDisconnect
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
from loguru import logger
@@ -11,10 +12,10 @@ from lnbits.core.models import User
from lnbits.decorators import check_user_exists # type: ignore
from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
-from ...core.crud import get_wallet
from .crud import (
get_diagonalley_market,
get_diagonalley_market_stalls,
+ get_diagonalley_order_details,
get_diagonalley_products,
get_diagonalley_stall,
get_diagonalley_zone,
@@ -31,6 +32,22 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
"diagonalley/index.html", {"request": request, "user": user.dict()}
)
+@diagonalley_ext.get("/chat", response_class=HTMLResponse)
+async def chat_page(request: Request, merch: str = Query(...), order: str = Query(...)):
+ stall = await get_diagonalley_stall(merch)
+ orders = await get_diagonalley_order_details(order)
+
+ logger.debug(f"ORDER: {orders}")
+
+ return diagonalley_renderer().TemplateResponse(
+ "diagonalley/chat.html",
+ {
+ "request": request,
+ "stall": {"id": stall.id, "name": stall.name, "publickey": stall.publickey, "wallet": stall.wallet },
+ "orders": [details.dict() for details in orders]
+ },
+ )
+
@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
@@ -85,3 +102,31 @@ async def display(request: Request, market_id):
"products": products,
},
)
+
+##################WEBSOCKET ROUTES########################
+
+class ConnectionManager:
+ def __init__(self):
+ self.active_connections: List[WebSocket] = []
+
+ async def connect(self, websocket: WebSocket, order_id: str):
+ await websocket.accept()
+ websocket.id = order_id
+ self.active_connections.append(websocket)
+
+ def disconnect(self, websocket: WebSocket):
+ self.active_connections.remove(websocket)
+
+ async def send_personal_message(self, message: str, order_id: str):
+ for connection in self.active_connections:
+ if connection.id == order_id:
+ await connection.send_text(message)
+
+ async def broadcast(self, message: str):
+ for connection in self.active_connections:
+ await connection.send_text(message)
+
+
+manager = ConnectionManager()
+
+
From b9371805e2eb0038b439a76589d26beca6c507ef Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 28 Sep 2022 17:02:15 +0100
Subject: [PATCH 096/226] websockets working localstorage for review
---
lnbits/extensions/diagonalley/notifier.py | 83 ++++++++++
.../templates/diagonalley/chat.html | 145 ++++++++++++++----
.../templates/diagonalley/index.html | 2 +-
lnbits/extensions/diagonalley/views.py | 85 +++++-----
lnbits/extensions/diagonalley/views_api.py | 5 +-
5 files changed, 254 insertions(+), 66 deletions(-)
create mode 100644 lnbits/extensions/diagonalley/notifier.py
diff --git a/lnbits/extensions/diagonalley/notifier.py b/lnbits/extensions/diagonalley/notifier.py
new file mode 100644
index 00000000..58a9f2bb
--- /dev/null
+++ b/lnbits/extensions/diagonalley/notifier.py
@@ -0,0 +1,83 @@
+## adapted from https://github.com/Sentymental/chat-fastapi-websocket
+"""
+Create a class Notifier that will handle messages
+and delivery to the specific person
+"""
+
+from collections import defaultdict
+
+from fastapi import WebSocket
+from loguru import logger
+
+
+class Notifier:
+ """
+ Manages chatrooms, sessions and members.
+
+ Methods:
+ - get_notification_generator(self): async generator with notification messages
+ - get_members(self, room_name: str): get members in room
+ - push(message: str, room_name: str): push message
+ - connect(websocket: WebSocket, room_name: str): connect to room
+ - remove(websocket: WebSocket, room_name: str): remove
+ - _notify(message: str, room_name: str): notifier
+ """
+
+ def __init__(self):
+ # Create sessions as a dict:
+ self.sessions: dict = defaultdict(dict)
+
+ # Create notification generator:
+ self.generator = self.get_notification_generator()
+
+ async def get_notification_generator(self):
+ """Notification Generator"""
+
+ while True:
+ message = yield
+ msg = message["message"]
+ room_name = message["room_name"]
+ await self._notify(msg, room_name)
+
+ def get_members(self, room_name: str):
+ """Get all members in a room"""
+
+ try:
+ logger.info(f"Looking for members in room: {room_name}")
+ return self.sessions[room_name]
+
+ except Exception:
+ logger.exception(f"There is no member in room: {room_name}")
+ return None
+
+ async def push(self, message: str, room_name: str = None):
+ """Push a message"""
+
+ message_body = {"message": message, "room_name": room_name}
+ await self.generator.asend(message_body)
+
+ async def connect(self, websocket: WebSocket, room_name: str):
+ """Connect to room"""
+
+ await websocket.accept()
+ if self.sessions[room_name] == {} or len(self.sessions[room_name]) == 0:
+ self.sessions[room_name] = []
+
+ self.sessions[room_name].append(websocket)
+ print(f"Connections ...: {self.sessions[room_name]}")
+
+ def remove(self, websocket: WebSocket, room_name: str):
+ """Remove websocket from room"""
+
+ self.sessions[room_name].remove(websocket)
+ print(f"Connection removed...\nOpen connections...: {self.sessions[room_name]}")
+
+ async def _notify(self, message: str, room_name: str):
+ """Notifier"""
+
+ remaining_sessions = []
+ while len(self.sessions[room_name]) > 0:
+ websocket = self.sessions[room_name].pop()
+ await websocket.send_text(message)
+ remaining_sessions.append(websocket)
+ self.sessions[room_name] = remaining_sessions
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/chat.html b/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
index bb3e607f..1713c9e2 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
@@ -45,13 +45,15 @@
{% raw %}
{{ stall.name }}
-
+
Public Key: {{ sliceKey(stall.publickey) }}
- {{ stall.publickey }}
+ Click to copy
{% endraw %}
+
+
-
-
+ -->
{ changeOrder() }"
>
@@ -79,16 +81,26 @@
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolore,
quasi.
-
-
-
-
-
-
+
+
+
+ {% raw %}
+
+
+ {{ user.keys[type] }}
+
+
{{ type == 'publickey' ? 'Public Key' : 'Private Key' }}
+ {% endraw %}
+
+
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolore,
@@ -123,7 +135,9 @@
showMessages: false,
messages: {},
stall: null,
+ selectedOrder: null,
orders: [],
+ user: null,
// Mock data
model: null,
mockMerch: ['Google', 'Facebook', 'Twitter', 'Apple', 'Oracle'],
@@ -136,29 +150,108 @@
this.newMessage = ''
this.$refs.newMessage.focus()
},
- sendMessage() {
+ sendMessage(e) {
let message = {
key: Date.now(),
text: this.newMessage,
from: 'me'
}
- this.$set(this.messages, message.key, message)
+ ws.send(JSON.stringify(message))
this.clearMessage()
+ e.preventDefault()
},
sliceKey(key) {
if (!key) return ''
return `${key.slice(0, 4)}...${key.slice(-4)}`
+ },
+ async generateKeys() {
+ await LNbits.api
+ .request('GET', '/diagonalley/api/v1/keys', null)
+ .then(response => {
+ if (response.data) {
+ let data = {
+ keys: {
+ privatekey: response.data.privkey,
+ publickey: response.data.pubkey
+ }
+ }
+ this.user = data
+ console.log('Keys done', this.user)
+ return
+ }
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ changeOrder() {
+ console.log(this.selectedOrder)
+ },
+ startChat(room_name) {
+ if (location.protocol == 'https:') {
+ ws_scheme = 'wss://'
+ } else {
+ ws_scheme = 'ws://'
+ }
+ ws = new WebSocket(
+ ws_scheme + location.host + '/diagonalley/ws/' + room_name
+ )
+
+ function checkWebSocket(event) {
+ if (ws.readyState === WebSocket.CLOSED) {
+ console.log('WebSocket CLOSED: Reopening')
+ ws = new WebSocket(
+ ws_scheme + location.host + '/diagonalley/ws/' + room_name
+ )
+ }
+ }
+
+ ws.onmessage = event => {
+ let event_data = JSON.parse(event.data)
+
+ this.$set(this.messages, event_data.key, event_data)
+ this.$q.localStorage.set()
+ }
+
+ this.ws = ws
}
},
- created() {
- let stall = JSON.parse('{{ stall | tojson }}')
- let orders = JSON.parse('{{ orders | tojson }}')
+ async created() {
+ this.stall = JSON.parse('{{ stall | tojson }}')
- this.stall = stall
- this.orders = orders
- console.log(stall)
- console.log(orders)
+ let order_details = JSON.parse('{{ order | tojson }}')
+ let order_id = order_details[0].order_id
+
+ let data = this.$q.localStorage.getItem(`lnbits.diagonalley.data`)
+
+ try {
+ if (data) {
+ this.user = data
+ //add chat key (merchant pubkey) if not set
+ if (!this.user.chats[`${this.stall.publickey}`]) {
+ this.$set(this.user.chats, this.stall.publickey, [])
+ }
+ //this.$q.localStorage.set(`lnbits.diagonalley.data`, this.user)
+ } else {
+ // generate keys
+ await this.generateKeys()
+ // populate user data
+ this.user.chats = {
+ [`${this.stall.publickey}`]: []
+ }
+ this.user.orders = []
+ }
+
+ this.order_details = order_details
+ this.user.orders = [...new Set([...this.user.orders, order_id])]
+ this.selectedOrder = order_id
+
+ this.$q.localStorage.set(`lnbits.diagonalley.data`, this.user)
+ this.startChat(order_id)
+ } catch (e) {
+ console.error(e)
+ }
}
})
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index cd03e6f3..5ad6f6a5 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -644,7 +644,7 @@
icon="storefront"
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
type="a"
- :href="'/diagonalley/' + props.row.id"
+ :href="'/diagonalley/stalls/' + props.row.id"
target="_blank"
>
Link to pass to stall relay
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index d6e701a0..a378658a 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -1,7 +1,8 @@
+import json
from http import HTTPStatus
from typing import List
-from fastapi import Query, Request, WebSocket, WebSocketDisconnect
+from fastapi import BackgroundTasks, Query, Request, WebSocket, WebSocketDisconnect
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates
from loguru import logger
@@ -11,6 +12,7 @@ from starlette.responses import HTMLResponse
from lnbits.core.models import User
from lnbits.decorators import check_user_exists # type: ignore
from lnbits.extensions.diagonalley import diagonalley_ext, diagonalley_renderer
+from lnbits.extensions.diagonalley.notifier import Notifier
from .crud import (
get_diagonalley_market,
@@ -32,24 +34,8 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
"diagonalley/index.html", {"request": request, "user": user.dict()}
)
-@diagonalley_ext.get("/chat", response_class=HTMLResponse)
-async def chat_page(request: Request, merch: str = Query(...), order: str = Query(...)):
- stall = await get_diagonalley_stall(merch)
- orders = await get_diagonalley_order_details(order)
- logger.debug(f"ORDER: {orders}")
-
- return diagonalley_renderer().TemplateResponse(
- "diagonalley/chat.html",
- {
- "request": request,
- "stall": {"id": stall.id, "name": stall.name, "publickey": stall.publickey, "wallet": stall.wallet },
- "orders": [details.dict() for details in orders]
- },
- )
-
-
-@diagonalley_ext.get("/{stall_id}", response_class=HTMLResponse)
+@diagonalley_ext.get("/stalls/{stall_id}", response_class=HTMLResponse)
async def display(request: Request, stall_id):
stall = await get_diagonalley_stall(stall_id)
products = await get_diagonalley_products(stall_id)
@@ -103,30 +89,55 @@ async def display(request: Request, market_id):
},
)
+
+@diagonalley_ext.get("/chat", response_class=HTMLResponse)
+async def chat_page(request: Request, merch: str = Query(...), order: str = Query(...)):
+ stall = await get_diagonalley_stall(merch)
+ _order = await get_diagonalley_order_details(order)
+
+ return diagonalley_renderer().TemplateResponse(
+ "diagonalley/chat.html",
+ {
+ "request": request,
+ "stall": {
+ "id": stall.id,
+ "name": stall.name,
+ "publickey": stall.publickey,
+ "wallet": stall.wallet,
+ },
+ "order": [details.dict() for details in _order],
+ },
+ )
+
+
##################WEBSOCKET ROUTES########################
-class ConnectionManager:
- def __init__(self):
- self.active_connections: List[WebSocket] = []
+# Initialize Notifier:
+notifier = Notifier()
- async def connect(self, websocket: WebSocket, order_id: str):
- await websocket.accept()
- websocket.id = order_id
- self.active_connections.append(websocket)
+@diagonalley_ext.websocket("/ws/{room_name}")
+async def websocket_endpoint(
+ websocket: WebSocket, room_name: str, background_tasks: BackgroundTasks
+):
+ await notifier.connect(websocket, room_name)
+ try:
+ while True:
+ data = await websocket.receive_text()
+ d = json.loads(data)
+ d["room_name"] = room_name
- def disconnect(self, websocket: WebSocket):
- self.active_connections.remove(websocket)
+ room_members = (
+ notifier.get_members(room_name)
+ if notifier.get_members(room_name) is not None
+ else []
+ )
- async def send_personal_message(self, message: str, order_id: str):
- for connection in self.active_connections:
- if connection.id == order_id:
- await connection.send_text(message)
+ if websocket not in room_members:
+ print("Sender not in room member: Reconnecting...")
+ await notifier.connect(websocket, room_name)
- async def broadcast(self, message: str):
- for connection in self.active_connections:
- await connection.send_text(message)
-
-
-manager = ConnectionManager()
+ await notifier._notify(f"{data}", room_name)
+ except WebSocketDisconnect:
+ notifier.remove(websocket, room_name)
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index c3615c90..aa8d338d 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -469,14 +469,15 @@ async def api_diagonalley_stall_create(
return market.dict()
+
## KEYS
+
@diagonalley_ext.get("/api/v1/keys")
-async def api_diagonalley_generate_keys(wallet: WalletTypeInfo = Depends(require_admin_key)):
+async def api_diagonalley_generate_keys():
private_key = PrivateKey()
public_key = private_key.pubkey.serialize().hex()
while not public_key.startswith("02"):
private_key = PrivateKey()
public_key = private_key.pubkey.serialize().hex()
return {"privkey": private_key.serialize(), "pubkey": public_key[2:]}
-
From 8ab9590594fc55bfc0a4bf9d3a7a799554c2ad83 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Wed, 28 Sep 2022 17:03:09 +0100
Subject: [PATCH 097/226] format
---
lnbits/extensions/diagonalley/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index a378658a..7b242aed 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -115,6 +115,7 @@ async def chat_page(request: Request, merch: str = Query(...), order: str = Quer
# Initialize Notifier:
notifier = Notifier()
+
@diagonalley_ext.websocket("/ws/{room_name}")
async def websocket_endpoint(
websocket: WebSocket, room_name: str, background_tasks: BackgroundTasks
@@ -140,4 +141,3 @@ async def websocket_endpoint(
except WebSocketDisconnect:
notifier.remove(websocket, room_name)
-
From 57bb9665c69e4194fce86ecea75b36b36c0dffd9 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Fri, 30 Sep 2022 10:16:34 +0100
Subject: [PATCH 098/226] chat messages stored in db
---
lnbits/extensions/diagonalley/crud.py | 15 +++++++++++
lnbits/extensions/diagonalley/migrations.py | 24 +++++++++++++++++
lnbits/extensions/diagonalley/models.py | 13 +++++++++
lnbits/extensions/diagonalley/notifier.py | 10 +++++++
.../templates/diagonalley/chat.html | 27 ++++++++++---------
lnbits/extensions/diagonalley/views.py | 6 +++--
6 files changed, 80 insertions(+), 15 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 8f053de1..9e3f2013 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -9,6 +9,7 @@ from lnbits.settings import WALLET
from . import db
from .models import (
+ CreateChatMessage,
CreateMarket,
CreateMarketStalls,
Market,
@@ -405,3 +406,17 @@ async def create_diagonalley_market_stalls(
async def update_diagonalley_market(market_id):
pass
+
+async def create_chat_message(data: CreateChatMessage):
+ print("DATA", data)
+ await db.execute(
+ """
+ INSERT INTO diagonalley.messages (msg, pubkey, id_conversation)
+ VALUES (?, ?, ?)
+ """,
+ (
+ data.msg,
+ data.pubkey,
+ data.room_name,
+ ),
+ )
diff --git a/lnbits/extensions/diagonalley/migrations.py b/lnbits/extensions/diagonalley/migrations.py
index 6e1510a7..3bcddcb0 100644
--- a/lnbits/extensions/diagonalley/migrations.py
+++ b/lnbits/extensions/diagonalley/migrations.py
@@ -113,3 +113,27 @@ async def m001_initial(db):
);
"""
)
+
+async def m002_add_chat_messages(db):
+ """
+ Initial chat messages table.
+ """
+ await db.execute(
+ f"""
+ CREATE TABLE diagonalley.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
+ + """
+ );
+ """
+ )
+
+ """
+ Create indexes for message fetching
+ """
+ await db.execute("CREATE INDEX idx_messages_timestamp ON diagonalley.messages (timestamp DESC)")
+ await db.execute("CREATE INDEX idx_messages_conversations ON diagonalley.messages (id_conversation)")
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index c3234bb6..f9fa1bca 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -107,3 +107,16 @@ class Market(BaseModel):
class CreateMarketStalls(BaseModel):
stallid: str
+
+
+class ChatMessage(BaseModel):
+ id: str
+ msg: str
+ pubkey: str
+ id_conversation: str
+ timestamp: int
+
+class CreateChatMessage(BaseModel):
+ msg: str = Query(..., min_length=1)
+ pubkey: str = Query(...)
+ room_name: str = Query(...)
diff --git a/lnbits/extensions/diagonalley/notifier.py b/lnbits/extensions/diagonalley/notifier.py
index 58a9f2bb..e21be500 100644
--- a/lnbits/extensions/diagonalley/notifier.py
+++ b/lnbits/extensions/diagonalley/notifier.py
@@ -4,11 +4,15 @@ Create a class Notifier that will handle messages
and delivery to the specific person
"""
+import json
from collections import defaultdict
from fastapi import WebSocket
from loguru import logger
+from lnbits.extensions.diagonalley.crud import create_chat_message
+from lnbits.extensions.diagonalley.models import CreateChatMessage
+
class Notifier:
"""
@@ -75,6 +79,12 @@ class Notifier:
async def _notify(self, message: str, room_name: str):
"""Notifier"""
+ d = json.loads(message)
+ d["room_name"] = room_name
+ db_msg = CreateChatMessage.parse_obj(d)
+ print("NOT:", db_msg)
+ await create_chat_message(data=db_msg)
+
remaining_sessions = []
while len(self.sessions[room_name]) > 0:
websocket = self.sessions[room_name].pop()
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/chat.html b/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
index 1713c9e2..21f59361 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
@@ -7,12 +7,12 @@
@@ -125,6 +125,9 @@
{% endblock %} {% block scripts %}
+
+{% endblock %}
From d5388ba7dee48554fd9ba1f09fa8e887f0477187 Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 4 Oct 2022 09:59:18 +0100
Subject: [PATCH 102/226] add publickey if stored
---
.../templates/diagonalley/stall.html | 29 +++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index 9396d663..a3a04b1e 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -162,6 +162,17 @@
v-model.trim="checkoutDialog.data.username"
label="Name *optional"
>
+
+
+
+ Click to restore saved public key
+
+
Cancel
Date: Tue, 4 Oct 2022 09:59:34 +0100
Subject: [PATCH 103/226] placeholder for product page WIP
---
.../diagonalley/templates/diagonalley/product.html | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 lnbits/extensions/diagonalley/templates/diagonalley/product.html
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/product.html b/lnbits/extensions/diagonalley/templates/diagonalley/product.html
new file mode 100644
index 00000000..66f56691
--- /dev/null
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/product.html
@@ -0,0 +1,14 @@
+{% extends "public.html" %} {% block page %}
+Product page
+{% endblock %} {% block scripts %}
+
+{% endblock %}
From c59e9efabc70735c1d9825557b70b254cbb6f5fa Mon Sep 17 00:00:00 2001
From: Tiago vasconcelos
Date: Tue, 4 Oct 2022 10:00:42 +0100
Subject: [PATCH 104/226] add public key and refactor endpoint
---
lnbits/extensions/diagonalley/crud.py | 1 +
lnbits/extensions/diagonalley/models.py | 1 +
.../templates/diagonalley/chat.html | 317 ------------------
lnbits/extensions/diagonalley/views.py | 13 +-
4 files changed, 11 insertions(+), 321 deletions(-)
delete mode 100644 lnbits/extensions/diagonalley/templates/diagonalley/chat.html
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index 18207888..f093ba69 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -408,6 +408,7 @@ async def create_diagonalley_market_stalls(
async def update_diagonalley_market(market_id):
pass
+### CHAT / MESSAGES
async def create_chat_message(data: CreateChatMessage):
print("DATA", data)
diff --git a/lnbits/extensions/diagonalley/models.py b/lnbits/extensions/diagonalley/models.py
index b1bfdc9c..e3ea2cc6 100644
--- a/lnbits/extensions/diagonalley/models.py
+++ b/lnbits/extensions/diagonalley/models.py
@@ -70,6 +70,7 @@ class createOrderDetails(BaseModel):
class createOrder(BaseModel):
wallet: str = Query(...)
+ username: str = Query(None)
pubkey: str = Query(None)
shippingzone: str = Query(...)
address: str = Query(...)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/chat.html b/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
deleted file mode 100644
index adbdb047..00000000
--- a/lnbits/extensions/diagonalley/templates/diagonalley/chat.html
+++ /dev/null
@@ -1,317 +0,0 @@
-{% extends "public.html" %} {% block page %}
-
-
-
-
-
- {% raw %}
- {{ stall.name }}
-
- Public Key: {{ sliceKey(stall.publickey) }}
- Click to copy
-
- {% endraw %}
-
-
-
-
- { changeOrder() }"
- >
-
-
-
-
-
- Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolore,
- quasi.
-
-
-
-
- {% raw %}
-
-
- {{ user.keys[type] }}
-
-
{{ type == 'publickey' ? 'Public Key' : 'Private Key' }}
- {% endraw %}
-
-
-
-
- Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolore,
- quasi.
-
-
-
-
-
- Backup keys
- Download your keys
-
- Delete data
- Delete all data from browser
-
-
-
-
-
-
-{% endblock %} {% block scripts %}
-
-
-{% endblock %}
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 1addb8a7..27875287 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -20,6 +20,7 @@ from .crud import (
get_diagonalley_market,
get_diagonalley_market_stalls,
get_diagonalley_order_details,
+ get_diagonalley_order_invoiceid,
get_diagonalley_products,
get_diagonalley_stall,
get_diagonalley_zone,
@@ -92,13 +93,15 @@ async def display(request: Request, market_id):
)
-@diagonalley_ext.get("/chat", response_class=HTMLResponse)
-async def chat_page(request: Request, merch: str = Query(...), order: str = Query(...)):
+@diagonalley_ext.get("/order", response_class=HTMLResponse)
+async def chat_page(request: Request, merch: str = Query(...), invoice_id: str = Query(...)):
stall = await get_diagonalley_stall(merch)
- _order = await get_diagonalley_order_details(order)
+ order = await get_diagonalley_order_invoiceid(invoice_id)
+ _order = await get_diagonalley_order_details(order.id)
+ products = await get_diagonalley_products(stall.id)
return diagonalley_renderer().TemplateResponse(
- "diagonalley/chat.html",
+ "diagonalley/order.html",
{
"request": request,
"stall": {
@@ -107,7 +110,9 @@ async def chat_page(request: Request, merch: str = Query(...), order: str = Quer
"publickey": stall.publickey,
"wallet": stall.wallet,
},
+ "order_id": order.id,
"order": [details.dict() for details in _order],
+ "products": [product.dict() for product in products]
},
)
From ebe8d8b0b983eb16257ca66b0d3c1720a0816980 Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Wed, 19 Oct 2022 22:07:38 +0100
Subject: [PATCH 105/226] just for bragging...
---
lnbits/extensions/diagonalley/config.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lnbits/extensions/diagonalley/config.json b/lnbits/extensions/diagonalley/config.json
index 8ad41727..194949d0 100644
--- a/lnbits/extensions/diagonalley/config.json
+++ b/lnbits/extensions/diagonalley/config.json
@@ -2,5 +2,5 @@
"name": "Diagon Alley",
"short_description": "Nostr shop system",
"icon": "add_shopping_cart",
- "contributors": ["benarc"]
+ "contributors": ["benarc", "talvasconcelos"]
}
From 532e12ec831b1a5908081edb5f32e95945e23023 Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Wed, 19 Oct 2022 22:08:48 +0100
Subject: [PATCH 106/226] merchant chat functional almost out of WIP
---
lnbits/extensions/diagonalley/crud.py | 13 +
lnbits/extensions/diagonalley/notifier.py | 2 +-
.../templates/diagonalley/index.html | 389 +++++++++++++++---
.../templates/diagonalley/order.html | 52 +--
.../templates/diagonalley/stall.html | 16 +-
lnbits/extensions/diagonalley/views.py | 45 +-
lnbits/extensions/diagonalley/views_api.py | 23 +-
7 files changed, 461 insertions(+), 79 deletions(-)
diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py
index f093ba69..8dadb739 100644
--- a/lnbits/extensions/diagonalley/crud.py
+++ b/lnbits/extensions/diagonalley/crud.py
@@ -408,8 +408,10 @@ async def create_diagonalley_market_stalls(
async def update_diagonalley_market(market_id):
pass
+
### CHAT / MESSAGES
+
async def create_chat_message(data: CreateChatMessage):
print("DATA", data)
await db.execute(
@@ -441,3 +443,14 @@ async def get_diagonalley_chat_messages(room_name: str):
)
return [ChatMessage(**row) for row in rows]
+
+
+async def get_diagonalley_chat_by_merchant(ids: List[str]) -> List[ChatMessage]:
+
+ q = ",".join(["?"] * len(ids))
+ rows = await db.fetchall(
+ f"SELECT * FROM diagonalley.messages WHERE id_conversation IN ({q})",
+ (*ids,),
+ )
+ print(ids, q, rows)
+ return [ChatMessage(**row) for row in rows]
diff --git a/lnbits/extensions/diagonalley/notifier.py b/lnbits/extensions/diagonalley/notifier.py
index e21be500..08badfc7 100644
--- a/lnbits/extensions/diagonalley/notifier.py
+++ b/lnbits/extensions/diagonalley/notifier.py
@@ -78,9 +78,9 @@ class Notifier:
async def _notify(self, message: str, room_name: str):
"""Notifier"""
-
d = json.loads(message)
d["room_name"] = room_name
+ print("hey", d)
db_msg = CreateChatMessage.parse_obj(d)
print("NOT:", db_msg)
await create_chat_message(data=db_msg)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index 5ad6f6a5..f898fd40 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -345,20 +345,6 @@
- + Product List a product
- + Product List a product
+ Shipping Zone Create a shipping zone
@@ -382,7 +368,26 @@
Create a market stall to list products on
- + Product List a product
+ + Product List a product
+ Create Market
Makes a simple frontend shop for your stalls (not NOSTR)
+
{{ col.label }}
@@ -434,6 +440,23 @@
:icon="props.expand ? 'remove' : 'add'"
/>
+
+
+
+
+
{{ col.value }}
@@ -824,22 +847,114 @@
{% include "diagonalley/_api_docs.html" %}
+
Messages
-
-
-
+
{% endblock %} {% block scripts %} {{ window_vars(user) }}
@@ -873,6 +987,15 @@
const pica = window.pica()
+ function imgSizeFit(img, maxWidth = 1024, maxHeight = 768) {
+ let ratio = Math.min(
+ 1,
+ maxWidth / img.naturalWidth,
+ maxHeight / img.naturalHeight
+ )
+ return {width: img.naturalWidth * ratio, height: img.naturalHeight * ratio}
+ }
+
const mapStalls = obj => {
obj._data = _.clone(obj)
return obj
@@ -891,6 +1014,7 @@
new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm'
)
+ // obj.unread = false
return obj
}
const mapKeys = obj => {
@@ -933,8 +1057,12 @@
customerKeys: [],
customerKey: '',
customerMessages: {},
+ messages: {},
+ newMessage: '',
+ orderMessages: {},
shippedModel: false,
shippingZoneOptions: [
+ 'Free (digital)',
'Worldwide',
'Europe',
'Australia',
@@ -999,17 +1127,17 @@
ordersTable: {
columns: [
/*{
- name: 'product',
- align: 'left',
- label: 'Product',
- field: 'product'
- },
- {
- name: 'quantity',
- align: 'left',
- label: 'Quantity',
- field: 'quantity'
- },*/
+ name: 'product',
+ align: 'left',
+ label: 'Product',
+ field: 'product'
+ },
+ {
+ name: 'quantity',
+ align: 'left',
+ label: 'Quantity',
+ field: 'quantity'
+ },*/
{
name: 'id',
align: 'left',
@@ -1443,9 +1571,10 @@
let image = new Image()
image.src = blobURL
image.onload = async () => {
+ let fit = imgSizeFit(image)
let canvas = document.createElement('canvas')
- canvas.setAttribute('width', 760)
- canvas.setAttribute('height', 490)
+ canvas.setAttribute('width', fit.width)
+ canvas.setAttribute('height', fit.height)
await pica.resize(image, canvas, {
quality: 0,
alpha: true,
@@ -1657,7 +1786,7 @@
.then(response => {
if (response.data) {
this.markets = response.data.map(mapMarkets)
- console.log(this.markets)
+ // console.log(this.markets)
}
})
.catch(error => {
@@ -1756,10 +1885,10 @@
////////////////////////////////////////
////////////////ORDERS//////////////////
////////////////////////////////////////
- getOrders: function () {
+ getOrders: async function () {
var self = this
- LNbits.api
+ await LNbits.api
.request(
'GET',
'/diagonalley/api/v1/orders?all_wallets=true',
@@ -1768,7 +1897,6 @@
.then(function (response) {
if (response.data) {
self.orders = response.data.map(mapOrders)
- console.log(self.orders)
}
})
.catch(function (error) {
@@ -1839,21 +1967,190 @@
},
exportOrdersCSV: function () {
LNbits.utils.exportCSV(this.ordersTable.columns, this.orders)
+ },
+ /// CHAT
+ async getAllMessages() {
+ await LNbits.api
+ .request(
+ 'GET',
+ `/diagonalley/api/v1/chat/messages/merchant?orders=${this.orders
+ .map(o => o.invoiceid)
+ .toString()}`,
+ this.g.user.wallets[0].adminkey
+ )
+ .then(res => {
+ this.messages = _.groupBy(res.data, 'id_conversation')
+ this.checkUnreadMessages()
+ console.log('Get new messages!')
+ })
+ .catch(error => {
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ updateLastSeenMsg(id) {
+ let data = this.$q.localStorage.getItem(
+ `lnbits.diagonalley.${this.g.user.id}`
+ )
+ let chat = {
+ ...data.chat,
+ [`${id}`]: {
+ timestamp: Object.keys(this.orderMessages)[
+ Object.keys(this.orderMessages).length - 1
+ ]
+ }
+ }
+ console.log({chat})
+ this.$q.localStorage.set(`lnbits.diagonalley.${this.g.user.id}`, {
+ ...data,
+ chat
+ })
+ this.checkUnreadMessages()
+ },
+ checkUnreadMessages() {
+ let lastMsgs = this.$q.localStorage.getItem(
+ `lnbits.diagonalley.${this.g.user.id}`
+ ).chat
+ for (let key in this.messages) {
+ let idx = this.orders.findIndex(f => f.invoiceid == key)
+ if (!lastMsgs[key]) {
+ this.updateLastSeenMsg(key)
+ //this.orders[idx].unread = true
+ return
+ }
+ console.log(
+ 'Key',
+ key,
+ 'saved:',
+ lastMsgs[key].timestamp,
+ 'messages: ',
+ Math.max(...this.messages[key].map(c => c.timestamp)),
+ lastMsgs[key].timestamp <
+ Math.max(...this.messages[key].map(c => c.timestamp))
+ )
+ if (
+ lastMsgs[key].timestamp <
+ Math.max(...this.messages[key].map(c => c.timestamp))
+ ) {
+ this.$set(this.orders[idx], 'unread', true)
+ // this.orders[idx].unread = true
+ } else {
+ this.$set(this.orders[idx], 'unread', false)
+ // this.orders[idx].unread = false
+ }
+ console.log('Order:', this.orders[idx])
+ }
+ },
+ clearMessage() {
+ this.newMessage = ''
+ this.$refs.newMessage.focus()
+ },
+ sendMessage() {
+ let message = {
+ msg: this.newMessage,
+ pubkey: this.keys.pubkey
+ }
+ this.ws.send(JSON.stringify(message))
+
+ this.clearMessage()
+ },
+ chatRoom(id) {
+ this.startChat(id)
+ this.orderMessages = {}
+ this.messages[id].map(m => {
+ this.$set(this.orderMessages, m.timestamp, {
+ msg: m.msg,
+ pubkey: m.pubkey
+ })
+ })
+ this.$refs.chatCard.scrollIntoView({
+ behavior: 'smooth',
+ inline: 'nearest'
+ })
+ this.updateLastSeenMsg(id)
+ //"ea2fbf6c91aa228603681e2cc34bb06e34e6d1375fa4d6c35756182b2fa3307f"
+ //"c7435a04875c26e28db91a377bd6e991dbfefeefea8258415f3ae0c716ed2335"
+ },
+ startChat(room_name) {
+ if (this.ws) {
+ this.ws.close()
+ }
+ if (location.protocol == 'https:') {
+ ws_scheme = 'wss://'
+ } else {
+ ws_scheme = 'ws://'
+ }
+ ws = new WebSocket(
+ ws_scheme + location.host + '/diagonalley/ws/' + room_name
+ )
+
+ function checkWebSocket(event) {
+ if (ws.readyState === WebSocket.CLOSED) {
+ console.log('WebSocket CLOSED: Reopening')
+ ws = new WebSocket(
+ ws_scheme + location.host + '/diagonalley/ws/' + room_name
+ )
+ }
+ }
+
+ ws.onmessage = event => {
+ let event_data = JSON.parse(event.data)
+
+ this.$set(this.orderMessages, Date.now(), event_data)
+ this.updateLastSeenMsg(room_name)
+ }
+
+ ws.onclose = event => {
+ this.updateLastSeenMsg(room_name)
+ }
+
+ this.ws = ws
}
},
- created: function () {
+ async created() {
if (this.g.user.wallets.length) {
this.getStalls()
this.getProducts()
this.getZones()
- this.getOrders()
+ await this.getOrders()
this.getMarkets()
- this.customerKeys = [
- 'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b',
- 'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07'
- ]
+ await this.getAllMessages()
+ let keys = this.$q.localStorage.getItem(
+ `lnbits.diagonalley.${this.g.user.id}`
+ )
+ if (keys) {
+ this.keys = keys
+ }
+ setInterval(() => {
+ this.getAllMessages()
+ }, 300000)
}
}
})
+
{% endblock %}
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/order.html b/lnbits/extensions/diagonalley/templates/diagonalley/order.html
index aa9d0de4..81cdfc36 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/order.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/order.html
@@ -68,7 +68,7 @@
dense
emit-value
v-model="selectedOrder"
- :options="user.orders"
+ :options="Object.keys(user.orders)"
label="Order"
hint="Select an order from this merchant"
@input="val => { changeOrder() }"
@@ -187,7 +187,7 @@
msg: this.newMessage,
pubkey: this.user.keys.publickey
}
- ws.send(JSON.stringify(message))
+ this.ws.send(JSON.stringify(message))
this.clearMessage()
},
@@ -236,10 +236,16 @@
LNbits.utils.notifyApiError(error)
})
},
- changeOrder() {
- console.log(this.selectedOrder)
+ async changeOrder() {
+ this.products = this.user.orders[this.selectedOrder]
+ this.messages = {}
+ await this.getMessages(this.selectedOrder)
+ this.startChat(this.selectedOrder)
},
startChat(room_name) {
+ if (this.ws) {
+ this.ws.close()
+ }
if (location.protocol == 'https:') {
ws_scheme = 'wss://'
} else {
@@ -268,51 +274,51 @@
}
},
async created() {
- this.stall = JSON.parse('{{ stall | tojson }}')
let order_details = JSON.parse('{{ order | tojson }}')
let products = JSON.parse('{{ products | tojson }}')
-
let order_id = '{{ order_id }}'
+ this.stall = JSON.parse('{{ stall | tojson }}')
+ this.products = order_details.map(o => {
+ let product = products.find(p => p.id == o.product_id)
+ return {
+ quantity: o.quantity,
+ name: product.product,
+ image: product.image,
+ price: product.price
+ }
+ })
+
let data = this.$q.localStorage.getItem(`lnbits.diagonalley.data`)
try {
if (data) {
this.user = data
//add chat key (merchant pubkey) if not set
- if (!this.user.chats[`${order_id}`]) {
- this.$set(this.user.chats, order_id, [])
+ if (!this.user.orders[`${order_id}`]) {
+ this.$set(this.user.orders, order_id, this.products)
}
//this.$q.localStorage.set(`lnbits.diagonalley.data`, this.user)
} else {
// generate keys
await this.generateKeys()
// populate user data
- this.user.chats = {
- [`${order_id}`]: []
+ this.user.orders = {
+ [`${order_id}`]: this.products
}
- this.user.orders = []
+ //this.user.orders = []
}
- this.order_details = order_details
- this.products = order_details.map(o => {
- let product = products.find(p => p.id == o.product_id)
- return {
- quantity: o.quantity,
- name: product.product,
- image: product.image,
- price: product.price
- }
- })
+ //this.order_details = order_details
- this.user.orders = [...new Set([...this.user.orders, order_id])]
+ //this.user.orders = [...new Set([...this.user.orders, order_id])]
this.selectedOrder = order_id
await this.getMessages(order_id)
this.$q.localStorage.set(`lnbits.diagonalley.data`, this.user)
this.startChat(order_id)
- console.log(this.products)
+ console.log(this.messages)
} catch (e) {
console.error(e)
}
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index a3a04b1e..05163573 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -125,7 +125,7 @@
>
- {{cat}}
@@ -409,8 +409,18 @@
if (res.data.paid) {
this.$q.notify({
type: 'positive',
- message: 'Sats received, thanks!',
- icon: 'thumb_up'
+ multiLine: true,
+ message:
+ "Sats received, thanks! You'l be redirected to the order page...",
+ icon: 'thumb_up',
+ actions: [
+ {
+ label: 'See Order',
+ handler: () => {
+ window.location.href = `/diagonalley/order/?merch=${this.stall.id}&invoice_id=${this.qrCodeDialog.data.payment_hash}`
+ }
+ }
+ ]
})
clearInterval(this.qrCodeDialog.paymentChecker)
this.resetCart()
diff --git a/lnbits/extensions/diagonalley/views.py b/lnbits/extensions/diagonalley/views.py
index 27875287..2bf98211 100644
--- a/lnbits/extensions/diagonalley/views.py
+++ b/lnbits/extensions/diagonalley/views.py
@@ -94,7 +94,9 @@ async def display(request: Request, market_id):
@diagonalley_ext.get("/order", response_class=HTMLResponse)
-async def chat_page(request: Request, merch: str = Query(...), invoice_id: str = Query(...)):
+async def chat_page(
+ request: Request, merch: str = Query(...), invoice_id: str = Query(...)
+):
stall = await get_diagonalley_stall(merch)
order = await get_diagonalley_order_invoiceid(invoice_id)
_order = await get_diagonalley_order_details(order.id)
@@ -110,9 +112,9 @@ async def chat_page(request: Request, merch: str = Query(...), invoice_id: str =
"publickey": stall.publickey,
"wallet": stall.wallet,
},
- "order_id": order.id,
+ "order_id": order.invoiceid,
"order": [details.dict() for details in _order],
- "products": [product.dict() for product in products]
+ "products": [product.dict() for product in products],
},
)
@@ -123,6 +125,41 @@ async def chat_page(request: Request, merch: str = Query(...), invoice_id: str =
notifier = Notifier()
+# class ConnectionManager:
+# def __init__(self):
+# self.active_connections: List[WebSocket] = []
+
+# async def connect(self, websocket: WebSocket, room_name: str):
+# await websocket.accept()
+# websocket.id = room_name
+# self.active_connections.append(websocket)
+
+# def disconnect(self, websocket: WebSocket):
+# self.active_connections.remove(websocket)
+
+# async def send_personal_message(self, message: str, room_name: str):
+# for connection in self.active_connections:
+# if connection.id == room_name:
+# await connection.send_text(message)
+
+# async def broadcast(self, message: str):
+# for connection in self.active_connections:
+# await connection.send_text(message)
+
+
+# manager = ConnectionManager()
+
+
+# @diagonalley_ext.websocket("/ws/{room_name}")
+# async def websocket_endpoint(websocket: WebSocket, room_name: str):
+# await manager.connect(websocket, room_name)
+# try:
+# while True:
+# data = await websocket.receive_text()
+# except WebSocketDisconnect:
+# manager.disconnect(websocket)
+
+
@diagonalley_ext.websocket("/ws/{room_name}")
async def websocket_endpoint(
websocket: WebSocket, room_name: str, background_tasks: BackgroundTasks
@@ -143,7 +180,7 @@ async def websocket_endpoint(
if websocket not in room_members:
print("Sender not in room member: Reconnecting...")
await notifier.connect(websocket, room_name)
-
+ print("ENDPOINT", data)
await notifier._notify(data, room_name)
except WebSocketDisconnect:
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index f84ea8e9..2f375357 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -1,10 +1,10 @@
from base64 import urlsafe_b64encode
from http import HTTPStatus
-from typing import List
+from typing import List, Union
from uuid import uuid4
from fastapi import Request
-from fastapi.param_functions import Query
+from fastapi.param_functions import Body, Query
from fastapi.params import Depends
from loguru import logger
from secp256k1 import PrivateKey, PublicKey
@@ -34,6 +34,7 @@ from .crud import (
delete_diagonalley_product,
delete_diagonalley_stall,
delete_diagonalley_zone,
+ get_diagonalley_chat_by_merchant,
get_diagonalley_chat_messages,
get_diagonalley_latest_chat_messages,
get_diagonalley_market,
@@ -255,6 +256,14 @@ async def api_diagonalley_orders(
return {"message": "We could not retrieve the orders."}
+@diagonalley_ext.get("/api/v1/orders/{order_id}")
+async def api_diagonalley_order_by_id(order_id: str):
+ order = (await get_diagonalley_order(order_id)).dict()
+ order["details"] = await get_diagonalley_order_details(order_id)
+
+ return order
+
+
@diagonalley_ext.post("/api/v1/orders")
async def api_diagonalley_order_create(data: createOrder):
ref = urlsafe_short_hash()
@@ -488,6 +497,16 @@ async def api_diagonalley_generate_keys():
## MESSAGES/CHAT
+@diagonalley_ext.get("/api/v1/chat/messages/merchant")
+async def api_get_merchant_messages(
+ orders: str = Query(...), wallet: WalletTypeInfo = Depends(require_admin_key)
+):
+
+ return [
+ msg.dict() for msg in await get_diagonalley_chat_by_merchant(orders.split(","))
+ ]
+
+
@diagonalley_ext.get("/api/v1/chat/messages/{room_name}")
async def api_get_latest_chat_msg(room_name: str, all_messages: bool = Query(False)):
if all_messages:
From 4dcb8d2ca047477f66b5a562735c85a2b1d52239 Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Tue, 25 Oct 2022 11:55:55 +0100
Subject: [PATCH 107/226] redirect to order page
---
lnbits/extensions/diagonalley/templates/diagonalley/stall.html | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
index 05163573..1299f694 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/stall.html
@@ -425,6 +425,9 @@
clearInterval(this.qrCodeDialog.paymentChecker)
this.resetCart()
this.closeQrCodeDialog()
+ setTimeout(() => {
+ window.location.href = `/diagonalley/order/?merch=${this.stall.id}&invoice_id=${this.qrCodeDialog.data.payment_hash}`
+ }, 5000)
}
})
.catch(error => {
From 227eaeae75f7228934127fc114fffa1bff4e301f Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Tue, 25 Oct 2022 11:57:01 +0100
Subject: [PATCH 108/226] some cleanup
---
.../templates/diagonalley/index.html | 34 ++++++++-----------
lnbits/extensions/diagonalley/views_api.py | 4 +--
2 files changed, 15 insertions(+), 23 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/index.html b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
index f898fd40..0882fd2f 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/index.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/index.html
@@ -580,6 +580,7 @@
- Link to pass to stall relay
+ Stall simple UI shopping cart
{{ col.value }}
@@ -1952,17 +1953,22 @@
})
})
},
- shipOrder: function (order_id) {
- var self = this
-
+ shipOrder(order_id){
LNbits.api
.request(
'GET',
'/diagonalley/api/v1/orders/shipped/' + order_id,
this.g.user.wallets[0].inkey
)
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
+ .then((response) => {
+ console.log(response.data)
+ this.orders = _.reject(this.orders, (obj) => {
+ return obj.id == order_id
+ })
+ this.orders.push(mapOrders(response.data))
+ })
+ .catch((error) => {
+ LNbits.utils.notifyApiError(error)
})
},
exportOrdersCSV: function () {
@@ -1999,7 +2005,7 @@
]
}
}
- console.log({chat})
+ //console.log({chat})
this.$q.localStorage.set(`lnbits.diagonalley.${this.g.user.id}`, {
...data,
chat
@@ -2014,28 +2020,16 @@
let idx = this.orders.findIndex(f => f.invoiceid == key)
if (!lastMsgs[key]) {
this.updateLastSeenMsg(key)
- //this.orders[idx].unread = true
return
}
- console.log(
- 'Key',
- key,
- 'saved:',
- lastMsgs[key].timestamp,
- 'messages: ',
- Math.max(...this.messages[key].map(c => c.timestamp)),
- lastMsgs[key].timestamp <
- Math.max(...this.messages[key].map(c => c.timestamp))
- )
+
if (
lastMsgs[key].timestamp <
Math.max(...this.messages[key].map(c => c.timestamp))
) {
this.$set(this.orders[idx], 'unread', true)
- // this.orders[idx].unread = true
} else {
this.$set(this.orders[idx], 'unread', false)
- // this.orders[idx].unread = false
}
console.log('Order:', this.orders[idx])
}
diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py
index 2f375357..e6a4c2de 100644
--- a/lnbits/extensions/diagonalley/views_api.py
+++ b/lnbits/extensions/diagonalley/views_api.py
@@ -286,8 +286,6 @@ async def api_diagonalley_order_create(data: createOrder):
"payment_request": payment_request,
"order_reference": ref,
}
- # order = await create_diagonalley_order(wallet_id=wallet.wallet.id, data=data)
- # return order.dict()
@diagonalley_ext.get("/api/v1/orders/payments/{payment_hash}")
@@ -352,7 +350,7 @@ async def api_diagonalley_order_shipped(
"SELECT * FROM diagonalley.orders WHERE id = ?", (order_id,)
)
- return [order.dict() for order in get_diagonalley_orders(order["wallet"])]
+ return order
###List products based on stall id
From c282f38726c2b62b4f4588cb665624aeb4fcd0ce Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Tue, 25 Oct 2022 12:30:15 +0100
Subject: [PATCH 109/226] cleanup and keys management
---
.../templates/diagonalley/order.html | 104 ++++++++++++++++--
1 file changed, 92 insertions(+), 12 deletions(-)
diff --git a/lnbits/extensions/diagonalley/templates/diagonalley/order.html b/lnbits/extensions/diagonalley/templates/diagonalley/order.html
index 81cdfc36..fe5c7903 100644
--- a/lnbits/extensions/diagonalley/templates/diagonalley/order.html
+++ b/lnbits/extensions/diagonalley/templates/diagonalley/order.html
@@ -133,11 +133,15 @@
- Backup keys
Download your keys
- Restore keys
+ Restore keys
+
+ Delete data
Delete all data from browser
@@ -145,6 +149,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{% endblock %} {% block scripts %}
{% endblock %}
From 301cfb25d9cb20d9c6bfe94748ad4cd9683d46c8 Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Fri, 30 Dec 2022 10:59:24 +0000
Subject: [PATCH 163/226] market is not fully ready! added stall name
---
lnbits/extensions/shop/templates/shop/market.html | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lnbits/extensions/shop/templates/shop/market.html b/lnbits/extensions/shop/templates/shop/market.html
index a9585bca..29631f08 100644
--- a/lnbits/extensions/shop/templates/shop/market.html
+++ b/lnbits/extensions/shop/templates/shop/market.html
@@ -125,7 +125,7 @@
>
- {{cat}}
@@ -140,13 +140,17 @@
+ {{ stall.find(s => s.id == item.stall).name }}
- View details
+ Visit shop
{% endraw %}
From 77051d26090b4a8064d944fb48d2ca63e5f770d9 Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Fri, 30 Dec 2022 12:00:16 +0000
Subject: [PATCH 164/226] toggle shipped
---
lnbits/extensions/shop/templates/shop/index.html | 4 +++-
lnbits/extensions/shop/views_api.py | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/lnbits/extensions/shop/templates/shop/index.html b/lnbits/extensions/shop/templates/shop/index.html
index acb1e5a3..5c02677d 100644
--- a/lnbits/extensions/shop/templates/shop/index.html
+++ b/lnbits/extensions/shop/templates/shop/index.html
@@ -1194,10 +1194,12 @@
})
},
shipOrder(order_id) {
+ let shipped = this.orders.find(o => o.id == order_id).shipped
+ console.log(this.orders, order_id, shipped)
LNbits.api
.request(
'GET',
- '/shop/api/v1/orders/shipped/' + order_id,
+ `/shop/api/v1/orders/shipped/${order_id}?shipped=${!shipped}`,
this.g.user.wallets[0].inkey
)
.then(response => {
diff --git a/lnbits/extensions/shop/views_api.py b/lnbits/extensions/shop/views_api.py
index a85d1618..41e0ca88 100644
--- a/lnbits/extensions/shop/views_api.py
+++ b/lnbits/extensions/shop/views_api.py
@@ -358,12 +358,12 @@ async def api_shop_order_pubkey(payment_hash: str, pubkey: str):
@shop_ext.get("/api/v1/orders/shipped/{order_id}")
async def api_shop_order_shipped(
- order_id, wallet: WalletTypeInfo = Depends(get_key_type)
+ order_id, shipped: bool = Query(...), wallet: WalletTypeInfo = Depends(get_key_type)
):
await db.execute(
"UPDATE shop.orders SET shipped = ? WHERE id = ?",
(
- True,
+ shipped,
order_id,
),
)
From 715709ce2520c8f452c8e5f86a7a3864dcc97a54 Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Fri, 30 Dec 2022 12:03:34 +0000
Subject: [PATCH 165/226] fix typo
---
lnbits/extensions/shop/templates/shop/stall.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lnbits/extensions/shop/templates/shop/stall.html b/lnbits/extensions/shop/templates/shop/stall.html
index f1050e23..08e59888 100644
--- a/lnbits/extensions/shop/templates/shop/stall.html
+++ b/lnbits/extensions/shop/templates/shop/stall.html
@@ -78,7 +78,7 @@
color="primary"
label="Reset"
@click="resetCart"
- />
+ >
From 7c1a639796e86330b9d4d4bf1df247b2c8beb1ee Mon Sep 17 00:00:00 2001
From: Tiago Vasconcelos
Date: Fri, 30 Dec 2022 16:51:09 +0000
Subject: [PATCH 166/226] make markets great again
---
lnbits/extensions/shop/crud.py | 14 +-
.../shop/templates/shop/_dialogs.html | 4 +-
.../shop/templates/shop/_tables.html | 6 +-
.../extensions/shop/templates/shop/index.html | 90 ++---
.../shop/templates/shop/market.html | 347 +++---------------
.../extensions/shop/templates/shop/stall.html | 2 +-
lnbits/extensions/shop/views_api.py | 5 +-
7 files changed, 101 insertions(+), 367 deletions(-)
diff --git a/lnbits/extensions/shop/crud.py b/lnbits/extensions/shop/crud.py
index 682c1708..2411fd38 100644
--- a/lnbits/extensions/shop/crud.py
+++ b/lnbits/extensions/shop/crud.py
@@ -399,8 +399,18 @@ async def create_shop_market_stalls(market_id: str, data: List[CreateMarketStall
return market_stalls
-async def update_shop_market(market_id):
- pass
+async def update_shop_market(market_id: str, name: str):
+ await db.execute(
+ "UPDATE shop.markets SET name = ? WHERE id = ?",
+ (name, market_id),
+ )
+ await db.execute(
+ "DELETE FROM shop.market_stalls WHERE marketid = ?",
+ (market_id,),
+ )
+
+ market = await get_shop_market(market_id)
+ return market
### CHAT / MESSAGES
diff --git a/lnbits/extensions/shop/templates/shop/_dialogs.html b/lnbits/extensions/shop/templates/shop/_dialogs.html
index 3718f38c..d2c22350 100644
--- a/lnbits/extensions/shop/templates/shop/_dialogs.html
+++ b/lnbits/extensions/shop/templates/shop/_dialogs.html
@@ -195,12 +195,12 @@
>
Link to pass to stall relay
- {{ col.value }}
+ {{ col.name == 'stalls' ? stallName(col.value) : col.value }}
@@ -369,7 +369,7 @@
flat
dense
size="xs"
- @click="deleteStall(props.row.id)"
+ @click="deleteMarket(props.row.id)"
icon="cancel"
color="pink"
>
diff --git a/lnbits/extensions/shop/templates/shop/index.html b/lnbits/extensions/shop/templates/shop/index.html
index 5c02677d..4d995fce 100644
--- a/lnbits/extensions/shop/templates/shop/index.html
+++ b/lnbits/extensions/shop/templates/shop/index.html
@@ -213,12 +213,12 @@
const mapMarkets = obj => {
obj._data = _.clone(obj)
- obj.stores = []
+ obj.stalls = []
LNbits.api
.request('GET', `/shop/api/v1/markets/${obj.id}/stalls`, null)
.then(response => {
if (response.data) {
- obj.stores = response.data.map(s => s.name).toString()
+ obj.stalls = response.data.map(s => s.id) //.toString()
}
})
.catch(error => {
@@ -460,10 +460,10 @@
field: 'name'
},
{
- name: 'stores',
+ name: 'stalls',
align: 'left',
label: 'Stalls',
- field: 'stores'
+ field: 'stalls'
}
],
pagination: {
@@ -637,6 +637,9 @@
////////////////////////////////////////
////////////////STALLS//////////////////
////////////////////////////////////////
+ stallName(id) {
+ return id.map(c => this.stalls.find(s => s.id == c).name).toString()
+ },
getStalls: function () {
var self = this
LNbits.api
@@ -1035,44 +1038,38 @@
})
},
- openShopUpdateDialog: function (linkId) {
- var self = this
- var link = _.findWhere(self.markets, {id: linkId})
-
- this.marketDialog.data = _.clone(link._data)
+ openMarketUpdateDialog(linkId) {
+ var link = _.findWhere(this.markets, {id: linkId})
+ this.marketDialog.data = link
this.marketDialog.show = true
},
- sendMarketplaceFormData: function () {
+ sendMarketplaceFormData() {
let data = {...this.marketDialog.data}
if (!data.usr) {
data.usr = this.g.user.id
}
-
if (data.id) {
- this.updateZone(data)
+ this.updateMarketplace(data)
} else {
this.createMarketplace(data)
}
},
- updateShop: function (data) {
- var self = this
+ updateMarketplace(data) {
LNbits.api
.request(
'PUT',
- '/shop/api/v1/shops' + data.id,
- _.findWhere(self.g.user.wallets, {
- id: self.marketDialog.data.wallet
- }).inkey,
- _.pick(data, 'countries', 'cost')
+ '/shop/api/v1/markets/' + data.id,
+ this.g.user.wallets[0].inkey,
+ data
)
- .then(function (response) {
- self.markets = _.reject(self.markets, function (obj) {
+ .then(response => {
+ this.markets = _.reject(this.markets, obj => {
return obj.id == data.id
})
- self.markets.push(mapShops(response.data))
- self.marketDialog.show = false
- self.marketDialog.data = {}
+ this.markets.push(mapMarkets(response.data))
+ this.marketDialog.show = false
+ this.marketDialog.data = {}
data = {}
})
.catch(function (error) {
@@ -1097,21 +1094,20 @@
LNbits.utils.notifyApiError(error)
})
},
- deleteShop: function (shopId) {
- var self = this
- var shop = _.findWhere(self.markets, {id: shopId})
+ deleteMarket(shopId) {
+ let market = _.findWhere(this.markets, {id: shopId})
LNbits.utils
- .confirmDialog('Are you sure you want to delete this Shop link?')
- .onOk(function () {
+ .confirmDialog('Are you sure you want to delete this Marketplace?')
+ .onOk(() => {
LNbits.api
.request(
'DELETE',
- '/shop/api/v1/shops/' + shopId,
- _.findWhere(self.g.user.wallets, {id: shop.wallet}).inkey
+ '/shop/api/v1/markets/' + shopId,
+ this.g.user.wallets[0].inkey
)
- .then(function (response) {
- self.markets = _.reject(self.markets, function (obj) {
+ .then(response => {
+ this.markets = _.reject(this.markets, obj => {
return obj.id == shopId
})
})
@@ -1144,32 +1140,6 @@
LNbits.utils.notifyApiError(error)
})
},
- /*createOrder: function () {
- var data = {
- address: this.orderDialog.data.address,
- email: this.orderDialog.data.email,
- quantity: this.orderDialog.data.quantity,
- shippingzone: this.orderDialog.data.shippingzone
- }
- var self = this
-
- LNbits.api
- .request(
- 'POST',
- '/shop/api/v1/orders',
- _.findWhere(self.g.user.wallets, {id: self.orderDialog.data.wallet})
- .inkey,
- data
- )
- .then(function (response) {
- self.orders.push(mapOrders(response.data))
- self.orderDialog.show = false
- self.orderDialog.data = {}
- })
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
- },*/
deleteOrder: function (orderId) {
var self = this
var order = _.findWhere(self.orders, {id: orderId})
@@ -1195,7 +1165,6 @@
},
shipOrder(order_id) {
let shipped = this.orders.find(o => o.id == order_id).shipped
- console.log(this.orders, order_id, shipped)
LNbits.api
.request(
'GET',
@@ -1383,7 +1352,6 @@
this.diagonAlley =
this.$q.localStorage.getItem('lnbits.DAmode') || false
this.currencies.unit = '{{ currency }}'
- console.log(this.currencies.unit, '{{currency}}')
await this.getCurrencies()
this.getStalls()
this.getProducts()
diff --git a/lnbits/extensions/shop/templates/shop/market.html b/lnbits/extensions/shop/templates/shop/market.html
index 29631f08..4aadfa26 100644
--- a/lnbits/extensions/shop/templates/shop/market.html
+++ b/lnbits/extensions/shop/templates/shop/market.html
@@ -21,49 +21,6 @@
-
- {% raw %}
-
- {{ cart.size }}
-
- {% endraw %}
-
-
- {% raw %}
-
-
- {{p.quantity}} x
-
-
-
-
-
-
-
-
- {{ p.name }}
-
-
-
- {{p.price}} sats
-
-
- {% endraw %}
-
-
-
-
-
-
-
@@ -85,22 +42,6 @@
>
- Add to cart
-