mirror of
https://github.com/lnbits/lnbits.git
synced 2025-06-26 08:41:04 +02:00
Merge remote-tracking branch 'origin/main' into main
This commit is contained in:
commit
72f2ec0be8
@ -84,18 +84,19 @@ def create_app(config_object="lnbits.settings") -> FastAPI:
|
||||
def check_funding_source(app: FastAPI) -> None:
|
||||
@app.on_event("startup")
|
||||
async def check_wallet_status():
|
||||
error_message, balance = await WALLET.status()
|
||||
if error_message:
|
||||
while True:
|
||||
error_message, balance = await WALLET.status()
|
||||
if not error_message:
|
||||
break
|
||||
warnings.warn(
|
||||
f" × The backend for {WALLET.__class__.__name__} isn't working properly: '{error_message}'",
|
||||
RuntimeWarning,
|
||||
)
|
||||
|
||||
sys.exit(4)
|
||||
else:
|
||||
print(
|
||||
f" ✔️ {WALLET.__class__.__name__} seems to be connected and with a balance of {balance} msat."
|
||||
)
|
||||
print("Retrying connection to backend in 5 seconds...")
|
||||
await asyncio.sleep(5)
|
||||
print(
|
||||
f" ✔️ {WALLET.__class__.__name__} seems to be connected and with a balance of {balance} msat."
|
||||
)
|
||||
|
||||
|
||||
def register_routes(app: FastAPI) -> None:
|
||||
|
@ -24,24 +24,24 @@ from lnbits.decorators import (
|
||||
WalletTypeInfo,
|
||||
get_key_type,
|
||||
)
|
||||
from lnbits.helpers import url_for
|
||||
from lnbits.helpers import url_for, urlsafe_short_hash
|
||||
from lnbits.requestvars import g
|
||||
from lnbits.settings import LNBITS_ADMIN_USERS, LNBITS_SITE_TITLE
|
||||
from lnbits.utils.exchange_rates import (
|
||||
currencies,
|
||||
fiat_amount_as_satoshis,
|
||||
satoshis_amount_as_fiat,
|
||||
)
|
||||
from lnbits.settings import LNBITS_SITE_TITLE
|
||||
|
||||
from .. import core_app, db
|
||||
from ..crud import (
|
||||
create_payment,
|
||||
get_payments,
|
||||
get_standalone_payment,
|
||||
save_balance_check,
|
||||
update_wallet,
|
||||
create_payment,
|
||||
get_wallet,
|
||||
save_balance_check,
|
||||
update_payment_status,
|
||||
update_wallet,
|
||||
)
|
||||
from ..services import (
|
||||
InvoiceFailure,
|
||||
@ -52,8 +52,6 @@ from ..services import (
|
||||
perform_lnurlauth,
|
||||
)
|
||||
from ..tasks import api_invoice_listeners
|
||||
from lnbits.settings import LNBITS_ADMIN_USERS
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
|
||||
@core_app.get("/api/v1/wallet")
|
||||
@ -503,12 +501,13 @@ async def api_lnurlscan(code: str):
|
||||
|
||||
@core_app.post("/api/v1/payments/decode")
|
||||
async def api_payments_decode(data: str = Query(None)):
|
||||
print(data)
|
||||
try:
|
||||
if data["data"][:5] == "LNURL":
|
||||
url = lnurl.decode(data["data"])
|
||||
if data[:5] == "LNURL":
|
||||
url = lnurl.decode(data)
|
||||
return {"domain": url}
|
||||
else:
|
||||
invoice = bolt11.decode(data["data"])
|
||||
invoice = bolt11.decode(data)
|
||||
return {
|
||||
"payment_hash": invoice.payment_hash,
|
||||
"amount_msat": invoice.amount_msat,
|
||||
|
@ -88,7 +88,7 @@ async def get_copilot(copilot_id: str) -> Copilots:
|
||||
|
||||
async def get_copilots(user: str) -> List[Copilots]:
|
||||
rows = await db.fetchall(
|
||||
"SELECT * FROM copilot.newer_copilots WHERE user = ?", (user,)
|
||||
'SELECT * FROM copilot.newer_copilots WHERE "user" = ?', (user,)
|
||||
)
|
||||
return [Copilots(**row) for row in rows]
|
||||
|
||||
|
@ -76,7 +76,7 @@ async def delete_ticket(payment_hash: str) -> None:
|
||||
|
||||
|
||||
async def delete_event_tickets(event_id: str) -> None:
|
||||
await db.execute("DELETE FROM events.tickets WHERE event = ?", (event_id,))
|
||||
await db.execute("DELETE FROM events.ticket WHERE event = ?", (event_id,))
|
||||
|
||||
|
||||
# EVENTS
|
||||
|
@ -12,7 +12,7 @@ async def create_jukebox(
|
||||
juke_id = urlsafe_short_hash()
|
||||
result = await db.execute(
|
||||
"""
|
||||
INSERT INTO jukebox.jukebox (id, user, title, wallet, sp_user, sp_secret, sp_access_token, sp_refresh_token, sp_device, sp_playlists, price, profit)
|
||||
INSERT INTO jukebox.jukebox (id, "user", title, wallet, sp_user, sp_secret, sp_access_token, sp_refresh_token, sp_device, sp_playlists, price, profit)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
@ -41,6 +41,7 @@ async def update_jukebox(
|
||||
q = ", ".join([f"{field[0]} = ?" for field in data])
|
||||
items = [f"{field[1]}" for field in data]
|
||||
items.append(juke_id)
|
||||
q = q.replace("user", '"user"', 1) # hack to make user be "user"!
|
||||
await db.execute(f"UPDATE jukebox.jukebox SET {q} WHERE id = ?", (items))
|
||||
row = await db.fetchone("SELECT * FROM jukebox.jukebox WHERE id = ?", (juke_id,))
|
||||
return Jukebox(**row) if row else None
|
||||
@ -57,11 +58,11 @@ async def get_jukebox_by_user(user: str) -> Optional[Jukebox]:
|
||||
|
||||
|
||||
async def get_jukeboxs(user: str) -> List[Jukebox]:
|
||||
rows = await db.fetchall("SELECT * FROM jukebox.jukebox WHERE user = ?", (user,))
|
||||
rows = await db.fetchall('SELECT * FROM jukebox.jukebox WHERE "user" = ?', (user,))
|
||||
for row in rows:
|
||||
if row.sp_playlists == None:
|
||||
await delete_jukebox(row.id)
|
||||
rows = await db.fetchall("SELECT * FROM jukebox.jukebox WHERE user = ?", (user,))
|
||||
rows = await db.fetchall('SELECT * FROM jukebox.jukebox WHERE "user" = ?', (user,))
|
||||
|
||||
return [Jukebox(**row) for row in rows]
|
||||
|
||||
|
@ -75,7 +75,6 @@ async def api_check_credentials_check(
|
||||
juke_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||
):
|
||||
jukebox = await get_jukebox(juke_id)
|
||||
|
||||
return jukebox
|
||||
|
||||
|
||||
@ -442,7 +441,7 @@ async def api_get_jukebox_currently(
|
||||
token = await api_get_token(juke_id)
|
||||
if token == False:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="INvoice not paid"
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="Invoice not paid"
|
||||
)
|
||||
elif retry:
|
||||
raise HTTPException(
|
||||
@ -456,5 +455,5 @@ async def api_get_jukebox_currently(
|
||||
)
|
||||
except:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong"
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong, or no song is playing yet"
|
||||
)
|
||||
|
@ -117,9 +117,10 @@
|
||||
{% raw %}
|
||||
<template v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
<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">
|
||||
{{ col.label }}
|
||||
{{ col.label }}
|
||||
</q-th>
|
||||
</q-tr>
|
||||
</template>
|
||||
@ -136,9 +137,19 @@
|
||||
:href="'mailto:' + props.row.email"
|
||||
></q-btn>
|
||||
</q-td>
|
||||
<q-td auto-width>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
size="xs"
|
||||
icon="launch"
|
||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
@click="ticketCard(props)"
|
||||
><q-tooltip> Click to show ticket </q-tooltip></q-btn>
|
||||
</q-td>
|
||||
|
||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ col.value }}
|
||||
{{ col.label == "Ticket" ? col.value.length > 20 ? `${col.value.substring(0, 20)}...` : col.value : col.value }}
|
||||
</q-td>
|
||||
|
||||
<q-td auto-width>
|
||||
@ -249,6 +260,29 @@
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
<!-- Read Ticket Dialog -->
|
||||
<q-dialog v-model="ticketDialog.show" position="top">
|
||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
{% raw %}
|
||||
<q-card-section>
|
||||
<h4 class="text-subtitle1 q-my-none">
|
||||
<i>{{this.ticketDialog.data.name}}</i> sent a ticket
|
||||
</h4>
|
||||
<div v-if="this.ticketDialog.data.email">
|
||||
<small>{{this.ticketDialog.data.email}}</small>
|
||||
</div>
|
||||
<small>{{this.ticketDialog.data.date}}</small>
|
||||
</q-card-section>
|
||||
<q-separator></q-separator>
|
||||
<q-card-section>
|
||||
<p>{{this.ticketDialog.data.content}}</p>
|
||||
</q-card-section>
|
||||
{% endraw %}
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="CLOSE" color="primary" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||
<script>
|
||||
@ -318,6 +352,10 @@
|
||||
formDialog: {
|
||||
show: false,
|
||||
data: {flatrate: false}
|
||||
},
|
||||
ticketDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -372,6 +410,16 @@
|
||||
})
|
||||
})
|
||||
},
|
||||
ticketCard(ticket){
|
||||
this.ticketDialog.show = true
|
||||
let {date, email, ltext, name} = ticket.row
|
||||
this.ticketDialog.data = {
|
||||
date,
|
||||
email,
|
||||
content: ltext,
|
||||
name
|
||||
}
|
||||
},
|
||||
exportticketsCSV: function () {
|
||||
LNbits.utils.exportCSV(this.ticketsTable.columns, this.tickets)
|
||||
},
|
||||
@ -421,12 +469,13 @@
|
||||
},
|
||||
updateformDialog: function (formId) {
|
||||
var link = _.findWhere(this.forms, {id: formId})
|
||||
console.log("LINK", link)
|
||||
|
||||
this.formDialog.data.id = link.id
|
||||
this.formDialog.data.wallet = link.wallet
|
||||
this.formDialog.data.name = link.name
|
||||
this.formDialog.data.description = link.description
|
||||
this.formDialog.data.flatrate = link.flatrate
|
||||
this.formDialog.data.flatrate = Boolean(link.flatrate)
|
||||
this.formDialog.data.amount = link.amount
|
||||
this.formDialog.show = true
|
||||
},
|
||||
|
@ -60,7 +60,7 @@ class Service(BaseModel):
|
||||
onchain: Optional[str]
|
||||
servicename: str # Currently, this will just always be "Streamlabs"
|
||||
authenticated: bool # Whether a token (see below) has been acquired yet
|
||||
token: Optional[int] # The token with which to authenticate requests
|
||||
token: Optional[str] # The token with which to authenticate requests
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, row: Row) -> "Service":
|
||||
|
@ -62,7 +62,7 @@
|
||||
donationDialog: {
|
||||
show: false,
|
||||
data: {
|
||||
name: '',
|
||||
name: null,
|
||||
sats: '',
|
||||
message: ''
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ from starlette.responses import RedirectResponse
|
||||
|
||||
from lnbits.core.crud import get_user
|
||||
from lnbits.decorators import WalletTypeInfo, get_key_type
|
||||
from lnbits.extensions.satspay.models import CreateCharge
|
||||
from lnbits.extensions.streamalerts.models import (
|
||||
CreateDonation,
|
||||
CreateService,
|
||||
@ -113,17 +114,18 @@ async def api_create_donation(data: CreateDonation, request: Request):
|
||||
service_id = data.service
|
||||
service = await get_service(service_id)
|
||||
charge_details = await get_charge_details(service.id)
|
||||
name = data.name
|
||||
name = data.name if data.name else "Anonymous"
|
||||
|
||||
description = f"{sats} sats donation from {name} to {service.twitchuser}"
|
||||
charge = await create_charge(
|
||||
create_charge_data = CreateCharge(
|
||||
amount=sats,
|
||||
completelink=f"https://twitch.tv/{service.twitchuser}",
|
||||
completelinktext="Back to Stream!",
|
||||
webhook=webhook_base + "/streamalerts/api/v1/postdonation",
|
||||
description=description,
|
||||
**charge_details,
|
||||
**charge_details
|
||||
)
|
||||
charge = await create_charge(user=charge_details["user"], data=create_charge_data)
|
||||
await create_donation(
|
||||
id=charge.id,
|
||||
wallet=service.wallet,
|
||||
|
@ -1,5 +1,5 @@
|
||||
from sqlite3 import Row
|
||||
from typing import NamedTuple, Optional
|
||||
from typing import Optional
|
||||
|
||||
from fastapi.param_functions import Query
|
||||
from pydantic import BaseModel
|
||||
@ -26,7 +26,7 @@ class createTip(BaseModel):
|
||||
message: str = ""
|
||||
|
||||
|
||||
class Tip(NamedTuple):
|
||||
class Tip(BaseModel):
|
||||
"""A Tip represents a single donation"""
|
||||
|
||||
id: str # This ID always corresponds to a satspay charge ID
|
||||
@ -55,7 +55,7 @@ class createTips(BaseModel):
|
||||
message: str
|
||||
|
||||
|
||||
class TipJar(NamedTuple):
|
||||
class TipJar(BaseModel):
|
||||
"""A TipJar represents a user's tip jar"""
|
||||
|
||||
id: int
|
||||
|
@ -112,7 +112,7 @@ async def api_get_addresses(wallet_id, w: WalletTypeInfo = Depends(get_key_type)
|
||||
async def api_update_mempool(
|
||||
endpoint: str = Query(...), w: WalletTypeInfo = Depends(require_admin_key)
|
||||
):
|
||||
mempool = await update_mempool(endpoint, user=w.wallet.user)
|
||||
mempool = await update_mempool(**{"endpoint": endpoint}, user=w.wallet.user)
|
||||
return mempool.dict()
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user