merchant chat functional almost out of WIP

This commit is contained in:
Tiago Vasconcelos 2022-10-19 22:08:48 +01:00
parent ebe8d8b0b9
commit 532e12ec83
7 changed files with 461 additions and 79 deletions

View file

@ -408,8 +408,10 @@ async def create_diagonalley_market_stalls(
async def update_diagonalley_market(market_id): async def update_diagonalley_market(market_id):
pass pass
### CHAT / MESSAGES ### CHAT / MESSAGES
async def create_chat_message(data: CreateChatMessage): async def create_chat_message(data: CreateChatMessage):
print("DATA", data) print("DATA", data)
await db.execute( await db.execute(
@ -441,3 +443,14 @@ async def get_diagonalley_chat_messages(room_name: str):
) )
return [ChatMessage(**row) for row in rows] 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]

View file

@ -78,9 +78,9 @@ class Notifier:
async def _notify(self, message: str, room_name: str): async def _notify(self, message: str, room_name: str):
"""Notifier""" """Notifier"""
d = json.loads(message) d = json.loads(message)
d["room_name"] = room_name d["room_name"] = room_name
print("hey", d)
db_msg = CreateChatMessage.parse_obj(d) db_msg = CreateChatMessage.parse_obj(d)
print("NOT:", db_msg) print("NOT:", db_msg)
await create_chat_message(data=db_msg) await create_chat_message(data=db_msg)

View file

