lnbits-legend/lnbits/extensions/subdomains/templates/subdomains/index.html

550 lines
15 KiB
HTML

{% 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="domainDialog.show = true"
>New Domain</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">Domains</h5>
</div>
<div class="col-auto">
<q-btn flat color="grey" @click="exportDomainsCSV"
>Export to CSV</q-btn
>
</div>
</div>
<q-table
dense
flat
:data="domains"
row-key="id"
:columns="domainsTable.columns"
:pagination.sync="domainsTable.pagination"
>
{% raw %}
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width></q-th>
<q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label }}
</q-th>
<q-th auto-width></q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td auto-width>
<q-btn
unelevated
dense
size="xs"
icon="link"
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
type="a"
:href="props.row.displayUrl"
target="_blank"
></q-btn>
</q-td>
<q-td v-for="col in props.cols" :key="col.name" :props="props">
{{ col.value }}
</q-td>
<q-td auto-width>
<q-btn
flat
dense
size="xs"
@click="updateDomainDialog(props.row.id)"
icon="edit"
color="light-blue"
>
</q-btn>
</q-td>
<q-td auto-width>
<q-btn
flat
dense
size="xs"
@click="deleteDomain(props.row.id)"
icon="cancel"
color="pink"
></q-btn>
</q-td>
</q-tr>
</template>
{% endraw %}
</q-table>
</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">Subdomains</h5>
</div>
<div class="col-auto">
<q-btn flat color="grey" @click="exportSubdomainsCSV"
>Export to CSV</q-btn
>
</div>
</div>
<q-table
dense
flat
:data="subdomains"
row-key="id"
:columns="subdomainsTable.columns"
:pagination.sync="subdomainsTable.pagination"
>
{% raw %}
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width></q-th>
<q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label }}
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" v-if="props.row.paid">
<q-td auto-width>
<q-btn
unelevated
dense
size="xs"
icon="email"
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
type="a"
:href="'mailto:' + props.row.email"
></q-btn>
</q-td>
<q-td v-for="col in props.cols" :key="col.name" :props="props">
{{ col.value }}
</q-td>
<q-td auto-width>
<q-btn
flat
dense
size="xs"
@click="deleteSubdomain(props.row.id)"
icon="cancel"
color="pink"
></q-btn>
</q-td>
</q-tr>
</template>
{% endraw %}
</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}} Subdomain extension
</h6>
</q-card-section>
<q-card-section class="q-pa-none">
<q-separator></q-separator>
<q-list> {% include "subdomains/_api_docs.html" %} </q-list>
</q-card-section>
</q-card>
</div>
<q-dialog v-model="domainDialog.show" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="sendFormData" class="q-gutter-md">
<q-select
filled
dense
emit-value
v-model="domainDialog.data.wallet"
:options="g.user.walletOptions"
label="Wallet *"
>
</q-select>
<q-select
dense
filled
v-model="domainDialog.data.allowed_record_types"
multiple
:options="dnsRecordTypes"
label="Allowed record types"
></q-select>
<q-input
filled
dense
emit-value
v-model.trim="domainDialog.data.domain"
type="text"
label="Domain name "
></q-input>
<q-input
filled
dense
v-model.trim="domainDialog.data.cf_token"
type="text"
label="Cloudflare API token"
>
</q-input>
<q-input
filled
dense
v-model.trim="domainDialog.data.cf_zone_id"
type="text"
label="Cloudflare Zone Id"
>
</q-input>
<q-input
filled
dense
v-model.trim="domainDialog.data.webhook"
type="text"
label="Webhook (optional)"
hint="A URL to be called whenever this link receives a payment."
></q-input>
<q-input
filled
dense
v-model.trim="domainDialog.data.description"
type="textarea"
label="Description "
>
</q-input>
<q-input
filled
dense
v-model.number="domainDialog.data.cost"
type="number"
label="Amount per day in satoshis"
></q-input>
<div class="row q-mt-lg">
<q-btn
v-if="domainDialog.data.id"
unelevated
color="primary"
type="submit"
>Update Form</q-btn
>
<q-btn
v-else
unelevated
color="primary"
:disable="domainDialog.data.cost == null || domainDialog.data.cost < 0 || domainDialog.data.domain == null"
type="submit"
>Create Domain</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
</div>
{% endblock %} {% block scripts %} {{ window_vars(user) }}
<script>
var mapLNDomain = function (obj) {
obj.date = Quasar.utils.date.formatDate(
new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm'
)
obj.displayUrl = ['/subdomains/', obj.id].join('')
console.log(obj)
return obj
}
new Vue({
el: '#vue',
mixins: [windowMixin],
data: function () {
return {
domains: [],
subdomains: [],
dnsRecordTypes: [
'A',
'AAAA',
'CNAME',
'HTTPS',
'TXT',
'SRV',
'LOC',
'MX',
'NS',
'SPF',
'CERT',
'DNSKEY',
'DS',
'NAPTR',
'SMIMEA',
'SSHFP',
'SVCB',
'TLSA',
'URI'
],
domainsTable: {
columns: [
{name: 'id', align: 'left', label: 'ID', field: 'id'},
{
name: 'domain',
align: 'left',
label: 'Domain name',
field: 'domain'
},
{
name: 'allowed_record_types',
align: 'left',
label: 'Allowed record types',
field: 'allowed_record_types'
},
{name: 'wallet', align: 'left', label: 'Wallet', field: 'wallet'},
{
name: 'webhook',
align: 'left',
label: 'Webhook',
field: 'webhook'
},
{
name: 'description',
align: 'left',
label: 'Description',
field: 'description'
},
{
name: 'cost',
align: 'left',
label: 'Cost Per Day',
field: 'cost'
}
],
pagination: {
rowsPerPage: 10
}
},
subdomainsTable: {
columns: [
{
name: 'subdomain',
align: 'left',
label: 'Subdomain name',
field: 'subdomain'
},
{
name: 'domain',
align: 'left',
label: 'Domain name',
field: 'domain_name'
},
{
name: 'record_type',
align: 'left',
label: 'Record type',
field: 'record_type'
},
{
name: 'email',
align: 'left',
label: 'Email',
field: 'email'
},
{
name: 'ip',
align: 'left',
label: 'IP address',
field: 'ip'
},
{
name: 'sats',
align: 'left',
label: 'Sats paid',
field: 'sats'
},
{
name: 'duration',
align: 'left',
label: 'Duration in days',
field: 'duration'
},
{name: 'id', align: 'left', label: 'ID', field: 'id'}
],
pagination: {
rowsPerPage: 10
}
},
domainDialog: {
show: false,
data: {}
}
}
},
methods: {
getSubdomains: function () {
var self = this
LNbits.api
.request(
'GET',
'/subdomains/api/v1/subdomains?all_wallets=true',
this.g.user.wallets[0].inkey
)
.then(function (response) {
self.subdomains = response.data.map(function (obj) {
return mapLNDomain(obj)
})
})
},
deleteSubdomain: function (subdomainId) {
var self = this
var subdomains = _.findWhere(this.subdomains, {id: subdomainId})
LNbits.utils
.confirmDialog('Are you sure you want to delete this subdomain')
.onOk(function () {
LNbits.api
.request(
'DELETE',
'/subdomains/api/v1/subdomains/' + subdomainId,
_.findWhere(self.g.user.wallets, {id: subdomains.wallet}).inkey
)
.then(function (response) {
self.subdomains = _.reject(self.subdomains, function (obj) {
return obj.id == subdomainId
})
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
})
},
exportSubdomainsCSV: function () {
LNbits.utils.exportCSV(this.subdomainsTable.columns, this.subdomains)
},
getDomains: function () {
var self = this
LNbits.api
.request(
'GET',
'/subdomains/api/v1/domains?all_wallets=true',
this.g.user.wallets[0].inkey
)
.then(function (response) {
self.domains = response.data.map(function (obj) {
return mapLNDomain(obj)
})
})
},
sendFormData: function () {
var wallet = _.findWhere(this.g.user.wallets, {
id: this.domainDialog.data.wallet
})
var data = this.domainDialog.data
data.allowed_record_types =
typeof data.allowed_record_types === 'string'
? data.allowed_record_types
: data.allowed_record_types.join(', ')
console.log(this.domainDialog)
if (data.id) {
this.updateDomain(wallet, data)
} else {
this.createDomain(wallet, data)
}
},
createDomain: function (wallet, data) {
var self = this
LNbits.api
.request('POST', '/subdomains/api/v1/domains', wallet.inkey, data)
.then(function (response) {
self.domains.push(mapLNDomain(response.data))
self.domainDialog.show = false
self.domainDialog.data = {}
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
updateDomainDialog: function (formId) {
var link = _.findWhere(this.domains, {id: formId})
console.log(link.id)
this.domainDialog.data = _.clone(link)
this.domainDialog.data.allowed_record_types = link.allowed_record_types.split(
', '
)
this.domainDialog.show = true
},
updateDomain: function (wallet, data) {
var self = this
console.log(data)
LNbits.api
.request(
'PUT',
'/subdomains/api/v1/domains/' + data.id,
wallet.inkey,
data
)
.then(function (response) {
self.domains = _.reject(self.domains, function (obj) {
return obj.id == data.id
})
self.domains.push(mapLNDomain(response.data))
self.domainDialog.show = false
self.domainDialog.data = {}
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
deleteDomain: function (domainId) {
var self = this
var domains = _.findWhere(this.domains, {id: domainId})
LNbits.utils
.confirmDialog('Are you sure you want to delete this domain link?')
.onOk(function () {
LNbits.api
.request(
'DELETE',
'/subdomains/api/v1/domains/' + domainId,
_.findWhere(self.g.user.wallets, {id: domains.wallet}).inkey
)
.then(function (response) {
self.domains = _.reject(self.domains, function (obj) {
return obj.id == domainId
})
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
})
},
exportDomainsCSV: function () {
LNbits.utils.exportCSV(this.domainsTable.columns, this.domains)
}
},
created: function () {
if (this.g.user.wallets.length) {
this.getDomains()
this.getSubdomains()
}
}
})
</script>
{% endblock %}