Skip to content

Commit 56ce94f

Browse files
committed
Cleanup and rebase on Foundry
1 parent 340d5c1 commit 56ce94f

File tree

11 files changed

+412
-724
lines changed

11 files changed

+412
-724
lines changed

app/Controllers/UsersController.php

Lines changed: 95 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
<?php
2+
/**
3+
* Argora Foundry
4+
*
5+
* A modular PHP boilerplate for building SaaS applications, admin panels, and control systems.
6+
*
7+
* @package App
8+
* @author Taras Kondratyuk <help@argora.org>
9+
* @copyright Copyright (c) 2025 Argora
10+
* @license MIT License
11+
* @link https://github.com/getargora/foundry
12+
*/
213

314
namespace App\Controllers;
415

@@ -7,6 +18,7 @@
718
use Psr\Http\Message\ServerRequestInterface as Request;
819
use Psr\Container\ContainerInterface;
920
use Respect\Validation\Validator as v;
21+
use App\Auth\Auth;
1022

1123
class UsersController extends Controller
1224
{
@@ -20,7 +32,7 @@ public function listUsers(Request $request, Response $response)
2032
$users = $userModel->getAllUsers();
2133
return view($response,'admin/users/listUsers.twig', compact('users'));
2234
}
23-
35+
2436
public function createUser(Request $request, Response $response)
2537
{
2638
// Registrars can not create new users, then need to ask the registry
@@ -48,7 +60,7 @@ public function createUser(Request $request, Response $response)
4860
'password' => v::stringType()->notEmpty()->length(6, 255)->setName('Password'),
4961
'password_confirmation' => v::equals($data['password'] ?? '')->setName('Password Confirmation'),
5062
'status' => v::in(['0', '4'])->setName('Status'),
51-
'role' => v::in(['admin', 'zone'])->setName('Role'),
63+
'role' => v::in(['admin', 'client'])->setName('Role'),
5264
];
5365

5466
// Add registrar_id validation if role is registrar
@@ -88,96 +100,71 @@ public function createUser(Request $request, Response $response)
88100
return $response->withHeader('Location', '/user/create')->withStatus(302);
89101
}
90102

91-
if ($_SESSION["auth_roles"] != 0) {
92-
$registrar = true;
93-
} else {
94-
$registrar = null;
95-
}
96-
97-
if ($email) {
98-
if ($zone_id) {
99-
$db->beginTransaction();
103+
if ($email) {
104+
$roles = [
105+
'admin' => 0,
106+
'zone' => 4,
107+
];
100108

101-
$password_hashed = password_hash($password, PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]);
109+
$role = $role ?? (!empty($zone_id) ? 'zone' : 'admin');
110+
$roles_mask = $roles[$role] ?? 4;
102111

103-
try {
104-
$db->insert(
105-
'users',
106-
[
107-
'email' => $email,
108-
'password' => $password_hashed,
109-
'username' => $username,
110-
'verified' => $verified,
111-
'roles_mask' => 4,
112-
'status' => $status,
113-
'registered' => \time()
114-
]
115-
);
116-
$user_id = $db->getLastInsertId();
117-
118-
$db->insert(
119-
'zone_users',
120-
[
121-
'zone_id' => $zone_id,
122-
'user_id' => $user_id
123-
]
124-
);
125-
126-
$db->commit();
127-
} catch (Exception $e) {
128-
$db->rollBack();
129-
$this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage());
130-
return $response->withHeader('Location', '/user/create')->withStatus(302);
131-
}
112+
$password_hashed = password_hash($password, PASSWORD_ARGON2ID, [
113+
'memory_cost' => 1024 * 128,
114+
'time_cost' => 6,
115+
'threads' => 4
116+
]);
132117

133-
$this->container->get('flash')->addMessage('success', 'User ' . $email . ' has been created successfully');
134-
return $response->withHeader('Location', '/users')->withStatus(302);
135-
} else {
118+
try {
136119
$db->beginTransaction();
137120

138-
$password_hashed = password_hash($password, PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]);
139-
140-
try {
141-
$db->insert(
142-
'users',
143-
[
144-
'email' => $email,
145-
'password' => $password_hashed,
146-
'username' => $username,
147-
'verified' => $verified,
148-
'roles_mask' => 0,
149-
'status' => $status,
150-
'registered' => \time()
151-
]
152-
);
153-
$userId = $db->getlastInsertId();
154-
155-
$db->commit();
156-
} catch (Exception $e) {
157-
$db->rollBack();
158-
$this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage());
159-
return $response->withHeader('Location', '/user/create')->withStatus(302);
121+
$db->insert('users', [
122+
'email' => $email,
123+
'password' => $password_hashed,
124+
'username' => $username,
125+
'verified' => $verified,
126+
'roles_mask' => $roles_mask,
127+
'status' => $status,
128+
'registered' => \time(),
129+
'password_last_updated'=> date('Y-m-d H:i:s'),
130+
]);
131+
132+
$user_id = $db->getLastInsertId();
133+
134+
if ($roles_mask === $roles['zone'] && !empty($zone_id)) {
135+
$db->insert('zone_users', [
136+
'zone_id' => $zone_id,
137+
'user_id' => $user_id,
138+
]);
160139
}
161140

162-
$db->exec('UPDATE users SET password_last_updated = NOW() WHERE id = ?', [$userId]);
141+
$db->commit();
142+
163143
$this->container->get('flash')->addMessage('success', 'User ' . $email . ' has been created successfully');
164144
return $response->withHeader('Location', '/users')->withStatus(302);
165-
}
145+
} catch (Exception $e) {
146+
$this->container->get('flash')->addMessage('error', 'Database failure: ' . $e->getMessage());
147+
return $response->withHeader('Location', '/user/create')->withStatus(302);
148+
}
149+
} else {
150+
$this->container->get('flash')->addMessage('error', 'An unexpected error occurred. Please try again later');
151+
return $response->withHeader('Location', '/user/create')->withStatus(302);
166152
}
167153
}
168154

