Add user role management functionality with CRUD operations and permissions handling

- Created user_role.php for viewing and editing user roles and their permissions.
- Implemented inline editing for role details and permissions.
- Added user_role_manage.php for creating and managing user roles.
- Introduced user_roles.php for listing all user roles with pagination and filtering options.
- Integrated API calls for fetching and updating role data and permissions.
- Enhanced user interface with success messages and navigation controls.
This commit is contained in:
“VeLiTi”
2026-01-19 11:16:54 +01:00
parent 3db13b9ebf
commit 782050c3ca
35 changed files with 4071 additions and 370 deletions

BIN
.DS_Store vendored

Binary file not shown.

188
access_element.php Normal file
View File

@@ -0,0 +1,188 @@
<?php
defined(page_security_key) or exit;
if (debug && debug_id == $_SESSION['id']){
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
include_once './assets/functions.php';
include_once './settings/settings_redirector.php';
//SET ORIGIN FOR NAVIGATION
$_SESSION['prev_origin_access_element'] = $_SERVER['REQUEST_URI'];
$page = 'access_element';
//Check if allowed
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
header('location: index.php');
exit;
}
//PAGE Security
$page_manage = 'access_element_manage';
$update_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'U');
$update_allowed_edit = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'C');
//GET Details from URL
$GET_VALUES = urlGETdetails($_GET) ?? '';
//CALL TO API FOR General information
$api_url = '/v2/access_elements/'.$GET_VALUES;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
$responses = $responses[0];
$element_id = $responses->rowID;
//CALL TO API FOR Roles using this access element
$api_url = '/v2/role_access_permissions/access_id='.$element_id;
$role_permissions = ioServer($api_url,'');
//Decode Payload
if (!empty($role_permissions)){$role_permissions = json_decode($role_permissions);}else{$role_permissions = null;}
//------------------------------
//Variables
//------------------------------
$status_text = ($responses->is_active == 1) ? ($enabled ?? 'Active') : ($disabled ?? 'Inactive');
$status_class = ($responses->is_active == 1) ? 'id1' : 'id0';
// Handle success messages
if (isset($_GET['success_msg'])) {
if ($_GET['success_msg'] == 1) {
$success_msg = ($message_access_1 ?? 'Access element created successfully');
}
if ($_GET['success_msg'] == 2) {
$success_msg = ($message_access_2 ?? 'Access element updated successfully');
}
if ($_GET['success_msg'] == 3) {
$success_msg = ($message_access_3 ?? 'Access element deleted successfully');
}
}
template_header(($access_element_title ?? 'Access Element'), 'access_element', 'view');
$view = '
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
<h2 class="responsive-width-100">'.($view_access_h2 ?? 'Access Element').' - '.$responses->access_name.'</h2>
<a href="index.php?page='.$_SESSION['origin'].'&p='.$_SESSION['p'].$_SESSION['status'].$_SESSION['sort'].$_SESSION['search'].'" class="btn alt mar-right-2">←</a>
';
if ($update_allowed_edit === 1){
$view .= '<a href="index.php?page=access_element_manage&rowID='.$responses->rowID.'" class="btn">✏️</a>';
}
$view .= '</div>';
if (isset($success_msg)){
$view .= ' <div class="msg success">
<i class="fas fa-check-circle"></i>
<p>'.$success_msg.'</p>
<i class="fas fa-times"></i>
</div>';
}
$view .= '<div class="content-block-wrapper">';
// Access Element Information Block
$view .= ' <div class="content-block order-details">
<div class="block-header">
<i class="fa-solid fa-circle-info"></i>'.($view_access_information ?? 'Access Element Information').'
</div>
<div class="order-detail">
<h3>'.($general_status ?? 'Status').'</h3>
<p><span class="status '.$status_class.'">'.$status_text.'</span></p>
</div>
<div class="order-detail">
<h3>'.($access_element_name ?? 'Name').'</h3>
<p>'.$responses->access_name.'</p>
</div>
<div class="order-detail">
<h3>'.($access_element_path ?? 'Path').'</h3>
<p>'.$responses->access_path.'</p>
</div>
<div class="order-detail">
<h3>'.($access_element_group ?? 'Group').'</h3>
<p>'.($responses->access_group ?? '-').'</p>
</div>
<div class="order-detail">
<h3>'.($role_description ?? 'Description').'</h3>
<p>'.($responses->description ?? '-').'</p>
</div>
</div>
';
$view .= '</div>'; // Close content-block-wrapper
// Roles Using This Access Element
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-user-shield fa-sm"></i>'.($view_access_roles ?? 'Roles Using This Element').'
</div>
<div class="table">
<table>
<thead>
<tr>
<th>'.($role_name ?? 'Role Name').'</th>
<th>'.($permission_create ?? 'C').'</th>
<th>'.($permission_read ?? 'R').'</th>
<th>'.($permission_update ?? 'U').'</th>
<th>'.($permission_delete ?? 'D').'</th>
</tr>
</thead>
<tbody>';
if (!empty($role_permissions)){
foreach ($role_permissions as $role_perm){
$can_create = ($role_perm->can_create == 1) ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
$can_read = ($role_perm->can_read == 1) ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
$can_update = ($role_perm->can_update == 1) ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
$can_delete = ($role_perm->can_delete == 1) ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
$view .= '<tr onclick="window.location.href=\'index.php?page=user_role&rowID='.$role_perm->role_id.'\'" style="cursor: pointer;">
<td>'.$role_perm->role_name.'</td>
<td>'.$can_create.'</td>
<td>'.$can_read.'</td>
<td>'.$can_update.'</td>
<td>'.$can_delete.'</td>
</tr>';
}
} else {
$view .= '<tr>
<td colspan="5" style="text-align:center;">'.($no_roles_using ?? 'No roles are using this access element').'</td>
</tr>';
}
$view .= ' </tbody>
</table>
</div>
</div>
';
// Metadata Block
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-bars fa-sm"></i>'.($tab3 ?? 'Details').'
</div>
<div class="table order-table">
<table>
<tr>
<td style="width:25%;">'.($general_created ?? 'Created').'</td>
<td>'.getRelativeTime($responses->created).'</td>
</tr>
<tr>
<td style="width:25%;">'.($general_updated ?? 'Updated').'</td>
<td>'.getRelativeTime($responses->updated).'</td>
</tr>
</table>
</div>
</div>
';
//OUTPUT
echo $view;
template_footer()
?>

168
access_element_manage.php Normal file
View File

@@ -0,0 +1,168 @@
<?php
defined(page_security_key) or exit;
if (debug && debug_id == $_SESSION['id']){
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
include_once './assets/functions.php';
include_once './settings/settings_redirector.php';
$page = 'access_element_manage';
//Check if allowed
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
header('location: index.php');
exit;
}
//PAGE Security
$update_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'C');
// Default input values
$element = [
'rowID' => '',
'access_name' => '',
'access_path' => '',
'access_group' => '',
'description' => '',
'is_active' => 1,
'created' => '',
'createdby' => $_SESSION['username'],
'updated' => '',
'updatedby' => ''
];
$element_ID = $_GET['rowID'] ?? '';
if ($element_ID !=''){
$url = 'index.php?page=access_element&rowID='.$element_ID.'';
} else {
$url = 'index.php?page=access_elements';
}
if (isset($_GET['rowID'])) {
// ID param exists, edit an existing element
//CALL TO API
$api_url = '/v2/access_elements/rowID='.$element_ID;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = null;}
$element = $responses[0];
if ($update_allowed === 1){
if (isset($_POST['submit'])) {
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//API call
$responses = ioServer('/v2/access_elements', $data);
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=access_element&rowID='.$element_ID.'&success_msg=2');
exit;
}
}
}
if ($delete_allowed === 1){
if (isset($_POST['delete'])) {
//GET ALL POST DATA
$data = json_encode($_POST , JSON_UNESCAPED_UNICODE);
//API call
$responses = ioServer('/v2/access_elements', $data);
// Redirect and delete element
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=access_elements&success_msg=3');
exit;
}
}
}
} else {
// Create a new element
if (isset($_POST['submit']) && $create_allowed === 1) {
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//API call
$responses = ioServer('/v2/access_elements', $data);
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=access_elements&success_msg=1');
exit;
}
}
}
template_header(($access_element_title ?? 'Access Element'), 'access_element', 'manage');
$label_h2 = (($element_ID !='')? ($manage_access_h2 ?? 'Edit Access Element') : ($button_create_access ?? 'Create Access Element'));
$view ='
<form action="" method="post">
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
<h2 class="responsive-width-100">'.$label_h2.'</h2>
<a href="'.$url.'" class="btn alt mar-right-2">←</a>
';
if ($delete_allowed === 1 && $element_ID != ''){
$view .= '<input type="submit" name="delete" value="X" class="btn red mar-right-2" onclick="return confirm(\''.($confirm_delete_access ?? 'Are you sure you want to delete this access element?').'\')">';
}
if ($update_allowed === 1 || ($create_allowed === 1 && $element_ID == '')){
$view .= '<input type="submit" name="submit" value="💾" class="btn">';
}
$view .= '</div>';
$view .= '<div class="tabs">
<a href="#" class="active">'.($tab1 ?? 'General').'</a>
</div>
<div class="content-block tab-content active">
<div class="form responsive-width-100">
<label for="is_active">'.($general_status ?? 'Status').'</label>
<select id="is_active" name="is_active">
<option value="1" '.($element['is_active']==1?' selected':'').'>'.($enabled ?? 'Active').'</option>
<option value="0" '.($element['is_active']==0?' selected':'').'>'.($disabled ?? 'Inactive').'</option>
</select>
<label for="access_name">'.($access_element_name ?? 'Name').' <i class="required">*</i></label>
<input id="access_name" type="text" name="access_name" placeholder="'.($access_element_name ?? 'Name').'" value="'.$element['access_name'].'" required>
<label for="access_path">'.($access_element_path ?? 'Path').' <i class="required">*</i></label>
<input id="access_path" type="text" name="access_path" placeholder="'.($access_element_path_placeholder ?? 'e.g., equipments, equipment_manage').'" value="'.$element['access_path'].'" required>
<label for="access_group">'.($access_element_group ?? 'Group').'</label>
<input id="access_group" type="text" name="access_group" placeholder="'.($access_element_group_placeholder ?? 'e.g., Views, API, Admin').'" value="'.($element['access_group'] ?? '').'">
<label for="description">'.($role_description ?? 'Description').'</label>
<textarea id="description" name="description" placeholder="'.($role_description ?? 'Description').'" style="height: 100px;">'.$element['description'].'</textarea>
<input type="hidden" name="rowID" value="'.$element_ID.'">
</div>
</div>';
//DISPLAY TAB 2 - Metadata
if ($element_ID != ''){
$view .= '<div class="tabs">
<a href="#">'.($tab3 ?? 'Details').'</a>
</div>
<div class="content-block tab-content">
<div class="form responsive-width-100">
<label for="created">'.($general_created ?? 'Created').'</label>
<input id="created" type="text" name="" placeholder="'.($general_created ?? 'Created').'" value="'.$element['created'].'" readonly>
<label for="createdby">'.($general_createdby ?? 'Created By').'</label>
<input id="createdby" type="text" name="" placeholder="'.($general_createdby ?? 'Created By').'" value="'.$element['createdby'].'" readonly>
<label for="updated">'.($general_updated ?? 'Updated').'</label>
<input id="updated" type="text" name="" placeholder="'.($general_updated ?? 'Updated').'" value="'.$element['updated'].'" readonly>
<label for="updatedby">'.($general_updatedby ?? 'Updated By').'</label>
<input id="updatedby" type="text" name="" placeholder="'.($general_updatedby ?? 'Updated By').'" value="'.$element['updatedby'].'" readonly>
</div>
</div>';
}
$view .= '</form>';
//Output
echo $view;
template_footer()?>

317
access_elements.php Normal file
View File

@@ -0,0 +1,317 @@
<?php
defined(page_security_key) or exit;
if (debug && debug_id == $_SESSION['id']){
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
include_once './assets/functions.php';
include_once './settings/settings_redirector.php';
//SET PAGE ORIGIN FOR NAVIGATION AND SECURITY
$prev_page = $_SESSION['prev_origin'] ?? '';
$page = $_SESSION['origin'] = 'access_elements';
//create backbutton to prev_origin
$back_btn_orgin = ($prev_page != '')? '<a href="'.$prev_page.'" class="btn alt mar-right-2">←</a>':'';
//Check if allowed
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
header('location: index.php');
exit;
}
//PAGE Security
$page_manage = 'access_element_manage';
$update_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'C');
// Function to scan project for new PHP files and add to access_elements
function scan_and_update_access_elements() {
$new_elements = [];
$base_path = dirname(__FILE__);
// Scan root PHP files (excluding index, login, logout)
$root_files = glob($base_path . '/*.php');
foreach ($root_files as $file) {
$filename = basename($file, '.php');
if (!in_array($filename, ['index', 'login', 'logout'])) {
// Only add if not already in array (first occurrence wins)
if (!isset($new_elements[$filename])) {
$new_elements[$filename] = [
'name' => ucwords(str_replace('_', ' ', $filename)),
'path' => $filename,
'group' => 'Views',
'description' => 'Auto-scanned: ' . $filename
];
}
}
}
// Scan API v2 get folder - only add if not already found in root
$get_files = glob($base_path . '/api/v2/get/*.php');
foreach ($get_files as $file) {
$filename = basename($file, '.php');
if (!isset($new_elements[$filename])) {
$new_elements[$filename] = [
'name' => ucwords(str_replace('_', ' ', $filename)),
'path' => $filename,
'group' => 'API',
'description' => 'Auto-scanned: ' . $filename
];
}
}
// Scan API v2 post folder - only add if not already found
$post_files = glob($base_path . '/api/v2/post/*.php');
foreach ($post_files as $file) {
$filename = basename($file, '.php');
if (!isset($new_elements[$filename])) {
$new_elements[$filename] = [
'name' => ucwords(str_replace('_', ' ', $filename)),
'path' => $filename,
'group' => 'API',
'description' => 'Auto-scanned: ' . $filename
];
}
}
// Get existing access elements from API
$api_url = '/v2/access_elements/';
$existing = ioServer($api_url, '');
$existing_paths = [];
if (!empty($existing)) {
$existing_data = json_decode($existing);
foreach ($existing_data as $element) {
$existing_paths[] = $element->access_path;
}
}
// Filter out elements that already exist
$elements_to_add = [];
foreach ($new_elements as $path => $element) {
if (!in_array($path, $existing_paths)) {
$elements_to_add[] = $element;
}
}
// Add new elements via API
$added_count = 0;
foreach ($elements_to_add as $element) {
$data = json_encode([
'access_name' => $element['name'],
'access_path' => $element['path'],
'access_group' => $element['group'],
'description' => $element['description'],
'is_active' => 1
], JSON_UNESCAPED_UNICODE);
$response = ioServer('/v2/access_elements', $data);
if ($response !== 'NOK') {
$added_count++;
}
}
return $added_count;
}
// Handle scan request
if (isset($_POST['scan_elements']) && $create_allowed === 1) {
$added_count = scan_and_update_access_elements();
header('Location: index.php?page=access_elements&elements_added=' . $added_count);
exit;
}
//GET PARAMETERS && STORE in SESSION for FURTHER USE/NAVIGATION
$pagination_page = $_SESSION['p'] = isset($_GET['p']) ? $_GET['p'] : 1;
$status = $_SESSION['status'] = isset($_GET['status']) ? '&status='.$_GET['status'] : '';
$sort = $_SESSION['sort'] = isset($_GET['sort']) ? '&sort='.$_GET['sort'] : '';
$search = $_SESSION['search'] = isset($_GET['search']) ? '&search='.$_GET['search'] : '';
//GET PARAMETERS FOR FILTERS
$filter = urlGETdetailsFilter($_GET) ?? '';
// Determine the URL
$url = 'index.php?page=access_elements'.$status.$search.$sort;
//GET Details from URL
$GET_VALUES = urlGETdetails($_GET) ?? '';
//CALL TO API
$api_url = '/v2/access_elements/'.$GET_VALUES;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
//Return QueryTotal from API
$total_url = ((!empty($GET_VALUES) && $GET_VALUES !='') ? '&totals=' : 'totals=' );
$api_url = '/v2/access_elements/'.$GET_VALUES.$total_url;
$query_total = ioServer($api_url,'');
//Decode Payload
if (!empty($query_total)){$query_total = json_decode($query_total);}else{$query_total = null;}
// Handle success messages
if (isset($_GET['success_msg'])) {
if ($_GET['success_msg'] == 1) {
$success_msg = ($message_access_1 ?? 'Access element created successfully');
}
if ($_GET['success_msg'] == 2) {
$success_msg = ($message_access_2 ?? 'Access element updated successfully');
}
if ($_GET['success_msg'] == 3) {
$success_msg = ($message_access_3 ?? 'Access element deleted successfully');
}
}
// Handle elements added message from scan
if (isset($_GET['elements_added'])) {
$added_count = (int)$_GET['elements_added'];
if ($added_count > 0) {
$success_msg = $added_count . ' ' . ($message_elements_added ?? 'new access elements added');
} else {
$success_msg = ($message_no_new_elements ?? 'No new elements found. All elements are up to date.');
}
}
template_header(($access_elements_title ?? 'Access Elements'), 'access_elements','view');
$view = '
<div class="content-title">
<div class="title">
<i class="fa-solid fa-lock"></i>
<div class="txt">
<h2>'.($access_elements_h2 ?? 'Access Elements').' ('.$query_total.')</h2>
<p>'.($access_elements_p ?? 'Manage system access elements and paths').'</p>
</div>
</div>
<div class="title-actions">
'.$back_btn_orgin;
// Scan button - only show if user has create permission
if ($create_allowed === 1){
$view .= '
<form action="" method="post" style="display:inline;">
<button type="submit" name="scan_elements" class="btn alt" title="'.($scan_elements_title ?? 'Scan for new files').'">
<i class="fa-solid fa-sync-alt"></i>
</button>
</form>';
$view .= '<a href="index.php?page=access_element_manage" class="btn">+</a>';
}
$view .= '<button id="filter-toggle" class="btn alt" onclick="toggleFilters()">
<i class="fa-solid fa-search"></i>
</button>
</div>
</div>';
if (isset($success_msg)){
$view .= ' <div class="msg success">
<i class="fas fa-check-circle"></i>
<p>'.$success_msg.'</p>
<i class="fas fa-times"></i>
</div>';
}
$view .= '
<div id="filter-panel" class="filter-panel" style="display: none;">
<div class="filter-content">
<form action="" method="get">
'.$filter.'
<div class="filter-row">
<div class="filter-group">
<select name="status">
<option value="" disabled selected>'.($general_status ?? 'Status').'</option>
<option value="1"'.(isset($_GET['status']) && $_GET['status']==1?' selected':'').'>'.($enabled ?? 'Active').'</option>
<option value="0"'.(isset($_GET['status']) && $_GET['status']==0?' selected':'').'>'.($disabled ?? 'Inactive').'</option>
</select>
</div>
<div class="filter-group">
<select name="sort">
<option value="" disabled selected>'.($general_sort ?? 'Sort').'</option>
<option value="1"'.(isset($_GET['sort']) && $_GET['sort']==1?' selected':'').'>'.($access_element_name ?? 'Name').' '.($general_sort_type_1 ?? 'ASC').'</option>
<option value="2"'.(isset($_GET['sort']) && $_GET['sort']==2?' selected':'').'>'.($access_element_name ?? 'Name').' '.($general_sort_type_2 ?? 'DESC').'</option>
<option value="3"'.(isset($_GET['sort']) && $_GET['sort']==3?' selected':'').'>'.($access_element_path ?? 'Path').' '.($general_sort_type_1 ?? 'ASC').'</option>
<option value="4"'.(isset($_GET['sort']) && $_GET['sort']==4?' selected':'').'>'.($access_element_path ?? 'Path').' '.($general_sort_type_2 ?? 'DESC').'</option>
</select>
</div>
<div class="filter-group search-group">
<input type="text" name="search" placeholder="'.($access_search ?? 'Search access elements...').'" value="">
</div>
</div>
<div class="filter-actions">
<button type="submit" class="btn"><i class="fas fa-level-down-alt fa-rotate-90"></i></button>
<a class="btn alt" href="index.php?page=access_elements">X</a>
</div>
</form>
</div>
</div>
';
$view .= '
<div class="content-block">
<div class="table">
<table class="sortable">
<thead>
<tr>
<th>'.($access_element_name ?? 'Name').'</th>
<th>'.($access_element_path ?? 'Path').'</th>
<th>'.($access_element_group ?? 'Group').'</th>
<th class="responsive-hidden">'.($role_description ?? 'Description').'</th>
<th>'.($general_status ?? 'Status').'</th>
<th class="responsive-hidden">'.($general_created ?? 'Created').'</th>
</tr>
</thead>
<tbody>
';
if (empty($responses)){
$view .= '
<tr>
<td colspan="6" style="text-align:center;">'.($message_no_access_elements ?? 'No access elements found').'</td>
</tr>';
}
foreach ($responses as $response){
//Translate status INT to STR
$status_text = ($response->is_active == 1) ? ($enabled ?? 'Active') : ($disabled ?? 'Inactive');
$status_class = ($response->is_active == 1) ? 'id1' : 'id0';
$view .= '<tr onclick="window.location.href=\'index.php?page=access_element&rowID='.$response->rowID.'\'" style="cursor: pointer;">
<td>'.$response->access_name.'</td>
<td>'.$response->access_path.'</td>
<td>'.($response->access_group ?? '-').'</td>
<td class="responsive-hidden">'.($response->description ?? '-').'</td>
<td><span class="status '.$status_class.'">'.$status_text.'</span></td>
<td class="responsive-hidden">'.getRelativeTime($response->created).'</td>
</tr>
';
}
$view .= '
</tbody>
</table>
</div>
</div>
';
$page_rows = $page_rows_equipment ?? 20;
$view.='<div class="pagination">';
if ($pagination_page > 1) {
$page = $pagination_page-1;
$view .= '<a href="'.$url.'&p=1">'.($general_first ?? 'First').'</a>';
$view .= '<a href="'.$url.'&p='.$page.'">'.($general_prev ?? 'Prev').'</a>';
}
$totals = ceil($query_total / $page_rows) == 0 ? 1 : ceil($query_total / $page_rows);
$view .= '<span> '.($general_page ?? 'Page ').$pagination_page.($general_page_of ?? ' of ').$totals.'</span>';
if ($pagination_page * $page_rows < $query_total){
$page = $pagination_page+1;
$view .= '<a href="'.$url.'&p='.$page.'">'.($general_next ?? 'Next').'</a>';
$view .= '<a href="'.$url.'&p='.$totals.'">'.($general_last ?? 'Last').'</a>';
}
$view .= '</div>';
//OUTPUT
echo $view;
template_footer();
?>