@ -345,20 +345,6 @@
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md"> <div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
<q-card> <q-card>
<q-card-section> <q-card-section>
<q-btn
unelevated
v-if="stalls.length > 0"
color="primary"
@click="productDialog.show = true"
>+ Product <q-tooltip> List a product </q-tooltip></q-btn
>
<q-btn
unelevated
v-else
color="primary"
@click="errorMessage('First set shipping zone(s), then create a stall.')"
>+ Product <q-tooltip> List a product </q-tooltip></q-btn
>
<q-btn unelevated color="primary" @click="zoneDialog.show = true" <q-btn unelevated color="primary" @click="zoneDialog.show = true"
>+ Shipping Zone<q-tooltip> Create a shipping zone </q-tooltip></q-btn >+ Shipping Zone<q-tooltip> Create a shipping zone </q-tooltip></q-btn
> >
@ -382,7 +368,26 @@
Create a market stall to list products on Create a market stall to list products on
</q-tooltip></q-btn </q-tooltip></q-btn
> >
<q-btn unelevated color="primary" @click="marketDialog.show = true" <q-btn
unelevated
v-if="stalls.length > 0"
color="primary"
@click="productDialog.show = true"
>+ Product <q-tooltip> List a product </q-tooltip></q-btn
>
<q-btn
unelevated
v-else
color="primary"
@click="errorMessage('First set shipping zone(s), then create a stall.')"
>+ Product <q-tooltip> List a product </q-tooltip></q-btn
>
<q-btn
class="float-right"
unelevated
flat
color="primary"
@click="marketDialog.show = true"
>Create Market >Create Market
<q-tooltip> <q-tooltip>
Makes a simple frontend shop for your stalls (not NOSTR)</q-tooltip Makes a simple frontend shop for your stalls (not NOSTR)</q-tooltip
@ -415,6 +420,7 @@
{% raw %} {% raw %}
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
<q-th auto-width></q-th>
<q-th auto-width></q-th> <q-th auto-width></q-th>
<q-th v-for="col in props.cols" :key="col.name" :props="props"> <q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label }} {{ col.label }}
@ -434,6 +440,23 @@
:icon="props.expand ? 'remove' : 'add'" :icon="props.expand ? 'remove' : 'add'"
/> />
</q-td> </q-td>
<q-td auto-width>
<q-btn
size="sm"
color="green"
dense
icon="chat"
@click="chatRoom(props.row.invoiceid)"
>
<q-badge
v-if="props.row.unread"
color="red"
rounded
floating
style="padding: 6px; border-radius: 6px"
/>
</q-btn>
</q-td>
<q-td v-for="col in props.cols" :key="col.name" :props="props"> <q-td v-for="col in props.cols" :key="col.name" :props="props">
{{ col.value }} {{ col.value }}
</q-td> </q-td>
@ -824,22 +847,114 @@
<q-list> {% include "diagonalley/_api_docs.html" %} </q-list> <q-list> {% include "diagonalley/_api_docs.html" %} </q-list>
</q-card-section> </q-card-section>
</q-card> </q-card>
<!-- CHAT BOX -->
<q-card> <q-card>
<q-card-section> <q-card-section>
<h6 class="text-subtitle1 q-my-none">Messages</h6> <h6 class="text-subtitle1 q-my-none">Messages</h6>
</q-card-section> </q-card-section>
<q-card-section class="q-pa-none"> <q-card-section class="q-pa-none">
<q-separator></q-separator> <q-separator></q-separator>
</q-card-section>
<div class="column q-ma-md q-pb-lg" style="height: 350px"> <q-card-section>
<div class="col q-pb-md"> <q-select
v-model="customerKey"
:options="Object.keys(messages)"
label="Customers"
@input="chatRoom(customerKey)"
></q-select>
</q-card-section>
<div class="chat-container q-pa-md" ref="chatCard">
<div class="chat-box">
<!-- <p v-if="Object.keys(messages).length === 0">No messages yet</p> -->
<div class="chat-messages">
<q-chat-message
:key="index"
v-for="(message, index) in orderMessages"
:name="message.pubkey == keys.pubkey ? 'me' : 'customer'"
:text="[message.msg]"
:sent="message.pubkey == keys.pubkey ? true : false"
:bg-color="message.pubkey == keys.pubkey ? 'white' : 'light-green-2'"
/>
</div>
</div>
<q-form @submit="sendMessage" class="full-width chat-input">
<q-input
ref="newMessage"
v-model="newMessage"
placeholder="Message"
class="full-width"
dense
outlined
>
<template>
<q-btn
round
dense
flat
type="submit"
icon="send"
color="primary"
/>
</template>
</q-input>
</q-form>
</div>
</q-card>
<!-- <q-card>
<q-card-section>
<h6 class="text-subtitle1 q-my-none">Messages</h6>
</q-card-section>
<q-card-section class="q-pa-none">
<q-separator></q-separator>
<div
ref="chatCard"
class="q-ma-md q-pb-lg"
style="height: 350px"
>
<div class="q-pb-md">
<q-select <q-select
v-model="customerKey" v-model="customerKey"
style="width: 80%" style="width: 80%"
:options="customerKeys" :options="Object.keys(messages)"
label="Customers" label="Customers"
@input="getMessages(customerKey)" @input="chatRoom(customerKey)"
></q-select> ></q-select>
<div class="chat-container q-pa-md">
<div class="chat-box">
<p v-if="Object.keys(messages).length === 0">No messages yet</p>
<div class="chat-messages">
<q-chat-message
:key="index"
v-for="(message, index) in orderMessages"
:name="message.pubkey == keys.pubkey ? 'me' : 'customer'"
:text="[message.msg]"
:sent="message.pubkey == keys.pubkey ? true : false"
:bg-color="message.pubkey == keys.pubkey ? 'white' : 'light-green-2'"
/>
</div>
</div>
<q-form @submit="sendMessage" class="full-width chat-input">
<q-input
ref="newMessage"
v-model="newMessage"
placeholder="Message"
class="full-width"
dense
outlined
>
<template>
<q-btn
round
dense
flat
type="submit"
icon="send"
color="primary"
/>
</template>
</q-input>
</q-form>
</div>
</div> </div>
<div class="col-8 q-px-md"> <div class="col-8 q-px-md">
<div v-for="message in customerMessages"> <div v-for="message in customerMessages">
@ -860,11 +975,10 @@
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
</q-card> </q-card> -->
</div> </div>
</div> </div>
<!-- </div>
</div> -->
{% endblock %} {% block scripts %} {{ window_vars(user) }} {% endblock %} {% block scripts %} {{ window_vars(user) }}
<script src="https://cdn.jsdelivr.net/npm/pica@6.1.1/dist/pica.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/pica@6.1.1/dist/pica.min.js"></script>
@ -873,6 +987,15 @@
const pica = window.pica() 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 => { const mapStalls = obj => {
obj._data = _.clone(obj) obj._data = _.clone(obj)
return obj return obj
@ -891,6 +1014,7 @@
new Date(obj.time * 1000), new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm' 'YYYY-MM-DD HH:mm'
) )
// obj.unread = false
return obj return obj
} }
const mapKeys = obj => { const mapKeys = obj => {
@ -933,8 +1057,12 @@
customerKeys: [], customerKeys: [],
customerKey: '', customerKey: '',
customerMessages: {}, customerMessages: {},
messages: {},
newMessage: '',
orderMessages: {},
shippedModel: false, shippedModel: false,
shippingZoneOptions: [ shippingZoneOptions: [
'Free (digital)',
'Worldwide', 'Worldwide',
'Europe', 'Europe',
'Australia', 'Australia',
@ -1443,9 +1571,10 @@
let image = new Image() let image = new Image()
image.src = blobURL image.src = blobURL
image.onload = async () => { image.onload = async () => {
let fit = imgSizeFit(image)
let canvas = document.createElement('canvas') let canvas = document.createElement('canvas')
canvas.setAttribute('width', 760) canvas.setAttribute('width', fit.width)
canvas.setAttribute('height', 490) canvas.setAttribute('height', fit.height)
await pica.resize(image, canvas, { await pica.resize(image, canvas, {
quality: 0, quality: 0,
alpha: true, alpha: true,
@ -1657,7 +1786,7 @@
.then(response => { .then(response => {
if (response.data) { if (response.data) {
this.markets = response.data.map(mapMarkets) this.markets = response.data.map(mapMarkets)
console.log(this.markets) // console.log(this.markets)
} }
}) })
.catch(error => { .catch(error => {
@ -1756,10 +1885,10 @@
//////////////////////////////////////// ////////////////////////////////////////
////////////////ORDERS////////////////// ////////////////ORDERS//////////////////
//////////////////////////////////////// ////////////////////////////////////////
getOrders: function () { getOrders: async function () {
var self = this var self = this
LNbits.api await LNbits.api
.request( .request(
'GET', 'GET',
'/diagonalley/api/v1/orders?all_wallets=true', '/diagonalley/api/v1/orders?all_wallets=true',
@ -1768,7 +1897,6 @@
.then(function (response) { .then(function (response) {
if (response.data) { if (response.data) {
self.orders = response.data.map(mapOrders) self.orders = response.data.map(mapOrders)
console.log(self.orders)
} }
}) })
.catch(function (error) { .catch(function (error) {
@ -1839,21 +1967,190 @@
}, },
exportOrdersCSV: function () { exportOrdersCSV: function () {
LNbits.utils.exportCSV(this.ordersTable.columns, this.orders) 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])
} }
}, },
created: function () { 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
}
},
async created() {
if (this.g.user.wallets.length) { if (this.g.user.wallets.length) {
this.getStalls() this.getStalls()
this.getProducts() this.getProducts()
this.getZones() this.getZones()
this.getOrders() await this.getOrders()
this.getMarkets() this.getMarkets()
this.customerKeys = [ await this.getAllMessages()
'cb4c0164fe03fcdadcbfb4f76611c71620790944c24f21a1cd119395cdedfe1b', let keys = this.$q.localStorage.getItem(
'a9c17358a6dc4ceb3bb4d883eb87967a66b3453a0f3199f0b1c8eef8070c6a07' `lnbits.diagonalley.${this.g.user.id}`
] )
if (keys) {
this.keys = keys
}
setInterval(() => {
this.getAllMessages()
}, 300000)
} }
} }
}) })
</script> </script>
<style scoped>
.chat-container {
position: relative;
display: grid;
grid-template-rows: 1fr auto;
height: calc(100vh - 140px);
}
.chat-box {
display: flex;
flex-direction: column-reverse;
padding: 1rem;
overflow-y: auto;
}
.chat-messages {
width: auto;
}
.chat-input {
position: relative;
display: flex;
align-items: end;
margin-top: 1rem;
}
</style>
{% endblock %} {% endblock %}

View file

@ -68,7 +68,7 @@
dense dense
emit-value emit-value
v-model="selectedOrder" v-model="selectedOrder"
:options="user.orders" :options="Object.keys(user.orders)"
label="Order" label="Order"
hint="Select an order from this merchant" hint="Select an order from this merchant"
@input="val => { changeOrder() }" @input="val => { changeOrder() }"
@ -187,7 +187,7 @@
msg: this.newMessage, msg: this.newMessage,
pubkey: this.user.keys.publickey pubkey: this.user.keys.publickey
} }
ws.send(JSON.stringify(message)) this.ws.send(JSON.stringify(message))
this.clearMessage() this.clearMessage()
}, },
@ -236,10 +236,16 @@
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}, },
changeOrder() { async changeOrder() {
console.log(this.selectedOrder) this.products = this.user.orders[this.selectedOrder]
this.messages = {}
await this.getMessages(this.selectedOrder)
this.startChat(this.selectedOrder)
}, },
startChat(room_name) { startChat(room_name) {
if (this.ws) {
this.ws.close()
}
if (location.protocol == 'https:') { if (location.protocol == 'https:') {
ws_scheme = 'wss://' ws_scheme = 'wss://'
} else { } else {
@ -268,33 +274,11 @@
} }
}, },
async created() { async created() {
this.stall = JSON.parse('{{ stall | tojson }}')
let order_details = JSON.parse('{{ order | tojson }}') let order_details = JSON.parse('{{ order | tojson }}')
let products = JSON.parse('{{ products | tojson }}') let products = JSON.parse('{{ products | tojson }}')
let order_id = '{{ order_id }}' let order_id = '{{ order_id }}'
let data = this.$q.localStorage.getItem(`lnbits.diagonalley.data`) this.stall = JSON.parse('{{ stall | tojson }}')
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, [])
}
//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 = []
}
this.order_details = order_details
this.products = order_details.map(o => { this.products = order_details.map(o => {
let product = products.find(p => p.id == o.product_id) let product = products.find(p => p.id == o.product_id)
return { return {
@ -305,14 +289,36 @@
} }
}) })
this.user.orders = [...new Set([...this.user.orders, 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.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.orders = {
[`${order_id}`]: this.products
}
//this.user.orders = []
}
//this.order_details = order_details
//this.user.orders = [...new Set([...this.user.orders, order_id])]
this.selectedOrder = order_id this.selectedOrder = order_id
await this.getMessages(order_id) await this.getMessages(order_id)
this.$q.localStorage.set(`lnbits.diagonalley.data`, this.user) this.$q.localStorage.set(`lnbits.diagonalley.data`, this.user)
this.startChat(order_id) this.startChat(order_id)
console.log(this.products) console.log(this.messages)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }

View file

@ -125,7 +125,7 @@
> >
</div> </div>
<div v-if="item.categories" class="text-subtitle1"> <div v-if="item.categories" class="text-subtitle1">
<q-chip v-for="cat in item.categories.split(',')" dense <q-chip v-for="(cat, i) in item.categories.split(',')" :key="i" dense
>{{cat}}</q-chip >{{cat}}</q-chip
> >
</div> </div>
@ -409,8 +409,18 @@
if (res.data.paid) { if (res.data.paid) {
this.$q.notify({ this.$q.notify({
type: 'positive', type: 'positive',
message: 'Sats received, thanks!', multiLine: true,
icon: 'thumb_up' 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) clearInterval(this.qrCodeDialog.paymentChecker)
this.resetCart() this.resetCart()

View file

@ -94,7 +94,9 @@ async def display(request: Request, market_id):
@diagonalley_ext.get("/order", response_class=HTMLResponse) @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) stall = await get_diagonalley_stall(merch)
order = await get_diagonalley_order_invoiceid(invoice_id) order = await get_diagonalley_order_invoiceid(invoice_id)
_order = await get_diagonalley_order_details(order.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, "publickey": stall.publickey,
"wallet": stall.wallet, "wallet": stall.wallet,
}, },
"order_id": order.id, "order_id": order.invoiceid,
"order": [details.dict() for details in _order], "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() 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}") @diagonalley_ext.websocket("/ws/{room_name}")
async def websocket_endpoint( async def websocket_endpoint(
websocket: WebSocket, room_name: str, background_tasks: BackgroundTasks websocket: WebSocket, room_name: str, background_tasks: BackgroundTasks
@ -143,7 +180,7 @@ async def websocket_endpoint(
if websocket not in room_members: if websocket not in room_members:
print("Sender not in room member: Reconnecting...") print("Sender not in room member: Reconnecting...")
await notifier.connect(websocket, room_name) await notifier.connect(websocket, room_name)
print("ENDPOINT", data)
await notifier._notify(data, room_name) await notifier._notify(data, room_name)
except WebSocketDisconnect: except WebSocketDisconnect:

View file

@ -1,10 +1,10 @@
from base64 import urlsafe_b64encode from base64 import urlsafe_b64encode
from http import HTTPStatus from http import HTTPStatus
from typing import List from typing import List, Union
from uuid import uuid4 from uuid import uuid4
from fastapi import Request from fastapi import Request
from fastapi.param_functions import Query from fastapi.param_functions import Body, Query
from fastapi.params import Depends from fastapi.params import Depends
from loguru import logger from loguru import logger
from secp256k1 import PrivateKey, PublicKey from secp256k1 import PrivateKey, PublicKey
@ -34,6 +34,7 @@ from .crud import (
delete_diagonalley_product, delete_diagonalley_product,
delete_diagonalley_stall, delete_diagonalley_stall,
delete_diagonalley_zone, delete_diagonalley_zone,
get_diagonalley_chat_by_merchant,
get_diagonalley_chat_messages, get_diagonalley_chat_messages,
get_diagonalley_latest_chat_messages, get_diagonalley_latest_chat_messages,
get_diagonalley_market, get_diagonalley_market,
@ -255,6 +256,14 @@ async def api_diagonalley_orders(
return {"message": "We could not retrieve the 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") @diagonalley_ext.post("/api/v1/orders")
async def api_diagonalley_order_create(data: createOrder): async def api_diagonalley_order_create(data: createOrder):
ref = urlsafe_short_hash() ref = urlsafe_short_hash()
@ -488,6 +497,16 @@ async def api_diagonalley_generate_keys():
## MESSAGES/CHAT ## 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}") @diagonalley_ext.get("/api/v1/chat/messages/{room_name}")
async def api_get_latest_chat_msg(room_name: str, all_messages: bool = Query(False)): async def api_get_latest_chat_msg(room_name: str, all_messages: bool = Query(False)):
if all_messages: if all_messages: