Skip to content

Commit 70ebb05

Browse files
committed
cleanup
1 parent cea0238 commit 70ebb05

10 files changed

Lines changed: 278 additions & 250 deletions

File tree

services.py

Lines changed: 131 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
import math
33
from datetime import datetime, timezone
44

5-
from lnbits.core.crud.wallets import get_wallets
6-
from lnbits.core.models import Payment
75
from lnbits.core.crud.users import get_user
86
from lnbits.core.crud.wallets import get_wallets
7+
from lnbits.core.models import Payment
98
from lnbits.core.services import create_invoice, pay_invoice, websocket_manager
109
from lnbits.core.services.notifications import send_notification
1110
from lnbits.helpers import urlsafe_short_hash
@@ -83,9 +82,7 @@ async def _broadcast_claim(chat_id: str, claimed_by_id: str | None, claimed_by_n
8382
await _broadcast_chat(chat_id, payload)
8483

8584

86-
async def _maybe_pay_claim_split(
87-
category: Categories, chat: ChatSession, amount: int
88-
) -> None:
85+
async def _maybe_pay_claim_split(category: Categories, chat: ChatSession, amount: int) -> None:
8986
if not chat.claimed_by_id:
9087
return
9188
split = float(category.claim_split or 0)
@@ -239,6 +236,103 @@ async def _calculate_amount(category: Categories, message: str) -> int:
239236
return math.ceil(raw_amount)
240237

241238

239+
async def _handle_lnurlp_drawdown(
240+
category: Categories,
241+
chat: ChatSession,
242+
amount: int,
243+
data: CreateChatMessage,
244+
sender_name: str,
245+
base_url: str | None,
246+
) -> ChatPaymentRequest:
247+
if chat.balance < amount:
248+
raise ValueError("Insufficient balance. Fund the chat to continue.")
249+
chat.balance = max(0, chat.balance - amount)
250+
await _maybe_pay_claim_split(category, chat, amount)
251+
message = ChatMessage(
252+
id=urlsafe_short_hash(),
253+
sender_id=data.sender_id,
254+
sender_name=sender_name,
255+
sender_role=data.sender_role,
256+
message=data.message,
257+
created_at=datetime.now(timezone.utc),
258+
amount=amount,
259+
message_type="message",
260+
)
261+
if not chat.messages:
262+
await _notify_new_chat(category, chat, base_url, data.message)
263+
await _append_message(chat, message, unread=True)
264+
await _broadcast_balance(chat.id, chat.balance)
265+
return ChatPaymentRequest(chat_id=chat.id, pending=False, message_id=message.id)
266+
267+
268+
async def _create_payg_payment_request(
269+
category: Categories,
270+
chat: ChatSession,
271+
amount: int,
272+
data: CreateChatMessage,
273+
sender_name: str,
274+
) -> ChatPaymentRequest:
275+
wallet_id = await _resolve_category_wallet(category)
276+
if not wallet_id:
277+
raise ValueError("Category wallet not configured.")
278+
payment = await create_invoice(
279+
wallet_id=wallet_id,
280+
amount=amount,
281+
memo=f"Chat message for {category.name}",
282+
extra={
283+
"tag": "chat",
284+
"chat_id": chat.id,
285+
"categories_id": chat.categories_id,
286+
"sender_id": data.sender_id,
287+
"sender_name": sender_name,
288+
"sender_role": data.sender_role,
289+
"message": data.message,
290+
"payment_type": "message",
291+
},
292+
)
293+
await create_chat_payment(
294+
ChatPayment(
295+
payment_hash=payment.payment_hash,
296+
chat_id=chat.id,
297+
categories_id=chat.categories_id,
298+
sender_id=data.sender_id,
299+
sender_name=sender_name,
300+
sender_role=data.sender_role,
301+
message=data.message,
302+
amount=amount,
303+
payment_type="message",
304+
)
305+
)
306+
return ChatPaymentRequest(
307+
chat_id=chat.id,
308+
payment_hash=payment.payment_hash,
309+
payment_request=payment.bolt11,
310+
amount=amount,
311+
pending=True,
312+
)
313+
314+
315+
async def _send_free_message(
316+
category: Categories,
317+
chat: ChatSession,
318+
data: CreateChatMessage,
319+
sender_name: str,
320+
base_url: str | None,
321+
) -> ChatPaymentRequest:
322+
message = ChatMessage(
323+
id=urlsafe_short_hash(),
324+
sender_id=data.sender_id,
325+
sender_name=sender_name,
326+
sender_role=data.sender_role,
327+
message=data.message,
328+
created_at=datetime.now(timezone.utc),
329+
)
330+
if not chat.messages:
331+
await _notify_new_chat(category, chat, base_url, data.message)
332+
await _append_message(chat, message, unread=True)
333+
return ChatPaymentRequest(chat_id=chat.id, pending=False, message_id=message.id)
334+
335+
242336
async def send_public_message(
243337
categories_id: str,
244338
chat_id: str,
@@ -267,78 +361,12 @@ async def send_public_message(
267361
amount = await _calculate_amount(category, data.message)
268362

269363
if category.paid and category.lnurlp and amount > 0 and not user_id:
270-
if chat.balance < amount:
271-
raise ValueError("Insufficient balance. Fund the chat to continue.")
272-
chat.balance = max(0, chat.balance - amount)
273-
await _maybe_pay_claim_split(category, chat, amount)
274-
message = ChatMessage(
275-
id=urlsafe_short_hash(),
276-
sender_id=data.sender_id,
277-
sender_name=sender_name,
278-
sender_role=data.sender_role,
279-
message=data.message,
280-
created_at=datetime.now(timezone.utc),
281-
amount=amount,
282-
message_type="message",
283-
)
284-
if not chat.messages:
285-
await _notify_new_chat(category, chat, base_url, data.message)
286-
await _append_message(chat, message, unread=True)
287-
await _broadcast_balance(chat.id, chat.balance)
288-
return ChatPaymentRequest(chat_id=chat.id, pending=False, message_id=message.id)
364+
return await _handle_lnurlp_drawdown(category, chat, amount, data, sender_name, base_url)
289365

290366
if category.paid and amount > 0 and not user_id:
291-
wallet_id = await _resolve_category_wallet(category)
292-
if not wallet_id:
293-
raise ValueError("Category wallet not configured.")
294-
payment = await create_invoice(
295-
wallet_id=wallet_id,
296-
amount=amount,
297-
memo=f"Chat message for {category.name}",
298-
extra={
299-
"tag": "chat",
300-
"chat_id": chat.id,
301-
"categories_id": categories_id,
302-
"sender_id": data.sender_id,
303-
"sender_name": sender_name,
304-
"sender_role": data.sender_role,
305-
"message": data.message,
306-
"payment_type": "message",
307-
},
308-
)
309-
await create_chat_payment(
310-
ChatPayment(
311-
payment_hash=payment.payment_hash,
312-
chat_id=chat.id,
313-
categories_id=categories_id,
314-
sender_id=data.sender_id,
315-
sender_name=sender_name,
316-
sender_role=data.sender_role,
317-
message=data.message,
318-
amount=amount,
319-
payment_type="message",
320-
)
321-
)
322-
return ChatPaymentRequest(
323-
chat_id=chat.id,
324-
payment_hash=payment.payment_hash,
325-
payment_request=payment.bolt11,
326-
amount=amount,
327-
pending=True,
328-
)
367+
return await _create_payg_payment_request(category, chat, amount, data, sender_name)
329368

330-
message = ChatMessage(
331-
id=urlsafe_short_hash(),
332-
sender_id=data.sender_id,
333-
sender_name=sender_name,
334-
sender_role=data.sender_role,
335-
message=data.message,
336-
created_at=datetime.now(timezone.utc),
337-
)
338-
if not chat.messages:
339-
await _notify_new_chat(category, chat, base_url, data.message)
340-
await _append_message(chat, message, unread=True)
341-
return ChatPaymentRequest(chat_id=chat.id, pending=False, message_id=message.id)
369+
return await _send_free_message(category, chat, data, sender_name, base_url)
342370

343371

344372
async def send_admin_message(
@@ -439,30 +467,22 @@ async def request_tip(
439467
)
440468

441469

442-
async def payment_received_for_client_data(payment: Payment) -> bool:
443-
if payment.extra.get("tag") != "chat":
470+
async def _apply_balance_payment(chat_id: str | None, amount_sat: int) -> bool:
471+
if not chat_id:
472+
logger.warning("Chat balance payment missing chat_id.")
444473
return False
445-
446-
if payment.extra.get("payment_type") == "balance":
447-
chat_id = payment.extra.get("chat_id")
448-
if not chat_id:
449-
logger.warning("Chat balance payment missing chat_id.")
450-
return False
451-
chat = await get_chat(chat_id)
452-
if not chat:
453-
logger.warning("Chat not found for balance payment.")
454-
return False
455-
chat.balance = max(0, chat.balance + payment.sat)
456-
chat.updated_at = datetime.now(timezone.utc)
457-
await update_chat(chat)
458-
await _broadcast_balance(chat.id, chat.balance)
459-
return True
460-
461-
chat_payment = await get_chat_payment(payment.payment_hash)
462-
if not chat_payment:
463-
logger.warning("Chat payment not found.")
474+
chat = await get_chat(chat_id)
475+
if not chat:
476+
logger.warning("Chat not found for balance payment.")
464477
return False
478+
chat.balance = max(0, chat.balance + amount_sat)
479+
chat.updated_at = datetime.now(timezone.utc)
480+
await update_chat(chat)
481+
await _broadcast_balance(chat.id, chat.balance)
482+
return True
483+
465484

485+
async def _finalize_chat_payment(chat_payment: ChatPayment) -> bool:
466486
if chat_payment.paid:
467487
return True
468488

@@ -496,14 +516,29 @@ async def payment_received_for_client_data(payment: Payment) -> bool:
496516
amount=chat_payment.amount,
497517
message_type=message_type,
498518
)
499-
if not chat.messages or len(chat.messages) == 0:
519+
if not chat.messages:
500520
category = await get_categories_by_id(chat.categories_id)
501521
if category:
502522
await _notify_new_chat(category, chat, None, chat_payment.message)
503523
await _append_message(chat, message, unread=True)
504524
return True
505525

506526

527+
async def payment_received_for_client_data(payment: Payment) -> bool:
528+
if payment.extra.get("tag") != "chat":
529+
return False
530+
531+
if payment.extra.get("payment_type") == "balance":
532+
return await _apply_balance_payment(payment.extra.get("chat_id"), payment.sat)
533+
534+
chat_payment = await get_chat_payment(payment.payment_hash)
535+
if not chat_payment:
536+
logger.warning("Chat payment not found.")
537+
return False
538+
539+
return await _finalize_chat_payment(chat_payment)
540+
541+
507542
async def toggle_chat_claim(chat_id: str, user_id: str) -> ChatSession:
508543
chat = await get_chat(chat_id)
509544
if not chat:

static/embed.js

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,34 @@ window.PageChatEmbed = {
178178
}
179179
},
180180

181+
async refreshBalance() {
182+
if (!this.chatId) return
183+
try {
184+
const {data} = await LNbits.api.request(
185+
'GET',
186+
`/chat/api/v1/chats/${this.categoriesId}/${this.chatId}/public`
187+
)
188+
if (data && typeof data.balance !== 'undefined') {
189+
this.applyBalanceUpdate(data.balance)
190+
}
191+
} catch (error) {
192+
console.warn(error)
193+
}
194+
},
195+
196+
applyBalanceUpdate(nextBalance) {
197+
const next = nextBalance || 0
198+
const prev = this.chatData.balance || 0
199+
this.chatData.balance = next
200+
if (this.lnurlDialog && next > prev) {
201+
this.lnurlDialog = false
202+
Quasar.Notify.create({
203+
type: 'positive',
204+
message: 'Balance funded'
205+
})
206+
}
207+
},
208+
181209
async openLnurlDialog() {
182210
if (!this.lnurlPay) {
183211
await this.fetchLnurl()
@@ -367,16 +395,7 @@ window.PageChatEmbed = {
367395
this.chatData.resolved = payload.resolved
368396
}
369397
if (payload.type === 'balance') {
370-
const nextBalance = payload.balance || 0
371-
const prevBalance = this.chatData.balance || 0
372-
this.chatData.balance = nextBalance
373-
if (this.lnurlDialog && nextBalance > prevBalance) {
374-
this.lnurlDialog = false
375-
Quasar.Notify.create({
376-
type: 'positive',
377-
message: 'Balance funded'
378-
})
379-
}
398+
this.applyBalanceUpdate(payload.balance)
380399
}
381400
if (payload.type === 'claim') {
382401
this.chatData.claimed_by_id = payload.claimed_by_id
@@ -398,20 +417,14 @@ window.PageChatEmbed = {
398417
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'
399418
url.pathname = `/api/v1/ws/chatbalance:${this.chatId}`
400419
const ws = new WebSocket(url)
420+
ws.addEventListener('open', () => {
421+
this.refreshBalance()
422+
})
401423
ws.addEventListener('message', ({data}) => {
402424
try {
403425
const payload = JSON.parse(data)
404426
if (payload.type === 'balance') {
405-
const nextBalance = payload.balance || 0
406-
const prevBalance = this.chatData.balance || 0
407-
this.chatData.balance = nextBalance
408-
if (this.lnurlDialog && nextBalance > prevBalance) {
409-
this.lnurlDialog = false
410-
Quasar.Notify.create({
411-
type: 'positive',
412-
message: 'Balance funded'
413-
})
414-
}
427+
this.applyBalanceUpdate(payload.balance)
415428
}
416429
} catch (err) {
417430
console.warn('Balance websocket message failed', err)

static/embed.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,10 @@
194194
</q-card-section>
195195
<q-card-section class="q-pa-none q-mb-md">
196196
<div class="chat-lnurl-no-buttons">
197-
<lnbits-qrcode-lnurl :url="lnurlPay" :nfc="true"></lnbits-qrcode-lnurl>
197+
<lnbits-qrcode-lnurl
198+
:url="lnurlPay"
199+
:nfc="true"
200+
></lnbits-qrcode-lnurl>
198201
</div>
199202
</q-card-section>
200203
<q-card-section class="row items-center">

static/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ window.PageChat = {
9191
chatSocket: null,
9292
messageInput: '',
9393
sending: false,
94-
adminParticipantId: '',
9594
poller: null,
9695
autoScroll: true,
9796
embedDialog: {
@@ -155,8 +154,7 @@ window.PageChat = {
155154
this.autoScroll = true
156155
return
157156
}
158-
this.autoScroll =
159-
el.scrollTop + el.clientHeight >= el.scrollHeight - 8
157+
this.autoScroll = el.scrollTop + el.clientHeight >= el.scrollHeight - 8
160158
},
161159

162160
async scrollToBottomSmooth() {
@@ -504,7 +502,6 @@ window.PageChat = {
504502
}
505503
},
506504
async created() {
507-
this.adminParticipantId = `admin-${this.g.user.id}`
508505
await this.fetchCurrencies()
509506
await this.getCategories()
510507
await this.getChats()

0 commit comments

Comments
 (0)