Product delete (#64)

* feat: restore stalls from `nostr` as pending

* feat: stall and prod last update time

* feat: restore products and stalls as `pending`

* feat: show pending stalls

* feat: restore stall

* feat: restore a stall from nostr

* feat: add  blank `Restore Product` button

* fix: handle no talls to restore case

* feat: show restore dialog

* feat: allow query for pending products

* feat: restore products

* chore: code clean-up

* fix: last dm and last order query

* chore: code clean-up

* fix: subscribe for stalls and products on merchant create/restore

* feat: add message type to orders

* feat: simplify messages; code format

* feat: add type to DMs; restore DMs from nostr

* fix: parsing ints

* fix: hide copy button if invoice not present

* fix: do not generate invoice if product not found

* feat: order restore: first version

* refactor: move some logic into `services`

* feat: improve restore UX

* fix: too many calls to customer DMs

* fix: allow `All` customers filter

* fix: ws reconnect on server restart

* fix: query for customer profiles only one

* fix: unread messages per customer per merchant

* fix: disable `user-profile-events`

* fix: customer profile is optional

* fix: get customers after new message debounced

* chore: code clean-up

* feat: auto-create zone

* feat: fixed ID for default zone

* feat: notify order paid
This commit is contained in:
Vlad Stan 2023-06-30 12:12:56 +02:00 committed by GitHub
parent 1cb8fe86b1
commit 51c4147e65
17 changed files with 934 additions and 610 deletions

View file

@ -2,7 +2,7 @@ import asyncio
import json
from asyncio import Queue
from threading import Thread
from typing import Callable
from typing import Callable, List
from loguru import logger
from websocket import WebSocketApp
@ -18,11 +18,6 @@ class NostrClient:
self.send_req_queue: Queue = Queue()
self.ws: WebSocketApp = None
async def restart(self):
await self.send_req_queue.put(ValueError("Restarting NostrClient..."))
await self.recieve_event_queue.put(ValueError("Restarting NostrClient..."))
self.ws.close()
self.ws = None
async def connect_to_nostrclient_ws(
self, on_open: Callable, on_message: Callable
@ -96,36 +91,80 @@ class NostrClient:
["REQ", f"direct-messages-out:{public_key}", out_messages_filter]
)
async def subscribe_to_merchant_events(self, public_key: str, since: int):
logger.debug(f"Subscribed to direct-messages '{public_key}'.")
async def subscribe_to_stall_events(self, public_key: str, since: int):
stall_filter = {"kinds": [30017], "authors": [public_key]}
product_filter = {"kinds": [30018], "authors": [public_key]}
if since and since != 0:
stall_filter["since"] = since
await self.send_req_queue.put(
["REQ", f"stall-events:{public_key}", stall_filter]
)
logger.debug(f"Subscribed to stall-events: '{public_key}'.")
async def subscribe_to_product_events(self, public_key: str, since: int):
product_filter = {"kinds": [30018], "authors": [public_key]}
if since and since != 0:
product_filter["since"] = since
await self.send_req_queue.put(
["REQ", f"product-events:{public_key}", product_filter]
)
logger.debug(f"Subscribed to product-events: '{public_key}'.")
async def subscribe_to_user_profile(self, public_key: str, since: int):
profile_filter = {"kinds": [0], "authors": [public_key]}
if since and since != 0:
profile_filter["since"] = since + 1
await self.send_req_queue.put(
["REQ", f"user-profile-events:{public_key}", profile_filter]
)
# Disabled for now. The number of clients can grow large.
# Some relays only allow a small number of subscriptions.
# There is the risk that more important subscriptions will be blocked.
# await self.send_req_queue.put(
# ["REQ", f"user-profile-events:{public_key}", profile_filter]
# )
async def unsubscribe_from_direct_messages(self, public_key: str):
await self.send_req_queue.put(["CLOSE", f"direct-messages-in:{public_key}"])
await self.send_req_queue.put(["CLOSE", f"direct-messages-out:{public_key}"])
logger.debug(f"Unsubscribed from direct-messages '{public_key}'.")
async def unsubscribe_from_merchant_events(self, public_key: str):
await self.send_req_queue.put(["CLOSE", f"stall-events:{public_key}"])
await self.send_req_queue.put(["CLOSE", f"product-events:{public_key}"])
def stop(self):
try:
self.ws.close()
except Exception as ex:
logger.warning(ex)
logger.debug(f"Unsubscribed from stall-events and product-events '{public_key}'.")
async def restart(self, public_keys: List[str]):
await self.unsubscribe_merchants(public_keys)
# Give some time for the CLOSE events to propagate before restarting
await asyncio.sleep(10)
logger.info("Restating NostrClient...")
await self.send_req_queue.put(ValueError("Restarting NostrClient..."))
await self.recieve_event_queue.put(ValueError("Restarting NostrClient..."))
self.ws.close()
self.ws = None
async def stop(self, public_keys: List[str]):
await self.unsubscribe_merchants(public_keys)
# Give some time for the CLOSE events to propagate before closing the connection
await asyncio.sleep(10)
self.ws.close()
self.ws = None
async def unsubscribe_merchants(self, public_keys: List[str]):
for pk in public_keys:
try:
await self.unsubscribe_from_direct_messages(pk)
await self.unsubscribe_from_merchant_events(pk)
except Exception as ex:
logger.warning(ex)