Add Domains
This commit is contained in:
240
Layout/default/Domain/Index.php
Normal file
240
Layout/default/Domain/Index.php
Normal file
@@ -0,0 +1,240 @@
|
||||
<?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
|
||||
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"); ?>
|
||||
|
||||
Reference in New Issue
Block a user