From f7dd15e775642d059f708db61df9c76ebdf2001b Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Thu, 4 May 2023 12:15:45 +0300 Subject: [PATCH] feat: allow to add test public key --- helpers.py | 19 ++++++ services.py | 2 +- .../direct-messages/direct-messages.html | 59 ++++++++++++++++--- .../direct-messages/direct-messages.js | 26 +++++++- templates/nostrmarket/index.html | 1 + views_api.py | 38 ++++++++++++ 6 files changed, 134 insertions(+), 11 deletions(-) diff --git a/helpers.py b/helpers.py index d3c9f93..a880e24 100644 --- a/helpers.py +++ b/helpers.py @@ -4,6 +4,7 @@ import secrets from typing import Any, Optional, Tuple import secp256k1 +from bech32 import bech32_decode, convertbits from cffi import FFI from cryptography.hazmat.primitives import padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes @@ -80,3 +81,21 @@ def order_from_json(s: str) -> Tuple[Optional[Any], Optional[str]]: return (order, s) if (type(order) is dict) and "items" in order else (None, s) except ValueError: return None, s + + +def normalize_public_key(pubkey: str) -> str: + if pubkey.startswith("npub1"): + _, decoded_data = bech32_decode(pubkey) + if not decoded_data: + raise ValueError("Public Key is not valid npub") + + decoded_data_bits = convertbits(decoded_data, 5, 8, False) + if not decoded_data_bits: + raise ValueError("Public Key is not valid npub") + return bytes(decoded_data_bits).hex() + + # check if valid hex + if len(pubkey) != 64: + raise ValueError("Public Key is not valid hex") + int(pubkey, 16) + return pubkey diff --git a/services.py b/services.py index 89b4859..57bb86a 100644 --- a/services.py +++ b/services.py @@ -352,7 +352,7 @@ async def _handle_new_order(order: PartialOrder) -> Optional[str]: return None -async def _handle_new_customer(event, merchant): +async def _handle_new_customer(event, merchant: Merchant): await create_customer( merchant.id, Customer(merchant_id=merchant.id, public_key=event.pubkey) ) diff --git a/static/components/direct-messages/direct-messages.html b/static/components/direct-messages/direct-messages.html index ab7eee1..a1f8662 100644 --- a/static/components/direct-messages/direct-messages.html +++ b/static/components/direct-messages/direct-messages.html @@ -26,14 +26,31 @@ - - +
+
+ + +
+
+ + + Add a public key to chat with + + +
+
+
@@ -76,4 +93,30 @@
+
+ + + + +
+ Add + Cancel +
+
+
+
+
diff --git a/static/components/direct-messages/direct-messages.js b/static/components/direct-messages/direct-messages.js index 39bc7d3..b295c19 100644 --- a/static/components/direct-messages/direct-messages.js +++ b/static/components/direct-messages/direct-messages.js @@ -2,7 +2,7 @@ async function directMessages(path) { const template = await loadTemplateAsync(path) Vue.component('direct-messages', { name: 'direct-messages', - props: ['active-chat-customer', 'adminkey', 'inkey'], + props: ['active-chat-customer', 'merchant-id', 'adminkey', 'inkey'], template, watch: { @@ -19,7 +19,9 @@ async function directMessages(path) { unreadMessages: 0, activePublicKey: null, messages: [], - newMessage: '' + newMessage: '', + showAddPublicKey: false, + newPublicKey: null } }, methods: { @@ -83,6 +85,26 @@ async function directMessages(path) { LNbits.utils.notifyApiError(error) } }, + addPublicKey: async function(){ + try { + const {data} = await LNbits.api.request( + 'POST', + '/nostrmarket/api/v1/customers', + this.adminkey, + { + public_key: this.newPublicKey, + merchant_id: this.merchantId, + unread_messages: 0 + } + ) + this.activePublicKey = data.public_key + await this.selectActiveCustomer() + } catch (error) { + LNbits.utils.notifyApiError(error) + } finally { + this.showAddPublicKey = false + } + }, handleNewMessage: async function (data) { if (data.customerPubkey === this.activePublicKey) { await this.getDirectMessages(this.activePublicKey) diff --git a/templates/nostrmarket/index.html b/templates/nostrmarket/index.html index 89e01ba..603cf6b 100644 --- a/templates/nostrmarket/index.html +++ b/templates/nostrmarket/index.html @@ -167,6 +167,7 @@ :inkey="g.user.wallets[0].inkey" :adminkey="g.user.wallets[0].adminkey" :active-chat-customer="activeChatCustomer" + :merchant-id="merchant.id" @customer-selected="filterOrdersForCustomer" > diff --git a/views_api.py b/views_api.py index 0fa8317..c48410f 100644 --- a/views_api.py +++ b/views_api.py @@ -13,10 +13,12 @@ from lnbits.decorators import ( require_admin_key, require_invoice_key, ) +from lnbits.extensions.nostrmarket.helpers import normalize_public_key from lnbits.utils.exchange_rates import currencies from . import nostr_client, nostrmarket_ext, scheduled_tasks from .crud import ( + create_customer, create_direct_message, create_merchant, create_product, @@ -31,6 +33,7 @@ from .crud import ( delete_product, delete_stall, delete_zone, + get_customer, get_customers, get_direct_messages, get_merchant_by_pubkey, @@ -818,6 +821,41 @@ async def api_get_customers( ) +@nostrmarket_ext.post("/api/v1/customers") +async def api_createcustomer( + data: Customer, + wallet: WalletTypeInfo = Depends(require_admin_key), +) -> Customer: + + try: + pubkey = normalize_public_key(data.public_key) + + merchant = await get_merchant_for_user(wallet.wallet.user) + assert merchant, "A merchant does not exists for this user" + assert merchant.id == data.merchant_id, "Invalid merchant id for user" + + existing_customer = await get_customer(merchant.id, pubkey) + assert existing_customer == None, "This public key already exists" + + customer = await create_customer( + merchant.id, Customer(merchant_id=merchant.id, public_key=pubkey) + ) + await nostr_client.subscribe_to_user_profile(pubkey, 0) + + return customer + except (ValueError, AssertionError) as ex: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=str(ex), + ) + except Exception as ex: + logger.warning(ex) + raise HTTPException( + status_code=HTTPStatus.INTERNAL_SERVER_ERROR, + detail="Cannot create customer", + ) + + ######################################## OTHER ########################################