Boltcard view page (#12)

This commit is contained in:
Tiago Vasconcelos 2023-08-22 17:41:38 +01:00 committed by GitHub
commit a823cf3e5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 186 additions and 1 deletions

View 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 %}

View file

@ -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>

View file

@ -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},
)

View file

@ -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]