Boltcard view page (#12)
This commit is contained in:
parent
f153c26517
commit
a823cf3e5d
4 changed files with 186 additions and 1 deletions
146
templates/boltcards/display.html
Normal file
146
templates/boltcards/display.html
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
{% extends "public.html" %} {% block toolbar_title %} Boltcard: ${
|
||||||
|
card.card_name }{% endblock %} {% block page %}
|
||||||
|
<div class="row q-col-gutter-md justify-center">
|
||||||
|
<div class="col-12 col-md-6 col-lg-5 q-gutter-y-md">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">Card Info</div>
|
||||||
|
<div class="text-subtitle2">This card is ${enabled}</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator dark inset></q-separator>
|
||||||
|
|
||||||
|
<q-card-section>
|
||||||
|
<q-list>
|
||||||
|
<q-item v-for="item in cardInfo">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label lines="1">${item.label}</q-item-label>
|
||||||
|
<q-item-label caption>${card[item.value]}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section
|
||||||
|
side
|
||||||
|
v-if="!['tx_limit', 'daily_limit'].includes(item.value)"
|
||||||
|
>
|
||||||
|
<q-tooltip>Click to copy</q-tooltip>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
icon="content_copy"
|
||||||
|
@click="copyText(item.value)"
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6 col-lg-5 q-gutter-y-md">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">Transactions</div>
|
||||||
|
<div class="text-subtitle2">Latest transactions</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator dark inset></q-separator>
|
||||||
|
|
||||||
|
<q-card-section>
|
||||||
|
<q-list>
|
||||||
|
<q-item v-for="hit in hits">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon
|
||||||
|
:name="hit.spent > 0 ? 'done_all' : 'done'"
|
||||||
|
:color="hit.spent > 0 ? 'green' : 'grey'"
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label
|
||||||
|
>ID: ${hit.id} ${refunds.some(r => r.hit_id == hit.id) ?
|
||||||
|
'(Refunded)' : null}</q-item-label
|
||||||
|
>
|
||||||
|
<q-item-label caption lines="1">IP: ${hit.ip}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-item-section side top>
|
||||||
|
<q-item-label caption>${hit.date}</q-item-label>
|
||||||
|
<q-item-label caption>${hit.amount} sats</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}{% block scripts %}
|
||||||
|
<script>
|
||||||
|
const mapHits = obj => {
|
||||||
|
obj.date = Quasar.utils.date.formatDate(
|
||||||
|
new Date(obj.time * 1000),
|
||||||
|
'YYYY-MM-DD HH:mm'
|
||||||
|
)
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
Vue.component(VueQrcode.name, VueQrcode)
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
el: '#vue',
|
||||||
|
delimiters: ['${', '}'],
|
||||||
|
mixins: [windowMixin],
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
card: null,
|
||||||
|
hits: null,
|
||||||
|
cardInfo: [
|
||||||
|
{
|
||||||
|
label: 'Card UID',
|
||||||
|
value: 'uid'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Auth Key',
|
||||||
|
value: 'k0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Meta Key',
|
||||||
|
value: 'k1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'File Key',
|
||||||
|
value: 'k2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Transaction Limit',
|
||||||
|
value: 'tx_limit'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Daily Limit',
|
||||||
|
value: 'daily_limit'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.card = JSON.parse('{{ card | tojson}}')
|
||||||
|
let hits = JSON.parse('{{ hits | tojson}}')
|
||||||
|
let refunds = JSON.parse('{{ refunds | tojson}}')
|
||||||
|
this.refunds = refunds || []
|
||||||
|
this.hits = hits.map(mapHits)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
enabled() {
|
||||||
|
return this.card.enable ? 'Enabled' : 'Disabled'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
copyText(text, message, position) {
|
||||||
|
Quasar.utils.copyToClipboard(text).then(() => {
|
||||||
|
this.$q.notify({
|
||||||
|
message: message || 'Copied to clipboard!',
|
||||||
|
position: position || 'bottom'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
{% raw %}
|
{% raw %}
|
||||||
<template v-slot:header="props">
|
<template v-slot:header="props">
|
||||||
<q-tr :props="props">
|
<q-tr :props="props">
|
||||||
|
<q-th auto-width></q-th>
|
||||||
<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">
|
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
{{ col.label }}
|
{{ col.label }}
|
||||||
|
|
@ -64,6 +65,19 @@
|
||||||
<q-tooltip>Card key credentials</q-tooltip>
|
<q-tooltip>Card key credentials</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
<q-td auto-width>
|
||||||
|
<q-btn
|
||||||
|
unelevated
|
||||||
|
dense
|
||||||
|
icon="query_stats"
|
||||||
|
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||||
|
type="a"
|
||||||
|
:href="'/boltcards/' + props.row.external_id"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<q-tooltip>Card Stats</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</q-td>
|
||||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
{{ col.value }}
|
{{ col.value }}
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
|
||||||
25
views.py
25
views.py
|
|
@ -1,11 +1,15 @@
|
||||||
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi import Depends, Request
|
from fastapi import Depends, Request
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
from starlette.exceptions import HTTPException
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
|
||||||
from lnbits.core.models import User
|
from lnbits.core.models import User
|
||||||
from lnbits.decorators import check_user_exists
|
from lnbits.decorators import check_user_exists
|
||||||
|
|
||||||
from . import boltcards_ext, boltcards_renderer
|
from . import boltcards_ext, boltcards_renderer
|
||||||
|
from .crud import get_card_by_external_id, get_hits, get_refunds
|
||||||
|
|
||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
|
||||||
|
|
@ -15,3 +19,24 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
return boltcards_renderer().TemplateResponse(
|
return boltcards_renderer().TemplateResponse(
|
||||||
"boltcards/index.html", {"request": request, "user": user.dict()}
|
"boltcards/index.html", {"request": request, "user": user.dict()}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@boltcards_ext.get("/{card_id}", response_class=HTMLResponse)
|
||||||
|
async def display(request: Request, card_id: str):
|
||||||
|
card = await get_card_by_external_id(card_id)
|
||||||
|
if not card:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=HTTPStatus.NOT_FOUND, detail="Card does not exist."
|
||||||
|
)
|
||||||
|
hits = [hit.dict() for hit in await get_hits([card.id])]
|
||||||
|
refunds = [
|
||||||
|
refund.hit_id for refund in await get_refunds([hit["id"] for hit in hits])
|
||||||
|
]
|
||||||
|
card = card.dict()
|
||||||
|
# Remove wallet id from card dict
|
||||||
|
del card["wallet"]
|
||||||
|
|
||||||
|
return boltcards_renderer().TemplateResponse(
|
||||||
|
"boltcards/display.html",
|
||||||
|
{"request": request, "card": card, "hits": hits, "refunds": refunds},
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ from .models import Card, CreateCardData
|
||||||
|
|
||||||
@boltcards_ext.get("/api/v1/cards")
|
@boltcards_ext.get("/api/v1/cards")
|
||||||
async def api_cards(
|
async def api_cards(
|
||||||
g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)
|
g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = False
|
||||||
):
|
):
|
||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue