fix admin
This commit is contained in:
parent
2b2884142f
commit
840ede1bd6
|
@ -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.tasks import internal_invoice_queue
|
||||
|
||||
from . import db
|
||||
from .models import Admin, Funding
|
||||
from .models import Funding
|
||||
|
||||
|
||||
async def update_wallet_balance(wallet_id: str, amount: int) -> str:
|
||||
|
@ -23,26 +24,26 @@ async def update_wallet_balance(wallet_id: str, amount: int) -> str:
|
|||
)
|
||||
# manually send this for now
|
||||
await internal_invoice_queue.put(internal_id)
|
||||
return payment
|
||||
|
||||
|
||||
async def update_admin(user: str, **kwargs) -> Admin:
|
||||
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.admin SET {q} WHERE "user" = ?', (*kwargs.values(), user)
|
||||
f'UPDATE admin.settings SET {q} WHERE "user" = ?', (*kwargs.values(), user)
|
||||
)
|
||||
row = await db.fetchone('SELECT * FROM admin.admin WHERE "user" = ?', (user,))
|
||||
row = await db.fetchone('SELECT * FROM admin.settings WHERE "user" = ?', (user,))
|
||||
assert row, "Newly updated settings couldn't be retrieved"
|
||||
return Admin(**row) if row else None
|
||||
|
||||
|
||||
async def get_admin() -> Admin:
|
||||
row = await db.fetchone("SELECT * FROM admin.admin")
|
||||
return Admin(**row) if row else None
|
||||
return Settings(**row) if row else None
|
||||
|
||||
|
||||
async def update_funding(data: Funding) -> Funding:
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE admin.settings SET funding_source = ? WHERE user = ?
|
||||
""",
|
||||
(data.backend_wallet, data.user),
|
||||
)
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE admin.funding
|
||||
|
@ -69,5 +70,4 @@ async def update_funding(data: Funding) -> Funding:
|
|||
|
||||
async def get_funding() -> List[Funding]:
|
||||
rows = await db.fetchall("SELECT * FROM admin.funding")
|
||||
|
||||
return [Funding(**row) for row in rows]
|
||||
|
|
|
@ -1,292 +1,57 @@
|
|||
from os import getenv
|
||||
|
||||
from sqlalchemy.exc import OperationalError # type: ignore
|
||||
|
||||
from lnbits.config import conf
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
|
||||
async def get_admin_user():
|
||||
if len(conf.admin_users) > 0:
|
||||
return conf.admin_users[0]
|
||||
from lnbits.core.crud import create_account, get_user
|
||||
|
||||
print("Seems like there's no admin users yet. Let's create an account for you!")
|
||||
account = await create_account()
|
||||
user = account.id
|
||||
assert user, "Newly created user couldn't be retrieved"
|
||||
print(
|
||||
f"Your newly created account/user id is: {user}. This will be the Super Admin user."
|
||||
)
|
||||
conf.admin_users.insert(0, user)
|
||||
return user
|
||||
|
||||
|
||||
async def m001_create_admin_table(db):
|
||||
|
||||
|
||||
# users/server
|
||||
user = await get_admin_user()
|
||||
admin_users = ",".join(conf.admin_users)
|
||||
allowed_users = ",".join(conf.allowed_users)
|
||||
admin_ext = ",".join(conf.admin_ext)
|
||||
disabled_ext = ",".join(conf.disabled_ext)
|
||||
funding_source = conf.funding_source
|
||||
# operational
|
||||
data_folder = conf.data_folder
|
||||
database_url = conf.database_url
|
||||
force_https = conf.force_https
|
||||
reserve_fee_min = conf.reserve_fee_min
|
||||
reserve_fee_pct = conf.reserve_fee_pct
|
||||
service_fee = conf.service_fee
|
||||
hide_api = conf.hide_api
|
||||
denomination = conf.denomination
|
||||
# Theme'ing
|
||||
site_title = conf.site_title
|
||||
site_tagline = conf.site_tagline
|
||||
site_description = conf.site_description
|
||||
default_wallet_name = conf.default_wallet_name
|
||||
theme = ",".join(conf.theme)
|
||||
custom_logo = conf.custom_logo
|
||||
ad_space = ",".join(conf.ad_space)
|
||||
|
||||
async def m001_create_admin_settings_table(db):
|
||||
await db.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS admin.admin (
|
||||
"user" TEXT PRIMARY KEY,
|
||||
admin_users TEXT,
|
||||
allowed_users TEXT,
|
||||
admin_ext TEXT,
|
||||
disabled_ext TEXT,
|
||||
funding_source TEXT,
|
||||
data_folder TEXT,
|
||||
database_url TEXT,
|
||||
force_https BOOLEAN,
|
||||
reserve_fee_min INT,
|
||||
reserve_fee_pct REAL,
|
||||
service_fee REAL,
|
||||
hide_api BOOLEAN,
|
||||
denomination TEXT,
|
||||
site_title TEXT,
|
||||
site_tagline TEXT,
|
||||
site_description TEXT,
|
||||
default_wallet_name TEXT,
|
||||
theme TEXT,
|
||||
custom_logo TEXT,
|
||||
ad_space TEXT
|
||||
);
|
||||
"""
|
||||
)
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.admin (
|
||||
"user",
|
||||
admin_users,
|
||||
allowed_users,
|
||||
admin_ext,
|
||||
disabled_ext,
|
||||
funding_source,
|
||||
data_folder,
|
||||
database_url,
|
||||
force_https,
|
||||
reserve_fee_min,
|
||||
reserve_fee_pct,
|
||||
service_fee,
|
||||
hide_api,
|
||||
denomination,
|
||||
site_title,
|
||||
site_tagline,
|
||||
site_description,
|
||||
default_wallet_name,
|
||||
theme,
|
||||
custom_logo,
|
||||
ad_space)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
user,
|
||||
admin_users,
|
||||
allowed_users,
|
||||
admin_ext,
|
||||
disabled_ext,
|
||||
funding_source,
|
||||
data_folder,
|
||||
database_url,
|
||||
force_https,
|
||||
reserve_fee_min,
|
||||
reserve_fee_pct,
|
||||
service_fee,
|
||||
hide_api,
|
||||
denomination,
|
||||
site_title,
|
||||
site_tagline,
|
||||
site_description,
|
||||
default_wallet_name,
|
||||
theme,
|
||||
custom_logo,
|
||||
ad_space,
|
||||
),
|
||||
)
|
||||
|
||||
funding_wallet = getenv("LNBITS_BACKEND_WALLET_CLASS")
|
||||
|
||||
# Make the funding table, if it does not already exist
|
||||
await db.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS admin.funding (
|
||||
id TEXT PRIMARY KEY,
|
||||
backend_wallet TEXT,
|
||||
endpoint TEXT,
|
||||
CREATE TABLE IF NOT EXISTS admin.settings (
|
||||
lnbits_admin_ui TEXT,
|
||||
debug TEXT,
|
||||
host TEXT,
|
||||
port INT,
|
||||
read_key TEXT,
|
||||
invoice_key TEXT,
|
||||
admin_key TEXT,
|
||||
cert TEXT,
|
||||
balance INT,
|
||||
selected INT
|
||||
lnbits_path TEXT,
|
||||
lnbits_commit TEXT,
|
||||
lnbits_admin_users TEXT,
|
||||
lnbits_allowed_users TEXT,
|
||||
lnbits_allowed_funding_sources TEXT,
|
||||
lnbits_admin_extensions TEXT,
|
||||
lnbits_disabled_extensions TEXT,
|
||||
lnbits_site_title TEXT,
|
||||
lnbits_site_tagline TEXT,
|
||||
lnbits_site_description TEXT,
|
||||
lnbits_default_wallet_name TEXT,
|
||||
lnbits_theme_options TEXT,
|
||||
lnbits_custom_logo TEXT,
|
||||
lnbits_ad_space TEXT,
|
||||
lnbits_data_folder TEXT,
|
||||
lnbits_database_url TEXT,
|
||||
lnbits_force_https TEXT,
|
||||
lnbits_reserve_fee_min TEXT,
|
||||
lnbits_reserve_fee_percent TEXT,
|
||||
lnbits_service_fee TEXT,
|
||||
lnbits_hide_api TEXT,
|
||||
lnbits_denomination TEXT,
|
||||
lnbits_backend_wallet_class TEXT,
|
||||
fake_wallet_secret TEXT,
|
||||
lnbits_endpoint TEXT,
|
||||
lnbits_key TEXT,
|
||||
cliche_endpoint TEXT,
|
||||
corelightning_rpc TEXT,
|
||||
eclair_url TEXT,
|
||||
eclair_pass TEXT,
|
||||
lnd_rest_endpoint TEXT,
|
||||
lnd_rest_cert TEXT,
|
||||
lnd_rest_macaroon TEXT,
|
||||
lnpay_api_endpoint TEXT,
|
||||
lnpay_api_key TEXT,
|
||||
lnpay_wallet_key TEXT,
|
||||
lntxbot_api_endpoint TEXT,
|
||||
lntxbot_key TEXT,
|
||||
opennode_api_endpoint TEXT,
|
||||
opennode_key TEXT,
|
||||
spark_url TEXT,
|
||||
spark_token TEXT,
|
||||
boltz_network TEXT,
|
||||
boltz_url TEXT,
|
||||
boltz_mempool_space_url TEXT,
|
||||
boltz_mempool_space_url_ws TEXT
|
||||
);
|
||||
"""
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, selected)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"CLightningWallet",
|
||||
getenv("CLIGHTNING_RPC"),
|
||||
1 if funding_wallet == "CLightningWallet" else 0,
|
||||
),
|
||||
)
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"SparkWallet",
|
||||
getenv("SPARK_URL"),
|
||||
getenv("SPARK_TOKEN"),
|
||||
1 if funding_wallet == "SparkWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"LnbitsWallet",
|
||||
getenv("LNBITS_ENDPOINT"),
|
||||
getenv("LNBITS_KEY"),
|
||||
1 if funding_wallet == "LnbitsWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, port, admin_key, cert, selected)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"LndWallet",
|
||||
getenv("LND_GRPC_ENDPOINT"),
|
||||
getenv("LND_GRPC_PORT"),
|
||||
getenv("LND_GRPC_MACAROON"),
|
||||
getenv("LND_GRPC_CERT"),
|
||||
1 if funding_wallet == "LndWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, cert, selected)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"LndRestWallet",
|
||||
getenv("LND_REST_ENDPOINT"),
|
||||
getenv("LND_REST_MACAROON"),
|
||||
getenv("LND_REST_CERT"),
|
||||
1 if funding_wallet == "LndWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, cert, selected)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"LNPayWallet",
|
||||
getenv("LNPAY_API_ENDPOINT"),
|
||||
getenv("LNPAY_WALLET_KEY"),
|
||||
getenv("LNPAY_API_KEY"), # this is going in as the cert
|
||||
1 if funding_wallet == "LNPayWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"LntxbotWallet",
|
||||
getenv("LNTXBOT_API_ENDPOINT"),
|
||||
getenv("LNTXBOT_KEY"),
|
||||
1 if funding_wallet == "LntxbotWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"OpenNodeWallet",
|
||||
getenv("OPENNODE_API_ENDPOINT"),
|
||||
getenv("OPENNODE_KEY"),
|
||||
1 if funding_wallet == "OpenNodeWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
urlsafe_short_hash(),
|
||||
"SparkWallet",
|
||||
getenv("SPARK_URL"),
|
||||
getenv("SPARK_TOKEN"),
|
||||
1 if funding_wallet == "SparkWallet" else 0,
|
||||
),
|
||||
)
|
||||
|
||||
## PLACEHOLDER FOR ECLAIR WALLET
|
||||
# await db.execute(
|
||||
# """
|
||||
# INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected)
|
||||
# VALUES (?, ?, ?, ?, ?)
|
||||
# """,
|
||||
# (
|
||||
# urlsafe_short_hash(),
|
||||
# "EclairWallet",
|
||||
# getenv("ECLAIR_URL"),
|
||||
# getenv("ECLAIR_PASS"),
|
||||
# 1 if funding_wallet == "EclairWallet" else 0,
|
||||
# ),
|
||||
# )
|
||||
|
|
|
@ -29,36 +29,36 @@ class UpdateAdminSettings(BaseModel):
|
|||
ad_space: str = Query(None)
|
||||
|
||||
|
||||
class Admin(BaseModel):
|
||||
# users
|
||||
user: str
|
||||
admin_users: Optional[str]
|
||||
allowed_users: Optional[str]
|
||||
admin_ext: Optional[str]
|
||||
disabled_ext: Optional[str]
|
||||
funding_source: Optional[str]
|
||||
# ops
|
||||
data_folder: Optional[str]
|
||||
database_url: Optional[str]
|
||||
force_https: bool = Field(default=True)
|
||||
reserve_fee_min: Optional[int]
|
||||
reserve_fee_pct: Optional[float]
|
||||
service_fee: float = Optional[float]
|
||||
hide_api: bool = Field(default=False)
|
||||
# Change theme
|
||||
site_title: Optional[str]
|
||||
site_tagline: Optional[str]
|
||||
site_description: Optional[str]
|
||||
default_wallet_name: Optional[str]
|
||||
denomination: str = Field(default="sats")
|
||||
theme: Optional[str]
|
||||
custom_logo: Optional[str]
|
||||
ad_space: Optional[str]
|
||||
# class Admin(BaseModel):
|
||||
# # users
|
||||
# user: str
|
||||
# admin_users: Optional[str]
|
||||
# allowed_users: Optional[str]
|
||||
# admin_ext: Optional[str]
|
||||
# disabled_ext: Optional[str]
|
||||
# funding_source: Optional[str]
|
||||
# # ops
|
||||
# data_folder: Optional[str]
|
||||
# database_url: Optional[str]
|
||||
# force_https: bool = Field(default=True)
|
||||
# reserve_fee_min: Optional[int]
|
||||
# reserve_fee_pct: Optional[float]
|
||||
# service_fee: float = Optional[float]
|
||||
# hide_api: bool = Field(default=False)
|
||||
# # Change theme
|
||||
# site_title: Optional[str]
|
||||
# site_tagline: Optional[str]
|
||||
# site_description: Optional[str]
|
||||
# default_wallet_name: Optional[str]
|
||||
# denomination: str = Field(default="sats")
|
||||
# theme: Optional[str]
|
||||
# custom_logo: Optional[str]
|
||||
# ad_space: Optional[str]
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, row: Row) -> "Admin":
|
||||
data = dict(row)
|
||||
return cls(**data)
|
||||
# @classmethod
|
||||
# def from_row(cls, row: Row) -> "Admin":
|
||||
# data = dict(row)
|
||||
# return cls(**data)
|
||||
|
||||
|
||||
class Funding(BaseModel):
|
||||
|
|
158
lnbits/extensions/admin/templates/admin/_tab_funding.html
Normal file
158
lnbits/extensions/admin/templates/admin/_tab_funding.html
Normal file
|
@ -0,0 +1,158 @@
|
|||
<q-tab-panel name="funding">
|
||||
<q-card-section class="q-pa-none">
|
||||
<h6 class="q-my-none">Wallets Management</h6>
|
||||
<br />
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<p>Funding Source Info</p>
|
||||
<ul>
|
||||
{%raw%}
|
||||
<li>
|
||||
Funding Source: {{data.settings.lnbits_backend_wallet_class}}
|
||||
</li>
|
||||
<li>Balance: {{data.balance / 1000}} sats</li>
|
||||
{%endraw%}
|
||||
</ul>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p>Active Funding<small> (Requires server restart)</small></p>
|
||||
<q-select
|
||||
filled
|
||||
v-model="data.settings.lnbits_backend_wallet_class"
|
||||
hint="Select the active funding wallet"
|
||||
:options="data.settings.lnbits_funding_sources"
|
||||
></q-select>
|
||||
<br />
|
||||
<div>
|
||||
<q-btn
|
||||
class="q-mt-md float-right"
|
||||
label="Restart Server"
|
||||
color="primary"
|
||||
@click="restartServer"
|
||||
></q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<p>Fee reserve</p>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-6">
|
||||
<q-input
|
||||
dense
|
||||
type="number"
|
||||
filled
|
||||
v-model="data.settings.lnbits_reserve_fee_min"
|
||||
label="Reserve fee in msats"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<q-input
|
||||
dense
|
||||
type="number"
|
||||
filled
|
||||
v-model="data.settings.lnbits_reserve_fee_percent"
|
||||
label="Reserve fee in percent"
|
||||
step="0.1"
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p>TopUp a wallet</p>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<q-input
|
||||
dense
|
||||
type="text"
|
||||
filled
|
||||
v-model="wallet.data.id"
|
||||
label="Wallet ID"
|
||||
hint="Use the wallet ID to topup any wallet"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<q-input
|
||||
dense
|
||||
type="number"
|
||||
filled
|
||||
v-model="wallet.data.amount"
|
||||
label="Topup amount"
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<q-btn
|
||||
class="q-mt-md float-right"
|
||||
label="Topup"
|
||||
color="primary"
|
||||
@click="topupWallet"
|
||||
></q-btn>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<p>Funding Sources</p>
|
||||
{% raw %}
|
||||
<q-list v-for="fund in data.settings.funding" :key="fund.id">
|
||||
<q-expansion-item
|
||||
expand-separator
|
||||
icon="payments"
|
||||
:label="fund.backend_wallet"
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
v-if="fund.endpoint"
|
||||
filled
|
||||
type="text"
|
||||
v-model="fund.endpoint"
|
||||
label="Endpoint"
|
||||
class="q-pr-md"
|
||||
></q-input>
|
||||
<q-input
|
||||
v-if="fund.port"
|
||||
filled
|
||||
type="text"
|
||||
v-model="fund.port"
|
||||
label="Port"
|
||||
class="q-pr-md"
|
||||
></q-input>
|
||||
<q-input
|
||||
v-if="fund.admin_key"
|
||||
filled
|
||||
type="text"
|
||||
v-model="fund.admin_key"
|
||||
label="Admin Key"
|
||||
class="q-pr-md"
|
||||
></q-input>
|
||||
<q-input
|
||||
v-if="fund.cert"
|
||||
filled
|
||||
type="text"
|
||||
v-model="fund.cert"
|
||||
label="Location of your ssl cert"
|
||||
class="q-pr-md"
|
||||
></q-input>
|
||||
<q-btn
|
||||
class="q-mt-md"
|
||||
label="Save"
|
||||
flat
|
||||
color="primary"
|
||||
@click="updateFunding(fund.backend_wallet)"
|
||||
></q-btn>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
</q-list>
|
||||
{% endraw %}
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
78
lnbits/extensions/admin/templates/admin/_tab_server.html
Normal file
78
lnbits/extensions/admin/templates/admin/_tab_server.html
Normal file
|
@ -0,0 +1,78 @@
|
|||
<q-tab-panel name="server">
|
||||
<q-card-section class="q-pa-none">
|
||||
<h6 class="q-my-none">Server Management</h6>
|
||||
<br />
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<p>Server Info</p>
|
||||
<ul>
|
||||
{%raw%}
|
||||
<li v-if="data.settings.lnbits_data_folder">
|
||||
SQlite: {{data.settings.lnbits_data_folder}}
|
||||
</li>
|
||||
<li v-if="data.settings.lnbits_database_url">
|
||||
Postgres: {{data.settings.lnbits_database_url}}
|
||||
</li>
|
||||
{%endraw%}
|
||||
</ul>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Service Fee</p>
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
v-model.number="data.settings.lnbits_service_fee"
|
||||
label="Service fee (%)"
|
||||
step="0.1"
|
||||
hint="Fee charged per tx (%)"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Miscelaneous</p>
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Force HTTPS</q-item-label>
|
||||
<q-item-label caption>Prefer secure URLs</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
size="md"
|
||||
v-model="data.settings.lnbits_force_https"
|
||||
checked-icon="check"
|
||||
color="green"
|
||||
unchecked-icon="clear"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Hide API</q-item-label>
|
||||
<q-item-label caption
|
||||
>Hides wallet api, extensions can choose to honor</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
size="md"
|
||||
v-model="data.settings.lnbits_hide_api"
|
||||
checked-icon="check"
|
||||
color="green"
|
||||
unchecked-icon="clear"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn unelevated color="primary" type="submit">Save</q-btn>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
122
lnbits/extensions/admin/templates/admin/_tab_theme.html
Normal file
122
lnbits/extensions/admin/templates/admin/_tab_theme.html
Normal file
|
@ -0,0 +1,122 @@
|
|||
<q-tab-panel name="theme">
|
||||
<q-card-section class="q-pa-none">
|
||||
<h6 class="q-my-none">UI Management</h6>
|
||||
<br />
|
||||
<div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Site Title</p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="data.settings.lnbits_site_title"
|
||||
label="Site title"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Site Tagline</p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="data.settings.lnbits_site_tagline"
|
||||
label="Site tagline"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>Site Description</p>
|
||||
<q-input
|
||||
v-model="data.settings.lnbits_site_description"
|
||||
filled
|
||||
type="textarea"
|
||||
hint="Use plain text or raw HTML"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Default Wallet Name</p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="data.settings.lnbits_default_wallet_name"
|
||||
label="LNbits wallet"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Denomination</p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="data.settings.lnbits_denomination"
|
||||
label="sats"
|
||||
hint="The name for the FakeWallet token"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Themes</p>
|
||||
<q-select
|
||||
filled
|
||||
v-model="data.settings.lnbits_theme"
|
||||
multiple
|
||||
hint="Choose themes available for users"
|
||||
:options="themes"
|
||||
label="Themes"
|
||||
></q-select>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Advertisement Slots</p>
|
||||
<q-input
|
||||
filled
|
||||
v-model="data.ad_space_add"
|
||||
@keydown.enter="addAdSpace"
|
||||
type="text"
|
||||
label="Ad image URL"
|
||||
hint="Ad image filepaths or urls, extensions can choose to honor"
|
||||
>
|
||||
<q-btn @click="addAdSpace" dense flat icon="add"></q-btn>
|
||||
</q-input>
|
||||
<div>
|
||||
{% raw %}
|
||||
<q-chip
|
||||
v-for="space in data.settings.lnbits_ad_space"
|
||||
:key="space"
|
||||
removable
|
||||
@remove="removeAdSpace(space)"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
>
|
||||
{{ space.slice(0, 8) + " ... " + space.slice(-8) }}
|
||||
</q-chip>
|
||||
{% endraw %}
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Custom Logo</p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="data.settings.lnbits_custom_logo"
|
||||
label="https://example.com/image.png"
|
||||
hint="URL to logo image"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn unelevated color="primary" type="submit">Save</q-btn>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
96
lnbits/extensions/admin/templates/admin/_tab_users.html
Normal file
96
lnbits/extensions/admin/templates/admin/_tab_users.html
Normal file
|
@ -0,0 +1,96 @@
|
|||
<q-tab-panel name="users">
|
||||
<q-card-section class="q-pa-none">
|
||||
<h6 class="q-my-none">User Management</h6>
|
||||
<br />
|
||||
<p class="q-my-none">
|
||||
Super Admin: {% raw %}{{this.data.settings.lnbits_admin_users[0]}}{%
|
||||
endraw %}
|
||||
</p>
|
||||
<br />
|
||||
<div>
|
||||
<p>Admin Users</p>
|
||||
<q-input
|
||||
filled
|
||||
v-model="data.admin_users_add"
|
||||
@keydown.enter="addAdminUser"
|
||||
type="text"
|
||||
label="User ID"
|
||||
hint="Users with admin privileges"
|
||||
>
|
||||
<q-btn @click="addAdminUser" dense flat icon="add"></q-btn>
|
||||
</q-input>
|
||||
<div>
|
||||
{% raw %}
|
||||
<q-chip
|
||||
v-for="user in data.settings.lnbits_admin_users.slice(1)"
|
||||
:key="user"
|
||||
removable
|
||||
@remove="removeAdminUser(user)"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
>
|
||||
{{ user }}
|
||||
</q-chip>
|
||||
{% endraw %}
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
<div>
|
||||
<p>Allowed Users</p>
|
||||
<q-input
|
||||
filled
|
||||
v-model="data.allowed_users_add"
|
||||
@keydown.enter="addAllowedUser"
|
||||
type="text"
|
||||
label="User ID"
|
||||
hint="Only these users can use LNbits"
|
||||
>
|
||||
<q-btn @click="addAllowedUser" dense flat icon="add"></q-btn>
|
||||
</q-input>
|
||||
<div>
|
||||
{% raw %}
|
||||
<q-chip
|
||||
v-for="user in data.settings.lnbits_allowed_users"
|
||||
:key="user"
|
||||
removable
|
||||
@remove="removeAllowedUser(user)"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
>
|
||||
{{ user }}
|
||||
</q-chip>
|
||||
{% endraw %}
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Admin Extensions</p>
|
||||
<q-select
|
||||
filled
|
||||
v-model="data.settings.admin_extensions"
|
||||
multiple
|
||||
hint="Extensions only user with admin privileges can use"
|
||||
:options="options"
|
||||
label="Admin extensions"
|
||||
></q-select>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p>Disabled Extensions</p>
|
||||
<q-select
|
||||
filled
|
||||
v-model="data.settings.lnbits_disabled_extensions"
|
||||
multiple
|
||||
hint="Disable extensions *amilk disabled by default as resource heavy"
|
||||
:options="options"
|
||||
label="Disable extensions"
|
||||
></q-select>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn unelevated color="primary" type="submit">Save</q-btn>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
File diff suppressed because it is too large
Load Diff
|
@ -7,30 +7,26 @@ from fastapi.templating import Jinja2Templates
|
|||
from starlette.responses import HTMLResponse
|
||||
|
||||
from lnbits.core.models import User
|
||||
from lnbits.decorators import check_user_exists
|
||||
from lnbits.extensions.admin import admin_ext
|
||||
from lnbits.decorators import check_admin
|
||||
from lnbits.requestvars import g
|
||||
from lnbits.settings import WALLET, settings
|
||||
|
||||
from . import admin_ext, admin_renderer
|
||||
from .crud import get_admin, get_funding
|
||||
from .crud import get_funding
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
|
||||
@admin_ext.get("/", response_class=HTMLResponse)
|
||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||
admin = await get_admin()
|
||||
funding = [f.dict() for f in await get_funding()]
|
||||
error, balance = await g().WALLET.status()
|
||||
async def index(request: Request, user: User = Depends(check_admin)):
|
||||
error, balance = await WALLET.status()
|
||||
|
||||
return admin_renderer().TemplateResponse(
|
||||
"admin/index.html",
|
||||
{
|
||||
"request": request,
|
||||
"user": user.dict(),
|
||||
"admin": admin.dict(),
|
||||
"funding": funding,
|
||||
"settings": g().admin_conf.dict(),
|
||||
"settings": settings.dict(),
|
||||
"balance": balance,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,17 +1,27 @@
|
|||
from http import HTTPStatus
|
||||
|
||||
# from config import conf
|
||||
from fastapi import Body, Depends, Request
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from lnbits.core.crud import get_wallet
|
||||
from lnbits.decorators import WalletTypeInfo, require_admin_key
|
||||
from lnbits.core.models import User
|
||||
from lnbits.decorators import WalletTypeInfo, check_admin, require_admin_key
|
||||
from lnbits.extensions.admin import admin_ext
|
||||
from lnbits.extensions.admin.models import Admin, Funding, UpdateAdminSettings
|
||||
from lnbits.extensions.admin.models import Funding, UpdateAdminSettings
|
||||
from lnbits.helpers import removeEmptyString
|
||||
from lnbits.requestvars import g
|
||||
from lnbits.server import server_restart
|
||||
from lnbits.settings import settings
|
||||
|
||||
from .crud import get_admin, update_admin, update_funding, update_wallet_balance
|
||||
from .crud import update_funding, update_settings, update_wallet_balance
|
||||
|
||||
|
||||
@admin_ext.get("/api/v1/admin/restart/", status_code=HTTPStatus.OK)
|
||||
async def api_restart_server(
|
||||
g: WalletTypeInfo = Depends(require_admin_key), # type: ignore
|
||||
):
|
||||
server_restart.set()
|
||||
return {"status": "Success"}
|
||||
|
||||
|
||||
@admin_ext.get("/api/v1/admin/{wallet_id}/{topup_amount}", status_code=HTTPStatus.OK)
|
||||
|
@ -36,9 +46,7 @@ async def api_update_admin(
|
|||
data: UpdateAdminSettings = Body(...),
|
||||
w: WalletTypeInfo = Depends(require_admin_key),
|
||||
):
|
||||
admin = await get_admin()
|
||||
# print(data)
|
||||
if not admin.user == w.wallet.user:
|
||||
if not settings.user == w.wallet.user:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin"
|
||||
)
|
||||
|
@ -53,7 +61,6 @@ async def api_update_admin(
|
|||
|
||||
g().admin_conf = g().admin_conf.copy(update=updated.dict())
|
||||
|
||||
# print(g().admin_conf)
|
||||
return {"status": "Success"}
|
||||
|
||||
|
||||
|
@ -63,11 +70,10 @@ async def api_update_funding(
|
|||
data: Funding = Body(...),
|
||||
w: WalletTypeInfo = Depends(require_admin_key),
|
||||
):
|
||||
admin = await get_admin()
|
||||
|
||||
if not admin.user == w.wallet.user:
|
||||
if not settings.user == w.wallet.user:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin"
|
||||
)
|
||||
|
||||
funding = await update_funding(data=data)
|
||||
return funding
|
||||
|
|
Loading…
Reference in New Issue
Block a user