mirror of
https://github.com/getnamingo/registry.git
synced 2025-07-21 18:16:03 +02:00
Added ability for registrars to edit their own accounts
Also small fixes to role based access
This commit is contained in:
parent
9af773eb37
commit
97343361cc
8 changed files with 946 additions and 14 deletions
|
@ -21,6 +21,10 @@ class LogsController extends Controller
|
|||
|
||||
public function log(Request $request, Response $response)
|
||||
{
|
||||
if ($_SESSION["auth_roles"] != 0) {
|
||||
return $response->withHeader('Location', '/dashboard')->withStatus(302);
|
||||
}
|
||||
|
||||
return view($response,'admin/logs/log.twig');
|
||||
}
|
||||
}
|
|
@ -12,6 +12,10 @@ class RegistrarsController extends Controller
|
|||
{
|
||||
public function view(Request $request, Response $response)
|
||||
{
|
||||
if ($_SESSION["auth_roles"] != 0) {
|
||||
return $response->withHeader('Location', '/dashboard')->withStatus(302);
|
||||
}
|
||||
|
||||
return view($response,'admin/registrars/index.twig');
|
||||
}
|
||||
|
||||
|
@ -303,7 +307,7 @@ class RegistrarsController extends Controller
|
|||
[ $args ]);
|
||||
|
||||
if ($registrar) {
|
||||
// Check if the user is not an admin (assuming role 0 is admin)
|
||||
// Check if the user is not an admin
|
||||
if ($_SESSION["auth_roles"] != 0) {
|
||||
$userRegistrars = $db->select('SELECT registrar_id FROM registrar_users WHERE user_id = ?', [$_SESSION['auth_user_id']]);
|
||||
|
||||
|
@ -311,7 +315,7 @@ class RegistrarsController extends Controller
|
|||
$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)) {
|
||||
if (!in_array($registrar['id'], $userRegistrarIds)) {
|
||||
// Redirect to the registrars view if the user is not authorized for this contact
|
||||
return $response->withHeader('Location', '/registrars')->withStatus(302);
|
||||
}
|
||||
|
@ -359,6 +363,58 @@ class RegistrarsController extends Controller
|
|||
|
||||
}
|
||||
|
||||
public function registrar(Request $request, Response $response)
|
||||
{
|
||||
$db = $this->container->get('db');
|
||||
// Get the current URI
|
||||
$uri = $request->getUri()->getPath();
|
||||
$registrarId = $_SESSION['auth_registrar_id'];
|
||||
|
||||
if (isset($registrarId) && $registrarId !== "") {
|
||||
$registrar = $db->selectRow('SELECT * FROM registrar WHERE id = ?',
|
||||
[ $registrarId ]);
|
||||
|
||||
if ($registrar) {
|
||||
$registrarContact = $db->selectRow('SELECT * FROM registrar_contact WHERE registrar_id = ?',
|
||||
[ $registrar['id'] ]);
|
||||
$registrarOte = $db->select('SELECT * FROM registrar_ote WHERE registrar_id = ? ORDER by command',
|
||||
[ $registrar['id'] ]);
|
||||
$registrarUsers = $db->selectRow('SELECT user_id FROM registrar_users WHERE registrar_id = ?',
|
||||
[ $registrar['id'] ]);
|
||||
$userEmail = $db->selectRow('SELECT email FROM users WHERE id = ?',
|
||||
[ $registrarUsers['user_id'] ]);
|
||||
$registrarWhitelist = $db->select('SELECT addr FROM registrar_whitelist WHERE registrar_id = ?',
|
||||
[ $registrar['id'] ]);
|
||||
// Check if RegistrarOTE is not empty
|
||||
if (is_array($registrarOte) && !empty($registrarOte)) {
|
||||
// Split the results into two groups
|
||||
$firstHalf = array_slice($registrarOte, 0, 5);
|
||||
$secondHalf = array_slice($registrarOte, 5);
|
||||
} else {
|
||||
// If RegistrarOTE is empty, set both halves to empty arrays
|
||||
$firstHalf = [];
|
||||
$secondHalf = [];
|
||||
}
|
||||
|
||||
return view($response,'admin/registrars/viewRegistrar.twig', [
|
||||
'registrar' => $registrar,
|
||||
'registrarContact' => $registrarContact,
|
||||
'firstHalf' => $firstHalf,
|
||||
'secondHalf' => $secondHalf,
|
||||
'userEmail' => $userEmail,
|
||||
'registrarWhitelist' => $registrarWhitelist,
|
||||
'currentUri' => $uri
|
||||
]);
|
||||
} else {
|
||||
// Contact does not exist, redirect to the dashboard view
|
||||
return $response->withHeader('Location', '/dashboard')->withStatus(302);
|
||||
}
|
||||
} else {
|
||||
// Redirect to the registrars view
|
||||
return $response->withHeader('Location', '/registrars')->withStatus(302);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateRegistrar(Request $request, Response $response, $args)
|
||||
{
|
||||
$db = $this->container->get('db');
|
||||
|
@ -518,11 +574,6 @@ class RegistrarsController extends Controller
|
|||
try {
|
||||
$currentDateTime = new \DateTime();
|
||||
$update = $currentDateTime->format('Y-m-d H:i:s.v');
|
||||
$characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$randomPrefix = '';
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$randomPrefix .= $characters[rand(0, strlen($characters) - 1)];
|
||||
}
|
||||
$currency = $_SESSION['_currency'] ?? 'USD';
|
||||
|
||||
if (empty($data['ianaId']) || !is_numeric($data['ianaId'])) {
|
||||
|
@ -668,4 +719,286 @@ class RegistrarsController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
public function editRegistrar(Request $request, Response $response)
|
||||
{
|
||||
if ($request->getMethod() === 'POST') {
|
||||
// Retrieve POST data
|
||||
$data = $request->getParsedBody();
|
||||
$db = $this->container->get('db');
|
||||
if (!empty($_SESSION['registrars_to_update'])) {
|
||||
$registrar = $_SESSION['registrars_to_update'][0];
|
||||
} else {
|
||||
$this->container->get('flash')->addMessage('error', 'No registrar specified for update');
|
||||
return $response->withHeader('Location', '/registrars')->withStatus(302);
|
||||
}
|
||||
|
||||
$data['ipAddress'] = array_filter($data['ipAddress']);
|
||||
$iso3166 = new ISO3166();
|
||||
$countries = $iso3166->all();
|
||||
|
||||
$ipAddressValidator = v::when(
|
||||
v::arrayType()->notEmpty(), // Condition: If it's a non-empty array
|
||||
v::arrayType()->each(v::ip()), // Then: Each element must be a valid IP address
|
||||
v::equals('') // Else: Allow it to be an empty string
|
||||
);
|
||||
|
||||
$data['owner']['cc'] = strtoupper($data['owner']['cc']);
|
||||
$data['billing']['cc'] = strtoupper($data['billing']['cc']);
|
||||
$data['abuse']['cc'] = strtoupper($data['abuse']['cc']);
|
||||
|
||||
$phoneValidator = v::regex('/^\+\d{1,3}\.\d{2,12}$/');
|
||||
|
||||
// Define validation for nested fields
|
||||
$contactValidator = [
|
||||
v::key('first_name', v::stringType()->notEmpty()->length(1, 255), true),
|
||||
v::key('last_name', v::stringType()->notEmpty()->length(1, 255), true),
|
||||
v::key('org', v::optional(v::stringType()->length(1, 255)), false),
|
||||
v::key('street1', v::optional(v::stringType()), false),
|
||||
v::key('city', v::stringType()->notEmpty(), true),
|
||||
v::key('sp', v::optional(v::stringType()), false),
|
||||
v::key('pc', v::optional(v::stringType()), false),
|
||||
v::key('cc', v::countryCode(), true),
|
||||
v::key('voice', v::optional($phoneValidator), false),
|
||||
v::key('fax', v::optional(v::phone()), false),
|
||||
v::key('email', v::email(), true)
|
||||
];
|
||||
|
||||
$validators = [
|
||||
'name' => v::stringType()->notEmpty()->length(1, 255),
|
||||
'ianaId' => v::optional(v::positive()->length(1, 5)),
|
||||
'email' => v::email(),
|
||||
'owner' => v::optional(v::keySet(...$contactValidator)),
|
||||
'billing' => v::optional(v::keySet(...$contactValidator)),
|
||||
'abuse' => v::optional(v::keySet(...$contactValidator)),
|
||||
'whoisServer' => v::domain(),
|
||||
'rdapServer' => v::domain(),
|
||||
'url' => v::url(),
|
||||
'abuseEmail' => v::email(),
|
||||
'abusePhone' => v::optional($phoneValidator),
|
||||
'ipAddress' => v::optional($ipAddressValidator)
|
||||
];
|
||||
|
||||
$errors = [];
|
||||
foreach ($validators as $field => $validator) {
|
||||
try {
|
||||
$validator->assert(isset($data[$field]) ? $data[$field] : []);
|
||||
} catch (\Respect\Validation\Exceptions\NestedValidationException $e) {
|
||||
$errors[$field] = $e->getMessages();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
// Handle errors
|
||||
$errorText = '';
|
||||
|
||||
foreach ($errors as $field => $messages) {
|
||||
$errorText .= ucfirst($field) . ' errors: ' . implode(', ', $messages) . '; ';
|
||||
}
|
||||
|
||||
// Trim the final semicolon and space
|
||||
$errorText = rtrim($errorText, '; ');
|
||||
|
||||
$this->container->get('flash')->addMessage('error', $errorText);
|
||||
return $response->withHeader('Location', '/registrar/edit')->withStatus(302);
|
||||
}
|
||||
|
||||
if (!empty($_SESSION['registrars_user_email'])) {
|
||||
$regEmail = $_SESSION['registrars_user_email'][0];
|
||||
} else {
|
||||
$this->container->get('flash')->addMessage('error', 'No email specified for update');
|
||||
return $response->withHeader('Location', '/registrar/edit')->withStatus(302);
|
||||
}
|
||||
|
||||
$db->beginTransaction();
|
||||
|
||||
try {
|
||||
$currentDateTime = new \DateTime();
|
||||
$update = $currentDateTime->format('Y-m-d H:i:s.v');
|
||||
$currency = $_SESSION['_currency'] ?? 'USD';
|
||||
|
||||
if (empty($data['ianaId']) || !is_numeric($data['ianaId'])) {
|
||||
$data['ianaId'] = null;
|
||||
}
|
||||
|
||||
$updateData = [
|
||||
'name' => $data['name'],
|
||||
'iana_id' => $data['ianaId'],
|
||||
'email' => $data['email'],
|
||||
'url' => $data['url'],
|
||||
'whois_server' => $data['whoisServer'],
|
||||
'rdap_server' => $data['rdapServer'],
|
||||
'abuse_email' => $data['abuseEmail'],
|
||||
'abuse_phone' => $data['abusePhone'],
|
||||
'currency' => $currency,
|
||||
'lastupdate' => $crdate
|
||||
];
|
||||
|
||||
if (!empty($data['eppPassword'])) {
|
||||
$eppPassword = password_hash($data['eppPassword'], PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]);
|
||||
$updateData['pw'] = $eppPassword;
|
||||
}
|
||||
|
||||
$db->update(
|
||||
'registrar',
|
||||
$updateData,
|
||||
[
|
||||
'clid' => $registrar
|
||||
]
|
||||
);
|
||||
$registrar_id = $db->selectValue(
|
||||
'SELECT id FROM registrar WHERE clid = ?',
|
||||
[$registrar]
|
||||
);
|
||||
|
||||
$db->update(
|
||||
'registrar_contact',
|
||||
[
|
||||
'first_name' => $data['owner']['first_name'],
|
||||
'last_name' => $data['owner']['last_name'],
|
||||
'org' => $data['owner']['org'],
|
||||
'street1' => $data['owner']['street1'],
|
||||
'city' => $data['owner']['city'],
|
||||
'sp' => $data['owner']['sp'],
|
||||
'pc' => $data['owner']['pc'],
|
||||
'cc' => strtolower($data['owner']['cc']),
|
||||
'voice' => $data['owner']['voice'],
|
||||
'email' => $data['owner']['email']
|
||||
],
|
||||
[
|
||||
'registrar_id' => $registrar_id,
|
||||
'type' => 'owner'
|
||||
]
|
||||
);
|
||||
|
||||
$db->update(
|
||||
'registrar_contact',
|
||||
[
|
||||
'first_name' => $data['billing']['first_name'],
|
||||
'last_name' => $data['billing']['last_name'],
|
||||
'org' => $data['billing']['org'],
|
||||
'street1' => $data['billing']['street1'],
|
||||
'city' => $data['billing']['city'],
|
||||
'sp' => $data['billing']['sp'],
|
||||
'pc' => $data['billing']['pc'],
|
||||
'cc' => strtolower($data['billing']['cc']),
|
||||
'voice' => $data['billing']['voice'],
|
||||
'email' => $data['billing']['email']
|
||||
],
|
||||
[
|
||||
'registrar_id' => $registrar_id,
|
||||
'type' => 'billing'
|
||||
]
|
||||
);
|
||||
|
||||
$db->update(
|
||||
'registrar_contact',
|
||||
[
|
||||
'first_name' => $data['abuse']['first_name'],
|
||||
'last_name' => $data['abuse']['last_name'],
|
||||
'org' => $data['abuse']['org'],
|
||||
'street1' => $data['abuse']['street1'],
|
||||
'city' => $data['abuse']['city'],
|
||||
'sp' => $data['abuse']['sp'],
|
||||
'pc' => $data['abuse']['pc'],
|
||||
'cc' => strtolower($data['abuse']['cc']),
|
||||
'voice' => $data['abuse']['voice'],
|
||||
'email' => $data['abuse']['email']
|
||||
],
|
||||
[
|
||||
'registrar_id' => $registrar_id,
|
||||
'type' => 'abuse'
|
||||
]
|
||||
);
|
||||
|
||||
if (!empty($data['ipAddress'])) {
|
||||
$db->delete(
|
||||
'registrar_whitelist',
|
||||
[
|
||||
'registrar_id' => $registrar_id
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($data['ipAddress'] as $ip) {
|
||||
$db->insert(
|
||||
'registrar_whitelist',
|
||||
[
|
||||
'registrar_id' => $registrar_id,
|
||||
'addr' => $ip
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['panelPassword']) {
|
||||
$panelPassword = password_hash($data['panelPassword'], PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]);
|
||||
|
||||
$db->update(
|
||||
'users',
|
||||
[
|
||||
'password' => $panelPassword,
|
||||
],
|
||||
[
|
||||
'email' => $regEmail
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$db->commit();
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
$this->container->get('flash')->addMessage('error', 'Database failure during update: ' . $e->getMessage());
|
||||
return $response->withHeader('Location', '/registrar/edit')->withStatus(302);
|
||||
}
|
||||
|
||||
unset($_SESSION['registrars_to_update']);
|
||||
unset($_SESSION['registrars_user_email']);
|
||||
$this->container->get('flash')->addMessage('success', 'Registrar ' . $data['name'] . ' has been updated successfully on ' . $update);
|
||||
return $response->withHeader('Location', '/registrar/edit')->withStatus(302);
|
||||
}
|
||||
|
||||
$db = $this->container->get('db');
|
||||
$iso3166 = new ISO3166();
|
||||
$countries = $iso3166->all();
|
||||
// Get the current URI
|
||||
$uri = $request->getUri()->getPath();
|
||||
$registrarId = $_SESSION['auth_registrar_id'];
|
||||
|
||||
if (isset($registrarId) && $registrarId !== "") {
|
||||
$registrar = $db->selectRow('SELECT * FROM registrar WHERE id = ?',
|
||||
[ $registrarId ]);
|
||||
|
||||
if ($registrar) {
|
||||
$contacts = $db->select("SELECT * FROM registrar_contact WHERE registrar_id = ?",
|
||||
[ $registrar['id'] ]);
|
||||
$ote = $db->select("SELECT * FROM registrar_ote WHERE registrar_id = ?",
|
||||
[ $registrar['id'] ]);
|
||||
$user_id = $db->selectValue("SELECT user_id FROM registrar_users WHERE registrar_id = ?",
|
||||
[ $registrar['id'] ]);
|
||||
$user = $db->selectRow("SELECT email FROM users WHERE id = ?",
|
||||
[ $user_id ]);
|
||||
$whitelist = $db->select("SELECT * FROM registrar_whitelist WHERE registrar_id = ?",
|
||||
[ $registrar['id'] ]);
|
||||
|
||||
$_SESSION['registrars_to_update'] = [$registrar['clid']];
|
||||
$_SESSION['registrars_user_email'] = [$user['email']];
|
||||
|
||||
return view($response,'admin/registrars/updateRegistrarUser.twig', [
|
||||
'registrar' => $registrar,
|
||||
'contacts' => $contacts,
|
||||
'ote' => $ote,
|
||||
'user' => $user,
|
||||
'whitelist' => $whitelist,
|
||||
'currentUri' => $uri,
|
||||
'countries' => $countries
|
||||
]);
|
||||
} else {
|
||||
// Registrar does not exist, redirect to the dashboard view
|
||||
return $response->withHeader('Location', '/dashboard')->withStatus(302);
|
||||
}
|
||||
} else {
|
||||
// Redirect to the registrars view
|
||||
return $response->withHeader('Location', '/registrars')->withStatus(302);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,10 @@ class ReportsController extends Controller
|
|||
{
|
||||
public function view(Request $request, Response $response)
|
||||
{
|
||||
if ($_SESSION["auth_roles"] != 0) {
|
||||
return $response->withHeader('Location', '/dashboard')->withStatus(302);
|
||||
}
|
||||
|
||||
return view($response,'admin/reports/index.twig');
|
||||
}
|
||||
}
|
|
@ -11,6 +11,10 @@ class UsersController extends Controller
|
|||
{
|
||||
public function listUsers(Request $request, Response $response)
|
||||
{
|
||||
if ($_SESSION["auth_roles"] != 0) {
|
||||
return $response->withHeader('Location', '/dashboard')->withStatus(302);
|
||||
}
|
||||
|
||||
$userModel = new User($this->container->get('db'));
|
||||
$users = $userModel->getAllUsers();
|
||||
return view($response,'admin/users/listUsers.twig', compact('users'));
|
||||
|
|
574
cp/resources/views/admin/registrars/updateRegistrarUser.twig
Normal file
574
cp/resources/views/admin/registrars/updateRegistrarUser.twig
Normal file
|
@ -0,0 +1,574 @@
|
|||
{% extends "layouts/app.twig" %}
|
||||
|
||||
{% block title %}{{ __('Update Registrar') }} {{ registrar.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 Registrar') }} {{ registrar.name }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="col-12">
|
||||
{% include 'partials/flash.twig' %}
|
||||
<form action="/registrar/edit" method="post" autocomplete="off">
|
||||
{{ csrf.field | raw }}
|
||||
<!-- Registrar Details Card -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ __('Registrar Details') }}</h5>
|
||||
<div class="row">
|
||||
<!-- First Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label required">{{ __('Name') }}</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required value="{{ registrar.name }}">
|
||||
<small class="text-muted">{{ __('The official name of the registrar.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ianaId" class="form-label">IANA ID</label>
|
||||
<input type="number" class="form-control" id="ianaId" name="ianaId" value="{{ registrar.iana_id }}">
|
||||
<small class="text-muted">{{ __('Unique identifier assigned by IANA.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label required">{{ __('Email') }}</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required autocapitalize="none" value="{{ registrar.email }}">
|
||||
<small class="text-muted">{{ __('Primary contact email of the registrar.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="url" class="form-label required">{{ __('URL') }}</label>
|
||||
<input type="url" class="form-control" id="url" name="url" required autocapitalize="none" value="{{ registrar.url }}">
|
||||
<small class="text-muted">{{ __('Registrar\'s official website URL.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Second Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="whoisServer" class="form-label required">{{ __('WHOIS Server') }}</label>
|
||||
<input type="text" class="form-control" id="whoisServer" name="whoisServer" required autocapitalize="none" value="{{ registrar.whois_server }}">
|
||||
<small class="text-muted">{{ __('Address of the registrar\'s WHOIS server.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="rdapServer" class="form-label required">{{ __('RDAP Server') }}</label>
|
||||
<input type="text" class="form-control" id="rdapServer" name="rdapServer" required autocapitalize="none" value="{{ registrar.rdap_server }}">
|
||||
<small class="text-muted">{{ __('Address of the registrar\'s RDAP server.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseEmail" class="form-label required">{{ __('Abuse Email') }}</label>
|
||||
<input type="email" class="form-control" id="abuseEmail" name="abuseEmail" required autocapitalize="none" value="{{ registrar.abuse_email }}">
|
||||
<small class="text-muted">{{ __('Email address for reporting abuse.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abusePhone" class="form-label required">{{ __('Abuse Phone') }}</label>
|
||||
<input type="tel" class="form-control" id="abusePhone" name="abusePhone" required value="{{ registrar.abuse_phone }}">
|
||||
<small class="text-muted">{{ __('Phone number for reporting abuse.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Financial Information Card -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ __('Financial Information') }}</h5>
|
||||
<div class="row">
|
||||
<!-- First Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="accountBalance" class="form-label">{{ __('Account Balance') }}</label>
|
||||
<div class="form-control-plaintext">{{ currency }} {{ registrar.accountBalance }}</div>
|
||||
<small class="text-muted">{{ __('Current balance in the registrar\'s account.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="creditLimit" class="form-label">{{ __('Credit Limit') }}</label>
|
||||
<div class="form-control-plaintext">{{ currency }} {{ registrar.creditLimit }}</div>
|
||||
<small class="text-muted">{{ __('Maximum credit limit for the registrar.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Second Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="creditThreshold" class="form-label">{{ __('Credit Threshold') }}</label>
|
||||
<div class="form-control-plaintext">{{ currency }} {{ registrar.creditThreshold }}</div>
|
||||
<small class="text-muted">{{ __('Credit threshold triggering alerts or actions.') }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="thresholdType" class="form-label">{{ __('Threshold Type') }}</label>
|
||||
<div class="form-control-plaintext">{{ registrar.thresholdType|slice(0, 1)|upper ~ registrar.thresholdType|slice(1) }}</div>
|
||||
<small class="text-muted">{{ __('Type of threshold: fixed value or percentage.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Registrar Contacts Section with Tabs -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ __('Registrar Contacts') }}</h5>
|
||||
<ul class="nav nav-tabs nav-fill" id="contactTabs" role="tablist">
|
||||
<!-- Tab Headers -->
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="owner-tab" data-bs-toggle="tab" data-bs-target="#owner" type="button" role="tab" aria-controls="owner" aria-selected="true">{{ __('Owner') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="billing-tab" data-bs-toggle="tab" data-bs-target="#billing" type="button" role="tab" aria-controls="billing" aria-selected="false">{{ __('Billing') }}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="abuse-tab" data-bs-toggle="tab" data-bs-target="#abuse" type="button" role="tab" aria-controls="abuse" aria-selected="false">{{ __('Abuse') }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="contactTabsContent">
|
||||
<!-- Owner Tab -->
|
||||
<div class="tab-pane fade show active" id="owner" role="tabpanel" aria-labelledby="owner-tab">
|
||||
<div class="mt-3">
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" value="" id="copyOwnerData">
|
||||
<label class="form-check-label" for="copyOwnerData">
|
||||
<strong>{{ __('Copy data to other contacts') }}</strong>
|
||||
</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
{% for contact in contacts %}
|
||||
{% if contact.type == 'owner' %}
|
||||
<!-- First Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="ownerFirstName" class="form-label required">{{ __('First Name') }}</label>
|
||||
<input type="text" class="form-control" id="ownerFirstName" name="owner[first_name]" value="{{ contact.first_name }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerLastName" class="form-label required">{{ __('Last Name') }}</label>
|
||||
<input type="text" class="form-control" id="ownerLastName" name="owner[last_name]" value="{{ contact.last_name }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerOrg" class="form-label">{{ __('Organization') }}</label>
|
||||
<input type="text" class="form-control" id="ownerOrg" name="owner[org]" value="{{ contact.org }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerStreet1" class="form-label">{{ __('Street Address') }}</label>
|
||||
<input type="text" class="form-control" id="ownerStreet1" name="owner[street1]" value="{{ contact.street1 }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerCity" class="form-label required">{{ __('City') }}</label>
|
||||
<input type="text" class="form-control" id="ownerCity" name="owner[city]" value="{{ contact.city }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Second Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="ownerSp" class="form-label">{{ __('State/Province') }}</label>
|
||||
<input type="text" class="form-control" id="ownerSp" name="owner[sp]" value="{{ contact.sp }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerPc" class="form-label">{{ __('Postal Code') }}</label>
|
||||
<input type="text" class="form-control" id="ownerPc" name="owner[pc]" value="{{ contact.pc }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerCc" class="form-label required">{{ __('Country') }}</label>
|
||||
<select class="form-select" id="ownerCc" name="owner[cc]" required="required">
|
||||
{% for country in countries %}
|
||||
<option value="{{ country.alpha2 }}" {% if country.alpha2|lower == contact.cc %}selected{% endif %}>{{ country.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerVoice" class="form-label">{{ __('Phone') }}</label>
|
||||
<input type="tel" class="form-control" id="ownerVoice" name="owner[voice]" value="{{ contact.voice }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ownerEmail" class="form-label required">{{ __('Email') }}</label>
|
||||
<input type="email" class="form-control" id="ownerEmail" name="owner[email]" required autocapitalize="none" value="{{ contact.email }}">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Billing Tab -->
|
||||
<div class="tab-pane fade" id="billing" role="tabpanel" aria-labelledby="billing-tab">
|
||||
<div class="mt-3">
|
||||
<div class="row">
|
||||
{% for contact in contacts %}
|
||||
{% if contact.type == 'billing' %}
|
||||
<!-- First Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="billingFirstName" class="form-label required">{{ __('First Name') }}</label>
|
||||
<input type="text" class="form-control" id="billingFirstName" name="billing[first_name]" value="{{ contact.first_name }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingLastName" class="form-label required">{{ __('Last Name') }}</label>
|
||||
<input type="text" class="form-control" id="billingLastName" name="billing[last_name]" value="{{ contact.last_name }}"required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingOrg" class="form-label">{{ __('Organization') }}</label>
|
||||
<input type="text" class="form-control" id="billingOrg" name="billing[org]" value="{{ contact.org }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingStreet1" class="form-label">{{ __('Street Address') }}</label>
|
||||
<input type="text" class="form-control" id="billingStreet1" name="billing[street1]" value="{{ contact.street1 }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingCity" class="form-label required">{{ __('City') }}</label>
|
||||
<input type="text" class="form-control" id="billingCity" name="billing[city]" value="{{ contact.city }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Second Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="billingSp" class="form-label">{{ __('State/Province') }}</label>
|
||||
<input type="text" class="form-control" id="billingSp" name="billing[sp]" value="{{ contact.sp }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingPc" class="form-label">{{ __('Postal Code') }}</label>
|
||||
<input type="text" class="form-control" id="billingPc" name="billing[pc]" value="{{ contact.pc }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingCc" class="form-label required">{{ __('Country') }}</label>
|
||||
<select class="form-select" id="billingCc" name="billing[cc]" required="required">
|
||||
{% for country in countries %}
|
||||
<option value="{{ country.alpha2 }}" {% if country.alpha2|lower == contact.cc %}selected{% endif %}>{{ country.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingVoice" class="form-label">{{ __('Phone') }}</label>
|
||||
<input type="tel" class="form-control" id="billingVoice" name="billing[voice]" value="{{ contact.voice }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="billingEmail" class="form-label required">{{ __('Email') }}</label>
|
||||
<input type="email" class="form-control" id="billingEmail" name="billing[email]" required autocapitalize="none" value="{{ contact.email }}">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Abuse Tab -->
|
||||
<div class="tab-pane fade" id="abuse" role="tabpanel" aria-labelledby="abuse-tab">
|
||||
<div class="mt-3">
|
||||
<div class="row">
|
||||
{% for contact in contacts %}
|
||||
{% if contact.type == 'abuse' %}
|
||||
<!-- First Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="abuseFirstName" class="form-label required">{{ __('First Name') }}</label>
|
||||
<input type="text" class="form-control" id="abuseFirstName" name="abuse[first_name]" value="{{ contact.first_name }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseLastName" class="form-label required">{{ __('Last Name') }}</label>
|
||||
<input type="text" class="form-control" id="abuseLastName" name="abuse[last_name]" value="{{ contact.last_name }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseOrg" class="form-label">{{ __('Organization') }}</label>
|
||||
<input type="text" class="form-control" id="abuseOrg" name="abuse[org]" value="{{ contact.org }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseStreet1" class="form-label">{{ __('Street Address') }}</label>
|
||||
<input type="text" class="form-control" id="abuseStreet1" name="abuse[street1]" value="{{ contact.street1 }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseCity" class="form-label required">{{ __('City') }}</label>
|
||||
<input type="text" class="form-control" id="abuseCity" name="abuse[city]" required value="{{ contact.city }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Second Column -->
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="abuseSp" class="form-label">{{ __('State/Province') }}</label>
|
||||
<input type="text" class="form-control" id="abuseSp" name="abuse[sp]" value="{{ contact.sp }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abusePc" class="form-label">{{ __('Postal Code') }}</label>
|
||||
<input type="text" class="form-control" id="abusePc" name="abuse[pc]" value="{{ contact.pc }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseCc" class="form-label required">{{ __('Country') }}</label>
|
||||
<select class="form-select" id="abuseCc" name="abuse[cc]" required="required">
|
||||
{% for country in countries %}
|
||||
<option value="{{ country.alpha2 }}" {% if country.alpha2|lower == contact.cc %}selected{% endif %}>{{ country.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseVoice" class="form-label">{{ __('Phone') }}</label>
|
||||
<input type="tel" class="form-control" id="abuseVoice" name="abuse[voice]" value="{{ contact.voice }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="abuseEmail" class="form-label required">{{ __('Email') }}</label>
|
||||
<input type="email" class="form-control" id="abuseEmail" name="abuse[email]" required autocapitalize="none" value="{{ contact.email }}">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- IP Whitelisting Column -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ __('IP Whitelisting') }} <span class="text-red">*</span></h5>
|
||||
<p class="card-text">
|
||||
{{ __('Whitelist IP addresses for secure access. Up to 5 IP addresses (IPv4 or IPv6) can be added.') }}
|
||||
</p>
|
||||
<div id="ipWhitelistForm">
|
||||
<div id="ipAddressFields">
|
||||
{% for ip in whitelist %}
|
||||
<div class="mb-3 d-flex align-items-center">
|
||||
<input type="text" class="form-control" name="ipAddress[]" value="{{ ip.addr }}" autocapitalize="none" required>
|
||||
<button type="button" class="btn btn-danger ms-2 remove-ip">-</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if whitelist|length < 5 %}
|
||||
<div class="mb-3 d-flex align-items-center">
|
||||
<input type="text" class="form-control" name="ipAddress[]" autocapitalize="none">
|
||||
<button type="button" class="btn btn-primary ms-2 add-ip">+</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Registrar User Column -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ __('Registrar User') }}</h5>
|
||||
<p class="card-text">
|
||||
{{ __('For an existing registrar user, you can view the current EPP username (also known as CLID) and panel access email. Additionally, you have the option to reset the passwords for EPP and panel access as needed.') }}
|
||||
</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col required">{{ __('Username/CLID') }}</th>
|
||||
<th scope="col">{{ __('Login Email') }}</th>
|
||||
<th scope="col">{{ __('Panel Password') }} <span class="text-red">*</span></th>
|
||||
<th scope="col">{{ __('EPP Password') }} <span class="text-red">*</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
{{ registrar.clid }}
|
||||
</td>
|
||||
<td>
|
||||
{{ user.email ? user.email : 'N/A' }}
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<input type="password" class="form-control form-control-sm me-2" name="panelPassword" id="panelPassword" autocomplete="off" disabled>
|
||||
<div class="form-check mb-0">
|
||||
<input class="form-check-input" type="checkbox" id="updatePanelPassword" title="{{ __('Update Panel Password') }}">
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<input type="password" class="form-control form-control-sm me-2" name="eppPassword" id="eppPassword" autocomplete="off" disabled>
|
||||
<div class="form-check mb-0">
|
||||
<input class="form-check-input" type="checkbox" id="updateEppPassword" title="{{ __('Update EPP Password') }}">
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- OTE Section -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ __('Operational Test and Evaluation (OTE)') }}</h5>
|
||||
<p class="card-text">
|
||||
{{ __('Operational Test and Evaluation (OTE) assesses the functionality of EPP commands in a simulated environment, ensuring effective communication between the registrar\'s system and the registry. Below are key EPP commands and their test statuses:') }}
|
||||
</p>
|
||||
<div class="row">
|
||||
<!-- First Column -->
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
contact:create
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
domain:check
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
domain:info
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
domain:renew
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
domain:transfer
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Second Column -->
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
host:create
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
host:info
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
contact:update
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
domain:delete
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
poll:request
|
||||
<span class="badge bg-orange text-orange-fg">{{ __('Pending') }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-primary">{{ __('Update Registrar') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'partials/footer.twig' %}
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const updatePanelPasswordCheckbox = document.getElementById('updatePanelPassword');
|
||||
const panelPasswordField = document.getElementById('panelPassword');
|
||||
|
||||
updatePanelPasswordCheckbox.addEventListener('change', function() {
|
||||
panelPasswordField.disabled = !this.checked;
|
||||
});
|
||||
|
||||
const updateEppPasswordCheckbox = document.getElementById('updateEppPassword');
|
||||
const eppPasswordField = document.getElementById('eppPassword');
|
||||
|
||||
updateEppPasswordCheckbox.addEventListener('change', function() {
|
||||
eppPasswordField.disabled = !this.checked;
|
||||
});
|
||||
|
||||
const ipForm = document.getElementById('ipWhitelistForm');
|
||||
const maxFields = 5;
|
||||
|
||||
ipForm.addEventListener('click', function(e) {
|
||||
const target = e.target;
|
||||
|
||||
// Handle Add IP Button Click
|
||||
if (target.classList.contains('add-ip')) {
|
||||
const totalFields = ipForm.querySelectorAll('input[name="ipAddress[]"]').length;
|
||||
if (totalFields < maxFields) {
|
||||
const newField = document.createElement('div');
|
||||
newField.className = 'mb-3 d-flex align-items-center';
|
||||
newField.innerHTML = `
|
||||
<input type="text" class="form-control" name="ipAddress[]" autocapitalize="none">
|
||||
<button type="button" class="btn btn-danger ms-2 remove-ip">-</button>
|
||||
`;
|
||||
ipForm.querySelector('#ipAddressFields').appendChild(newField);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Remove IP Button Click
|
||||
if (target.classList.contains('remove-ip')) {
|
||||
target.parentElement.remove();
|
||||
}
|
||||
|
||||
// Disable the add button if maxFields is reached
|
||||
const totalFields = ipForm.querySelectorAll('input[name="ipAddress[]"]').length;
|
||||
const addButton = ipForm.querySelector('.add-ip');
|
||||
if (addButton) {
|
||||
addButton.disabled = totalFields >= maxFields;
|
||||
}
|
||||
});
|
||||
|
||||
const copyCheckbox = document.getElementById('copyOwnerData');
|
||||
|
||||
// Function to copy data to another tab
|
||||
function copyDataToTab(tabId) {
|
||||
const ownerInputs = document.querySelectorAll('#owner input:not([type="checkbox"]), #owner select');
|
||||
const targetFields = document.querySelectorAll(`${tabId} input:not([type='checkbox']), ${tabId} select`);
|
||||
|
||||
ownerInputs.forEach((input, index) => {
|
||||
if (targetFields[index] && input.tagName === targetFields[index].tagName) {
|
||||
targetFields[index].value = input.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
copyCheckbox.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
copyDataToTab('#billing');
|
||||
copyDataToTab('#abuse');
|
||||
} else {
|
||||
// Clear fields when unchecked, if desired
|
||||
['#billing', '#abuse'].forEach(tabId => {
|
||||
const fields = document.querySelectorAll(`${tabId} input:not([type='checkbox']), ${tabId} select`);
|
||||
fields.forEach(field => {
|
||||
field.value = '';
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -27,6 +27,14 @@
|
|||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">{{ __('Registrar') }} {{ registrar.name }} <span class="status status-green" title="Prefix">{{ registrar.prefix }}</span> <span class="status status-info" title="IANA ID">{{ registrar.iana_id|default('N/A') }}</span></h3>
|
||||
{% if roles != 0 %}
|
||||
<div class="card-actions">
|
||||
<a href="{{route('editRegistrar')}}" type="button" class="btn btn-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><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 d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z" /><path d="M16 5l3 3" /></svg>
|
||||
{{ __('Update Registrar') }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="datagrid">
|
||||
|
|
|
@ -194,15 +194,18 @@
|
|||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<li {{ is_current_url('epphistory') or is_current_url('poll') or is_current_url('log') or is_current_url('registry') or is_current_url('reports') or is_current_url('listTlds') or is_current_url('createTld') or 'tld' in currentUri or 'reserved' in currentUri ? 'class="nav-item dropdown active"' : 'class="nav-item dropdown"' }}>
|
||||
<li {{ is_current_url('epphistory') or is_current_url('poll') or is_current_url('log') or is_current_url('registry') or is_current_url('reports') or is_current_url('listTlds') or is_current_url('createTld') or 'tld' in currentUri or 'reserved' in currentUri or (roles != 0 and 'registrar' in currentUri) ? 'class="nav-item dropdown active"' : 'class="nav-item dropdown"' }}>
|
||||
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false">
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><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="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z"></path> <path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"></path></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
{{ __('Registry') }}
|
||||
{% if roles == 0 %}{{ __('Registry') }}{% else %}{{ __('Registrar') }}{% endif %}
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
{% if roles != 0 %}<a class="dropdown-item" href="{{route('registrar')}}">
|
||||
{{ __('Details') }}
|
||||
</a>{% endif %}
|
||||
{% if roles == 0 %}<a class="dropdown-item" href="{{route('registry')}}">
|
||||
{{ __('Configuration') }}
|
||||
</a>
|
||||
|
@ -216,10 +219,10 @@
|
|||
<a class="dropdown-item" href="{{route('poll')}}">
|
||||
{{ __('Message Queue') }}
|
||||
</a>
|
||||
{% if roles == 0 %}<a class="dropdown-item" href="{{route('epphistory')}}">
|
||||
<a class="dropdown-item" href="{{route('epphistory')}}">
|
||||
{{ __('EPP History') }}
|
||||
</a>
|
||||
<a class="dropdown-item" href="{{route('log')}}">
|
||||
{% if roles == 0 %}<a class="dropdown-item" href="{{route('log')}}">
|
||||
{{ __('System Log') }}
|
||||
</a>{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -90,6 +90,8 @@ $app->group('', function ($route) {
|
|||
$route->get('/registrar/view/{registrar}', RegistrarsController::class . ':viewRegistrar')->setName('viewRegistrar');
|
||||
$route->get('/registrar/update/{registrar}', RegistrarsController::class . ':updateRegistrar')->setName('updateRegistrar');
|
||||
$route->post('/registrar/update', RegistrarsController::class . ':updateRegistrarProcess')->setName('updateRegistrarProcess');
|
||||
$route->get('/registrar', RegistrarsController::class .':registrar')->setName('registrar');
|
||||
$route->map(['GET', 'POST'], '/registrar/edit', RegistrarsController::class .':editRegistrar')->setName('editRegistrar');
|
||||
|
||||
$route->get('/users', UsersController::class .':listUsers')->setName('listUsers');
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue