Further cp updates

This commit is contained in:
Pinga 2023-12-04 19:21:40 +02:00
parent 56ff89a37c
commit ee02066073
6 changed files with 413 additions and 28 deletions

View file

@ -9,12 +9,12 @@ use Psr\Container\ContainerInterface;
class HostsController extends Controller
{
public function view(Request $request, Response $response)
public function listHosts(Request $request, Response $response)
{
return view($response,'admin/hosts/view.twig');
return view($response,'admin/hosts/listHosts.twig');
}
public function create(Request $request, Response $response)
public function createHost(Request $request, Response $response)
{
if ($request->getMethod() === 'POST') {
// Retrieve POST data
@ -37,7 +37,7 @@ class HostsController extends Controller
if (preg_match('/^([A-Z0-9]([A-Z0-9-]{0,61}[A-Z0-9]){0,1}\.){1,125}[A-Z0-9]([A-Z0-9-]{0,61}[A-Z0-9])$/i', $hostName) && strlen($hostName) < 254) {
$host_id_already_exist = $hostModel->getHostByNom($hostName);
if ($host_id_already_exist) {
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => 'host name already exists',
'registrars' => $registrars,
@ -45,7 +45,7 @@ class HostsController extends Controller
]);
}
} else {
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => 'Invalid host name',
'registrars' => $registrars,
@ -64,7 +64,7 @@ class HostsController extends Controller
if ($ipv4) {
$ipv4 = normalize_v4_address($ipv4);
if (!filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => 'Invalid host addr v4',
'registrars' => $registrars,
@ -76,7 +76,7 @@ class HostsController extends Controller
if ($ipv6) {
$ipv6 = normalize_v6_address($ipv6);
if (!filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => 'Invalid host addr v6',
'registrars' => $registrars,
@ -114,7 +114,7 @@ class HostsController extends Controller
}
if (!$domain_exist) {
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => 'A host name object can NOT be created in a repository for which no superordinate domain name object exists',
'registrars' => $registrars,
@ -124,7 +124,7 @@ class HostsController extends Controller
if ($_SESSION['auth_roles'] !== 0) {
if ($clid != $clid_domain) {
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => 'The domain name belongs to another registrar, you are not allowed to create hosts for it',
'registrars' => $registrars,
@ -151,7 +151,7 @@ class HostsController extends Controller
$host_id = $db->getLastInsertId();
if (!$ipv4 && !$ipv6) {
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => 'At least one of IPv4 or IPv6 must be provided',
'registrars' => $registrars,
@ -195,7 +195,7 @@ class HostsController extends Controller
$db->commit();
} catch (Exception $e) {
$db->rollBack();
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'error' => $e->getMessage(),
'registrars' => $registrars,
@ -208,7 +208,7 @@ class HostsController extends Controller
[$hostName]
);
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'crdate' => $crdate,
'registrars' => $registrars,
@ -242,7 +242,7 @@ class HostsController extends Controller
[$hostName]
);
return view($response, 'admin/hosts/create.twig', [
return view($response, 'admin/hosts/createHost.twig', [
'hostName' => $hostName,
'crdate' => $crdate,
'registrars' => $registrars,
@ -261,7 +261,7 @@ class HostsController extends Controller
}
// Default view for GET requests or if POST data is not set
return view($response,'admin/hosts/create.twig', [
return view($response,'admin/hosts/createHost.twig', [
'registrars' => $registrars,
'registrar' => $registrar,
]);
@ -336,4 +336,263 @@ class HostsController extends Controller
}
public function updateHost(Request $request, Response $response, $args)
{
$db = $this->container->get('db');
// Get the current URI
$uri = $request->getUri()->getPath();
function isValidHostname($hostname) {
// Check for IDN and convert to ASCII if necessary
if (mb_detect_encoding($hostname, 'ASCII', true) === false) {
$hostname = idn_to_ascii($hostname, 0, INTL_IDNA_VARIANT_UTS46);
}
// Regular expression for validating a hostname (simplified version)
$pattern = '/^([a-zA-Z0-9-]{1,63}\.){1,}[a-zA-Z]{2,63}$/';
return preg_match($pattern, $hostname);
}
if ($args && isValidHostname($args)) {
$internal_host = false;
$query = "SELECT tld FROM domain_tld";
$result = $db->select($query);
foreach ($result as $row) {
if (preg_match("/" . preg_quote(strtoupper($row['tld']), '/') . "$/i", $args)) {
$internal_host = true;
break;
}
}
if (!$internal_host) {
$host = $db->selectRow('SELECT id, name, clid, crdate FROM host WHERE name = ?',
[ $args ]);
if ($host) {
return view($response,'admin/hosts/updateInternalHost.twig', [
'host' => $host
]);
} else {
// Host does not exist, redirect to the hosts view
return $response->withHeader('Location', '/hosts')->withStatus(302);
}
} else {
$host = $db->selectRow('SELECT id, name, clid, crdate FROM host WHERE name = ?',
[ $args ]);
if ($host) {
$registrars = $db->selectRow('SELECT id, clid, name FROM registrar WHERE id = ?', [$host['clid']]);
// Check if the user is not an admin (assuming role 0 is admin)
if ($_SESSION["auth_roles"] != 0) {
$userRegistrars = $db->select('SELECT registrar_id FROM registrar_users WHERE user_id = ?', [$_SESSION['auth_user_id']]);
// Assuming $userRegistrars returns an array of arrays, each containing 'registrar_id'
$userRegistrarIds = array_column($userRegistrars, 'registrar_id');
// Check if the registrar's ID is in the user's list of registrar IDs
if (!in_array($registrars['id'], $userRegistrarIds)) {
// Redirect to the hosts view if the user is not authorized for this host
return $response->withHeader('Location', '/hosts')->withStatus(302);
}
}
$hostIPv4 = $db->select("SELECT addr FROM host_addr WHERE host_id = ? AND ip = 'v4'",
[ $host['id'] ]);
$hostIPv6 = $db->select("SELECT addr FROM host_addr WHERE host_id = ? AND ip = 'v6'",
[ $host['id'] ]);
return view($response,'admin/hosts/updateHost.twig', [
'host' => $host,
'hostIPv4' => $hostIPv4,
'hostIPv6' => $hostIPv6,
'registrars' => $registrars,
'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 updateHostProcess(Request $request, Response $response)
{
if ($request->getMethod() === 'POST') {
// Retrieve POST data
$data = $request->getParsedBody();
$db = $this->container->get('db');
$hostName = $data['hostName'] ?? null;
$result = $db->selectRow('SELECT registrar_id FROM registrar_users WHERE user_id = ?', [$_SESSION['auth_user_id']]);
if ($_SESSION["auth_roles"] != 0) {
$clid = $result['registrar_id'];
} else {
$clid = $db->selectValue('SELECT clid FROM host WHERE name = ?', [$hostName]);
}
$ipv4 = $data['ipv4'] ?? null;
$ipv6 = $data['ipv6'] ?? null;
try {
$db->beginTransaction();
$host_id = $db->selectValue(
'SELECT id FROM host WHERE name = ?',
[$hostName]
);
if (isset($ipv4) && !empty($ipv4)) {
$ipv4 = normalize_v4_address($ipv4);
$does_it_exist = $db->selectValue("SELECT id FROM host_addr WHERE host_id = ? AND ip = 'v4'", [$host_id]);
if ($does_it_exist) {
$db->update(
'host_addr',
[
'addr' => $ipv4
],
[
'host_id' => $host_id,
'ip' => 'v4'
]
);
} else {
$db->insert(
'host_addr',
[
'addr' => $ipv4,
'host_id' => $host_id,
'ip' => 'v4'
]
);
}
}
if (isset($ipv6) && !empty($ipv6)) {
$ipv6 = normalize_v6_address($ipv6);
$does_it_exist = $db->selectValue("SELECT id FROM host_addr WHERE host_id = ? AND ip = 'v6'", [$host_id]);
if ($does_it_exist) {
$db->update(
'host_addr',
[
'addr' => $ipv6
],
[
'host_id' => $host_id,
'ip' => 'v6'
]
);
} else {
$db->insert(
'host_addr',
[
'addr' => $ipv6,
'host_id' => $host_id,
'ip' => 'v6'
]
);
}
}
$currentDateTime = new \DateTime();
$update = $currentDateTime->format('Y-m-d H:i:s.v'); // Current timestamp
$db->update('host', [
'update' => $update,
'upid' => $clid
],
[
'name' => $hostName
]
);
$db->commit();
} catch (Exception $e) {
$db->rollBack();
$this->container->get('flash')->addMessage('error', 'Database failure during update: ' . $e->getMessage());
return $response->withHeader('Location', '/host/update/'.$hostName)->withStatus(302);
}
$this->container->get('flash')->addMessage('success', 'Host ' . $hostName . ' has been updated successfully on ' . $update);
return $response->withHeader('Location', '/host/update/'.$hostName)->withStatus(302);
}
}
public function deleteHost(Request $request, Response $response, $args)
{
// if ($request->getMethod() === 'POST') {
$db = $this->container->get('db');
// Get the current URI
$uri = $request->getUri()->getPath();
function isValidHostname($hostname) {
// Check for IDN and convert to ASCII if necessary
if (mb_detect_encoding($hostname, 'ASCII', true) === false) {
$hostname = idn_to_ascii($hostname, 0, INTL_IDNA_VARIANT_UTS46);
}
// Regular expression for validating a hostname (simplified version)
$pattern = '/^([a-zA-Z0-9-]{1,63}\.){1,}[a-zA-Z]{2,63}$/';
return preg_match($pattern, $hostname);
}
if ($args && isValidHostname($args)) {
$host_id = $db->selectValue('SELECT id FROM host WHERE name = ?',
[ $args ]);
$is_linked = $db->selectRow('SELECT domain_id FROM domain_host_map WHERE host_id = ?',
[ $host_id ]);
if ($is_linked) {
$this->container->get('flash')->addMessage('error', 'It is not possible to delete ' . $args . ' because it is a dependency, it is used by some domain');
return $response->withHeader('Location', '/hosts')->withStatus(302);
} else {
$db->delete(
'host_addr',
[
'host_id' => $host_id
]
);
$db->delete(
'host_status',
[
'host_id' => $host_id
]
);
$db->delete(
'host',
[
'id' => $host_id
]
);
$this->container->get('flash')->addMessage('success', 'Host ' . $args . ' deleted successfully');
return $response->withHeader('Location', '/hosts')->withStatus(302);
}
} else {
// Redirect to the hosts view
return $response->withHeader('Location', '/hosts')->withStatus(302);
}
//}
}
}

View file

@ -62,7 +62,7 @@
</a>
</div>
<div class="col-sm-6 col-lg-3">
<a class="card card-link" href="{{route('contacts')}}">
<a class="card card-link" href="{{route('listContacts')}}">
<div class="card-body">
<div class="row align-items-center">
<div class="col-auto">
@ -79,7 +79,7 @@
</a>
</div>
<div class="col-sm-6 col-lg-3">
<a class="card card-link" href="{{route('hosts')}}">
<a class="card card-link" href="{{route('listHosts')}}">
<div class="card-body">
<div class="row align-items-center">
<div class="col-auto">

View file

@ -36,6 +36,7 @@
<div class="page-body">
<div class="container-xl">
<div class="col-12">
{% include 'partials/flash.twig' %}
<div class="card">
<div class="card-body border-bottom py-3">
<div class="d-flex">

View file

@ -0,0 +1,70 @@
{% extends "layouts/app.twig" %}
{% block title %}{{ __('Update Host') }} {{ host.name }}{% endblock %}
{% block content %}
<div class="page-wrapper">
<!-- Page header -->
<div class="page-header d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<!-- Page pre-title -->
<div class="page-pretitle">
Overview
</div>
<h2 class="page-title">
{{ __('Update Host') }} {{ host.name }}
</h2>
</div>
</div>
</div>
</div>
<!-- Page body -->
<div class="page-body">
<div class="container-xl">
<div class="col-12">
{% include 'partials/flash.twig' %}
<div class="card">
<div class="card-body">
<form action="/host/update" method="post">
{{ csrf.field | raw }}<input type="hidden" name="hostName" value="{{ host.name }}">
<div class="form-group mt-3">
<label for="ipv4" class="form-label">{{ __('IPv4 Address') }}:</label>
<input type="text" class="form-control" id="ipv4" name="ipv4" placeholder="192.168.1.1" pattern="^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$" value="{{ hostIPv4[0].addr }}">
<small class="form-text text-muted">{{ __('Please enter a valid IPv4 address.') }}</small>
</div>
<div class="form-group mt-3">
<label for="ipv6" class="form-label">{{ __('IPv6 Address') }}:</label>
<input type="text" class="form-control" id="ipv6" name="ipv6" placeholder="2001:0db8:85a3:0000:0000:8a2e:0370:7334" autocapitalize="none" value="{{ hostIPv6[0].addr }}">
<small class="form-text text-muted">{{ __('Please enter a valid IPv6 address.') }}</small>
</div>
</div>
<div class="card-footer">
<div class="row align-items-center">
<div class="col-auto">
<button type="submit" class="btn btn-primary">Update Host</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<footer class="footer footer-transparent d-print-none">
<div class="container-xl">
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
<ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item">
Copyright &copy; 2023
<a href="https://namingo.org" target="_blank" class="link-secondary">Namingo</a>.
</li>
</ul>
</div>
</div>
</div>
</footer>
</div>
{% endblock %}

View file

@ -0,0 +1,50 @@
{% extends "layouts/app.twig" %}
{% block title %}{{ __('Update Host') }} {{ host.name }}{% endblock %}
{% block content %}
<div class="page-wrapper">
<!-- Page header -->
<div class="page-header d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<!-- Page pre-title -->
<div class="page-pretitle">
Overview
</div>
<h2 class="page-title">
{{ __('Update Host') }} {{ host.name }}
</h2>
</div>
</div>
</div>
</div>
<!-- Page body -->
<div class="page-body">
<div class="container-xl">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="alert alert-important alert-info" role="alert">
The host you're trying to update, <strong>{{ host.name }}</strong>, is external to the registry. Consequently, it does not store any IP addresses within our system, and therefore, does not require any updates from your end. This means there are no associated IP addresses under our management that need your attention.
</div>
</div>
</div>
</div>
</div>
<footer class="footer footer-transparent d-print-none">
<div class="container-xl">
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
<ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item">
Copyright &copy; 2023
<a href="https://namingo.org" target="_blank" class="link-secondary">Namingo</a>.
</li>
</ul>
</div>
</div>
</div>
</footer>
</div>
{% endblock %}

View file

@ -5,14 +5,22 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.6.0/jspdf.plugin.autotable.min.js"></script>
<script>
var table;
document.addEventListener("DOMContentLoaded", function(){
document.querySelector("#hostTable").addEventListener('click', function(e) {
if (e.target.matches('.delete-btn')) {
let id = e.target.getAttribute('data-id');
deleteRecord(id);
// Check if the clicked element has the class 'delete-btn' or the ID 'delete-btn'
if (e.target.classList.contains('delete-btn') || e.target.id === 'delete-btn') {
// Confirmation dialog
let confirmDeletion = confirm("Are you sure you want to delete this record?");
// If user does not confirm, prevent the default action
if (!confirmDeletion) {
e.preventDefault();
}
}
});
document.addEventListener("DOMContentLoaded", function(){
function hostLinkFormatter(cell){
var value = cell.getValue();
return `<a href="/host/view/${value}" style="font-weight:bold;">${value}</a>`;
@ -21,7 +29,7 @@
function actionsFormatter(cell, formatterParams, onRendered) {
return `
<a class="btn btn-primary btn-icon update-btn" href="host/update/${cell.getRow().getData().name}"><svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z"></path><path d="M16 5l3 3"></path></svg></a>
<button class="btn btn-danger btn-icon delete-btn" data-id="${cell.getRow().getData().id}"><svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 7h16"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path><path d="M10 12l4 4m0 -4l-4 4"></path></svg></button>
<a class="btn btn-danger btn-icon delete-btn" id="delete-btn" href="host/delete/${cell.getRow().getData().name}"><svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 7h16"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path><path d="M10 12l4 4m0 -4l-4 4"></path></svg></a>
`;
}
@ -100,22 +108,19 @@
{title:"Name", field:"name", width:300, headerSort:false, formatter: hostLinkFormatter, responsive:0},
{title:"Creation Date", field:"crdate", width:300, minWidth:200, headerSort:false, responsive:2},
{title:"Status", field:"host_status", width:300, minWidth:200, formatter: statusFormatter, headerSort:false, download:false, responsive:2},
{title: "Actions", formatter: actionsFormatter, headerSort: false, download:false, hozAlign: "center", responsive:0, cellClick:function(e, cell){ e.stopPropagation(); }},
{title: "Actions", formatter: actionsFormatter, headerSort: false, download:false, hozAlign: "center", responsive:0},
],
placeholder:function(){
return this.getHeaderFilters().length ? "No Matching Data" : "No Data"; //set placeholder based on if there are currently any header filters
}
});
var searchInput = document.getElementById("search-input");
searchInput.addEventListener("input", function () {
updateSearchTerm(searchInput.value);
});
});
function deleteRecord(id) {
console.log("Deleting record with ID: " + id);
}
function downloadCSV() {
table.download("csv", "data.csv");
}