BIN
api/.DS_Store vendored

Binary file not shown.

BIN
api/v1/.DS_Store vendored

Binary file not shown.

BIN
api/v2/.DS_Store vendored

Binary file not shown.

View File

@@ -0,0 +1,158 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// Access Elements
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//------------------------------------------
//NEW ARRAY
//------------------------------------------
$criterias = [];
$clause = '';
//------------------------------------------
//Check for $_GET variables and build up clause
//------------------------------------------
if(isset($get_content) && $get_content!=''){
//GET VARIABLES FROM URL
$requests = explode("&", $get_content);
//Check for keys and values
foreach ($requests as $y){
$v = explode("=", $y);
//INCLUDE VARIABLES IN ARRAY
$criterias[$v[0]] = $v[1];
if ($v[0] == 'page' || $v[0] =='p' || $v[0] =='totals' || $v[0] =='success_msg' || $v[0] =='sort' || $v[0] =='all'){
//do nothing
}
elseif ($v[0] == 'rowid') {
//build up search by ID
$clause .= ' AND a.rowID = :'.$v[0];
}
elseif ($v[0] == 'status') {
//Update status based on status
$clause .= ' AND a.is_active = :'.$v[0];
}
elseif ($v[0] == 'search') {
//build up search
$clause .= ' AND (a.access_name LIKE :'.$v[0].' OR a.access_path LIKE :'.$v[0].' OR a.description LIKE :'.$v[0].')';
}
elseif ($v[0] == 'access_path') {
//build up path search
$clause .= ' AND a.access_path = :'.$v[0];
}
else {
//create clause
$clause .= ' AND a.'.$v[0].' = :'.$v[0];
}
}
}
//Build WHERE clause
$whereclause = '';
if ($clause != ''){
$whereclause = 'WHERE '.substr($clause, 4);
}
// GET SORT INDICATOR
$sort_indicator = $criterias['sort'] ?? '';
switch ($sort_indicator){
case 1:
$sort = ' a.access_name ASC ';
break;
case 2:
$sort = ' a.access_name DESC ';
break;
case 3:
$sort = ' a.access_path ASC ';
break;
case 4:
$sort = ' a.access_path DESC ';
break;
default:
$sort = ' a.access_name ASC ';
break;
}
if (isset($criterias['totals']) && $criterias['totals'] ==''){
//Request for total rows
$sql = 'SELECT count(*) as count FROM access_elements a '.$whereclause;
}
elseif (isset($criterias['all']) && $criterias['all'] ==''){
//Return all records (no paging)
$sql = 'SELECT a.* FROM access_elements a '.$whereclause.' ORDER BY '.$sort;
}
else {
//SQL
$sql = 'SELECT a.* FROM access_elements a '.$whereclause.' ORDER BY '.$sort.' LIMIT :page,:num_rows';
}
$stmt = $pdo->prepare($sql);
//------------------------------------------
//Bind to query
//------------------------------------------
if (!empty($criterias)){
foreach ($criterias as $key => $value){
$key_condition = ':'.$key;
if (str_contains($sql, $key_condition)){
if ($key == 'search'){
$search_value = '%'.$value.'%';
$stmt->bindValue($key, $search_value, PDO::PARAM_STR);
}
elseif ($key == 'p'){
//Do nothing (bug)
}
else {
$stmt->bindValue($key, $value, PDO::PARAM_STR);
}
}
}
}
//------------------------------------------
// Debuglog
//------------------------------------------
if (debug){
$message = $date.';'.$sql.';'.$username;
debuglog($message);
}
//------------------------------------------
//Add paging details
//------------------------------------------
$page_rows = $page_rows_equipment ?? 20;
if(isset($criterias['totals']) && $criterias['totals']==''){
$stmt->execute();
$messages = $stmt->fetch();
$messages = $messages[0];
}
elseif(isset($criterias['all']) && $criterias['all']==''){
//Return all records (no paging)
$stmt->execute();
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
else {
$current_page = isset($criterias['p']) && is_numeric($criterias['p']) ? (int)$criterias['p'] : 1;
$stmt->bindValue('page', ($current_page - 1) * $page_rows, PDO::PARAM_INT);
$stmt->bindValue('num_rows', $page_rows, PDO::PARAM_INT);
//Execute Query
$stmt->execute();
//Get results
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//------------------------------------------
//JSON_EnCODE
//------------------------------------------
$messages = json_encode($messages, JSON_UNESCAPED_UNICODE);
//------------------------------------------
//Send results
//------------------------------------------
echo $messages;
?>

View File

@@ -12,7 +12,7 @@ $pdo = dbConnect($dbname);
if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}
//default whereclause
list($whereclause,$condition) = getWhereclauselvl2("software_upgrade_paths",$permission,$partner,'get');
list($whereclause,$condition) = getWhereclauselvl2("",$permission,$partner,'get');
//NEW ARRAY
$criterias = [];

View File

@@ -12,7 +12,7 @@ $pdo = dbConnect($dbname);
if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}
//default whereclause
list($whereclause,$condition) = getWhereclauselvl2("software_versions",$permission,$partner,'get');
list($whereclause,$condition) = getWhereclauselvl2("",$permission,$partner,'get');
//NEW ARRAY
$criterias = [];

View File

@@ -0,0 +1,152 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// Report Builder - GET Endpoints
//------------------------------------------
// Set content type to JSON
header('Content-Type: application/json');
// Connect to DB
$pdo = dbConnect($dbname);
// Get the action parameter from URL
$criterias = [];
if (isset($get_content) && $get_content != '') {
$requests = explode("&", $get_content);
foreach ($requests as $y) {
$v = explode("=", $y);
if (isset($v[1])) {
$criterias[$v[0]] = urldecode($v[1]);
} else {
$criterias[$v[0]] = '';
}
}
}
$action = strtolower($criterias['action'] ?? '');
/**
* Validate table name - only allow alphanumeric, underscores, hyphens
*/
function sanitizeTableName($table) {
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $table)) {
return false;
}
return $table;
}
/**
* Get list of tables
*/
if ($action === 'gettables') {
try {
$result = $pdo->query("SHOW TABLES");
$tables = [];
while ($row = $result->fetch(PDO::FETCH_NUM)) {
$tables[] = $row[0];
}
$messages = json_encode([
'success' => true,
'tables' => $tables
], JSON_UNESCAPED_UNICODE);
} catch (Exception $e) {
http_response_code(500);
$messages = json_encode([
'success' => false,
'message' => 'Failed to fetch tables'
], JSON_UNESCAPED_UNICODE);
}
}
/**
* Get columns for a specific table
*/
elseif ($action === 'getcolumns') {
$table = sanitizeTableName($criterias['table'] ?? '');
if (!$table) {
http_response_code(400);
$messages = json_encode([
'success' => false,
'message' => 'Invalid table name'
], JSON_UNESCAPED_UNICODE);
} else {
try {
$result = $pdo->query("SHOW COLUMNS FROM `$table`");
$columns = [];
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
$columns[] = $row['Field'];
}
$messages = json_encode([
'success' => true,
'columns' => $columns
], JSON_UNESCAPED_UNICODE);
} catch (Exception $e) {
http_response_code(500);
$messages = json_encode([
'success' => false,
'message' => 'Failed to fetch columns'
], JSON_UNESCAPED_UNICODE);
}
}
}
/**
* Get table schema information
*/
elseif ($action === 'gettableschema') {
$table = sanitizeTableName($criterias['table'] ?? '');
if (!$table) {
http_response_code(400);
$messages = json_encode([
'success' => false,
'message' => 'Invalid table name'
], JSON_UNESCAPED_UNICODE);
} else {
try {
$result = $pdo->query("DESCRIBE `$table`");
$schema = [];
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
$schema[] = [
'field' => $row['Field'],
'type' => $row['Type'],
'null' => $row['Null'],
'key' => $row['Key'],
'default' => $row['Default'],
'extra' => $row['Extra']
];
}
$messages = json_encode([
'success' => true,
'schema' => $schema
], JSON_UNESCAPED_UNICODE);
} catch (Exception $e) {
http_response_code(500);
$messages = json_encode([
'success' => false,
'message' => 'Failed to fetch table schema'
], JSON_UNESCAPED_UNICODE);
}
}
}
/**
* Invalid or missing action
*/
else {
http_response_code(400);
$messages = json_encode([
'success' => false,
'message' => 'Invalid or missing action parameter'
], JSON_UNESCAPED_UNICODE);
}
// Send results
echo $messages;
?>

View File

