mirror of
https://github.com/getnamingo/registry.git
synced 2025-05-12 01:38:46 +02:00
449 lines
17 KiB
PHP
449 lines
17 KiB
PHP
<?php
|
|
|
|
$c = require_once 'config.php';
|
|
require_once 'helpers.php';
|
|
|
|
// Set up logging
|
|
$logFilePath = '/var/log/namingo/domain_lifecycle_manager.log';
|
|
$log = setupLogger($logFilePath, 'Domain_Lifecycle_Manager');
|
|
$log->info('Job started.');
|
|
|
|
$lockFile = '/tmp/domain-lifecycle-manager.lock';
|
|
|
|
if (file_exists($lockFile)) {
|
|
$lockTime = filemtime($lockFile);
|
|
// Check if the lock file is stale (e.g., older than 10 minutes)
|
|
if (time() - $lockTime > 600) {
|
|
// Remove stale lock file
|
|
unlink($lockFile);
|
|
} else {
|
|
$log->warning('Script is already running. Exiting.');
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
// Create the lock file
|
|
touch($lockFile);
|
|
|
|
try {
|
|
// Connect to the database
|
|
$dsn = "{$c['db_type']}:host={$c['db_host']};dbname={$c['db_database']};port={$c['db_port']}";
|
|
$dbh = new PDO($dsn, $c['db_username'], $c['db_password']);
|
|
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
// Instantiate the DomainLifecycleManager
|
|
$manager = new DomainLifecycleManager($dbh, $log, $c);
|
|
$manager->processLifecycle();
|
|
|
|
$log->info('Job finished successfully.');
|
|
} catch (PDOException $e) {
|
|
$log->error('DB Connection failed: ' . $e->getMessage());
|
|
exit(1);
|
|
} catch (Exception $e) {
|
|
$log->error('An unexpected error occurred: ' . $e->getMessage());
|
|
exit(1);
|
|
} finally {
|
|
// Remove the lock file
|
|
unlink($lockFile);
|
|
}
|
|
|
|
class DomainLifecycleManager {
|
|
private $dbh;
|
|
private $log;
|
|
private $config;
|
|
|
|
public function __construct($dbh, $log, $config) {
|
|
$this->dbh = $dbh;
|
|
$this->log = $log;
|
|
$this->config = $config;
|
|
}
|
|
|
|
public function processLifecycle() {
|
|
// Process lifecycle phases
|
|
if ($this->config['enableAutoRenew']) {
|
|
$this->processAutoRenewal();
|
|
} else {
|
|
$this->processGracePeriod();
|
|
}
|
|
|
|
$this->cleanUpPeriods();
|
|
|
|
if ($this->config['enableRedemptionPeriod']) {
|
|
$this->processPendingDelete();
|
|
$this->processPendingRestore();
|
|
}
|
|
|
|
if ($this->config['enablePendingDelete']) {
|
|
$this->processDomainDeletion();
|
|
}
|
|
}
|
|
|
|
// ========================
|
|
// 1. Auto-Renewal Phase
|
|
// ========================
|
|
private function processAutoRenewal() {
|
|
$this->log->info('Starting Auto-Renewal Phase.');
|
|
|
|
$minimum_data = $this->config['minimum_data'];
|
|
|
|
// Fetch domains eligible for auto-renewal
|
|
$sth = $this->dbh->prepare("
|
|
SELECT id, name, tldid, exdate, clid
|
|
FROM domain
|
|
WHERE CURRENT_TIMESTAMP > exdate
|
|
AND rgpstatus IS NULL
|
|
");
|
|
$sth->execute();
|
|
|
|
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
|
|
$domain_id = $row['id'];
|
|
$name = $row['name'];
|
|
$tldid = $row['tldid'];
|
|
$exdate = $row['exdate'];
|
|
$clid = $row['clid'];
|
|
|
|
// Check if domain can be set to auto-renew period
|
|
if ($this->canSetAutoRenewPeriod($domain_id)) {
|
|
// Process auto-renewal
|
|
$this->handleAutoRenewal($domain_id, $name, $tldid, $exdate, $clid);
|
|
}
|
|
|
|
$this->log->info("$name (ID $domain_id) processed for auto-renewal.");
|
|
}
|
|
|
|
$this->log->info('Completed Auto-Renewal Phase.');
|
|
}
|
|
|
|
private function canSetAutoRenewPeriod($domain_id) {
|
|
$sth_status = $this->dbh->prepare("SELECT status FROM domain_status WHERE domain_id = ?");
|
|
$sth_status->execute([$domain_id]);
|
|
|
|
while ($status_row = $sth_status->fetch(PDO::FETCH_ASSOC)) {
|
|
$status = $status_row['status'];
|
|
if (preg_match("/(serverUpdateProhibited|serverDeleteProhibited)$/", $status) || preg_match("/^pending/", $status)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private function handleAutoRenewal($domain_id, $name, $tldid, $exdate, $clid) {
|
|
// Get registrar balance and credit limit
|
|
$sthRegistrar = $this->dbh->prepare("
|
|
SELECT accountBalance, creditLimit
|
|
FROM registrar
|
|
WHERE id = ?
|
|
LIMIT 1
|
|
");
|
|
$sthRegistrar->execute([$clid]);
|
|
list($registrar_balance, $creditLimit) = $sthRegistrar->fetch(PDO::FETCH_NUM);
|
|
|
|
// Get domain price
|
|
$returnValue = getDomainPrice($this->dbh, $name, $tldid, 12, 'renew', $clid);
|
|
$price = $returnValue['price'];
|
|
|
|
if (($registrar_balance + $creditLimit) > $price) {
|
|
// Proceed with auto-renewal
|
|
$this->renewDomain($domain_id, $name, $exdate, $clid, $price);
|
|
} else {
|
|
// Insufficient funds, move to redemption period
|
|
$this->moveToRedemptionPeriod($domain_id, $exdate);
|
|
}
|
|
}
|
|
|
|
private function renewDomain($domain_id, $name, $exdate, $clid, $price) {
|
|
// Update domain and registrar records
|
|
$sth = $this->dbh->prepare("UPDATE domain SET rgpstatus = 'autoRenewPeriod', exdate = DATE_ADD(exdate, INTERVAL 12 MONTH), autoRenewPeriod = '12', renewedDate = exdate WHERE id = ?");
|
|
$sth->execute([$domain_id]);
|
|
|
|
$sth = $this->dbh->prepare("UPDATE registrar SET accountBalance = (accountBalance - ?) WHERE id = ?");
|
|
$sth->execute([$price, $clid]);
|
|
|
|
$sth = $this->dbh->prepare("INSERT INTO payment_history (registrar_id, date, description, amount) VALUES(?, CURRENT_TIMESTAMP, ?, ?)");
|
|
$description = "autoRenew domain $name for period 12 MONTH";
|
|
$sth->execute([$clid, $description, -$price]);
|
|
|
|
list($to) = $this->dbh->query("SELECT exdate FROM domain WHERE id = '$domain_id' LIMIT 1")->fetch(PDO::FETCH_NUM);
|
|
$sthStatement = $this->dbh->prepare("INSERT INTO statement (registrar_id, date, command, domain_name, length_in_months, fromS, toS, amount) VALUES(?, CURRENT_TIMESTAMP, ?, ?, ?, ?, ?, ?)");
|
|
$sthStatement->execute([$clid, 'autoRenew', $name, '12', $exdate, $to, $price]);
|
|
|
|
// Update statistics
|
|
$this->updateStatistics('renewed_domains');
|
|
}
|
|
|
|
private function moveToRedemptionPeriod($domain_id, $exdate) {
|
|
$this->dbh->beginTransaction();
|
|
try {
|
|
$this->dbh->prepare("DELETE FROM domain_status WHERE domain_id = ?")->execute([$domain_id]);
|
|
$this->dbh->prepare("UPDATE domain SET rgpstatus = 'redemptionPeriod', delTime = ? WHERE id = ?")->execute([$exdate, $domain_id]);
|
|
$this->dbh->prepare("INSERT INTO domain_status (domain_id, status) VALUES(?, 'pendingDelete')")->execute([$domain_id]);
|
|
|
|
$this->dbh->commit();
|
|
} catch (Exception $e) {
|
|
$this->dbh->rollBack();
|
|
$this->log->error("Failed to move domain ID $domain_id to redemption period: " . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
// ========================
|
|
// 2. Grace Period Phase
|
|
// ========================
|
|
private function processGracePeriod() {
|
|
$this->log->info('Starting Grace Period Phase.');
|
|
|
|
$gracePeriodDays = $this->config['gracePeriodDays'];
|
|
|
|
// Fetch domains eligible for grace period
|
|
$sth = $this->dbh->prepare("
|
|
SELECT id, name, exdate
|
|
FROM domain
|
|
WHERE CURRENT_TIMESTAMP > DATE_ADD(exdate, INTERVAL ? DAY)
|
|
AND rgpstatus IS NULL
|
|
");
|
|
$sth->execute([$gracePeriodDays]);
|
|
|
|
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
|
|
$domain_id = $row['id'];
|
|
$name = $row['name'];
|
|
$exdate = $row['exdate'];
|
|
|
|
// Check if domain can be moved to redemption period
|
|
if ($this->canSetGracePeriod($domain_id)) {
|
|
$this->moveToRedemptionPeriod($domain_id, $exdate);
|
|
$this->log->info("$name (ID $domain_id) moved to redemption period.");
|
|
}
|
|
}
|
|
|
|
$this->log->info('Completed Grace Period Phase.');
|
|
}
|
|
|
|
private function canSetGracePeriod($domain_id) {
|
|
$sth_status = $this->dbh->prepare("SELECT status FROM domain_status WHERE domain_id = ?");
|
|
$sth_status->execute([$domain_id]);
|
|
|
|
while ($status_row = $sth_status->fetch(PDO::FETCH_ASSOC)) {
|
|
$status = $status_row['status'];
|
|
if (preg_match("/(serverUpdateProhibited|serverDeleteProhibited)$/", $status) || preg_match("/^pending/", $status)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ========================
|
|
// 3. Clean-Up Periods
|
|
// ========================
|
|
private function cleanUpPeriods() {
|
|
$this->log->info('Starting Clean-Up Periods Phase.');
|
|
|
|
$periods = [
|
|
'autoRenewPeriod' => $this->config['autoRenewPeriodDays'],
|
|
'addPeriod' => $this->config['addPeriodDays'],
|
|
'renewPeriod' => $this->config['renewPeriodDays'],
|
|
'transferPeriod' => $this->config['transferPeriodDays'],
|
|
];
|
|
|
|
foreach ($periods as $periodName => $days) {
|
|
$this->cleanupPeriod($periodName, $days);
|
|
}
|
|
|
|
$this->log->info('Completed Clean-Up Periods Phase.');
|
|
}
|
|
|
|
private function cleanupPeriod($periodName, $days) {
|
|
$column = $periodName === 'addPeriod' ? 'crdate' : ($periodName === 'renewPeriod' ? 'renewedDate' : ($periodName === 'transferPeriod' ? 'trdate' : 'exdate'));
|
|
$sth = $this->dbh->prepare("UPDATE domain SET rgpstatus = NULL WHERE CURRENT_TIMESTAMP > DATE_ADD($column, INTERVAL ? DAY) AND rgpstatus = ?");
|
|
$sth->execute([$days, $periodName]);
|
|
}
|
|
|
|
// ========================
|
|
// 4. Pending Delete Phase
|
|
// ========================
|
|
private function processPendingDelete() {
|
|
$this->log->info('Starting Pending Delete Phase.');
|
|
|
|
$redemptionPeriodDays = $this->config['redemptionPeriodDays'];
|
|
|
|
// Fetch domains eligible for pending delete
|
|
$sth = $this->dbh->prepare("
|
|
SELECT id, name, exdate
|
|
FROM domain
|
|
WHERE CURRENT_TIMESTAMP > DATE_ADD(delTime, INTERVAL ? DAY)
|
|
AND rgpstatus = 'redemptionPeriod'
|
|
");
|
|
$sth->execute([$redemptionPeriodDays]);
|
|
|
|
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
|
|
$domain_id = $row['id'];
|
|
$name = $row['name'];
|
|
|
|
if ($this->canSetPendingDelete($domain_id)) {
|
|
$sthUpdate = $this->dbh->prepare("UPDATE domain SET rgpstatus = 'pendingDelete' WHERE id = ?");
|
|
$sthUpdate->execute([$domain_id]);
|
|
$this->log->info("$name (ID $domain_id) moved to pending delete.");
|
|
}
|
|
}
|
|
|
|
$this->log->info('Completed Pending Delete Phase.');
|
|
}
|
|
|
|
private function canSetPendingDelete($domain_id) {
|
|
$sth_status = $this->dbh->prepare("SELECT status FROM domain_status WHERE domain_id = ?");
|
|
$sth_status->execute([$domain_id]);
|
|
|
|
while ($status_row = $sth_status->fetch(PDO::FETCH_ASSOC)) {
|
|
$status = $status_row['status'];
|
|
if (preg_match("/(serverUpdateProhibited|serverDeleteProhibited)$/", $status)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ========================
|
|
// 5. Pending Restore Phase
|
|
// ========================
|
|
private function processPendingRestore() {
|
|
$this->log->info('Starting Pending Restore Phase.');
|
|
|
|
// Fetch domains in pendingRestore status that have exceeded the restore period
|
|
$sth = $this->dbh->prepare("
|
|
SELECT id, name
|
|
FROM domain
|
|
WHERE rgpstatus = 'pendingRestore'
|
|
AND CURRENT_TIMESTAMP > DATE_ADD(resTime, INTERVAL 7 DAY)
|
|
");
|
|
$sth->execute();
|
|
|
|
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
|
|
$domain_id = $row['id'];
|
|
$name = $row['name'];
|
|
|
|
$sthUpdate = $this->dbh->prepare("UPDATE domain SET rgpstatus = 'redemptionPeriod' WHERE id = ?");
|
|
$sthUpdate->execute([$domain_id]);
|
|
|
|
$this->log->info("$name (ID $domain_id) returned to redemption period from pending restore.");
|
|
}
|
|
|
|
$this->log->info('Completed Pending Restore Phase.');
|
|
}
|
|
|
|
// ========================
|
|
// 6. Domain Deletion Phase
|
|
// ========================
|
|
private function processDomainDeletion() {
|
|
$this->log->info('Starting Domain Deletion Phase.');
|
|
|
|
$totalPendingDays = $this->config['redemptionPeriodDays'] + $this->config['pendingDeletePeriodDays'];
|
|
|
|
// Fetch domains eligible for deletion
|
|
$sth = $this->dbh->prepare("
|
|
SELECT id, name, delTime
|
|
FROM domain
|
|
WHERE CURRENT_TIMESTAMP > DATE_ADD(delTime, INTERVAL ? DAY)
|
|
AND rgpstatus = 'pendingDelete'
|
|
");
|
|
$sth->execute([$totalPendingDays]);
|
|
|
|
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
|
|
$domain_id = $row['id'];
|
|
$name = $row['name'];
|
|
$delTime = $row['delTime'];
|
|
|
|
if ($this->shouldDeleteDomainNow($delTime)) {
|
|
if ($this->canDeleteDomain($domain_id)) {
|
|
$this->deleteDomain($domain_id, $name);
|
|
$this->log->info("$name (ID $domain_id) has been deleted.");
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->log->info('Completed Domain Deletion Phase.');
|
|
}
|
|
|
|
private function shouldDeleteDomainNow($delTime) {
|
|
$currentTime = new DateTime();
|
|
$deletionTime = new DateTime($delTime);
|
|
$totalPendingDays = $this->config['redemptionPeriodDays'] + $this->config['pendingDeletePeriodDays'];
|
|
$deletionTime->modify("+$totalPendingDays days");
|
|
|
|
if ($this->config['dropStrategy'] === 'fixed') {
|
|
$dropTime = $this->config['dropTime'];
|
|
$deletionTime->setTime((int)substr($dropTime, 0, 2), (int)substr($dropTime, 3, 2), (int)substr($dropTime, 6, 2));
|
|
return $currentTime >= $deletionTime;
|
|
} elseif ($this->config['dropStrategy'] === 'random') {
|
|
$randomDays = rand(0, $this->config['pendingDeletePeriodDays']);
|
|
$deletionTime->modify("+$randomDays days");
|
|
return $currentTime >= $deletionTime;
|
|
} else {
|
|
return $currentTime >= $deletionTime;
|
|
}
|
|
}
|
|
|
|
private function canDeleteDomain($domain_id) {
|
|
$sth_status = $this->dbh->prepare("SELECT status FROM domain_status WHERE domain_id = ?");
|
|
$sth_status->execute([$domain_id]);
|
|
|
|
$delete_domain = false;
|
|
while ($status_row = $sth_status->fetch(PDO::FETCH_ASSOC)) {
|
|
$status = $status_row['status'];
|
|
if ($status == 'pendingDelete') {
|
|
$delete_domain = true;
|
|
}
|
|
if (preg_match("/(serverUpdateProhibited|serverDeleteProhibited)$/", $status)) {
|
|
return false;
|
|
}
|
|
}
|
|
return $delete_domain;
|
|
}
|
|
|
|
private function deleteDomain($domain_id, $name) {
|
|
$minimum_data = $this->config['minimum_data'];
|
|
|
|
$this->dbh->beginTransaction();
|
|
try {
|
|
// Delete associated hosts
|
|
$sth = $this->dbh->prepare("SELECT id FROM host WHERE domain_id = ?");
|
|
$sth->execute([$domain_id]);
|
|
while ($host_row = $sth->fetch(PDO::FETCH_ASSOC)) {
|
|
$host_id = $host_row['id'];
|
|
$this->dbh->prepare("DELETE FROM host_addr WHERE host_id = ?")->execute([$host_id]);
|
|
$this->dbh->prepare("DELETE FROM host_status WHERE host_id = ?")->execute([$host_id]);
|
|
$this->dbh->prepare("DELETE FROM domain_host_map WHERE host_id = ?")->execute([$host_id]);
|
|
}
|
|
|
|
if (!$minimum_data) {
|
|
$this->dbh->prepare("DELETE FROM domain_contact_map WHERE domain_id = ?")->execute([$domain_id]);
|
|
}
|
|
$this->dbh->prepare("DELETE FROM domain_host_map WHERE domain_id = ?")->execute([$domain_id]);
|
|
$this->dbh->prepare("DELETE FROM domain_authInfo WHERE domain_id = ?")->execute([$domain_id]);
|
|
$this->dbh->prepare("DELETE FROM domain_status WHERE domain_id = ?")->execute([$domain_id]);
|
|
$this->dbh->prepare("DELETE FROM host WHERE domain_id = ?")->execute([$domain_id]);
|
|
|
|
$this->dbh->prepare("DELETE FROM domain WHERE id = ?")->execute([$domain_id]);
|
|
|
|
// Update statistics
|
|
$this->updateStatistics('deleted_domains');
|
|
|
|
$this->dbh->commit();
|
|
} catch (Exception $e) {
|
|
$this->dbh->rollBack();
|
|
$this->log->error("$domain_id|$name could not be deleted: " . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
// ========================
|
|
// Helper Methods
|
|
// ========================
|
|
private function updateStatistics($field) {
|
|
// Ensure today's statistics record exists
|
|
$sth = $this->dbh->prepare("SELECT id FROM statistics WHERE date = CURDATE()");
|
|
$sth->execute();
|
|
if (!$sth->fetchColumn()) {
|
|
$this->dbh->prepare("INSERT INTO statistics (date) VALUES (CURDATE())")->execute();
|
|
}
|
|
// Update the specific field
|
|
$sthUpdate = $this->dbh->prepare("UPDATE statistics SET $field = $field + 1 WHERE date = CURDATE()");
|
|
$sthUpdate->execute();
|
|
}
|
|
}
|