update funding wallets

This commit is contained in:
Tiago vasconcelos
2022-04-14 16:37:13 +01:00
committed by dni ⚡
parent 2c48e3aa5f
commit f16ead4f73
4 changed files with 315 additions and 242 deletions

View File

@@ -39,6 +39,18 @@ async def get_admin() -> Admin:
row = await db.fetchone("SELECT * FROM admin") row = await db.fetchone("SELECT * FROM admin")
return Admin(**row) if row else None return Admin(**row) if row else None
async def update_funding(data: Funding) -> Funding:
await db.execute(
"""
UPDATE funding
SET backend_wallet = ?, endpoint = ?, port = ?, read_key = ?, invoice_key = ?, admin_key = ?, cert = ?, balance = ?, selected = ?
WHERE id = ?
""",
(data.backend_wallet, data.endpoint, data.port, data.read_key, data.invoice_key, data.admin_key, data.cert, data.balance, data.selected, data.id,),
)
row = await db.fetchone('SELECT * FROM funding WHERE "id" = ?', (data.id,))
assert row, "Newly updated settings couldn't be retrieved"
return Funding(**row) if row else None
async def get_funding() -> List[Funding]: async def get_funding() -> List[Funding]:
rows = await db.fetchall("SELECT * FROM funding") rows = await db.fetchall("SELECT * FROM funding")

View File

