feat: update to v1.0.0 (#30)

This commit is contained in:
dni ⚡ 2024-11-08 14:32:04 +01:00 committed by GitHub
parent 2bdbbb274d
commit 73054fd5ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 2029 additions and 2132 deletions

View 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()
}
})

View file

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

View file

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