feat: update to v1.0.0 (#30)
This commit is contained in:
parent
2bdbbb274d
commit
73054fd5ce
20 changed files with 2029 additions and 2132 deletions
290
static/components/relay-details.js
Normal file
290
static/components/relay-details.js
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
window.app.component('relay-details', {
|
||||
name: 'relay-details',
|
||||
template: '#relay-details',
|
||||
props: ['relay-id', 'adminkey', 'inkey', 'wallet-options'],
|
||||
data() {
|
||||
return {
|
||||
tab: 'info',
|
||||
relay: null,
|
||||
accounts: [],
|
||||
accountPubkey: '',
|
||||
formDialogItem: {
|
||||
show: false,
|
||||
data: {
|
||||
name: '',
|
||||
description: ''
|
||||
}
|
||||
},
|
||||
showBlockedAccounts: true,
|
||||
showAllowedAccounts: false,
|
||||
accountsTable: {
|
||||
columns: [
|
||||
{
|
||||
name: 'action',
|
||||
align: 'left',
|
||||
label: '',
|
||||
field: ''
|
||||
},
|
||||
{
|
||||
name: 'pubkey',
|
||||
align: 'left',
|
||||
label: 'Public Key',
|
||||
field: 'pubkey'
|
||||
},
|
||||
{
|
||||
name: 'allowed',
|
||||
align: 'left',
|
||||
label: 'Allowed',
|
||||
field: 'allowed'
|
||||
},
|
||||
{
|
||||
name: 'blocked',
|
||||
align: 'left',
|
||||
label: 'Blocked',
|
||||
field: 'blocked'
|
||||
},
|
||||
{
|
||||
name: 'paid_to_join',
|
||||
align: 'left',
|
||||
label: 'Paid to join',
|
||||
field: 'paid_to_join'
|
||||
},
|
||||
{
|
||||
name: 'sats',
|
||||
align: 'left',
|
||||
label: 'Spent Sats',
|
||||
field: 'sats'
|
||||
},
|
||||
{
|
||||
name: 'storage',
|
||||
align: 'left',
|
||||
label: 'Storage',
|
||||
field: 'storage'
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
rowsPerPage: 10
|
||||
}
|
||||
},
|
||||
skipEventKind: 0,
|
||||
forceEventKind: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
hours() {
|
||||
const y = []
|
||||
for (let i = 0; i <= 24; i++) {
|
||||
y.push(i)
|
||||
}
|
||||
return y
|
||||
},
|
||||
range60() {
|
||||
const y = []
|
||||
for (let i = 0; i <= 60; i++) {
|
||||
y.push(i)
|
||||
}
|
||||
return y
|
||||
},
|
||||
storageUnits() {
|
||||
return ['KB', 'MB']
|
||||
},
|
||||
fullStorageActions() {
|
||||
return [
|
||||
{value: 'block', label: 'Block New Events'},
|
||||
{value: 'prune', label: 'Prune Old Events'}
|
||||
]
|
||||
},
|
||||
wssLink() {
|
||||
this.relay.meta.domain =
|
||||
this.relay.meta.domain || window.location.hostname
|
||||
return 'wss://' + this.relay.meta.domain + '/nostrrelay/' + this.relay.id
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
satBtc(val, showUnit = true) {
|
||||
return satOrBtc(val, showUnit, this.satsDenominated)
|
||||
},
|
||||
deleteRelay() {
|
||||
LNbits.utils
|
||||
.confirmDialog(
|
||||
'All data will be lost! Are you sure you want to delete this relay?'
|
||||
)
|
||||
.onOk(async () => {
|
||||
try {
|
||||
await LNbits.api.request(
|
||||
'DELETE',
|
||||
'/nostrrelay/api/v1/relay/' + this.relayId,
|
||||
this.adminkey
|
||||
)
|
||||
this.$emit('relay-deleted', this.relayId)
|
||||
Quasar.Notify.create({
|
||||
type: 'positive',
|
||||
message: 'Relay Deleted',
|
||||
timeout: 5000
|
||||
})
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
})
|
||||
},
|
||||
async getRelay() {
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'GET',
|
||||
'/nostrrelay/api/v1/relay/' + this.relayId,
|
||||
this.inkey
|
||||
)
|
||||
this.relay = data
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
async updateRelay() {
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'PATCH',
|
||||
'/nostrrelay/api/v1/relay/' + this.relayId,
|
||||
this.adminkey,
|
||||
this.relay
|
||||
)
|
||||
this.relay = data
|
||||
this.$emit('relay-updated', this.relay)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Relay Updated',
|
||||
timeout: 5000
|
||||
})
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
togglePaidRelay: async function () {
|
||||
this.relay.meta.wallet =
|
||||
this.relay.meta.wallet || this.walletOptions[0].value
|
||||
},
|
||||
getAccounts: async function () {
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'GET',
|
||||
`/nostrrelay/api/v1/account?relay_id=${this.relay.id}&allowed=${this.showAllowedAccounts}&blocked=${this.showBlockedAccounts}`,
|
||||
this.inkey
|
||||
)
|
||||
this.accounts = data
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
allowPublicKey: async function (pubkey, allowed) {
|
||||
await this.updatePublicKey({pubkey, allowed})
|
||||
},
|
||||
blockPublicKey: async function (pubkey, blocked = true) {
|
||||
await this.updatePublicKey({pubkey, blocked})
|
||||
},
|
||||
removePublicKey: async function (pubkey) {
|
||||
LNbits.utils
|
||||
.confirmDialog('This public key will be removed from relay!')
|
||||
.onOk(async () => {
|
||||
await this.deletePublicKey(pubkey)
|
||||
})
|
||||
},
|
||||
togglePublicKey: async function (account, action) {
|
||||
if (action === 'allow') {
|
||||
await this.updatePublicKey({
|
||||
pubkey: account.pubkey,
|
||||
allowed: account.allowed
|
||||
})
|
||||
}
|
||||
if (action === 'block') {
|
||||
await this.updatePublicKey({
|
||||
pubkey: account.pubkey,
|
||||
blocked: account.blocked
|
||||
})
|
||||
}
|
||||
},
|
||||
updatePublicKey: async function (ops) {
|
||||
try {
|
||||
await LNbits.api.request(
|
||||
'PUT',
|
||||
'/nostrrelay/api/v1/account',
|
||||
this.adminkey,
|
||||
{
|
||||
relay_id: this.relay.id,
|
||||
pubkey: ops.pubkey,
|
||||
allowed: ops.allowed,
|
||||
blocked: ops.blocked
|
||||
}
|
||||
)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Account Updated',
|
||||
timeout: 5000
|
||||
})
|
||||
this.accountPubkey = ''
|
||||
await this.getAccounts()
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
|
||||
deletePublicKey: async function (pubkey) {
|
||||
try {
|
||||
await LNbits.api.request(
|
||||
'DELETE',
|
||||
`/nostrrelay/api/v1/account/${this.relay.id}/${pubkey}`,
|
||||
this.adminkey,
|
||||
{}
|
||||
)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Account Deleted',
|
||||
timeout: 5000
|
||||
})
|
||||
await this.getAccounts()
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
|
||||
addSkipAuthForEvent: function () {
|
||||
value = +this.skipEventKind
|
||||
if (this.relay.meta.skipedAuthEvents.indexOf(value) != -1) {
|
||||
return
|
||||
}
|
||||
this.relay.meta.skipedAuthEvents.push(value)
|
||||
},
|
||||
removeSkipAuthForEvent: function (eventKind) {
|
||||
value = +eventKind
|
||||
this.relay.meta.skipedAuthEvents =
|
||||
this.relay.meta.skipedAuthEvents.filter(e => e !== value)
|
||||
},
|
||||
addForceAuthForEvent: function () {
|
||||
value = +this.forceEventKind
|
||||
if (this.relay.meta.forcedAuthEvents.indexOf(value) != -1) {
|
||||
return
|
||||
}
|
||||
this.relay.meta.forcedAuthEvents.push(value)
|
||||
},
|
||||
removeForceAuthForEvent: function (eventKind) {
|
||||
value = +eventKind
|
||||
this.relay.meta.forcedAuthEvents =
|
||||
this.relay.meta.forcedAuthEvents.filter(e => e !== value)
|
||||
},
|
||||
// todo: bad. base.js not present in custom components
|
||||
copyText: function (text, message, position) {
|
||||
Quasar.copyToClipboard(text).then(function () {
|
||||
Quasar.Notify.create({
|
||||
message: message || 'Copied to clipboard!',
|
||||
position: position || 'bottom'
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async created() {
|
||||
await this.getRelay()
|
||||
await this.getAccounts()
|
||||
}
|
||||
})
|
||||
|
|
@ -1,676 +0,0 @@
|
|||
<div>
|
||||
<q-tabs v-model="tab" no-caps class="bg-dark text-white shadow-2">
|
||||
<q-tab name="info" label="Relay Info"></q-tab>
|
||||
<q-tab name="payment" label="Payment"></q-tab>
|
||||
<q-tab name="config" label="Config"></q-tab>
|
||||
<q-tab name="accounts" label="Accounts"></q-tab>
|
||||
</q-tabs>
|
||||
<q-tab-panels v-model="tab">
|
||||
<q-tab-panel name="info">
|
||||
<div v-if="relay">
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Name:</div>
|
||||
<div class="col-6 col-sm-8 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.name"
|
||||
type="text"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-3 col-sm-1"></div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Description:</div>
|
||||
<div class="col-6 col-sm-8 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.description"
|
||||
type="text"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-3 col-sm-1"></div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Relay Public Key:</div>
|
||||
<div class="col-6 col-sm-8 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.pubkey"
|
||||
type="text"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-3 col-sm-1"></div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Contact:</div>
|
||||
<div class="col-6 col-sm-8 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.contact"
|
||||
type="text"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-3 col-sm-1"></div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Domain:</div>
|
||||
<div class="col-6 col-sm-8 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.domain"
|
||||
type="text"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-3 col-sm-1"></div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Web Socket Link:</div>
|
||||
<div class="col-6 col-sm-8 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="wssLink"
|
||||
type="text"
|
||||
readonly
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-3 col-sm-1">
|
||||
<q-btn outline color="grey" @click="copyText(wssLink)">Copy</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="payment">
|
||||
<div v-if="relay">
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg q-pb-md">Free Storage:</div>
|
||||
<div class="col-md-2 col-sm-4 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.freeStorageValue"
|
||||
type="number"
|
||||
hint="Value"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-md-2 col-sm-4 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.freeStorageUnit"
|
||||
type="text"
|
||||
hint="Unit"
|
||||
:options="storageUnits"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-1 q-pr-lg">
|
||||
<q-icon name="info" class="cursor-pointer q-pb-md">
|
||||
<q-tooltip>
|
||||
How much data a client can store. This can be extended with the
|
||||
Paid Plan.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-2">
|
||||
<q-badge
|
||||
v-if="relay.config.freeStorageValue == 0"
|
||||
color="orange"
|
||||
class="float-right q-mb-md"
|
||||
><span>No free storage</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator></q-separator>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Paid Plan:</div>
|
||||
<div class="col-md-3 q-pr-lg">
|
||||
<q-toggle
|
||||
color="secodary"
|
||||
v-model="relay.config.isPaidRelay"
|
||||
@input="togglePaidRelay"
|
||||
></q-toggle>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<q-badge
|
||||
v-if="!relay.config.isPaidRelay && relay.config.freeStorageValue == 0"
|
||||
color="orange"
|
||||
class="float-right q-mb-md"
|
||||
><span>No data will be stored. Read-only relay.</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="relay.config.isPaidRelay && relay.config.wallet">
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Wallet:</div>
|
||||
<div class="col-md-6 col-sm-8 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model="relay.config.wallet"
|
||||
:options="walletOptions"
|
||||
label="Wallet *"
|
||||
>
|
||||
</q-select>
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-1">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
Wallet where the paiments will be sent to.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Cost to join (sats):</div>
|
||||
<div class="col-md-2 col-sm-4 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.costToJoin"
|
||||
type="number"
|
||||
hint="sats"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-1 q-pr-lg">
|
||||
<q-icon name="info" class="cursor-pointer q-pb-md">
|
||||
<q-tooltip>
|
||||
Ask a fee for clients to join. Expected to be paid only once.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-4">
|
||||
<q-badge
|
||||
v-if="relay.config.costToJoin == 0"
|
||||
color="green"
|
||||
class="float-right"
|
||||
><span>Free to join</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Storage Cost (sats):</div>
|
||||
<div class="col-md-2 col-sm-4 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.storageCostValue"
|
||||
type="number"
|
||||
hint="sats"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-md-2 col-sm-4 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.storageCostUnit"
|
||||
type="text"
|
||||
hint="Unit"
|
||||
:options="storageUnits"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-1 q-pr-lg">
|
||||
<q-icon name="info" class="cursor-pointer q-pb-md">
|
||||
<q-tooltip>
|
||||
Cost for clients to buy additional storage.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-0">
|
||||
<q-badge
|
||||
v-if="relay.config.storageCostValue == 0"
|
||||
color="green"
|
||||
class="float-right"
|
||||
><span>Unlimited storage</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="config">
|
||||
<div v-if="relay">
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Created At in Past:</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.createdAtDaysPast"
|
||||
type="number"
|
||||
min="0"
|
||||
hint="Days"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.createdAtHoursPast"
|
||||
type="number"
|
||||
hint="Hours"
|
||||
:options="hours"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.createdAtMinutesPast"
|
||||
type="number"
|
||||
hint="Minutes"
|
||||
:options="range60"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.createdAtSecondsPast"
|
||||
type="number"
|
||||
hint="Seconds"
|
||||
:options="range60"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-1 q-pb-md">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
NIP 22: Lower limit within which a relay will consider an
|
||||
event's created_at to be acceptable.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Created At in Future:</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.createdAtDaysFuture"
|
||||
type="number"
|
||||
min="0"
|
||||
hint="Days"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.createdAtHoursFuture"
|
||||
type="number"
|
||||
hint="Hours"
|
||||
:options="hours"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.createdAtMinutesFuture"
|
||||
type="number"
|
||||
hint="Minutes"
|
||||
:options="range60"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-2 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
v-model="relay.config.createdAtSecondsFuture"
|
||||
type="number"
|
||||
hint="Seconds"
|
||||
:options="range60"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-1 q-pb-md">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
NIP 22: Upper limit within which a relay will consider an
|
||||
event's created_at to be acceptable.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator></q-separator>
|
||||
<div class="row items-center no-wrap q-mb-md q-mt-md">
|
||||
<div class="col-3 q-pr-lg">Require Auth :</div>
|
||||
<div class="col-2 col-sm-4 q-pr-lg">
|
||||
<q-toggle
|
||||
color="secodary"
|
||||
class="q-ml-md q-mr-md"
|
||||
v-model="relay.config.requireAuthFilter"
|
||||
>For Filters</q-toggle
|
||||
>
|
||||
</div>
|
||||
<div class="col-2 col-sm-4 q-pr-lg">
|
||||
<q-toggle
|
||||
color="secodary"
|
||||
class="q-ml-md q-mr-md"
|
||||
v-model="relay.config.requireAuthEvents"
|
||||
>For All Events</q-toggle
|
||||
>
|
||||
</div>
|
||||
<div class="col-5 col-sm-5">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
Require client authentication for accessing different types of
|
||||
resources.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="relay.config.requireAuthEvents"
|
||||
class="row items-center no-wrap q-mb-md q-mt-md"
|
||||
>
|
||||
<div class="col-3 q-pr-lg">Skip Auth For Events:</div>
|
||||
<div class="col-1">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="skipEventKind"
|
||||
type="number"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="secondary"
|
||||
icon="add"
|
||||
@click="addSkipAuthForEvent()"
|
||||
></q-btn>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<q-chip
|
||||
v-for="e in relay.config.skipedAuthEvents"
|
||||
:key="e"
|
||||
removable
|
||||
@remove="removeSkipAuthForEvent(e)"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
>
|
||||
{{ e }}
|
||||
</q-chip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="row items-center no-wrap q-mb-md q-mt-md">
|
||||
<div class="col-3 q-pr-lg">Force Auth For Events:</div>
|
||||
<div class="col-1">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="forceEventKind"
|
||||
type="number"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="secondary"
|
||||
icon="add"
|
||||
@click="addForceAuthForEvent()"
|
||||
></q-btn>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<q-chip
|
||||
v-for="e in relay.config.forcedAuthEvents"
|
||||
:key="e"
|
||||
removable
|
||||
@remove="removeForceAuthForEvent(e)"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
>
|
||||
{{ e }}
|
||||
</q-chip>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator></q-separator>
|
||||
<div class="row items-center no-wrap q-mb-md q-mt-md">
|
||||
<div class="col-3 q-pr-lg">Full Storage Action:</div>
|
||||
<div class="col-3 col-sm-4 q-pr-lg">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model="relay.config.fullStorageAction"
|
||||
type="text"
|
||||
:options="fullStorageActions"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-6 col-sm-5">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
Action to be taken when the storage limit (if any) has been
|
||||
reached.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Limit per filter:</div>
|
||||
<div class="col-3 col-sm-4 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.limitPerFilter"
|
||||
type="number"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-6 col-sm-5">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
Maximum number of events to be returned in the initial query
|
||||
(default 1000)
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
<q-badge
|
||||
v-if="relay.config.limitPerFilter == 0"
|
||||
color="green"
|
||||
class="float-right"
|
||||
><span>No Limit</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Max Filters (per client):</div>
|
||||
<div class="col-3 col-sm-4 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.maxClientFilters"
|
||||
type="number"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-6 col-sm-5">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
Limit the number of filters that a client can have. Prevents
|
||||
relay from being abused by clients with extremly high number of
|
||||
fiters.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
<q-badge
|
||||
v-if="relay.config.maxClientFilters == 0"
|
||||
color="green"
|
||||
class="float-right"
|
||||
><span>Unlimited Filters</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Max events per hour:</div>
|
||||
<div class="col-3 col-sm-4 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="relay.config.maxEventsPerHour"
|
||||
type="number"
|
||||
min="0"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-6 col-sm-5">
|
||||
<q-icon name="info" class="cursor-pointer">
|
||||
<q-tooltip>
|
||||
Limits the rate at which events are accepted by the relay.
|
||||
Prevent clients from clogging the relay.
|
||||
</q-tooltip></q-icon
|
||||
>
|
||||
<q-badge
|
||||
v-if="relay.config.maxEventsPerHour == 0"
|
||||
color="green"
|
||||
class="float-right"
|
||||
><span>No Limit</span>
|
||||
</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="accounts">
|
||||
<div v-if="relay">
|
||||
<q-card class="q-mr-lg q-mb-md"
|
||||
><q-card-section>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-2 q-pr-lg">Public Key:</div>
|
||||
<div class="col-5 q-pr-lg">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="accountPubkey"
|
||||
type="text"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-2 q-pr-md">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="green"
|
||||
class="float-left"
|
||||
@click="allowPublicKey(accountPubkey, true)"
|
||||
>Allow</q-btn
|
||||
>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="pink"
|
||||
class="float-left"
|
||||
@click="blockPublicKey(accountPubkey, true)"
|
||||
>Block</q-btn
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
<q-card class="q-mr-lg q-mb-dm"
|
||||
><q-card-section>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-3 q-pr-lg">Filter:</div>
|
||||
<div class="col-9 q-pr-lg">
|
||||
<q-toggle
|
||||
size="sm"
|
||||
color="secodary"
|
||||
class="q-mr-lg"
|
||||
v-model="showAllowedAccounts"
|
||||
@input="getAccounts()"
|
||||
>Show Allowed Account</q-toggle
|
||||
>
|
||||
<q-toggle
|
||||
size="sm"
|
||||
color="secodary"
|
||||
class="q-mr-lg"
|
||||
v-model="showBlockedAccounts"
|
||||
@input="getAccounts()"
|
||||
>
|
||||
Show Blocked Accounts</q-toggle
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section></q-card
|
||||
>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-12 q-pr-lg">
|
||||
<q-table
|
||||
flat
|
||||
dense
|
||||
:data="accounts"
|
||||
row-key="pubkey"
|
||||
:columns="accountsTable.columns"
|
||||
:pagination.sync="accountsTable.pagination"
|
||||
>
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props">
|
||||
<q-td key="action" :props="props">
|
||||
<q-btn
|
||||
dense
|
||||
color="pink"
|
||||
class="float-right"
|
||||
@click="removePublicKey(props.row.pubkey)"
|
||||
size="sm"
|
||||
>Delete</q-btn
|
||||
>
|
||||
</q-td>
|
||||
<q-td key="pubkey" :props="props">
|
||||
{{props.row.pubkey}}
|
||||
</q-td>
|
||||
<q-td key="allowed" :props="props">
|
||||
<q-toggle
|
||||
size="sm"
|
||||
color="secodary"
|
||||
v-model="props.row.allowed"
|
||||
@input="togglePublicKey(props.row, 'allow')"
|
||||
></q-toggle>
|
||||
</q-td>
|
||||
<q-td key="blocked" :props="props">
|
||||
<q-toggle
|
||||
size="sm"
|
||||
color="secodary"
|
||||
v-model="props.row.blocked"
|
||||
@input="togglePublicKey(props.row, 'block')"
|
||||
></q-toggle>
|
||||
</q-td>
|
||||
<q-td auto-width> {{props.row.paid_to_join}} </q-td>
|
||||
<q-td auto-width> {{props.row.sats}} </q-td>
|
||||
<q-td auto-width> {{props.row.storage}} </q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
<div class="row items-center q-mt-md q-mb-lg">
|
||||
<div class="col-6 q-pr-lg">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="secondary"
|
||||
class="float-left"
|
||||
@click="updateRelay()"
|
||||
>Update Relay</q-btn
|
||||
>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="pink"
|
||||
icon="cancel"
|
||||
class="float-right"
|
||||
@click="deleteRelay()"
|
||||
>Delete Relay</q-btn
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
async function relayDetails(path) {
|
||||
const template = await loadTemplateAsync(path)
|
||||
Vue.component('relay-details', {
|
||||
name: 'relay-details',
|
||||
template,
|
||||
|
||||
props: ['relay-id', 'adminkey', 'inkey', 'wallet-options'],
|
||||
data: function () {
|
||||
return {
|
||||
tab: 'info',
|
||||
relay: null,
|
||||
accounts: [],
|
||||
accountPubkey: '',
|
||||
formDialogItem: {
|
||||
show: false,
|
||||
data: {
|
||||
name: '',
|
||||
description: ''
|
||||
}
|
||||
},
|
||||
showBlockedAccounts: true,
|
||||
showAllowedAccounts: false,
|
||||
accountsTable: {
|
||||
columns: [
|
||||
{
|
||||
name: 'action',
|
||||
align: 'left',
|
||||
label: '',
|
||||
field: ''
|
||||
},
|
||||
{
|
||||
name: 'pubkey',
|
||||
align: 'left',
|
||||
label: 'Public Key',
|
||||
field: 'pubkey'
|
||||
},
|
||||
{
|
||||
name: 'allowed',
|
||||
align: 'left',
|
||||
label: 'Allowed',
|
||||
field: 'allowed'
|
||||
},
|
||||
{
|
||||
name: 'blocked',
|
||||
align: 'left',
|
||||
label: 'Blocked',
|
||||
field: 'blocked'
|
||||
},
|
||||
{
|
||||
name: 'paid_to_join',
|
||||
align: 'left',
|
||||
label: 'Paid to join',
|
||||
field: 'paid_to_join'
|
||||
},
|
||||
{
|
||||
name: 'sats',
|
||||
align: 'left',
|
||||
label: 'Spent Sats',
|
||||
field: 'sats'
|
||||
},
|
||||
{
|
||||
name: 'storage',
|
||||
align: 'left',
|
||||
label: 'Storage',
|
||||
field: 'storage'
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
rowsPerPage: 10
|
||||
}
|
||||
},
|
||||
skipEventKind: 0,
|
||||
forceEventKind: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
hours: function () {
|
||||
const y = []
|
||||
for (let i = 0; i <= 24; i++) {
|
||||
y.push(i)
|
||||
}
|
||||
return y
|
||||
},
|
||||
range60: function () {
|
||||
const y = []
|
||||
for (let i = 0; i <= 60; i++) {
|
||||
y.push(i)
|
||||
}
|
||||
return y
|
||||
},
|
||||
storageUnits: function () {
|
||||
return ['KB', 'MB']
|
||||
},
|
||||
fullStorageActions: function () {
|
||||
return [
|
||||
{value: 'block', label: 'Block New Events'},
|
||||
{value: 'prune', label: 'Prune Old Events'}
|
||||
]
|
||||
},
|
||||
wssLink: function () {
|
||||
this.relay.config.domain =
|
||||
this.relay.config.domain || window.location.hostname
|
||||
return (
|
||||
'wss://' + this.relay.config.domain + '/nostrrelay/' + this.relay.id
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
satBtc(val, showUnit = true) {
|
||||
return satOrBtc(val, showUnit, this.satsDenominated)
|
||||
},
|
||||
deleteRelay: function () {
|
||||
LNbits.utils
|
||||
.confirmDialog(
|
||||
'All data will be lost! Are you sure you want to delete this relay?'
|
||||
)
|
||||
.onOk(async () => {
|
||||
try {
|
||||
await LNbits.api.request(
|
||||
'DELETE',
|
||||
'/nostrrelay/api/v1/relay/' + this.relayId,
|
||||
this.adminkey
|
||||
)
|
||||
this.$emit('relay-deleted', this.relayId)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Relay Deleted',
|
||||
timeout: 5000
|
||||
})
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
})
|
||||
},
|
||||
getRelay: async function () {
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'GET',
|
||||
'/nostrrelay/api/v1/relay/' + this.relayId,
|
||||
this.inkey
|
||||
)
|
||||
this.relay = data
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
updateRelay: async function () {
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'PATCH',
|
||||
'/nostrrelay/api/v1/relay/' + this.relayId,
|
||||
this.adminkey,
|
||||
this.relay
|
||||
)
|
||||
this.relay = data
|
||||
this.$emit('relay-updated', this.relay)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Relay Updated',
|
||||
timeout: 5000
|
||||
})
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
togglePaidRelay: async function () {
|
||||
this.relay.config.wallet =
|
||||
this.relay.config.wallet || this.walletOptions[0].value
|
||||
},
|
||||
getAccounts: async function () {
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'GET',
|
||||
`/nostrrelay/api/v1/account?relay_id=${this.relay.id}&allowed=${this.showAllowedAccounts}&blocked=${this.showBlockedAccounts}`,
|
||||
this.inkey
|
||||
)
|
||||
this.accounts = data
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
allowPublicKey: async function (pubkey, allowed) {
|
||||
await this.updatePublicKey({pubkey, allowed})
|
||||
},
|
||||
blockPublicKey: async function (pubkey, blocked = true) {
|
||||
await this.updatePublicKey({pubkey, blocked})
|
||||
},
|
||||
removePublicKey: async function (pubkey) {
|
||||
LNbits.utils
|
||||
.confirmDialog('This public key will be removed from relay!')
|
||||
.onOk(async () => {
|
||||
await this.deletePublicKey(pubkey)
|
||||
})
|
||||
},
|
||||
togglePublicKey: async function (account, action) {
|
||||
if (action === 'allow') {
|
||||
await this.updatePublicKey({
|
||||
pubkey: account.pubkey,
|
||||
allowed: account.allowed
|
||||
})
|
||||
}
|
||||
if (action === 'block') {
|
||||
await this.updatePublicKey({
|
||||
pubkey: account.pubkey,
|
||||
blocked: account.blocked
|
||||
})
|
||||
}
|
||||
},
|
||||
updatePublicKey: async function (ops) {
|
||||
try {
|
||||
await LNbits.api.request(
|
||||
'PUT',
|
||||
'/nostrrelay/api/v1/account',
|
||||
this.adminkey,
|
||||
{
|
||||
relay_id: this.relay.id,
|
||||
pubkey: ops.pubkey,
|
||||
allowed: ops.allowed,
|
||||
blocked: ops.blocked
|
||||
}
|
||||
)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Account Updated',
|
||||
timeout: 5000
|
||||
})
|
||||
this.accountPubkey = ''
|
||||
await this.getAccounts()
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
|
||||
deletePublicKey: async function (pubkey) {
|
||||
try {
|
||||
await LNbits.api.request(
|
||||
'DELETE',
|
||||
`/nostrrelay/api/v1/account/${this.relay.id}/${pubkey}`,
|
||||
this.adminkey,
|
||||
{}
|
||||
)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Account Deleted',
|
||||
timeout: 5000
|
||||
})
|
||||
await this.getAccounts()
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
|
||||
addSkipAuthForEvent: function () {
|
||||
value = +this.skipEventKind
|
||||
if (this.relay.config.skipedAuthEvents.indexOf(value) != -1) {
|
||||
return
|
||||
}
|
||||
this.relay.config.skipedAuthEvents.push(value)
|
||||
},
|
||||
removeSkipAuthForEvent: function (eventKind) {
|
||||
value = +eventKind
|
||||
this.relay.config.skipedAuthEvents =
|
||||
this.relay.config.skipedAuthEvents.filter(e => e !== value)
|
||||
},
|
||||
addForceAuthForEvent: function () {
|
||||
value = +this.forceEventKind
|
||||
if (this.relay.config.forcedAuthEvents.indexOf(value) != -1) {
|
||||
return
|
||||
}
|
||||
this.relay.config.forcedAuthEvents.push(value)
|
||||
},
|
||||
removeForceAuthForEvent: function (eventKind) {
|
||||
value = +eventKind
|
||||
this.relay.config.forcedAuthEvents =
|
||||
this.relay.config.forcedAuthEvents.filter(e => e !== value)
|
||||
},
|
||||
// todo: bad. base.js not present in custom components
|
||||
copyText: function (text, message, position) {
|
||||
var notify = this.$q.notify
|
||||
Quasar.utils.copyToClipboard(text).then(function () {
|
||||
notify({
|
||||
message: message || 'Copied to clipboard!',
|
||||
position: position || 'bottom'
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
created: async function () {
|
||||
await this.getRelay()
|
||||
await this.getAccounts()
|
||||
}
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue