feat: allow to add test public key

This commit is contained in:
Vlad Stan 2023-05-04 12:15:45 +03:00
parent 7554374236
commit f7dd15e775
6 changed files with 134 additions and 11 deletions

View file

@ -4,6 +4,7 @@ import secrets
from typing import Any, Optional, Tuple from typing import Any, Optional, Tuple
import secp256k1 import secp256k1
from bech32 import bech32_decode, convertbits
from cffi import FFI from cffi import FFI
from cryptography.hazmat.primitives import padding from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 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) return (order, s) if (type(order) is dict) and "items" in order else (None, s)
except ValueError: except ValueError:
return None, s 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

View file

@ -352,7 +352,7 @@ async def _handle_new_order(order: PartialOrder) -> Optional[str]:
return None return None
async def _handle_new_customer(event, merchant): async def _handle_new_customer(event, merchant: Merchant):
await create_customer( await create_customer(
merchant.id, Customer(merchant_id=merchant.id, public_key=event.pubkey) merchant.id, Customer(merchant_id=merchant.id, public_key=event.pubkey)
) )

View file

@ -26,14 +26,31 @@
<q-separator></q-separator> <q-separator></q-separator>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
<q-select <div class="row">
v-model="activePublicKey" <div class="col-10">
:options="customers.map(c => ({label: buildCustomerLabel(c), value: c.public_key}))" <q-select
label="Select Customer" v-model="activePublicKey"
emit-value :options="customers.map(c => ({label: buildCustomerLabel(c), value: c.public_key}))"
@input="selectActiveCustomer()" label="Select Customer"
> emit-value
</q-select> @input="selectActiveCustomer()"
>
</q-select>
</div>
<div class="col-2">
<q-btn
label="Add"
color="green"
class="float-right q-mt-md"
@click="showAddPublicKey = true"
>
<q-tooltip>
Add a public key to chat with
</q-tooltip>
</q-btn>
</div>
</div>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
<div class="chat-container" ref="chatCard"> <div class="chat-container" ref="chatCard">
@ -76,4 +93,30 @@
</div> </div>
</q-card-section> </q-card-section>
</q-card> </q-card>
<div>
<q-dialog v-model="showAddPublicKey" position="top">
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
<q-form @submit="addPublicKey" class="q-gutter-md">
<q-input
filled
dense
v-model.trim="newPublicKey"
label="Public Key (hex or nsec)"
></q-input>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
:disable="!newPublicKey"
type="submit"
>Add</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
</div>
</div> </div>

View file

@ -2,7 +2,7 @@ async function directMessages(path) {
const template = await loadTemplateAsync(path) const template = await loadTemplateAsync(path)
Vue.component('direct-messages', { Vue.component('direct-messages', {
name: 'direct-messages', name: 'direct-messages',
props: ['active-chat-customer', 'adminkey', 'inkey'], props: ['active-chat-customer', 'merchant-id', 'adminkey', 'inkey'],
template, template,
watch: { watch: {
@ -19,7 +19,9 @@ async function directMessages(path) {
unreadMessages: 0, unreadMessages: 0,
activePublicKey: null, activePublicKey: null,
messages: [], messages: [],
newMessage: '' newMessage: '',
showAddPublicKey: false,
newPublicKey: null
} }
}, },
methods: { methods: {
@ -83,6 +85,26 @@ async function directMessages(path) {
LNbits.utils.notifyApiError(error) 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) { handleNewMessage: async function (data) {
if (data.customerPubkey === this.activePublicKey) { if (data.customerPubkey === this.activePublicKey) {
await this.getDirectMessages(this.activePublicKey) await this.getDirectMessages(this.activePublicKey)

View file

@ -167,6 +167,7 @@
:inkey="g.user.wallets[0].inkey" :inkey="g.user.wallets[0].inkey"
:adminkey="g.user.wallets[0].adminkey" :adminkey="g.user.wallets[0].adminkey"
:active-chat-customer="activeChatCustomer" :active-chat-customer="activeChatCustomer"
:merchant-id="merchant.id"
@customer-selected="filterOrdersForCustomer" @customer-selected="filterOrdersForCustomer"
> >
</direct-messages> </direct-messages>

View file

@ -13,10 +13,12 @@ from lnbits.decorators import (
require_admin_key, require_admin_key,
require_invoice_key, require_invoice_key,
) )
from lnbits.extensions.nostrmarket.helpers import normalize_public_key
from lnbits.utils.exchange_rates import currencies from lnbits.utils.exchange_rates import currencies
from . import nostr_client, nostrmarket_ext, scheduled_tasks from . import nostr_client, nostrmarket_ext, scheduled_tasks
from .crud import ( from .crud import (
create_customer,
create_direct_message, create_direct_message,
create_merchant, create_merchant,
create_product, create_product,
@ -31,6 +33,7 @@ from .crud import (
delete_product, delete_product,
delete_stall, delete_stall,
delete_zone, delete_zone,
get_customer,
get_customers, get_customers,
get_direct_messages, get_direct_messages,
get_merchant_by_pubkey, 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 ######################################## ######################################## OTHER ########################################