@@ -0,0 +1,123 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// Role Access Permissions
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//------------------------------------------
//NEW ARRAY
//------------------------------------------
$criterias = [];
$clause = '';
//------------------------------------------
//Check for $_GET variables and build up clause
//------------------------------------------
if(isset($get_content) && $get_content!=''){
//GET VARIABLES FROM URL
$requests = explode("&", $get_content);
//Check for keys and values
foreach ($requests as $y){
$v = explode("=", $y);
//INCLUDE VARIABLES IN ARRAY
$criterias[$v[0]] = $v[1];
if ($v[0] == 'page' || $v[0] =='p' || $v[0] =='totals' || $v[0] =='success_msg'){
//do nothing
}
elseif ($v[0] == 'rowid') {
//build up search by ID
$clause .= ' AND rap.rowID = :'.$v[0];
}
elseif ($v[0] == 'role_id') {
//build up search by role_id
$clause .= ' AND rap.role_id = :'.$v[0];
}
elseif ($v[0] == 'access_id') {
//build up search by access_id
$clause .= ' AND rap.access_id = :'.$v[0];
}
else {
//create clause
$clause .= ' AND rap.'.$v[0].' = :'.$v[0];
}
}
}
//Build WHERE clause
$whereclause = '';
if ($clause != ''){
$whereclause = 'WHERE '.substr($clause, 4);
}
if (isset($criterias['totals']) && $criterias['totals'] ==''){
//Request for total rows
$sql = 'SELECT count(*) as count FROM role_access_permissions rap '.$whereclause;
}
else {
//SQL with joined tables for names
$sql = 'SELECT rap.*,
r.name as role_name,
ae.access_name,
ae.access_path
FROM role_access_permissions rap
LEFT JOIN user_roles r ON rap.role_id = r.rowID
LEFT JOIN access_elements ae ON rap.access_id = ae.rowID
'.$whereclause.'
ORDER BY ae.access_name ASC';
}
$stmt = $pdo->prepare($sql);
//------------------------------------------
//Bind to query
//------------------------------------------
if (!empty($criterias)){
foreach ($criterias as $key => $value){
$key_condition = ':'.$key;
if (str_contains($sql, $key_condition)){
if ($key == 'p'){
//Do nothing (bug)
}
else {
$stmt->bindValue($key, $value, PDO::PARAM_STR);
}
}
}
}
//------------------------------------------
// Debuglog
//------------------------------------------
if (debug){
$message = $date.';'.$sql.';'.$username;
debuglog($message);
}
//------------------------------------------
//Execute Query
//------------------------------------------
if(isset($criterias['totals']) && $criterias['totals']==''){
$stmt->execute();
$messages = $stmt->fetch();
$messages = $messages[0];
}
else {
//Execute Query
$stmt->execute();
//Get results
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//------------------------------------------
//JSON_EnCODE
//------------------------------------------
$messages = json_encode($messages, JSON_UNESCAPED_UNICODE);
//------------------------------------------
//Send results
//------------------------------------------
echo $messages;
?>

View File

@@ -55,17 +55,20 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
}
//GET EQUIPMENT AND PRODUCT DATA BASED ON SERIAL NUMBER
$sql = 'SELECT
$sql = "SELECT
p.rowID as product_rowid,
p.productcode,
e.sw_version as current_sw_version,
e.hw_version,
e.sw_version_license,
e.sw_version_upgrade,
e.rowID as equipment_rowid
e.rowID as equipment_rowid,
partner.*
FROM equipment e
JOIN products p ON e.productrowid = p.rowID
WHERE e.serialnumber = ?';
LEFT JOIN partner ON partner.partnerID = SUBSTRING_INDEX(JSON_UNQUOTE(JSON_EXTRACT(e.accounthierarchy, '$.soldto')), '-', 1)
AND partner.is_dealer = 1 AND partner.status = 1
WHERE e.serialnumber = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$criterias['sn']]);
$equipment_data = $stmt->fetch(PDO::FETCH_ASSOC);
@@ -81,6 +84,17 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
$sw_version_upgrade = $equipment_data['sw_version_upgrade'];
$equipment_rowid = $equipment_data['equipment_rowid'];
$dealer_info = [
'is_dealer' => $equipment_data['is_dealer'] ?? 0,
'name' => $equipment_data['name'] ?? '',
'address' => $equipment_data['address'] ?? '',
'city' => $equipment_data['city'] ?? '',
'postalcode' => $equipment_data['postalcode'] ?? '',
'country' => $equipment_data['country'] ?? '',
'email' => $equipment_data['email'] ?? '',
'phone' => $equipment_data['phone'] ?? ''
];
if (debug) {
$debug['equipment_data'] = [
'product_rowid' => $product_rowid,
@@ -402,7 +416,7 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
}
}
$output[] = [
$entry = [
"productcode" => $productcode,
"name" => $version['name'] ?? '',
"version" => $version['version'],
@@ -416,8 +430,11 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
"source_type" => '',
"price" => $final_price,
"currency" => $final_currency,
"is_current" => $is_current
"is_current" => $is_current,
"dealer_info" => $dealer_info
];
$output[] = $entry;
}
if (debug) {

View File

@@ -0,0 +1,128 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// User Role Assignments
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//------------------------------------------
//NEW ARRAY
//------------------------------------------
$criterias = [];
$clause = '';
//------------------------------------------
//Check for $_GET variables and build up clause
//------------------------------------------
if(isset($get_content) && $get_content!=''){
//GET VARIABLES FROM URL
$requests = explode("&", $get_content);
//Check for keys and values
foreach ($requests as $y){
$v = explode("=", $y);
//INCLUDE VARIABLES IN ARRAY
$criterias[$v[0]] = $v[1];
if ($v[0] == 'page' || $v[0] =='p' || $v[0] =='totals' || $v[0] =='success_msg'){
//do nothing
}
elseif ($v[0] == 'rowid') {
//build up search by ID
$clause .= ' AND ura.rowID = :'.$v[0];
}
elseif ($v[0] == 'role_id') {
//build up search by role_id
$clause .= ' AND ura.role_id = :'.$v[0];
}
elseif ($v[0] == 'user_id') {
//build up search by user_id
$clause .= ' AND ura.user_id = :'.$v[0];
}
elseif ($v[0] == 'status') {
//Update status based on status
$clause .= ' AND ura.is_active = :'.$v[0];
}
else {
//create clause
$clause .= ' AND ura.'.$v[0].' = :'.$v[0];
}
}
}
//Build WHERE clause
$whereclause = '';
if ($clause != ''){
$whereclause = 'WHERE '.substr($clause, 4);
}
if (isset($criterias['totals']) && $criterias['totals'] ==''){
//Request for total rows
$sql = 'SELECT count(*) as count FROM user_role_assignments ura '.$whereclause;
}
else {
//SQL with joined tables for names
$sql = 'SELECT ura.*,
u.username,
u.email,
r.name as role_name,
r.description as role_description
FROM user_role_assignments ura
LEFT JOIN users u ON ura.user_id = u.id
LEFT JOIN user_roles r ON ura.role_id = r.rowID
'.$whereclause.'
ORDER BY u.username ASC';
}
$stmt = $pdo->prepare($sql);
//------------------------------------------
//Bind to query
//------------------------------------------
if (!empty($criterias)){
foreach ($criterias as $key => $value){
$key_condition = ':'.$key;
if (str_contains($sql, $key_condition)){
if ($key == 'p'){
//Do nothing (bug)
}
else {
$stmt->bindValue($key, $value, PDO::PARAM_STR);
}
}
}
}
//------------------------------------------
// Debuglog
//------------------------------------------
if (debug){
$message = $date.';'.$sql.';'.$username;
debuglog($message);
}
//------------------------------------------
//Execute Query
//------------------------------------------
if(isset($criterias['totals']) && $criterias['totals']==''){
$stmt->execute();
$messages = $stmt->fetch();
$messages = $messages[0];
}
else {
//Execute Query
$stmt->execute();
//Get results
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//------------------------------------------
//JSON_EnCODE
//------------------------------------------
$messages = json_encode($messages, JSON_UNESCAPED_UNICODE);
//------------------------------------------
//Send results
//------------------------------------------
echo $messages;
?>

151
api/v2/get/user_roles.php Normal file
View File

@@ -0,0 +1,151 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// User Roles
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//------------------------------------------
//NEW ARRAY
//------------------------------------------
$criterias = [];
$clause = '';
//------------------------------------------
//Check for $_GET variables and build up clause
//------------------------------------------
if(isset($get_content) && $get_content!=''){
//GET VARIABLES FROM URL
$requests = explode("&", $get_content);
//Check for keys and values
foreach ($requests as $y){
$v = explode("=", $y);
//INCLUDE VARIABLES IN ARRAY
$criterias[$v[0]] = $v[1];
if ($v[0] == 'page' || $v[0] =='p' || $v[0] =='totals' || $v[0] =='success_msg' || $v[0] =='sort'){
//do nothing
}
elseif ($v[0] == 'rowid') {
//build up search by ID
$clause .= ' AND r.rowID = :'.$v[0];
}
elseif ($v[0] == 'status') {
//Update status based on status
$clause .= ' AND r.is_active = :'.$v[0];
}
elseif ($v[0] == 'search') {
//build up search
$clause .= ' AND (r.name LIKE :'.$v[0].' OR r.description LIKE :'.$v[0].')';
}
elseif ($v[0] == 'name') {
//build up name search
$clause .= ' AND r.name = :'.$v[0];
}
else {
//create clause
$clause .= ' AND r.'.$v[0].' = :'.$v[0];
}
}
}
//Build WHERE clause
$whereclause = '';
if ($clause != ''){
$whereclause = 'WHERE '.substr($clause, 4);
}
// GET SORT INDICATOR
$sort_indicator = $criterias['sort'] ?? '';
switch ($sort_indicator){
case 1:
$sort = ' r.name ASC ';
break;
case 2:
$sort = ' r.name DESC ';
break;
case 3:
$sort = ' r.created ASC ';
break;
case 4:
$sort = ' r.created DESC ';
break;
default:
$sort = ' r.rowID ';
break;
}
if (isset($criterias['totals']) && $criterias['totals'] ==''){
//Request for total rows
$sql = 'SELECT count(*) as count FROM user_roles r '.$whereclause;
}
else {
//SQL with permission count
$sql = 'SELECT r.*,
(SELECT COUNT(*) FROM role_access_permissions WHERE role_id = r.rowID) as permission_count
FROM user_roles r '.$whereclause.' ORDER BY '.$sort.' LIMIT :page,:num_rows';
}
$stmt = $pdo->prepare($sql);
//------------------------------------------
//Bind to query
//------------------------------------------
if (!empty($criterias)){
foreach ($criterias as $key => $value){
$key_condition = ':'.$key;
if (str_contains($sql, $key_condition)){
if ($key == 'search'){
$search_value = '%'.$value.'%';
$stmt->bindValue($key, $search_value, PDO::PARAM_STR);
}
elseif ($key == 'p'){
//Do nothing (bug)
}
else {
$stmt->bindValue($key, $value, PDO::PARAM_STR);
}
}
}
}
//------------------------------------------
// Debuglog
//------------------------------------------
if (debug){
$message = $date.';'.$sql.';'.$username;
debuglog($message);
}
//------------------------------------------
//Add paging details
//------------------------------------------
$page_rows = $page_rows_equipment ?? 20;
if(isset($criterias['totals']) && $criterias['totals']==''){
$stmt->execute();
$messages = $stmt->fetch();
$messages = $messages[0];
}
else {
$current_page = isset($criterias['p']) && is_numeric($criterias['p']) ? (int)$criterias['p'] : 1;
$stmt->bindValue('page', ($current_page - 1) * $page_rows, PDO::PARAM_INT);
$stmt->bindValue('num_rows', $page_rows, PDO::PARAM_INT);
//Execute Query
$stmt->execute();
//Get results
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//------------------------------------------
//JSON_EnCODE
//------------------------------------------
$messages = json_encode($messages, JSON_UNESCAPED_UNICODE);
//------------------------------------------
//Send results
//------------------------------------------
echo $messages;
?>

View File

@@ -0,0 +1,79 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// Access Elements
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//CONTENT FROM API (POST)
$post_content = json_decode($input,true);
//SET PARAMETERS FOR QUERY
$id = $post_content['rowID'] ?? '';
$command = ($id == '')? 'insert' : 'update';
if (isset($post_content['delete'])){$command = 'delete';}
$date = date('Y-m-d H:i:s');
//CREATE EMPTY STRINGS
$clause = '';
$clause_insert ='';
$input_insert = '';
$execute_input = [];
$criterias = [];
//ADD STANDARD PARAMETERS TO ARRAY BASED ON INSERT OR UPDATE
if ($command == 'update'){
$post_content['updatedby'] = $username;;
$post_content['updated'] = $date;
}
elseif ($command == 'insert'){
$post_content['created'] = $date;
$post_content['createdby'] = $username;;
}
//CREAT NEW ARRAY AND MAP TO CLAUSE
if(isset($post_content) && $post_content!=''){
foreach ($post_content as $key => $var){
if ($key == 'submit' || $key == 'rowID' || str_contains($key, 'old_')){
//do nothing
}
else {
$criterias[$key] = $var;
$clause .= ' , '.$key.' = ?';
$clause_insert .= ' , '.$key.'';
$input_insert .= ', ?';
$execute_input[]= $var;
}
}
}
//CLEAN UP INPUT
$clause = substr($clause, 2);
$clause_insert = substr($clause_insert, 2);
$input_insert = substr($input_insert, 1);
//QUERY AND VERIFY ALLOWED
if ($command == 'update' && isAllowed('access_element_manage',$profile,$permission,'U') === 1){
$sql = 'UPDATE access_elements SET '.$clause.' WHERE rowID = ?';
$execute_input[] = $id;
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
}
elseif ($command == 'insert' && isAllowed('access_element_manage',$profile,$permission,'C') === 1){
$sql = 'INSERT INTO access_elements ('.$clause_insert.') VALUES ('.$input_insert.')';
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
}
elseif ($command == 'delete' && isAllowed('access_element_manage',$profile,$permission,'D') === 1){
//Delete role permissions using this access element first (foreign key constraint)
$stmt = $pdo->prepare('DELETE FROM role_access_permissions WHERE access_id = ?');
$stmt->execute([$id]);
//Delete access element
$stmt = $pdo->prepare('DELETE FROM access_elements WHERE rowID = ?');
$stmt->execute([$id]);
}
?>

View File

@@ -0,0 +1,124 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// Report Builder - POST Endpoints
//------------------------------------------
// Set content type to JSON
header('Content-Type: application/json');
// Connect to DB
$pdo = dbConnect($dbname);
// Parse input data
$data = json_decode($input, true);
$action = strtolower($data['action'] ?? '');
/**
* Security check: Only allow SELECT queries
*/
function isSelectQuery($query) {
$query = trim($query);
$query = preg_replace('/\s+/', ' ', $query); // Normalize whitespace
// Only allow SELECT queries
if (!preg_match('/^SELECT\s/i', $query)) {
return false;
}
// Block dangerous keywords that could be used for injection
$dangerousPatterns = [
'/;\s*DROP\s/i',
'/;\s*DELETE\s/i',
'/;\s*UPDATE\s/i',
'/;\s*INSERT\s/i',
'/;\s*CREATE\s/i',
'/;\s*ALTER\s/i',
'/;\s*TRUNCATE\s/i',
'/INTO\s+OUTFILE\s/i',
'/LOAD_FILE\s*\(/i',
'/SLEEP\s*\(/i',
'/BENCHMARK\s*\(/i',
];
foreach ($dangerousPatterns as $pattern) {
if (preg_match($pattern, $query)) {
return false;
}
}
return true;
}
/**
* Execute a SELECT query
*/
if ($action === 'executequery') {
$query = $data['query'] ?? '';
if (empty($query)) {
http_response_code(400);
$messages = json_encode([
'success' => false,
'message' => 'Query parameter is required'
], JSON_UNESCAPED_UNICODE);
}
// Security check: only allow SELECT queries
elseif (!isSelectQuery($query)) {
http_response_code(400);
$messages = json_encode([
'success' => false,
'message' => 'Only SELECT queries are allowed'
], JSON_UNESCAPED_UNICODE);
} else {
try {
// Execute the query
$stmt = $pdo->query($query);
// Fetch all results
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Get row count
$rowCount = count($results);
// Limit results to prevent memory issues
$maxResults = 5000;
if ($rowCount > $maxResults) {
$results = array_slice($results, 0, $maxResults);
$message = "Query executed successfully. Showing first $maxResults of $rowCount rows.";
} else {
$message = "Query executed successfully. $rowCount rows returned.";
}
$messages = json_encode([
'success' => true,
'results' => $results,
'rowCount' => $rowCount,
'message' => $message
], JSON_UNESCAPED_UNICODE);
} catch (PDOException $e) {
http_response_code(400);
$messages = json_encode([
'success' => false,
'message' => 'Query execution failed: ' . $e->getMessage()
], JSON_UNESCAPED_UNICODE);
}
}
}
/**
* Invalid or missing action
*/
else {
http_response_code(400);
$messages = json_encode([
'success' => false,
'message' => 'Invalid or missing action parameter'
], JSON_UNESCAPED_UNICODE);
}
// Send results
echo $messages;
?>

View File

@@ -0,0 +1,75 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// Role Access Permissions
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//CONTENT FROM API (POST)
$post_content = json_decode($input,true);
//SET PARAMETERS FOR QUERY
$id = $post_content['rowID'] ?? '';
$command = ($id == '')? 'insert' : 'update';
if (isset($post_content['delete'])){$command = 'delete';}
$date = date('Y-m-d H:i:s');
//CREATE EMPTY STRINGS
$clause = '';
$clause_insert ='';
$input_insert = '';
$execute_input = [];
$criterias = [];
//ADD STANDARD PARAMETERS TO ARRAY BASED ON INSERT OR UPDATE
if ($command == 'update'){
$post_content['updatedby'] = $username;;
$post_content['updated'] = $date;
}
elseif ($command == 'insert'){
$post_content['created'] = $date;
$post_content['createdby'] = $username;;
}
//CREAT NEW ARRAY AND MAP TO CLAUSE
if(isset($post_content) && $post_content!=''){
foreach ($post_content as $key => $var){
if ($key == 'submit' || $key == 'rowID' || str_contains($key, 'old_')){
//do nothing
}
else {
$criterias[$key] = $var;
$clause .= ' , '.$key.' = ?';
$clause_insert .= ' , '.$key.'';
$input_insert .= ', ?';
$execute_input[]= $var;
}
}
}
//CLEAN UP INPUT
$clause = substr($clause, 2);
$clause_insert = substr($clause_insert, 2);
$input_insert = substr($input_insert, 1);
//QUERY AND VERIFY ALLOWED
if ($command == 'update' && isAllowed('user_role_manage',$profile,$permission,'U') === 1){
$sql = 'UPDATE role_access_permissions SET '.$clause.' WHERE rowID = ?';
$execute_input[] = $id;
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
}
elseif ($command == 'insert' && isAllowed('user_role_manage',$profile,$permission,'C') === 1){
$sql = 'INSERT INTO role_access_permissions ('.$clause_insert.') VALUES ('.$input_insert.')';
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
}
elseif ($command == 'delete' && isAllowed('user_role_manage',$profile,$permission,'D') === 1){
//Delete permission
$stmt = $pdo->prepare('DELETE FROM role_access_permissions WHERE rowID = ?');
$stmt->execute([$id]);
}
?>

View File

@@ -0,0 +1,141 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// User Role Assignments
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//CONTENT FROM API (POST)
$post_content = json_decode($input,true);
//SET PARAMETERS FOR QUERY
$id = $post_content['rowID'] ?? '';
$date = date('Y-m-d H:i:s');
//------------------------------------------
// BATCH UPDATE - Update all roles for a user
//------------------------------------------
if (isset($post_content['batch_update']) && isset($post_content['user_id']) && isAllowed('user_manage',$profile,$permission,'U') === 1){
$user_id = $post_content['user_id'];
$selected_roles = $post_content['roles'] ?? [];
//Get currently assigned active roles
$stmt = $pdo->prepare('SELECT role_id, rowID FROM user_role_assignments WHERE user_id = ? AND is_active = 1');
$stmt->execute([$user_id]);
$current_roles = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$current_roles[$row['role_id']] = $row['rowID'];
}
//Remove roles that are no longer selected (soft delete)
foreach ($current_roles as $role_id => $assignment_id){
if (!in_array($role_id, $selected_roles)){
$stmt = $pdo->prepare('UPDATE user_role_assignments SET is_active = 0, updatedby = ?, updated = ? WHERE rowID = ?');
$stmt->execute([$username, $date, $assignment_id]);
}
}
//Add new roles that are selected but not currently assigned
foreach ($selected_roles as $role_id){
if (!array_key_exists($role_id, $current_roles)){
//Check if this user-role combination existed before (inactive)
$stmt = $pdo->prepare('SELECT rowID FROM user_role_assignments WHERE user_id = ? AND role_id = ? AND is_active = 0 LIMIT 1');
$stmt->execute([$user_id, $role_id]);
$existing = $stmt->fetch(PDO::FETCH_ASSOC);
if ($existing){
//Reactivate existing assignment
$stmt = $pdo->prepare('UPDATE user_role_assignments SET is_active = 1, assigned_by = ?, assigned_at = ?, updatedby = ?, updated = ? WHERE rowID = ?');
$stmt->execute([$username, $date, $username, $date, $existing['rowID']]);
} else {
//Create new assignment
$stmt = $pdo->prepare('INSERT INTO user_role_assignments (user_id, role_id, is_active, assigned_by, assigned_at, created, createdby) VALUES (?, ?, 1, ?, ?, ?, ?)');
$stmt->execute([$user_id, $role_id, $username, $date, $date, $userkey]);
}
}
}
}
//------------------------------------------
// SINGLE OPERATIONS (for backward compatibility or direct API calls)
//------------------------------------------
else {
$command = ($id == '')? 'insert' : 'update';
if (isset($post_content['delete'])){$command = 'delete';}
//CREATE EMPTY STRINGS
$clause = '';
$clause_insert ='';
$input_insert = '';
$execute_input = [];
$criterias = [];
//ADD STANDARD PARAMETERS TO ARRAY BASED ON INSERT OR UPDATE
if ($command == 'update'){
$post_content['updatedby'] = $username;
$post_content['updated'] = $date;
}
elseif ($command == 'insert'){
$post_content['created'] = $date;
$post_content['createdby'] = $username;
$post_content['assigned_by'] = $username;
$post_content['assigned_at'] = $date;
}
//CREAT NEW ARRAY AND MAP TO CLAUSE
if(isset($post_content) && $post_content!=''){
foreach ($post_content as $key => $var){
if ($key == 'submit' || $key == 'rowID' || $key == 'delete' || $key == 'batch_update' || str_contains($key, 'old_')){
//do nothing
}
else {
$criterias[$key] = $var;
$clause .= ' , '.$key.' = ?';
$clause_insert .= ' , '.$key.'';
$input_insert .= ', ?';
$execute_input[]= $var;
}
}
}
//CLEAN UP INPUT
$clause = substr($clause, 2);
$clause_insert = substr($clause_insert, 2);
$input_insert = substr($input_insert, 1);
//QUERY AND VERIFY ALLOWED
if ($command == 'update' && isAllowed('user_manage',$profile,$permission,'U') === 1){
$sql = 'UPDATE user_role_assignments SET '.$clause.' WHERE rowID = ?';
$execute_input[] = $id;
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
}
elseif ($command == 'insert' && isAllowed('user_manage',$profile,$permission,'C') === 1){
//Check if this user-role combination already exists (including inactive ones)
$stmt = $pdo->prepare('SELECT rowID, is_active FROM user_role_assignments WHERE user_id = ? AND role_id = ? LIMIT 1');
$stmt->execute([$post_content['user_id'], $post_content['role_id']]);
$existing = $stmt->fetch(PDO::FETCH_ASSOC);
if ($existing){
//If exists but inactive, reactivate it
if ($existing['is_active'] == 0){
$stmt = $pdo->prepare('UPDATE user_role_assignments SET is_active = 1, assigned_by = ?, assigned_at = ?, updatedby = ?, updated = ? WHERE rowID = ?');
$stmt->execute([$username, $date, $username, $date, $existing['rowID']]);
}
//If already active, do nothing (or could throw an error)
} else {
//Insert new assignment
$sql = 'INSERT INTO user_role_assignments ('.$clause_insert.') VALUES ('.$input_insert.')';
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
}
}
elseif ($command == 'delete' && isAllowed('user_manage',$profile,$permission,'D') === 1){
//Soft delete by setting is_active to 0
$stmt = $pdo->prepare('UPDATE user_role_assignments SET is_active = 0, updatedby = ?, updated = ? WHERE rowID = ?');
$stmt->execute([$username, $date, $id]);
}
}
?>

123
api/v2/post/user_roles.php Normal file
View File

@@ -0,0 +1,123 @@
<?php
defined($security_key) or exit;
//------------------------------------------
// User Roles
//------------------------------------------
//Connect to DB
$pdo = dbConnect($dbname);
//CONTENT FROM API (POST)
$post_content = json_decode($input,true);
//SET PARAMETERS FOR QUERY
$id = $post_content['rowID'] ?? '';
$command = ($id == '')? 'insert' : 'update';
if (isset($post_content['delete'])){$command = 'delete';}
$date = date('Y-m-d H:i:s');
//CREATE EMPTY STRINGS
$clause = '';
$clause_insert ='';
$input_insert = '';
$execute_input = [];
$criterias = [];
//ADD STANDARD PARAMETERS TO ARRAY BASED ON INSERT OR UPDATE
if ($command == 'update'){
$post_content['updatedby'] = $username;
$post_content['updated'] = $date;
}
elseif ($command == 'insert'){
$post_content['created'] = $date;
$post_content['createdby'] = $username;
}
//CREAT NEW ARRAY AND MAP TO CLAUSE
if(isset($post_content) && $post_content!=''){
foreach ($post_content as $key => $var){
if ($key == 'submit' || $key == 'rowID' || $key == 'permissions' || str_contains($key, 'old_')){
//do nothing
}
else {
$criterias[$key] = $var;
$clause .= ' , '.$key.' = ?';
$clause_insert .= ' , '.$key.'';
$input_insert .= ', ?';
$execute_input[]= $var;
}
}
}
//CLEAN UP INPUT
$clause = substr($clause, 2);
$clause_insert = substr($clause_insert, 2);
$input_insert = substr($input_insert, 1);
//QUERY AND VERIFY ALLOWED
if ($command == 'update' && isAllowed('user_role_manage',$profile,$permission,'U') === 1){
$sql = 'UPDATE user_roles SET '.$clause.' WHERE rowID = ?';
$execute_input[] = $id;
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
//Handle permissions update
if (isset($post_content['permissions'])){
//First delete all existing permissions for this role
$stmt = $pdo->prepare('DELETE FROM role_access_permissions WHERE role_id = ?');
$stmt->execute([$id]);
//Insert new permissions
foreach ($post_content['permissions'] as $access_id => $perms){
$can_create = isset($perms['can_create']) ? 1 : 0;
$can_read = isset($perms['can_read']) ? 1 : 0;
$can_update = isset($perms['can_update']) ? 1 : 0;
$can_delete = isset($perms['can_delete']) ? 1 : 0;
//Only insert if at least one permission is set
if ($can_create || $can_read || $can_update || $can_delete){
$stmt = $pdo->prepare('INSERT INTO role_access_permissions (role_id, access_id, can_create, can_read, can_update, can_delete, created, createdby) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
$stmt->execute([$id, $access_id, $can_create, $can_read, $can_update, $can_delete, $date, $userkey]);
}
}
}
}
elseif ($command == 'insert' && isAllowed('user_role_manage',$profile,$permission,'C') === 1){
$sql = 'INSERT INTO user_roles ('.$clause_insert.') VALUES ('.$input_insert.')';
$stmt = $pdo->prepare($sql);
$stmt->execute($execute_input);
//Get the new role ID
$new_role_id = $pdo->lastInsertId();
//Handle permissions for new role
if (isset($post_content['permissions'])){
foreach ($post_content['permissions'] as $access_id => $perms){
$can_create = isset($perms['can_create']) ? 1 : 0;
$can_read = isset($perms['can_read']) ? 1 : 0;
$can_update = isset($perms['can_update']) ? 1 : 0;
$can_delete = isset($perms['can_delete']) ? 1 : 0;
//Only insert if at least one permission is set
if ($can_create || $can_read || $can_update || $can_delete){
$stmt = $pdo->prepare('INSERT INTO role_access_permissions (role_id, access_id, can_create, can_read, can_update, can_delete, created, createdby) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
$stmt->execute([$new_role_id, $access_id, $can_create, $can_read, $can_update, $can_delete, $date, $userkey]);
}
}
}
}
elseif ($command == 'delete' && isAllowed('user_role_manage',$profile,$permission,'D') === 1){
//Delete role permissions first (foreign key constraint)
$stmt = $pdo->prepare('DELETE FROM role_access_permissions WHERE role_id = ?');
$stmt->execute([$id]);
//Delete user role assignments
$stmt = $pdo->prepare('DELETE FROM user_role_assignments WHERE role_id = ?');
$stmt->execute([$id]);
//Delete role
$stmt = $pdo->prepare('DELETE FROM user_roles WHERE rowID = ?');
$stmt->execute([$id]);
}
?>

View File

@@ -44,10 +44,11 @@ $user_name_old = $user_data['username'];
$view_old = $user_data['view'];
$partnerhierarchy_old = json_decode($user_data['partnerhierarchy']);
$salesid_new = ((isset($post_content['salesid']) && $post_content['salesid'] != '' && $post_content['salesid'] != $partnerhierarchy_old->salesid)? $post_content['salesid'] : $partnerhierarchy_old->salesid);
$soldto_new = ((isset($post_content['soldto']) && $post_content['soldto'] != '' && $post_content['soldto'] != $partnerhierarchy_old->soldto)? $post_content['soldto'] : $partnerhierarchy_old->soldto);
$shipto_new = ((isset($post_content['shipto']) && $post_content['shipto'] != '' && $post_content['shipto'] != $partnerhierarchy_old->shipto)? $post_content['shipto'] : $partnerhierarchy_old->shipto);
$location_new = ((isset($post_content['location']) && $post_content['location'] != '' && $post_content['location'] != $partnerhierarchy_old->location)? $post_content['location'] : $partnerhierarchy_old->location);
// Allow clearing values by checking if key exists (even if empty)
$salesid_new = (array_key_exists('salesid', $post_content)) ? $post_content['salesid'] : ($partnerhierarchy_old->salesid ?? '');
$soldto_new = (array_key_exists('soldto', $post_content)) ? $post_content['soldto'] : ($partnerhierarchy_old->soldto ?? '');
$shipto_new = (array_key_exists('shipto', $post_content)) ? $post_content['shipto'] : ($partnerhierarchy_old->shipto ?? '');
$location_new = (array_key_exists('location', $post_content)) ? $post_content['location'] : ($partnerhierarchy_old->location ?? '');
if ($permission == 4){
//ADMIN+ ONLY ARE ALLOWED TO CHANGE SALES AND SOLD

BIN
assets/.DS_Store vendored

Binary file not shown.

65
assets/database/user_rbac Normal file
View File

@@ -0,0 +1,65 @@
CREATE TABLE `user_roles` (
`rowID` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`description` text DEFAULT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT 1,
`created` timestamp NULL DEFAULT current_timestamp(),
`createdby` int(11) DEFAULT NULL,
`updated` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`updatedby` int(11) DEFAULT NULL,
PRIMARY KEY (`rowID`),
UNIQUE KEY `unique_role_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `user_role_assignments` (
`rowID` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT 1,
`assigned_by` varchar(255) DEFAULT NULL,
`assigned_at` timestamp NULL DEFAULT current_timestamp(),
`expires_at` timestamp NULL DEFAULT NULL,
`created` timestamp NULL DEFAULT current_timestamp(),
`createdby` int(11) DEFAULT NULL,
`updated` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`updatedby` int(11) DEFAULT NULL,
PRIMARY KEY (`rowID`),
UNIQUE KEY `unique_user_role_active` (`user_id`,`role_id`,`is_active`),
KEY `role_id` (`role_id`),
CONSTRAINT `user_role_assignments_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`rowID`) ON DELETE CASCADE,
CONSTRAINT `user_role_assignments_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `user_roles` (`rowID`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
REATE TABLE `role_access_permissions` (
`rowID` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) NOT NULL,
`access_id` int(11) NOT NULL,
`can_create` tinyint(1) NOT NULL DEFAULT 0,
`can_read` tinyint(1) NOT NULL DEFAULT 1,
`can_update` tinyint(1) NOT NULL DEFAULT 0,
`can_delete` tinyint(1) NOT NULL DEFAULT 0,
`created` timestamp NULL DEFAULT current_timestamp(),
`createdby` int(11) DEFAULT NULL,
`updated` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`updatedby` int(11) DEFAULT NULL,
PRIMARY KEY (`rowID`),
UNIQUE KEY `unique_role_view` (`role_id`,`access_id`),
KEY `access_id` (`access_id`),
CONSTRAINT `role_view_permissions_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `user_roles` (`rowID`) ON DELETE CASCADE,
CONSTRAINT `role_view_permissions_ibfk_2` FOREIGN KEY (`access_id`) REFERENCES `system_views` (`rowID`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=112 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `access_elements` (
`rowID` int(11) NOT NULL AUTO_INCREMENT,
`access_group` varchar(100) NOT NULL,
`access_name` varchar(100) NOT NULL,
`access_path` varchar(255) NOT NULL,
`description` text DEFAULT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT 1,
`created` timestamp NULL DEFAULT current_timestamp(),
`createdby` int(11) DEFAULT NULL,
`updated` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`updatedby` int(11) DEFAULT NULL,
PRIMARY KEY (`rowID`),
UNIQUE KEY `unique_access_path` (`access_path`)
) ENGINE=InnoDB AUTO_INCREMENT=393 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

View File

@@ -1541,6 +1541,12 @@ function getProfile($profile, $permission){
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
function isAllowed($page,$profile,$permission,$action){
//++++++++++++++++
//OVERRIDE
//++++++++++++++++
return 1;
//++++++++++++++++
//Include settingsa
include dirname(__FILE__,2).'/settings/settings_redirector.php';
@@ -1573,13 +1579,17 @@ function getProfile($profile, $permission){
// Debug log
if(debug){
debuglog("isAllowed called: page=$page, permission=$permission, action=$action");
$test = "$date - isAllowed called: page=$page, permission=$permission, action=$action".PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/permission_log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}
// 1. Check always allowed
if (isset($always_allowed[$page]) && str_contains($always_allowed[$page], $action)) {
if(debug){
debuglog("Allowed by always_allowed");
$test = "$date - Allowed by always_allowed".PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/permission_log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}
return 1;
@@ -1593,13 +1603,18 @@ function getProfile($profile, $permission){
$page_access = str_contains($profile,$page) > 0 ? 1 : 0; //CHECK USER IS ALLOWED TO ACCESS PAGE
if(debug){
debuglog("user_permission=$user_permission, page_action=$page_action, page_access=$page_access");
$test = "$date - user_permission=$user_permission, page_action=$page_action, page_access=$page_access".PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/permission_log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}
// 2. Check user permissions (standard)
if ($page_access == 1 && $page_action == 1){
if(debug){
debuglog("Allowed by user permissions");
$test = "$date - Allowed by user permissions".PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/permission_log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}
return 1;
}
@@ -1609,11 +1624,15 @@ function getProfile($profile, $permission){
foreach ($group_permissions as $granting_page => $grants) {
if (str_contains($profile, $granting_page)) {
if(debug){
debuglog("Found granting_page: $granting_page");
$test = "$date - Found granting_page: $granting_page".PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/permission_log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}
if (isset($grants[$page]) && str_contains($grants[$page], $action)) {
if(debug){
debuglog("Allowed by group permissions");
$test = "$date - Allowed by group permissions".PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/permission_log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}
return 1;
}
@@ -1622,7 +1641,9 @@ function getProfile($profile, $permission){
}
if(debug){
debuglog("Not allowed");
$test = "$date - Not allowed".PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/permission_log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}
// Not allowed
return 0;
@@ -2866,7 +2887,7 @@ function uploadrequest($key){
//------------------------------------------
function debuglog($error){
include_once dirname(__FILE__,2).'/settings/config_redirector.php';
$test = $error.PHP_EOL;
$test = $error.PHP_EOL;
$filelocation = dirname(__FILE__,2).'/log/log_'.date('d').'.txt';
error_log($test, 3, $filelocation);
}

Binary file not shown.

View File

@@ -576,6 +576,8 @@ function displaySoftwareOptions(options) {
const price = parseFloat(option.price);
const isFree = price === 0;
const isCurrent = option.is_current === true || option.is_current === 1;
const dealerInfo = option.dealer_info || {};
const isDealer = dealerInfo.is_dealer === 1 || dealerInfo.is_dealer === '1';
// Create card with gradient background
const card = document.createElement("div");
@@ -680,75 +682,138 @@ function displaySoftwareOptions(options) {
margin-top: auto;
`;
const priceText = document.createElement("div");
priceText.style.cssText = `
font-size: ${isCurrent ? '18px' : '28px'};
font-weight: ${isCurrent ? '600' : '800'};
color: ${isCurrent ? '#6c757d' : (isFree ? '#04AA6D' : '#FF6B35')};
margin-bottom: 15px;
text-align: center;
letter-spacing: 0.5px;
`;
// Check if this is a dealer customer - show dealer contact info instead of price/buy button
if (isDealer && !isCurrent && !isFree) {
// Dealer info section - replaces price and buy button
const dealerSection = document.createElement("div");
dealerSection.style.cssText = `
background: linear-gradient(135deg, rgb(255, 107, 53) 0%, rgb(255, 69, 0) 100%);
border-radius: 4px;
padding: 15px;
text-align: center;
`;
if (isCurrent) {
priceText.innerHTML = '<i class="fa-solid fa-check-circle"></i> INSTALLED';
// Contact dealer message
const dealerMessage = document.createElement("div");
dealerMessage.style.cssText = `
color: white;
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
`;
dealerMessage.innerHTML = '<i class="fa-solid fa-handshake" style="margin-right: 8px;"></i>Contact your dealer for pricing and upgrade options';
dealerSection.appendChild(dealerMessage);
// Dealer contact details
const dealerDetails = document.createElement("div");
dealerDetails.style.cssText = `
background: white;
border-radius: 4px;
padding: 12px;
text-align: left;
font-size: 13px;
color: #333;
`;
let dealerHtml = '';
if (dealerInfo.name) {
dealerHtml += `<div style="font-weight: 600; margin-bottom: 8px; color: #1565c0;"><i class="fa-solid fa-building" style="margin-right: 8px; width: 16px;"></i>${dealerInfo.name}</div>`;
}
if (dealerInfo.address || dealerInfo.city || dealerInfo.postalcode || dealerInfo.country) {
dealerHtml += `<div style="margin-bottom: 6px; color: #666; display: flex; align-items: flex-start;"><i class="fa-solid fa-location-dot" style="margin-right: 8px; width: 16px; color: #999; margin-top: 2px;"></i><div>`;
if (dealerInfo.address) {
dealerHtml += `<div>${dealerInfo.address}</div>`;
}
if (dealerInfo.postalcode || dealerInfo.city) {
dealerHtml += `<div>${[dealerInfo.postalcode, dealerInfo.city].filter(Boolean).join(' ')}</div>`;
}
if (dealerInfo.country) {
dealerHtml += `<div>${dealerInfo.country}</div>`;
}
dealerHtml += `</div></div>`;
}
if (dealerInfo.email) {
dealerHtml += `<div style="margin-bottom: 6px;"><i class="fa-solid fa-envelope" style="margin-right: 8px; width: 16px; color: #999;"></i><a href="mailto:${dealerInfo.email}" style="color: #1565c0; text-decoration: none;">${dealerInfo.email}</a></div>`;
}
if (dealerInfo.phone) {
dealerHtml += `<div><i class="fa-solid fa-phone" style="margin-right: 8px; width: 16px; color: #999;"></i><a href="tel:${dealerInfo.phone}" style="color: #1565c0; text-decoration: none;">${dealerInfo.phone}</a></div>`;
}
dealerDetails.innerHTML = dealerHtml;
dealerSection.appendChild(dealerDetails);
priceSection.appendChild(dealerSection);
} else {
priceText.innerHTML = isFree
? 'Free'
: `${option.currency || "€"} ${price.toFixed(2)} <small style="font-size: 12px; font-weight: 400; color: #888;">(excl. VAT)</small>`;
// Standard price display for non-dealer customers
const priceText = document.createElement("div");
priceText.style.cssText = `
font-size: ${isCurrent ? '18px' : '28px'};
font-weight: ${isCurrent ? '600' : '800'};
color: ${isCurrent ? '#6c757d' : (isFree ? '#04AA6D' : '#FF6B35')};
margin-bottom: 15px;
text-align: center;
letter-spacing: 0.5px;
`;
if (isCurrent) {
priceText.innerHTML = '<i class="fa-solid fa-check-circle"></i> INSTALLED';
} else {
priceText.innerHTML = isFree
? 'Free'
: `${option.currency || "€"} ${price.toFixed(2)} <small style="font-size: 12px; font-weight: 400; color: #888;">(excl. VAT)</small>`;
}
priceSection.appendChild(priceText);
// Action button with gradient for paid
const actionBtn = document.createElement("button");
actionBtn.className = "btn";
actionBtn.style.cssText = `
width: 100%;
background: ${isCurrent ? '#6c757d' : (isFree ? 'linear-gradient(135deg, #04AA6D 0%, #038f5a 100%)' : 'linear-gradient(135deg, #FF6B35 0%, #FF4500 100%)')};
color: white;
border: none;
cursor: ${isCurrent ? 'not-allowed' : 'pointer'};
transition: all 0.3s ease;
opacity: ${isCurrent ? '0.5' : '1'};
box-shadow: ${isCurrent ? 'none' : '0 4px 12px rgba(0,0,0,0.15)'};
letter-spacing: 0.5px;
text-transform: uppercase;
`;
if (isCurrent) {
actionBtn.innerHTML = '<i class="fa-solid fa-check"></i> Currently Installed';
actionBtn.disabled = true;
} else if (isFree) {
actionBtn.innerHTML = '<i class="fa-solid fa-download"></i>';
actionBtn.onclick = () => selectUpgrade(option);
actionBtn.onmouseenter = () => {
actionBtn.style.background = 'linear-gradient(135deg, #038f5a 0%, #026b43 100%)';
actionBtn.style.transform = 'translateY(-2px)';
actionBtn.style.boxShadow = '0 6px 16px rgba(0,0,0,0.2)';
};
actionBtn.onmouseleave = () => {
actionBtn.style.background = 'linear-gradient(135deg, #04AA6D 0%, #038f5a 100%)';
actionBtn.style.transform = 'translateY(0)';
actionBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
};
} else {
actionBtn.innerHTML = '<i class="fa-solid fa-shopping-cart"></i>';
actionBtn.onclick = () => selectUpgrade(option);
actionBtn.onmouseenter = () => {
actionBtn.style.background = 'linear-gradient(135deg, #FF4500 0%, #CC3700 100%)';
actionBtn.style.transform = 'translateY(-2px)';
actionBtn.style.boxShadow = '0 6px 16px rgba(255,107,53,0.4)';
};
actionBtn.onmouseleave = () => {
actionBtn.style.background = 'linear-gradient(135deg, #FF6B35 0%, #FF4500 100%)';
actionBtn.style.transform = 'translateY(0)';
actionBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
};
}
priceSection.appendChild(actionBtn);
}
priceSection.appendChild(priceText);
// Action button with gradient for paid
const actionBtn = document.createElement("button");
actionBtn.className = "btn";
actionBtn.style.cssText = `
width: 100%;
background: ${isCurrent ? '#6c757d' : (isFree ? 'linear-gradient(135deg, #04AA6D 0%, #038f5a 100%)' : 'linear-gradient(135deg, #FF6B35 0%, #FF4500 100%)')};
color: white;
border: none;
cursor: ${isCurrent ? 'not-allowed' : 'pointer'};
transition: all 0.3s ease;
opacity: ${isCurrent ? '0.5' : '1'};
box-shadow: ${isCurrent ? 'none' : '0 4px 12px rgba(0,0,0,0.15)'};
letter-spacing: 0.5px;
text-transform: uppercase;
`;
if (isCurrent) {
actionBtn.innerHTML = '<i class="fa-solid fa-check"></i> Currently Installed';
actionBtn.disabled = true;
} else if (isFree) {
actionBtn.innerHTML = '<i class="fa-solid fa-download"></i>';
actionBtn.onclick = () => selectUpgrade(option);
actionBtn.onmouseenter = () => {
actionBtn.style.background = 'linear-gradient(135deg, #038f5a 0%, #026b43 100%)';
actionBtn.style.transform = 'translateY(-2px)';
actionBtn.style.boxShadow = '0 6px 16px rgba(0,0,0,0.2)';
};
actionBtn.onmouseleave = () => {
actionBtn.style.background = 'linear-gradient(135deg, #04AA6D 0%, #038f5a 100%)';
actionBtn.style.transform = 'translateY(0)';
actionBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
};
} else {
actionBtn.innerHTML = '<i class="fa-solid fa-shopping-cart"></i>';
actionBtn.onclick = () => selectUpgrade(option);
actionBtn.onmouseenter = () => {
actionBtn.style.background = 'linear-gradient(135deg, #FF4500 0%, #CC3700 100%)';
actionBtn.style.transform = 'translateY(-2px)';
actionBtn.style.boxShadow = '0 6px 16px rgba(255,107,53,0.4)';
};
actionBtn.onmouseleave = () => {
actionBtn.style.background = 'linear-gradient(135deg, #FF6B35 0%, #FF4500 100%)';
actionBtn.style.transform = 'translateY(0)';
actionBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
};
}
priceSection.appendChild(actionBtn);
card.appendChild(priceSection);
grid.appendChild(card);
});

0
custom/morvalwatches/style/VeLiTi-Logo2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -130,6 +130,11 @@ $view .= '<div class="content-block tab-content active">
<option value="1" '.(($partner['status']==1 )?' selected':'').'>'.$enabled .'</option>
<option value="0" '.(($partner['status']==0 )?' selected':'').'>'.$disabled .'</option>
</select>
<label for="status">'.($menu_dealers ?? 'is_dealer').'</label>
<select id="is_dealer" name="is_dealer">
<option value="0" '.(($partner['is_dealer']==0 )?' selected':'').'>'.$disabled .'</option>
<option value="1" '.(($partner['is_dealer']==1 )?' selected':'').'>'.$enabled .'</option>
</select>
<label for="partnertype">'.$partner_partnertype.'</label>
<select id="partnertype" name="partnertype" required>
';
@@ -178,6 +183,41 @@ if ($_SESSION['permission'] == 3 || $_SESSION['permission'] == 4){
</div>
</div>';
$view .= '<div class="tabs">
<a href="#">'.($menu_dealers ?? 'is_dealer').'</a>
</div>';
$view .= '<div class="content-block tab-content">
<div class="form responsive-width-100">
<label for="name">'.$dealers_name.'</label>
<input id="name" type="text" name="name" placeholder="'.$dealers_name.'" value="'.htmlspecialchars($partner['name'] ?? '').'">
<label for="address">'.$dealers_address.'</label>
<input id="address" type="text" name="address" placeholder="'.$dealers_address.'" value="'.htmlspecialchars($partner['address'] ?? '').'">
<label for="city">'.$dealers_city.'</label>
<input id="city" type="text" name="city" placeholder="'.$dealers_city.'" value="'.htmlspecialchars($partner['city'] ?? '').'">
<label for="postalcode">'.$dealers_postalcode.'</label>
<input id="postalcode" type="text" name="postalcode" placeholder="'.$dealers_postalcode.'" value="'.htmlspecialchars($partner['postalcode'] ?? '').'">
<label for="country">'.$dealers_country.'</label>
<select id="country" name="country">
<option value="" > -select-</option>
';
// Sort countries alphabetically
usort($countries, function($a, $b) {
return strcmp($a['country'], $b['country']);
});
foreach ($countries as $id => $data) {
$selected = ($partner['country'] == $data['country']) ? 'selected' : '';
$view .='<option value="' . $data['country'] . '" ' . $selected . '>' . $data['country'] . '</option>';
}
$view .= '
</select>
<label for="">'.($dealers_email ?? 'email').'</label>
<input name="email" type="text" value="'.$partner['email'].'">
<label for="">'.($dealers_phone ?? 'phone').'</label>
<input name="phone" type="text" value="'.$partner['phone'].'">
</div>';
$view .= '<div class="tabs">
<a href="#">'.$tab3.'</a>
</div>';

511
report_builder.php Normal file
View File

@@ -0,0 +1,511 @@
<?php
defined(page_security_key) or exit;
//SET ORIGIN FOR NAVIGATION
$_SESSION['prev_origin'] = $_SERVER['REQUEST_URI'];
$page = $_SESSION['origin'] = 'report_builder';
//Check if allowed
if (isAllowed($page, $_SESSION['profile'], $_SESSION['permission'], 'R') === 0) {
header('location: index.php');
exit;
}
// Create bearer token for API calls
$bearertoken = createCommunicationToken($_SESSION['userkey']);
// Include settings for baseurl
include './settings/settings_redirector.php';
template_header('Report Builder', 'report_builder', 'view');
$view = '
<p id="servicetoken" hidden>'.$bearertoken.'</p>
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
<h2 class="responsive-width-100"><i class="fa-solid fa-chart-bar"></i> ' . ($report_builder_title ?? 'Report Builder') . '</h2>
</div>
<!-- Query Builder Section -->
<div class="content-block" id="query-builder">
<div id="query-builder-header" style="display:none;padding:15px 20px;cursor:pointer;border-bottom:1px solid #f0f1f2;" onclick="toggleQueryBuilder()">
<span style="font-weight:600;color:#555;"><i class="fa-solid fa-chevron-down" id="query-builder-icon"></i> ' . ($report_builder_title ?? 'Query Builder') . '</span>
<span id="current-query-info" style="margin-left:15px;color:#6b788c;font-size:13px;"></span>
</div>
<div id="query-builder-content" style="display:flex;flex-wrap:wrap;gap:20px;padding:20px;">
<!-- Left Column: Table & Columns -->
<div style="flex:1;min-width:250px;">
<label for="query-table" style="display:block;margin-bottom:8px;font-weight:600;">' . ($report_builder_select_table ?? 'Select Table') . '</label>
<select id="query-table" style="width:100%;padding:10px;border:0;border-bottom:1px solid #dedfe1;margin-bottom:20px;">
<option value="">' . ($report_builder_choose_table ?? 'Choose a table...') . '</option>
</select>
<label for="query-columns" style="display:block;margin-bottom:8px;font-weight:600;">' . ($report_builder_select_columns ?? 'Select Columns') . ' <span style="font-weight:normal;color:#6b788c;font-size:12px;">(Ctrl/Cmd + click)</span></label>
<select id="query-columns" multiple style="width:100%;height:180px;padding:5px;border:1px solid #dedfe1;border-radius:4px;">
<option value="">' . ($report_builder_select_table_first ?? 'Select a table first...') . '</option>
</select>
</div>
<!-- Middle Column: Filters -->
<div style="flex:1;min-width:300px;">
<label style="display:block;margin-bottom:8px;font-weight:600;">' . ($report_builder_filters ?? 'Filters') . ' <span style="font-weight:normal;color:#6b788c;font-size:12px;">(WHERE)</span></label>
<div id="filters-container" style="min-height:100px;background:#f9fafb;border-radius:4px;padding:10px;margin-bottom:10px;"></div>
<button class="btn green small" onclick="addFilter()"><i class="fa-solid fa-plus"></i> ' . ($report_builder_add_filter ?? 'Add Filter') . '</button>
</div>
<!-- Right Column: Options -->
<div style="flex:0 0 200px;min-width:150px;">
<label for="query-order" style="display:block;margin-bottom:8px;font-weight:600;">' . ($report_builder_order_by ?? 'Order By') . '</label>
<select id="query-order" style="width:100%;padding:10px;border:0;border-bottom:1px solid #dedfe1;margin-bottom:15px;">
<option value="">' . ($report_builder_none ?? 'None') . '</option>
</select>
<label for="query-sort" style="display:block;margin-bottom:8px;font-weight:600;">' . ($report_builder_sort_direction ?? 'Sort') . '</label>
<select id="query-sort" style="width:100%;padding:10px;border:0;border-bottom:1px solid #dedfe1;margin-bottom:15px;">
<option value="ASC">' . ($report_builder_ascending ?? 'Ascending') . '</option>
<option value="DESC">' . ($report_builder_descending ?? 'Descending') . '</option>
</select>
<label for="query-limit" style="display:block;margin-bottom:8px;font-weight:600;">' . ($report_builder_limit ?? 'Limit') . '</label>
<input type="number" id="query-limit" value="100" min="1" max="5000" style="width:100%;padding:10px;border:0;border-bottom:1px solid #dedfe1;">
</div>
</div>
<!-- Action Buttons -->
<div id="query-builder-actions" style="padding:0 20px 20px 20px;display:flex;gap:10px;flex-wrap:wrap;align-items:center;">
<button class="btn" onclick="executeBuilderQuery()"><i class="fa-solid fa-play"></i> ' . ($report_builder_run ?? 'Run Query') . '</button>
<button class="btn alt" onclick="clearAll()"><i class="fa-solid fa-eraser"></i> ' . ($report_builder_clear ?? 'Clear') . '</button>
<span style="flex:1;"></span>
<a href="#" onclick="toggleAdvanced(event)" style="color:#6b788c;font-size:13px;"><i class="fa-solid fa-code"></i> ' . ($report_builder_advanced ?? 'Advanced SQL') . '</a>
</div>
<!-- Advanced SQL (hidden by default) -->
<div id="advanced-sql" style="display:none;border-top:1px solid #f0f1f2;padding:20px;">
<label for="sql-query" style="display:block;margin-bottom:8px;font-weight:600;">' . ($report_builder_sql_query ?? 'SQL Query') . '</label>
<textarea id="sql-query" placeholder="SELECT * FROM table_name WHERE condition LIMIT 100" style="width:100%;font-family:monospace;min-height:100px;padding:10px;border:1px solid #dedfe1;border-radius:4px;margin-bottom:10px;"></textarea>
<button class="btn" onclick="executeAdvancedQuery()"><i class="fa-solid fa-play"></i> ' . ($report_builder_execute ?? 'Execute') . '</button>
<span style="margin-left:15px;color:#6b788c;font-size:12px;"><i class="fa-solid fa-info-circle"></i> ' . ($report_builder_tip1 ?? 'Only SELECT queries are allowed') . '</span>
</div>
</div>
</div>
<!-- Loading Indicator -->
<div id="query-loading" style="display:none;text-align:center;padding:30px;">
<div class="loader" style="margin:0 auto 15px;"></div>
<p>' . ($report_builder_loading ?? 'Loading...') . '</p>
</div>
<!-- Results Container -->
<div id="results"></div>
<script>
// API base URL (from PHP settings)
var link = "'.$baseurl.'";
// Get bearer token from hidden element
function getAuthHeader() {
const token = document.getElementById("servicetoken").textContent;
return {
"Authorization": "Bearer " + token,
"Content-Type": "application/json"
};
}
// Toggle advanced SQL section
function toggleAdvanced(e) {
e.preventDefault();
const adv = document.getElementById("advanced-sql");
adv.style.display = adv.style.display === "none" ? "block" : "none";
}
// Toggle query builder collapse/expand
function toggleQueryBuilder() {
const content = document.getElementById("query-builder-content");
const actions = document.getElementById("query-builder-actions");
const advanced = document.getElementById("advanced-sql");
const icon = document.getElementById("query-builder-icon");
if (content.style.display === "none") {
content.style.display = "flex";
actions.style.display = "flex";
icon.className = "fa-solid fa-chevron-down";
} else {
content.style.display = "none";
actions.style.display = "none";
advanced.style.display = "none";
icon.className = "fa-solid fa-chevron-right";
}
}
// Collapse query builder and show header
function collapseQueryBuilder(query) {
const header = document.getElementById("query-builder-header");
const content = document.getElementById("query-builder-content");
const actions = document.getElementById("query-builder-actions");
const advanced = document.getElementById("advanced-sql");
const icon = document.getElementById("query-builder-icon");
const info = document.getElementById("current-query-info");
header.style.display = "block";
content.style.display = "none";
actions.style.display = "none";
advanced.style.display = "none";
icon.className = "fa-solid fa-chevron-right";
// Show truncated query info
const table = document.getElementById("query-table").value;
info.textContent = table ? "Table: " + table : "";
}
// Initialize the application
document.addEventListener("DOMContentLoaded", function() {
loadTables();
document.getElementById("query-table").addEventListener("change", function() {
loadColumns();
});
});
// Load tables from database
async function loadTables() {
try {
const response = await fetch(link + "/v2/report_builder/action=getTables", {
method: "GET",
headers: getAuthHeader()
});
const data = await response.json();
if (data.success) {
const select = document.getElementById("query-table");
select.innerHTML = \'<option value="">' . ($report_builder_choose_table ?? 'Choose a table...') . '</option>\';
data.tables.forEach(table => {
const option = document.createElement("option");
option.value = table;
option.textContent = table;
select.appendChild(option);
});
} else {
showError(data.message || "Failed to load tables");
}
} catch (error) {
showError("' . ($report_builder_error_load_tables ?? 'Failed to load tables') . ': " + error.message);
}
}
// Load columns for selected table
async function loadColumns() {
const table = document.getElementById("query-table").value;
const columnsSelect = document.getElementById("query-columns");
const orderSelect = document.getElementById("query-order");
if (!table) {
columnsSelect.innerHTML = \'<option value="">' . ($report_builder_select_table_first ?? 'Select a table first...') . '</option>\';
orderSelect.innerHTML = \'<option value="">' . ($report_builder_none ?? 'None') . '</option>\';
document.getElementById("filters-container").innerHTML = "";
return;
}
try {
const response = await fetch(link + "/v2/report_builder/action=getColumns&table=" + encodeURIComponent(table), {
method: "GET",
headers: getAuthHeader()
});
const data = await response.json();
if (data.success) {
// Populate columns select
columnsSelect.innerHTML = "";
const allOption = document.createElement("option");
allOption.value = "*";
allOption.textContent = "* (' . ($report_builder_all_columns ?? 'All Columns') . ')";
allOption.selected = true;
columnsSelect.appendChild(allOption);
data.columns.forEach(column => {
const option = document.createElement("option");
option.value = column;
option.textContent = column;
columnsSelect.appendChild(option);
});
// Populate order by select
orderSelect.innerHTML = \'<option value="">' . ($report_builder_none ?? 'None') . '</option>\';
data.columns.forEach(column => {
const option = document.createElement("option");
option.value = column;
option.textContent = column;
orderSelect.appendChild(option);
});
// Clear filters
document.getElementById("filters-container").innerHTML = "";
} else {
showError(data.message || "Failed to load columns");
}
} catch (error) {
showError("' . ($report_builder_error_load_columns ?? 'Failed to load columns') . ': " + error.message);
}
}
// Execute query builder query
function executeBuilderQuery() {
const table = document.getElementById("query-table").value;
const columnsSelect = document.getElementById("query-columns");
const selectedColumns = Array.from(columnsSelect.selectedOptions).map(opt => opt.value);
const orderBy = document.getElementById("query-order").value;
const sortDir = document.getElementById("query-sort").value;
const limit = document.getElementById("query-limit").value;
if (!table) {
showError("' . ($report_builder_error_select_table ?? 'Please select a table') . '");
return;
}
if (selectedColumns.length === 0) {
showError("' . ($report_builder_error_select_column ?? 'Please select at least one column') . '");
return;
}
const columns = selectedColumns.join(", ");
let query = `SELECT ${columns} FROM ${table}`;
// Add filters
const filters = getFilters();
if (filters.length > 0) {
query += " WHERE " + filters.join(" AND ");
}
// Add order by
if (orderBy) {
query += ` ORDER BY ${orderBy} ${sortDir}`;
}
// Add limit
query += ` LIMIT ${limit || 100}`;
executeQuery(query);
}
// Execute advanced query
function executeAdvancedQuery() {
const query = document.getElementById("sql-query").value.trim();
if (!query) {
showError("' . ($report_builder_error_enter_query ?? 'Please enter a SQL query') . '");
return;
}
if (!query.toLowerCase().startsWith("select")) {
showError("' . ($report_builder_error_select_only ?? 'Only SELECT queries are allowed') . '");
return;
}
executeQuery(query);
}
// Get filters from query builder
function getFilters() {
const filters = [];
const filterRows = document.querySelectorAll(".filter-row");
filterRows.forEach(row => {
const column = row.querySelector(".filter-column").value;
const operator = row.querySelector(".filter-operator").value;
const value = row.querySelector(".filter-value").value;
if (column && value) {
if (operator === "LIKE") {
filters.push(`${column} LIKE \'%${value}%\'`);
} else {
filters.push(`${column} ${operator} \'${value}\'`);
}
}
});
return filters;
}
// Add filter row
function addFilter() {
const table = document.getElementById("query-table").value;
if (!table) {
showError("' . ($report_builder_error_select_table_first ?? 'Please select a table first') . '");
return;
}
const container = document.getElementById("filters-container");
const filterRow = document.createElement("div");
filterRow.className = "filter-row";
filterRow.style.cssText = "display:flex;gap:8px;margin-bottom:8px;align-items:center;flex-wrap:wrap;";
const columnsSelect = document.getElementById("query-columns");
const columns = Array.from(columnsSelect.options).map(opt => opt.value).filter(v => v && v !== "*");
filterRow.innerHTML = `
<select class="filter-column" style="flex:1;min-width:100px;padding:8px;border:1px solid #dedfe1;border-radius:4px;">
${columns.map(col => `<option value="${col}">${col}</option>`).join("")}
</select>
<select class="filter-operator" style="width:70px;padding:8px;border:1px solid #dedfe1;border-radius:4px;">
<option value="=">=</option>
<option value="!=">!=</option>
<option value=">">&gt;</option>
<option value="<">&lt;</option>
<option value=">=">&gt;=</option>
<option value="<=">&lt;=</option>
<option value="LIKE">LIKE</option>
</select>
<input type="text" class="filter-value" placeholder="Value" style="flex:1;min-width:100px;padding:8px;border:1px solid #dedfe1;border-radius:4px;">
<button class="btn red small" onclick="this.parentElement.remove()" style="padding:8px 12px;"><i class="fa-solid fa-times"></i></button>
`;
container.appendChild(filterRow);
}
// Execute query via POST
async function executeQuery(query) {
showLoading();
try {
const response = await fetch(link + "/v2/report_builder", {
method: "POST",
headers: getAuthHeader(),
body: JSON.stringify({
action: "executeQuery",
query: query
})
});
const data = await response.json();
hideLoading();
if (data.success) {
displayResults(data.results, query, data.rowCount);
} else {
showError(data.message || "Query execution failed");
}
} catch (error) {
hideLoading();
showError("' . ($report_builder_error_execute ?? 'Failed to execute query') . ': " + error.message);
}
}
// Display results
function displayResults(results, query, rowCount) {
const resultsDiv = document.getElementById("results");
if (!results || results.length === 0) {
resultsDiv.innerHTML = \'<div class="msg" style="margin-top:20px;background-color:#d1ecf1;border-left:4px solid #0c5460;color:#0c5460;"><i class="fa-solid fa-info-circle"></i><p>' . ($report_builder_no_results ?? 'No results found') . '</p></div>\';
return;
}
// Table
const columns = Object.keys(results[0]);
let tableHtml = `
<div class="content-block" style="margin-top:20px;">
<div style="padding:15px;border-bottom:1px solid #f0f1f2;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;">
<div style="flex:1;min-width:200px;">
<strong>' . ($report_builder_query ?? 'Query') . ':</strong> <code style="font-family:monospace;background:#f8fafc;padding:5px 10px;border-radius:3px;display:inline-block;margin-top:5px;word-break:break-all;">${escapeHtml(query)}</code>
</div>
<button class="btn green" onclick="exportToCSV()"><i class="fa-solid fa-download"></i> </button>
</div>
<div class="table">
<table>
<thead>
<tr>
${columns.map(col => `<th>${escapeHtml(col)}</th>`).join("")}
</tr>
</thead>
<tbody>
`;
results.forEach(row => {
tableHtml += "<tr>";
columns.forEach(col => {
tableHtml += `<td>${escapeHtml(String(row[col] ?? ""))}</td>`;
});
tableHtml += "</tr>";
});
tableHtml += `
</tbody>
</table>
</div>
</div>
`;
resultsDiv.innerHTML = tableHtml;
window.currentResults = results;
// Collapse query builder after showing results
collapseQueryBuilder(query);
}
// Export to CSV
function exportToCSV() {
if (!window.currentResults || window.currentResults.length === 0) {
showError("' . ($report_builder_error_no_export ?? 'No results to export') . '");
return;
}
const results = window.currentResults;
const columns = Object.keys(results[0]);
let csv = columns.join(",") + "\\n";
results.forEach(row => {
const values = columns.map(col => {
const value = String(row[col] ?? "");
return \'"\' + value.replace(/"/g, \'"""\') + \'"\';
});
csv += values.join(",") + "\\n";
});
const blob = new Blob([csv], { type: "text/csv" });
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "report_" + new Date().toISOString().slice(0,10) + ".csv";
a.click();
window.URL.revokeObjectURL(url);
}
// Utility functions
function showLoading() {
document.getElementById("query-loading").style.display = "block";
document.getElementById("results").innerHTML = "";
}
function hideLoading() {
document.getElementById("query-loading").style.display = "none";
}
function showError(message) {
document.getElementById("results").innerHTML = `<div class="msg error" style="margin-top:20px;"><i class="fa-solid fa-exclamation-circle"></i><p><strong>' . ($report_builder_error ?? 'Error') . ':</strong> ${escapeHtml(message)}</p></div>`;
}
function clearAll() {
document.getElementById("query-table").value = "";
document.getElementById("query-columns").innerHTML = \'<option value="">' . ($report_builder_select_table_first ?? 'Select a table first...') . '</option>\';
document.getElementById("query-order").innerHTML = \'<option value="">' . ($report_builder_none ?? 'None') . '</option>\';
document.getElementById("query-limit").value = "100";
document.getElementById("filters-container").innerHTML = "";
document.getElementById("sql-query").value = "";
document.getElementById("results").innerHTML = "";
window.currentResults = null;
// Expand query builder
document.getElementById("query-builder-header").style.display = "none";
document.getElementById("query-builder-content").style.display = "flex";
document.getElementById("query-builder-actions").style.display = "flex";
}
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
</script>
';
echo $view;
template_footer();

View File

@@ -176,8 +176,8 @@ $main_menu = [
],
"reporting" => [
"main_menu" => [
"url" => "report_build",
"selected" => "report_build",
"url" => "report_builder",
"selected" => "report_builder",
"icon" => "fa-solid fa-magnifying-glass-chart",
"name" => "menu_report_main"
],
@@ -293,6 +293,18 @@ $main_menu = [
"icon" => "fas fa-tachometer-alt",
"name" => "menu_maintenance"
],
"Access_elements" => [
"url" => "access_elements",
"selected" => "access_elements",
"icon" => "fas fa-tools",
"name" => "menu_access_elements"
],
"user_roles" => [
"url" => "user_roles",
"selected" => "user_roles",
"icon" => "fas fa-tools",
"name" => "menu_user_roles"
],
"profiles" => [
"url" => "profiles",
"selected" => "profiles",

791
user.php
View File

@@ -1,6 +1,17 @@
<?php
defined(page_security_key) or exit;
if (debug && debug_id == $_SESSION['id']){
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
include_once './assets/functions.php';
include_once './settings/settings_redirector.php';
//SET ORIGIN FOR NAVIGATION
$_SESSION['prev_origin_user'] = $_SERVER['REQUEST_URI'];
$page = 'user';
//Check if allowed
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
@@ -8,331 +19,551 @@ if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
exit;
}
//PAGE Security
$page_manage = 'user_manage';
$update_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'C');
// Default input product values
$user = [
'id' => '',
'username' => '',
'email' => '',
'partnerhierarchy' => '',
'view' => 3,
'service' => 0,
'settings' => '',
'userkey' => 1,
'created' => '',
'createdby' => '',
'updated' => '',
'updatedby' => '',
'lastlogin' => '',
'language' => 'US',
'login_count' => 0
];
$update_allowed_edit = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'C');
//GET Details from URL
$user_ID = $_GET['id'] ?? '';
if ($user_ID !=''){
$url = 'index.php?page=users&id='.$user_ID.'';
} else {
$url = 'index.php?page=users';
if ($user_ID == ''){
header('location: index.php?page=users');
exit;
}
if (isset($_GET['id'])) {
// ID param exists, edit an existing product
//CALL TO API
$api_url = '/v1/users/id='.$user_ID;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = decode_payload($responses);}else{$responses = null;}
$user = json_decode(json_encode($responses[0]), true);
//CALL TO API FOR User information
$api_url = '/v2/users/id='.$user_ID;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
$user = $responses[0];
if ($update_allowed === 1){
if (isset($_POST['submit'])) {
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//Secure data
$payload = generate_payload($data);
//API call
$responses = ioServer('/v1/users', $payload);
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=users&success_msg=2');
exit;
}
}
}
if ($update_allowed === 1){
if (isset($_POST['reset'])) {
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//Secure data
$payload = generate_payload($data);
//API call
$responses = ioServer('/v1/users', $payload);
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=users&success_msg=2');
exit;
}
}
}
if ($update_allowed === 1){
if (isset($_POST['unblock'])) {
//UNSET THE SUMBIT FROM POST
unset($_POST['unblock']);
//CHANGE LOGIN COUNT TO 0
$_POST['login_count'] = '0';
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//Secure data
$payload = generate_payload($data);
//API call
$responses = ioServer('/v1/users', $payload);
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=users&success_msg=2');
exit;
}
}
}
if ($delete_allowed === 1){
if (isset($_POST['delete'])) {
//GET ALL POST DATA
$data = json_encode($_POST , JSON_UNESCAPED_UNICODE);
//Secure data
$payload = generate_payload($data);
//API call
$responses = ioServer('/v1/users', $payload);
// Redirect and delete product
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=users&success_msg=3');
exit;
}
}
}
} else {
// Create a new product
if (isset($_POST['submit']) && $create_allowed === 1) {
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//Secure data
$payload = generate_payload($data);
//API call
$responses = ioServer('/v1/users', $payload);
$responses = decode_payload($responses);
if ($responses === 'NOK'){
header('Location: index.php?page=user&success_msg=0');
} elseif ($responses == 1){
header('Location: index.php?page=user&success_msg=0');
}
else {
header('Location: index.php?page=users&success_msg=1');
exit;
}
//Helper function to convert service hex string to 1/0
function isServiceActive($service) {
// If service is a valid hex string (50 chars from bin2hex(random_bytes(25))), return 1
if (!empty($service) && ctype_xdigit($service)) {
return 1;
}
return 0;
}
$service_active = isServiceActive($user->service);
//CALL TO API FOR User Role Assignments
$api_url = '/v2/user_role_assignments/user_id='.$user_ID;
$role_assignments = ioServer($api_url,'');
//Decode Payload
if (!empty($role_assignments)){$role_assignments = json_decode($role_assignments);}else{$role_assignments = null;}
//CALL TO API FOR All Available Roles
$api_url = '/v2/user_roles/status=1&p=1';
$all_roles_response = ioServer($api_url,'');
//Decode Payload
if (!empty($all_roles_response)){
$all_roles = json_decode($all_roles_response);
if (!is_array($all_roles)){
$all_roles = [];
}
} else {
$all_roles = [];
}
//------------------------------
// Handle POST for inline edit (user AND roles)
//------------------------------
if (isset($_POST['save_user']) && $update_allowed_edit === 1) {
// Build user data using existing field names
$user_data = [
'id' => $user_ID,
'userkey' => $_POST['userkey'] ?? 1,
'username' => $_POST['username'] ?? '',
'email' => $_POST['email'] ?? '',
'view' => $_POST['view'] ?? 3,
'settings' => $_POST['settings'] ?? '',
'service' => $_POST['service'] ?? 0,
'language' => $_POST['language'] ?? '',
'login_count' => $_POST['login_count'] ?? 0,
'salesid' => $_POST['salesid'] ?? '',
'soldto' => $_POST['soldto'] ?? '',
'shipto' => $_POST['shipto'] ?? '',
'location' => $_POST['location'] ?? ''
];
$data = json_encode($user_data, JSON_UNESCAPED_UNICODE);
ioServer('/v2/users', $data);
// Also save role assignments
$role_data = [
'batch_update' => true,
'user_id' => (int)$user_ID,
'roles' => isset($_POST['roles']) ? array_map('intval', $_POST['roles']) : []
];
$data = json_encode($role_data, JSON_UNESCAPED_UNICODE);
ioServer('/v2/user_role_assignments', $data);
// Redirect to refresh
header('Location: index.php?page=user&id='.$user_ID.'&success_msg=2');
exit;
}
// Handle password reset
if (isset($_POST['reset']) && $update_allowed_edit === 1) {
$data = json_encode(['id' => $user_ID, 'reset' => 'reset'], JSON_UNESCAPED_UNICODE);
ioServer('/v2/users', $data);
header('Location: index.php?page=user&id='.$user_ID.'&success_msg=4');
exit;
}
// Handle unblock
if (isset($_POST['unblock']) && $update_allowed_edit === 1) {
$data = json_encode(['id' => $user_ID, 'login_count' => '0'], JSON_UNESCAPED_UNICODE);
ioServer('/v2/users', $data);
header('Location: index.php?page=user&id='.$user_ID.'&success_msg=5');
exit;
}
// Handle delete
if (isset($_POST['delete']) && $delete_allowed === 1) {
$data = json_encode(['id' => $user_ID, 'delete' => 'delete'], JSON_UNESCAPED_UNICODE);
ioServer('/v2/users', $data);
header('Location: index.php?page=users&success_msg=3');
exit;
}
//------------------------------
//Variables
//------------------------------
$is_blocked = ($user->login_count > 4);
$is_active = ($user->userkey && $user->userkey != '');
if ($is_blocked) {
$status_text = ($User_block ?? 'Blocked');
$status_class = 'id0';
} elseif ($is_active) {
$status_text = ($enabled ?? 'Active');
$status_class = 'id1';
} else {
$status_text = ($disabled ?? 'Inactive');
$status_class = 'id0';
}
//EMPTY VIEW
$view = '';
// Handle success messages
if (isset($_GET['success_msg'])) {
if ($_GET['success_msg'] == 0) {
$success_msg = $error_msg_0;
if ($_GET['success_msg'] == 1) {
$success_msg = ($message_user_1 ?? 'User created successfully');
}
if ($_GET['success_msg'] == 2) {
$success_msg = ($message_user_2 ?? 'User updated successfully');
}
if ($_GET['success_msg'] == 3) {
$success_msg = ($message_user_3 ?? 'User deleted successfully');
}
if ($_GET['success_msg'] == 4) {
$success_msg = ($message_user_4 ?? 'Password reset successfully');
}
if ($_GET['success_msg'] == 5) {
$success_msg = ($message_user_5 ?? 'User unblocked successfully');
}
if ($_GET['success_msg'] == 6) {
$success_msg = ($message_user_6 ?? 'Roles updated successfully');
}
}
template_header('User', 'user', 'manage');
template_header(($user_title ?? 'User'), 'user', 'view');
$view = '
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
<h2 class="responsive-width-100">'.($user_h2 ?? 'User').' - '.$user->username.'</h2>
<a href="index.php?page='.($_SESSION['origin'] ?? 'users').'&p='.($_SESSION['p'] ?? '1').($_SESSION['status'] ?? '').($_SESSION['sort'] ?? '').($_SESSION['search'] ?? '').'" class="btn alt mar-right-2">←</a>
';
if ($update_allowed_edit === 1){
$view .= '<a href="javascript:void(0);" id="editBtn" class="btn mar-right-2" onclick="toggleUserEdit()">✏️</a>';
$view .= '<button type="submit" form="userForm" id="saveBtn" class="btn" style="display:none;">💾</button>';
}
$view .= '</div>';
if (isset($success_msg)){
$view .= ' <div class="msg error">
$view .= ' <div class="msg success">
<i class="fas fa-check-circle"></i>
<p>'.$success_msg.'</p>
<i class="fas fa-times"></i>
</div>';
}
$view .='
<form action="" method="post">
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
<h2 class="responsive-width-100">'.$user_h2.': '.$user['username'].' '.(($user['login_count'] > 4)? '<span class="status disabled">'.$User_block:(($user['userkey'] && $user['userkey'] !='')? '<span class="status enabled">'.$enabled:'<span class="status">'.$disabled)).'</h2>
<a href="index.php?page=users" class="btn alt mar-right-2">←</a>
// Start form wrapper for edit mode
$view .= '<form id="userForm" action="" method="post">
<input type="hidden" name="save_user" value="1">
<input type="hidden" name="id" value="'.$user_ID.'">';
$view .= '<div class="content-block-wrapper">';
// User Information Block
$view .= ' <div class="content-block order-details">
<div class="block-header">
<i class="fa-solid fa-circle-info"></i>'.($view_user_information ?? 'User Information').'
</div>
<div class="order-detail">
<h3>'.($general_status ?? 'Status').'</h3>
<p>
<span class="view-mode status '.$status_class.'">'.$status_text.'</span>
<select class="edit-mode" name="userkey" style="display:none;">
<option value="1"'.($is_active ? ' selected' : '').'>'.($enabled ?? 'Active').'</option>
<option value="0"'.(!$is_active ? ' selected' : '').'>'.($disabled ?? 'Inactive').'</option>
</select>
</p>
</div>
<div class="order-detail">
<h3>'.($User_username ?? 'Username').'</h3>
<p>
<span class="view-mode">'.$user->username.'</span>
<input type="text" class="edit-mode" name="username" value="'.$user->username.'" style="display:none;" pattern="^\S+$" required>
</p>
</div>
<div class="order-detail">
<h3>'.($User_email ?? 'Email').'</h3>
<p>
<span class="view-mode">'.$user->email.'</span>
<input type="email" class="edit-mode" name="email" value="'.$user->email.'" style="display:none;" required>
</p>
</div>
<div class="order-detail">
<h3>'.($User_language ?? 'Language').'</h3>
<p>
<span class="view-mode">'.($user->language ?? '-').'</span>
<select class="edit-mode" name="language" style="display:none;">
<option value="">-</option>';
foreach ($supportedLanguages as $language){
$view .= '<option value="'.$language.'"'.(($user->language == $language) ? ' selected' : '').'>'.$language.'</option>';
}
$view .= ' </select>
</p>
</div>
</div>
';
if ($delete_allowed === 1){
$view .= '<input type="submit" name="delete" value="X" class="btn red mar-right-2" onclick="return confirm(\'Are you sure you want to delete this user?\')">';
}
if ($update_allowed === 1){
$view .= '<input type="submit" name="submit" value="💾" class="btn">';
}
$view .= '</div>';
// Role Assignments Block
$view .='<div class="content-block order-details" id="rolesBlock">
<div class="block-header">
<i class="fa-solid fa-user-shield fa-sm"></i>'.($view_user_roles ?? 'Assigned Roles').'
</div>
<div class="view-mode-roles">';
$view .= '<div class="tabs">
<a href="#" class="active">'.$tab1 .'</a>
</div>';
//Define Service and User enabled
$view .= '<div class="content-block tab-content active">
<div class="form responsive-width-100">
<label for="userkey">Active</label>
<select id="userkey" name="userkey">
<option value="1" '.(($user['userkey']==1 || $user['userkey'] !='' )?' selected':'').'>'.$enabled .'</option>
<option value="0" '.(($user['userkey']==0 || $user['userkey'] =='' )?' selected':'').'>'.$disabled .'</option>
</select>
<label for="username">'.$User_username.'</label>
<input id="name" type="text" name="username" placeholder="'.$User_username.'" value="'.$user['username'].'" pattern="^\S+$" required">
<label for="username">'.$User_email.'</label>
<input id="name" type="email" name="email" placeholder="'.$User_email.'" value="'.$user['email'].'" required">
<label for="view">'.$User_permission.'</label>
<select id="view" name="view" required>
<option value="3" '.($user['view']==3?' selected':'').'>'.$permission3.'</option>
<option value="2" '.($user['view']==2?' selected':'').'>'.$permission2.'</option>
<option value="1" '.($user['view']==1?' selected':'').'>'.$permission1.'</option>
';
//ADD PERMISSION SET BASED ON USER PERMISSION ADMIN OR ADMIN+
if ($_SESSION['permission'] == 3){
$view .= ' <option value="4" '.($user['view']==4?' selected':'').'>'.$permission4.'</option>';
}
if ($_SESSION['permission'] == 4){
$view .= ' <option value="4" '.($user['view']==4?' selected':'').'>'.$permission4.'</option>
<option value="5" '.($user['view']==5?' selected':'').'>'.$permission5.'</option>';
}
$view .= ' </select>
<label for="profile">'.$User_profile.'</label>
';
//Show profiles for AMIN
if ($_SESSION['permission'] == 3 || $_SESSION['permission'] == 4){
$view .='<select id="settings" name="settings">
<option value="" '.($user['settings']== ''?' selected':'').'></option>';
foreach ($all_profiles as $profile) {
$view .='<option value="'.$profile.'" '.($user['settings']== $profile?' selected':'').'>'.$profile.'</option>';
}
$view .='</select>';
} else {
//CHECK IF USER HAS A SPECIFIC PROFILE ASSIGNED
if (isset($_SESSION['profile_name']) && $_SESSION['profile_name'] !=''){
$view .=' <input id="name" type="text" name="settings" placeholder="settings" value="'.$_SESSION['profile_name'].'" readonly>';
} else {
$view .=' <input id="name" type="text" name="" placeholder="settings" value="'.$user['settings'].'" readonly>
';
}
// Get list of already assigned role IDs
$assigned_role_ids = [];
if (!empty($role_assignments)){
foreach ($role_assignments as $assignment){
if ($assignment->is_active == 1){
$assigned_role_ids[] = $assignment->role_id;
}
}
}
$view .=' <label for="service">'.$User_service.'</label>
<select id="service" name="service">
<option value="1" '.(($user['service']==1 || $user['service'] !='')?' selected':'').'>'.$enabled .'</option>
<option value="0" '.(($user['service']==0 || $user['service'] =='')?' selected':'').'>'.$disabled .'</option>
</select>
<label for="service">'.$User_language.'</label>
<select id="language" name="language">
<option value="" '.(($user['language'] =='')?' selected':'').'></option>';
foreach ($supportedLanguages as $language){
$view .='<option value="'.$language.'" '.(($user['language']==$language)?' selected':'').'>'.$language.'</option>';
}
$view .=' </select>
<input type="hidden" name="id" value="'.$user_ID.'">
<input type="hidden" name="old_view" value="'.$user['view'].'">
';
// VIEW MODE - Show only assigned roles
if (!empty($role_assignments)){
$has_active_roles = false;
foreach ($role_assignments as $assignment){
if ($assignment->is_active == 1){
$has_active_roles = true;
$view .= '<div class="order-detail">
<h3>'.$assignment->role_name.'</h3>';
if (!empty($assignment->role_description)){
$view .= '<p>'.$assignment->role_description.'</p>';
}
$view .= '</div>';
}
}
if (!$has_active_roles){
$view .= '<div class="order-detail">
<h3>-</h3>
<p>'.($no_roles_assigned ?? 'No roles assigned to this user').'</p>
</div>';
}
} else {
$view .= '<div class="order-detail">
<h3>-</h3>
<p>'.($no_roles_assigned ?? 'No roles assigned to this user').'</p>
</div>';
}
$view .= '</div>
$view .= '</div>'; // Close view-mode-roles
// EDIT MODE - Show all roles with checkboxes (only if user has edit permission)
if ($update_allowed_edit === 1 && !empty($all_roles)){
$view .= '<div class="edit-mode-roles" style="display:none;">';
foreach ($all_roles as $role){
$is_checked = in_array($role->rowID, $assigned_role_ids) ? ' checked' : '';
$view .= '<div class="order-detail" style="display: flex; align-items: center; gap: 10px;">
<input type="checkbox"
name="roles[]"
value="'.$role->rowID.'"
id="role_'.$role->rowID.'"'.$is_checked.'>
<label for="role_'.$role->rowID.'" style="margin: 0; cursor: pointer; flex: 1;">
<h3 style="margin: 0;">'.$role->name.'</h3>
<p style="margin: 5px 0 0 0; font-size: 0.9em; color: #666;">'.($role->description ?? '').'</p>
</label>
</div>';
}
$view .= '</div>'; // Close edit-mode-roles
}
$view .= '</div>'; // Close content-block
$view .= '</div>'; // Close content-block-wrapper
// Permissions Block
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-key fa-sm"></i>'.($view_user_permissions ?? 'Permissions').'
</div>
<div class="table order-table">
<table>
<tr>
<td style="width:25%;">'.($User_permission ?? 'Permission Level').'</td>
<td>
<span class="view-mode">';
// Display permission level text
switch($user->view){
case 1: $view .= ($permission1 ?? 'View'); break;
case 2: $view .= ($permission2 ?? 'Edit'); break;
case 3: $view .= ($permission3 ?? 'Admin'); break;
case 4: $view .= ($permission4 ?? 'Super Admin'); break;
case 5: $view .= ($permission5 ?? 'System'); break;
default: $view .= '-';
}
$view .= '</span>
<select class="edit-mode" name="view" style="display:none;">
<option value="3"'.($user->view == 3 ? ' selected' : '').'>'.($permission3 ?? 'Admin').'</option>
<option value="2"'.($user->view == 2 ? ' selected' : '').'>'.($permission2 ?? 'Edit').'</option>
<option value="1"'.($user->view == 1 ? ' selected' : '').'>'.($permission1 ?? 'View').'</option>';
if ($_SESSION['permission'] == 3){
$view .= '<option value="4"'.($user->view == 4 ? ' selected' : '').'>'.($permission4 ?? 'Super Admin').'</option>';
}
if ($_SESSION['permission'] == 4){
$view .= '<option value="4"'.($user->view == 4 ? ' selected' : '').'>'.($permission4 ?? 'Super Admin').'</option>
<option value="5"'.($user->view == 5 ? ' selected' : '').'>'.($permission5 ?? 'System').'</option>';
}
$view .= ' </select>
</td>
</tr>
<tr>
<td style="width:25%;">'.($User_profile ?? 'Profile').'</td>
<td>
<span class="view-mode">'.($user->settings ?? '-').'</span>';
if ($_SESSION['permission'] == 3 || $_SESSION['permission'] == 4){
$view .= '<select class="edit-mode" name="settings" style="display:none;">
<option value="">-</option>';
foreach ($all_profiles as $profile) {
$view .= '<option value="'.$profile.'"'.($user->settings == $profile ? ' selected' : '').'>'.$profile.'</option>';
}
$view .= '</select>';
} else {
$view .= '<input type="hidden" name="settings" value="'.$user->settings.'">';
}
$view .= ' </td>
</tr>
<tr>
<td style="width:25%;">'.($User_service ?? 'Service Access').'</td>
<td>
<span class="view-mode">'.(($service_active == 1) ? ($enabled ?? 'Enabled') : ($disabled ?? 'Disabled')).'</span>
<select class="edit-mode" name="service" style="display:none;">
<option value="1"'.(($service_active == 1) ? ' selected' : '').'>'.($enabled ?? 'Enabled').'</option>
<option value="0"'.(($service_active == 0) ? ' selected' : '').'>'.($disabled ?? 'Disabled').'</option>
</select>
</td>
</tr>
</table>
</div>
</div>';
$view .= '<div class="tabs">
<a href="#">'.$tab2.'</a>
</div>';
// Partner Hierarchy Block
$partner_data = json_decode($user->partnerhierarchy) ?? json_decode($_SESSION['partnerhierarchy']);
//GET PARTNERDATA
$partner_data = json_decode($user['partnerhierarchy'])?? json_decode($_SESSION['partnerhierarchy']) ;
//BUID UP DROPDOWNS
$salesid_dropdown = listPartner('salesid',$_SESSION['permission'],$partner_data->salesid,'');
$soldto_dropdown = listPartner('soldto',$_SESSION['permission'],$partner_data->soldto,'');
$shipto_dropdown = listPartner('shipto',$_SESSION['permission'],$partner_data->shipto,'');
$location_dropdown = listPartner('location',$_SESSION['permission'],$partner_data->location,'');
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-building fa-sm"></i>'.($view_user_partners ?? 'Partner Hierarchy').'
</div>
<div class="table order-table">
<table>';
//DISPLAY
$view .= '<div class="content-block tab-content">
<div class="form responsive-width-100">
';
if ($_SESSION['permission'] == 3 || $_SESSION['permission'] == 4){
$view .= '<label for="status">'.$general_salesid.'</label>';
$view .= $salesid_dropdown;
$view .= '<label for="status">'.$general_soldto.'</label>';
$view .= $soldto_dropdown;
$salesid_dropdown = listPartner('salesid', $_SESSION['permission'], $partner_data->salesid ?? '', '');
$soldto_dropdown = listPartner('soldto', $_SESSION['permission'], $partner_data->soldto ?? '', '');
$view .= '<tr>
<td style="width:25%;">'.($general_salesid ?? 'Sales ID').'</td>
<td>
<span class="view-mode">'.($partner_data->salesid ?? '-').'</span>
<span class="edit-mode" style="display:none;">'.$salesid_dropdown.'</span>
</td>
</tr>
<tr>
<td style="width:25%;">'.($general_soldto ?? 'Sold To').'</td>
<td>
<span class="view-mode">'.($partner_data->soldto ?? '-').'</span>
<span class="edit-mode" style="display:none;">'.$soldto_dropdown.'</span>
</td>
</tr>';
}
$view .= '<label for="status">'.$general_shipto.'</label>';
$view .= $shipto_dropdown;
$view .= '<label for="status">'.$general_location.'</label>';
$view .= $location_dropdown;
$view .= '
</div>
$shipto_dropdown = listPartner('shipto', $_SESSION['permission'], $partner_data->shipto ?? '', '');
$location_dropdown = listPartner('location', $_SESSION['permission'], $partner_data->location ?? '', '');
$view .= '<tr>
<td style="width:25%;">'.($general_shipto ?? 'Ship To').'</td>
<td>
<span class="view-mode">'.($partner_data->shipto ?? '-').'</span>
<span class="edit-mode" style="display:none;">'.$shipto_dropdown.'</span>
</td>
</tr>
<tr>
<td style="width:25%;">'.($general_location ?? 'Location').'</td>
<td>
<span class="view-mode">'.($partner_data->location ?? '-').'</span>
<span class="edit-mode" style="display:none;">'.$location_dropdown.'</span>
</td>
</tr>
</table>
</div>
</div>';
$view .= '<div class="tabs">
<a href="#">'.$tab3.'</a>
</div>';
// Metadata Block
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-bars fa-sm"></i>'.($tab3 ?? 'Details').'
</div>
<div class="table order-table">
<table>
<tr>
<td style="width:25%;">'.($general_created ?? 'Created').'</td>
<td>'.getRelativeTime($user->created).'</td>
</tr>
<tr>
<td style="width:25%;">'.($User_lastlogin ?? 'Last Login').'</td>
<td>'.($user->lastlogin ? getRelativeTime($user->lastlogin) : '-').'</td>
</tr>
<tr>
<td style="width:25%;">'.($general_updated ?? 'Updated').'</td>
<td>'.($user->updated ? getRelativeTime($user->updated) : '-').'</td>
</tr>
<tr>
<td style="width:25%;">'.($general_updatedby ?? 'Updated By').'</td>
<td>'.($user->updatedby ?? '-').'</td>
</tr>
<tr>
<td style="width:25%;">'.($User_pw_login_count ?? 'Login Attempts').'</td>
<td>
<span class="view-mode">'.$user->login_count.'</span>';
//SUPERUSERS AND ADMINS CAN RESET BLOCKED USERS
if ($_SESSION['permission'] == 3 || $_SESSION['permission'] == 4){
$login_count = '<input id="name" type="text" name="login_count" placeholder="'.$User_pw_login_count.'" value="'.$user['login_count'].'">';
$view .= '<input type="number" class="edit-mode" name="login_count" value="'.$user->login_count.'" style="display:none; width: 80px;">';
} else {
$login_count = '<input id="name" type="text" name="" placeholder="'.$User_pw_login_count.'" value="'.$user['login_count'].'" readonly>';
$view .= '<input type="hidden" name="login_count" value="'.$user->login_count.'">';
}
$view .= '<div class="content-block tab-content">
<div class="form responsive-width-100">
<label for="">'.$general_created.'</label>
<input id="name" type="text" name="" placeholder="'.$general_created.'" value="'.$user['created'].'" readonly>
<label for="">'.$User_lastlogin.'</label>
<input id="name" type="text" name="" placeholder="'.$User_lastlogin.'" value="'.$user['lastlogin'].'" readonly>
<label for="productcode">'.$general_updated.'</label>
<input id="name" type="text" name="" placeholder="'.$general_updated.'" value="'.$user['updated'].'" readonly>
<label for="productcode">'.$general_updatedby.'</label>
<input id="name" type="text" name="" placeholder="'.$general_updatedby.'" value="'.$user['updatedby'].'" readonly>
<label for="">'.$User_pw_login_count.'</label>
'.$login_count.'
</div>
</div>';
$view .= ' </td>
</tr>
</table>
</div>
</div>
</form>
';
if ($update_allowed === 1 && $user_ID !=''){
$view .= '<div class="tabs">
<a href="#">'.$general_actions.'</a>
</div>';
$view .= '<div class="content-block tab-content">
<div class="form responsive-width-100">
<label for="service">'.$User_pw_reset .'</label>
<input type="submit" name="reset" value="Reset" class="btn" style="width: 15%;" onclick="return confirm(\'Are you sure you want to reset this user password?\')">
<label for="service">'.$User_unblock .'</label>
<input type="submit" name="unblock" value="'.$User_unblock.'" class="btn" style="width: 15%;" onclick="return confirm(\'Are you sure you want to unblock this user?\')">
// Actions Block (outside form for separate actions)
if ($update_allowed_edit === 1){
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-bolt fa-sm"></i>'.($general_actions ?? 'Actions').'
</div>
<div class="table order-table">
<table>
<tr>
<td style="width:25%;">'.($User_pw_reset ?? 'Reset Password').'</td>
<td>
<form action="" method="post" style="display:inline;">
<input type="hidden" name="id" value="'.$user_ID.'">
<button type="submit" name="reset" class="btn alt" onclick="return confirm(\''.($confirm_reset_password ?? 'Are you sure you want to reset this user\'s password?').'\')">
<i class="fa-solid fa-key"></i>
</button>
</form>
</td>
</tr>';
if ($is_blocked){
$view .= ' <tr>
<td style="width:25%;">'.($User_unblock ?? 'Unblock User').'</td>
<td>
<form action="" method="post" style="display:inline;">
<input type="hidden" name="id" value="'.$user_ID.'">
<button type="submit" name="unblock" class="btn alt" onclick="return confirm(\''.($confirm_unblock ?? 'Are you sure you want to unblock this user?').'\')">
<i class="fa-solid fa-unlock"></i>
</button>
</form>
</td>
</tr>';
}
if ($delete_allowed === 1){
$view .= ' <tr>
<td style="width:25%;">'.($general_delete ?? 'Delete User').'</td>
<td>
<form action="" method="post" style="display:inline;">
<input type="hidden" name="id" value="'.$user_ID.'">
<button type="submit" name="delete" class="btn red" onclick="return confirm(\''.($confirm_delete_user ?? 'Are you sure you want to delete this user?').'\')">
<i class="fa-solid fa-trash"></i>
</button>
</form>
</td>
</tr>';
}
$view .= ' </table>
</div>
</div>';
}
$view .= '</form>';
//Output
//OUTPUT
echo $view;
template_footer()
?>
$js = 'var userEditMode = false;
function toggleUserEdit() {
userEditMode = !userEditMode;
var editBtn = document.getElementById("editBtn");
var saveBtn = document.getElementById("saveBtn");
var viewElements = document.querySelectorAll(".view-mode");
var editElements = document.querySelectorAll(".edit-mode");
var viewRolesElements = document.querySelectorAll(".view-mode-roles");
var editRolesElements = document.querySelectorAll(".edit-mode-roles");
var i;
if (userEditMode) {
// Enter edit mode for user info AND roles
for (i = 0; i < viewElements.length; i++) { viewElements[i].style.display = "none"; }
for (i = 0; i < editElements.length; i++) { editElements[i].style.display = "inline"; }
for (i = 0; i < viewRolesElements.length; i++) { viewRolesElements[i].style.display = "none"; }
for (i = 0; i < editRolesElements.length; i++) { editRolesElements[i].style.display = "block"; }
editBtn.style.display = "none";
saveBtn.style.display = "inline-block";
} else {
// Exit edit mode
for (i = 0; i < viewElements.length; i++) { viewElements[i].style.display = "inline"; }
for (i = 0; i < editElements.length; i++) { editElements[i].style.display = "none"; }
for (i = 0; i < viewRolesElements.length; i++) { viewRolesElements[i].style.display = "block"; }
for (i = 0; i < editRolesElements.length; i++) { editRolesElements[i].style.display = "none"; }
editBtn.style.display = "inline-block";
saveBtn.style.display = "none";
}
}';
template_footer($js);

382
user_role.php Normal file
View File

@@ -0,0 +1,382 @@
<?php
defined(page_security_key) or exit;
if (debug && debug_id == $_SESSION['id']){
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
include_once './assets/functions.php';
include_once './settings/settings_redirector.php';
//SET ORIGIN FOR NAVIGATION
$_SESSION['prev_origin_user_role'] = $_SERVER['REQUEST_URI'];
$page = 'user_role';
//Check if allowed
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
header('location: index.php');
exit;
}
//PAGE Security
$page_manage = 'user_role_manage';
$update_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'U');
$update_allowed_edit = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'C');
//GET Details from URL
$GET_VALUES = urlGETdetails($_GET) ?? '';
//CALL TO API FOR General information
$api_url = '/v2/user_roles/'.$GET_VALUES;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
$responses = $responses[0];
$role_id = $responses->rowID;
//CALL TO API FOR Role Permissions
$api_url = '/v2/role_access_permissions/role_id='.$role_id;
$permissions = ioServer($api_url,'');
//Decode Payload
if (!empty($permissions)){$permissions = json_decode($permissions);}else{$permissions = null;}
//CALL TO API FOR All Access Elements (no paging)
$api_url = '/v2/access_elements/all=';
$all_access_elements = ioServer($api_url,'');
//Decode Payload
if (!empty($all_access_elements)){$all_access_elements = json_decode($all_access_elements);}else{$all_access_elements = null;}
// Create lookup array for existing permissions
$permission_lookup = [];
if (!empty($permissions)){
foreach ($permissions as $perm){
$permission_lookup[$perm->access_id] = $perm;
}
}
//CALL TO API FOR User Role Assignments
$api_url = '/v2/user_role_assignments/role_id='.$role_id;
$assignments = ioServer($api_url,'');
//Decode Payload
if (!empty($assignments)){$assignments = json_decode($assignments);}else{$assignments = null;}
//------------------------------
// Handle POST for inline edit
//------------------------------
if (isset($_POST['save_permissions']) && $update_allowed_edit === 1) {
// Update role info (name, description, status)
$role_data = json_encode([
'rowID' => $role_id,
'name' => $_POST['name'] ?? '',
'description' => $_POST['description'] ?? '',
'is_active' => $_POST['is_active'] ?? 1
], JSON_UNESCAPED_UNICODE);
ioServer('/v2/user_roles', $role_data);
// Process permission updates
$posted_permissions = $_POST['permissions'] ?? [];
// For each access element, update or create permission
foreach ($all_access_elements as $element) {
$access_id = $element->rowID;
$has_permission = isset($posted_permissions[$access_id]);
$existing_permission = $permission_lookup[$access_id] ?? null;
if ($has_permission) {
// Get CRUD values
$can_create = isset($posted_permissions[$access_id]['C']) ? 1 : 0;
$can_read = isset($posted_permissions[$access_id]['R']) ? 1 : 0;
$can_update = isset($posted_permissions[$access_id]['U']) ? 1 : 0;
$can_delete = isset($posted_permissions[$access_id]['D']) ? 1 : 0;
if ($existing_permission) {
// Update existing permission
$data = json_encode([
'rowID' => $existing_permission->rowID,
'role_id' => $role_id,
'access_id' => $access_id,
'can_create' => $can_create,
'can_read' => $can_read,
'can_update' => $can_update,
'can_delete' => $can_delete
], JSON_UNESCAPED_UNICODE);
} else {
// Insert new permission
$data = json_encode([
'role_id' => $role_id,
'access_id' => $access_id,
'can_create' => $can_create,
'can_read' => $can_read,
'can_update' => $can_update,
'can_delete' => $can_delete
], JSON_UNESCAPED_UNICODE);
}
ioServer('/v2/role_access_permissions', $data);
} else {
// If no permission checkboxes selected but had existing permission, delete it
if ($existing_permission) {
$data = json_encode([
'rowID' => $existing_permission->rowID,
'delete' => 'delete'
], JSON_UNESCAPED_UNICODE);
ioServer('/v2/role_access_permissions', $data);
}
}
}
// Redirect to refresh
header('Location: index.php?page=user_role&rowID='.$role_id.'&success_msg=2');
exit;
}
//------------------------------
//Variables
//------------------------------
$status_text = ($responses->is_active == 1) ? ($enabled ?? 'Active') : ($disabled ?? 'Inactive');
$status_class = ($responses->is_active == 1) ? 'id1' : 'id0';
// Handle success messages
if (isset($_GET['success_msg'])) {
if ($_GET['success_msg'] == 1) {
$success_msg = ($message_role_1 ?? 'Role created successfully');
}
if ($_GET['success_msg'] == 2) {
$success_msg = ($message_role_2 ?? 'Role updated successfully');
}
if ($_GET['success_msg'] == 3) {
$success_msg = ($message_role_3 ?? 'Role deleted successfully');
}
}
template_header(($user_role_title ?? 'User Role'), 'user_role', 'view');
$view = '
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
<h2 class="responsive-width-100">'.($view_role_h2 ?? 'User Role').' - '.$responses->name.'</h2>
<a href="index.php?page='.$_SESSION['origin'].'&p='.$_SESSION['p'].$_SESSION['status'].$_SESSION['sort'].$_SESSION['search'].'" class="btn alt mar-right-2">←</a>
';
if ($update_allowed_edit === 1){
$view .= '<a href="javascript:void(0);" id="editBtn" class="btn mar-right-2" onclick="togglePermissionsEdit()">✏️</a>';
$view .= '<button type="submit" form="permissionsForm" id="saveBtn" class="btn" style="display:none;">💾</button>';
}
$view .= '</div>';
if (isset($success_msg)){
$view .= ' <div class="msg success">
<i class="fas fa-check-circle"></i>
<p>'.$success_msg.'</p>
<i class="fas fa-times"></i>
</div>';
}
// Start form wrapper for edit mode
$view .= '<form id="permissionsForm" action="" method="post">
<input type="hidden" name="save_permissions" value="1">
<input type="hidden" name="rowID" value="'.$role_id.'">';
$view .= '<div class="content-block-wrapper">';
// Role Information Block
$view .= ' <div class="content-block order-details">
<div class="block-header">
<i class="fa-solid fa-circle-info"></i>'.($view_role_information ?? 'Role Information').'
</div>
<div class="order-detail">
<h3>'.($general_status ?? 'Status').'</h3>
<p>
<span class="view-mode status '.$status_class.'">'.$status_text.'</span>
<select class="edit-mode" name="is_active" style="display:none;">
<option value="1"'.($responses->is_active == 1 ? ' selected' : '').'>'.($enabled ?? 'Active').'</option>
<option value="0"'.($responses->is_active == 0 ? ' selected' : '').'>'.($disabled ?? 'Inactive').'</option>
</select>
</p>
</div>
<div class="order-detail">
<h3>'.($role_name ?? 'Role Name').'</h3>
<p>
<span class="view-mode">'.$responses->name.'</span>
<input type="text" class="edit-mode" name="name" value="'.$responses->name.'" style="display:none;" required>
</p>
</div>
<div class="order-detail">
<h3>'.($role_description ?? 'Description').'</h3>
<p>
<span class="view-mode">'.($responses->description ?? '-').'</span>
<textarea class="edit-mode" name="description" style="display:none;">'.($responses->description ?? '').'</textarea>
</p>
</div>
</div>
';
// Role Assignments Block
$view .='<div class="content-block order-details">
<div class="block-header">
<i class="fa-solid fa-users fa-sm"></i>'.($view_role_assignments ?? 'Assigned Users').'
</div>';
if (!empty($assignments)){
foreach ($assignments as $assignment){
$assignment_status = ($assignment->is_active == 1) ? ($enabled ?? 'Active') : ($disabled ?? 'Inactive');
$view .= '<div class="order-detail">
<h3>'.$assignment->username.'</h3>
<p>'.$assignment_status.((!empty($assignment->expires_at))? ' - '.($expires ?? 'Expires').': '.$assignment->expires_at : '').'</p>
</div>';
}
} else {
$view .= '<div class="order-detail">
<h3>-</h3>
<p>'.($no_users_assigned ?? 'No users assigned to this role').'</p>
</div>';
}
$view .= '</div>';
$view .= '</div>'; // Close content-block-wrapper
// Permissions Table Block
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-key fa-sm"></i>'.($view_role_permissions ?? 'Role Permissions').'
</div>
<div class="table">
<table>
<thead>
<tr>
<th>'.($access_element_name ?? 'Access Element').'</th>
<th class="responsive-hidden">'.($access_element_path ?? 'Path').'</th>
<th class="responsive-hidden">'.($access_element_group ?? 'Group').'</th>
<th><span class="view-mode">'.($permission_create ?? 'C').'</span><a href="javascript:void(0);" class="edit-mode" style="display:none;" onclick="toggleColumn(\'C\')">'.($permission_create ?? 'C').'</a></th>
<th><span class="view-mode">'.($permission_read ?? 'R').'</span><a href="javascript:void(0);" class="edit-mode" style="display:none;" onclick="toggleColumn(\'R\')">'.($permission_read ?? 'R').'</a></th>
<th><span class="view-mode">'.($permission_update ?? 'U').'</span><a href="javascript:void(0);" class="edit-mode" style="display:none;" onclick="toggleColumn(\'U\')">'.($permission_update ?? 'U').'</a></th>
<th><span class="view-mode">'.($permission_delete ?? 'D').'</span><a href="javascript:void(0);" class="edit-mode" style="display:none;" onclick="toggleColumn(\'D\')">'.($permission_delete ?? 'D').'</a></th>
</tr>
</thead>
<tbody>';
if (!empty($all_access_elements)){
foreach ($all_access_elements as $element){
$access_id = $element->rowID;
$existing_perm = $permission_lookup[$access_id] ?? null;
// Determine current permission values
$has_create = ($existing_perm && $existing_perm->can_create == 1);
$has_read = ($existing_perm && $existing_perm->can_read == 1);
$has_update = ($existing_perm && $existing_perm->can_update == 1);
$has_delete = ($existing_perm && $existing_perm->can_delete == 1);
$has_any_permission = ($has_create || $has_read || $has_update || $has_delete);
// Row class - hide unassigned rows in view mode
$row_class = $has_any_permission ? '' : ' class="edit-only-row" style="display:none;"';
// View mode icons
$icon_create = $has_create ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
$icon_read = $has_read ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
$icon_update = $has_update ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
$icon_delete = $has_delete ? '<i class="fa-solid fa-check" style="color:green;"></i>' : '<i class="fa-solid fa-times" style="color:red;"></i>';
// Edit mode checkboxes
$cb_create_checked = $has_create ? ' checked' : '';
$cb_read_checked = $has_read ? ' checked' : '';
$cb_update_checked = $has_update ? ' checked' : '';
$cb_delete_checked = $has_delete ? ' checked' : '';
$view .= '<tr'.$row_class.'>
<td>'.$element->access_name.'</td>
<td class="responsive-hidden">'.$element->access_path.'</td>
<td class="responsive-hidden">'.($element->access_group ?? '-').'</td>
<td>
<span class="view-mode">'.$icon_create.'</span>
<input type="checkbox" class="edit-mode" name="permissions['.$access_id.'][C]" value="1"'.$cb_create_checked.' style="display:none;">
</td>
<td>
<span class="view-mode">'.$icon_read.'</span>
<input type="checkbox" class="edit-mode" name="permissions['.$access_id.'][R]" value="1"'.$cb_read_checked.' style="display:none;">
</td>
<td>
<span class="view-mode">'.$icon_update.'</span>
<input type="checkbox" class="edit-mode" name="permissions['.$access_id.'][U]" value="1"'.$cb_update_checked.' style="display:none;">
</td>
<td>
<span class="view-mode">'.$icon_delete.'</span>
<input type="checkbox" class="edit-mode" name="permissions['.$access_id.'][D]" value="1"'.$cb_delete_checked.' style="display:none;">
</td>
</tr>';
}
} else {
$view .= '<tr>
<td colspan="7" style="text-align:center;">'.($no_access_elements ?? 'No access elements found').'</td>
</tr>';
}
$view .= ' </tbody>
</table>
</div>
</div>
';
// Metadata Block
$view .= '<div class="content-block">
<div class="block-header">
<i class="fa-solid fa-bars fa-sm"></i>'.($tab3 ?? 'Details').'
</div>
<div class="table order-table">
<table>
<tr>
<td style="width:25%;">'.($general_created ?? 'Created').'</td>
<td>'.getRelativeTime($responses->created).'</td>
</tr>
<tr>
<td style="width:25%;">'.($general_updated ?? 'Updated').'</td>
<td>'.getRelativeTime($responses->updated).'</td>
</tr>
</table>
</div>
</div>
</form>
';
//OUTPUT
echo $view;
$js = 'var permissionsEditMode = false;
function togglePermissionsEdit() {
permissionsEditMode = !permissionsEditMode;
var editBtn = document.getElementById("editBtn");
var saveBtn = document.getElementById("saveBtn");
var viewElements = document.querySelectorAll(".view-mode");
var editElements = document.querySelectorAll(".edit-mode");
var editOnlyRows = document.querySelectorAll(".edit-only-row");
var i;
if (permissionsEditMode) {
for (i = 0; i < viewElements.length; i++) { viewElements[i].style.display = "none"; }
for (i = 0; i < editElements.length; i++) { editElements[i].style.display = "inline"; }
for (i = 0; i < editOnlyRows.length; i++) { editOnlyRows[i].style.display = "table-row"; }
editBtn.style.display = "none";
saveBtn.style.display = "inline-block";
} else {
for (i = 0; i < viewElements.length; i++) { viewElements[i].style.display = "inline"; }
for (i = 0; i < editElements.length; i++) { editElements[i].style.display = "none"; }
for (i = 0; i < editOnlyRows.length; i++) { editOnlyRows[i].style.display = "none"; }
editBtn.style.display = "inline-block";
saveBtn.style.display = "none";
}
}
function toggleColumn(type) {
var checkboxes = document.querySelectorAll("input[name$=\\"[" + type + "]\\"]");
var allChecked = true;
for (var i = 0; i < checkboxes.length; i++) {
if (!checkboxes[i].checked) {
allChecked = false;
break;
}
}
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = !allChecked;
}
}';
template_footer($js);

227
user_role_manage.php Normal file
View File

@@ -0,0 +1,227 @@
<?php
defined(page_security_key) or exit;
if (debug && debug_id == $_SESSION['id']){
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
include_once './assets/functions.php';
include_once './settings/settings_redirector.php';
$page = 'user_role_manage';
//Check if allowed
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
header('location: index.php');
exit;
}
//PAGE Security
$update_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page ,$_SESSION['profile'],$_SESSION['permission'],'C');
// Default input values
$role = [
'rowID' => '',
'name' => '',
'description' => '',
'is_active' => 1,
'created' => '',
'createdby' => $_SESSION['username'],
'updated' => '',
'updatedby' => ''
];
$role_ID = $_GET['rowID'] ?? '';
if ($role_ID !=''){
$url = 'index.php?page=user_role&rowID='.$role_ID.'';
} else {
$url = 'index.php?page=user_roles';
}
//GET ALL ACCESS ELEMENTS
$api_url = '/v2/access_elements/status=1';
$access_elements = ioServer($api_url,'');
//Decode Payload
if (!empty($access_elements)){$access_elements = json_decode($access_elements);}else{$access_elements = null;}
//GET ROLE PERMISSIONS (if editing)
$role_permissions = [];
if ($role_ID != ''){
$api_url = '/v2/role_access_permissions/role_id='.$role_ID;
$role_permissions_response = ioServer($api_url,'');
if (!empty($role_permissions_response)){
$role_permissions_data = json_decode($role_permissions_response);
foreach ($role_permissions_data as $perm){
$role_permissions[$perm->access_id] = [
'can_create' => $perm->can_create,
'can_read' => $perm->can_read,
'can_update' => $perm->can_update,
'can_delete' => $perm->can_delete
];
}
}
}
if (isset($_GET['rowID'])) {
// ID param exists, edit an existing role
//CALL TO API
$api_url = '/v2/user_roles/rowID='.$role_ID;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = null;}
$role = $responses[0];
if ($update_allowed === 1){
if (isset($_POST['submit'])) {
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//API call
$responses = ioServer('/v2/user_roles', $data);
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=user_role&rowID='.$role_ID.'&success_msg=2');
exit;
}
}
}
if ($delete_allowed === 1){
if (isset($_POST['delete'])) {
//GET ALL POST DATA
$data = json_encode($_POST , JSON_UNESCAPED_UNICODE);
//API call
$responses = ioServer('/v2/user_roles', $data);
// Redirect and delete role
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=user_roles&success_msg=3');
exit;
}
}
}
} else {
// Create a new role
if (isset($_POST['submit']) && $create_allowed === 1) {
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
//API call
$responses = ioServer('/v2/user_roles', $data);
if ($responses === 'NOK'){
} else {
header('Location: index.php?page=user_roles&success_msg=1');
exit;
}
}
}
template_header(($user_role_title ?? 'User Role'), 'user_role', 'manage');
$label_h2 = (($role_ID !='')? ($manage_role_h2 ?? 'Edit Role') : ($button_create_role ?? 'Create Role'));
$view ='
<form action="" method="post">
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
<h2 class="responsive-width-100">'.$label_h2.'</h2>
<a href="'.$url.'" class="btn alt mar-right-2">←</a>
';
if ($delete_allowed === 1 && $role_ID != ''){
$view .= '<input type="submit" name="delete" value="X" class="btn red mar-right-2" onclick="return confirm(\''.($confirm_delete_role ?? 'Are you sure you want to delete this role?').'\')">';
}
if ($update_allowed === 1 || ($create_allowed === 1 && $role_ID == '')){
$view .= '<input type="submit" name="submit" value="💾" class="btn">';
}
$view .= '</div>';
$view .= '<div class="tabs">
<a href="#" class="active">'.($tab1 ?? 'General').'</a>
</div>
<div class="content-block tab-content active">
<div class="form responsive-width-100">
<label for="is_active">'.($general_status ?? 'Status').'</label>
<select id="is_active" name="is_active">
<option value="1" '.($role['is_active']==1?' selected':'').'>'.($enabled ?? 'Active').'</option>
<option value="0" '.($role['is_active']==0?' selected':'').'>'.($disabled ?? 'Inactive').'</option>
</select>
<label for="name">'.($role_name ?? 'Role Name').' <i class="required">*</i></label>
<input id="name" type="text" name="name" placeholder="'.($role_name ?? 'Role Name').'" value="'.$role['name'].'" required>
<label for="description">'.($role_description ?? 'Description').'</label>
<textarea id="description" name="description" placeholder="'.($role_description ?? 'Description').'" style="height: 100px;">'.$role['description'].'</textarea>
<input type="hidden" name="rowID" value="'.$role_ID.'">
</div>
</div>';
// Permissions Tab
$view .= '<div class="tabs">
<a href="#">'.($tab_permissions ?? 'Permissions').'</a>
</div>
<div class="content-block tab-content">
<div class="table">
<table>
<thead>
<tr>
<th>'.($access_element_name ?? 'Access Element').'</th>
<th>'.($permission_create ?? 'Create').'</th>
<th>'.($permission_read ?? 'Read').'</th>
<th>'.($permission_update ?? 'Update').'</th>
<th>'.($permission_delete ?? 'Delete').'</th>
</tr>
</thead>
<tbody>';
if (!empty($access_elements)){
foreach ($access_elements as $element){
$perm = $role_permissions[$element->rowID] ?? ['can_create' => 0, 'can_read' => 0, 'can_update' => 0, 'can_delete' => 0];
$view .= '<tr>
<td>'.$element->access_name.'<br><small style="color:#888;">'.$element->access_path.'</small></td>
<td><input type="checkbox" name="permissions['.$element->rowID.'][can_create]" value="1" '.($perm['can_create']==1?'checked':'').'></td>
<td><input type="checkbox" name="permissions['.$element->rowID.'][can_read]" value="1" '.($perm['can_read']==1?'checked':'').'></td>
<td><input type="checkbox" name="permissions['.$element->rowID.'][can_update]" value="1" '.($perm['can_update']==1?'checked':'').'></td>
<td><input type="checkbox" name="permissions['.$element->rowID.'][can_delete]" value="1" '.($perm['can_delete']==1?'checked':'').'></td>
</tr>';
}
} else {
$view .= '<tr>
<td colspan="5" style="text-align:center;">'.($no_access_elements ?? 'No access elements found').'</td>
</tr>';
}
$view .= ' </tbody>
</table>
</div>
</div>';
//DISPLAY TAB 3 - Metadata
if ($role_ID != ''){
$view .= '<div class="tabs">
<a href="#">'.($tab3 ?? 'Details').'</a>
</div>
<div class="content-block tab-content">
<div class="form responsive-width-100">
<label for="created">'.($general_created ?? 'Created').'</label>
<input id="created" type="text" name="" placeholder="'.($general_created ?? 'Created').'" value="'.$role['created'].'" readonly>
<label for="createdby">'.($general_createdby ?? 'Created By').'</label>
<input id="createdby" type="text" name="" placeholder="'.($general_createdby ?? 'Created By').'" value="'.$role['createdby'].'" readonly>
<label for="updated">'.($general_updated ?? 'Updated').'</label>
<input id="updated" type="text" name="" placeholder="'.($general_updated ?? 'Updated').'" value="'.$role['updated'].'" readonly>
<label for="updatedby">'.($general_updatedby ?? 'Updated By').'</label>
<input id="updatedby" type="text" name="" placeholder="'.($general_updatedby ?? 'Updated By').'" value="'.$role['updatedby'].'" readonly>
</div>
</div>';
}
$view .= '</form>';
//Output
echo $view;
template_footer()?>

202
user_roles.php Normal file
View File

@@ -0,0 +1,202 @@
<?php
defined(page_security_key) or exit;
if (debug && debug_id == $_SESSION['id']){
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
include_once './assets/functions.php';
include_once './settings/settings_redirector.php';
//SET PAGE ORIGIN FOR NAVIGATION AND SECURITY
$prev_page = $_SESSION['prev_origin'] ?? '';
$page = $_SESSION['origin'] = 'user_roles';
//create backbutton to prev_origin
$back_btn_orgin = ($prev_page != '')? '<a href="'.$prev_page.'" class="btn alt mar-right-2">←</a>':'';
//Check if allowed
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
header('location: index.php');
exit;
}
//PAGE Security
$page_manage = 'user_role_manage';
$update_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'U');
$delete_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'D');
$create_allowed = isAllowed($page_manage ,$_SESSION['profile'],$_SESSION['permission'],'C');
//GET PARAMETERS && STORE in SESSION for FURTHER USE/NAVIGATION
$pagination_page = $_SESSION['p'] = isset($_GET['p']) ? $_GET['p'] : 1;
$status = $_SESSION['status'] = isset($_GET['status']) ? '&status='.$_GET['status'] : '';
$sort = $_SESSION['sort'] = isset($_GET['sort']) ? '&sort='.$_GET['sort'] : '';
$search = $_SESSION['search'] = isset($_GET['search']) ? '&search='.$_GET['search'] : '';
//GET PARAMETERS FOR FILTERS
$filter = urlGETdetailsFilter($_GET) ?? '';
// Determine the URL
$url = 'index.php?page=user_roles'.$status.$search.$sort;
//GET Details from URL
$GET_VALUES = urlGETdetails($_GET) ?? '';
//CALL TO API
$api_url = '/v2/user_roles/'.$GET_VALUES;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
//Return QueryTotal from API
$total_url = ((!empty($GET_VALUES) && $GET_VALUES !='') ? '&totals=' : 'totals=' );
$api_url = '/v2/user_roles/'.$GET_VALUES.$total_url;
$query_total = ioServer($api_url,'');
//Decode Payload
if (!empty($query_total)){$query_total = json_decode($query_total);}else{$query_total = null;}
// Handle success messages
if (isset($_GET['success_msg'])) {
if ($_GET['success_msg'] == 1) {
$success_msg = ($message_role_1 ?? 'Role created successfully');
}
if ($_GET['success_msg'] == 2) {
$success_msg = ($message_role_2 ?? 'Role updated successfully');
}
if ($_GET['success_msg'] == 3) {
$success_msg = ($message_role_3 ?? 'Role deleted successfully');
}
}
template_header(($user_roles_title ?? 'User Roles'), 'user_roles','view');
$view = '
<div class="content-title">
<div class="title">
<i class="fa-solid fa-user-shield"></i>
<div class="txt">
<h2>'.($user_roles_h2 ?? 'User Roles').' ('.$query_total.')</h2>
<p>'.($user_roles_p ?? 'Manage user roles and permissions').'</p>
</div>
</div>
<div class="title-actions">
'.$back_btn_orgin;
if ($create_allowed === 1){
$view .= '<a href="index.php?page=user_role_manage" class="btn">+</a>';
}
$view .= '<button id="filter-toggle" class="btn alt" onclick="toggleFilters()">
<i class="fa-solid fa-search"></i>
</button>
</div>
</div>';
if (isset($success_msg)){
$view .= ' <div class="msg success">
<i class="fas fa-check-circle"></i>
<p>'.$success_msg.'</p>
<i class="fas fa-times"></i>
</div>';
}
$view .= '
<div id="filter-panel" class="filter-panel" style="display: none;">
<div class="filter-content">
<form action="" method="get">
'.$filter.'
<div class="filter-row">
<div class="filter-group">
<select name="status">
<option value="" disabled selected>'.($general_status ?? 'Status').'</option>
<option value="1"'.(isset($_GET['status']) && $_GET['status']==1?' selected':'').'>'.($enabled ?? 'Active').'</option>
<option value="0"'.(isset($_GET['status']) && $_GET['status']==0?' selected':'').'>'.($disabled ?? 'Inactive').'</option>
</select>
</div>
<div class="filter-group">
<select name="sort">
<option value="" disabled selected>'.($general_sort ?? 'Sort').'</option>
<option value="1"'.(isset($_GET['sort']) && $_GET['sort']==1?' selected':'').'>'.($role_name ?? 'Name').' '.($general_sort_type_1 ?? 'ASC').'</option>
<option value="2"'.(isset($_GET['sort']) && $_GET['sort']==2?' selected':'').'>'.($role_name ?? 'Name').' '.($general_sort_type_2 ?? 'DESC').'</option>
<option value="3"'.(isset($_GET['sort']) && $_GET['sort']==3?' selected':'').'>'.($general_created ?? 'Created').' '.($general_sort_type_1 ?? 'ASC').'</option>
<option value="4"'.(isset($_GET['sort']) && $_GET['sort']==4?' selected':'').'>'.($general_created ?? 'Created').' '.($general_sort_type_2 ?? 'DESC').'</option>
</select>
</div>
<div class="filter-group search-group">
<input type="text" name="search" placeholder="'.($role_search ?? 'Search roles...').'" value="">
</div>
</div>
<div class="filter-actions">
<button type="submit" class="btn"><i class="fas fa-level-down-alt fa-rotate-90"></i></button>
<a class="btn alt" href="index.php?page=user_roles">X</a>
</div>
</form>
</div>
</div>
';
$view .= '
<div class="content-block">
<div class="table">
<table class="sortable">
<thead>
<tr>
<th>'.($role_name ?? 'Role Name').'</th>
<th class="responsive-hidden">'.($role_description ?? 'Description').'</th>
<th>'.($general_status ?? 'Status').'</th>
<th class="responsive-hidden">'.($role_permissions_count ?? 'Permissions').'</th>
<th class="responsive-hidden">'.($general_created ?? 'Created').'</th>
</tr>
</thead>
<tbody>
';
if (empty($responses)){
$view .= '
<tr>
<td colspan="5" style="text-align:center;">'.($message_no_roles ?? 'No roles found').'</td>
</tr>';
}
foreach ($responses as $response){
//Translate status INT to STR
$status_text = ($response->is_active == 1) ? ($enabled ?? 'Active') : ($disabled ?? 'Inactive');
$status_class = ($response->is_active == 1) ? 'id1' : 'id0';
$view .= '<tr onclick="window.location.href=\'index.php?page=user_role&rowID='.$response->rowID.'\'" style="cursor: pointer;">
<td>'.$response->name.'</td>
<td class="responsive-hidden">'.($response->description ?? '-').'</td>
<td><span class="status '.$status_class.'">'.$status_text.'</span></td>
<td class="responsive-hidden">'.($response->permission_count ?? '0').'</td>
<td class="responsive-hidden">'.getRelativeTime($response->created).'</td>
</tr>
';
}
$view .= '
</tbody>
</table>
</div>
</div>
';
$page_rows = $page_rows_equipment ?? 20;
$view.='<div class="pagination">';
if ($pagination_page > 1) {
$page = $pagination_page-1;
$view .= '<a href="'.$url.'&p=1">'.($general_first ?? 'First').'</a>';
$view .= '<a href="'.$url.'&p='.$page.'">'.($general_prev ?? 'Prev').'</a>';
}
$totals = ceil($query_total / $page_rows) == 0 ? 1 : ceil($query_total / $page_rows);
$view .= '<span> '.($general_page ?? 'Page ').$pagination_page.($general_page_of ?? ' of ').$totals.'</span>';
if ($pagination_page * $page_rows < $query_total){
$page = $pagination_page+1;
$view .= '<a href="'.$url.'&p='.$page.'">'.($general_next ?? 'Next').'</a>';
$view .= '<a href="'.$url.'&p='.$totals.'">'.($general_last ?? 'Last').'</a>';
}
$view .= '</div>';
//OUTPUT
echo $view;
template_footer();
?>

View File

@@ -38,16 +38,16 @@ $url = 'index.php?page=users'.$status.$search;
//GET Details from URL
$GET_VALUES = urlGETdetails($_GET) ?? '';
//CALL TO API
$api_url = '/v1/users/'.$GET_VALUES;
$api_url = '/v2/users/'.$GET_VALUES;
$responses = ioServer($api_url,'');
//Decode Payload
if (!empty($responses)){$responses = decode_payload($responses);}else{$responses = null;}
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
//Return QueryTotal from API
$api_url = '/v1/users/'.$GET_VALUES.'&totals=';
$api_url = '/v2/users/'.$GET_VALUES.'&totals=';
$query_total = ioServer($api_url,'');
//Decode Payload
if (!empty($query_total)){$query_total = decode_payload($query_total);}else{$query_total = null;}
if (!empty($query_total)){$query_total = json_decode($query_total);}else{$query_total = null;}
// Handle success messages
if (isset($_GET['success_msg'])) {