make format && generate keys with schnorr

This commit is contained in:
Tiago Vasconcelos 2022-12-20 16:11:56 +00:00
parent 9b69851155
commit 70a051a413
7 changed files with 105 additions and 159 deletions

View file

@ -59,17 +59,13 @@ async def update_shop_product(product_id: str, **kwargs) -> Optional[Stalls]:
f"UPDATE shop.products SET {q} WHERE id = ?", f"UPDATE shop.products SET {q} WHERE id = ?",
(*kwargs.values(), product_id), (*kwargs.values(), product_id),
) )
row = await db.fetchone( row = await db.fetchone("SELECT * FROM shop.products WHERE id = ?", (product_id,))
"SELECT * FROM shop.products WHERE id = ?", (product_id,)
)
return Products(**row) if row else None return Products(**row) if row else None
async def get_shop_product(product_id: str) -> Optional[Products]: async def get_shop_product(product_id: str) -> Optional[Products]:
row = await db.fetchone( row = await db.fetchone("SELECT * FROM shop.products WHERE id = ?", (product_id,))
"SELECT * FROM shop.products WHERE id = ?", (product_id,)
)
return Products(**row) if row else None return Products(**row) if row else None
@ -132,9 +128,7 @@ async def get_shop_zone(zone_id: str) -> Optional[Zones]:
async def get_shop_zones(user: str) -> List[Zones]: async def get_shop_zones(user: str) -> List[Zones]:
rows = await db.fetchall( rows = await db.fetchall('SELECT * FROM shop.zones WHERE "user" = ?', (user,))
'SELECT * FROM shop.zones WHERE "user" = ?', (user,)
)
return [Zones(**row) for row in rows] return [Zones(**row) for row in rows]
@ -182,16 +176,12 @@ async def update_shop_stall(stall_id: str, **kwargs) -> Optional[Stalls]:
f"UPDATE shop.stalls SET {q} WHERE id = ?", f"UPDATE shop.stalls SET {q} WHERE id = ?",
(*kwargs.values(), stall_id), (*kwargs.values(), stall_id),
) )
row = await db.fetchone( row = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,))
"SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)
)
return Stalls(**row) if row else None return Stalls(**row) if row else None
async def get_shop_stall(stall_id: str) -> Optional[Stalls]: async def get_shop_stall(stall_id: str) -> Optional[Stalls]:
row = await db.fetchone( row = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,))
"SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)
)
return Stalls(**row) if row else None return Stalls(**row) if row else None
@ -203,9 +193,7 @@ async def get_shop_stalls(wallet_ids: Union[str, List[str]]) -> List[Stalls]:
return [Stalls(**row) for row in rows] return [Stalls(**row) for row in rows]
async def get_shop_stalls_by_ids( async def get_shop_stalls_by_ids(stall_ids: Union[str, List[str]]) -> List[Stalls]:
stall_ids: Union[str, List[str]]
) -> List[Stalls]:
q = ",".join(["?"] * len(stall_ids)) q = ",".join(["?"] * len(stall_ids))
rows = await db.fetchall( rows = await db.fetchall(
f"SELECT * FROM shop.stalls WHERE id IN ({q})", (*stall_ids,) f"SELECT * FROM shop.stalls WHERE id IN ({q})", (*stall_ids,)
@ -250,9 +238,7 @@ async def create_shop_order(data: createOrder, invoiceid: str) -> Orders:
# return link # return link
async def create_shop_order_details( async def create_shop_order_details(order_id: str, data: List[createOrderDetails]):
order_id: str, data: List[createOrderDetails]
):
for item in data: for item in data:
item_id = urlsafe_short_hash() item_id = urlsafe_short_hash()
await db.execute( await db.execute(
@ -280,9 +266,7 @@ async def get_shop_order_details(order_id: str) -> List[OrderDetail]:
async def get_shop_order(order_id: str) -> Optional[Orders]: async def get_shop_order(order_id: str) -> Optional[Orders]:
row = await db.fetchone( row = await db.fetchone("SELECT * FROM shop.orders WHERE id = ?", (order_id,))
"SELECT * FROM shop.orders WHERE id = ?", (order_id,)
)
return Orders(**row) if row else None return Orders(**row) if row else None
@ -362,9 +346,7 @@ async def get_shop_markets(user: str) -> List[Market]:
async def get_shop_market(market_id: str) -> Optional[Market]: async def get_shop_market(market_id: str) -> Optional[Market]:
row = await db.fetchone( row = await db.fetchone("SELECT * FROM shop.markets WHERE id = ?", (market_id,))
"SELECT * FROM shop.markets WHERE id = ?", (market_id,)
)
return Market(**row) if row else None return Market(**row) if row else None
@ -397,9 +379,7 @@ async def create_shop_market(data: CreateMarket):
return market return market
async def create_shop_market_stalls( async def create_shop_market_stalls(market_id: str, data: List[CreateMarketStalls]):
market_id: str, data: List[CreateMarketStalls]
):
for stallid in data: for stallid in data:
id = urlsafe_short_hash() id = urlsafe_short_hash()

View file

@ -14,17 +14,18 @@
<li>Create Shipping Zones you're willing to ship to</li> <li>Create Shipping Zones you're willing to ship to</li>
<li>Create a Stall to list yiur products on</li> <li>Create a Stall to list yiur products on</li>
<li>Create products to put on the Stall</li> <li>Create products to put on the Stall</li>
<li> <li>Take orders</li>
Take orders <li>Includes chat support!</li>
</li>
<li>
Includes chat support!
</li>
</ol> </ol>
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 routed through Nostr relays. 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
routed through Nostr relays.
<br /> <br />
<small> <small>
Created by, <a href="https://github.com/talvasconcelos">Tal Vasconcelos</a>, <a href="https://github.com/benarc">Ben Arc</a></small Created by,
<a href="https://github.com/talvasconcelos">Tal Vasconcelos</a>,
<a href="https://github.com/benarc">Ben Arc</a></small
> >
<!-- </p> --> <!-- </p> -->
</q-card-section> </q-card-section>

View file

@ -261,7 +261,6 @@
label="Public Key" label="Public Key"
></q-input> ></q-input>
<q-input <q-input
v-if="diagonalley" v-if="diagonalley"
v-if="keys" v-if="keys"
filled filled
@ -300,7 +299,7 @@
label="Relays" label="Relays"
></q-select> ></q-select>
<q-input <q-input
v-if="diagonalley" v-if="diagonalley"
filled filled
dense dense
v-model.trim="stallDialog.data.crelays" v-model.trim="stallDialog.data.crelays"
@ -399,9 +398,7 @@
<q-separator inset></q-separator> <q-separator inset></q-separator>
<q-card-section> <q-card-section>
<div class="text-h6">Shop</div> <div class="text-h6">Shop</div>
<div class="text-subtitle2"> <div class="text-subtitle2">Make a shop of multiple stalls.</div>
Make a shop of multiple stalls.
</div>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
@ -929,7 +926,7 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
<!-- CHAT BOX --> <!-- CHAT BOX -->
<q-card style="max-height: 600px"> <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>
@ -946,45 +943,45 @@
></q-select> ></q-select>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
<div class="chat-container q-pa-md" ref="chatCard"> <div class="chat-container" ref="chatCard">
<div class="chat-box"> <div class="chat-box">
<!-- <p v-if="Object.keys(messages).length === 0">No messages yet</p> --> <!-- <p v-if="Object.keys(messages).length === 0">No messages yet</p> -->
<div class="chat-messages"> <div class="chat-messages">
<q-chat-message <q-chat-message
:key="index" :key="index"
v-for="(message, index) in orderMessages" v-for="(message, index) in orderMessages"
:name="message.pubkey == keys.pubkey ? 'me' : 'customer'" :name="message.pubkey == keys.pubkey ? 'me' : 'customer'"
:text="[message.msg]" :text="[message.msg]"
:sent="message.pubkey == keys.pubkey ? true : false" :sent="message.pubkey == keys.pubkey ? true : false"
:bg-color="message.pubkey == keys.pubkey ? 'white' : 'light-green-2'" :bg-color="message.pubkey == keys.pubkey ? 'white' : 'light-green-2'"
/>
</div>
</div>
<q-card-section>
<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> </div>
</q-input> </div>
</q-form> <q-card-section>
<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>
</q-card-section>
</div>
</q-card-section> </q-card-section>
</div>
</q-card-section>
</q-card> </q-card>
<!-- <q-card> <!-- <q-card>
<q-card-section> <q-card-section>
@ -1112,12 +1109,15 @@
</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>
<script src="https://github.com/paulmillr/noble-secp256k1/releases/download/1.7.0/noble-secp256k1.js"></script>
<script> <script>
Vue.component(VueQrcode.name, VueQrcode) Vue.component(VueQrcode.name, VueQrcode)
const pica = window.pica() const pica = window.pica()
const secp = window.nobleSecp256k1
function imgSizeFit(img, maxWidth = 1024, maxHeight = 768) { function imgSizeFit(img, maxWidth = 1024, maxHeight = 768) {
let ratio = Math.min( let ratio = Math.min(
@ -1504,31 +1504,17 @@
window.URL.revokeObjectURL(url) window.URL.revokeObjectURL(url)
}, },
generateKeys() { generateKeys() {
LNbits.api const privkey = secp.utils.bytesToHex(secp.utils.randomPrivateKey())
.request( const pubkey = secp.utils.bytesToHex(secp.schnorr.getPublicKey(privKey))
'GET',
'/shop/api/v1/keys', this.keys = {privKey, pubKey}
this.g.user.wallets[0].adminkey this.stallDialog.data.publickey = this.keys.pubkey
) this.stallDialog.data.privatekey = this.keys.privkey
.then(response => { this.$q.localStorage.set(`lnbits.shop.${this.g.user.id}`, this.keys)
if (response.data) { console.log({privKey, pubKey})
this.keys = response.data
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
)
}
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
}, },
restoreKeys() { restoreKeys() {
let keys = this.$q.localStorage.getItem( let keys = this.$q.localStorage.getItem(`lnbits.shop.${this.g.user.id}`)
`lnbits.shop.${this.g.user.id}`
)
if (keys) { if (keys) {
this.keys = keys this.keys = keys
this.stallDialog.data.publickey = this.keys.pubkey this.stallDialog.data.publickey = this.keys.pubkey
@ -1858,11 +1844,7 @@
var self = this var self = this
LNbits.api LNbits.api
.request( .request('GET', '/shop/api/v1/zones', this.g.user.wallets[0].inkey)
'GET',
'/shop/api/v1/zones',
this.g.user.wallets[0].inkey
)
.then(function (response) { .then(function (response) {
if (response.data) { if (response.data) {
self.zones = response.data.map(mapZone) self.zones = response.data.map(mapZone)
@ -1967,11 +1949,7 @@
//////////////////////////////////////// ////////////////////////////////////////
getMarkets() { getMarkets() {
LNbits.api LNbits.api
.request( .request('GET', '/shop/api/v1/markets', this.g.user.wallets[0].inkey)
'GET',
'/shop/api/v1/markets',
this.g.user.wallets[0].inkey
)
.then(response => { .then(response => {
if (response.data) { if (response.data) {
this.markets = response.data.map(mapMarkets) this.markets = response.data.map(mapMarkets)
@ -2171,17 +2149,17 @@
this.g.user.wallets[0].adminkey this.g.user.wallets[0].adminkey
) )
.then(res => { .then(res => {
if (!res.data?.length) return
this.messages = _.groupBy(res.data, 'id_conversation') this.messages = _.groupBy(res.data, 'id_conversation')
this.checkUnreadMessages() this.checkUnreadMessages()
}) })
.catch(error => { .catch(error => {
console.error(error)
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}, },
updateLastSeenMsg(id) { updateLastSeenMsg(id) {
let data = this.$q.localStorage.getItem( let data = this.$q.localStorage.getItem(`lnbits.shop.${this.g.user.id}`)
`lnbits.shop.${this.g.user.id}`
)
let chat = { let chat = {
...data.chat, ...data.chat,
[`${id}`]: { [`${id}`]: {
@ -2256,9 +2234,7 @@
} else { } else {
ws_scheme = 'ws://' ws_scheme = 'ws://'
} }
ws = new WebSocket( ws = new WebSocket(ws_scheme + location.host + '/shop/ws/' + room_name)
ws_scheme + location.host + '/shop/ws/' + room_name
)
function checkWebSocket(event) { function checkWebSocket(event) {
if (ws.readyState === WebSocket.CLOSED) { if (ws.readyState === WebSocket.CLOSED) {
@ -2296,9 +2272,7 @@
await this.getOrders() await this.getOrders()
this.getMarkets() this.getMarkets()
await this.getAllMessages() await this.getAllMessages()
let keys = this.$q.localStorage.getItem( let keys = this.$q.localStorage.getItem(`lnbits.shop.${this.g.user.id}`)
`lnbits.shop.${this.g.user.id}`
)
if (keys) { if (keys) {
this.keys = keys this.keys = keys
} }
@ -2319,7 +2293,8 @@
position: relative; position: relative;
display: grid; display: grid;
grid-template-rows: 1fr auto; grid-template-rows: 1fr auto;
height: calc(100vh - 140px); /*height: calc(100vh - 200px);*/
height: 50vh;
} }
.chat-box { .chat-box {
@ -2327,6 +2302,7 @@
flex-direction: column-reverse; flex-direction: column-reverse;
padding: 1rem; padding: 1rem;
overflow-y: auto; overflow-y: auto;
margin-left: auto;
} }
.chat-messages { .chat-messages {

View file

@ -2,7 +2,7 @@
<div class="row q-col-gutter-md flex"> <div class="row q-col-gutter-md flex">
<div class="col-12 col-md-7 col-lg-6 q-gutter-y-md"> <div class="col-12 col-md-7 col-lg-6 q-gutter-y-md">
<q-card> <q-card>
<div class="chat-container q-pa-md"> <div class="chat-container">
<div class="chat-box"> <div class="chat-box">
<!-- <p v-if="Object.keys(messages).length === 0">No messages yet</p> --> <!-- <p v-if="Object.keys(messages).length === 0">No messages yet</p> -->
<div class="chat-messages"> <div class="chat-messages">
@ -102,7 +102,11 @@
<q-card-section> <q-card-section>
<q-separator></q-separator> <q-separator></q-separator>
<q-list> <q-list>
<q-expansion-item v-if="diagonalley" group="extras" icon="vpn_key" label="Keys" <q-expansion-item
v-if="diagonalley"
group="extras"
icon="vpn_key"
label="Keys"
><p> ><p>
Bellow are the keys needed to contact the merchant. They are Bellow are the keys needed to contact the merchant. They are
stored in the browser! stored in the browser!
@ -197,7 +201,7 @@
</div> </div>
<!-- RESTORE KEYS DIALOG --> <!-- RESTORE KEYS DIALOG -->
<q-dialog <q-dialog
v-if="diagonalley" v-if="diagonalley"
v-model="keysDialog.show" v-model="keysDialog.show"
position="top" position="top"
@hide="clearRestoreKeyDialog" @hide="clearRestoreKeyDialog"
@ -398,9 +402,7 @@
} else { } else {
ws_scheme = 'ws://' ws_scheme = 'ws://'
} }
ws = new WebSocket( ws = new WebSocket(ws_scheme + location.host + '/shop/ws/' + room_name)
ws_scheme + location.host + '/shop/ws/' + room_name
)
function checkWebSocket(event) { function checkWebSocket(event) {
if (ws.readyState === WebSocket.CLOSED) { if (ws.readyState === WebSocket.CLOSED) {
@ -448,8 +450,7 @@
} }
}) })
let data = let data = this.$q.localStorage.getItem(`lnbits.shop.data`) || false
this.$q.localStorage.getItem(`lnbits.shop.data`) || false
if (data) { if (data) {
this.user = data this.user = data
@ -486,7 +487,8 @@
position: relative; position: relative;
display: grid; display: grid;
grid-template-rows: 1fr auto; grid-template-rows: 1fr auto;
height: calc(100vh - 133px); /*height: calc(100vh - 200px);*/
height: 50vh;
} }
.chat-box { .chat-box {
@ -494,6 +496,7 @@
flex-direction: column-reverse; flex-direction: column-reverse;
padding: 1rem; padding: 1rem;
overflow-y: auto; overflow-y: auto;
margin-left: auto;
} }
.chat-messages { .chat-messages {

View file

@ -280,7 +280,7 @@
stall: null, stall: null,
products: [], products: [],
searchText: null, searchText: null,
diagonalley:false, diagonalley: false,
cart: { cart: {
total: 0, total: 0,
size: 0, size: 0,

View file

@ -78,9 +78,7 @@ async def display(request: Request, market_id):
stalls = await get_shop_market_stalls(market_id) stalls = await get_shop_market_stalls(market_id)
stalls_ids = [stall.id for stall in stalls] stalls_ids = [stall.id for stall in stalls]
products = [ products = [product.dict() for product in await get_shop_products(stalls_ids)]
product.dict() for product in await get_shop_products(stalls_ids)
]
return shop_renderer().TemplateResponse( return shop_renderer().TemplateResponse(
"shop/market.html", "shop/market.html",

View file

@ -346,9 +346,7 @@ async def api_shop_order_shipped(
order_id, order_id,
), ),
) )
order = await db.fetchone( order = await db.fetchone("SELECT * FROM shop.orders WHERE id = ?", (order_id,))
"SELECT * FROM shop.orders WHERE id = ?", (order_id,)
)
return order return order
@ -361,15 +359,11 @@ async def api_shop_stall_products(
stall_id, wallet: WalletTypeInfo = Depends(get_key_type) stall_id, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
rows = await db.fetchone( rows = await db.fetchone("SELECT * FROM shop.stalls WHERE id = ?", (stall_id,))
"SELECT * FROM shop.stalls WHERE id = ?", (stall_id,)
)
if not rows: if not rows:
return {"message": "Stall does not exist."} return {"message": "Stall does not exist."}
products = db.fetchone( products = db.fetchone("SELECT * FROM shop.products WHERE wallet = ?", (rows[1],))
"SELECT * FROM shop.products WHERE wallet = ?", (rows[1],)
)
if not products: if not products:
return {"message": "No products"} return {"message": "No products"}
@ -441,10 +435,7 @@ async def api_shop_stall_checkshipped(
async def api_shop_markets(wallet: WalletTypeInfo = Depends(get_key_type)): async def api_shop_markets(wallet: WalletTypeInfo = Depends(get_key_type)):
# await get_shop_market_stalls(market_id="FzpWnMyHQMcRppiGVua4eY") # await get_shop_market_stalls(market_id="FzpWnMyHQMcRppiGVua4eY")
try: try:
return [ return [market.dict() for market in await get_shop_markets(wallet.wallet.user)]
market.dict()
for market in await get_shop_markets(wallet.wallet.user)
]
except: except:
return {"message": "We could not retrieve the markets."} return {"message": "We could not retrieve the markets."}
@ -498,10 +489,7 @@ async def api_shop_generate_keys():
async def api_get_merchant_messages( async def api_get_merchant_messages(
orders: str = Query(...), wallet: WalletTypeInfo = Depends(require_admin_key) 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_shop_chat_by_merchant(orders.split(","))
]
@shop_ext.get("/api/v1/chat/messages/{room_name}") @shop_ext.get("/api/v1/chat/messages/{room_name}")