Files
thetool/Layout/default/Domain/Index.php
2024-03-12 20:36:11 +01:00

241 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">&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>{{ 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
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"); ?>