From 6b2f3d05d51d7aabe8a00dac10f9dfc3d96134a9 Mon Sep 17 00:00:00 2001 From: benarc Date: Thu, 27 Jan 2022 12:24:38 +0000 Subject: [PATCH 001/174] 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!
+

    +
  1. Create Shipping Zones you're willing to ship to
  2. +
  3. Create a Stall to list yiur products on
  4. +
  5. Create products to put on the Stall
  6. +
  7. List stalls on a simple frontend shop page, or point at Nostr shop client key
  8. +
+ 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 %} + + + {% endraw %} + +
+
+ + + +
+
+
Products
+
+
+ Export to CSV +
+
+ + {% raw %} + + + {% endraw %} + +
+
+ + + +
+
+
Stalls
+
+
+ Export to CSV +
+
+ + {% raw %} + + + {% endraw %} + +
+
+ + + +
+
+
Shipping Zones
+
+
+ Export to CSV +
+
+ + {% raw %} + + + {% 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/174] 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/174] 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/174] 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/174] 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/174] 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/174] 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/174] 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 @@ >
-
+
@@ -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/174] 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/174] 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/174] 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/174] 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/174] 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/174] 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/174] 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 @@ >
-
+
@@ -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/174] 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/174] 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 zcmeAS@N?(olHy`uVBq!ia0y~yV4lIiz_f{jnSp_!J*+XCfq{V~-O<;Pfnj4m_n$;o z1_lO&WRD0By z_2c^wZ(hGXapJ_OQ>U(6xpMW&l`EGoU%hhm{o8l%-n_ka^Va>l_fDQXdFITS%azA)?-@bkN^y#;6 z-aLNv_`><~Cr_Nbee3pv`wyN!efH+n>x&mIT)cSk^{ZDmu3x`=>GHX=XWzblbLaM* zXHTD?k@bJ>bOSf*^eDdh=sgox! zUby(+-u)|=uRMDA@ZQ~fr%#=J{p$6rm#^NwdHep|`-cx6oIP{q|NsBh!RwbZFfcGC zdAqx0oX+{8#K6G7UgGKN%Kn%~oKs2Q;X9oK1_q9;o-U3d6}R5r{at>!MB>218v(Z* z*d8xRo+&!v?9Rx!(=9(XiKi^8a8x(a&$0UW>HmLrKg*(oEt!|L{G9f!vd;hh^v$0w z7v|1#5o8$7z-L#wl<^bE`urA6AAw~Cg3AmXXB={wafl_6OSpyekcb*b@C=UN845m$ zN6QYSjI8Ecsmk9=mO^4=Kmsb5d zbF=vQ{MvO}1-OOP6wh#XpFG^W`P-$>8x0f-X3TvaZ}IEY&7pHuiy%g$d#|EK4#=M;8o**WjY-nwsd3>N+~2%pR-?8hPe zitqE(cMCXg8YVjJO)Q(n-X9Supms&-*=pCcJ=3^^vv`UZ-p489O5& zdPe@9$O12K5No~I+)vXC7OpdRe0EXrt>Qy1vkuKU&DCESJtH7^hIm*1O(C@_BF|<% zO1=e>x}#&5?l&XAe}-qL<$Dg{SDc&A%vpV?CF+pR=`)skJ}aL0%$z#o^E!it^9**Y zKHH=2vqJsMckeTut(?y7k*~f@mFKZ_n_;lc_}SJ+$?G_Tv$!^2*0V{A1=;no-F115 z2scP9EsBz7}rR^l6EFIM05*i1en&S0WX*QJ$@x z2JQUDdL_M%Vec+FoesPrqIPIaLHy0IiKjo=>0Z4i-R`cl?2yZh!|gNA@yl(Dc&B{x z^8b0s`5eNDeDZ0^azA=nmORN{^1u3EZlcl|u0%5{=6A^-Zk{d5jIH{x?Q1bquzTn8 z)849=e?2-_=)KZFFs;=B5Ot=_D&=cd}dU;00O z^9C7i;lwb`%@-r~UVXiF|DJ$-Yu3xj-37T&EN$_|57#c{n{1ChyvO%WT}6$#sM?`5 z5^0MKzkmG{^l8Dll&74AxQpk+s)T{TW>x;|9=0(M8)tr89+XmF4yMEB`FI8#05VI3{t~@7?>i zx8Ev>pTSYAlUSA~_J7NBPJ3?Q#6G(-&8w@wug>}9uH(~U`N$yu-M^Wkx3^r#-`~<{ z;9X<9$)qW?ytUK7UG&-AYcqe}^a#`aw1y>7=}e>EaqG_~UzF`t_i2f=Jk$L3=hBJq zs{CefY)+bCoqqe~is`ljYKPW{JX@Kv8fdpz&eL1`Tl$d84Ci*s zWqOM0F#Z^|b{ZTmnHddAAq(_Ap901B)l|Qkhg@bH-1R0NB)miK z_cTqP7Re2#>r%Od6WiWw@&`#f?tT*slD?r=4VK<lD%!z5+KdA_B_%GkTehMe3@YYm^mi4H$2CN2vi?(#~eZJ*o!C8<`)MX8A;sSHL2hL*a9M!H7EAqJLK#wJ#VX4(b@Rt5$Qm;dfU(U6;; zl9^VCTf@gbS5R0=f@}!RPb(=;EJ|f?Ovz75Rq)JBOiv9;O-!jQJeg_(3UE(XKbLh* G2~7YIWw#>$ 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/174] 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 %} -
-
- +
+
+ +
+ {{ stall.name }} +
+
+ + + +
+ +
- - -
{{ item.product }}
-
{{ item.description }}
+ +
+
+ Special Price +
+ {{ item.price }} satsBTC {{ (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/174] 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/174] 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/174] 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/174] 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 }} satsBTC {{ (item.price / 1e8).toFixed(8) }} - + + >
Update Product - - Create ProductCheckout 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/174] 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/174] 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/174] 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 }} satsBTC {{ (item.price / 1e8).toFixed(8) }} - + + >
Update Product - - Create ProductCheckout 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/174] 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/174] 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/174] 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!
-

    -
  1. Create Shipping Zones you're willing to ship to
  2. -
  3. Create a Stall to list yiur products on
  4. -
  5. Create products to put on the Stall
  6. -
  7. List stalls on a simple frontend shop page, or point at Nostr shop client key
  8. -
- 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!

+ +
    +
  1. Create Shipping Zones you're willing to ship to
  2. +
  3. Create a Stall to list yiur products on
  4. +
  5. Create products to put on the Stall
  6. +
  7. + List stalls on a simple frontend shop page, or point at Nostr shop + client key +
  8. +
+ 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/174] 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/174] 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 %} {% 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/174] 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/174] 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/174] 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/174] 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/174] 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/174] 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 RelayUpdate Marketplace LaunchLaunch 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/174] 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/174] 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 %} + + + {% 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/174] 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 }} satsBTC {{ (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/174] 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/174] 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 StoreCreate 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/174] 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/174] 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/174] 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 %} +
+ - -
+
-->
@@ -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/174] 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/174] 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/174] 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" > + + + Cancel Date: Tue, 4 Oct 2022 09:59:34 +0100 Subject: [PATCH 103/174] 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/174] 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 %} -
- - - - - - - - -

- 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/174] 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/174] 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/174] 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/174] 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/174] 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 161/174] 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 162/174] 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 163/174] 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 164/174] 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 -
{{ item.product }} @@ -112,13 +53,23 @@
- - {{ item.price }} satsBTC {{ (item.price / 1e8).toFixed(8) }} +
+ {{ item.stallName }} +
+ + {{ item.price }} satsBTC {{ (item.price / 1e8).toFixed(8) }} + + + {{ getAmountFormated(item.price, item.currency) }} + ({{ getValueInSats(item.price, item.currency) }} sats) + {{item.quantity}} left - {{ stall.find(s => s.id == item.stall).name }} + {{ item.stallName }}
- - - - - - - - -

Select the shipping zone:

