Files
thetool/public/js/pages/Domain/Domain.js
2024-07-30 17:52:04 +00:00

234 lines
11 KiB
JavaScript

Vue.component('Domain', {
//language=Vue
template: `
<tt-card>
<tt-table :fetch-url="window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=getDomains'" :config="domainsTableConfig"
small ssr ref="table">
<template v-slot:top-buttons>
<button type="button" class="btn btn-primary" @click="reloadDomains">
<template v-if="reloadDomainsLoading">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</template>
<template v-else>
<i class="fas fa-sync-alt"></i>
Reload Domains
</template>
</button>
<div class="input-group">
<input type="text" class="form-control" v-model="checkDomainInput" style="height: 100%" placeholder="Neue Domain überprüfen">
<div class="input-group-append">
<button class="btn btn-primary" @click="checkDomainAvailability">
<template v-if="checkDomainLoading">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</template>
<template v-else>
<i class="fas fa-search"></i>
</template>
</button>
</div>
</div>
</template>
<!-- Slot to show DNS records button -->
<template v-slot:inwxroid="{ row }">
<div style="display: flex; justify-content: space-around; align-items: center;min-width: 38px">
<a style="cursor: pointer;" @click="showDnsRecordsModal(row.domain)">
<i class="fas fa-eye text-primary" title="DNS"></i>
</a>
<a :style="row.contractId ? 'cursor:pointer' : 'pointer-events: none; cursor: not-allowed;'"
@click="showContract(row.contractId)">
<i :class="row.contractId ? 'fas fa-file-contract text-primary' : 'fas fa-file-contract text-grey disabled'" title="Contract"></i>
</a>
</div>
</template>
<!-- Registrant Admin Tech Billing from domainContacts -->
<template v-slot:registrant="{ row }">
{{ domainContacts[row.registrant] ? domainContacts[row.registrant]["name"] : '' }}
</template>
<template v-slot:admin="{ row }">{{ domainContacts[row.admin] ? domainContacts[row.admin]["name"] : ''}}
</template>
<template v-slot:tech="{ row }">{{ domainContacts[row.tech] ? domainContacts[row.tech]["name"] : ''}}
</template>
<template v-slot:billing="{ row }">{{ domainContacts[row.billing] ? domainContacts[row.billing]["name"] : ''}}
</template>
</tt-table>
<!-- Bootstrap Modal to query and show all DNS records for a domain -->
<div class="modal show d-block" tabindex="-1" role="dialog" style="background: rgba(0, 0, 0, 0.5);"
ref="dnsRecordsModal" @click="dnsRecordsModal.domain = null" @keydown.esc="dnsRecordsModal.domain = null"
v-if="dnsRecordsModal.domain">
<div class="modal-dialog" role="document" style="max-width: fit-content" @click.stop>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">DNS Records for {{ dnsRecordsModal.domain ?? '' }}</h5>
<button type="button" class="close" @click="dnsRecordsModal.domain = null">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<table class="tt-table table-striped table-bordered table-hover table-sm table-condensed">
<thead>
<tr>
<th>Record Class</th>
<th>Record Type</th>
<th>Record Host</th>
<th>Record Value</th>
<th>Record TTL</th>
</tr>
</thead>
<tbody>
<tr v-for="record in dnsRecordsModal.records">
<td v-if="record">{{ record.class }}</td>
<td>{{ record.type }} {{ record.pri ? '(' + record.pri + ')' : '' }}</td>
<td>{{ record.host }}</td>
<td>{{ record.value }}</td>
<td>{{ record.ttl }}</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" @click="dnsRecordsModal.domain = null">Close</button>
</div>
</div>
</div>
</div>
</tt-card>
`,
data() {
return {
window: window,
domainContacts: {},
reloadDomainsLoading: false,
dnsRecordsModalLoading: null,
dnsRecordsModal: {
domain: null, records: []
},
checkDomainInput: '',
checkDomainResult: null,
checkDomainLoading: false
}
}, created() {
this.fetchDomainContacts().then()
}, computed: {
domainsTableConfig() {
const base = {
headers: [{
text: "Domain",
key: "domain"
}, {
text: "Plesk",
key: "pleskId",
filter: 'iconSelect',
filterOptions: [{value: 1, text: 'Yes', icon: 'fas fa-check text-success'}, {
value: 0,
text: 'No',
icon: 'fas fa-times text-danger'
}],
sortable: false
}, {text: "Created Date", key: "crDate", filter: "date"}, {
text: "Expiration Date",
key: "exDate",
filter: "date"
}, {text: "Renewal Date", key: "reDate", filter: "date"}, {
text: "Updated Date",
key: "upDate",
filter: "date"
}, {
text: "Transfer Lock",
key: "transferLock",
filter: 'iconSelect',
filterOptions: [{value: 1, text: 'Locked', icon: 'fas fa-lock text-danger'}, {
value: 0,
text: 'Unlocked',
icon: 'fas fa-unlock text-success'
}]
}, {text: "Authorization Code", key: "authCode", sortable: false}, {
text: "Registrant ID",
key: "registrant",
sortable: false
}, {text: "Admin ID", key: "admin", sortable: false}, {
text: "Tech ID",
key: "tech",
sortable: false
}, {text: "Billing ID", key: "billing", sortable: false}, {text: "Name Servers", key: "ns"},
{text: "Actions", key: "inwxRoId", filter: false, sortable: false, priority: 1}],
tableHeader: 'Domains',
key: 'Domain'
}
const domainContactsSorted = Object.entries(this.domainContacts).sort(([, a], [, b]) => a.name.localeCompare(b.name))
const domainContactsFilterOptions = domainContactsSorted.map(([, contact]) => {
return {text: contact.name, value: contact.inwxRoId}
})
// for registrant admin tech billing set filter to select with domainContacts if domainContacts is not empty
if (Object.keys(this.domainContacts).length > 0) {
base.headers = base.headers.map(header => {
if (['registrant', 'admin', 'tech', 'billing'].includes(header.key)) {
header.filter = 'select'
header.filterOptions = domainContactsFilterOptions
}
return header
})
}
return base
}
}, methods: {
async showContract(contractId) {
if (!contractId) return
const contractUrl= window['TT_CONFIG']['CONTRACT_URL'] + '/view/?contract_id=' + contractId
//redirect to contractUrl in new tab
const win = window.open(contractUrl, '_blank')
win.focus()
},
async showDnsRecordsModal(domain) {
this.dnsRecordsModalLoading = domain
this.dnsRecordsModal = {
domain: null, records: []
}
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=getDnsRecords&domain=' + domain)
this.dnsRecordsModal.domain = domain
this.dnsRecordsModal.records = response.data.map(record => {
if (typeof record.entries === 'object') {
record.value = record.entries[0]
} else {
record.value = record.target || record.txt || record.ip
}
if (record.type === 'SOA') {
record.value = record.mname + ' ' + record.rname + ' ' + record.serial + ' ' + record.refresh + ' ' + record.retry + ' ' + record.expire
}
return record
})
this.dnsRecordsModalLoading = null
this.$nextTick(() => {
this.$refs.dnsRecordsModal.focus()
})
}, async fetchDomainContacts() {
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=getDomainContacts')
this.domainContacts = response.data
}, async reloadDomains() {
this.reloadDomainsLoading = true
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=importAllDomains')
window.notify('success', response.data["importMessages"].join('<br>'))
await Promise.all([this.fetchDomainContacts(), this.$refs.table.fetchData(this.$refs.table.pagination.page)])
this.reloadDomainsLoading = false
}, //TODO: make this cleaner
async checkDomainAvailability() {
this.checkDomainLoading = true
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=checkDomain&domain=' + this.checkDomainInput)
const priceInformation = response.data.price.domain[this.checkDomainInput]
window.notify(response.data.status === 'free' ? 'success' : 'error', `Domain ist ${response.data.status === 'free' ? 'verfügbar. Registrieren um' : 'nicht frei. Transfer um'} ${priceInformation.price}${priceInformation.currency}/${priceInformation.period === '1Y' ? 'Jahr' : priceInformation.period}`)
this.checkDomainLoading = false
}
}
})