@@ -31,11 +31,11 @@
</div> </div>
<q-form @submit="UpdateLNbits"> <q-form @submit="UpdateLNbits">
<q-tab-panels v-model="tab" animated> <q-tab-panels v-model="tab" animated>
<q-tab-panel name="funding"> <q-tab-panel name="funding">
<q-card-section class="q-pa-none"> <q-card-section class="q-pa-none">
<h6 class="q-my-none">Wallets Management</h6> <h6 class="q-my-none">Wallets Management</h6>
<br /> <br />
<div> <div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
@@ -62,43 +62,96 @@
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<!-- <q-form @submit="topupWallet"> --> <!-- <q-form @submit="topupWallet"> -->
<p>TopUp a wallet</p> <p>TopUp a wallet</p>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<q-input <q-input
dense dense
type="text" type="text"
filled filled
v-model="wallet.data.id" v-model="wallet.data.id"
label="Wallet ID" label="Wallet ID"
hint="Use the wallet ID to topup any wallet" hint="Use the wallet ID to topup any wallet"
></q-input> ></q-input>
<br /> <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>
<div> <div class="col-12">
<q-btn <q-input
class="q-mt-md float-right" dense
label="Topup" type="number"
color="primary" filled
@click="topupWallet" v-model="wallet.data.amount"
></q-btn> label="Topup amount"
></q-input>
</div> </div>
</div>
<div>
<q-btn
class="q-mt-md float-right"
label="Topup"
color="primary"
@click="topupWallet"
></q-btn>
</div>
<!-- </q-form> --> <!-- </q-form> -->
<br /> <br />
</div> </div>
</div> </div>
<p>Funding Sources</p> <p>Funding Sources</p>
<q-list bordered class="rounded-borders"> {% raw %}
<q-list v-for="fund in data.admin.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 %}
<!-- <q-list bordered class="rounded-borders">
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -109,15 +162,23 @@
<q-card-section> <q-card-section>
<q-input <q-input
filled filled
type="text"
v-model="data.admin.funding.CLightningWallet.endpoint" v-model="data.admin.funding.CLightningWallet.endpoint"
label="GRPC Endpoint" label="GRPC Endpoint"
class="q-pr-md" class="q-pr-md"
hint="ie /home/bob/.lightning/bitcoin/lightning-rpc" hint="ie /home/bob/.lightning/bitcoin/lightning-rpc"
></q-input> ></q-input>
<q-btn
class="q-mt-md"
label="Save"
flat
color="primary"
@click="updateFunding(data.admin.funding.CLightningWallet.backend_wallet)"
></q-btn>
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -153,7 +214,7 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -197,7 +258,7 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -226,7 +287,7 @@
></q-input> ></q-input>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<q-input <q-input
@@ -250,7 +311,7 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -274,7 +335,7 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -304,7 +365,7 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -339,7 +400,7 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
expand-separator expand-separator
icon="payments" icon="payments"
@@ -361,29 +422,19 @@
</div> </div>
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-list </q-expansion-item>
> </q-list> -->
</div> </div>
</q-card-section>
<div class="row q-mt-lg"> </q-tab-panel>
<q-btn <q-tab-panel name="users">
unelevated <q-card-section class="q-pa-none">
color="primary" <h6 class="q-my-none">User Management</h6>
type="submit" <br />
>Save</q-btn <p class="q-my-none">
> Super Admin: {% raw %}{{this.data.admin.user}}{% endraw %}
</div> </p>
</q-card-section> <br />
</q-tab-panel>
<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.admin.user}}{% endraw %}
</p>
<br />
<div> <div>
<p>Admin Users</p> <p>Admin Users</p>
<q-input <q-input
@@ -392,12 +443,15 @@
@keydown.enter="addAdminUser" @keydown.enter="addAdminUser"
type="text" type="text"
label="User ID" label="User ID"
hint="Users with admin privileges"> hint="Users with admin privileges"
>
<q-btn @click="addAdminUser" dense flat icon="add"></q-btn> <q-btn @click="addAdminUser" dense flat icon="add"></q-btn>
</q-input> </q-input>
<div> <div>
{% raw %} {% raw %}
<q-chip v-for="user in data.admin.admin_users.slice(1)" <q-chip
v-for="user in data.admin.admin_users.slice(1)"
:key="user"
removable removable
@remove="removeAdminUser(user)" @remove="removeAdminUser(user)"
color="primary" color="primary"
@@ -408,80 +462,82 @@
{% endraw %} {% endraw %}
</div> </div>
<br /> <br />
</div> </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> <div>
{% raw %} <p>Allowed Users</p>
<q-chip v-for="user in data.admin.allowed_users" <q-input
removable filled
@remove="removeAllowedUser(user)" v-model="data.allowed_users_add"
color="primary" @keydown.enter="addAllowedUser"
text-color="white" type="text"
label="User ID"
hint="Only these users can use LNbits"
> >
{{ user }} <q-btn @click="addAllowedUser" dense flat icon="add"></q-btn>
</q-chip> </q-input>
{% endraw %} <div>
{% raw %}
<q-chip
v-for="user in data.admin.allowed_users"
:key="user"
removable
@remove="removeAllowedUser(user)"
color="primary"
text-color="white"
>
{{ user }}
</q-chip>
{% endraw %}
</div>
<br />
</div> </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.admin.admin_ext"
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.admin.disabled_ext"
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>
<q-tab-panel name="server">
<q-card-section class="q-pa-none">
<h6 class="q-my-none">Server Management</h6>
<br /> <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.admin.admin_ext"
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.admin.disabled_ext"
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>
<q-tab-panel name="server">
<q-card-section class="q-pa-none">
<h6 class="q-my-none">Server Management</h6>
<br />
<div> <div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<p>Server Info</p> <p>Server Info</p>
<ul> <ul>
{%raw%} {%raw%}
<li v-if="data.admin.data_folder">SQlite: {{data.admin.data_folder}}</li> <li v-if="data.admin.data_folder">
<li v-if="data.admin.database_url">Postgres: {{data.admin.database_url}}</li> SQlite: {{data.admin.data_folder}}
</li>
<li v-if="data.admin.database_url">
Postgres: {{data.admin.database_url}}
</li>
{%endraw%} {%endraw%}
</ul> </ul>
<br /> <br />
@@ -520,7 +576,10 @@
<q-item tag="label" v-ripple> <q-item tag="label" v-ripple>
<q-item-section> <q-item-section>
<q-item-label>Hide API</q-item-label> <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-label caption
>Hides wallet api, extensions can choose to
honor</q-item-label
>
</q-item-section> </q-item-section>
<q-item-section avatar> <q-item-section avatar>
<q-toggle <q-toggle
@@ -535,22 +594,17 @@
<br /> <br />
</div> </div>
</div> </div>
</div> </div>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn <q-btn unelevated color="primary" type="submit">Save</q-btn>
unelevated </div>
color="primary" </q-card-section>
type="submit" </q-tab-panel>
>Save</q-btn <q-tab-panel name="theme">
> <q-card-section class="q-pa-none">
</div> <h6 class="q-my-none">UI Management</h6>
</q-card-section> <br />
</q-tab-panel>
<q-tab-panel name="theme">
<q-card-section class="q-pa-none">
<h6 class="q-my-none">UI Management</h6>
<br />
<div> <div>
<div class="row q-col-gutter-md"> <div class="row q-col-gutter-md">
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
@@ -575,15 +629,15 @@
</div> </div>
</div> </div>
<div> <div>
<p>Site Description</p> <p>Site Description</p>
<q-input <q-input
v-model="data.admin.site_description" v-model="data.admin.site_description"
filled filled
type="textarea" type="textarea"
hint="Use plain text or raw HTML" hint="Use plain text or raw HTML"
/> />
</div> </div>
<br /> <br />
<div class="row q-col-gutter-md"> <div class="row q-col-gutter-md">
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<p>Default Wallet Name</p> <p>Default Wallet Name</p>
@@ -628,12 +682,15 @@
@keydown.enter="addAdSpace" @keydown.enter="addAdSpace"
type="text" type="text"
label="Ad image URL" label="Ad image URL"
hint="Ad image filepaths or urls, extensions can choose to honor"> hint="Ad image filepaths or urls, extensions can choose to honor"
>
<q-btn @click="addAdSpace" dense flat icon="add"></q-btn> <q-btn @click="addAdSpace" dense flat icon="add"></q-btn>
</q-input> </q-input>
<div> <div>
{% raw %} {% raw %}
<q-chip v-for="space in data.admin.ad_space" <q-chip
v-for="space in data.admin.ad_space"
:key="space"
removable removable
@remove="removeAdSpace(space)" @remove="removeAdSpace(space)"
color="primary" color="primary"
@@ -646,26 +703,19 @@
<br /> <br />
</div> </div>
</div> </div>
</div> </div>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn <q-btn unelevated color="primary" type="submit">Save</q-btn>
unelevated </div>
color="primary" </q-card-section>
type="submit" </q-tab-panel>
>Save</q-btn </q-tab-panels>
> </q-form>
</div>
</q-card-section>
</q-tab-panel>
</q-tab-panels>
</q-form>
</q-card> </q-card>
</div> </div>
</div> </div>
<!-- END TABS --> <!-- END TABS -->
<h3 class="q-my-none">Admin</h3>
<p></p>
<!-- <!--
Forked from: Forked from:
https://quasar.dev/vue-components/form#Example--Basic https://quasar.dev/vue-components/form#Example--Basic
@@ -1039,42 +1089,6 @@
</q-form> </q-form>
</q-card> </q-card>
</div> --> </div> -->
<div class="col-4">
<q-card class="q-mr-md">
<q-form class="q-px-md q-py-md" @submit="topupWallet">
<div class="text-h6" class="q-px-md">Wallet topup</div>
<div class="row">
<div class="col-8">
<q-input
type="text"
filled
v-model="wallet.data.id"
label="Wallet ID"
class="q-pr-md"
hint="Use the wallet ID to topup any wallet"
></q-input>
</div>
<div class="col-4">
<q-input
type="number"
filled
v-model="wallet.data.amount"
label="Topup amount"
></q-input>
</div>
</div>
<div>
<q-btn
class="q-mt-md"
label="Topup"
type="submit"
color="primary"
></q-btn>
</div>
</q-form>
</q-card>
</div>
</div> </div>
{% endblock %} {% block scripts %} {{ window_vars(user) }} {% endblock %} {% block scripts %} {{ window_vars(user) }}
@@ -1100,14 +1114,22 @@
'LnbitsWallet', 'LnbitsWallet',
'OpenNodeWallet' 'OpenNodeWallet'
], ],
admin: { admin: {
edited: [], edited: [],
funding: {}, funding: [],
senddata: {} senddata: {}
} }
}, },
themes: ['classic', 'bitcoin', 'flamingo', 'mint', 'autumn', 'monochrome', 'salvador'], themes: [
'classic',
'bitcoin',
'flamingo',
'mint',
'autumn',
'monochrome',
'salvador'
],
options: [ options: [
'bleskomat', 'bleskomat',
'captcha', 'captcha',
@@ -1139,10 +1161,13 @@
self.cancel.on = true self.cancel.on = true
} }
funding = JSON.parse(String('{{ funding | tojson|safe }}')) funding = JSON.parse(String('{{ funding | tojson|safe }}'))
var i funding.map(f => {
this.data.admin.funding.push(f)
})
/*var i
for (i = 0; i < funding.length; i++) { for (i = 0; i < funding.length; i++) {
self.data.admin.funding[funding[i].backend_wallet] = funding[i] self.data.admin.funding[funding[i].backend_wallet] = funding[i]
} }*/
let settings = JSON.parse('{{ settings | tojson|safe }}') let settings = JSON.parse('{{ settings | tojson|safe }}')
settings.balance = '{{ balance }}' settings.balance = '{{ balance }}'
this.data.admin = {...this.data.admin, ...settings} this.data.admin = {...this.data.admin, ...settings}
@@ -1150,42 +1175,42 @@
console.log(settings) console.log(settings)
}, },
methods: { methods: {
addAdminUser(){ addAdminUser() {
let addUser = this.data.admin_users_add let addUser = this.data.admin_users_add
let admin_users = this.data.admin.admin_users let admin_users = this.data.admin.admin_users
if(addUser.length && !admin_users.includes(addUser)){ if (addUser.length && !admin_users.includes(addUser)) {
admin_users.push(addUser) admin_users.push(addUser)
this.data.admin.admin_users = admin_users this.data.admin.admin_users = admin_users
this.data.admin_users_add = "" this.data.admin_users_add = ''
} }
}, },
removeAdminUser(user){ removeAdminUser(user) {
let admin_users = this.data.admin.admin_users let admin_users = this.data.admin.admin_users
this.data.admin.admin_users = admin_users.filter(u => u !== user) this.data.admin.admin_users = admin_users.filter(u => u !== user)
}, },
addAllowedUser(){ addAllowedUser() {
let addUser = this.data.allowed_users_add let addUser = this.data.allowed_users_add
let allowed_users = this.data.admin.allowed_users let allowed_users = this.data.admin.allowed_users
if(addUser.length && !allowed_users.includes(addUser)){ if (addUser.length && !allowed_users.includes(addUser)) {
allowed_users.push(addUser) allowed_users.push(addUser)
this.data.admin.allowed_users = allowed_users this.data.admin.allowed_users = allowed_users
this.data.allowed_users_add = "" this.data.allowed_users_add = ''
} }
}, },
removeAllowedUser(user){ removeAllowedUser(user) {
let allowed_users = this.data.admin.allowed_users let allowed_users = this.data.admin.allowed_users
this.data.admin.allowed_users = allowed_users.filter(u => u !== user) this.data.admin.allowed_users = allowed_users.filter(u => u !== user)
}, },
addAdSpace(){ addAdSpace() {
let adSpace = this.data.ad_space_add let adSpace = this.data.ad_space_add
let spaces = this.data.admin.ad_space let spaces = this.data.admin.ad_space
if(adSpace.length && !spaces.includes(adSpace)){ if (adSpace.length && !spaces.includes(adSpace)) {
spaces.push(adSpace) spaces.push(adSpace)
this.data.admin.ad_space = spaces this.data.admin.ad_space = spaces
this.data.ad_space_add = "" this.data.ad_space_add = ''
} }
}, },
removeAdSpace(ad){ removeAdSpace(ad) {
let spaces = this.data.admin.ad_space let spaces = this.data.admin.ad_space
this.data.admin.ad_space = spaces.filter(s => s !== ad) this.data.admin.ad_space = spaces.filter(s => s !== ad)
}, },
@@ -1199,14 +1224,14 @@
this.wallet.data.amount, this.wallet.data.amount,
this.g.user.wallets[0].adminkey this.g.user.wallets[0].adminkey
) )
.then((response) => { .then(response => {
this.$q.notify({ this.$q.notify({
type: 'positive', type: 'positive',
message: message:
'Success! Added ' + 'Success! Added ' +
this.wallet.data.amount + this.wallet.data.amount +
' to ' + ' to ' +
this.wallet.data.id, this.wallet.data.id,
icon: null icon: null
}) })
this.wallet.data = {} this.wallet.data = {}
@@ -1224,6 +1249,29 @@
self.data.admin.edited.push(source) self.data.admin.edited.push(source)
console.log(self.data.admin.edited) console.log(self.data.admin.edited)
}, },
updateFunding(fund) {
let data = this.data.admin.funding.find(v => v.backend_wallet == fund)
LNbits.api
.request(
'POST',
'/admin/api/v1/admin/funding',
this.g.user.wallets[0].adminkey,
data
)
.then(response => {
//let wallet = response.data.backend_wallet
//this.data.admin.funding[wallet] = response.data
//this.data.admin.funding[wallet].endpoint = response.data.endpoint
//console.log(this.data.admin.funding)
//console.log(this.data.admin)
this.$q.notify({
type: 'positive',
message: `Success! ${response.data.backend_wallet} changed!`,
icon: null
})
})
},
UpdateLNbits() { UpdateLNbits() {
let { let {
admin_users, admin_users,
@@ -1272,8 +1320,7 @@
console.log(response.data) console.log(response.data)
this.$q.notify({ this.$q.notify({
type: 'positive', type: 'positive',
message: message: 'Success! Settings changed!',
'Success! Settings changed!',
icon: null icon: null
}) })
}) })

View File

@@ -21,8 +21,7 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
admin = await get_admin() admin = await get_admin()
funding = [f.dict() for f in await get_funding()] funding = [f.dict() for f in await get_funding()]
error, balance = await g().WALLET.status() error, balance = await g().WALLET.status()
print("ADMIN", admin.dict())
print(g().admin_conf)
return admin_renderer().TemplateResponse( return admin_renderer().TemplateResponse(
"admin/index.html", { "admin/index.html", {
"request": request, "request": request,

View File

@@ -7,11 +7,11 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_wallet from lnbits.core.crud import get_wallet
from lnbits.decorators import WalletTypeInfo, require_admin_key from lnbits.decorators import WalletTypeInfo, require_admin_key
from lnbits.extensions.admin import admin_ext from lnbits.extensions.admin import admin_ext
from lnbits.extensions.admin.models import Admin, UpdateAdminSettings from lnbits.extensions.admin.models import Admin, Funding, UpdateAdminSettings
from lnbits.helpers import removeEmptyString from lnbits.helpers import removeEmptyString
from lnbits.requestvars import g from lnbits.requestvars import g
from .crud import get_admin, update_admin, update_wallet_balance from .crud import get_admin, update_admin, update_funding, update_wallet_balance
@admin_ext.get("/api/v1/admin/{wallet_id}/{topup_amount}", status_code=HTTPStatus.OK) @admin_ext.get("/api/v1/admin/{wallet_id}/{topup_amount}", status_code=HTTPStatus.OK)
@@ -53,3 +53,18 @@ async def api_update_admin(
print(g().admin_conf) print(g().admin_conf)
return {"status": "Success"} return {"status": "Success"}
@admin_ext.post("/api/v1/admin/funding/", status_code=HTTPStatus.OK)
async def api_update_funding(
request: Request,
data: Funding = Body(...),
w: WalletTypeInfo = Depends(require_admin_key)
):
admin = await get_admin()
if not admin.user == w.wallet.user:
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin"
)
funding = await update_funding(data=data)
return funding