Tokens can be also updated

This commit is contained in:
Pinga 2025-03-31 17:33:30 +03:00
parent 664102d65d
commit 25f119a094
4 changed files with 180 additions and 4 deletions

View file

@ -1358,6 +1358,98 @@ class SystemController extends Controller
]); ]);
} }
public function updateToken(Request $request, Response $response, $args)
{
if ($_SESSION["auth_roles"] != 0) {
return $response->withHeader('Location', '/dashboard')->withStatus(302);
}
$db = $this->container->get('db');
// 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 token format');
return $response->withHeader('Location', '/registry/tokens')->withStatus(302);
}
$token = $db->selectRow('SELECT token, domain_name, crdate, lastupdate, tokenStatus FROM allocation_tokens WHERE token = ?', [ $args ]);
if ($token) {
$_SESSION['token_to_update'] = $token;
return view($response,'admin/system/updateToken.twig', [
'token' => $token,
'currentUri' => $uri
]);
} else {
// Token does not exist, redirect to the tokens view
return $response->withHeader('Location', '/registry/tokens')->withStatus(302);
}
} else {
// Redirect to the tokens view
return $response->withHeader('Location', '/registry/tokens')->withStatus(302);
}
}
public function updateTokenProcess(Request $request, Response $response)
{
if ($_SESSION["auth_roles"] != 0) {
return $response->withHeader('Location', '/dashboard')->withStatus(302);
}
if ($request->getMethod() === 'POST') {
// Retrieve POST data
$data = $request->getParsedBody();
$db = $this->container->get('db');
if (!empty($_SESSION['token_to_update'])) {
$token = $_SESSION['token_to_update']['token'];
} else {
$this->container->get('flash')->addMessage('error', 'No token specified for update');
return $response->withHeader('Location', '/registry/tokens')->withStatus(302);
}
$domain_name = $data['domain_name'] ?? null;
if (empty($domain_name)) {
$this->container->get('flash')->addMessage('error', 'Domain name must be provided');
return $response->withHeader('Location', '/registry/tokens/update/'.$token)->withStatus(302);
}
$invalid_domain = validate_label($domain_name, $this->container->get('db'));
if ($invalid_domain) {
$this->container->get('flash')->addMessage('error', 'Domain ' . $domainName . ' is invalid: ' . $invalid_domain);
return $response->withHeader('Location', '/registry/tokens/update/'.$token)->withStatus(302);
}
try {
$db->beginTransaction();
$currentDateTime = new \DateTime();
$update = $currentDateTime->format('Y-m-d H:i:s.v'); // Current timestamp
$db->update('allocation_tokens', [
'domain_name' => $domain_name,
'lastupdate' => $update
],
[
'token' => $token
]
);
$db->commit();
} catch (Exception $e) {
$db->rollBack();
$this->container->get('flash')->addMessage('error', 'Database failure during update: ' . $e->getMessage());
return $response->withHeader('Location', '/registry/tokens/update/'.$token)->withStatus(302);
}
unset($_SESSION['token_to_update']);
$this->container->get('flash')->addMessage('success', 'Token ' . $token . ' has been updated successfully on ' . $update);
return $response->withHeader('Location', '/registry/tokens/update/'.$token)->withStatus(302);
}
}
public function deleteToken(Request $request, Response $response, $args) public function deleteToken(Request $request, Response $response, $args)
{ {
if ($_SESSION["auth_roles"] != 0) { if ($_SESSION["auth_roles"] != 0) {

View file

@ -0,0 +1,81 @@
{% extends "layouts/app.twig" %}
{% block title %}{{ __('Update Token') }} {{ token.token }}{% 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 Token') }} {{ token.token }}
</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">
<div class="datagrid">
<div class="datagrid-item">
<div class="datagrid-title">{{ __('Token') }}</div>
<div class="datagrid-content">{{ token.token }}</div>
</div>
<div class="datagrid-item">
<div class="datagrid-title">{{ __('Creation Date') }}</div>
<div class="datagrid-content">{{ token.crdate }}</div>
</div>
<div class="datagrid-item">
<div class="datagrid-title">{{ __('Last Updated') }}</div>
<div class="datagrid-content">{{ token.lastupdate | default('N/A') }}</div>
</div>
<div class="datagrid-item">
<div class="datagrid-title">{{ __('Status') }}</div>
<div class="datagrid-content">{% set status = token.tokenStatus|lower %}
{% set color = 'gray' %}
{% if status == 'new' %}
{% set color = 'green' %}
{% elseif status == 'used' %}
{% set color = 'yellow' %}
{% elseif status == 'deprecated' %}
{% set color = 'red' %}
{% endif %}
<span class="status status-{{ color }}">{{ status|capitalize }}</span>
</div>
</div>
</div>
<form action="/registry/tokens/update" method="post">
{{ csrf.field | raw }}
<div class="form-group mt-3">
<label for="domain_name" class="form-label required">{{ __('Create Domain') }}:</label>
<input type="text" class="form-control" id="domain_name" name="domain_name" placeholder="example.com" value="{{ token.domain_name }}" required="required">
</div>
</div>
<div class="card-footer">
<div class="row align-items-center">
<div class="col-auto">
<button type="submit" class="btn btn-primary">{{ __('Update Token') }}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% include 'partials/footer.twig' %}
</div>
{% endblock %}

View file

@ -70,7 +70,8 @@
} }
function actionsFormatter(cell, formatterParams, onRendered) { function actionsFormatter(cell, formatterParams, onRendered) {
return `<a class="btn btn-outline-danger btn-icon delete-btn" id="delete-btn" href="javascript:void(0);" data-delete-url="/registry/tokens/delete/${cell.getRow().getData().token}" title="{{ __('Delete Token') }}"><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>`; return `<a class="btn btn-outline-primary btn-icon update-btn" href="/registry/tokens/update/${cell.getRow().getData().token}" title="{{ __('Update Token') }}"><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>
<a class="btn btn-outline-danger btn-icon delete-btn" id="delete-btn" href="javascript:void(0);" data-delete-url="/registry/tokens/delete/${cell.getRow().getData().token}" title="{{ __('Delete Token') }}"><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>`;
} }
table = new Tabulator("#tokenTable", { table = new Tabulator("#tokenTable", {
@ -93,10 +94,10 @@
placeholder: "{{ __('No Data') }}", placeholder: "{{ __('No Data') }}",
columns:[ columns:[
{formatter:"responsiveCollapse", width:30, minWidth:30, hozAlign:"center", resizable:false, headerSort:false, responsive:0}, {formatter:"responsiveCollapse", width:30, minWidth:30, hozAlign:"center", resizable:false, headerSort:false, responsive:0},
{title:"{{ __('Token') }}", field:"token", minWidth:300, minWidth:100, headerSort:true, resizable:false, formatter: copyableFormatter, responsive:0}, {title:"{{ __('Token') }}", field:"token", width:400, minWidth:200, headerSort:true, resizable:false, formatter: copyableFormatter, responsive:0},
{ title: "{{ __('Domain') }}", field: "domain_name", width:300, minWidth:80, headerSort:true, resizable:false, formatter: domainFormatter, responsive:2}, { title: "{{ __('Domain') }}", field: "domain_name", width:300, minWidth:80, headerSort:true, resizable:false, formatter: domainFormatter, responsive:2},
{title:"{{ __('Type') }}", field:"tokenType", width:120, minWidth:80, headerSort:true, resizable:false, formatter: typeStatusFormatter, responsive:2}, {title:"{{ __('Type') }}", field:"tokenType", width:160, minWidth:100, headerSort:true, resizable:false, formatter: typeStatusFormatter, responsive:2},
{title:"{{ __('Status') }}", field:"tokenStatus", width:120, minWidth:80, headerSort:true, resizable:false, formatter: lifecycleStatusFormatter, responsive:2}, {title:"{{ __('Status') }}", field:"tokenStatus", width:160, minWidth:100, headerSort:true, resizable:false, formatter: lifecycleStatusFormatter, responsive:2},
{title: "{{ __('Actions') }}", formatter: actionsFormatter, resizable:false, headerSort:false, download:false, hozAlign: "center", responsive:0, cellClick: function(e, cell){ {title: "{{ __('Actions') }}", formatter: actionsFormatter, resizable:false, headerSort:false, download:false, hozAlign: "center", responsive:0, cellClick: function(e, cell){
if (e.target.closest('.delete-btn')) { if (e.target.closest('.delete-btn')) {
e.preventDefault(); // Prevent the default link behavior e.preventDefault(); // Prevent the default link behavior

View file

@ -141,6 +141,8 @@ $app->group('', function ($route) {
$route->map(['GET', 'POST'], '/registry/reserved', SystemController::class .':manageReserved')->setName('manageReserved'); $route->map(['GET', 'POST'], '/registry/reserved', SystemController::class .':manageReserved')->setName('manageReserved');
$route->get('/registry/tokens', SystemController::class .':manageTokens')->setName('manageTokens'); $route->get('/registry/tokens', SystemController::class .':manageTokens')->setName('manageTokens');
$route->get('/registry/tokens/generate', SystemController::class .':generateTokens')->setName('generateTokens'); $route->get('/registry/tokens/generate', SystemController::class .':generateTokens')->setName('generateTokens');
$route->get('/registry/tokens/update/{token}', SystemController::class . ':updateToken')->setName('updateToken');
$route->post('/registry/tokens/update', SystemController::class . ':updateTokenProcess')->setName('updateTokenProcess');
$route->map(['GET', 'POST'], '/registry/tokens/delete/{token}', SystemController::class . ':deleteToken')->setName('deleteToken'); $route->map(['GET', 'POST'], '/registry/tokens/delete/{token}', SystemController::class . ':deleteToken')->setName('deleteToken');
$route->post('/registry/promotions', SystemController::class . ':managePromo')->setName('managePromo'); $route->post('/registry/promotions', SystemController::class . ':managePromo')->setName('managePromo');
$route->post('/registry/phases', SystemController::class . ':managePhases')->setName('managePhases'); $route->post('/registry/phases', SystemController::class . ':managePhases')->setName('managePhases');