diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py
index 2dc144f8c..cc937b5e9 100644
--- a/lnbits/extensions/admin/crud.py
+++ b/lnbits/extensions/admin/crud.py
@@ -2,10 +2,11 @@ from typing import List
from lnbits.core.crud import create_payment
from lnbits.helpers import urlsafe_short_hash
-from lnbits.settings import Settings
+from lnbits.settings import Settings, read_only_variables
from lnbits.tasks import internal_invoice_queue
from . import db
+from .models import UpdateSettings
async def update_wallet_balance(wallet_id: str, amount: int) -> str:
@@ -25,10 +26,28 @@ async def update_wallet_balance(wallet_id: str, amount: int) -> str:
await internal_invoice_queue.put(internal_id)
-async def update_settings(user: str, **kwargs) -> Settings:
- q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
- # print("UPDATE", q)
- await db.execute(f'UPDATE admin.settings SET {q}')
- row = await db.fetchone('SELECT * FROM admin.settings')
+async def update_settings(data: UpdateSettings) -> Settings:
+ fields = []
+ for key, value in data.dict(exclude_none=True).items():
+ if not key in read_only_variables:
+ if type(value) == list:
+ joined = ",".join(value)
+ fields.append(f"{key} = '{joined}'")
+ if type(value) == int or type(value) == float:
+ fields.append(f"{key} = {value}")
+ if type(value) == bool:
+ fields.append(f"{key} = {'true' if value else 'false'}")
+ if type(value) == str:
+ value = value.replace("'", "")
+ fields.append(f"{key} = '{value}'")
+
+ q = ", ".join(fields)
+ print("UPDATE", q)
+ await db.execute(f"UPDATE admin.settings SET {q}")
+ row = await db.fetchone("SELECT * FROM admin.settings")
assert row, "Newly updated settings couldn't be retrieved"
return Settings(**row) if row else None
+
+
+async def delete_settings():
+ await db.execute("DELETE FROM admin.settings")
diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py
index 2110f7f20..13a6cd233 100644
--- a/lnbits/extensions/admin/models.py
+++ b/lnbits/extensions/admin/models.py
@@ -1,10 +1,9 @@
-from sqlite3 import Row
-from typing import List, Optional
-
from fastapi import Query
-from pydantic import BaseModel, Field
+from pydantic import BaseModel
+
class UpdateSettings(BaseModel):
+ lnbits_backend_wallet_class: str = Query(None)
lnbits_admin_users: str = Query(None)
lnbits_allowed_users: str = Query(None)
lnbits_admin_ext: str = Query(None)
@@ -15,11 +14,11 @@ class UpdateSettings(BaseModel):
lnbits_reserve_fee_percent: float = Query(None, ge=0)
lnbits_service_fee: float = Query(None, ge=0)
lnbits_hide_api: bool = Query(None)
- lnbits_site_title: str = Query("LNbits")
- lnbits_site_tagline: str = Query("free and open-source lightning wallet")
+ lnbits_site_title: str = Query(None)
+ lnbits_site_tagline: str = Query(None)
lnbits_site_description: str = Query(None)
- lnbits_default_wallet_name: str = Query("LNbits wallet")
- lnbits_denomination: str = Query("sats")
+ lnbits_default_wallet_name: str = Query(None)
+ lnbits_denomination: str = Query(None)
lnbits_theme: str = Query(None)
lnbits_custom_logo: str = Query(None)
lnbits_ad_space: str = Query(None)
diff --git a/lnbits/extensions/admin/templates/admin/_tab_funding.html b/lnbits/extensions/admin/templates/admin/_tab_funding.html
index 715f0e099..503f2adcd 100644
--- a/lnbits/extensions/admin/templates/admin/_tab_funding.html
+++ b/lnbits/extensions/admin/templates/admin/_tab_funding.html
@@ -24,6 +24,7 @@
Active Funding (Requires server restart)
@@ -46,6 +48,7 @@
dense
type="number"
filled
+ name="lnbits_reserve_fee_percent"
v-model="data.settings.lnbits_reserve_fee_percent"
label="Reserve fee in percent"
step="0.1"
diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html
index 50e05413a..f1ead27b0 100644
--- a/lnbits/extensions/admin/templates/admin/index.html
+++ b/lnbits/extensions/admin/templates/admin/index.html
@@ -4,8 +4,12 @@
-
-
+
+
@@ -37,7 +41,7 @@
-
+
{% include "admin/_tab_funding.html" %} {% include
"admin/_tab_users.html" %} {% include "admin/_tab_server.html" %} {%
@@ -111,8 +115,7 @@
LNbits.api
.request(
'GET',
- '/admin/api/v1/admin/restart/',
- this.g.user.wallets[0].adminkey
+ '/admin/api/v1/restart/?usr=' + this.g.user.id,
)
.then(response => {
this.$q.notify({
@@ -129,8 +132,7 @@
LNbits.api
.request(
'POST',
- '/admin/api/v1/admin/topup/',
- this.g.user.wallets[0].adminkey,
+ '/admin/api/v1/topup/?usr=' + this.g.user.id,
this.wallet.id,
this.wallet.amount,
)
@@ -151,11 +153,18 @@
})
},
updateSettings() {
- let data = {}
+ const formElement = document.getElementById('settings_form');
+ const formData = new FormData(formElement);
+ const data = {};
+ formData.forEach((value, key) => (data[key] = value));
+ // only for debugging
+ for (const [key, value] of formData) {
+ console.log(`${key}: ${value}\n`);
+ }
LNbits.api
.request(
'PUT',
- '/admin/api/v1/admin/',
+ '/admin/api/v1/settings/?usr=' + this.g.user.id,
this.g.user.wallets[0].adminkey,
data
)
@@ -169,6 +178,40 @@
.catch(function (error) {
LNbits.utils.notifyApiError(error)
});
+ },
+ deleteSettings() {
+ LNbits.api
+ .request(
+ 'DELETE',
+ '/admin/api/v1/settings/?usr=' + this.g.user.id
+ )
+ .then(response => {
+ this.$q.notify({
+ type: 'positive',
+ message: 'Success! Restored settings to defaults, restart required!',
+ icon: null
+ })
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ });
+ },
+ downloadBackup() {
+ LNbits.api
+ .request(
+ 'GET',
+ '/admin/api/v1/backup/?usr=' + this.g.user.id
+ )
+ .then(response => {
+ this.$q.notify({
+ type: 'positive',
+ message: 'Success! Database backup request, download starts soon!',
+ icon: null
+ })
+ })
+ .catch(function (error) {
+ LNbits.utils.notifyApiError(error)
+ });
}
}
})
diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py
index ceb403120..c81205643 100644
--- a/lnbits/extensions/admin/views_api.py
+++ b/lnbits/extensions/admin/views_api.py
@@ -1,7 +1,7 @@
from http import HTTPStatus
-from loguru import logger
from fastapi import Body, Depends, Request
+from loguru import logger
from starlette.exceptions import HTTPException
from lnbits.core.crud import get_wallet
@@ -13,18 +13,16 @@ from lnbits.requestvars import g
from lnbits.server import server_restart
from lnbits.settings import settings
-from .crud import update_settings, update_wallet_balance
+from .crud import delete_settings, update_settings, update_wallet_balance
-@admin_ext.get("/api/v1/admin/restart/", status_code=HTTPStatus.OK)
-async def api_restart_server(
- user: User = Depends(check_admin)
-):
+@admin_ext.get("/api/v1/restart/", status_code=HTTPStatus.OK)
+async def api_restart_server(user: User = Depends(check_admin)):
server_restart.set()
return {"status": "Success"}
-@admin_ext.put("/api/v1/admin/topup/", status_code=HTTPStatus.OK)
+@admin_ext.put("/api/v1/topup/", status_code=HTTPStatus.OK)
async def api_update_balance(
wallet_id, topup_amount: int, user: User = Depends(check_admin)
):
@@ -32,7 +30,7 @@ async def api_update_balance(
wallet = await get_wallet(wallet_id)
except:
raise HTTPException(
- status_code=HTTPStatus.FORBIDDEN, detail="wallet: {wallet_id} does not exist."
+ status_code=HTTPStatus.FORBIDDEN, detail="wallet does not exist."
)
await update_wallet_balance(wallet_id=wallet_id, amount=int(topup_amount))
@@ -40,13 +38,23 @@ async def api_update_balance(
return {"status": "Success"}
-@admin_ext.put("/api/v1/admin/", status_code=HTTPStatus.OK)
-async def api_update_admin(
- request: Request,
+@admin_ext.put("/api/v1/settings/", status_code=HTTPStatus.OK)
+async def api_update_settings(
user: User = Depends(check_admin),
data: UpdateSettings = Body(...),
):
- updated = await update_settings(data)
- g().settings = g().settings.copy(update=updated.dict())
-
+ await update_settings(data)
return {"status": "Success"}
+
+
+@admin_ext.delete("/api/v1/settings/", status_code=HTTPStatus.OK)
+async def api_delete_settings(
+ user: User = Depends(check_admin),
+):
+ await delete_settings()
+ return {"status": "Success"}
+
+
+@admin_ext.get("/api/v1/backup/", status_code=HTTPStatus.OK)
+async def api_backup(user: User = Depends(check_admin)):
+ return {"status": "not implemented"}