FEAT: add db export admin route for pg and sqlite, add to adminui

This commit is contained in:
dni ⚡
2023-03-02 15:22:39 +01:00
parent c81d3e06c8
commit 6cf1d97d5a
3 changed files with 52 additions and 16 deletions

2
.gitignore vendored
View File

@@ -43,6 +43,8 @@ docker
# fly.io # fly.io
fly.toml fly.toml
lnbits-backup.zip
# Ignore extensions (post installable extension PR) # Ignore extensions (post installable extension PR)
extensions/ extensions/
upgrades/ upgrades/

View File

@@ -47,11 +47,11 @@
<q-tooltip> Add funds to a wallet. </q-tooltip> <q-tooltip> Add funds to a wallet. </q-tooltip>
</q-btn> </q-btn>
<!-- <q-btn <q-btn
label="Download Database Backup" label="Download Database Backup"
flat flat
@click="downloadBackup" @click="downloadBackup"
></q-btn> --> ></q-btn>
<q-btn <q-btn
flat flat
@@ -535,19 +535,7 @@
}) })
}, },
downloadBackup() { downloadBackup() {
LNbits.api window.open('/admin/api/v1/backup/?usr=' + this.g.user.id, '_blank')
.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)
})
} }
} }
}) })

View File

@@ -1,7 +1,13 @@
import os
import time
from http import HTTPStatus from http import HTTPStatus
from shutil import make_archive
from subprocess import Popen
from typing import Optional from typing import Optional
from urllib.parse import urlparse
from fastapi import Body, Depends from fastapi import Body, Depends
from fastapi.responses import FileResponse
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from lnbits.core.crud import get_wallet from lnbits.core.crud import get_wallet
@@ -9,7 +15,7 @@ from lnbits.core.models import User
from lnbits.core.services import update_cached_settings, update_wallet_balance from lnbits.core.services import update_cached_settings, update_wallet_balance
from lnbits.decorators import check_admin, check_super_user from lnbits.decorators import check_admin, check_super_user
from lnbits.server import server_restart from lnbits.server import server_restart
from lnbits.settings import AdminSettings, EditableSettings from lnbits.settings import AdminSettings, EditableSettings, settings
from .. import core_app from .. import core_app
from ..crud import delete_admin_settings, get_admin_settings, update_admin_settings from ..crud import delete_admin_settings, get_admin_settings, update_admin_settings
@@ -72,3 +78,43 @@ async def api_topup_balance(
await update_wallet_balance(wallet_id=id, amount=int(amount)) await update_wallet_balance(wallet_id=id, amount=int(amount))
return {"status": "Success"} return {"status": "Success"}
@core_app.get(
"/admin/api/v1/backup/",
status_code=HTTPStatus.OK,
dependencies=[Depends(check_super_user)],
response_class=FileResponse,
)
async def api_download_backup() -> FileResponse:
last_filename = "lnbits-backup"
filename = f"lnbits-backup-{int(time.time())}.zip"
db_url = settings.lnbits_database_url
pg_backup_filename = f"{settings.lnbits_data_folder}/lnbits-database.dmp"
is_pg = db_url and db_url.startswith("postgres://")
if is_pg:
p = urlparse(db_url)
command = (
f"pg_dump --host={p.hostname} "
f'--dbname={p.path.replace("/", "")} '
f"--username={p.username} "
f"--no-password "
f"--format=c "
f"--file={pg_backup_filename}"
)
proc = Popen(
command, shell=True, env={**os.environ, "PGPASSWORD": p.password or ""}
)
proc.wait()
make_archive(last_filename, "zip", settings.lnbits_data_folder)
# cleanup pg_dump file
if is_pg:
proc = Popen(f"rm {pg_backup_filename}", shell=True)
proc.wait()
return FileResponse(
path=f"{last_filename}.zip", filename=filename, media_type="application/zip"
)