changed name to myextension
This commit is contained in:
parent
ba7e11e30d
commit
0711f583d6
16 changed files with 221 additions and 225 deletions
79
templates/myextension/_api_docs.html
Normal file
79
templates/myextension/_api_docs.html
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<q-expansion-item
|
||||
group="extras"
|
||||
icon="swap_vertical_circle"
|
||||
label="API info"
|
||||
:content-inset-level="0.5"
|
||||
>
|
||||
<q-btn flat label="Swagger API" type="a" href="../docs#/myextension"></q-btn>
|
||||
<q-expansion-item group="api" dense expand-separator label="List MyExtension">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<code><span class="text-blue">GET</span> /myextension/api/v1/temps</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <invoice_key>}</code><br />
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 200 OK (application/json)
|
||||
</h5>
|
||||
<code>[<temp_object>, ...]</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X GET {{ request.base_url }}myextension/api/v1/temps -H "X-Api-Key:
|
||||
<invoice_key>"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
<q-expansion-item group="api" dense expand-separator label="Create a MyExtension">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<code><span class="text-green">POST</span> /myextension/api/v1/temps</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <invoice_key>}</code><br />
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||
<code
|
||||
>{"name": <string>, "currency": <string*ie USD*>}</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 201 CREATED (application/json)
|
||||
</h5>
|
||||
<code
|
||||
>{"currency": <string>, "id": <string>, "name":
|
||||
<string>, "wallet": <string>}</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X POST {{ request.base_url }}myextension/api/v1/temps -d '{"name":
|
||||
<string>, "currency": <string>}' -H "Content-type:
|
||||
application/json" -H "X-Api-Key: <admin_key>"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
|
||||
<q-expansion-item
|
||||
group="api"
|
||||
dense
|
||||
expand-separator
|
||||
label="Delete a MyExtension"
|
||||
class="q-pb-md"
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-pink">DELETE</span>
|
||||
/myextension/api/v1/temps/<myextension_id></code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <admin_key>}</code><br />
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Returns 204 NO CONTENT</h5>
|
||||
<code></code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X DELETE {{ request.base_url
|
||||
}}myextension/api/v1/temps/<myextension_id> -H "X-Api-Key: <admin_key>"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
</q-expansion-item>
|
||||
18
templates/myextension/_myextension.html
Normal file
18
templates/myextension/_myextension.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<q-expansion-item group="extras" icon="info" label="About MyExtension">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<p>
|
||||
MyExtension extension is a basic extension that you can use to get started building your own extension
|
||||
</p>
|
||||
<small
|
||||
>Created by
|
||||
<a
|
||||
class="text-secondary"
|
||||
href="https://github.com/benarc"
|
||||
target="_blank"
|
||||
>Ben Arc</a
|
||||
>.</small
|
||||
>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
396
templates/myextension/index.html
Normal file
396
templates/myextension/index.html
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
|
||||
%} {% block page %}
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<q-btn unelevated color="primary" @click="formDialog.show = true"
|
||||
>New MyExtension</q-btn
|
||||
>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col">
|
||||
<h5 class="text-subtitle1 q-my-none">MyExtension</h5>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn flat color="grey" @click="exportCSV">Export to CSV</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
flat
|
||||
:data="temps"
|
||||
row-key="id"
|
||||
:columns="tempsTable.columns"
|
||||
:pagination.sync="tempsTable.pagination"
|
||||
>
|
||||
<myextension v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||
${ col.label }
|
||||
</q-th>
|
||||
</q-tr>
|
||||
</myextension>
|
||||
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props">
|
||||
<q-td
|
||||
v-for="col in props.cols"
|
||||
:key="col.name"
|
||||
:props="props"
|
||||
>
|
||||
${ col.value }
|
||||
</q-td>
|
||||
<q-td auto-width>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
size="sm"
|
||||
icon="qr_code"
|
||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
class="q-mr-sm"
|
||||
@click="openUrlDialog(props.row.id)"
|
||||
></q-btn></q-td>
|
||||
<q-td auto-width>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
size="sm"
|
||||
icon="launch"
|
||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
type="a"
|
||||
:href="props.row.myextension"
|
||||
target="_blank"
|
||||
><q-tooltip>Open public page</q-tooltip></q-btn
|
||||
></q-td>
|
||||
<q-td auto-width>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
size="md"
|
||||
copy="copy"
|
||||
@click="copyText(props.row.id)"
|
||||
><q-tooltip>Click to copy</q-tooltip
|
||||
>${props.row.id.substring(0,6)}...</q-btn
|
||||
>
|
||||
</q-td>
|
||||
|
||||
|
||||
</q-tr>
|
||||
</template>
|
||||
|
||||
</q-table>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4 col-lg-5 q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<h6 class="text-subtitle1 q-my-none">{{SITE_TITLE}} MyExtension extension</h6>
|
||||
<p>Simple extension you can use as a base for your own extension. <br/> Includes very simple LNURL-pay and LNURL-withdraw example.</p>
|
||||
</q-card-section>
|
||||
<q-card-section class="q-pa-none">
|
||||
<q-separator></q-separator>
|
||||
<q-list>
|
||||
{% include "myextension/_api_docs.html" %}
|
||||
<q-separator></q-separator>
|
||||
{% include "myextension/_myextension.html" %}
|
||||
</q-list>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<q-dialog v-model="formDialog.show" position="top" @hide="closeFormDialog">
|
||||
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
||||
<q-form @submit="sendTPosData" class="q-gutter-md">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="formDialog.data.name"
|
||||
label="Name"
|
||||
placeholder="Name for your record"
|
||||
></q-input>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model="formDialog.data.wallet"
|
||||
:options="g.user.walletOptions"
|
||||
label="Wallet *"
|
||||
></q-select>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
type="number"
|
||||
v-model.trim="formDialog.data.lnurlwithdrawamount"
|
||||
label="LNURL-withdraw amount"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
type="number"
|
||||
v-model.trim="formDialog.data.lnurlpayamount"
|
||||
label="LNURL-pay amount"
|
||||
></q-input>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
v-if="formDialog.data.id"
|
||||
unelevated
|
||||
color="primary"
|
||||
type="submit"
|
||||
>Update MyExtension</q-btn
|
||||
>
|
||||
<q-btn
|
||||
v-else
|
||||
unelevated
|
||||
color="primary"
|
||||
:disable="formDialog.data.name == null || formDialog.data.wallet == null || formDialog.data.lnurlwithdrawamount == null || formDialog.data.lnurlpayamount == null"
|
||||
type="submit"
|
||||
>Create MyExtension</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
||||
>Cancel</q-btn
|
||||
>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog v-model="urlDialog.show" position="top">
|
||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
||||
<lnbits-qrcode :value="urlDialog.data.lnurlpay"></lnbits-qrcode>
|
||||
</q-responsive>
|
||||
<div class="text-center q-mb-xl">
|
||||
<p style="word-break: break-all">
|
||||
<strong>${ urlDialog.data.lnurlpay }</strong><br />${
|
||||
urlDialog.data.shareUrl }
|
||||
</p>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
@click="copyText(urlDialog.data.lnurlpay, 'MyExtension URL copied to clipboard!')"
|
||||
>Copy URL</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn>
|
||||
</div>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||
<script>
|
||||
// The object returned here will be merged with the data object of the Vue instance
|
||||
const mapTemp = obj => {
|
||||
obj.date = Quasar.utils.date.formatDate(
|
||||
new Date(obj.time * 1000),
|
||||
'YYYY-MM-DD HH:mm'
|
||||
)
|
||||
obj.myextension = ['/myextension/', obj.id].join('')
|
||||
return obj
|
||||
}
|
||||
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
mixins: [windowMixin],
|
||||
delimiters: ['${', '}'],
|
||||
data: function () {
|
||||
return {
|
||||
temps: [],
|
||||
tempsTable: {
|
||||
columns: [
|
||||
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
||||
{name: 'name', align: 'left', label: 'Name', field: 'name'},
|
||||
{
|
||||
name: 'wallet',
|
||||
align: 'left',
|
||||
label: 'Wallet',
|
||||
field: 'wallet'
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
rowsPerPage: 10
|
||||
}
|
||||
},
|
||||
formDialog: {
|
||||
show: false,
|
||||
data: {
|
||||
withdrawpin: 878787,
|
||||
tip_options: [],
|
||||
withdrawbtwn: 10
|
||||
},
|
||||
advanced: {
|
||||
tips: false,
|
||||
otc: false
|
||||
}
|
||||
},
|
||||
urlDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeFormDialog() {
|
||||
this.formDialog.show = false
|
||||
this.formDialog.data = {
|
||||
withdrawpin: 878787,
|
||||
tip_options: [],
|
||||
withdrawbtwn: 10
|
||||
}
|
||||
},
|
||||
getTemps: function () {
|
||||
var self = this
|
||||
|
||||
LNbits.api
|
||||
.request(
|
||||
'GET',
|
||||
'/myextension/api/v1/temps?all_wallets=true',
|
||||
this.g.user.wallets[0].inkey
|
||||
)
|
||||
.then(function (response) {
|
||||
self.temps = response.data.map(function (obj) {
|
||||
return mapTemp(obj)
|
||||
})
|
||||
})
|
||||
},
|
||||
sendTPosData() {
|
||||
const data = {
|
||||
name: this.formDialog.data.name,
|
||||
lnurlwithdrawamount: this.formDialog.data.lnurlwithdrawamount,
|
||||
lnurlpayamount: this.formDialog.data.lnurlpayamount
|
||||
}
|
||||
const wallet = _.findWhere(this.g.user.wallets, {
|
||||
id: this.formDialog.data.wallet
|
||||
})
|
||||
console.log(data)
|
||||
console.log(wallet)
|
||||
if (data.id) {
|
||||
this.updateTPos(wallet, data)
|
||||
} else {
|
||||
this.createTemp(wallet, data)
|
||||
}
|
||||
},
|
||||
updateTPosForm(tempId) {
|
||||
const myextension = _.findWhere(this.temps, {id: tempId})
|
||||
this.formDialog.data = {
|
||||
...myextension,
|
||||
tip_options: JSON.parse(myextension.tip_options)
|
||||
}
|
||||
if (this.formDialog.data.tip_wallet != '') {
|
||||
this.formDialog.advanced.tips = true
|
||||
}
|
||||
if (this.formDialog.data.withdrawlimit >= 1) {
|
||||
this.formDialog.advanced.otc = true
|
||||
}
|
||||
this.formDialog.show = true
|
||||
},
|
||||
createTemp(wallet, data) {
|
||||
LNbits.api
|
||||
.request('POST', '/myextension/api/v1/temps', wallet.inkey, data)
|
||||
.then(response => {
|
||||
this.temps.push(mapTemp(response.data))
|
||||
this.closeFormDialog()
|
||||
})
|
||||
.catch(error => {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
updateTPos(wallet, data) {
|
||||
LNbits.api
|
||||
.request(
|
||||
'PUT',
|
||||
`/myextension/api/v1/temps/${data.id}`,
|
||||
wallet.adminkey,
|
||||
data
|
||||
)
|
||||
.then(response => {
|
||||
this.temps = _.reject(this.temps, obj => {
|
||||
return obj.id == data.id
|
||||
})
|
||||
this.temps.push(mapTemp(response.data))
|
||||
this.closeFormDialog()
|
||||
})
|
||||
.catch(error => {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
deleteTemp: function (tempId) {
|
||||
var self = this
|
||||
var myextension = _.findWhere(this.temps, {id: tempId})
|
||||
|
||||
LNbits.utils
|
||||
.confirmDialog('Are you sure you want to delete this MyExtension?')
|
||||
.onOk(function () {
|
||||
LNbits.api
|
||||
.request(
|
||||
'DELETE',
|
||||
'/myextension/api/v1/temps/' + tempId,
|
||||
_.findWhere(self.g.user.wallets, {id: myextension.wallet}).adminkey
|
||||
)
|
||||
.then(function (response) {
|
||||
self.temps = _.reject(self.temps, function (obj) {
|
||||
return obj.id == tempId
|
||||
})
|
||||
})
|
||||
.catch(function (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
exportCSV: function () {
|
||||
LNbits.utils.exportCSV(this.tempsTable.columns, this.temps)
|
||||
},
|
||||
itemsArray(tempId) {
|
||||
const myextension = _.findWhere(this.temps, {id: tempId})
|
||||
return [...myextension.itemsMap.values()]
|
||||
},
|
||||
itemFormatPrice(price, id) {
|
||||
const myextension = id.split(':')[0]
|
||||
const currency = _.findWhere(this.temps, {id: myextension}).currency
|
||||
return LNbits.utils.formatCurrency(Number(price).toFixed(2), currency)
|
||||
},
|
||||
openformDialog(id) {
|
||||
const [tempId, itemId] = id.split(':')
|
||||
const myextension = _.findWhere(this.temps, {id: tempId})
|
||||
if (itemId) {
|
||||
const item = myextension.itemsMap.get(id)
|
||||
this.formDialog.data = {
|
||||
...item,
|
||||
myextension: tempId
|
||||
}
|
||||
} else {
|
||||
this.formDialog.data.myextension = tempId
|
||||
}
|
||||
this.formDialog.data.currency = myextension.currency
|
||||
this.formDialog.show = true
|
||||
},
|
||||
closeformDialog() {
|
||||
this.formDialog.show = false
|
||||
this.formDialog.data = {
|
||||
title: '',
|
||||
image: '',
|
||||
price: '',
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
openUrlDialog(id) {
|
||||
this.urlDialog.data = _.findWhere(this.temps, {id})
|
||||
this.urlDialog.show = true
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
if (this.g.user.wallets.length) {
|
||||
this.getTemps()
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
65
templates/myextension/myextension.html
Normal file
65
templates/myextension/myextension.html
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
{% extends "public.html" %} {% block page %}
|
||||
<div class="row q-col-gutter-md justify-center">
|
||||
<div class="col-12 col-sm-6 col-md-5 col-lg-4">
|
||||
<q-card class="q-pa-lg">
|
||||
<q-card-section class="q-pa-none">
|
||||
<div class="text-center">
|
||||
<a class="text-secondary" href="lightning:{{ lnurl }}">
|
||||
<q-responsive :ratio="1" class="q-mx-md">
|
||||
<qrcode
|
||||
value="lightning:{{ lnurl }}"
|
||||
:options="{width: 800}"
|
||||
class="rounded-borders"
|
||||
></qrcode>
|
||||
</q-responsive>
|
||||
</a>
|
||||
</div>
|
||||
<div class="row q-mt-lg q-gutter-sm">
|
||||
<q-btn outline color="grey" @click="copyText('{{ lnurl }}')"
|
||||
>Copy LNURL</q-btn
|
||||
>
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
icon="nfc"
|
||||
@click="writeNfcTag(' {{ lnurl }} ')"
|
||||
:disable="nfcTagWriting"
|
||||
></q-btn>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-5 col-lg-4 q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<h6 class="text-subtitle1 q-mb-sm q-mt-none">LNbits LNURL-pay link</h6>
|
||||
<p class="q-my-none">Use an LNURL compatible bitcoin wallet to pay.</p>
|
||||
</q-card-section>
|
||||
<q-card-section class="q-pa-none">
|
||||
<q-separator></q-separator>
|
||||
<q-list> </q-list>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
return {
|
||||
lnurlpay: "",
|
||||
lnurlwithdraw: "",
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
if (this.g.user.wallets.length) {
|
||||
this.getTemps()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue