diff --git a/cp/app/Controllers/ContactsController.php b/cp/app/Controllers/ContactsController.php index 82c158a..3973351 100644 --- a/cp/app/Controllers/ContactsController.php +++ b/cp/app/Controllers/ContactsController.php @@ -881,6 +881,57 @@ class ContactsController extends Controller } + public function historyContact(Request $request, Response $response, $args) + { + if (envi('MINIMUM_DATA') === 'true') { + return $response->withHeader('Location', '/dashboard')->withStatus(302); + } + + $db = $this->container->get('db'); + $db_audit = $this->container->get('db_audit'); + // Get the current URI + $uri = $request->getUri()->getPath(); + + if ($args) { + $args = trim($args); + + if (!preg_match('/^[a-zA-Z0-9\-]+$/', $args)) { + $this->container->get('flash')->addMessage('error', 'Invalid contact ID format'); + return $response->withHeader('Location', '/contacts')->withStatus(302); + } + + try { + $exists = $db_audit->selectValue('SELECT 1 FROM domain LIMIT 1'); + } catch (\PDOException $e) { + throw new \RuntimeException('Audit table is empty or not configured'); + } + + $contact = $db->selectRow('SELECT id, identifier FROM contact WHERE identifier = ?', + [ $args ]); + + if ($contact) { + $history = $db_audit->select( + 'SELECT * FROM contact WHERE identifier = ? ORDER BY audit_timestamp DESC, audit_rownum ASC', + [$args] + ); + + return view($response,'admin/contacts/historyContact.twig', [ + 'contact' => $contact, + 'history' => $history, + 'currentUri' => $uri + ]); + } else { + // Contact does not exist, redirect to the contacts view + return $response->withHeader('Location', '/contacts')->withStatus(302); + } + + } else { + // Redirect to the contacts view + return $response->withHeader('Location', '/contacts')->withStatus(302); + } + + } + public function updateContact(Request $request, Response $response, $args) { if (envi('MINIMUM_DATA') === 'true') { diff --git a/cp/app/Controllers/HostsController.php b/cp/app/Controllers/HostsController.php index 6111624..224379e 100644 --- a/cp/app/Controllers/HostsController.php +++ b/cp/app/Controllers/HostsController.php @@ -297,7 +297,57 @@ class HostsController extends Controller } } - + + public function historyHost(Request $request, Response $response, $args) + { + $db = $this->container->get('db'); + $db_audit = $this->container->get('db_audit'); + // Get the current URI + $uri = $request->getUri()->getPath(); + + if ($args && isValidHostname($args)) { + $args = trim($args); + + if (mb_detect_encoding($args, 'ASCII', true) === false) { + $args = idn_to_ascii($args, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); + if ($args === false) { + // Redirect to the hosts view + return $response->withHeader('Location', '/hosts')->withStatus(302); + } + } + + $host = $db->selectRow('SELECT id, name FROM host WHERE name = ?', + [ $args ]); + + if ($host) { + try { + $exists = $db_audit->selectValue('SELECT 1 FROM domain LIMIT 1'); + } catch (\PDOException $e) { + throw new \RuntimeException('Audit table is empty or not configured'); + } + + $history = $db_audit->select( + 'SELECT * FROM host WHERE name = ? ORDER BY audit_timestamp DESC, audit_rownum ASC', + [$args] + ); + + return view($response,'admin/hosts/historyHost.twig', [ + 'host' => $host, + 'history' => $history, + 'currentUri' => $uri + ]); + } else { + // Host does not exist, redirect to the hosts view + return $response->withHeader('Location', '/hosts')->withStatus(302); + } + + } else { + // Redirect to the hosts view + return $response->withHeader('Location', '/hosts')->withStatus(302); + } + + } + public function updateHost(Request $request, Response $response, $args) { $db = $this->container->get('db'); diff --git a/cp/app/Controllers/RegistrarsController.php b/cp/app/Controllers/RegistrarsController.php index 538d6be..4a697e9 100644 --- a/cp/app/Controllers/RegistrarsController.php +++ b/cp/app/Controllers/RegistrarsController.php @@ -407,7 +407,54 @@ class RegistrarsController extends Controller } } - + + public function historyRegistrar(Request $request, Response $response, $args) + { + $db = $this->container->get('db'); + $db_audit = $this->container->get('db_audit'); + // Get the current URI + $uri = $request->getUri()->getPath(); + + if ($args) { + $args = trim(preg_replace('/\s+/', ' ', $args)); + + if (!preg_match('/^[a-zA-Z0-9\s.\-]+$/', $args)) { + $this->container->get('flash')->addMessage('error', 'Invalid registrar'); + return $response->withHeader('Location', '/registrars')->withStatus(302); + } + + $registrar = $db->selectRow('SELECT id,name,clid FROM registrar WHERE clid = ?', + [ $args ]); + + if ($registrar) { + try { + $exists = $db_audit->selectValue('SELECT 1 FROM domain LIMIT 1'); + } catch (\PDOException $e) { + throw new \RuntimeException('Audit table is empty or not configured'); + } + + $history = $db_audit->select( + 'SELECT * FROM registrar WHERE clid = ? ORDER BY audit_timestamp DESC, audit_rownum ASC LIMIT 200', + [$args] + ); + + return view($response,'admin/registrars/historyRegistrar.twig', [ + 'registrar' => $registrar, + 'history' => $history, + 'currentUri' => $uri + ]); + } else { + // Registrar does not exist, redirect to the registrars view + return $response->withHeader('Location', '/registrars')->withStatus(302); + } + + } else { + // Redirect to the registrars view + return $response->withHeader('Location', '/registrars')->withStatus(302); + } + + } + public function registrar(Request $request, Response $response) { $db = $this->container->get('db'); diff --git a/cp/resources/views/admin/contacts/historyContact.twig b/cp/resources/views/admin/contacts/historyContact.twig new file mode 100644 index 0000000..53a6c2e --- /dev/null +++ b/cp/resources/views/admin/contacts/historyContact.twig @@ -0,0 +1,125 @@ +{% extends "layouts/app.twig" %} + +{% block title %}{{ __('Contact History') }}{% endblock %} + +{% block content %} +
+ + + +
+
+
+
+
+

+ {{ __('Contact') }} {{ contact.identifier }} +

+
+
+
+ + + + + + + + + + + + + + {% if history|length == 0 %} + + + + {% else %} + {% set max = history|length %} + {% for i in 0..max-1 %} + {% set entry = history[i] %} + {% if entry.audit_statement == 'UPDATE' and entry.audit_type == 'OLD' %} + {% set old = entry %} + {% set new = history[i + 1] is defined and history[i + 1].audit_type == 'NEW' ? history[i + 1] : {} %} + {% for key in old|keys %} + {% if old[key] != new[key] and key not in ['audit_timestamp','audit_statement','audit_type','audit_uuid','audit_rownum','audit_user','audit_ses_id','audit_usr_id'] %} + + + + + + + + + + {% endif %} + {% endfor %} + {% elseif entry.audit_statement == 'INSERT' %} + + + + + + + + {% elseif entry.audit_statement == 'DELETE' %} + + + + + + + + {% endif %} + {% endfor %} + {% endif %} + +
{{ __('Timestamp') }}{{ __('Action') }}{{ __('User') }}{{ __('Session') }}{{ __('Changed Field') }}{{ __('Old Value') }}{{ __('New Value') }}
{{ __('No audit history available for this contact.') }}
{{ old.audit_timestamp }}{{ old.audit_statement }}{{ old.audit_usr_id|default('–') }}{{ old.audit_ses_id|default('–') }}{{ key }}{{ old[key]|default('–') }}{{ new[key]|default('–') }}
{{ entry.audit_timestamp }}{{ entry.audit_statement }}{{ entry.audit_usr_id|default('–') }}{{ entry.audit_ses_id|default('–') }}{{ __('New contact inserted.') }}
{{ entry.audit_timestamp }}{{ entry.audit_statement }}{{ entry.audit_usr_id|default('–') }}{{ entry.audit_ses_id|default('–') }}{{ __('Contact was deleted.') }}
+
+
+
+
+
+
+ {% include 'partials/footer.twig' %} +
+{% endblock %} \ No newline at end of file diff --git a/cp/resources/views/admin/contacts/viewContact.twig b/cp/resources/views/admin/contacts/viewContact.twig index 125015f..5082e3d 100644 --- a/cp/resources/views/admin/contacts/viewContact.twig +++ b/cp/resources/views/admin/contacts/viewContact.twig @@ -29,6 +29,13 @@
+ + + {{ __('Contact History') }} + + + + {{ __('Update Contact') }} diff --git a/cp/resources/views/admin/hosts/historyHost.twig b/cp/resources/views/admin/hosts/historyHost.twig new file mode 100644 index 0000000..d74d2b4 --- /dev/null +++ b/cp/resources/views/admin/hosts/historyHost.twig @@ -0,0 +1,125 @@ +{% extends "layouts/app.twig" %} + +{% block title %}{{ __('Host History') }}{% endblock %} + +{% block content %} +
+ + + +
+
+
+
+
+

+ {{ __('Host') }} {{ host.name }} +

+
+
+
+ + + + + + + + + + + + + + {% if history|length == 0 %} + + + + {% else %} + {% set max = history|length %} + {% for i in 0..max-1 %} + {% set entry = history[i] %} + {% if entry.audit_statement == 'UPDATE' and entry.audit_type == 'OLD' %} + {% set old = entry %} + {% set new = history[i + 1] is defined and history[i + 1].audit_type == 'NEW' ? history[i + 1] : {} %} + {% for key in old|keys %} + {% if old[key] != new[key] and key not in ['audit_timestamp','audit_statement','audit_type','audit_uuid','audit_rownum','audit_user','audit_ses_id','audit_usr_id'] %} + + + + + + + + + + {% endif %} + {% endfor %} + {% elseif entry.audit_statement == 'INSERT' %} + + + + + + + + {% elseif entry.audit_statement == 'DELETE' %} + + + + + + + + {% endif %} + {% endfor %} + {% endif %} + +
{{ __('Timestamp') }}{{ __('Action') }}{{ __('User') }}{{ __('Session') }}{{ __('Changed Field') }}{{ __('Old Value') }}{{ __('New Value') }}
{{ __('No audit history available for this host.') }}
{{ old.audit_timestamp }}{{ old.audit_statement }}{{ old.audit_usr_id|default('–') }}{{ old.audit_ses_id|default('–') }}{{ key }}{{ old[key]|default('–') }}{{ new[key]|default('–') }}
{{ entry.audit_timestamp }}{{ entry.audit_statement }}{{ entry.audit_usr_id|default('–') }}{{ entry.audit_ses_id|default('–') }}{{ __('New host inserted.') }}
{{ entry.audit_timestamp }}{{ entry.audit_statement }}{{ entry.audit_usr_id|default('–') }}{{ entry.audit_ses_id|default('–') }}{{ __('Host was deleted.') }}
+
+
+
+
+
+
+ {% include 'partials/footer.twig' %} +
+{% endblock %} \ No newline at end of file diff --git a/cp/resources/views/admin/hosts/viewHost.twig b/cp/resources/views/admin/hosts/viewHost.twig index 651f94b..494f314 100644 --- a/cp/resources/views/admin/hosts/viewHost.twig +++ b/cp/resources/views/admin/hosts/viewHost.twig @@ -29,6 +29,13 @@
+ + + {{ __('Host History') }} + + + + {{ __('Update Host') }} diff --git a/cp/resources/views/admin/registrars/historyRegistrar.twig b/cp/resources/views/admin/registrars/historyRegistrar.twig new file mode 100644 index 0000000..32acbd6 --- /dev/null +++ b/cp/resources/views/admin/registrars/historyRegistrar.twig @@ -0,0 +1,125 @@ +{% extends "layouts/app.twig" %} + +{% block title %}{{ __('Registrar History') }}{% endblock %} + +{% block content %} +
+ + + +
+
+
+
+
+

+ {{ __('Registrar') }} {{ registrar.name }} +

+
+
+
+ + + + + + + + + + + + + + {% if history|length == 0 %} + + + + {% else %} + {% set max = history|length %} + {% for i in 0..max-1 %} + {% set entry = history[i] %} + {% if entry.audit_statement == 'UPDATE' and entry.audit_type == 'OLD' %} + {% set old = entry %} + {% set new = history[i + 1] is defined and history[i + 1].audit_type == 'NEW' ? history[i + 1] : {} %} + {% for key in old|keys %} + {% if old[key] != new[key] and key not in ['audit_timestamp','audit_statement','audit_type','audit_uuid','audit_rownum','audit_user','audit_ses_id','audit_usr_id'] %} + + + + + + + + + + {% endif %} + {% endfor %} + {% elseif entry.audit_statement == 'INSERT' %} + + + + + + + + {% elseif entry.audit_statement == 'DELETE' %} + + + + + + + + {% endif %} + {% endfor %} + {% endif %} + +
{{ __('Timestamp') }}{{ __('Action') }}{{ __('User') }}{{ __('Session') }}{{ __('Changed Field') }}{{ __('Old Value') }}{{ __('New Value') }}
{{ __('No audit history available for this registrar.') }}
{{ old.audit_timestamp }}{{ old.audit_statement }}{{ old.audit_usr_id|default('–') }}{{ old.audit_ses_id|default('–') }}{{ key }}{{ old[key]|default('–') }}{{ new[key]|default('–') }}
{{ entry.audit_timestamp }}{{ entry.audit_statement }}{{ entry.audit_usr_id|default('–') }}{{ entry.audit_ses_id|default('–') }}{{ __('New registrar inserted.') }}
{{ entry.audit_timestamp }}{{ entry.audit_statement }}{{ entry.audit_usr_id|default('–') }}{{ entry.audit_ses_id|default('–') }}{{ __('Registrar was deleted.') }}
+
+
+
+
+
+
+ {% include 'partials/footer.twig' %} +
+{% endblock %} \ No newline at end of file diff --git a/cp/resources/views/admin/registrars/viewRegistrar.twig b/cp/resources/views/admin/registrars/viewRegistrar.twig index 16e0e8a..e3e920e 100644 --- a/cp/resources/views/admin/registrars/viewRegistrar.twig +++ b/cp/resources/views/admin/registrars/viewRegistrar.twig @@ -30,6 +30,13 @@
+ + + {{ __('Registrar History') }} + + + + {{ __('Update Registrar') }} diff --git a/cp/routes/web.php b/cp/routes/web.php index 18a27c0..285ace6 100644 --- a/cp/routes/web.php +++ b/cp/routes/web.php @@ -78,6 +78,7 @@ $app->group('', function ($route) { $route->map(['GET', 'POST'], '/contact/create', ContactsController::class . ':createContact')->setName('createContact'); $route->map(['GET', 'POST'], '/contact/create-api', ContactsController::class . ':createContactApi')->setName('createContactApi'); $route->get('/contact/view/{contact}', ContactsController::class . ':viewContact')->setName('viewContact'); + $route->get('/contact/history/{contact}', ContactsController::class . ':historyContact')->setName('historyContact'); $route->get('/contact/update/{contact}', ContactsController::class . ':updateContact')->setName('updateContact'); $route->get('/contact/validate/{contact}', ContactsController::class . ':validateContact')->setName('validateContact'); $route->post('/contact/update', ContactsController::class . ':updateContactProcess')->setName('updateContactProcess'); @@ -87,6 +88,7 @@ $app->group('', function ($route) { $route->get('/hosts', HostsController::class .':listHosts')->setName('listHosts'); $route->map(['GET', 'POST'], '/host/create', HostsController::class . ':createHost')->setName('createHost'); $route->get('/host/view/{host}', HostsController::class . ':viewHost')->setName('viewHost'); + $route->get('/host/history/{host}', HostsController::class . ':historyHost')->setName('historyHost'); $route->get('/host/update/{host}', HostsController::class . ':updateHost')->setName('updateHost'); $route->post('/host/update', HostsController::class . ':updateHostProcess')->setName('updateHostProcess'); $route->map(['GET', 'POST'], '/host/delete/{host}', HostsController::class . ':deleteHost')->setName('deleteHost'); @@ -94,6 +96,7 @@ $app->group('', function ($route) { $route->get('/registrars', RegistrarsController::class .':view')->setName('registrars'); $route->map(['GET', 'POST'], '/registrar/create', RegistrarsController::class . ':create')->setName('registrarcreate'); $route->get('/registrar/view/{registrar}', RegistrarsController::class . ':viewRegistrar')->setName('viewRegistrar'); + $route->get('/registrar/history/{registrar}', RegistrarsController::class . ':historyRegistrar')->setName('historyRegistrar'); $route->get('/registrar/update/{registrar}', RegistrarsController::class . ':updateRegistrar')->setName('updateRegistrar'); $route->get('/registrar/pricing/{registrar}', RegistrarsController::class . ':customPricingView')->setName('customPricingView'); $route->map(['POST', 'DELETE'], '/registrar/updatepricing/{registrar}', RegistrarsController::class . ':updateCustomPricing')->setName('updateCustomPricing');