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"); ?>
|
||||
|
||||
9
application/Domain/Domain.php
Normal file
9
application/Domain/Domain.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class Domain extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
196
application/Domain/DomainController.php
Normal file
196
application/Domain/DomainController.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
|
||||
class DomainController extends mfBaseController {
|
||||
private User $me;
|
||||
private string $INWX_USER = INWX_USER;
|
||||
private string $INWX_PASS = INWX_PASS;
|
||||
private string $PLESK_USER = PLESK_HOST;
|
||||
private string $PLESK_AUTH = PLESK_AUTH;
|
||||
private Inwx $inwx;
|
||||
private Plesk $plesk;
|
||||
|
||||
|
||||
protected function init(): void {
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
$this->layout()->set("me", $me);
|
||||
$this->me = $me;
|
||||
|
||||
$this->inwx = new Inwx($this->INWX_USER, $this->INWX_PASS);
|
||||
$this->plesk = new Plesk($this->PLESK_USER, $this->PLESK_AUTH);
|
||||
}
|
||||
|
||||
protected function indexAction(): void {
|
||||
$this->layout()->setTemplate("Domain/Index");
|
||||
}
|
||||
|
||||
protected function apiAction() {
|
||||
$do = $this->request->do;
|
||||
|
||||
if ($do !== "getConfig" && !$this->me->is("employee")) {
|
||||
$this->redirect("dashboard");
|
||||
}
|
||||
switch ($do) {
|
||||
case "importAllDomains":
|
||||
$return = $this->importAllDomains();
|
||||
break;
|
||||
case "getDomains":
|
||||
$return = $this->getAllDomains();
|
||||
break;
|
||||
case "getDomainContacts":
|
||||
$return = $this->getDomainContacts();
|
||||
break;
|
||||
case "getDnsRecords":
|
||||
$return = $this->getDnsRecords();
|
||||
break;
|
||||
case "checkDomain":
|
||||
$return = $this->checkDomain();
|
||||
break;
|
||||
default:
|
||||
$return = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$return) {
|
||||
$return = [
|
||||
"status" => "error",
|
||||
"message" => "Invalid request."
|
||||
];
|
||||
}
|
||||
|
||||
die(json_encode($return));
|
||||
}
|
||||
|
||||
protected function importDomain(): void {
|
||||
// use plesk api to get all domains
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected function importAllDomains(): array {
|
||||
|
||||
try {
|
||||
$inwxContact = $this->inwx->contactList();
|
||||
$pleskDomains = $this->plesk->getAllDomains();
|
||||
$inwxDomains = $this->inwx->domainList();
|
||||
|
||||
$domains = [];
|
||||
$pleskDomainsArray = [];
|
||||
|
||||
foreach ($pleskDomains as $pleskDomain) {
|
||||
$pleskDomainsArray[$pleskDomain['name']] = $pleskDomain;
|
||||
}
|
||||
|
||||
foreach ($inwxDomains as $inwxDomain) {
|
||||
if (isset($pleskDomainsArray[$inwxDomain['domain']])) {
|
||||
$inwxDomain['plesk'] = [
|
||||
"id" => $pleskDomainsArray[$inwxDomain['domain']]['id'],
|
||||
"hosting_type" => $pleskDomainsArray[$inwxDomain['domain']]['hosting_type'],
|
||||
"created" => strtotime($pleskDomainsArray[$inwxDomain['domain']]['created'])
|
||||
];
|
||||
}
|
||||
|
||||
$domains[] = $inwxDomain;
|
||||
}
|
||||
|
||||
$domainsImport = DomainModel::importDomains($domains);
|
||||
$contactsImport = DomainContactModel::importDomainContacts($inwxContact);
|
||||
|
||||
return [
|
||||
"status" => "success",
|
||||
"importMessages" => [
|
||||
$domainsImport['message'],
|
||||
$contactsImport['message']
|
||||
],
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
$this->log->error("Error while importing domains: " . $e->getMessage());
|
||||
return [
|
||||
"status" => "error",
|
||||
"message" => "Error while importing domains: " . $e->getMessage()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getAllDomains(): array {
|
||||
|
||||
$json = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$filters = $json['filters'] ?? [];
|
||||
$page = $json['pagination']['page'] ?? 1;
|
||||
$perPage = $json['pagination']['per_page'] ?? 10;
|
||||
|
||||
$domains = DomainModel::getAllDomains($filters, $perPage, $perPage * $page - $perPage);
|
||||
$totalRows = DomainModel::countDomains($filters);
|
||||
|
||||
return [
|
||||
"rows" => $domains,
|
||||
"pagination" => [
|
||||
"page" => $page,
|
||||
"total_pages" => ceil($totalRows / $perPage),
|
||||
"per_page" => $perPage,
|
||||
"total_rows" => intval($totalRows)
|
||||
]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
private function getDnsRecords() {
|
||||
if (!isset($this->request->domain)) {
|
||||
return ["status" => "error", "message" => "No domain specified."];
|
||||
}
|
||||
|
||||
$domain = $this->request->domain;
|
||||
return array_merge(
|
||||
dns_get_record($domain, DNS_TXT),
|
||||
dns_get_record($domain, DNS_A),
|
||||
dns_get_record($domain, DNS_CNAME),
|
||||
dns_get_record($domain, DNS_MX),
|
||||
dns_get_record($domain, DNS_NS),
|
||||
dns_get_record($domain, DNS_SOA),
|
||||
dns_get_record($domain, DNS_SRV),
|
||||
dns_get_record($domain, DNS_AAAA),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
private function getDomainContacts(): array {
|
||||
$domainContacts = [];
|
||||
$dbDomainContacts = DomainContactModel::getAllDomainContacts();
|
||||
|
||||
foreach ($dbDomainContacts as $dbDomainContact) {
|
||||
$domainContacts[$dbDomainContact['inwxRoId']] = $dbDomainContact;
|
||||
}
|
||||
|
||||
return $domainContacts;
|
||||
}
|
||||
|
||||
private function checkDomain(): array {
|
||||
$domain = $this->request->domain;
|
||||
|
||||
if(empty($domain)) {
|
||||
return ["status" => "error", "message" => "No domain or tld specified."];
|
||||
}
|
||||
|
||||
try {
|
||||
$domainCheck = $this->inwx->domainCheck($domain);
|
||||
|
||||
if($domainCheck['domain'][0]['status'] === "free") {
|
||||
$domainPrice = $this->inwx->domainGetDomainPrice($domain, "reg");
|
||||
} else {
|
||||
$domainPrice = $this->inwx->domainGetDomainPrice($domain, "transfer");
|
||||
}
|
||||
|
||||
$domainCheck['domain'][0]['price'] = $domainPrice;
|
||||
|
||||
return $domainCheck['domain'][0];
|
||||
} catch (Exception $e) {
|
||||
$this->log->error("Error while checking domain: " . $e->getMessage());
|
||||
return ["status" => "error", "message" => "Error while checking domain: " . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
133
application/Domain/DomainModel.php
Normal file
133
application/Domain/DomainModel.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
class DomainModel {
|
||||
public $inwxRoId;
|
||||
public $domain;
|
||||
public $period;
|
||||
public $crDate;
|
||||
public $exDate;
|
||||
public $reDate;
|
||||
public $upDate;
|
||||
public $transferLock;
|
||||
public $status;
|
||||
public $authCode;
|
||||
public $registrant;
|
||||
public $admin;
|
||||
public $tech;
|
||||
public $billing;
|
||||
public $ns;
|
||||
public $pleskId;
|
||||
public $pleskHostingType;
|
||||
public $pleskCreated;
|
||||
|
||||
|
||||
public function __construct($data = []) {
|
||||
foreach ($data as $field => $value) {
|
||||
if (property_exists(get_called_class(), $field)) {
|
||||
$this->$field = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function importDomains($domains): array {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$db->query("TRUNCATE TABLE `Domain`");
|
||||
|
||||
$sql = /** @lang text */
|
||||
"INSERT INTO `Domain` (`inwxRoId`, `domain`, `period`, `crDate`, `exDate`, `reDate`, `upDate`, `transferLock`, `status`, `authCode`, `registrant`, `admin`, `tech`, `billing`, `ns`, `pleskId`, `pleskHostingType`, `pleskCreated`) VALUES ";
|
||||
$values = [];
|
||||
foreach ($domains as $domain) {
|
||||
$valueStr ="(" .
|
||||
$domain['roId'] . ", '" .
|
||||
$domain['domain'] . "', '" .
|
||||
$domain['period'] . "', " .
|
||||
$domain['crDate']['timestamp'] . ", " .
|
||||
$domain['exDate']['timestamp'] . ", " .
|
||||
$domain['reDate']['timestamp'] . ", " .
|
||||
$domain['upDate']['timestamp'] . ", " .
|
||||
($domain['transferLock'] ? 1 : 0) . ", '" .
|
||||
$domain['status'] . "', '" .
|
||||
$domain['authCode'] . "', " .
|
||||
$domain['registrant'] . ", " .
|
||||
$domain['admin'] . ", " .
|
||||
$domain['tech'] . ", " .
|
||||
$domain['billing'] . ", '" .
|
||||
implode(", ", $domain['ns']) . "', ";
|
||||
|
||||
// Check if 'pleskId' is set
|
||||
if (isset($domain['plesk']) && is_array($domain['plesk'])) {
|
||||
$valueStr .= $domain['plesk']['id'] . ", ";
|
||||
$valueStr .= "'" . $domain['plesk']['hosting_type'] . "', ";
|
||||
$valueStr .= $domain['plesk']['created'];
|
||||
} else {
|
||||
$valueStr .= "NULL, NULL, NULL";
|
||||
}
|
||||
|
||||
$values[] = $valueStr . ")";
|
||||
}
|
||||
$sql .= implode(", ", $values);
|
||||
$db->query($sql);
|
||||
return [
|
||||
"message" => "Imported " . count($domains) . " domains."
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SQL Filter condition (space separated) for a given column.
|
||||
*
|
||||
* @param string|null $filterValue The filter value to match against.
|
||||
* @param string $columnName The name of the column in the database table.
|
||||
* @return string The SQL condition generated based on the filter value and column name.
|
||||
*/
|
||||
public static function generateFilterCondition(?string $filterValue, string $columnName): string {
|
||||
$sql = "";
|
||||
if (!empty($filterValue)) {
|
||||
$filterItems = explode(" ", $filterValue);
|
||||
foreach ($filterItems as $item) {
|
||||
$sql .= " AND `$columnName` LIKE '%" . $item . "%'";
|
||||
}
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public static function getSqlFilter($filters): string {
|
||||
$sql = isset($filters['crDate']) ? self::generateFilterCondition($filters['domain'], "domain") : "";
|
||||
$sql .= isset($filters['crDate']) ? " AND `crDate` = " . $filters['crDate'] : "";
|
||||
$sql .= isset($filters['exDate']) ? " AND `exDate` = " . $filters['exDate'] : "";
|
||||
$sql .= isset($filters['reDate']) ? " AND `reDate` = " . $filters['reDate'] : "";
|
||||
$sql .= isset($filters['upDate']) ? " AND `upDate` = " . $filters['upDate'] : "";
|
||||
$sql .= isset($filters['status']) ? " AND `status` = '" . $filters['status'] . "'" : "";
|
||||
$sql .= isset($filters['transferLock']) && $filters['transferLock'] == 1 ? " AND `transferLock` = true" : "";
|
||||
$sql .= isset($filters['authCode']) ? self::generateFilterCondition($filters['authCode'], "authCode") : "";
|
||||
$sql .= isset($filters['registrant']) && $filters['registrant'] !== 'all' ? " AND `registrant` = " . $filters['registrant'] : "";
|
||||
$sql .= isset($filters['admin']) && $filters['admin'] !== 'all' ? " AND `admin` = " . $filters['admin'] : "";
|
||||
$sql .= isset($filters['tech']) && $filters['tech'] !== 'all' ? " AND `tech` = " . $filters['tech'] : "";
|
||||
$sql .= isset($filters['billing']) && $filters['billing'] !== 'all' ? " AND `billing` = " . $filters['billing'] : "";
|
||||
$sql .= isset($filters['ns']) ? self::generateFilterCondition($filters['ns'], "ns") : "";
|
||||
return $sql;
|
||||
|
||||
}
|
||||
|
||||
public static function getAllDomains($filters, $limit = null, $offset = 0): array {
|
||||
$db = FronkDB::singleton();
|
||||
$sql = "SELECT * FROM `Domain` WHERE 1 " . self::getSqlFilter($filters);
|
||||
$sql .= $limit === null ? "" : " LIMIT " . $limit . " OFFSET " . $offset;
|
||||
|
||||
$result = $db->query($sql);
|
||||
$rows = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$rows[] = new DomainModel($row);
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public static function countDomains($filters) {
|
||||
$db = FronkDB::singleton();
|
||||
$sql = "SELECT COUNT(*) as `total_rows` FROM `Domain` WHERE 1 " . self::getSqlFilter($filters);
|
||||
$result = $db->query($sql);
|
||||
return $result->fetch_assoc()['total_rows'];
|
||||
}
|
||||
}
|
||||
8
application/DomainContact/DomainContact.php
Normal file
8
application/DomainContact/DomainContact.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class DomainContact extends mfBaseModel {
|
||||
|
||||
}
|
||||
121
application/DomainContact/DomainContactModel.php
Normal file
121
application/DomainContact/DomainContactModel.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
class DomainContactModel {
|
||||
|
||||
public $id;
|
||||
public $roId;
|
||||
public $type;
|
||||
public $name;
|
||||
public $street;
|
||||
public $city;
|
||||
public $pc;
|
||||
public $cc;
|
||||
public $voice;
|
||||
public $email;
|
||||
public $protection;
|
||||
public $usedCount;
|
||||
public $verificationStatus;
|
||||
|
||||
|
||||
public function __construct($data = []) {
|
||||
foreach ($data as $field => $value) {
|
||||
if (property_exists(get_called_class(), $field)) {
|
||||
$this->$field = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function importDomainContacts($domainContacts): array {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$db->query("TRUNCATE TABLE `DomainContact`");
|
||||
|
||||
$sql = /** @lang text */
|
||||
"INSERT INTO `DomainContact` (`inwxRoId`, `type`, `name`, `street`, `city`, `pc`, `cc`, `voice`, `email`, `protection`, `verificationStatus`, `usedCount`) VALUES ";
|
||||
$values = [];
|
||||
|
||||
foreach ($domainContacts as $domainContact) {
|
||||
$valueStr = "(" .
|
||||
$domainContact['roId'] . ", '" .
|
||||
$domainContact['type'] . "', '" .
|
||||
$domainContact['name'] . "', '" .
|
||||
$domainContact['street'] . "', '" .
|
||||
$domainContact['city'] . "', '" .
|
||||
$domainContact['pc'] . "', '" .
|
||||
$domainContact['cc'] . "', '" .
|
||||
$domainContact['voice'] . "', '" .
|
||||
$domainContact['email'] . "', " .
|
||||
($domainContact['protection'] ? 1 : 0) . ", '" .
|
||||
$domainContact['verificationStatus'] . "', ";
|
||||
|
||||
$valueStr .= $domainContact['usedCount'] ?? "NULL";
|
||||
$valueStr .= ")";
|
||||
|
||||
$values[] = $valueStr;
|
||||
}
|
||||
|
||||
$sql .= implode(", ", $values);
|
||||
$db->query($sql);
|
||||
return [
|
||||
"message" => "Imported " . count($domainContacts) . " domain contacts."
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SQL Filter condition (space separated) for a given column.
|
||||
*
|
||||
* @param string|null $filterValue The filter value to match against.
|
||||
* @param string $columnName The name of the column in the database table.
|
||||
* @return string The SQL condition generated based on the filter value and column name.
|
||||
*/
|
||||
public static function generateFilterCondition(?string $filterValue, string $columnName): string {
|
||||
$sql = "";
|
||||
if (!empty($filterValue)) {
|
||||
$filterItems = explode(" ", $filterValue);
|
||||
foreach ($filterItems as $item) {
|
||||
$sql .= " AND `$columnName` LIKE '%" . $item . "%'";
|
||||
}
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public static function getSqlFilter($filters): string {
|
||||
$sql = isset($filters['roId']) ? " AND `inwxRoId` = " . $filters['roId'] : "";
|
||||
$sql .= isset($filters['type']) ? " AND `type` = '" . $filters['type'] . "'" : "";
|
||||
$sql .= isset($filters['name']) ? self::generateFilterCondition($filters['name'], "name") : "";
|
||||
$sql .= isset($filters['street']) ? self::generateFilterCondition($filters['street'], "street") : "";
|
||||
$sql .= isset($filters['city']) ? self::generateFilterCondition($filters['city'], "city") : "";
|
||||
$sql .= isset($filters['pc']) ? " AND `pc` = " . $filters['pc'] : "";
|
||||
$sql .= isset($filters['cc']) ? " AND `cc` = " . $filters['cc'] : "";
|
||||
$sql .= isset($filters['voice']) ? " AND `voice` = " . $filters['voice'] : "";
|
||||
$sql .= isset($filters['email']) ? self::generateFilterCondition($filters['email'], "email") : "";
|
||||
$sql .= isset($filters['protection']) ? " AND `protection` = " . $filters['protection'] : "";
|
||||
$sql .= isset($filters['usedCount']) ? " AND `usedCount` = " . $filters['usedCount'] : "";
|
||||
$sql .= isset($filters['verificationStatus']) ? " AND `verificationStatus` = '" . $filters['verificationStatus'] . "'" : "";
|
||||
return $sql;
|
||||
|
||||
}
|
||||
|
||||
public static function getAllDomainContacts($filters = null, $limit = null, $offset = 0, $raw_array = true): array {
|
||||
$db = FronkDB::singleton();
|
||||
$sql = "SELECT * FROM `DomainContact` WHERE 1 ";
|
||||
$sql .= $filters === null ? "" : self::getSqlFilter($filters);
|
||||
$sql .= $limit === null ? "" : " LIMIT " . $limit . " OFFSET " . $offset;
|
||||
|
||||
$result = $db->query($sql);
|
||||
$rows = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$rows[] = $raw_array ? $row : new DomainContactModel($row);
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public static function countDomainContacts($filters) {
|
||||
$db = FronkDB::singleton();
|
||||
$sql = "SELECT COUNT(*) as `total_rows` FROM `DomainContact` WHERE 1 " . self::getSqlFilter($filters);
|
||||
$result = $db->query($sql);
|
||||
return $result->fetch_assoc()['total_rows'];
|
||||
}
|
||||
}
|
||||
64
db/migrations/20240312203000_add_domain.php
Normal file
64
db/migrations/20240312203000_add_domain.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php /** @noinspection ALL */
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class AddDomain extends AbstractMigration {
|
||||
public function up(): void {
|
||||
if ($this->getEnvironment() == "thetool") {
|
||||
//Domain Table
|
||||
$domainTable = $this->table("Domain", ["signed" => true]);
|
||||
$domainTable->addColumn("inwxRoId", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("domain", "string", ["null" => true, "limit" => 255]);
|
||||
$domainTable->addColumn("period", "string", ["null" => true, "limit" => 50]);
|
||||
$domainTable->addColumn("crDate", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("exDate", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("reDate", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("upDate", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("transferLock", "integer", ["null" => true, "limit" => \Phinx\Db\Adapter\MysqlAdapter::INT_TINY]);
|
||||
$domainTable->addColumn("status", "string", ["null" => true, "limit" => 50]);
|
||||
$domainTable->addColumn("authCode", "string", ["null" => true, "limit" => 50]);
|
||||
$domainTable->addColumn("registrant", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("admin", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("tech", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("billing", "integer", ["null" => true]);
|
||||
$domainTable->addColumn("ns", "string", ["null" => true, "limit" => 255]);
|
||||
$domainTable->addColumn("pleskId", "string", ["null" => true, "limit" => 255]);
|
||||
$domainTable->addColumn("pleskHostingType", "string", ["null" => true, "limit" => 255]);
|
||||
$domainTable->addColumn("pleskCreated", "integer", ["null" => true]);
|
||||
$domainTable->save();
|
||||
|
||||
//DomainContact Table
|
||||
|
||||
$domainContactTable = $this->table("DomainContact", ["signed" => true]);
|
||||
$domainContactTable->addColumn("inwxRoId", "integer", ["null" => true]);
|
||||
$domainContactTable->addColumn("type", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("name", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("street", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("city", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("pc", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("cc", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("voice", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("email", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->addColumn("protection", "integer", ["null" => true, "limit" => \Phinx\Db\Adapter\MysqlAdapter::INT_TINY]);
|
||||
$domainContactTable->addColumn("usedCount", "integer", ["null" => true]);
|
||||
$domainContactTable->addColumn("verificationStatus", "string", ["null" => true, "limit" => 255]);
|
||||
$domainContactTable->save();
|
||||
}
|
||||
|
||||
if ($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void {
|
||||
if ($this->getEnvironment() == "thetool") {
|
||||
$this->table("Domain")->drop()->save();
|
||||
$this->table("DomainContact")->drop()->save();
|
||||
}
|
||||
|
||||
if ($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
155
lib/inwx/inwx.php
Normal file
155
lib/inwx/inwx.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Represents the INWX API.
|
||||
*
|
||||
* @link https://www.inwx.at/en/help/apidoc JSON-RPC API documentation
|
||||
*/
|
||||
class Inwx {
|
||||
private string $apiUrl = 'https://api.domrobot.com/jsonrpc/';
|
||||
private string $username;
|
||||
private string $password;
|
||||
|
||||
/**
|
||||
* Inwx constructor.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*/
|
||||
public function __construct(string $username, string $password) {
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of contacts.
|
||||
*
|
||||
* @param int $pageLimit
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function contactList(int $pageLimit = 300): array {
|
||||
$requestData = array(
|
||||
'jsonrpc' => '2.0',
|
||||
'method' => 'contact.list',
|
||||
'params' => array(
|
||||
'user' => $this->username,
|
||||
'pass' => $this->password,
|
||||
'pagelimit' => $pageLimit,
|
||||
),
|
||||
'id' => 1
|
||||
);
|
||||
|
||||
return $this->makeRequest($requestData)['contact'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of domains.
|
||||
*
|
||||
* @param int $pageLimit
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function domainList(int $pageLimit = 300): array {
|
||||
$requestData = array(
|
||||
'jsonrpc' => '2.0',
|
||||
'method' => 'domain.list',
|
||||
'params' => array(
|
||||
'user' => $this->username,
|
||||
'pass' => $this->password,
|
||||
'pagelimit' => $pageLimit,
|
||||
),
|
||||
'id' => 1
|
||||
);
|
||||
|
||||
return $this->makeRequest($requestData)['domain'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a domain is available.
|
||||
*
|
||||
* @param string $domain
|
||||
* @param string $tld
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function domainCheck(string $domain): array {
|
||||
$requestData = array(
|
||||
'jsonrpc' => '2.0',
|
||||
'method' => 'domain.check',
|
||||
'params' => array(
|
||||
'user' => $this->username,
|
||||
'pass' => $this->password,
|
||||
'domain' => $domain
|
||||
),
|
||||
'id' => 1
|
||||
);
|
||||
|
||||
return $this->makeRequest($requestData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the price of a domain.
|
||||
*
|
||||
* @param string $domain
|
||||
* @param string $priceType reg | renewal | transfer | update | trade | restore
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function domainGetDomainPrice(string $domain, string $priceType): array {
|
||||
$requestData = array(
|
||||
'jsonrpc' => '2.0',
|
||||
'method' => 'domain.getdomainprice',
|
||||
'params' => array(
|
||||
'user' => $this->username,
|
||||
'pass' => $this->password,
|
||||
'domain' => $domain,
|
||||
'pricetype' => $priceType,
|
||||
),
|
||||
'id' => 1
|
||||
);
|
||||
|
||||
return $this->makeRequest($requestData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request to the INWX API.
|
||||
*
|
||||
* @param array $requestData
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function makeRequest(array $requestData): array {
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $this->apiUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json'
|
||||
));
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if ($response === false) {
|
||||
throw new Exception('cURL Error: ' . curl_error($ch));
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$responseData = json_decode($response, true);
|
||||
|
||||
if (isset($responseData['error'])) {
|
||||
throw new Exception('JSON-RPC Error: ' . $responseData['error']['message']);
|
||||
}
|
||||
|
||||
if (!isset($responseData['resData'])) {
|
||||
throw new Exception('Unexpected response format.');
|
||||
}
|
||||
|
||||
return $responseData['resData'];
|
||||
}
|
||||
}
|
||||
?>
|
||||
36
lib/plesk/plesk.php
Normal file
36
lib/plesk/plesk.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
class Plesk {
|
||||
private $host;
|
||||
private $authorization;
|
||||
|
||||
public function __construct($host, $authorization) {
|
||||
$this->host = $host;
|
||||
$this->authorization = $authorization;
|
||||
}
|
||||
|
||||
public function getAllDomains() {
|
||||
// Implement code to fetch all configured domains using Plesk API
|
||||
// You can use cURL or any HTTP client library to make API requests
|
||||
// Example:
|
||||
$url = "https://{$this->host}/api/v2/domains";
|
||||
$headers = array(
|
||||
"Authorization: {$this->authorization}",
|
||||
"Content-Type: application/json"
|
||||
);
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
|
||||
$response = json_decode($response, true);
|
||||
|
||||
if (is_array($response)) {
|
||||
return $response;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user