Browse Source

working subdomains frontend, table, popup, payments

master
Kristjan 4 years ago
parent
commit
6c4b5ea406
  1. 15
      lnbits/extensions/subdomains/crud.py
  2. 1
      lnbits/extensions/subdomains/migrations.py
  3. 2
      lnbits/extensions/subdomains/models.py
  4. 27
      lnbits/extensions/subdomains/templates/subdomains/display.html
  5. 140
      lnbits/extensions/subdomains/templates/subdomains/index.html
  6. 4
      lnbits/extensions/subdomains/views.py
  7. 6
      lnbits/extensions/subdomains/views_api.py

15
lnbits/extensions/subdomains/crud.py

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

1
lnbits/extensions/subdomains/migrations.py

@ -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'))
);

2
lnbits/extensions/subdomains/models.py

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

27
lnbits/extensions/subdomains/templates/subdomains/display.html

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

140
lnbits/extensions/subdomains/templates/subdomains/index.html

@ -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: {}
@ -133,51 +213,51 @@
methods: {
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) {
LNbits.utils.notifyApiError(error)
})
})
},
exportSubdomainsCSV: function () {
LNbits.utils.exportCSV(this.domainsTable.columns, this.tickets)
LNbits.utils.exportCSV(this.subdomainsTable.columns, this.subdomains)
},
getDomains: function () {
var self = this
LNbits.api
.request(
'GET',
@ -189,7 +269,7 @@
return mapLNDomain(obj)
})
})
},
sendFormData: function () {
var wallet = _.findWhere(this.g.user.wallets, {
@ -206,7 +286,7 @@
createDomain: function (wallet, data) {
var self = this
LNbits.api
.request('POST', '/subdomains/api/v1/domains', wallet.inkey, data)
.then(function (response) {
@ -217,10 +297,10 @@
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
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
@ -235,7 +315,7 @@
updateDomain: function (wallet, data) {
var self = this
console.log(data)
LNbits.api
.request(
@ -255,12 +335,12 @@
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
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?')
.onOk(function () {
@ -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) {
@ -279,7 +359,7 @@
LNbits.utils.notifyApiError(error)
})
})
},
exportDomainsCSV: function () {
LNbits.utils.exportCSV(this.domainsTable.columns, this.domains)

4
lnbits/extensions/subdomains/views.py

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

6
lnbits/extensions/subdomains/views_api.py

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

Loading…
Cancel
Save