working subdomains frontend, table, popup, payments

This commit is contained in:
Kristjan 2020-12-29 20:52:54 +01:00
parent c0d7371137
commit 6c4b5ea406
7 changed files with 143 additions and 52 deletions

View File

@ -16,13 +16,14 @@ async def create_subdomain(
email: str,
ip: str,
sats: int,
duration: int
) -> Subdomains:
await db.execute(
"""
INSERT INTO subdomain (id, domain, email, subdomain, ip, wallet, sats, paid)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
INSERT INTO subdomain (id, domain, email, subdomain, ip, wallet, sats, duration, paid)
VALUES (?, ?, ?, ?, ?, ?, ?, ?,?)
""",
(payment_hash, domain, email, subdomain, ip, wallet, sats, False),
(payment_hash, domain, email, subdomain, ip, wallet, sats, duration, False),
)
subdomain = await get_subdomain(payment_hash)
@ -32,7 +33,7 @@ async def create_subdomain(
async def set_subdomain_paid(payment_hash: str) -> Subdomains:
row = await db.fetchone("SELECT * FROM subdomain WHERE id = ?", (payment_hash,))
if row[7] == False:
if row[8] == False:
await db.execute(
"""
UPDATE subdomain
@ -45,7 +46,7 @@ async def set_subdomain_paid(payment_hash: str) -> Subdomains:
domaindata = await get_domain(row[1])
assert domaindata, "Couldn't get domain from paid subdomain"
amount = domaindata.amountmade + row[7]
amount = domaindata.amountmade + row[8]
await db.execute(
"""
UPDATE domain
@ -77,7 +78,7 @@ async def set_subdomain_paid(payment_hash: str) -> Subdomains:
async def get_subdomain(subdomain_id: str) -> Optional[Subdomains]:
row = await db.fetchone("SELECT * FROM subdomain WHERE id = ?", (subdomain_id,))
row = await db.fetchone("SELECT * FROM subdomain s INNER JOIN domain d ON (s.domain = d.id) WHERE s.id = ?", (subdomain_id,))
return Subdomains(**row) if row else None
@ -86,7 +87,7 @@ async def get_subdomains(wallet_ids: Union[str, List[str]]) -> List[Subdomains]:
wallet_ids = [wallet_ids]
q = ",".join(["?"] * len(wallet_ids))
rows = await db.fetchall(f"SELECT * FROM subdomain WHERE wallet IN ({q})", (*wallet_ids,))
rows = await db.fetchall(f"SELECT s.*, d.domain as domain_name FROM subdomain s INNER JOIN domain d ON (s.domain = d.id) WHERE s.wallet IN ({q})", (*wallet_ids,))
return [Subdomains(**row) for row in rows]

View File

@ -27,6 +27,7 @@ async def m001_initial(db):
ip TEXT NOT NULL,
wallet TEXT NOT NULL,
sats INTEGER NOT NULL,
duration INTEGER NOT NULL,
paid BOOLEAN NOT NULL,
time TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now'))
);

View File

@ -18,9 +18,11 @@ class Subdomains(NamedTuple):
id: str
wallet: str
domain: str
domain_name: str
subdomain: str
email: str
ip: str
sats: int
duration: int
paid: bool
time: int

View File

@ -3,9 +3,9 @@
<div class="col-12 col-md-7 col-lg-6 q-gutter-y-md">
<q-card class="q-pa-lg">
<q-card-section class="q-pa-none">
<h3 class="q-my-none">{{ form_domain }}</h3>
<h3 class="q-my-none">{{ domain_domain }}</h3>
<br />
<h5 class="q-my-none">{{ form_desc }}</h5>
<h5 class="q-my-none">{{ domain_desc }}</h5>
<br />
<q-form @submit="Invoice()" class="q-gutter-md">
<q-input filled dense v-model.trim="formDialog.data.email" type="email"
@ -14,7 +14,7 @@
</q-input>
<q-input filled dense v-model.trim="formDialog.data.ip" type="text" label="ip of your server">
</q-input>
<q-input filled dense v-model.trim="formDialog.data.duration" type="number" label="{{ form_cost }} sats per day">
<q-input filled dense v-model.trim="formDialog.data.duration" type="number" label="{{ domain_cost }} sats per day">
</q-input>
<p>{% raw %}{{amountSats}}{% endraw %}</p>
<div class="row q-mt-lg">
@ -48,7 +48,7 @@
{% endblock %} {% block scripts %}
<script>
console.log('{{ form_cost }}')
console.log('{{ domain_cost }}')
Vue.component(VueQrcode.name, VueQrcode)
new Vue({
@ -76,8 +76,8 @@
},
computed: {
amountSats() {
var sats = this.formDialog.data.duration * parseInt('{{ form_cost }}')
if (sats === parseInt('{{ form_cost }}')) {
var sats = this.formDialog.data.duration * parseInt('{{ domain_cost }}')
if (sats === parseInt('{{ domain_cost }}')) {
return '0 Sats to pay'
} else {
this.formDialog.data.sats = sats
@ -111,6 +111,7 @@
ip: self.formDialog.data.ip,
email: self.formDialog.data.email,
sats: self.formDialog.data.sats,
duration: parseInt(self.formDialog.data.duration),
})
.then(function (response) {
self.paymentReq = response.data.payment_request
@ -131,6 +132,7 @@
axios
.get('/subdomains/api/v1/subdomains/' + self.paymentCheck)
.then(function (res) {
console.log(res.data)
if (res.data.paid) {
clearInterval(paymentChecker)
self.receive = {
@ -140,25 +142,28 @@
}
dismissMsg()
this.formDialog.data.subdomain = ''
this.formDialog.data.email = ''
this.formDialog.data.ip = ''
this.formDialog.data.duration = ''
console.log(self.formDialog)
self.formDialog.data.subdomain = ''
self.formDialog.data.email = ''
self.formDialog.data.ip = ''
self.formDialog.data.duration = ''
self.$q.notify({
type: 'positive',
message: 'Sent, thank you!',
icon: 'thumb_up',
})
console.log("END")
}
})
.catch(function (error) {
console.log(error)
LNbits.utils.notifyApiError(error)
})
}, 2000)
})
.catch(function (error) {
console.log(error)
LNbits.utils.notifyApiError(error)
})
}

View File

@ -53,8 +53,52 @@
</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>
<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">
@ -68,7 +112,8 @@
</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.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"></q-input>
<div class="row q-mt-lg">
<q-btn v-if="domainDialog.data.id" unelevated color="deep-purple" type="submit">Update Form</q-btn>
@ -90,8 +135,8 @@
new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm'
)
obj.fsat = new Intl.NumberFormat(LOCALE).format(obj.amount)
obj.displayUrl = ['/subdomains/', obj.id].join('')
console.log(obj)
return obj
}
@ -101,12 +146,13 @@
data: function () {
return {
domains: [],
subdomains: [],
domainsTable: {
columns: [
{name: 'id', align: 'left', label: 'ID', field: 'id'},
{name: 'domain', align: 'left', label: 'Domain name', field: 'domain'},
{name: 'wallet', align: 'left', label: 'Wallet', field: 'wallet'},
{name: 'webhook', align: 'left', label: 'Webhook', field: 'webhook'},
{ name: 'id', align: 'left', label: 'ID', field: 'id' },
{ name: 'domain', align: 'left', label: 'Domain name', field: 'domain' },
{ name: 'wallet', align: 'left', label: 'Wallet', field: 'wallet' },
{ name: 'webhook', align: 'left', label: 'Webhook', field: 'webhook' },
{
name: 'description',
align: 'left',
@ -124,6 +170,40 @@
rowsPerPage: 10
},
},
subdomainsTable: {
columns: [
{ name: 'subdomain', align: 'left', label: 'Subdomain name', field: 'subdomain' },
{ name: 'domain', align: 'left', label: 'Domain name', field: 'domain_name' },
{
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: {}
@ -134,35 +214,35 @@
getSubdomains: function () {
var self = this
LNbits.api
LNbits.api
.request(
'GET',
'/subdomains/api/v1/subdomains?all_wallets',
this.g.user.wallets[0].inkey
)
.then(function (response) {
self.tickets = response.data.map(function (obj) {
return mapLNSubdomain(obj)
self.subdomains = response.data.map(function (obj) {
return mapLNDomain(obj)
})
})
},
deleteSubdomain: function (subdomainId) {
var self = this
var tickets = _.findWhere(this.tickets, {id: ticketId})
var subdomains = _.findWhere(this.subdomains, { id: subdomainId })
LNbits.utils
.confirmDialog('Are you sure you want to delete this ticket')
.confirmDialog('Are you sure you want to delete this subdomain')
.onOk(function () {
LNbits.api
.request(
'DELETE',
'/subdomain/api/v1/subdomains/' + subdomainId,
_.findWhere(self.g.user.wallets, {id: subdomains.wallet}).inkey
_.findWhere(self.g.user.wallets, { id: subdomains.wallet }).inkey
)
.then(function (response) {
self.tickets = _.reject(self.tickets, function (obj) {
return obj.id == ticketId
self.subdomains = _.reject(self.subdomains, function (obj) {
return obj.id == subdomainId
})
})
.catch(function (error) {
@ -172,7 +252,7 @@
},
exportSubdomainsCSV: function () {
LNbits.utils.exportCSV(this.domainsTable.columns, this.tickets)
LNbits.utils.exportCSV(this.subdomainsTable.columns, this.subdomains)
},
getDomains: function () {
@ -220,7 +300,7 @@
},
updateDomainDialog: function (formId) {
var link = _.findWhere(this.domains, {id: formId})
var link = _.findWhere(this.domains, { id: formId })
console.log(link.id)
this.domainDialog.data.id = link.id
this.domainDialog.data.wallet = link.wallet
@ -259,7 +339,7 @@
},
deleteDomain: function (domainId) {
var self = this
var domains = _.findWhere(this.domains, {id: domainId})
var domains = _.findWhere(this.domains, { id: domainId })
LNbits.utils
.confirmDialog('Are you sure you want to delete this domain link?')
@ -268,7 +348,7 @@
.request(
'DELETE',
'/subdomains/api/v1/domains/' + domainId,
_.findWhere(self.g.user.wallets, {id: domains.wallet}).inkey
_.findWhere(self.g.user.wallets, { id: domains.wallet }).inkey
)
.then(function (response) {
self.domains = _.reject(self.domains, function (obj) {

View File

@ -22,6 +22,6 @@ async def display(domain_id):
"subdomains/display.html",
domain_id=domain.id,
domain_domain=domain.domain,
form_desc=domain.description,
form_cost=domain.cost,
domain_desc=domain.description,
domain_cost=domain.cost,
)

View File

@ -103,6 +103,7 @@ async def api_subdomains():
"email": {"type": "string", "empty": True, "required": True},
"ip": {"type": "string", "empty": False, "required": True},
"sats": {"type": "integer", "min": 0, "required": True},
"duration": {"type": "integer", "empty": False, "required": True},
}
)
async def api_subdomain_make_subdomain(domain_id):
@ -110,12 +111,13 @@ async def api_subdomain_make_subdomain(domain_id):
if not domain:
return jsonify({"message": "LNsubdomain does not exist."}), HTTPStatus.NOT_FOUND
subdomain = len(re.split(r"\s+", g.data["subdomain"]))
subdomain = g.data["subdomain"]
duration = g.data["duration"]
sats = g.data["sats"]
payment_hash, payment_request = await create_invoice(
wallet_id=domain.wallet,
amount=sats,
memo=f"subdomain with {subdomain} words on {domain_id}",
memo=f"subdomain {subdomain}.{domain.domain} for {sats} sats for {duration} days",
extra={"tag": "lnsubdomain"},
)