diff --git a/cp/app/Controllers/UsersController.php b/cp/app/Controllers/UsersController.php
index 4046c49..f54da7a 100644
--- a/cp/app/Controllers/UsersController.php
+++ b/cp/app/Controllers/UsersController.php
@@ -104,7 +104,7 @@ class UsersController extends Controller
'password' => $password_hashed,
'username' => $username,
'verified' => $verified,
- 'roles_mask' => 6,
+ 'roles_mask' => 4,
'status' => $status,
'registered' => \time()
]
@@ -205,12 +205,21 @@ class UsersController extends Controller
$_SESSION['user_to_update'] = [$args];
+ $roles_new = [
+ '4' => ($user['roles_mask'] & 4) ? true : false, // Registrar
+ '8' => ($user['roles_mask'] & 8) ? true : false, // Accountant
+ '16' => ($user['roles_mask'] & 16) ? true : false, // Support
+ '32' => ($user['roles_mask'] & 32) ? true : false, // Auditor
+ '64' => ($user['roles_mask'] & 64) ? true : false, // Sales
+ ];
+
return view($response,'admin/users/updateUser.twig', [
'user' => $user,
'currentUri' => $uri,
'registrars' => $registrars,
'user_asso' => $user_asso,
- 'registrar_name' => $registrar_name
+ 'registrar_name' => $registrar_name,
+ 'roles_new' => $roles_new
]);
} else {
// User does not exist, redirect to the users view
@@ -240,6 +249,10 @@ class UsersController extends Controller
$password_confirmation = $data['password_confirmation'] ?? null;
$status = $data['status'] ?? null;
$verified = $data['verified'] ?? null;
+ $roles_mask = $data['roles_mask'] ?? 0;
+
+ $allowedRoles = [0, 2, 4, 8, 16, 32, 64];
+ $allowedRolesMask = array_sum($allowedRoles); // 124 (sum of allowed roles)
// Define validation rules
$validators = [
@@ -249,6 +262,14 @@ class UsersController extends Controller
'verified' => v::in(['0', '1'])->setName('Verified'), // Ensure verified is checked as 0 or 1
];
+ // Add custom validation for roles_mask
+ $validators['roles_mask'] = v::oneOf(
+ v::intVal()->callback(function ($value) use ($allowedRolesMask) {
+ return ($value & ~$allowedRolesMask) === 0; // Ensure only allowed roles are included
+ }),
+ v::nullType() // Allow null as a valid value
+ )->setName('Roles Mask');
+
// Add password validation only if provided
if (!empty($password)) {
$validators['password'] = v::stringType()->notEmpty()->length(6, 255)->setName('Password');
@@ -289,6 +310,11 @@ class UsersController extends Controller
return $response->withHeader('Location', '/user/update/'.$old_username)->withStatus(302);
}
+ if (in_array($roles_mask, [0, '0'], true)) {
+ $this->container->get('flash')->addMessage('error', 'No roles assigned. Please assign at least one role');
+ return $response->withHeader('Location', '/user/update/' . $old_username)->withStatus(302);
+ }
+
$db->beginTransaction();
try {
@@ -301,6 +327,7 @@ class UsersController extends Controller
'username' => $username,
'verified' => $verified,
'status' => $status,
+ 'roles_mask' => $roles_mask,
];
if (!empty($password)) {
diff --git a/cp/resources/views/admin/users/createUser.twig b/cp/resources/views/admin/users/createUser.twig
index 339913a..530519a 100644
--- a/cp/resources/views/admin/users/createUser.twig
+++ b/cp/resources/views/admin/users/createUser.twig
@@ -93,7 +93,7 @@
-
+
+
+
{% endblock %}
\ No newline at end of file
diff --git a/cp/resources/views/partials/js-users.twig b/cp/resources/views/partials/js-users.twig
index ca5b236..d1413d1 100644
--- a/cp/resources/views/partials/js-users.twig
+++ b/cp/resources/views/partials/js-users.twig
@@ -7,7 +7,7 @@
var table;
document.addEventListener("DOMContentLoaded", function(){
- function userLinkFormatter(cell){
+ function emailLinkFormatter(cell){
var value = cell.getValue();
return `
${value}`;
}
@@ -28,14 +28,33 @@
function roleLabelFormatter(cell) {
var value = cell.getValue();
+
+ // Define role mappings with labels and styles
+ var roles = [
+ { bit: 0, label: 'Administrator', class: 'status status-purple' },
+ { bit: 4, label: 'Registrar', class: 'status status-indigo' },
+ { bit: 8, label: 'Accountant', class: 'status status-green' },
+ { bit: 16, label: 'Support', class: 'status status-azure' },
+ { bit: 32, label: 'Auditor', class: 'status status-orange' },
+ { bit: 64, label: 'Sales', class: 'status status-teal' }
+ ];
+
+ // Special case for Administrator (no roles assigned)
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
+
+ // Check assigned roles using bitmask
+ var assignedRoles = roles
+ .filter(function (role) {
+ return role.bit !== 0 && (value & role.bit);
+ })
+ .map(function (role) {
+ return '' + role.label + '';
+ });
+
+ // Join assigned roles with separators
+ return assignedRoles.length > 0 ? assignedRoles.join(', ') : 'Unknown Role';
}
function verifiedFormatter(cell) {
@@ -144,10 +163,10 @@
placeholder: "{{ __('No Data') }}",
columns:[
{formatter:"responsiveCollapse", width:30, minWidth:30, hozAlign:"center", resizable:false, headerSort:false, responsive:0},
- {title:"{{ __('Name') }}", field:"username", width:200, resizable:false, headerSort:true, formatter: userLinkFormatter, responsive:0},
- {title:"{{ __('Email') }}", field:"email", width:300, resizable:false, headerSort:true, responsive:2},
- {title:"{{ __('Roles') }}", field:"roles_mask", width:200, resizable:false, headerSort:true, formatter: roleLabelFormatter, responsive:2},
- {title:"{{ __('Verified') }}", field:"verified", width:200, resizable:false, headerSort:true, formatter: verifiedFormatter, responsive:2},
+ {title:"{{ __('Email') }}", field:"email", width:300, resizable:false, headerSort:true, formatter: emailLinkFormatter, responsive:0},
+ {title:"{{ __('User Name') }}", field:"username", width:200, resizable:false, headerSort:true, responsive:2},
+ {title:"{{ __('Roles') }}", field:"roles_mask", width:300, resizable:false, headerSort:true, formatter: roleLabelFormatter, responsive:2},
+ {title:"{{ __('Verified') }}", field:"verified", width:150, resizable:false, headerSort:true, formatter: verifiedFormatter, responsive:2},
{title:"{{ __('Status') }}", field:"status", width:200, resizable:false, headerSort:true, formatter: statusBadgeFormatter, responsive:2},
{title: "{{ __('Actions') }}", formatter: actionsFormatter, responsive:0, headerSort: false, download:false, hozAlign: "center", cellClick:function(e, cell){ e.stopPropagation(); }},
]