245 lines
11 KiB
PHP
245 lines
11 KiB
PHP
<?php /** @noinspection PhpUndefinedClassInspection
|
|
* @var string $mfLayoutPackage
|
|
* @var TYPE_NAME $git_merge_ts
|
|
*/
|
|
|
|
//additional css /css/views/RaspberryDisplay.css
|
|
|
|
$JSGlobals = ["BASE_URL" => self::getUrl("Domain"),
|
|
"DASHBOARD_URL" => self::getUrl("Dashboard"),
|
|
"MFAPPNAME" => MFAPPNAME_SLUG,
|
|
"PAGE_TITLE" => "Domains",
|
|
"PATH" => [
|
|
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
|
|
["text" => "Domain Management", "href" => self::getUrl("Domain")],
|
|
["text" => "Domains"]
|
|
],
|
|
"DOMAIN_API_URL" => self::getUrl("Domain/api"),
|
|
];
|
|
|
|
$additionalJS = ["plugins/vue/vue.js",
|
|
"plugins/axios/axios.min.js",
|
|
"plugins/vue/tt-components/tt-page-title.js",
|
|
"plugins/vue/tt-components/tt-table.js",
|
|
];
|
|
$additionalCSS = [
|
|
'plugins/vue/tt-components/css/tt-table.css',
|
|
];
|
|
|
|
include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
|
|
|
|
<div id="app">
|
|
<!-- start page title -->
|
|
<tt-page-title :title="window['TT_CONFIG']['PAGE_TITLE']" :path="window['TT_CONFIG']['PATH']"></tt-page-title>
|
|
|
|
<tt-table :fetch-url="window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=getDomains'" :table-config="domainsTableConfig"
|
|
small 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" 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>
|
|
</template>
|
|
|
|
<!-- Slot to show DNS records button -->
|
|
<template v-slot:inwxroid="{ row }">
|
|
<button type="button" class="btn btn-primary" @click="showDnsRecordsModal(row.domain)"
|
|
:class="dnsRecordsModalLoading === row.domain ? 'disabled' : ''">
|
|
<template v-if="dnsRecordsModalLoading === row.domain">
|
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
|
</template>
|
|
<span v-else>DNS</span>
|
|
</button>
|
|
</template>
|
|
|
|
<!-- Slot to show if Domain is in Plesk -->
|
|
<template v-slot:pleskid="{ row }">
|
|
<i v-if="row.pleskId !== null" class="fas fa-check text-success"></i>
|
|
<i v-else class="fas fa-times text-danger"></i>
|
|
</template>
|
|
|
|
<!-- Convert all Dates to human readable format -->
|
|
<template v-slot:crdate="{ row }">{{ new Date(row.crDate * 1000).toLocaleDateString() }}</template>
|
|
<template v-slot:exdate="{ row }">{{ new Date(row.exDate * 1000).toLocaleDateString() }}</template>
|
|
<template v-slot:redate="{ row }">{{ new Date(row.reDate * 1000).toLocaleDateString() }}</template>
|
|
<template v-slot:update="{ row }">{{ new Date(row.upDate * 1000).toLocaleDateString() }}</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);"
|
|
v-if="dnsRecordsModal.domain">
|
|
<div class="modal-dialog" role="document" style="max-width: fit-content">
|
|
<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">×</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>{{ 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>
|
|
</div>
|
|
|
|
<script>
|
|
new Vue({
|
|
el: '#app',
|
|
data: {
|
|
window: window,
|
|
domainContacts: {},
|
|
reloadDomainsLoading: false,
|
|
dnsRecordsModalLoading: null,
|
|
dnsRecordsModal: {
|
|
domain: null,
|
|
records: []
|
|
},
|
|
checkDomainInput: '',
|
|
checkDomainResult: null,
|
|
checkDomainLoading: false
|
|
},
|
|
mounted() {
|
|
this.fetchDomainContacts()
|
|
},
|
|
computed: {
|
|
domainsTableConfig() {
|
|
const base = {
|
|
headers: [
|
|
{text: "ID", key: "inwxRoId", "filter": false},
|
|
{text: "Domain", key: "domain"},
|
|
{text: "Plesk", key: "pleskId", filter: false},
|
|
{text: "Created Date", key: "crDate", filter: false},
|
|
{text: "Expiration Date", key: "exDate", filter: false},
|
|
{text: "Renewal Date", key: "reDate", filter: false},
|
|
{text: "Updated Date", key: "upDate", filter: false},
|
|
{text: "Transfer Lock", key: "transferLock"},
|
|
{text: "Authorization Code", key: "authCode"},
|
|
{text: "Registrant ID", key: "registrant"},
|
|
{text: "Admin ID", key: "admin"},
|
|
{text: "Tech ID", key: "tech"},
|
|
{text: "Billing ID", key: "billing"},
|
|
{text: "Name Servers", key: "ns"}
|
|
],
|
|
tableHeader: 'Bestellungen',
|
|
}
|
|
// 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 = Object.entries(this.domainContacts).map(([, contact]) => {
|
|
return {text: contact.name, value: contact.inwxRoId}
|
|
})
|
|
}
|
|
return header
|
|
})
|
|
}
|
|
return base
|
|
}
|
|
},
|
|
methods: {
|
|
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
|
|
},
|
|
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
|
|
}
|
|
}
|
|
})
|
|
</script>
|
|
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>
|
|
|