169155
$db = $this->container->get('db');
170156
$zones = $db->select("SELECT id, domain_name FROM zones");
157+
171158
if ($_SESSION["auth_roles"] != 0) {
172-
$registrar = true;
159+
$user = true;
173160
} else {
174-
$registrar = null;
161+
$user = null;
175162
}
176163

177164
// Default view for GET requests or if POST data is not set
178165
return view($response,'admin/users/createUser.twig', [
179166
'zones' => $zones,
180-
'registrar' => $registrar,
167+
'user' => $user,
181168
]);
182169
}
183170

@@ -212,7 +199,7 @@ public function updateUser(Request $request, Response $response, $args)
212199
$_SESSION['user_to_update'] = [$args];
213200

214201
$roles_new = [
215-
'4' => ($user['roles_mask'] & 4) ? true : false, // Zone
202+
'4' => ($user['roles_mask'] & 4) ? true : false, // Client
216203
'8' => ($user['roles_mask'] & 8) ? true : false, // Accountant
217204
'16' => ($user['roles_mask'] & 16) ? true : false, // Support
218205
'32' => ($user['roles_mask'] & 32) ? true : false, // Auditor
@@ -351,7 +338,7 @@ public function updateUserProcess(Request $request, Response $response)
351338

352339
// Prevent elevating privileges to 4 unless the user was already 4
353340
if ($roles_mask == 4 && $currentRolesMask != 4) {
354-
$errors[] = 'You cannot elevate role to registrar unless the user was already registrar';
341+
$errors[] = 'You cannot elevate role to client administrator unless the user was already client administrator';
355342
}
356343
}
357344

@@ -391,6 +378,7 @@ public function updateUserProcess(Request $request, Response $response)
391378
if (!empty($password)) {
392379
$password_hashed = password_hash($password, PASSWORD_ARGON2ID, ['memory_cost' => 1024 * 128, 'time_cost' => 6, 'threads' => 4]);
393380
$updateData['password'] = $password_hashed;
381+
$updateData['password_last_updated'] = date('Y-m-d H:i:s');
394382
}
395383

396384
$db->update(
@@ -410,10 +398,42 @@ public function updateUserProcess(Request $request, Response $response)
410398

411399
$userId = $db->selectValue('SELECT id from users WHERE username = ?', [ $username ]);
412400
unset($_SESSION['user_to_update']);
413-
$db->exec('UPDATE users SET password_last_updated = NOW() WHERE id = ?', [$userId]);
414401
$this->container->get('flash')->addMessage('success', 'User ' . $username . ' has been updated successfully on ' . $update);
415402
return $response->withHeader('Location', '/user/update/'.$username)->withStatus(302);
416403
}
417404
}
418-
405+
406+
public function impersonateUser(Request $request, Response $response, $args)
407+
{
408+
if ($_SESSION["auth_roles"] != 0) {
409+
return $response->withHeader('Location', '/dashboard')->withStatus(302);
410+
}
411+
412+
$db = $this->container->get('db');
413+
414+
if ($args) {
415+
$args = trim($args);
416+
417+
if (!preg_match('/^[a-z0-9_-]+$/', $args)) {
418+
$this->container->get('flash')->addMessage('error', 'Invalid user name');
419+
return $response->withHeader('Location', '/users')->withStatus(302);
420+
}
421+
422+
$user_id = $db->selectValue('SELECT id FROM users WHERE username = ? AND status = 0', [ $args ]);
423+
if (!$user_id) {
424+
$this->container->get('flash')->addMessage('error', 'The specified user does not exist or is no longer active');
425+
return $response->withHeader('Location', '/users')->withStatus(302);
426+
}
427+
428+
Auth::impersonateUser($user_id);
429+
} else {
430+
// Redirect to the users view
431+
return $response->withHeader('Location', '/users')->withStatus(302);
432+
}
433+
}
434+
435+
public function leave_impersonation(Request $request, Response $response)
436+
{
437+
Auth::leaveImpersonation();
438+
}
419439
}

0 commit comments

Comments
 (0)