-
- -
-
- {% raw %} Total: {{ finalCost }} {% endraw %} -
-
- Checkout - Cancel -
-
-
-
- - - - - - -
- Copy invoice - Close -
-
-
{% endblock %} {% block scripts %} - {% endblock %} diff --git a/lnbits/extensions/shop/templates/shop/stall.html b/lnbits/extensions/shop/templates/shop/stall.html index 08e59888..dc6c2049 100644 --- a/lnbits/extensions/shop/templates/shop/stall.html +++ b/lnbits/extensions/shop/templates/shop/stall.html @@ -300,7 +300,7 @@ {% endblock %} {% block scripts %} From f998681dc071a5a3cc8f69dc2a283e1b5dd27e5d Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 3 Jan 2023 20:51:38 +0000 Subject: [PATCH 166/174] int to float --- lnbits/extensions/shop/templates/shop/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/shop/templates/shop/index.html b/lnbits/extensions/shop/templates/shop/index.html index 4d995fce..49ddf6fb 100644 --- a/lnbits/extensions/shop/templates/shop/index.html +++ b/lnbits/extensions/shop/templates/shop/index.html @@ -946,7 +946,7 @@ sendZoneFormData: function () { var data = { countries: String(this.zoneDialog.data.countries), - cost: parseInt(this.zoneDialog.data.cost) + cost: parseFloat(this.zoneDialog.data.cost) } if (this.zoneDialog.data.id) { data.id = this.zoneDialog.data.id From dc2689f2c1f38b7fda0199f307729effff02025f Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 3 Jan 2023 20:54:38 +0000 Subject: [PATCH 167/174] Name fix --- lnbits/extensions/shop/templates/shop/market.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/shop/templates/shop/market.html b/lnbits/extensions/shop/templates/shop/market.html index 96695041..403e9fa8 100644 --- a/lnbits/extensions/shop/templates/shop/market.html +++ b/lnbits/extensions/shop/templates/shop/market.html @@ -91,7 +91,7 @@ - {{ item.stallName }} + Stall: {{ item.stallName }} - Visit shop + Visit Stall {% endraw %} From fc3465c750f1edbf3ccdf8e756f6bc8d9005a147 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 3 Jan 2023 21:01:30 +0000 Subject: [PATCH 168/174] Added some titling --- lnbits/extensions/shop/templates/shop/market.html | 2 +- lnbits/extensions/shop/templates/shop/stall.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/shop/templates/shop/market.html b/lnbits/extensions/shop/templates/shop/market.html index 403e9fa8..6763ef3b 100644 --- a/lnbits/extensions/shop/templates/shop/market.html +++ b/lnbits/extensions/shop/templates/shop/market.html @@ -3,7 +3,7 @@
- {{ market.name }} + Market: {{ market.name }}
- {{ stall.name }} + Stall: {{ stall.name }}
Date: Wed, 4 Jan 2023 11:16:20 +0000 Subject: [PATCH 169/174] mypyfication and format --- lnbits/extensions/shop/crud.py | 9 +-- lnbits/extensions/shop/tasks.py | 2 +- lnbits/extensions/shop/views.py | 32 ++++++--- lnbits/extensions/shop/views_api.py | 105 +++++++++++++++------------- 4 files changed, 84 insertions(+), 64 deletions(-) diff --git a/lnbits/extensions/shop/crud.py b/lnbits/extensions/shop/crud.py index 2411fd38..c58dfb3e 100644 --- a/lnbits/extensions/shop/crud.py +++ b/lnbits/extensions/shop/crud.py @@ -209,7 +209,7 @@ async def delete_shop_stall(stall_id: str) -> None: ###Orders -async def create_shop_order(data: createOrder, invoiceid: str) -> Orders: +async def create_shop_order(data: createOrder, invoiceid: str): returning = "" if db.type == SQLITE else "RETURNING ID" method = db.execute if db.type == SQLITE else db.fetchone @@ -234,9 +234,6 @@ async def create_shop_order(data: createOrder, invoiceid: str) -> Orders: return result._result_proxy.lastrowid else: return result[0] - # link = await get_shop_order(link.id) - # assert link, "Newly created link couldn't be retrieved" - # return link async def create_shop_order_details(order_id: str, data: List[createOrderDetails]): @@ -278,7 +275,7 @@ async def get_shop_order_invoiceid(invoice_id: str) -> Optional[Orders]: return Orders(**row) if row else None -async def set_shop_order_paid(payment_hash: str) -> Orders: +async def set_shop_order_paid(payment_hash: str): await db.execute( """ UPDATE shop.orders @@ -380,7 +377,7 @@ async def create_shop_market(data: CreateMarket): return market -async def create_shop_market_stalls(market_id: str, data: List[CreateMarketStalls]): +async def create_shop_market_stalls(market_id: str, data: List[str]): for stallid in data: id = urlsafe_short_hash() diff --git a/lnbits/extensions/shop/tasks.py b/lnbits/extensions/shop/tasks.py index 0e742466..3dc460aa 100644 --- a/lnbits/extensions/shop/tasks.py +++ b/lnbits/extensions/shop/tasks.py @@ -23,7 +23,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") != "shop": + if payment.extra and payment.extra.get("tag") != "shop": return order = await get_shop_order_invoiceid(payment.payment_hash) diff --git a/lnbits/extensions/shop/views.py b/lnbits/extensions/shop/views.py index 8dad15ae..309ed134 100644 --- a/lnbits/extensions/shop/views.py +++ b/lnbits/extensions/shop/views.py @@ -2,8 +2,14 @@ import json from http import HTTPStatus from typing import List -from fastapi import BackgroundTasks, Query, Request, WebSocket, WebSocketDisconnect -from fastapi.params import Depends +from fastapi import ( + BackgroundTasks, + Depends, + Query, + Request, + WebSocket, + WebSocketDisconnect, +) from fastapi.templating import Jinja2Templates from loguru import logger from starlette.exceptions import HTTPException @@ -42,6 +48,7 @@ async def index(request: Request, user: User = Depends(check_user_exists)): user=user.id, data=SetSettings(currency="sat", fiat_base_multiplier=1) ) settings = await get_shop_settings(user.id) + assert settings return shop_renderer().TemplateResponse( "shop/index.html", {"request": request, "user": user.dict(), "currency": settings.currency}, @@ -52,26 +59,28 @@ async def index(request: Request, user: User = Depends(check_user_exists)): async def stall(request: Request, stall_id): stall = await get_shop_stall(stall_id) products = await get_shop_products(stall_id) - zones = [] - for id in stall.shippingzones.split(","): - z = await get_shop_zone(id) - z = z.dict() - zones.append({"label": z["countries"], "cost": z["cost"], "value": z["id"]}) if not stall: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Stall does not exist." ) - stall = stall.dict() + zones = [] + for id in stall.shippingzones.split(","): + zone = await get_shop_zone(id) + assert zone + z = zone.dict() + zones.append({"label": z["countries"], "cost": z["cost"], "value": z["id"]}) - stall["zones"] = zones + _stall = stall.dict() + + _stall["zones"] = zones return shop_renderer().TemplateResponse( "shop/stall.html", { "request": request, - "stall": stall, + "stall": _stall, "products": [product.dict() for product in products], }, ) @@ -109,9 +118,12 @@ async def order_chat( keys: str = Query(None), ): stall = await get_shop_stall(merch) + assert stall order = await get_shop_order_invoiceid(invoice_id) + assert order _order = await get_shop_order_details(order.id) products = await get_shop_products(stall.id) + assert products return shop_renderer().TemplateResponse( "shop/order.html", diff --git a/lnbits/extensions/shop/views_api.py b/lnbits/extensions/shop/views_api.py index bc098dee..87374b20 100644 --- a/lnbits/extensions/shop/views_api.py +++ b/lnbits/extensions/shop/views_api.py @@ -3,11 +3,8 @@ from http import HTTPStatus from typing import List, Union from uuid import uuid4 -from fastapi import Request -from fastapi.param_functions import Body, Query -from fastapi.params import Depends +from fastapi import Body, Depends, Query, Request from loguru import logger -from secp256k1 import PrivateKey, PublicKey from starlette.exceptions import HTTPException from lnbits.core.crud import get_user @@ -63,6 +60,7 @@ from .crud import ( ) from .models import ( CreateMarket, + CreateMarketStalls, Orders, Products, SetSettings, @@ -86,7 +84,8 @@ async def api_shop_products( wallet_ids = [wallet.wallet.id] if all_stalls: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] stalls = [stall.id for stall in await get_shop_stalls(wallet_ids)] @@ -106,7 +105,11 @@ async def api_shop_product_create( # For fiat currencies, # we multiply by data.fiat_base_multiplier (usually 100) to save the value in cents. settings = await get_shop_settings(user=wallet.wallet.user) + assert settings + stall = await get_shop_stall(stall_id=data.stall) + assert stall + if stall.currency != "sat": data.price *= settings.fiat_base_multiplier @@ -122,7 +125,7 @@ async def api_shop_product_create( product = await update_shop_product(product_id, **data.dict()) else: product = await create_shop_product(data=data) - + assert product return product.dict() @@ -136,6 +139,8 @@ async def api_shop_products_delete( return {"message": "Product does not exist."} stall = await get_shop_stall(product.stall) + assert stall + if stall.wallet != wallet.wallet.id: return {"message": "Not your Shop."} @@ -201,7 +206,8 @@ async def api_shop_stalls( wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] return [stall.dict() for stall in await get_shop_stalls(wallet_ids)] @@ -225,7 +231,7 @@ async def api_shop_stall_create( stall = await update_shop_stall(stall_id, **data.dict()) else: stall = await create_shop_stall(data=data) - + assert stall return stall.dict() @@ -254,16 +260,17 @@ async def api_shop_orders( ): wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] orders = await get_shop_orders(wallet_ids) if not orders: return orders_with_details = [] for order in orders: - order = order.dict() - order["details"] = await get_shop_order_details(order["id"]) - orders_with_details.append(order) + _order = order.dict() + _order["details"] = await get_shop_order_details(_order["id"]) + orders_with_details.append(_order) try: return orders_with_details # [order for order in orders] # return [order.dict() for order in await get_shop_orders(wallet_ids)] @@ -273,10 +280,12 @@ async def api_shop_orders( @shop_ext.get("/api/v1/orders/{order_id}") async def api_shop_order_by_id(order_id: str): - order = (await get_shop_order(order_id)).dict() - order["details"] = await get_shop_order_details(order_id) + order = await get_shop_order(order_id) + assert order + _order = order.dict() + _order["details"] = await get_shop_order_details(order_id) - return order + return _order @shop_ext.post("/api/v1/orders") @@ -336,18 +345,18 @@ async def api_shop_order_delete( raise HTTPException(status_code=HTTPStatus.NO_CONTENT) -@shop_ext.get("/api/v1/orders/paid/{order_id}") -async def api_shop_order_paid( - order_id, wallet: WalletTypeInfo = Depends(require_admin_key) -): - await db.execute( - "UPDATE shop.orders SET paid = ? WHERE id = ?", - ( - True, - order_id, - ), - ) - return "", HTTPStatus.OK +# @shop_ext.get("/api/v1/orders/paid/{order_id}") +# async def api_shop_order_paid( +# order_id, wallet: WalletTypeInfo = Depends(require_admin_key) +# ): +# await db.execute( +# "UPDATE shop.orders SET paid = ? WHERE id = ?", +# ( +# True, +# order_id, +# ), +# ) +# return "", HTTPStatus.OK @shop_ext.get("/api/v1/order/pubkey/{payment_hash}/{pubkey}") @@ -375,33 +384,33 @@ async def api_shop_order_shipped( ###List products based on stall id -@shop_ext.get("/api/v1/stall/products/{stall_id}") -async def api_shop_stall_products( - stall_id, wallet: WalletTypeInfo = Depends(get_key_type) -): +# @shop_ext.get("/api/v1/stall/products/{stall_id}") +# async def api_shop_stall_products( +# stall_id, wallet: WalletTypeInfo = Depends(get_key_type) +# ): - rows = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)) - if not rows: - return {"message": "Stall does not exist."} +# rows = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)) +# if not rows: +# return {"message": "Stall does not exist."} - products = db.fetchone("SELECT * FROM shop.products WHERE wallet = ?", (rows[1],)) - if not products: - return {"message": "No products"} +# products = db.fetchone("SELECT * FROM shop.products WHERE wallet = ?", (rows[1],)) +# if not products: +# return {"message": "No products"} - return [products.dict() for products in await get_shop_products(rows[1])] +# return [products.dict() for products in await get_shop_products(rows[1])] ###Check a product has been shipped -@shop_ext.get("/api/v1/stall/checkshipped/{checking_id}") -async def api_shop_stall_checkshipped( - checking_id, wallet: WalletTypeInfo = Depends(get_key_type) -): - rows = await db.fetchone( - "SELECT * FROM shop.orders WHERE invoiceid = ?", (checking_id,) - ) - return {"shipped": rows["shipped"]} +# @shop_ext.get("/api/v1/stall/checkshipped/{checking_id}") +# async def api_shop_stall_checkshipped( +# checking_id, wallet: WalletTypeInfo = Depends(get_key_type) +# ): +# rows = await db.fetchone( +# "SELECT * FROM shop.orders WHERE invoiceid = ?", (checking_id,) +# ) +# return {"shipped": rows["shipped"]} ## @@ -426,7 +435,7 @@ async def api_shop_market_stalls(market_id: str): @shop_ext.post("/api/v1/markets") @shop_ext.put("/api/v1/markets/{market_id}") -async def api_shop_stall_create( +async def api_shop_market_create( data: CreateMarket, market_id: str = None, wallet: WalletTypeInfo = Depends(require_invoice_key), @@ -443,6 +452,7 @@ async def api_shop_stall_create( else: market = await create_shop_market(data=data) + assert market await create_shop_market_stalls(market_id=market.id, data=data.stalls) return market.dict() @@ -494,6 +504,7 @@ async def api_set_settings( return {"message": "Not your Shop."} settings = await get_shop_settings(user=usr) + assert settings if settings.user != wallet.wallet.user: return {"message": "Not your Shop."} From 7328d222a08ee66116d8322712a35e419fe10182 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Wed, 4 Jan 2023 11:28:43 +0000 Subject: [PATCH 170/174] prusnak's suggestion --- lnbits/extensions/shop/tasks.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/shop/tasks.py b/lnbits/extensions/shop/tasks.py index 3dc460aa..621e4fae 100644 --- a/lnbits/extensions/shop/tasks.py +++ b/lnbits/extensions/shop/tasks.py @@ -23,7 +23,10 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra and payment.extra.get("tag") != "shop": + if not payment.extra: + return + + if payment.extra.get("tag") != "shop": return order = await get_shop_order_invoiceid(payment.payment_hash) From 4a86acf8797df5cbe382e509d1a8914e7bd4868e Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 20:45:30 +0000 Subject: [PATCH 171/174] Added tile --- lnbits/extensions/shop/config.json | 2 +- .../shop/static/images/bitcoin-shop.png | Bin 0 -> 6034 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 lnbits/extensions/shop/static/images/bitcoin-shop.png diff --git a/lnbits/extensions/shop/config.json b/lnbits/extensions/shop/config.json index 90f117dd..eba0def9 100644 --- a/lnbits/extensions/shop/config.json +++ b/lnbits/extensions/shop/config.json @@ -1,6 +1,6 @@ { "name": "Shop", "short_description": "Make a webshop on LNbits", - "icon": "add_shopping_cart", + "tile": "/shop/static/images/bitcoin-shop.png", "contributors": ["benarc", "talvasconcelos"] } diff --git a/lnbits/extensions/shop/static/images/bitcoin-shop.png b/lnbits/extensions/shop/static/images/bitcoin-shop.png new file mode 100644 index 0000000000000000000000000000000000000000..debffbb28586737964b97aa788242ebf68ded85e GIT binary patch literal 6034 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+TQZ%U13aCb6$*;-(=u~X z85lGs)=sqbI2<6->VLUQNtE5V!y;vcpO}lQ%vLVf6#`kUVX{7Pzu0}HCW(lW&OE+oHhYI=UcZ)0D+c{)}%*b;;#(1}2O^K0W zYVqoz@7his4lN9xiQ6pIPiwMVyKY+=eD`Q&Si$}ISC>D{WouD+6qy#q_mS=6mu1OC z_teEAJuh~g?>w%vOW~vP_0akEEyQibDwbuWUiy4QX=BKngsshyCogp_??|4N7qD-_ z*T~0vjz+G(67hQ8pVo_eHf}mo8gi&vZO zwa!SwQY@gA@95{|{|DdSyw!S=(_V8H!>+iP@5wAL?y=4)z5ds(?Cvv8fjYKzJ=^x* zVo0;|T)%zm4Z#chd1GR>o0jtLxWmXc-{)wMji!&chDgJA<6p~U3<|ivtovDg?N1#8%lD#cMU~m&3=9lxN#5=*4F5rJ!QSPQ z85kHi3p^r=85s1GL71^(seKs(0|R@Br>`sfb4C^s9lh@OpbZQR43Z_T5hc#~xw)x% zB@E6*sfi`2DGKG8B^e6tp1uL$jeOz^45C?{E{-7;x8BaJE{M5Wd))r{z1{k6*WL4v zF8VVmRr<79i=oJEiw4esprA`ZPC-tyP6{+#o^~No$Y}1Q6r)VfSw5eegeGlS>N9KG za`$wL0|@4t06a{XENB13ecOiWyCN`|Y#qVt1coZM0!-G`#C8rXP2P*Zj_bv*!2DTn&%+_4Vy7 z`dJ(>Ygu4$uybgrsNMYhLvH$eJ{+1-*k~8}etyoM)$4Y3-MST(`iJ{~_KzC7Q>RaV ztgu-Uq*+x}<)Jotru<){52DGd4C^m1^A$c8Zu@^O{{yB*hGm)0Op+=qE&1A$-BMrg zI``-2=bKwHFSnH6*jb!@?%{zGSAYMlv(LW1F7@-Xv!~wf_wG9W*yit-%Oz!HX?vfS z?XG;Wuzkg- ziw7Hz%bl*ue|lKASTDSArte5Q!zLzhQ#`?aGOJVp?V<)B;V`0nSC7!P{A=@LIA?A@}JJW+8 zdASf_4TdQq3|?FeODzSbJpKL8TGe@G(z8vuv;Y08Yin!cGK)|VO01}`cwYUnVve$V zpMi-12x8FCWSFAoxKigqO;!K0z}VQc({!V`{FsG1S#EF7 zPyhe#Z{+)*f9u}u{T}zHuHG?~OL4{e_4*l#{Y)SYi5n6Rvt3&sAOE4;d7;3;1Os&j zUS3|C9}k+ZT)QR~vrb^qf~_)K4WC06^4i_3_6dJiy-~&gD1#P9NDzYt$j+2mYHf)H z8y0t;yH^)9t@5O4%Ea48+1Ew1UVrQ4Re4ZnrM*6b&*>xsgJbb_zby9VZ@c)lOuS5| z$n%|!YRTMJudHUxnziG*{=XjU{5uU(iq5THXO?#FwQgM1+SY#CU$t)0Wr@6B8gh#@ z^L4IOe^IE_-M_f>e)gZcyZA4B>W^QrY)^`xvw<>$&h514@_a?tukZ6sIBqA`(T>(dSJq=y6qVVC2Wh)ATK5cdul(01ooObi8+U;%s?osyQR*lD{{PYk&wb zJD5yzXZ;OO)zkJ2YTo$o-WG*zm!>aSXENn&?74-Tl!^$6wFG_Vxo=g1 zpSAKgOqo>w@8x=nuirkFOxI+Yb-Vjn$->Ob|2?+rc^o+$xjS4}XS&IhlTAXLiY#^E zZu;Vn1vp}zp9ISLGM{}Y!Jhi)p4tfy$H?Ab{^F;9@;-z)KKUYbFr?}F?c1KS#9Sr6 zu3NL_$+z42{_mx?^`3rOb^e(k7n1{r<8A5u1ir7!Lba8$D_LC-x?g- z%aOp|F8Su2SANCegqN3=KL2<5S@jb}u3e}3>vzsgxX+oQHSgWOxp^jsXHNgfXk%4T zI`J7}j30CRWozxn31>D5?qaN}s(-=B#S|ELL6FB!*<)@!i-z^zGSpL zKPS46-D+V$RsM=ES!eWT&y9)X=$&ykli^&`ol+w|o5%{Epm3pt;^YT8kwHm(^B%QM zyT&cvuzdU86P@q$QfwyK-F#HCP}0w3-aGls=G4CZYRnI=M~0kSW9#+7O7_Q|c|7Iw zohHmV=#$AZ|2F5bC5Z|m5BOz|TVA?aoXBKgX5;WErF_@JmcHY!-9?P9>pDiM`EYF$ zXxgOI%=Uj`WH!gb*N+Q*qHbj*-b_;4XvDpG&z<_WOOEJIRk(HeWz24NqhH{v?o)u{pWcXWG!*M&Cz%vhQqMC_?Z)P?D-i-O)9ImbOkKh^}r&* z@uo!fGgXV-^5!%C?ydRRdOyB`;f?JNwu|$&PuN%x^&})Fsx8f;GrEkiH(9vUQ|r99t|$LhhM)PN0x=We;71m7v;DbLPTNX#ua4P#OTaL?kG)Y+^Txb;A{(Ea zvAH~pP5rw5+%1o{=L)`lnH2x~BR6})NAS0!G>+;lpcj7r(F83Df5SXR0A~fgrxl;^XcbihDDxZ0krKITL*`czQr+*s5 z%vpgGcZsD0mKye6P2W3PMpot4?V}gZt>b2HNRQ?dw!S#?>A!C8E{)D+=7HS8to4(=G<^*3%kOshRUb+EH@Sy z<$2b)&RetK+m8vZMQyfW9J64Wxb&QeXK|Y2Y=*pumx~wr z%r+6Zbz|Ag&wCbpk2-c{1>5q&8a0zbqHd&V^{P8J{|b`MZR2zB^1MG|uJr?rf{4zW zW}ebQ7r(GO=W%Ynh~*SBDC> zwpJ`B-#0d6n_f>rvv-mKPffSHITg{&l63XPB~xYot*hh* z{JnijXHy(`-&{JN=zFZ`N4dg%1M;`rm^&?|AI#?|KEk}UGFBQ+>+v2yJnKRU5Ra7{>3}&4{n#=ZChNIm}YYP z#s!9p8yWQ8Xet(DOYvm}rl@XM{BVx#rpF;O)=RW>+ z$;ZITq(in};qA)3-O<87T6-taZQ19$g=Wl4|w z7Z~$utLCY+%{;)x+QHU#z-!*&+c*AHxU27fJI7xo(lGahyyvdUq;TDS8*%U7=@ULo zdlbE+N3>h~94AA`vGWsT`5X4c&6+(sa(CI=BmYcPkJdFgJANxINn$tJ=4={#BsoxK zSKH|e2euh5>CKCNv8{7jPjVZxihH{xx6j`9x%mbMI}?THFYof2FT7s3rL2nY-iqh`HvIL_jIS?i3BR>`rrk8Nj~OiO%Mv*ZSVUe*`Kip%G%@a+*d@%#XHc|hwu^~P zsw}&cX54$fptu*Bv*QoKyT=biK29G5-+HP1BsV>A1f4K6|N3q`y+kc>+SRL9KQ*$;O<22jtx@oLIU6N!vw9b<_?dJ5%$>Q%Y~L;WkGo#} z{8n6ZPIaM6P>AkAFQ<(x&n-{ydAf4?(_`VkpX&PWo#QThWXgN-=~I_qExf#La`5$w z;kpZ*n(7zzDLt->D%~6N_v7zWlX(+1FLY5-oF`SM)vMQZ# z6b~U_EXP$~w@5AqvAN4Yp zJes!qg1C-qOziyYQzq8lwq3L1tz1oQzF_|C(+}3y9eVLXBKe`fv`j%hwoSG@hYx<8 z9)B$63eP;&l>h(t7asM>s^6mgdh$fcFs+za{;OXr*8O3SODH-v=ZvL*k748!J*B|i z3|Zn2_P;xvlDAK4cBbre-KNTJjomNLdH!dVy1wqKX=HAiMDb^lZ{<(yJ+}J4b9lKX zET--$Yw-2*XZ{(lW;`^}t@%+sU4p^urKQ`%c*X+H*GyKGv5WPx{JtZK&z$3DDQr+K|_Ge!ii}NyUJIuQ7 z%iVSJ_J1|%ii!`N#-4P)g5gke=Jk^G^G{FLo%wawQ>#^W*^@O+Z`z>4t(khwP|t~D zU)lTPH~+mcE-5WvvUhv!Y4<5#i%-6MwrSZ@6SFJlvP^SsAKSEMrLBXG*yAIe!X+go z1}0N(uMMB}W9Ig6{TH6=2Oc|n{GWID$M4a0&8g?_X(mof735*d%+8)I)exZJ;_lAw z-Y1iokdW}FXTMC|ll}7h`j5@dbI;G%vtXNZrGKhLfm!UiPty61``7PeioKjB+VJpU zVpLSrGI^$5yLV^i<}O{ivh&m_udJ-BO>K=ouTFha@g?z{mVWw!-r5qG*9ZFCo*g=w zU#!5&uy)6kXH!@IxU>9USAT7Rvftqup^w>_7|Y(@n|ql#D$TR<%~O~*fy~+Uf)}9Du1s+l&{@xwQYUT`}_Or z?cctAYsq-R;$`9;?l(6#x3{&i)!4~@etzEldhz>`mtS}McyxFB>Ur}oIzDR(S}9Un zTf67WCGRcUwiy{1ObER?XP>4B*T($&c6aj3cdgr;d3l+pqJS3PjAE3>#u3N>|Vv!e?)K3OTE10$;v-nc%hbLxs(h>C=NlLRyw(uDX8SF>+dK<}6{``rF%bWh@F5 zroXno{PHrx4=+8ANheioZEYi_wO)RCbZy-PhOGr(azadga=+N8f)7Iz5?_7E<*+^|sl; zgb5EHCYHUwclO`k- Date: Wed, 4 Jan 2023 21:08:28 +0000 Subject: [PATCH 172/174] Changed naming to Market and Stall --- lnbits/extensions/{shop => market}/README.md | 4 +- .../extensions/{shop => market}/__init__.py | 22 +- lnbits/extensions/market/config.json | 6 + lnbits/extensions/{shop => market}/crud.py | 184 +++++------ .../extensions/{shop => market}/migrations.py | 24 +- lnbits/extensions/{shop => market}/models.py | 2 +- .../extensions/{shop => market}/notifier.py | 4 +- .../static/images/bitcoin-shop.png | Bin .../static/images/placeholder.png | Bin lnbits/extensions/{shop => market}/tasks.py | 18 +- .../templates/market}/_api_docs.html | 14 +- .../templates/market}/_chat_box.html | 0 .../templates/market}/_dialogs.html | 8 +- .../templates/market}/_tables.html | 10 +- .../templates/market}/index.html | 94 +++--- .../templates/market}/market.html | 4 +- .../templates/market}/order.html | 22 +- .../templates/market}/product.html | 0 .../templates/market}/stall.html | 12 +- lnbits/extensions/{shop => market}/views.py | 80 ++--- .../extensions/{shop => market}/views_api.py | 304 +++++++++--------- lnbits/extensions/shop/config.json | 6 - 22 files changed, 409 insertions(+), 409 deletions(-) rename lnbits/extensions/{shop => market}/README.md (54%) rename lnbits/extensions/{shop => market}/__init__.py (59%) create mode 100644 lnbits/extensions/market/config.json rename lnbits/extensions/{shop => market}/crud.py (54%) rename lnbits/extensions/{shop => market}/migrations.py (85%) rename lnbits/extensions/{shop => market}/models.py (98%) rename lnbits/extensions/{shop => market}/notifier.py (95%) rename lnbits/extensions/{shop => market}/static/images/bitcoin-shop.png (100%) rename lnbits/extensions/{shop => market}/static/images/placeholder.png (100%) rename lnbits/extensions/{shop => market}/tasks.py (62%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/_api_docs.html (88%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/_chat_box.html (100%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/_dialogs.html (98%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/_tables.html (97%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/index.html (93%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/market.html (97%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/order.html (95%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/product.html (100%) rename lnbits/extensions/{shop/templates/shop => market/templates/market}/stall.html (96%) rename lnbits/extensions/{shop => market}/views.py (67%) rename lnbits/extensions/{shop => market}/views_api.py (51%) delete mode 100644 lnbits/extensions/shop/config.json diff --git a/lnbits/extensions/shop/README.md b/lnbits/extensions/market/README.md similarity index 54% rename from lnbits/extensions/shop/README.md rename to lnbits/extensions/market/README.md index 86ac9ed9..22d38e0d 100644 --- a/lnbits/extensions/shop/README.md +++ b/lnbits/extensions/market/README.md @@ -1,7 +1,7 @@ -

Shop

+

Market

A movable market stand

Make a list of products to sell, point the list to an relay (or many), stack sats. -Shop 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. +Market 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

diff --git a/lnbits/extensions/shop/__init__.py b/lnbits/extensions/market/__init__.py similarity index 59% rename from lnbits/extensions/shop/__init__.py rename to lnbits/extensions/market/__init__.py index 8c85d8b6..3795ec73 100644 --- a/lnbits/extensions/shop/__init__.py +++ b/lnbits/extensions/market/__init__.py @@ -7,20 +7,20 @@ from lnbits.db import Database from lnbits.helpers import template_renderer from lnbits.tasks import catch_everything_and_restart -db = Database("ext_shop") +db = Database("ext_market") -shop_ext: APIRouter = APIRouter(prefix="/shop", tags=["shop"]) +market_ext: APIRouter = APIRouter(prefix="/market", tags=["market"]) -shop_static_files = [ +market_static_files = [ { - "path": "/shop/static", - "app": StaticFiles(directory="lnbits/extensions/shop/static"), - "name": "shop_static", + "path": "/market/static", + "app": StaticFiles(directory="lnbits/extensions/market/static"), + "name": "market_static", } ] # if 'nostradmin' not in LNBITS_ADMIN_EXTENSIONS: -# @shop_ext.get("/", response_class=HTMLResponse) +# @market_ext.get("/", response_class=HTMLResponse) # async def index(request: Request): # return template_renderer().TemplateResponse( # "error.html", {"request": request, "err": "Ask system admin to enable NostrAdmin!"} @@ -28,9 +28,9 @@ shop_static_files = [ # else: -def shop_renderer(): - return template_renderer(["lnbits/extensions/shop/templates"]) - # return template_renderer(["lnbits/extensions/shop/templates"]) +def market_renderer(): + return template_renderer(["lnbits/extensions/market/templates"]) + # return template_renderer(["lnbits/extensions/market/templates"]) from .tasks import wait_for_paid_invoices @@ -38,6 +38,6 @@ from .views import * # noqa from .views_api import * # noqa -def shop_start(): +def market_start(): loop = asyncio.get_event_loop() loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/market/config.json b/lnbits/extensions/market/config.json new file mode 100644 index 00000000..b540189e --- /dev/null +++ b/lnbits/extensions/market/config.json @@ -0,0 +1,6 @@ +{ + "name": "Market", + "short_description": "Webmarket on LNbits", + "tile": "/market/static/images/bitcoin-shop.png", + "contributors": ["benarc", "talvasconcelos"] +} diff --git a/lnbits/extensions/shop/crud.py b/lnbits/extensions/market/crud.py similarity index 54% rename from lnbits/extensions/shop/crud.py rename to lnbits/extensions/market/crud.py index c58dfb3e..6d82b354 100644 --- a/lnbits/extensions/shop/crud.py +++ b/lnbits/extensions/market/crud.py @@ -17,7 +17,7 @@ from .models import ( OrderDetail, Orders, Products, - ShopSettings, + MarketSettings, Stalls, Zones, createOrder, @@ -30,11 +30,11 @@ from .models import ( ###Products -async def create_shop_product(data: createProduct) -> Products: +async def create_market_product(data: createProduct) -> Products: product_id = urlsafe_short_hash() await db.execute( f""" - INSERT INTO shop.products (id, stall, product, categories, description, image, price, quantity) + INSERT INTO market.products (id, stall, product, categories, description, image, price, quantity) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, ( @@ -48,55 +48,55 @@ async def create_shop_product(data: createProduct) -> Products: data.quantity, ), ) - product = await get_shop_product(product_id) + product = await get_market_product(product_id) assert product, "Newly created product couldn't be retrieved" return product -async def update_shop_product(product_id: str, **kwargs) -> Optional[Products]: +async def update_market_product(product_id: str, **kwargs) -> Optional[Products]: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) await db.execute( - f"UPDATE shop.products SET {q} WHERE id = ?", + f"UPDATE market.products SET {q} WHERE id = ?", (*kwargs.values(), product_id), ) - row = await db.fetchone("SELECT * FROM shop.products WHERE id = ?", (product_id,)) + row = await db.fetchone("SELECT * FROM market.products WHERE id = ?", (product_id,)) return Products(**row) if row else None -async def get_shop_product(product_id: str) -> Optional[Products]: - row = await db.fetchone("SELECT * FROM shop.products WHERE id = ?", (product_id,)) +async def get_market_product(product_id: str) -> Optional[Products]: + row = await db.fetchone("SELECT * FROM market.products WHERE id = ?", (product_id,)) return Products(**row) if row else None -async def get_shop_products(stall_ids: Union[str, List[str]]) -> List[Products]: +async def get_market_products(stall_ids: Union[str, List[str]]) -> List[Products]: if isinstance(stall_ids, str): stall_ids = [stall_ids] - # with open_ext_db("shop") as db: + # with open_ext_db("market") as db: q = ",".join(["?"] * len(stall_ids)) rows = await db.fetchall( f""" - SELECT * FROM shop.products WHERE stall IN ({q}) + SELECT * FROM market.products WHERE stall IN ({q}) """, (*stall_ids,), ) return [Products(**row) for row in rows] -async def delete_shop_product(product_id: str) -> None: - await db.execute("DELETE FROM shop.products WHERE id = ?", (product_id,)) +async def delete_market_product(product_id: str) -> None: + await db.execute("DELETE FROM market.products WHERE id = ?", (product_id,)) ###zones -async def create_shop_zone(user, data: createZones) -> Zones: +async def create_market_zone(user, data: createZones) -> Zones: zone_id = urlsafe_short_hash() await db.execute( f""" - INSERT INTO shop.zones ( + INSERT INTO market.zones ( id, "user", cost, @@ -108,43 +108,43 @@ async def create_shop_zone(user, data: createZones) -> Zones: (zone_id, user, data.cost, data.countries.lower()), ) - zone = await get_shop_zone(zone_id) + zone = await get_market_zone(zone_id) assert zone, "Newly created zone couldn't be retrieved" return zone -async def update_shop_zone(zone_id: str, **kwargs) -> Optional[Zones]: +async def update_market_zone(zone_id: str, **kwargs) -> Optional[Zones]: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) await db.execute( - f"UPDATE shop.zones SET {q} WHERE id = ?", + f"UPDATE market.zones SET {q} WHERE id = ?", (*kwargs.values(), zone_id), ) - row = await db.fetchone("SELECT * FROM shop.zones WHERE id = ?", (zone_id,)) + row = await db.fetchone("SELECT * FROM market.zones WHERE id = ?", (zone_id,)) return Zones(**row) if row else None -async def get_shop_zone(zone_id: str) -> Optional[Zones]: - row = await db.fetchone("SELECT * FROM shop.zones WHERE id = ?", (zone_id,)) +async def get_market_zone(zone_id: str) -> Optional[Zones]: + row = await db.fetchone("SELECT * FROM market.zones WHERE id = ?", (zone_id,)) return Zones(**row) if row else None -async def get_shop_zones(user: str) -> List[Zones]: - rows = await db.fetchall('SELECT * FROM shop.zones WHERE "user" = ?', (user,)) +async def get_market_zones(user: str) -> List[Zones]: + rows = await db.fetchall('SELECT * FROM market.zones WHERE "user" = ?', (user,)) return [Zones(**row) for row in rows] -async def delete_shop_zone(zone_id: str) -> None: - await db.execute("DELETE FROM shop.zones WHERE id = ?", (zone_id,)) +async def delete_market_zone(zone_id: str) -> None: + await db.execute("DELETE FROM market.zones WHERE id = ?", (zone_id,)) ###Stalls -async def create_shop_stall(data: createStalls) -> Stalls: +async def create_market_stall(data: createStalls) -> Stalls: stall_id = urlsafe_short_hash() await db.execute( f""" - INSERT INTO shop.stalls ( + INSERT INTO market.stalls ( id, wallet, name, @@ -166,56 +166,56 @@ async def create_shop_stall(data: createStalls) -> Stalls: ), ) - stall = await get_shop_stall(stall_id) + stall = await get_market_stall(stall_id) assert stall, "Newly created stall couldn't be retrieved" return stall -async def update_shop_stall(stall_id: str, **kwargs) -> Optional[Stalls]: +async def update_market_stall(stall_id: str, **kwargs) -> Optional[Stalls]: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) await db.execute( - f"UPDATE shop.stalls SET {q} WHERE id = ?", + f"UPDATE market.stalls SET {q} WHERE id = ?", (*kwargs.values(), stall_id), ) - row = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)) + row = await db.fetchone("SELECT * FROM market.stalls WHERE id = ?", (stall_id,)) return Stalls(**row) if row else None -async def get_shop_stall(stall_id: str) -> Optional[Stalls]: - row = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)) +async def get_market_stall(stall_id: str) -> Optional[Stalls]: + row = await db.fetchone("SELECT * FROM market.stalls WHERE id = ?", (stall_id,)) return Stalls(**row) if row else None -async def get_shop_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]: +async def get_market_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]: q = ",".join(["?"] * len(wallet_ids)) rows = await db.fetchall( - f"SELECT * FROM shop.stalls WHERE wallet IN ({q})", (*wallet_ids,) + f"SELECT * FROM market.stalls WHERE wallet IN ({q})", (*wallet_ids,) ) return [Stalls(**row) for row in rows] -async def get_shop_stalls_by_ids(stall_ids: Union[str, List[str]]) -> List[Stalls]: +async def get_market_stalls_by_ids(stall_ids: Union[str, List[str]]) -> List[Stalls]: q = ",".join(["?"] * len(stall_ids)) rows = await db.fetchall( - f"SELECT * FROM shop.stalls WHERE id IN ({q})", (*stall_ids,) + f"SELECT * FROM market.stalls WHERE id IN ({q})", (*stall_ids,) ) return [Stalls(**row) for row in rows] -async def delete_shop_stall(stall_id: str) -> None: - await db.execute("DELETE FROM shop.stalls WHERE id = ?", (stall_id,)) +async def delete_market_stall(stall_id: str) -> None: + await db.execute("DELETE FROM market.stalls WHERE id = ?", (stall_id,)) ###Orders -async def create_shop_order(data: createOrder, invoiceid: str): +async def create_market_order(data: createOrder, invoiceid: str): returning = "" if db.type == SQLITE else "RETURNING ID" method = db.execute if db.type == SQLITE else db.fetchone result = await (method)( f""" - INSERT INTO shop.orders (wallet, shippingzone, address, email, total, invoiceid, paid, shipped) + INSERT INTO market.orders (wallet, shippingzone, address, email, total, invoiceid, paid, shipped) VALUES (?, ?, ?, ?, ?, ?, ?, ?) {returning} """, @@ -236,12 +236,12 @@ async def create_shop_order(data: createOrder, invoiceid: str): return result[0] -async def create_shop_order_details(order_id: str, data: List[createOrderDetails]): +async def create_market_order_details(order_id: str, data: List[createOrderDetails]): for item in data: item_id = urlsafe_short_hash() await db.execute( """ - INSERT INTO shop.order_details (id, order_id, product_id, quantity) + INSERT INTO market.order_details (id, order_id, product_id, quantity) VALUES (?, ?, ?, ?) """, ( @@ -251,34 +251,34 @@ async def create_shop_order_details(order_id: str, data: List[createOrderDetails item.quantity, ), ) - order_details = await get_shop_order_details(order_id) + order_details = await get_market_order_details(order_id) return order_details -async def get_shop_order_details(order_id: str) -> List[OrderDetail]: +async def get_market_order_details(order_id: str) -> List[OrderDetail]: rows = await db.fetchall( - f"SELECT * FROM shop.order_details WHERE order_id = ?", (order_id,) + f"SELECT * FROM market.order_details WHERE order_id = ?", (order_id,) ) return [OrderDetail(**row) for row in rows] -async def get_shop_order(order_id: str) -> Optional[Orders]: - row = await db.fetchone("SELECT * FROM shop.orders WHERE id = ?", (order_id,)) +async def get_market_order(order_id: str) -> Optional[Orders]: + row = await db.fetchone("SELECT * FROM market.orders WHERE id = ?", (order_id,)) return Orders(**row) if row else None -async def get_shop_order_invoiceid(invoice_id: str) -> Optional[Orders]: +async def get_market_order_invoiceid(invoice_id: str) -> Optional[Orders]: row = await db.fetchone( - "SELECT * FROM shop.orders WHERE invoiceid = ?", (invoice_id,) + "SELECT * FROM market.orders WHERE invoiceid = ?", (invoice_id,) ) return Orders(**row) if row else None -async def set_shop_order_paid(payment_hash: str): +async def set_market_order_paid(payment_hash: str): await db.execute( """ - UPDATE shop.orders + UPDATE market.orders SET paid = true WHERE invoiceid = ? """, @@ -286,10 +286,10 @@ async def set_shop_order_paid(payment_hash: str): ) -async def set_shop_order_pubkey(payment_hash: str, pubkey: str): +async def set_market_order_pubkey(payment_hash: str, pubkey: str): await db.execute( """ - UPDATE shop.orders + UPDATE market.orders SET pubkey = ? WHERE invoiceid = ? """, @@ -300,7 +300,7 @@ async def set_shop_order_pubkey(payment_hash: str, pubkey: str): ) -async def update_shop_product_stock(products): +async def update_market_product_stock(products): q = "\n".join( [f"""WHEN id='{p.product_id}' THEN quantity - {p.quantity}""" for p in products] @@ -309,7 +309,7 @@ async def update_shop_product_stock(products): await db.execute( f""" - UPDATE shop.products + UPDATE market.products SET quantity=(CASE {q} END) @@ -319,51 +319,51 @@ async def update_shop_product_stock(products): ) -async def get_shop_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]: +async def get_market_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 shop.orders WHERE wallet IN ({q})", (*wallet_ids,) + f"SELECT * FROM market.orders WHERE wallet IN ({q})", (*wallet_ids,) ) # return [Orders(**row) for row in rows] -async def delete_shop_order(order_id: str) -> None: - await db.execute("DELETE FROM shop.orders WHERE id = ?", (order_id,)) +async def delete_market_order(order_id: str) -> None: + await db.execute("DELETE FROM market.orders WHERE id = ?", (order_id,)) ### Market/Marketplace -async def get_shop_markets(user: str) -> List[Market]: - rows = await db.fetchall("SELECT * FROM shop.markets WHERE usr = ?", (user,)) +async def get_market_markets(user: str) -> List[Market]: + rows = await db.fetchall("SELECT * FROM market.markets WHERE usr = ?", (user,)) return [Market(**row) for row in rows] -async def get_shop_market(market_id: str) -> Optional[Market]: - row = await db.fetchone("SELECT * FROM shop.markets WHERE id = ?", (market_id,)) +async def get_market_market(market_id: str) -> Optional[Market]: + row = await db.fetchone("SELECT * FROM market.markets WHERE id = ?", (market_id,)) return Market(**row) if row else None -async def get_shop_market_stalls(market_id: str): +async def get_market_market_stalls(market_id: str): rows = await db.fetchall( - "SELECT * FROM shop.market_stalls WHERE marketid = ?", (market_id,) + "SELECT * FROM market.market_stalls WHERE marketid = ?", (market_id,) ) ids = [row["stallid"] for row in rows] - return await get_shop_stalls_by_ids(ids) + return await get_market_stalls_by_ids(ids) -async def create_shop_market(data: CreateMarket): +async def create_market_market(data: CreateMarket): market_id = urlsafe_short_hash() await db.execute( """ - INSERT INTO shop.markets (id, usr, name) + INSERT INTO market.markets (id, usr, name) VALUES (?, ?, ?) """, ( @@ -372,18 +372,18 @@ async def create_shop_market(data: CreateMarket): data.name, ), ) - market = await get_shop_market(market_id) + market = await get_market_market(market_id) assert market, "Newly created market couldn't be retrieved" return market -async def create_shop_market_stalls(market_id: str, data: List[str]): +async def create_market_market_stalls(market_id: str, data: List[str]): for stallid in data: id = urlsafe_short_hash() await db.execute( """ - INSERT INTO shop.market_stalls (id, marketid, stallid) + INSERT INTO market.market_stalls (id, marketid, stallid) VALUES (?, ?, ?) """, ( @@ -392,21 +392,21 @@ async def create_shop_market_stalls(market_id: str, data: List[str]): stallid, ), ) - market_stalls = await get_shop_market_stalls(market_id) + market_stalls = await get_market_market_stalls(market_id) return market_stalls -async def update_shop_market(market_id: str, name: str): +async def update_market_market(market_id: str, name: str): await db.execute( - "UPDATE shop.markets SET name = ? WHERE id = ?", + "UPDATE market.markets SET name = ? WHERE id = ?", (name, market_id), ) await db.execute( - "DELETE FROM shop.market_stalls WHERE marketid = ?", + "DELETE FROM market.market_stalls WHERE marketid = ?", (market_id,), ) - market = await get_shop_market(market_id) + market = await get_market_market(market_id) return market @@ -416,7 +416,7 @@ async def update_shop_market(market_id: str, name: str): async def create_chat_message(data: CreateChatMessage): await db.execute( """ - INSERT INTO shop.messages (msg, pubkey, id_conversation) + INSERT INTO market.messages (msg, pubkey, id_conversation) VALUES (?, ?, ?) """, ( @@ -427,44 +427,44 @@ async def create_chat_message(data: CreateChatMessage): ) -async def get_shop_latest_chat_messages(room_name: str): +async def get_market_latest_chat_messages(room_name: str): rows = await db.fetchall( - "SELECT * FROM shop.messages WHERE id_conversation = ? ORDER BY timestamp DESC LIMIT 20", + "SELECT * FROM market.messages WHERE id_conversation = ? ORDER BY timestamp DESC LIMIT 20", (room_name,), ) return [ChatMessage(**row) for row in rows] -async def get_shop_chat_messages(room_name: str): +async def get_market_chat_messages(room_name: str): rows = await db.fetchall( - "SELECT * FROM shop.messages WHERE id_conversation = ? ORDER BY timestamp DESC", + "SELECT * FROM market.messages WHERE id_conversation = ? ORDER BY timestamp DESC", (room_name,), ) return [ChatMessage(**row) for row in rows] -async def get_shop_chat_by_merchant(ids: List[str]) -> List[ChatMessage]: +async def get_market_chat_by_merchant(ids: List[str]) -> List[ChatMessage]: q = ",".join(["?"] * len(ids)) rows = await db.fetchall( - f"SELECT * FROM shop.messages WHERE id_conversation IN ({q})", + f"SELECT * FROM market.messages WHERE id_conversation IN ({q})", (*ids,), ) return [ChatMessage(**row) for row in rows] -async def get_shop_settings(user) -> Optional[ShopSettings]: - row = await db.fetchone("""SELECT * FROM shop.settings WHERE "user" = ?""", (user,)) +async def get_market_settings(user) -> Optional[MarketSettings]: + row = await db.fetchone("""SELECT * FROM market.settings WHERE "user" = ?""", (user,)) - return ShopSettings(**row) if row else None + return MarketSettings(**row) if row else None -async def create_shop_settings(user: str, data): +async def create_market_settings(user: str, data): await db.execute( """ - INSERT INTO shop.settings ("user", currency, fiat_base_multiplier) + INSERT INTO market.settings ("user", currency, fiat_base_multiplier) VALUES (?, ?, ?) """, ( @@ -475,10 +475,10 @@ async def create_shop_settings(user: str, data): ) -async def set_shop_settings(user: str, data): +async def set_market_settings(user: str, data): await db.execute( """ - UPDATE shop.settings + UPDATE market.settings SET currency = ?, fiat_base_multiplier = ? WHERE "user" = ?; """, diff --git a/lnbits/extensions/shop/migrations.py b/lnbits/extensions/market/migrations.py similarity index 85% rename from lnbits/extensions/shop/migrations.py rename to lnbits/extensions/market/migrations.py index e6592dff..72b584f9 100644 --- a/lnbits/extensions/shop/migrations.py +++ b/lnbits/extensions/market/migrations.py @@ -1,10 +1,10 @@ async def m001_initial(db): """ - Initial Shop settings table. + Initial Market settings table. """ await db.execute( """ - CREATE TABLE shop.settings ( + CREATE TABLE market.settings ( "user" TEXT PRIMARY KEY, currency TEXT DEFAULT 'sat', fiat_base_multiplier INTEGER DEFAULT 1 @@ -17,7 +17,7 @@ async def m001_initial(db): """ await db.execute( """ - CREATE TABLE shop.stalls ( + CREATE TABLE market.stalls ( id TEXT PRIMARY KEY, wallet TEXT NOT NULL, name TEXT NOT NULL, @@ -35,7 +35,7 @@ async def m001_initial(db): """ await db.execute( f""" - CREATE TABLE shop.products ( + CREATE TABLE market.products ( id TEXT PRIMARY KEY, stall TEXT NOT NULL REFERENCES {db.references_schema}stalls (id) ON DELETE CASCADE, product TEXT NOT NULL, @@ -54,7 +54,7 @@ async def m001_initial(db): """ await db.execute( """ - CREATE TABLE shop.zones ( + CREATE TABLE market.zones ( id TEXT PRIMARY KEY, "user" TEXT NOT NULL, cost TEXT NOT NULL, @@ -68,7 +68,7 @@ async def m001_initial(db): """ await db.execute( f""" - CREATE TABLE shop.orders ( + CREATE TABLE market.orders ( id {db.serial_primary_key}, wallet TEXT NOT NULL, username TEXT, @@ -92,7 +92,7 @@ async def m001_initial(db): """ await db.execute( f""" - CREATE TABLE shop.order_details ( + CREATE TABLE market.order_details ( id TEXT PRIMARY KEY, order_id INTEGER NOT NULL REFERENCES {db.references_schema}orders (id) ON DELETE CASCADE, product_id TEXT NOT NULL REFERENCES {db.references_schema}products (id) ON DELETE CASCADE, @@ -106,7 +106,7 @@ async def m001_initial(db): """ await db.execute( """ - CREATE TABLE shop.markets ( + CREATE TABLE market.markets ( id TEXT PRIMARY KEY, usr TEXT NOT NULL, name TEXT @@ -119,7 +119,7 @@ async def m001_initial(db): """ await db.execute( f""" - CREATE TABLE shop.market_stalls ( + CREATE TABLE market.market_stalls ( id TEXT PRIMARY KEY, marketid TEXT NOT NULL REFERENCES {db.references_schema}markets (id) ON DELETE CASCADE, stallid TEXT NOT NULL REFERENCES {db.references_schema}stalls (id) ON DELETE CASCADE @@ -132,7 +132,7 @@ async def m001_initial(db): """ await db.execute( f""" - CREATE TABLE shop.messages ( + CREATE TABLE market.messages ( id {db.serial_primary_key}, msg TEXT NOT NULL, pubkey TEXT NOT NULL, @@ -149,8 +149,8 @@ async def m001_initial(db): Create indexes for message fetching """ await db.execute( - "CREATE INDEX idx_messages_timestamp ON shop.messages (timestamp DESC)" + "CREATE INDEX idx_messages_timestamp ON market.messages (timestamp DESC)" ) await db.execute( - "CREATE INDEX idx_messages_conversations ON shop.messages (id_conversation)" + "CREATE INDEX idx_messages_conversations ON market.messages (id_conversation)" ) diff --git a/lnbits/extensions/shop/models.py b/lnbits/extensions/market/models.py similarity index 98% rename from lnbits/extensions/shop/models.py rename to lnbits/extensions/market/models.py index ed6342f0..ea7f6f20 100644 --- a/lnbits/extensions/shop/models.py +++ b/lnbits/extensions/market/models.py @@ -4,7 +4,7 @@ from fastapi.param_functions import Query from pydantic import BaseModel -class ShopSettings(BaseModel): +class MarketSettings(BaseModel): user: str currency: str fiat_base_multiplier: int diff --git a/lnbits/extensions/shop/notifier.py b/lnbits/extensions/market/notifier.py similarity index 95% rename from lnbits/extensions/shop/notifier.py rename to lnbits/extensions/market/notifier.py index 0030001c..e2bf7c91 100644 --- a/lnbits/extensions/shop/notifier.py +++ b/lnbits/extensions/market/notifier.py @@ -10,8 +10,8 @@ from collections import defaultdict from fastapi import WebSocket from loguru import logger -from lnbits.extensions.shop.crud import create_chat_message -from lnbits.extensions.shop.models import CreateChatMessage +from lnbits.extensions.market.crud import create_chat_message +from lnbits.extensions.market.models import CreateChatMessage class Notifier: diff --git a/lnbits/extensions/shop/static/images/bitcoin-shop.png b/lnbits/extensions/market/static/images/bitcoin-shop.png similarity index 100% rename from lnbits/extensions/shop/static/images/bitcoin-shop.png rename to lnbits/extensions/market/static/images/bitcoin-shop.png diff --git a/lnbits/extensions/shop/static/images/placeholder.png b/lnbits/extensions/market/static/images/placeholder.png similarity index 100% rename from lnbits/extensions/shop/static/images/placeholder.png rename to lnbits/extensions/market/static/images/placeholder.png diff --git a/lnbits/extensions/shop/tasks.py b/lnbits/extensions/market/tasks.py similarity index 62% rename from lnbits/extensions/shop/tasks.py rename to lnbits/extensions/market/tasks.py index 621e4fae..004ebb4d 100644 --- a/lnbits/extensions/shop/tasks.py +++ b/lnbits/extensions/market/tasks.py @@ -6,10 +6,10 @@ from lnbits.core.models import Payment from lnbits.tasks import register_invoice_listener from .crud import ( - get_shop_order_details, - get_shop_order_invoiceid, - set_shop_order_paid, - update_shop_product_stock, + get_market_order_details, + get_market_order_invoiceid, + set_market_order_paid, + update_market_product_stock, ) @@ -26,17 +26,17 @@ async def on_invoice_paid(payment: Payment) -> None: if not payment.extra: return - if payment.extra.get("tag") != "shop": + if payment.extra.get("tag") != "market": return - order = await get_shop_order_invoiceid(payment.payment_hash) + order = await get_market_order_invoiceid(payment.payment_hash) if not order: logger.error("this should never happen", payment) return # set order as paid - await set_shop_order_paid(payment.payment_hash) + await set_market_order_paid(payment.payment_hash) # deduct items sold from stock - details = await get_shop_order_details(order.id) - await update_shop_product_stock(details) + details = await get_market_order_details(order.id) + await update_market_product_stock(details) diff --git a/lnbits/extensions/shop/templates/shop/_api_docs.html b/lnbits/extensions/market/templates/market/_api_docs.html similarity index 88% rename from lnbits/extensions/shop/templates/shop/_api_docs.html rename to lnbits/extensions/market/templates/market/_api_docs.html index 3990c301..f0d97dbf 100644 --- a/lnbits/extensions/shop/templates/shop/_api_docs.html +++ b/lnbits/extensions/market/templates/market/_api_docs.html @@ -7,7 +7,7 @@
- LNbits Shop (Nostr support coming soon) + LNbits Market (Nostr support coming soon)
    @@ -17,9 +17,9 @@
  1. Take orders
  2. Includes chat support!
- The first LNbits shop idea 'Diagon Alley' helped create Nostr, and soon - this shop extension will have the option to work on Nostr 'Diagon Alley' - mode, by the merchant, shop, and buyer all having keys, and data being + The first LNbits market idea 'Diagon Alley' helped create Nostr, and soon + this market extension will have the option to work on Nostr 'Diagon Alley' + mode, by the merchant, market, and buyer all having keys, and data being routed through Nostr relays.
@@ -48,7 +48,7 @@ GET - /shop/api/v1/stall/products/<relay_id>
Body (application/json)
@@ -73,7 +73,7 @@ POST - /shop/api/v1/stall/order/<relay_id>
Body (application/json)
GET - /shop/api/v1/stall/checkshipped/<checking_id>
Headers
diff --git a/lnbits/extensions/shop/templates/shop/_chat_box.html b/lnbits/extensions/market/templates/market/_chat_box.html similarity index 100% rename from lnbits/extensions/shop/templates/shop/_chat_box.html rename to lnbits/extensions/market/templates/market/_chat_box.html diff --git a/lnbits/extensions/shop/templates/shop/_dialogs.html b/lnbits/extensions/market/templates/market/_dialogs.html similarity index 98% rename from lnbits/extensions/shop/templates/shop/_dialogs.html rename to lnbits/extensions/market/templates/market/_dialogs.html index d2c22350..d2a8dd0a 100644 --- a/lnbits/extensions/shop/templates/shop/_dialogs.html +++ b/lnbits/extensions/market/templates/market/_dialogs.html @@ -184,7 +184,7 @@ - + @@ -314,8 +314,8 @@ v-if="diagonAlley" filled dense - v-model.trim="stallDialog.data.nostrShops" - label="Nostr shop public keys (seperate by comma)" + v-model.trim="stallDialog.data.nostrMarkets" + label="Nostr market public keys (seperate by comma)" >
@@ -350,7 +350,7 @@ -
How to use Shop
+
How to use Market
Product shipped? @@ -194,7 +194,7 @@ unelevated dense size="xs" - icon="add_shopping_cart" + icon="add_marketping_cart" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" type="a" :href="props.row.wallet" @@ -276,10 +276,10 @@ icon="storefront" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" type="a" - :href="'/shop/stalls/' + props.row.id" + :href="'/market/stalls/' + props.row.id" target="_blank" > - Stall simple UI shopping cart + Stall simple UI marketping cart {{ col.value }} @@ -348,7 +348,7 @@ icon="storefront" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" type="a" - :href="'/shop/market/' + props.row.id" + :href="'/market/market/' + props.row.id" target="_blank" > Link to pass to stall relay diff --git a/lnbits/extensions/shop/templates/shop/index.html b/lnbits/extensions/market/templates/market/index.html similarity index 93% rename from lnbits/extensions/shop/templates/shop/index.html rename to lnbits/extensions/market/templates/market/index.html index 49ddf6fb..e16e5d48 100644 --- a/lnbits/extensions/shop/templates/shop/index.html +++ b/lnbits/extensions/market/templates/market/index.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% from "macros.jinja" import window_vars with context %} {% block page %}
- {% include "shop/_dialogs.html" %} + {% include "market/_dialogs.html" %}
@@ -60,14 +60,14 @@ @click="marketDialog.show = true" >Create Market - Makes a simple frontend shop for your stalls (not NOSTR) -
Shop
-
Make a shop of multiple stalls.
+
Market
+
Make a market of multiple stalls.
@@ -87,16 +87,16 @@ class="float-right" unelevated color="primary" - @click="shopDataDownload" + @click="marketDataDownload" >Export all Data - Export all data (shops, products, orders, etc...)
- {% include "shop/_tables.html" %} + {% include "market/_tables.html" %} @@ -149,16 +149,16 @@
- LNbits Shop Extension, powered by Nostr + LNbits Market Extension (Nostr support coming soon)
- {% include "shop/_api_docs.html" %} + {% include "market/_api_docs.html" %}
- {% include "shop/_chat_box.html" %} + {% include "market/_chat_box.html" %}
@@ -215,7 +215,7 @@ obj._data = _.clone(obj) obj.stalls = [] LNbits.api - .request('GET', `/shop/api/v1/markets/${obj.id}/stalls`, null) + .request('GET', `/market/api/v1/markets/${obj.id}/stalls`, null) .then(response => { if (response.data) { obj.stalls = response.data.map(s => s.id) //.toString() @@ -548,7 +548,7 @@ LNbits.api .request( 'PUT', - '/shop/api/v1/settings/' + this.g.user.id, + '/market/api/v1/settings/' + this.g.user.id, this.g.user.wallets[0].adminkey, data ) @@ -563,7 +563,7 @@ LNbits.utils.notifyApiError(error) }) }, - shopDataDownload() { + marketDataDownload() { const removeClone = obj => { delete obj._data return obj @@ -593,10 +593,10 @@ this.keys = {privkey, pubkey} this.stallDialog.data.publickey = this.keys.pubkey this.stallDialog.data.privatekey = this.keys.privkey - this.$q.localStorage.set(`lnbits.shop.${this.g.user.id}`, this.keys) + this.$q.localStorage.set(`lnbits.market.${this.g.user.id}`, this.keys) }, restoreKeys() { - let keys = this.$q.localStorage.getItem(`lnbits.shop.${this.g.user.id}`) + let keys = this.$q.localStorage.getItem(`lnbits.market.${this.g.user.id}`) if (keys) { this.keys = keys this.stallDialog.data.publickey = this.keys.pubkey @@ -645,7 +645,7 @@ LNbits.api .request( 'GET', - '/shop/api/v1/stalls?all_wallets=true', + '/market/api/v1/stalls?all_wallets=true', self.g.user.wallets[0].adminkey ) .then(function (response) { @@ -704,7 +704,7 @@ LNbits.api .request( 'PUT', - '/shop/api/v1/stalls/' + data.id, + '/market/api/v1/stalls/' + data.id, _.findWhere(self.g.user.wallets, { id: self.stallDialog.data.wallet }).inkey, @@ -726,7 +726,7 @@ LNbits.api .request( 'POST', - '/shop/api/v1/stalls', + '/market/api/v1/stalls', _.findWhere(self.g.user.wallets, { id: self.stallDialog.data.wallet }).inkey, @@ -753,7 +753,7 @@ LNbits.api .request( 'DELETE', - '/shop/api/v1/stalls/' + stallId, + '/market/api/v1/stalls/' + stallId, _.findWhere(self.g.user.wallets, {id: stall.wallet}).adminkey ) .then(function (response) { @@ -778,7 +778,7 @@ LNbits.api .request( 'GET', - '/shop/api/v1/products?all_stalls=true', + '/market/api/v1/products?all_stalls=true', self.g.user.wallets[0].inkey ) .then(function (response) { @@ -851,7 +851,7 @@ LNbits.api .request( 'PUT', - '/shop/api/v1/products/' + data.id, + '/market/api/v1/products/' + data.id, _.findWhere(self.g.user.wallets, { id: wallet }).inkey, @@ -877,7 +877,7 @@ LNbits.api .request( 'POST', - '/shop/api/v1/products', + '/market/api/v1/products', _.findWhere(self.g.user.wallets, {id: walletId}).inkey, data ) @@ -899,7 +899,7 @@ LNbits.api .request( 'DELETE', - '/shop/api/v1/products/' + productId, + '/market/api/v1/products/' + productId, _.findWhere(this.g.user.wallets, {id: walletId}).adminkey ) .then(() => { @@ -922,7 +922,7 @@ var self = this LNbits.api - .request('GET', '/shop/api/v1/zones', this.g.user.wallets[0].inkey) + .request('GET', '/market/api/v1/zones', this.g.user.wallets[0].inkey) .then(function (response) { if (response.data) { self.zones = response.data.map(mapZone) @@ -960,7 +960,7 @@ LNbits.api .request( 'POST', - '/shop/api/v1/zones/' + data.id, + '/market/api/v1/zones/' + data.id, self.g.user.wallets[0].adminkey, data ) @@ -982,7 +982,7 @@ LNbits.api .request( 'POST', - '/shop/api/v1/zones', + '/market/api/v1/zones', self.g.user.wallets[0].inkey, data ) @@ -1006,7 +1006,7 @@ LNbits.api .request( 'DELETE', - '/shop/api/v1/zones/' + zoneId, + '/market/api/v1/zones/' + zoneId, self.g.user.wallets[0].adminkey ) .then(function (response) { @@ -1027,7 +1027,7 @@ //////////////////////////////////////// getMarkets() { LNbits.api - .request('GET', '/shop/api/v1/markets', this.g.user.wallets[0].inkey) + .request('GET', '/market/api/v1/markets', this.g.user.wallets[0].inkey) .then(response => { if (response.data) { this.markets = response.data.map(mapMarkets) @@ -1059,7 +1059,7 @@ LNbits.api .request( 'PUT', - '/shop/api/v1/markets/' + data.id, + '/market/api/v1/markets/' + data.id, this.g.user.wallets[0].inkey, data ) @@ -1080,7 +1080,7 @@ LNbits.api .request( 'POST', - '/shop/api/v1/markets', + '/market/api/v1/markets', this.g.user.wallets[0].inkey, data ) @@ -1094,8 +1094,8 @@ LNbits.utils.notifyApiError(error) }) }, - deleteMarket(shopId) { - let market = _.findWhere(this.markets, {id: shopId}) + deleteMarket(marketId) { + let market = _.findWhere(this.markets, {id: marketId}) LNbits.utils .confirmDialog('Are you sure you want to delete this Marketplace?') @@ -1103,12 +1103,12 @@ LNbits.api .request( 'DELETE', - '/shop/api/v1/markets/' + shopId, + '/market/api/v1/markets/' + marketId, this.g.user.wallets[0].inkey ) .then(response => { this.markets = _.reject(this.markets, obj => { - return obj.id == shopId + return obj.id == marketId }) }) .catch(function (error) { @@ -1116,8 +1116,8 @@ }) }) }, - exportShopsCSV: function () { - LNbits.utils.exportCSV(this.shopsTable.columns, this.markets) + exportMarketsCSV: function () { + LNbits.utils.exportCSV(this.marketsTable.columns, this.markets) }, //////////////////////////////////////// ////////////////ORDERS////////////////// @@ -1128,7 +1128,7 @@ await LNbits.api .request( 'GET', - '/shop/api/v1/orders?all_wallets=true', + '/market/api/v1/orders?all_wallets=true', this.g.user.wallets[0].inkey ) .then(response => { @@ -1150,7 +1150,7 @@ LNbits.api .request( 'DELETE', - '/shop/api/v1/orders/' + orderId, + '/market/api/v1/orders/' + orderId, _.findWhere(self.g.user.wallets, {id: order.wallet}).adminkey ) .then(function (response) { @@ -1168,7 +1168,7 @@ LNbits.api .request( 'GET', - `/shop/api/v1/orders/shipped/${order_id}?shipped=${!shipped}`, + `/market/api/v1/orders/shipped/${order_id}?shipped=${!shipped}`, this.g.user.wallets[0].inkey ) .then(response => { @@ -1189,7 +1189,7 @@ await LNbits.api .request( 'GET', - `/shop/api/v1/chat/messages/merchant?orders=${this.orders + `/market/api/v1/chat/messages/merchant?orders=${this.orders .map(o => o.invoiceid) .toString()}`, this.g.user.wallets[0].adminkey @@ -1205,7 +1205,7 @@ }) }, updateLastSeenMsg(id) { - let data = this.$q.localStorage.getItem(`lnbits.shop.chat`) + let data = this.$q.localStorage.getItem(`lnbits.market.chat`) let chat = { ...data, [`${id}`]: { @@ -1214,11 +1214,11 @@ ] } } - this.$q.localStorage.set(`lnbits.shop.chat`, chat) + this.$q.localStorage.set(`lnbits.market.chat`, chat) this.checkUnreadMessages() }, checkUnreadMessages() { - let lastMsgs = this.$q.localStorage.getItem(`lnbits.shop.chat`) || {} + let lastMsgs = this.$q.localStorage.getItem(`lnbits.market.chat`) || {} for (let key in this.messages) { let idx = this.orders.findIndex(f => f.invoiceid == key) @@ -1287,7 +1287,7 @@ if (this.ws.readyState === WebSocket.CLOSED) { console.log('WebSocket CLOSED: Reopening') this.ws = new WebSocket( - ws_scheme + location.host + '/shop/ws/' + this.customerKey + ws_scheme + location.host + '/market/ws/' + this.customerKey ) } }, @@ -1318,7 +1318,7 @@ } else { ws_scheme = 'ws://' } - ws = new WebSocket(ws_scheme + location.host + '/shop/ws/' + room_name) + ws = new WebSocket(ws_scheme + location.host + '/market/ws/' + room_name) ws.onmessage = async event => { let event_data = JSON.parse(event.data) @@ -1335,7 +1335,7 @@ }, async getCurrencies() { await LNbits.api - .request('GET', '/shop/api/v1/currencies') + .request('GET', '/market/api/v1/currencies') .then(response => { this.currencies.units = ['sat', ...response.data] }) @@ -1359,7 +1359,7 @@ await this.getOrders() this.getMarkets() await this.getAllMessages() - let keys = this.$q.localStorage.getItem(`lnbits.shop.${this.g.user.id}`) + let keys = this.$q.localStorage.getItem(`lnbits.market.${this.g.user.id}`) if (keys) { this.keys = keys } diff --git a/lnbits/extensions/shop/templates/shop/market.html b/lnbits/extensions/market/templates/market/market.html similarity index 97% rename from lnbits/extensions/shop/templates/shop/market.html rename to lnbits/extensions/market/templates/market/market.html index 6763ef3b..e59bb245 100644 --- a/lnbits/extensions/shop/templates/shop/market.html +++ b/lnbits/extensions/market/templates/market/market.html @@ -33,7 +33,7 @@ {% raw %} Visit Stall diff --git a/lnbits/extensions/shop/templates/shop/order.html b/lnbits/extensions/market/templates/market/order.html similarity index 95% rename from lnbits/extensions/shop/templates/shop/order.html rename to lnbits/extensions/market/templates/market/order.html index 14d14f34..ebabe882 100644 --- a/lnbits/extensions/shop/templates/shop/order.html +++ b/lnbits/extensions/market/templates/market/order.html @@ -292,7 +292,7 @@ lnbitsBookmark: { show: true, finish: () => { - this.$q.localStorage.set('lnbits.shopbookmark', false) + this.$q.localStorage.set('lnbits.marketbookmark', false) this.lnbitsBookmark.show = false } }, @@ -368,8 +368,8 @@ }, restoreKeys() { this.user.keys = this.keysDialog.data - let data = this.$q.localStorage.getItem(`lnbits.shop.data`) - this.$q.localStorage.set(`lnbits.shop.data`, { + let data = this.$q.localStorage.getItem(`lnbits.market.data`) + this.$q.localStorage.set(`lnbits.market.data`, { ...data, keys: this.user.keys }) @@ -380,7 +380,7 @@ LNbits.utils .confirmDialog('Are you sure you want to delete your stored data?') .onOk(() => { - this.$q.localStorage.remove('lnbits.shop.data') + this.$q.localStorage.remove('lnbits.market.data') this.user = null }) }, @@ -401,7 +401,7 @@ await LNbits.api .request( 'GET', - `/shop/api/v1/chat/messages/${room_name}${ + `/market/api/v1/chat/messages/${room_name}${ all ? '?all_messages=true' : '' }` ) @@ -430,7 +430,7 @@ if (this.ws.readyState === WebSocket.CLOSED) { console.log('WebSocket CLOSED: Reopening') this.ws = new WebSocket( - ws_scheme + location.host + '/shop/ws/' + this.selectedOrder + ws_scheme + location.host + '/market/ws/' + this.selectedOrder ) } }, @@ -443,7 +443,7 @@ } else { ws_scheme = 'ws://' } - ws = new WebSocket(ws_scheme + location.host + '/shop/ws/' + room_name) + ws = new WebSocket(ws_scheme + location.host + '/market/ws/' + room_name) ws.onmessage = event => { let event_data = JSON.parse(event.data) @@ -455,7 +455,7 @@ } }, async created() { - let showBookmark = this.$q.localStorage.getItem('lnbits.shopbookmark') + let showBookmark = this.$q.localStorage.getItem('lnbits.marketbookmark') this.lnbitsBookmark.show = showBookmark === true || showBookmark == null let order_details = JSON.parse('{{ order | tojson }}') @@ -488,7 +488,7 @@ this.products = this.products.map(mapProductsItems) } - let data = this.$q.localStorage.getItem(`lnbits.shop.data`) || false + let data = this.$q.localStorage.getItem(`lnbits.market.data`) || false if (data) { this.user = data @@ -501,7 +501,7 @@ try { await LNbits.api.request( 'GET', - `/shop/api/v1/order/pubkey/${order_id}/${this.user.keys.publickey}` + `/market/api/v1/order/pubkey/${order_id}/${this.user.keys.publickey}` ) } catch (error) { LNbits.utils.notifyApiError(error) @@ -516,7 +516,7 @@ await this.getMessages(order_id) - this.$q.localStorage.set(`lnbits.shop.data`, this.user) + this.$q.localStorage.set(`lnbits.market.data`, this.user) this.startChat(order_id) } }) diff --git a/lnbits/extensions/shop/templates/shop/product.html b/lnbits/extensions/market/templates/market/product.html similarity index 100% rename from lnbits/extensions/shop/templates/shop/product.html rename to lnbits/extensions/market/templates/market/product.html diff --git a/lnbits/extensions/shop/templates/shop/stall.html b/lnbits/extensions/market/templates/market/stall.html similarity index 96% rename from lnbits/extensions/shop/templates/shop/stall.html rename to lnbits/extensions/market/templates/market/stall.html index f715cf37..f9189b30 100644 --- a/lnbits/extensions/shop/templates/shop/stall.html +++ b/lnbits/extensions/market/templates/market/stall.html @@ -94,7 +94,7 @@ {% raw %} { this.checkoutDialog = {show: false, data: {}} @@ -477,7 +477,7 @@ LNbits.api .request( 'GET', - `/shop/api/v1/orders/payments/${this.qrCodeDialog.data.payment_hash}` + `/market/api/v1/orders/payments/${this.qrCodeDialog.data.payment_hash}` ) .then(res => { if (res.data.paid) { @@ -491,7 +491,7 @@ { label: 'See Order', handler: () => { - window.location.href = `/shop/order/?merch=${this.stall.id}&invoice_id=${this.qrCodeDialog.data.payment_hash}` + window.location.href = `/market/order/?merch=${this.stall.id}&invoice_id=${this.qrCodeDialog.data.payment_hash}` } } ] @@ -500,7 +500,7 @@ this.resetCart() this.closeQrCodeDialog() setTimeout(() => { - window.location.href = `/shop/order/?merch=${this.stall.id}&invoice_id=${this.qrCodeDialog.data.payment_hash}` + window.location.href = `/market/order/?merch=${this.stall.id}&invoice_id=${this.qrCodeDialog.data.payment_hash}` }, 5000) } }) diff --git a/lnbits/extensions/shop/views.py b/lnbits/extensions/market/views.py similarity index 67% rename from lnbits/extensions/shop/views.py rename to lnbits/extensions/market/views.py index 309ed134..23bc5706 100644 --- a/lnbits/extensions/shop/views.py +++ b/lnbits/extensions/market/views.py @@ -17,48 +17,48 @@ from starlette.responses import HTMLResponse from lnbits.core.models import User from lnbits.decorators import check_user_exists # type: ignore -from lnbits.extensions.shop import shop_ext, shop_renderer -from lnbits.extensions.shop.models import CreateChatMessage, SetSettings -from lnbits.extensions.shop.notifier import Notifier +from lnbits.extensions.market import market_ext, market_renderer +from lnbits.extensions.market.models import CreateChatMessage, SetSettings +from lnbits.extensions.market.notifier import Notifier from .crud import ( create_chat_message, - create_shop_settings, - get_shop_market, - get_shop_market_stalls, - get_shop_order_details, - get_shop_order_invoiceid, - get_shop_products, - get_shop_settings, - get_shop_stall, - get_shop_zone, - get_shop_zones, - update_shop_product_stock, + create_market_settings, + get_market_market, + get_market_market_stalls, + get_market_order_details, + get_market_order_invoiceid, + get_market_products, + get_market_settings, + get_market_stall, + get_market_zone, + get_market_zones, + update_market_product_stock, ) templates = Jinja2Templates(directory="templates") -@shop_ext.get("/", response_class=HTMLResponse) +@market_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): - settings = await get_shop_settings(user=user.id) + settings = await get_market_settings(user=user.id) if not settings: - await create_shop_settings( + await create_market_settings( user=user.id, data=SetSettings(currency="sat", fiat_base_multiplier=1) ) - settings = await get_shop_settings(user.id) + settings = await get_market_settings(user.id) assert settings - return shop_renderer().TemplateResponse( - "shop/index.html", + return market_renderer().TemplateResponse( + "market/index.html", {"request": request, "user": user.dict(), "currency": settings.currency}, ) -@shop_ext.get("/stalls/{stall_id}", response_class=HTMLResponse) +@market_ext.get("/stalls/{stall_id}", response_class=HTMLResponse) async def stall(request: Request, stall_id): - stall = await get_shop_stall(stall_id) - products = await get_shop_products(stall_id) + stall = await get_market_stall(stall_id) + products = await get_market_products(stall_id) if not stall: raise HTTPException( @@ -67,7 +67,7 @@ async def stall(request: Request, stall_id): zones = [] for id in stall.shippingzones.split(","): - zone = await get_shop_zone(id) + zone = await get_market_zone(id) assert zone z = zone.dict() zones.append({"label": z["countries"], "cost": z["cost"], "value": z["id"]}) @@ -76,8 +76,8 @@ async def stall(request: Request, stall_id): _stall["zones"] = zones - return shop_renderer().TemplateResponse( - "shop/stall.html", + return market_renderer().TemplateResponse( + "market/stall.html", { "request": request, "stall": _stall, @@ -86,21 +86,21 @@ async def stall(request: Request, stall_id): ) -@shop_ext.get("/market/{market_id}", response_class=HTMLResponse) +@market_ext.get("/market/{market_id}", response_class=HTMLResponse) async def market(request: Request, market_id): - market = await get_shop_market(market_id) + market = await get_market_market(market_id) if not market: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Marketplace doesn't exist." ) - stalls = await get_shop_market_stalls(market_id) + stalls = await get_market_market_stalls(market_id) stalls_ids = [stall.id for stall in stalls] - products = [product.dict() for product in await get_shop_products(stalls_ids)] + products = [product.dict() for product in await get_market_products(stalls_ids)] - return shop_renderer().TemplateResponse( - "shop/market.html", + return market_renderer().TemplateResponse( + "market/market.html", { "request": request, "market": market, @@ -110,23 +110,23 @@ async def market(request: Request, market_id): ) -@shop_ext.get("/order", response_class=HTMLResponse) +@market_ext.get("/order", response_class=HTMLResponse) async def order_chat( request: Request, merch: str = Query(...), invoice_id: str = Query(...), keys: str = Query(None), ): - stall = await get_shop_stall(merch) + stall = await get_market_stall(merch) assert stall - order = await get_shop_order_invoiceid(invoice_id) + order = await get_market_order_invoiceid(invoice_id) assert order - _order = await get_shop_order_details(order.id) - products = await get_shop_products(stall.id) + _order = await get_market_order_details(order.id) + products = await get_market_products(stall.id) assert products - return shop_renderer().TemplateResponse( - "shop/order.html", + return market_renderer().TemplateResponse( + "market/order.html", { "request": request, "stall": { @@ -151,7 +151,7 @@ async def order_chat( notifier = Notifier() -@shop_ext.websocket("/ws/{room_name}") +@market_ext.websocket("/ws/{room_name}") async def websocket_endpoint( websocket: WebSocket, room_name: str, background_tasks: BackgroundTasks ): diff --git a/lnbits/extensions/shop/views_api.py b/lnbits/extensions/market/views_api.py similarity index 51% rename from lnbits/extensions/shop/views_api.py rename to lnbits/extensions/market/views_api.py index 87374b20..8d0202a3 100644 --- a/lnbits/extensions/shop/views_api.py +++ b/lnbits/extensions/market/views_api.py @@ -19,44 +19,44 @@ from lnbits.decorators import ( from lnbits.helpers import urlsafe_short_hash from lnbits.utils.exchange_rates import currencies, get_fiat_rate_satoshis -from . import db, shop_ext +from . import db, market_ext from .crud import ( - create_shop_market, - create_shop_market_stalls, - create_shop_order, - create_shop_order_details, - create_shop_product, - create_shop_settings, - create_shop_stall, - create_shop_zone, - delete_shop_order, - delete_shop_product, - delete_shop_stall, - delete_shop_zone, - get_shop_chat_by_merchant, - get_shop_chat_messages, - get_shop_latest_chat_messages, - get_shop_market, - get_shop_market_stalls, - get_shop_markets, - get_shop_order, - get_shop_order_details, - get_shop_order_invoiceid, - get_shop_orders, - get_shop_product, - get_shop_products, - get_shop_settings, - get_shop_stall, - get_shop_stalls, - get_shop_stalls_by_ids, - get_shop_zone, - get_shop_zones, - set_shop_order_pubkey, - set_shop_settings, - update_shop_market, - update_shop_product, - update_shop_stall, - update_shop_zone, + create_market_market, + create_market_market_stalls, + create_market_order, + create_market_order_details, + create_market_product, + create_market_settings, + create_market_stall, + create_market_zone, + delete_market_order, + delete_market_product, + delete_market_stall, + delete_market_zone, + get_market_chat_by_merchant, + get_market_chat_messages, + get_market_latest_chat_messages, + get_market_market, + get_market_market_stalls, + get_market_markets, + get_market_order, + get_market_order_details, + get_market_order_invoiceid, + get_market_orders, + get_market_product, + get_market_products, + get_market_settings, + get_market_stall, + get_market_stalls, + get_market_stalls_by_ids, + get_market_zone, + get_market_zones, + set_market_order_pubkey, + set_market_settings, + update_market_market, + update_market_product, + update_market_stall, + update_market_zone, ) from .models import ( CreateMarket, @@ -76,8 +76,8 @@ from .models import ( ### Products -@shop_ext.get("/api/v1/products") -async def api_shop_products( +@market_ext.get("/api/v1/products") +async def api_market_products( wallet: WalletTypeInfo = Depends(require_invoice_key), all_stalls: bool = Query(False), ): @@ -87,104 +87,104 @@ async def api_shop_products( user = await get_user(wallet.wallet.user) wallet_ids = user.wallet_ids if user else [] - stalls = [stall.id for stall in await get_shop_stalls(wallet_ids)] + stalls = [stall.id for stall in await get_market_stalls(wallet_ids)] if not stalls: return - return [product.dict() for product in await get_shop_products(stalls)] + return [product.dict() for product in await get_market_products(stalls)] -@shop_ext.post("/api/v1/products") -@shop_ext.put("/api/v1/products/{product_id}") -async def api_shop_product_create( +@market_ext.post("/api/v1/products") +@market_ext.put("/api/v1/products/{product_id}") +async def api_market_product_create( data: createProduct, product_id=None, wallet: WalletTypeInfo = Depends(require_invoice_key), ): # For fiat currencies, # we multiply by data.fiat_base_multiplier (usually 100) to save the value in cents. - settings = await get_shop_settings(user=wallet.wallet.user) + settings = await get_market_settings(user=wallet.wallet.user) assert settings - stall = await get_shop_stall(stall_id=data.stall) + stall = await get_market_stall(stall_id=data.stall) assert stall if stall.currency != "sat": data.price *= settings.fiat_base_multiplier if product_id: - product = await get_shop_product(product_id) + product = await get_market_product(product_id) if not product: return {"message": "Product does not exist."} - # stall = await get_shop_stall(stall_id=product.stall) + # stall = await get_market_stall(stall_id=product.stall) if stall.wallet != wallet.wallet.id: return {"message": "Not your product."} - product = await update_shop_product(product_id, **data.dict()) + product = await update_market_product(product_id, **data.dict()) else: - product = await create_shop_product(data=data) + product = await create_market_product(data=data) assert product return product.dict() -@shop_ext.delete("/api/v1/products/{product_id}") -async def api_shop_products_delete( +@market_ext.delete("/api/v1/products/{product_id}") +async def api_market_products_delete( product_id, wallet: WalletTypeInfo = Depends(require_admin_key) ): - product = await get_shop_product(product_id) + product = await get_market_product(product_id) if not product: return {"message": "Product does not exist."} - stall = await get_shop_stall(product.stall) + stall = await get_market_stall(product.stall) assert stall if stall.wallet != wallet.wallet.id: - return {"message": "Not your Shop."} + return {"message": "Not your Market."} - await delete_shop_product(product_id) + await delete_market_product(product_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) # # # Shippingzones -@shop_ext.get("/api/v1/zones") -async def api_shop_zones(wallet: WalletTypeInfo = Depends(get_key_type)): +@market_ext.get("/api/v1/zones") +async def api_market_zones(wallet: WalletTypeInfo = Depends(get_key_type)): - return await get_shop_zones(wallet.wallet.user) + return await get_market_zones(wallet.wallet.user) -@shop_ext.post("/api/v1/zones") -async def api_shop_zone_create( +@market_ext.post("/api/v1/zones") +async def api_market_zone_create( data: createZones, wallet: WalletTypeInfo = Depends(get_key_type) ): - zone = await create_shop_zone(user=wallet.wallet.user, data=data) + zone = await create_market_zone(user=wallet.wallet.user, data=data) return zone.dict() -@shop_ext.post("/api/v1/zones/{zone_id}") -async def api_shop_zone_update( +@market_ext.post("/api/v1/zones/{zone_id}") +async def api_market_zone_update( data: createZones, zone_id: str, wallet: WalletTypeInfo = Depends(require_admin_key), ): - zone = await get_shop_zone(zone_id) + zone = await get_market_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_shop_zone(zone_id, **data.dict()) + zone = await update_market_zone(zone_id, **data.dict()) return zone -@shop_ext.delete("/api/v1/zones/{zone_id}") -async def api_shop_zone_delete( +@market_ext.delete("/api/v1/zones/{zone_id}") +async def api_market_zone_delete( zone_id, wallet: WalletTypeInfo = Depends(require_admin_key) ): - zone = await get_shop_zone(zone_id) + zone = await get_market_zone(zone_id) if not zone: return {"message": "zone does not exist."} @@ -192,15 +192,15 @@ async def api_shop_zone_delete( if zone.user != wallet.wallet.user: return {"message": "Not your zone."} - await delete_shop_zone(zone_id) + await delete_market_zone(zone_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) # # # Stalls -@shop_ext.get("/api/v1/stalls") -async def api_shop_stalls( +@market_ext.get("/api/v1/stalls") +async def api_market_stalls( wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False) ): wallet_ids = [wallet.wallet.id] @@ -209,37 +209,37 @@ async def api_shop_stalls( user = await get_user(wallet.wallet.user) wallet_ids = user.wallet_ids if user else [] - return [stall.dict() for stall in await get_shop_stalls(wallet_ids)] + return [stall.dict() for stall in await get_market_stalls(wallet_ids)] -@shop_ext.post("/api/v1/stalls") -@shop_ext.put("/api/v1/stalls/{stall_id}") -async def api_shop_stall_create( +@market_ext.post("/api/v1/stalls") +@market_ext.put("/api/v1/stalls/{stall_id}") +async def api_market_stall_create( data: createStalls, stall_id: str = None, wallet: WalletTypeInfo = Depends(require_invoice_key), ): if stall_id: - stall = await get_shop_stall(stall_id) + stall = await get_market_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_shop_stall(stall_id, **data.dict()) + stall = await update_market_stall(stall_id, **data.dict()) else: - stall = await create_shop_stall(data=data) + stall = await create_market_stall(data=data) assert stall return stall.dict() -@shop_ext.delete("/api/v1/stalls/{stall_id}") -async def api_shop_stall_delete( +@market_ext.delete("/api/v1/stalls/{stall_id}") +async def api_market_stall_delete( stall_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) ): - stall = await get_shop_stall(stall_id) + stall = await get_market_stall(stall_id) if not stall: return {"message": "Stall does not exist."} @@ -247,15 +247,15 @@ async def api_shop_stall_delete( if stall.wallet != wallet.wallet.id: return {"message": "Not your Stall."} - await delete_shop_stall(stall_id) + await delete_market_stall(stall_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) ###Orders -@shop_ext.get("/api/v1/orders") -async def api_shop_orders( +@market_ext.get("/api/v1/orders") +async def api_market_orders( wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False) ): wallet_ids = [wallet.wallet.id] @@ -263,48 +263,48 @@ async def api_shop_orders( user = await get_user(wallet.wallet.user) wallet_ids = user.wallet_ids if user else [] - orders = await get_shop_orders(wallet_ids) + orders = await get_market_orders(wallet_ids) if not orders: return orders_with_details = [] for order in orders: _order = order.dict() - _order["details"] = await get_shop_order_details(_order["id"]) + _order["details"] = await get_market_order_details(_order["id"]) orders_with_details.append(_order) try: return orders_with_details # [order for order in orders] - # return [order.dict() for order in await get_shop_orders(wallet_ids)] + # return [order.dict() for order in await get_market_orders(wallet_ids)] except: return {"message": "We could not retrieve the orders."} -@shop_ext.get("/api/v1/orders/{order_id}") -async def api_shop_order_by_id(order_id: str): - order = await get_shop_order(order_id) +@market_ext.get("/api/v1/orders/{order_id}") +async def api_market_order_by_id(order_id: str): + order = await get_market_order(order_id) assert order _order = order.dict() - _order["details"] = await get_shop_order_details(order_id) + _order["details"] = await get_market_order_details(order_id) return _order -@shop_ext.post("/api/v1/orders") -async def api_shop_order_create(data: createOrder): +@market_ext.post("/api/v1/orders") +async def api_market_order_create(data: createOrder): 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", + memo=f"New order on Market", extra={ - "tag": "shop", + "tag": "market", "reference": ref, }, ) - order_id = await create_shop_order(invoiceid=payment_hash, data=data) + order_id = await create_market_order(invoiceid=payment_hash, data=data) logger.debug(f"ORDER ID {order_id}") logger.debug(f"PRODUCTS {data.products}") - await create_shop_order_details(order_id=order_id, data=data.products) + await create_market_order_details(order_id=order_id, data=data.products) return { "payment_hash": payment_hash, "payment_request": payment_request, @@ -312,9 +312,9 @@ async def api_shop_order_create(data: createOrder): } -@shop_ext.get("/api/v1/orders/payments/{payment_hash}") -async def api_shop_check_payment(payment_hash: str): - order = await get_shop_order_invoiceid(payment_hash) +@market_ext.get("/api/v1/orders/payments/{payment_hash}") +async def api_market_check_payment(payment_hash: str): + order = await get_market_order_invoiceid(payment_hash) if not order: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Order does not exist." @@ -328,11 +328,11 @@ async def api_shop_check_payment(payment_hash: str): return status -@shop_ext.delete("/api/v1/orders/{order_id}") -async def api_shop_order_delete( +@market_ext.delete("/api/v1/orders/{order_id}") +async def api_market_order_delete( order_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) ): - order = await get_shop_order(order_id) + order = await get_market_order(order_id) if not order: return {"message": "Order does not exist."} @@ -340,17 +340,17 @@ async def api_shop_order_delete( if order.wallet != wallet.wallet.id: return {"message": "Not your Order."} - await delete_shop_order(order_id) + await delete_market_order(order_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) -# @shop_ext.get("/api/v1/orders/paid/{order_id}") -# async def api_shop_order_paid( +# @market_ext.get("/api/v1/orders/paid/{order_id}") +# async def api_market_order_paid( # order_id, wallet: WalletTypeInfo = Depends(require_admin_key) # ): # await db.execute( -# "UPDATE shop.orders SET paid = ? WHERE id = ?", +# "UPDATE market.orders SET paid = ? WHERE id = ?", # ( # True, # order_id, @@ -359,24 +359,24 @@ async def api_shop_order_delete( # return "", HTTPStatus.OK -@shop_ext.get("/api/v1/order/pubkey/{payment_hash}/{pubkey}") -async def api_shop_order_pubkey(payment_hash: str, pubkey: str): - await set_shop_order_pubkey(payment_hash, pubkey) +@market_ext.get("/api/v1/order/pubkey/{payment_hash}/{pubkey}") +async def api_market_order_pubkey(payment_hash: str, pubkey: str): + await set_market_order_pubkey(payment_hash, pubkey) return "", HTTPStatus.OK -@shop_ext.get("/api/v1/orders/shipped/{order_id}") -async def api_shop_order_shipped( +@market_ext.get("/api/v1/orders/shipped/{order_id}") +async def api_market_order_shipped( order_id, shipped: bool = Query(...), wallet: WalletTypeInfo = Depends(get_key_type) ): await db.execute( - "UPDATE shop.orders SET shipped = ? WHERE id = ?", + "UPDATE market.orders SET shipped = ? WHERE id = ?", ( shipped, order_id, ), ) - order = await db.fetchone("SELECT * FROM shop.orders WHERE id = ?", (order_id,)) + order = await db.fetchone("SELECT * FROM market.orders WHERE id = ?", (order_id,)) return order @@ -384,31 +384,31 @@ async def api_shop_order_shipped( ###List products based on stall id -# @shop_ext.get("/api/v1/stall/products/{stall_id}") -# async def api_shop_stall_products( +# @market_ext.get("/api/v1/stall/products/{stall_id}") +# async def api_market_stall_products( # stall_id, wallet: WalletTypeInfo = Depends(get_key_type) # ): -# rows = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)) +# rows = await db.fetchone("SELECT * FROM market.stalls WHERE id = ?", (stall_id,)) # if not rows: # return {"message": "Stall does not exist."} -# products = db.fetchone("SELECT * FROM shop.products WHERE wallet = ?", (rows[1],)) +# products = db.fetchone("SELECT * FROM market.products WHERE wallet = ?", (rows[1],)) # if not products: # return {"message": "No products"} -# return [products.dict() for products in await get_shop_products(rows[1])] +# return [products.dict() for products in await get_market_products(rows[1])] ###Check a product has been shipped -# @shop_ext.get("/api/v1/stall/checkshipped/{checking_id}") -# async def api_shop_stall_checkshipped( +# @market_ext.get("/api/v1/stall/checkshipped/{checking_id}") +# async def api_market_stall_checkshipped( # checking_id, wallet: WalletTypeInfo = Depends(get_key_type) # ): # rows = await db.fetchone( -# "SELECT * FROM shop.orders WHERE invoiceid = ?", (checking_id,) +# "SELECT * FROM market.orders WHERE invoiceid = ?", (checking_id,) # ) # return {"shipped": rows["shipped"]} @@ -418,42 +418,42 @@ async def api_shop_order_shipped( ## -@shop_ext.get("/api/v1/markets") -async def api_shop_markets(wallet: WalletTypeInfo = Depends(get_key_type)): - # await get_shop_market_stalls(market_id="FzpWnMyHQMcRppiGVua4eY") +@market_ext.get("/api/v1/markets") +async def api_market_markets(wallet: WalletTypeInfo = Depends(get_key_type)): + # await get_market_market_stalls(market_id="FzpWnMyHQMcRppiGVua4eY") try: - return [market.dict() for market in await get_shop_markets(wallet.wallet.user)] + return [market.dict() for market in await get_market_markets(wallet.wallet.user)] except: return {"message": "We could not retrieve the markets."} -@shop_ext.get("/api/v1/markets/{market_id}/stalls") -async def api_shop_market_stalls(market_id: str): - stall_ids = await get_shop_market_stalls(market_id) +@market_ext.get("/api/v1/markets/{market_id}/stalls") +async def api_market_market_stalls(market_id: str): + stall_ids = await get_market_market_stalls(market_id) return stall_ids -@shop_ext.post("/api/v1/markets") -@shop_ext.put("/api/v1/markets/{market_id}") -async def api_shop_market_create( +@market_ext.post("/api/v1/markets") +@market_ext.put("/api/v1/markets/{market_id}") +async def api_market_market_create( data: CreateMarket, market_id: str = None, wallet: WalletTypeInfo = Depends(require_invoice_key), ): if market_id: - market = await get_shop_market(market_id) + market = await get_market_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_shop_market(market_id, data.name) + market = await update_market_market(market_id, data.name) else: - market = await create_shop_market(data=data) + market = await create_market_market(data=data) assert market - await create_shop_market_stalls(market_id=market.id, data=data.stalls) + await create_market_market_stalls(market_id=market.id, data=data.stalls) return market.dict() @@ -461,39 +461,39 @@ async def api_shop_market_create( ## MESSAGES/CHAT -@shop_ext.get("/api/v1/chat/messages/merchant") +@market_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_shop_chat_by_merchant(orders.split(","))] + return [msg.dict() for msg in await get_market_chat_by_merchant(orders.split(","))] -@shop_ext.get("/api/v1/chat/messages/{room_name}") +@market_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: - messages = await get_shop_chat_messages(room_name) + messages = await get_market_chat_messages(room_name) else: - messages = await get_shop_latest_chat_messages(room_name) + messages = await get_market_latest_chat_messages(room_name) return messages -@shop_ext.get("/api/v1/currencies") +@market_ext.get("/api/v1/currencies") async def api_list_currencies_available(): return list(currencies.keys()) -@shop_ext.get("/api/v1/settings") +@market_ext.get("/api/v1/settings") async def api_get_settings(wallet: WalletTypeInfo = Depends(require_admin_key)): user = wallet.wallet.user - settings = await get_shop_settings(user) + settings = await get_market_settings(user) return settings -@shop_ext.post("/api/v1/settings") -@shop_ext.put("/api/v1/settings/{usr}") +@market_ext.post("/api/v1/settings") +@market_ext.put("/api/v1/settings/{usr}") async def api_set_settings( data: SetSettings, usr: str = None, @@ -501,16 +501,16 @@ async def api_set_settings( ): if usr: if usr != wallet.wallet.user: - return {"message": "Not your Shop."} + return {"message": "Not your Market."} - settings = await get_shop_settings(user=usr) + settings = await get_market_settings(user=usr) assert settings if settings.user != wallet.wallet.user: - return {"message": "Not your Shop."} + return {"message": "Not your Market."} - return await set_shop_settings(usr, data) + return await set_market_settings(usr, data) user = wallet.wallet.user - return await create_shop_settings(user, data) + return await create_market_settings(user, data) diff --git a/lnbits/extensions/shop/config.json b/lnbits/extensions/shop/config.json deleted file mode 100644 index eba0def9..00000000 --- a/lnbits/extensions/shop/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Shop", - "short_description": "Make a webshop on LNbits", - "tile": "/shop/static/images/bitcoin-shop.png", - "contributors": ["benarc", "talvasconcelos"] -} From a035612da3460eb6178cc9a03be5c14c130402ca Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 21:11:06 +0000 Subject: [PATCH 173/174] format --- lnbits/extensions/market/crud.py | 6 ++++-- .../market/templates/market/index.html | 21 ++++++++++++++----- .../market/templates/market/order.html | 4 +++- lnbits/extensions/market/views_api.py | 4 +++- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lnbits/extensions/market/crud.py b/lnbits/extensions/market/crud.py index 6d82b354..1d9c28be 100644 --- a/lnbits/extensions/market/crud.py +++ b/lnbits/extensions/market/crud.py @@ -14,10 +14,10 @@ from .models import ( CreateMarket, CreateMarketStalls, Market, + MarketSettings, OrderDetail, Orders, Products, - MarketSettings, Stalls, Zones, createOrder, @@ -456,7 +456,9 @@ async def get_market_chat_by_merchant(ids: List[str]) -> List[ChatMessage]: async def get_market_settings(user) -> Optional[MarketSettings]: - row = await db.fetchone("""SELECT * FROM market.settings WHERE "user" = ?""", (user,)) + row = await db.fetchone( + """SELECT * FROM market.settings WHERE "user" = ?""", (user,) + ) return MarketSettings(**row) if row else None diff --git a/lnbits/extensions/market/templates/market/index.html b/lnbits/extensions/market/templates/market/index.html index e16e5d48..ffcb612b 100644 --- a/lnbits/extensions/market/templates/market/index.html +++ b/lnbits/extensions/market/templates/market/index.html @@ -60,7 +60,8 @@ @click="marketDialog.show = true" >Create Market - Makes a simple frontend market for your stalls (not NOSTR) @@ -596,7 +597,9 @@ this.$q.localStorage.set(`lnbits.market.${this.g.user.id}`, this.keys) }, restoreKeys() { - let keys = this.$q.localStorage.getItem(`lnbits.market.${this.g.user.id}`) + let keys = this.$q.localStorage.getItem( + `lnbits.market.${this.g.user.id}` + ) if (keys) { this.keys = keys this.stallDialog.data.publickey = this.keys.pubkey @@ -1027,7 +1030,11 @@ //////////////////////////////////////// getMarkets() { LNbits.api - .request('GET', '/market/api/v1/markets', this.g.user.wallets[0].inkey) + .request( + 'GET', + '/market/api/v1/markets', + this.g.user.wallets[0].inkey + ) .then(response => { if (response.data) { this.markets = response.data.map(mapMarkets) @@ -1318,7 +1325,9 @@ } else { ws_scheme = 'ws://' } - ws = new WebSocket(ws_scheme + location.host + '/market/ws/' + room_name) + ws = new WebSocket( + ws_scheme + location.host + '/market/ws/' + room_name + ) ws.onmessage = async event => { let event_data = JSON.parse(event.data) @@ -1359,7 +1368,9 @@ await this.getOrders() this.getMarkets() await this.getAllMessages() - let keys = this.$q.localStorage.getItem(`lnbits.market.${this.g.user.id}`) + let keys = this.$q.localStorage.getItem( + `lnbits.market.${this.g.user.id}` + ) if (keys) { this.keys = keys } diff --git a/lnbits/extensions/market/templates/market/order.html b/lnbits/extensions/market/templates/market/order.html index ebabe882..5be606f9 100644 --- a/lnbits/extensions/market/templates/market/order.html +++ b/lnbits/extensions/market/templates/market/order.html @@ -443,7 +443,9 @@ } else { ws_scheme = 'ws://' } - ws = new WebSocket(ws_scheme + location.host + '/market/ws/' + room_name) + ws = new WebSocket( + ws_scheme + location.host + '/market/ws/' + room_name + ) ws.onmessage = event => { let event_data = JSON.parse(event.data) diff --git a/lnbits/extensions/market/views_api.py b/lnbits/extensions/market/views_api.py index 8d0202a3..045bc0fc 100644 --- a/lnbits/extensions/market/views_api.py +++ b/lnbits/extensions/market/views_api.py @@ -422,7 +422,9 @@ async def api_market_order_shipped( async def api_market_markets(wallet: WalletTypeInfo = Depends(get_key_type)): # await get_market_market_stalls(market_id="FzpWnMyHQMcRppiGVua4eY") try: - return [market.dict() for market in await get_market_markets(wallet.wallet.user)] + return [ + market.dict() for market in await get_market_markets(wallet.wallet.user) + ] except: return {"message": "We could not retrieve the markets."} From 4ff0d0a799e2074d3fa81b366a773a0fd2e9f7c3 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 21:17:04 +0000 Subject: [PATCH 174/174] Name Tweak --- lnbits/extensions/market/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/market/config.json b/lnbits/extensions/market/config.json index b540189e..8a294867 100644 --- a/lnbits/extensions/market/config.json +++ b/lnbits/extensions/market/config.json @@ -1,6 +1,6 @@ { - "name": "Market", - "short_description": "Webmarket on LNbits", + "name": "Marketplace", + "short_description": "Webshop/market on LNbits", "tile": "/market/static/images/bitcoin-shop.png", "contributors": ["benarc", "talvasconcelos"] }