From 63b544c9153a44e46b140c04ab36f04a69c6cf26 Mon Sep 17 00:00:00 2001 From: Pinga <121483313+getpinga@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:07:14 +0200 Subject: [PATCH] Added ability to create more users from CP --- cp/app/Controllers/ProfileController.php | 7 +- cp/app/Controllers/UsersController.php | 153 +++++++++++++++++ cp/resources/views/admin/profile/profile.twig | 4 +- .../views/admin/users/createUser.twig | 162 ++++++++++++++++++ cp/resources/views/admin/users/listUsers.twig | 13 ++ cp/resources/views/layouts/app.twig | 5 +- cp/resources/views/partials/js-users.twig | 4 +- cp/routes/web.php | 3 +- 8 files changed, 345 insertions(+), 6 deletions(-) create mode 100644 cp/resources/views/admin/users/createUser.twig diff --git a/cp/app/Controllers/ProfileController.php b/cp/app/Controllers/ProfileController.php index 0e1fbc1..c526178 100644 --- a/cp/app/Controllers/ProfileController.php +++ b/cp/app/Controllers/ProfileController.php @@ -43,9 +43,14 @@ class ProfileController extends Controller } else { $status = "Unknown"; } + $roles = $_SESSION['auth_roles']; if ($roles == 0) { - $role = "Admin"; + $role = "Administrator"; + } else if ($roles == 4) { + $role = "Registrar"; + } else if ($roles == 6) { + $role = "Registrar Assistant"; } else { $role = "Unknown"; } diff --git a/cp/app/Controllers/UsersController.php b/cp/app/Controllers/UsersController.php index 999ea70..ecfd725 100644 --- a/cp/app/Controllers/UsersController.php +++ b/cp/app/Controllers/UsersController.php @@ -6,6 +6,7 @@ use App\Models\User; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Container\ContainerInterface; +use Respect\Validation\Validator as v; class UsersController extends Controller { @@ -19,4 +20,156 @@ class UsersController extends Controller $users = $userModel->getAllUsers(); return view($response,'admin/users/listUsers.twig', compact('users')); } + + public function createUser(Request $request, Response $response) + { + // Registrars can not create new users, then need to ask the registry + 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'); + $email = $data['email'] ?? null; + $username = $data['username'] ?? null; + $password = $data['password'] ?? null; + $password_confirmation = $data['password_confirmation'] ?? null; + $status = $data['status'] ?? null; + $verified = $data['verified'] ?? null; + $role = $data['role'] ?? null; + $registrar_id = $data['registrar_id'] ?? null; + + // Define validation rules + $validators = [ + 'email' => v::email()->notEmpty()->setName('Email'), + 'username' => v::regex('/^[a-zA-Z0-9_-]+$/')->length(3, 20)->setName('Username'), + 'password' => v::stringType()->notEmpty()->length(6, 255)->setName('Password'), + 'password_confirmation' => v::equals($data['password'] ?? '')->setName('Password Confirmation'), + 'status' => v::in(['active', 'inactive'])->setName('Status'), + 'role' => v::in(['admin', 'registrar'])->setName('Role'), + ]; + + // Add registrar_id validation if role is registrar + if (($data['role'] ?? '') === 'registrar') { + $validators['registrar_id'] = v::numericVal()->notEmpty()->setName('Registrar ID'); + } + + // Validate data + $errors = []; + foreach ($validators as $field => $validator) { + try { + $validator->assert($data[$field] ?? null); + } catch (\Respect\Validation\Exceptions\ValidationException $exception) { + $errors[$field] = $exception->getMessages(); // Collect all error messages + } + } + + // If errors exist, return with errors + if (!empty($errors)) { + // Flatten the errors array into a string + $errorMessages = []; + foreach ($errors as $field => $fieldErrors) { + $fieldMessages = implode(', ', $fieldErrors); // Concatenate messages for the field + $errorMessages[] = ucfirst($field) . ': ' . $fieldMessages; // Prefix with field name + } + $errorString = implode('; ', $errorMessages); // Join all fields' errors + + // Add the flattened error string as a flash message + $this->container->get('flash')->addMessage('error', 'Error: ' . $errorString); + + // Redirect back to the form + return $response->withHeader('Location', '/user/create')->withStatus(302); + } + + $registrars = $db->select("SELECT id, clid, name FROM registrar"); + if ($_SESSION["auth_roles"] != 0) { + $registrar = true; + } else { + $registrar = null; + } + + if ($email) { + if ($registrar_id) { + $db->beginTransaction(); + + $password_hashed = password_hash($password, PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]); + + try { + $db->insert( + 'users', + [ + 'email' => $email, + 'password' => $password_hashed, + 'username' => $username, + 'verified' => $verified, + 'roles_mask' => 6, + 'registered' => \time() + ] + ); + $user_id = $db->getLastInsertId(); + + $db->insert( + 'registrar_users', + [ + 'registrar_id' => $registrar_id, + 'user_id' => $user_id + ] + ); + + $db->commit(); + } catch (Exception $e) { + $db->rollBack(); + $this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage()); + return $response->withHeader('Location', '/user/create')->withStatus(302); + } + + $this->container->get('flash')->addMessage('success', 'User ' . $email . ' has been created successfully'); + return $response->withHeader('Location', '/users')->withStatus(302); + } else { + $db->beginTransaction(); + + $password_hashed = password_hash($password, PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]); + + try { + $db->insert( + 'users', + [ + 'email' => $email, + 'password' => $password_hashed, + 'username' => $username, + 'verified' => $verified, + 'roles_mask' => 0, + 'registered' => \time() + ] + ); + + $db->commit(); + } catch (Exception $e) { + $db->rollBack(); + $this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage()); + return $response->withHeader('Location', '/user/create')->withStatus(302); + } + + $this->container->get('flash')->addMessage('success', 'User ' . $email . ' has been created successfully'); + return $response->withHeader('Location', '/users')->withStatus(302); + } + } + } + + $db = $this->container->get('db'); + $registrars = $db->select("SELECT id, clid, name FROM registrar"); + if ($_SESSION["auth_roles"] != 0) { + $registrar = true; + } else { + $registrar = null; + } + + // Default view for GET requests or if POST data is not set + return view($response,'admin/users/createUser.twig', [ + 'registrars' => $registrars, + 'registrar' => $registrar, + ]); + } } \ No newline at end of file diff --git a/cp/resources/views/admin/profile/profile.twig b/cp/resources/views/admin/profile/profile.twig index 70e375f..813d1f5 100644 --- a/cp/resources/views/admin/profile/profile.twig +++ b/cp/resources/views/admin/profile/profile.twig @@ -61,11 +61,11 @@ {{ status }} - +
{{ __('Role') }}
- + {{ role }}
diff --git a/cp/resources/views/admin/users/createUser.twig b/cp/resources/views/admin/users/createUser.twig new file mode 100644 index 0000000..b06f5e6 --- /dev/null +++ b/cp/resources/views/admin/users/createUser.twig @@ -0,0 +1,162 @@ +{% extends "layouts/app.twig" %} + +{% block title %}{{ __('Create New User') }}{% endblock %} + +{% block content %} +
+ + + +
+
+
+ {% include 'partials/flash.twig' %} +
+ {{ csrf.field | raw }} +
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ +
+ + +
+ + +
+
+
+ + + +
+ + +
+
+
+
+
+ {% include 'partials/footer.twig' %} +
+ +{% endblock %} \ No newline at end of file diff --git a/cp/resources/views/admin/users/listUsers.twig b/cp/resources/views/admin/users/listUsers.twig index 6d91afb..ae52211 100644 --- a/cp/resources/views/admin/users/listUsers.twig +++ b/cp/resources/views/admin/users/listUsers.twig @@ -17,6 +17,18 @@ {{ __('List Users') }}
+ +
+
+ + + {{ __('Create New User') }} + + + + +
+
@@ -24,6 +36,7 @@
+ {% include 'partials/flash.twig' %}
diff --git a/cp/resources/views/layouts/app.twig b/cp/resources/views/layouts/app.twig index 3e402d0..d71bcae 100644 --- a/cp/resources/views/layouts/app.twig +++ b/cp/resources/views/layouts/app.twig @@ -150,7 +150,7 @@
- {% if roles == 0 %}
  • + {% if roles == 0 %}
  • {{ __('List Users') }} + + {{ __('Create User') }} +
  • {% endif %}
  • diff --git a/cp/resources/views/partials/js-users.twig b/cp/resources/views/partials/js-users.twig index 68759cf..4c35a50 100644 --- a/cp/resources/views/partials/js-users.twig +++ b/cp/resources/views/partials/js-users.twig @@ -19,13 +19,15 @@ } return ""; } - + function roleLabelFormatter(cell) { var value = cell.getValue(); if (value === 0) { return 'Administrator'; } else if (value === 4) { return 'Registrar'; + } else if (value === 6) { + return 'Registrar Assistant'; } return value; // If the value is neither 0 nor 4, return it as is } diff --git a/cp/routes/web.php b/cp/routes/web.php index 7ce14fb..9c61453 100644 --- a/cp/routes/web.php +++ b/cp/routes/web.php @@ -99,7 +99,8 @@ $app->group('', function ($route) { $route->get('/leave_impersonation', RegistrarsController::class . ':leave_impersonation')->setName('leave_impersonation'); $route->get('/users', UsersController::class .':listUsers')->setName('listUsers'); - + $route->map(['GET', 'POST'], '/user/create', UsersController::class . ':createUser')->setName('createUser'); + $route->get('/epphistory', LogsController::class .':view')->setName('epphistory'); $route->get('/poll', LogsController::class .':poll')->setName('poll'); $route->get('/log', LogsController::class .':log')->setName('log');