Implement RBAC migration and role management enhancements
- Added AJAX functionality to fetch role permissions for copying. - Introduced system role management with permission checks for updates. - Implemented role deletion with confirmation modal and backend handling. - Enhanced user role assignment migration scripts to transition from legacy profiles to RBAC. - Created SQL migration scripts for user roles and permissions mapping. - Updated user interface to support new role management features including copy permissions and system role indicators.
This commit is contained in:
2
api.php
2
api.php
@@ -134,7 +134,7 @@ if($is_jwt_valid && str_contains($version, 'v')) {
|
||||
//------------------------------------------
|
||||
// Check for maintenance mode, exclude debug user
|
||||
//------------------------------------------
|
||||
if(maintenance_mode == false|| debug_id == $user_data['id']){
|
||||
if(maintenance_mode == false || debug_id == $user_data['id']){
|
||||
|
||||
//------------------------------------------
|
||||
// Build up version and check if file is available
|
||||
|
||||
@@ -14,9 +14,6 @@ if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} el
|
||||
//default whereclause
|
||||
$whereclause = '';
|
||||
|
||||
// For testing, disable account hierarchy filtering
|
||||
// list($whereclause,$condition) = getWhereclauselvl2("",$permission,$partner,'get');
|
||||
|
||||
//NEW ARRAY
|
||||
$criterias = [];
|
||||
$clause = '';
|
||||
|
||||
@@ -31,8 +31,6 @@ if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} el
|
||||
//default whereclause
|
||||
$whereclause = '';
|
||||
|
||||
list($whereclause,$condition) = getWhereclauselvl2('',$permission,$partner,'get');
|
||||
|
||||
//NEW ARRAY
|
||||
$criterias = [];
|
||||
$clause = '';
|
||||
@@ -110,11 +108,6 @@ else {
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
//Bind to query
|
||||
if (str_contains($whereclause, ':condition')){
|
||||
$stmt->bindValue('condition', $condition, PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
if (!empty($criterias)){
|
||||
foreach ($criterias as $key => $value){
|
||||
$key_condition = ':'.$key;
|
||||
|
||||
@@ -14,9 +14,6 @@ if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} el
|
||||
//default whereclause
|
||||
$whereclause = '';
|
||||
|
||||
// Tags are global, so no account hierarchy filtering
|
||||
// list($whereclause,$condition) = getWhereclauselvl2("",$permission,$partner,'get');
|
||||
|
||||
//NEW ARRAY
|
||||
$criterias = [];
|
||||
$clause = '';
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
<?php
|
||||
defined($security_key) or exit;
|
||||
|
||||
//------------------------------------------
|
||||
//Connect to DB
|
||||
//------------------------------------------
|
||||
$pdo = dbConnect($dbname);
|
||||
|
||||
//------------------------------------------
|
||||
// Application related calls
|
||||
//------------------------------------------
|
||||
$request = explode('/', trim($_SERVER['PATH_INFO'],'/'));
|
||||
$action = $request[2] ?? '';
|
||||
|
||||
|
||||
if ($action == 'init'){
|
||||
include './settings/systemservicetool_init.php';
|
||||
echo json_encode($init);
|
||||
@@ -34,6 +38,43 @@ elseif ($action == 'questions' && (isset($_GET['type']) && $_GET['type'] != ''))
|
||||
//Return JSON
|
||||
echo json_encode($arrayQuestions);
|
||||
}
|
||||
elseif ($action == 'products') {
|
||||
|
||||
$sql = "SELECT * FROM products";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute();
|
||||
//Get results
|
||||
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode($messages);
|
||||
|
||||
}
|
||||
elseif ($action == 'equipments' && (isset($_GET['serialnumber']) && $_GET['serialnumber'] != '' && !isset($_GET['validate']))) {
|
||||
|
||||
$sql = "SELECT e.rowID as equipmentID, e.*, p.productcode, p.productname, p.product_media, psl.starts_at,psl.expires_at,psl.status as license_status from equipment e LEFT JOIN products p ON e.productrowid = p.rowID LEFT JOIN products_software_licenses psl ON e.sw_version_license = psl.license_key WHERE e.serialnumber = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$_GET['serialnumber']]);
|
||||
//Get results
|
||||
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode($messages);
|
||||
|
||||
}
|
||||
elseif ($action == 'equipments' && (isset($_GET['serialnumber']) && $_GET['serialnumber'] != '' && isset($_GET['validate']))){
|
||||
|
||||
$sql = "SELECT count(rowID) as rowID from equipment e WHERE e.serialnumber = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$_GET['serialnumber']]);
|
||||
$messages = $stmt->fetch();
|
||||
|
||||
if ($messages[0] == 1) {
|
||||
echo json_encode(array('SN'=> TRUE));
|
||||
}
|
||||
else {
|
||||
echo json_encode(array('SN'=> FALSE));
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
http_response_code(400);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ if(isset($get_content) && $get_content!=''){
|
||||
$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'){
|
||||
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') {
|
||||
@@ -50,6 +50,11 @@ if(isset($get_content) && $get_content!=''){
|
||||
}
|
||||
}
|
||||
|
||||
//Filter system roles for users without delete permission on user_roles
|
||||
if (isAllowed('user_roles', $profile, $permission, 'D') !== 1) {
|
||||
$clause .= ' AND r.is_system != 1';
|
||||
}
|
||||
|
||||
//Build WHERE clause
|
||||
$whereclause = '';
|
||||
if ($clause != ''){
|
||||
@@ -81,6 +86,12 @@ if (isset($criterias['totals']) && $criterias['totals'] ==''){
|
||||
//Request for total rows
|
||||
$sql = 'SELECT count(*) as count FROM user_roles r '.$whereclause;
|
||||
}
|
||||
elseif (isset($criterias['all']) && $criterias['all'] ==''){
|
||||
//Return all records (no paging)
|
||||
$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;
|
||||
}
|
||||
else {
|
||||
//SQL with permission count
|
||||
$sql = 'SELECT r.*,
|
||||
@@ -129,6 +140,11 @@ if(isset($criterias['totals']) && $criterias['totals']==''){
|
||||
$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);
|
||||
|
||||
@@ -389,8 +389,8 @@ if (isset($post_content['sn']) && (isset($post_content['payload']) || isset($pos
|
||||
|
||||
// Create license
|
||||
$sql = 'INSERT INTO products_software_licenses
|
||||
(version_id, license_type, license_key, status, starts_at, expires_at, transaction_id, created, createdby)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
(version_id, license_type, license_key, status, starts_at, expires_at, transaction_id, accounthierarchy,created, createdby)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
$sw_version_consent,
|
||||
@@ -400,6 +400,7 @@ if (isset($post_content['sn']) && (isset($post_content['payload']) || isset($pos
|
||||
date('Y-m-d H:i:s'),
|
||||
'2099-12-31 23:59:59', // effectively permanent
|
||||
'Customer_consent',
|
||||
$account,
|
||||
date('Y-m-d H:i:s'),
|
||||
$user
|
||||
]);
|
||||
|
||||
@@ -25,12 +25,12 @@ $criterias = [];
|
||||
|
||||
//ADD STANDARD PARAMETERS TO ARRAY BASED ON INSERT OR UPDATE
|
||||
if ($command == 'update'){
|
||||
$post_content['updatedby'] = $username;;
|
||||
$post_content['updatedby'] = $username;
|
||||
$post_content['updated'] = $date;
|
||||
}
|
||||
elseif ($command == 'insert'){
|
||||
$post_content['created'] = $date;
|
||||
$post_content['createdby'] = $username;;
|
||||
$post_content['createdby'] = $username;
|
||||
}
|
||||
|
||||
//CREAT NEW ARRAY AND MAP TO CLAUSE
|
||||
|
||||
BIN
assets/.DS_Store
vendored
BIN
assets/.DS_Store
vendored
Binary file not shown.
222
assets/database/migration_profiles_to_rbac.sql
Normal file
222
assets/database/migration_profiles_to_rbac.sql
Normal file
@@ -0,0 +1,222 @@
|
||||
-- ===================================================
|
||||
-- PROFILE TO RBAC MIGRATION SCRIPT
|
||||
-- Date: 2025-01-22
|
||||
-- Description: Migrate from settingsprofiles.php to user_roles RBAC system
|
||||
-- Note: Uses existing access_elements table (already populated)
|
||||
-- ===================================================
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
-- ===================================================
|
||||
-- PHASE 1: CREATE ROLES (matching existing profiles)
|
||||
-- ===================================================
|
||||
|
||||
INSERT INTO `user_roles` (`name`, `description`, `is_active`, `created`, `createdby`) VALUES
|
||||
('Standard', 'Basic user access - view equipment, history, service reports', 1, NOW(), 1),
|
||||
('Superuser', 'Extended access - manage equipment, products, users', 1, NOW(), 1),
|
||||
('Admin', 'Administrative access - full management capabilities', 1, NOW(), 1),
|
||||
('AdminPlus', 'System administrator - complete system access', 1, NOW(), 1),
|
||||
('Build', 'Build tool access only', 1, NOW(), 1),
|
||||
('Commerce', 'E-commerce and catalog management', 1, NOW(), 1),
|
||||
('Distribution', 'Distribution partner access', 1, NOW(), 1),
|
||||
('Firmware', 'Firmware/software update access only', 1, NOW(), 1),
|
||||
('Garage', 'Car testing and diagnostics', 1, NOW(), 1),
|
||||
('Interface', 'API/Interface access', 1, NOW(), 1),
|
||||
('Service', 'Service technician access', 1, NOW(), 1),
|
||||
('Other', 'Miscellaneous access level', 1, NOW(), 1)
|
||||
ON DUPLICATE KEY UPDATE `description` = VALUES(`description`);
|
||||
|
||||
-- ===================================================
|
||||
-- PHASE 2: CREATE ROLE_ACCESS_PERMISSIONS MAPPINGS
|
||||
-- ===================================================
|
||||
|
||||
-- Get role IDs
|
||||
SET @role_standard = (SELECT rowID FROM user_roles WHERE name = 'Standard' LIMIT 1);
|
||||
SET @role_superuser = (SELECT rowID FROM user_roles WHERE name = 'Superuser' LIMIT 1);
|
||||
SET @role_admin = (SELECT rowID FROM user_roles WHERE name = 'Admin' LIMIT 1);
|
||||
SET @role_adminplus = (SELECT rowID FROM user_roles WHERE name = 'AdminPlus' LIMIT 1);
|
||||
SET @role_build = (SELECT rowID FROM user_roles WHERE name = 'Build' LIMIT 1);
|
||||
SET @role_commerce = (SELECT rowID FROM user_roles WHERE name = 'Commerce' LIMIT 1);
|
||||
SET @role_distribution = (SELECT rowID FROM user_roles WHERE name = 'Distribution' LIMIT 1);
|
||||
SET @role_firmware = (SELECT rowID FROM user_roles WHERE name = 'Firmware' LIMIT 1);
|
||||
SET @role_garage = (SELECT rowID FROM user_roles WHERE name = 'Garage' LIMIT 1);
|
||||
SET @role_interface = (SELECT rowID FROM user_roles WHERE name = 'Interface' LIMIT 1);
|
||||
SET @role_service = (SELECT rowID FROM user_roles WHERE name = 'Service' LIMIT 1);
|
||||
SET @role_other = (SELECT rowID FROM user_roles WHERE name = 'Other' LIMIT 1);
|
||||
|
||||
-- ===================================================
|
||||
-- STANDARD ROLE PERMISSIONS (Read-only)
|
||||
-- Profile: application,firmwaretool,histories,history,servicereport,servicereports,dashboard,profile,equipment,equipments,products_software
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_standard, rowID, 0, 1, 0, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'firmwaretool', 'histories', 'history', 'servicereport', 'servicereports',
|
||||
'dashboard', 'profile', 'equipment', 'equipments', 'products_software'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_read = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- SUPERUSER ROLE PERMISSIONS (Create, Read, Update)
|
||||
-- Profile: application,assets,firmwaretool,histories,history,history_manage,marketing,partner,partners,
|
||||
-- servicereport,servicereports,admin,dashboard,profile,equipment,equipment_manage,
|
||||
-- equipment_manage_edit,equipments,equipments_mass_update,product,product_manage,products,
|
||||
-- products_software,products_versions,user,user_manage,users
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_superuser, rowID, 1, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'firmwaretool', 'histories', 'history', 'history_manage',
|
||||
'marketing', 'partner', 'partners', 'servicereport', 'servicereports',
|
||||
'dashboard', 'profile', 'equipment', 'equipment_manage',
|
||||
'equipments', 'equipments_mass_update', 'product', 'product_manage', 'products',
|
||||
'products_software', 'products_versions', 'user', 'users'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- ADMIN ROLE PERMISSIONS (Full CRUD)
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_admin, rowID, 1, 1, 1, 1 FROM access_elements WHERE access_path IN (
|
||||
'application', 'buildtool', 'cartest', 'cartest_manage', 'cartests',
|
||||
'changelog', 'communication', 'communication_send', 'communications', 'firmwaretool',
|
||||
'histories', 'history', 'history_manage', 'marketing', 'partner', 'partners',
|
||||
'servicereport', 'servicereports', 'software_available', 'software_download',
|
||||
'software_update', 'softwaretool', 'account', 'accounts', 'dashboard', 'profile',
|
||||
'contract', 'contract_manage', 'contracts', 'equipment', 'equipment_data',
|
||||
'equipment_healthindex', 'equipment_history', 'equipment_manage',
|
||||
'equipments', 'equipments_mass_update', 'product', 'product_manage', 'products',
|
||||
'products_software', 'products_software_assignment', 'products_software_assignments',
|
||||
'products_software_licenses', 'products_versions', 'report_build',
|
||||
'report_contracts_billing', 'report_healthindex', 'rma', 'rma_history',
|
||||
'rma_manage', 'rmas', 'user', 'users'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1, can_delete = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- ADMINPLUS ROLE PERMISSIONS (Full access to everything)
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_adminplus, rowID, 1, 1, 1, 1 FROM access_elements WHERE is_active = 1
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1, can_delete = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- BUILD ROLE PERMISSIONS
|
||||
-- Profile: application,buildtool,firmwaretool,dashboard,profile,products_software
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_build, rowID, 1, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'buildtool', 'firmwaretool', 'dashboard', 'profile', 'products_software'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- COMMERCE ROLE PERMISSIONS
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_commerce, rowID, 1, 1, 1, 1 FROM access_elements WHERE access_path IN (
|
||||
'application', 'catalog', 'categories', 'category', 'checkout', 'discount', 'discounts',
|
||||
'identity', 'invoice', 'media', 'media_manage', 'order', 'orders', 'partner', 'partners',
|
||||
'placeorder', 'pricelists', 'pricelists_items', 'pricelists_manage', 'shipping',
|
||||
'shipping_manage', 'shopping_cart', 'taxes', 'transactions', 'transactions_items',
|
||||
'translation_manage', 'translations', 'translations_details', 'uploader',
|
||||
'dashboard', 'profile', 'product', 'product_manage', 'products', 'products_attributes',
|
||||
'products_attributes_items', 'products_attributes_manage', 'products_categories',
|
||||
'products_configurations', 'products_media', 'products_software', 'products_versions',
|
||||
'user', 'users'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1, can_delete = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- DISTRIBUTION ROLE PERMISSIONS
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_distribution, rowID, 1, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'firmwaretool', 'histories', 'history', 'history_manage',
|
||||
'marketing', 'partner', 'partners', 'servicereport', 'servicereports',
|
||||
'dashboard', 'profile', 'equipment', 'equipment_manage',
|
||||
'equipments', 'equipments_mass_update', 'product', 'product_manage', 'products',
|
||||
'products_software', 'products_versions', 'user', 'users'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- FIRMWARE ROLE PERMISSIONS
|
||||
-- Profile: application,software_available,software_download,software_update,softwaretool,
|
||||
-- transactions,transactions_items,products_software_versions
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_firmware, rowID, 0, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'software_available', 'software_download', 'software_update',
|
||||
'softwaretool', 'transactions', 'transactions_items', 'products_software_versions'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- GARAGE ROLE PERMISSIONS
|
||||
-- Profile: application,cartest,cartest_manage,cartests,dashboard,profile,products_versions
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_garage, rowID, 1, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'cartest', 'cartest_manage', 'cartests', 'dashboard', 'profile', 'products_versions'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- INTERFACE ROLE PERMISSIONS
|
||||
-- Profile: application,firmwaretool,invoice,payment,transactions,transactions_items,
|
||||
-- contract,contracts,equipment_manage,equipments,products_software,products_versions,users
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_interface, rowID, 1, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'firmwaretool', 'invoice', 'payment', 'transactions', 'transactions_items',
|
||||
'contract', 'contracts', 'equipment_manage', 'equipments', 'products_software',
|
||||
'products_versions', 'users'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- SERVICE ROLE PERMISSIONS
|
||||
-- Profile: application,assets,firmwaretool,histories,history,history_manage,marketing,partner,partners,
|
||||
-- servicereport,servicereports,admin,dashboard,profile,equipment,equipment_manage,equipments,
|
||||
-- products_software,user,user_manage,users
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_service, rowID, 1, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'firmwaretool', 'histories', 'history', 'history_manage',
|
||||
'marketing', 'partner', 'partners', 'servicereport', 'servicereports',
|
||||
'dashboard', 'profile', 'equipment', 'equipment_manage', 'equipments', 'products_software',
|
||||
'user', 'users'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_create = 1, can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- OTHER ROLE PERMISSIONS
|
||||
-- Profile: application,assets,firmwaretool,histories,history,history_manage,marketing,partner,partners,
|
||||
-- servicereport,servicereports,admin,dashboard,profile,equipment,equipment_manage,equipments,products_software
|
||||
-- ===================================================
|
||||
INSERT INTO `role_access_permissions` (`role_id`, `access_id`, `can_create`, `can_read`, `can_update`, `can_delete`)
|
||||
SELECT @role_other, rowID, 0, 1, 1, 0 FROM access_elements WHERE access_path IN (
|
||||
'application', 'firmwaretool', 'histories', 'history', 'history_manage',
|
||||
'marketing', 'partner', 'partners', 'servicereport', 'servicereports',
|
||||
'dashboard', 'profile', 'equipment', 'equipment_manage', 'equipments', 'products_software'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE can_read = 1, can_update = 1;
|
||||
|
||||
-- ===================================================
|
||||
-- VERIFICATION QUERIES
|
||||
-- ===================================================
|
||||
|
||||
-- Check roles created
|
||||
SELECT rowID, name, description, is_active FROM user_roles ORDER BY rowID;
|
||||
|
||||
-- Check permissions per role
|
||||
SELECT ur.name as role_name, COUNT(rap.rowID) as permission_count
|
||||
FROM user_roles ur
|
||||
LEFT JOIN role_access_permissions rap ON ur.rowID = rap.role_id
|
||||
GROUP BY ur.rowID, ur.name
|
||||
ORDER BY ur.rowID;
|
||||
|
||||
-- ===================================================
|
||||
-- Change ROLLBACK to COMMIT when ready to apply
|
||||
-- ===================================================
|
||||
COMMIT;
|
||||
228
assets/database/migration_users_to_rbac.sql
Normal file
228
assets/database/migration_users_to_rbac.sql
Normal file
@@ -0,0 +1,228 @@
|
||||
-- ===================================================
|
||||
-- USER TO RBAC ROLE ASSIGNMENT MIGRATION SCRIPT
|
||||
-- Date: 2025-01-22
|
||||
-- Description: Migrate users from settings/view fields to user_role_assignments
|
||||
-- Prerequisites: Run migration_profiles_to_rbac.sql first to create roles
|
||||
-- ===================================================
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
-- ===================================================
|
||||
-- MAPPING REFERENCE:
|
||||
--
|
||||
-- users.settings field values -> role names:
|
||||
-- 'standard_profile' or empty with view 0-2 -> Standard
|
||||
-- 'superuser_profile' or view=2 -> Superuser
|
||||
-- 'admin_profile' or view=4 -> Admin
|
||||
-- 'adminplus_profile' or view=5 -> AdminPlus
|
||||
-- 'build' -> Build
|
||||
-- 'commerce' -> Commerce
|
||||
-- 'distribution' -> Distribution
|
||||
-- 'firmware' -> Firmware
|
||||
-- 'garage' -> Garage
|
||||
-- 'interface' -> Interface
|
||||
-- 'service' -> Service
|
||||
-- 'other' -> Other
|
||||
--
|
||||
-- users.view field (legacy permission level):
|
||||
-- 1 = SuperUser
|
||||
-- 2 = Create & Update
|
||||
-- 3 = Read-only
|
||||
-- 4 = Admin
|
||||
-- 5 = Admin+
|
||||
-- ===================================================
|
||||
|
||||
-- Get role IDs
|
||||
SET @role_standard = (SELECT rowID FROM user_roles WHERE name = 'Standard' LIMIT 1);
|
||||
SET @role_superuser = (SELECT rowID FROM user_roles WHERE name = 'Superuser' LIMIT 1);
|
||||
SET @role_admin = (SELECT rowID FROM user_roles WHERE name = 'Admin' LIMIT 1);
|
||||
SET @role_adminplus = (SELECT rowID FROM user_roles WHERE name = 'AdminPlus' LIMIT 1);
|
||||
SET @role_build = (SELECT rowID FROM user_roles WHERE name = 'Build' LIMIT 1);
|
||||
SET @role_commerce = (SELECT rowID FROM user_roles WHERE name = 'Commerce' LIMIT 1);
|
||||
SET @role_distribution = (SELECT rowID FROM user_roles WHERE name = 'Distribution' LIMIT 1);
|
||||
SET @role_firmware = (SELECT rowID FROM user_roles WHERE name = 'Firmware' LIMIT 1);
|
||||
SET @role_garage = (SELECT rowID FROM user_roles WHERE name = 'Garage' LIMIT 1);
|
||||
SET @role_interface = (SELECT rowID FROM user_roles WHERE name = 'Interface' LIMIT 1);
|
||||
SET @role_service = (SELECT rowID FROM user_roles WHERE name = 'Service' LIMIT 1);
|
||||
SET @role_other = (SELECT rowID FROM user_roles WHERE name = 'Other' LIMIT 1);
|
||||
|
||||
-- ===================================================
|
||||
-- PHASE 1: MIGRATE USERS BY SETTINGS FIELD (profile name)
|
||||
-- ===================================================
|
||||
|
||||
-- Users with 'standard_profile' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_standard, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'standard_profile'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'superuser_profile' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_superuser, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'superuser_profile'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'admin_profile' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_admin, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'admin_profile'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'adminplus_profile' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_adminplus, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'adminplus_profile'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'build' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_build, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'build'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'commerce' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_commerce, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'commerce'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'distribution' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_distribution, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'distribution'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'firmware' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_firmware, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'firmware'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'garage' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_garage, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'garage'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'interface' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_interface, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'interface'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'service' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_service, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'service'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with 'other' setting
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT id, @role_other, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users
|
||||
WHERE settings = 'other'
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- ===================================================
|
||||
-- PHASE 2: MIGRATE USERS WITH EMPTY/NULL SETTINGS (use view field)
|
||||
-- Only for users not already assigned a role
|
||||
-- ===================================================
|
||||
|
||||
-- Users with view=5 (Admin+) and no settings
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT u.id, @role_adminplus, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users u
|
||||
LEFT JOIN user_role_assignments ura ON u.id = ura.user_id AND ura.is_active = 1
|
||||
WHERE (u.settings IS NULL OR u.settings = '')
|
||||
AND u.view = '5'
|
||||
AND ura.rowID IS NULL
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with view=4 (Admin) and no settings
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT u.id, @role_admin, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users u
|
||||
LEFT JOIN user_role_assignments ura ON u.id = ura.user_id AND ura.is_active = 1
|
||||
WHERE (u.settings IS NULL OR u.settings = '')
|
||||
AND u.view = '4'
|
||||
AND ura.rowID IS NULL
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with view=1 (SuperUser) and no settings
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT u.id, @role_superuser, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users u
|
||||
LEFT JOIN user_role_assignments ura ON u.id = ura.user_id AND ura.is_active = 1
|
||||
WHERE (u.settings IS NULL OR u.settings = '')
|
||||
AND u.view = '1'
|
||||
AND ura.rowID IS NULL
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- Users with view=2 or view=3 (Create/Update or Read-only) and no settings -> Standard
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT u.id, @role_standard, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users u
|
||||
LEFT JOIN user_role_assignments ura ON u.id = ura.user_id AND ura.is_active = 1
|
||||
WHERE (u.settings IS NULL OR u.settings = '')
|
||||
AND u.view IN ('2', '3')
|
||||
AND ura.rowID IS NULL
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- ===================================================
|
||||
-- PHASE 3: CATCH-ALL - Any remaining users without role -> Standard
|
||||
-- ===================================================
|
||||
|
||||
INSERT INTO `user_role_assignments` (`user_id`, `role_id`, `is_active`, `assigned_by`, `assigned_at`, `created`, `createdby`)
|
||||
SELECT u.id, @role_standard, 1, 'migration_script', NOW(), NOW(), 1
|
||||
FROM users u
|
||||
LEFT JOIN user_role_assignments ura ON u.id = ura.user_id AND ura.is_active = 1
|
||||
WHERE ura.rowID IS NULL
|
||||
ON DUPLICATE KEY UPDATE updated = NOW();
|
||||
|
||||
-- ===================================================
|
||||
-- VERIFICATION QUERIES
|
||||
-- ===================================================
|
||||
|
||||
-- Check migration results: users per role
|
||||
SELECT
|
||||
ur.name as role_name,
|
||||
COUNT(ura.user_id) as user_count
|
||||
FROM user_roles ur
|
||||
LEFT JOIN user_role_assignments ura ON ur.rowID = ura.role_id AND ura.is_active = 1
|
||||
GROUP BY ur.rowID, ur.name
|
||||
ORDER BY user_count DESC;
|
||||
|
||||
-- Check for users without role assignments (should be 0)
|
||||
SELECT COUNT(*) as users_without_role
|
||||
FROM users u
|
||||
LEFT JOIN user_role_assignments ura ON u.id = ura.user_id AND ura.is_active = 1
|
||||
WHERE ura.rowID IS NULL;
|
||||
|
||||
-- Compare old vs new: show users with their old settings and new role
|
||||
SELECT
|
||||
u.id,
|
||||
u.username,
|
||||
u.settings as old_profile,
|
||||
u.view as old_view_level,
|
||||
ur.name as new_role
|
||||
FROM users u
|
||||
LEFT JOIN user_role_assignments ura ON u.id = ura.user_id AND ura.is_active = 1
|
||||
LEFT JOIN user_roles ur ON ura.role_id = ur.rowID
|
||||
ORDER BY u.id
|
||||
LIMIT 50;
|
||||
|
||||
-- ===================================================
|
||||
-- Change ROLLBACK to COMMIT when ready to apply
|
||||
-- ===================================================
|
||||
COMMIT;
|
||||
@@ -519,6 +519,15 @@ echo <<<EOT
|
||||
// Intercept fetch and XMLHttpRequest
|
||||
interceptNetworkRequests();
|
||||
|
||||
// Intercept form submissions to show loading
|
||||
function setupFormInterception() {
|
||||
document.querySelectorAll('form').forEach(function(form) {
|
||||
form.addEventListener('submit', function() {
|
||||
showLoading();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Intercept all network requests (fetch and XMLHttpRequest)
|
||||
function interceptNetworkRequests() {
|
||||
// Track active requests
|
||||
@@ -1637,42 +1646,25 @@ function getProfile($profile, $permission){
|
||||
|
||||
// Always allowed collections: [collection => allowed_actions_string]
|
||||
$always_allowed = [
|
||||
'com_log' => 'U',
|
||||
'com_log' => 'CRU',
|
||||
'application' => 'CRU',
|
||||
'user_permissions' => 'R',
|
||||
'software_update' => 'R',
|
||||
'software_download' => 'R',
|
||||
'software_available' => 'R',
|
||||
'history' => 'U',
|
||||
'payment' => 'U',
|
||||
'marketing_files' => 'CRUD',
|
||||
'marketing_folders' => 'CRUD',
|
||||
'marketing_tags' => 'CRUD',
|
||||
'marketing_upload' => 'CRUD',
|
||||
'marketing_delete' => 'CRUD'
|
||||
'history' => 'RU',
|
||||
'payment' => 'U'
|
||||
];
|
||||
|
||||
// Debug log - initial call
|
||||
if(debug){
|
||||
$perm_count = is_array($permissions) ? count($permissions) : 'not_array';
|
||||
$test = "$date - isAllowed called: access_element=$access_element, basic_permission_level=$basic_permission_level, action=$action, permissions_count=$perm_count".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
}
|
||||
|
||||
// 1. Check if basic_permission_level is 4 (System-admin+) - always allow
|
||||
if ($basic_permission_level !== null && $basic_permission_level == 4) {
|
||||
if(debug){
|
||||
$test = "$date - Allowed by system permission (level 5)".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2. Check always_allowed list
|
||||
if (isset($always_allowed[$access_element]) && str_contains($always_allowed[$access_element], $action)) {
|
||||
if(debug){
|
||||
$test = "$date - Allowed by always_allowed list".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1691,20 +1683,21 @@ function getProfile($profile, $permission){
|
||||
$permission_key = $action_map[$action] ?? null;
|
||||
|
||||
if ($permission_key && isset($element_permissions[$permission_key]) && $element_permissions[$permission_key] == 1) {
|
||||
if(debug){
|
||||
$test = "$date - Allowed by RBAC permissions: $access_element -> $permission_key = 1".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(debug){
|
||||
$test = "$date - isAllowed called: access_element=$access_element, basic_permission_level=$basic_permission_level, action=$action".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
$perm_value = $element_permissions[$permission_key] ?? 'not_set';
|
||||
$test = "$date - RBAC check failed: $access_element -> $permission_key = $perm_value".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
}
|
||||
} else {
|
||||
if(debug){
|
||||
$test = "$date - isAllowed called: access_element=$access_element, basic_permission_level=$basic_permission_level, action=$action".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
$test = "$date - Access element '$access_element' not found in permissions array".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
}
|
||||
@@ -1712,9 +1705,12 @@ function getProfile($profile, $permission){
|
||||
|
||||
// Not allowed
|
||||
if(debug){
|
||||
$test = "$date - isAllowed called: access_element=$access_element, basic_permission_level=$basic_permission_level, action=$action".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
$test = "$date - Not allowed: access_element=$access_element, action=$action".PHP_EOL;
|
||||
error_log($test, 3, $filelocation);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3913,6 +3909,8 @@ function dateInRange($start_date, $end_date, $date_check)
|
||||
|
||||
function getLatestVersion($productcode,$token){
|
||||
|
||||
//$pdo = dbConnect($dbname);
|
||||
|
||||
//CALL TO API TO GET ALL ACTIVE CONTRACTS
|
||||
$api_url = '/v2/products_software/productcode='.$productcode;
|
||||
$responses = ioAPIv2($api_url,'',$token);
|
||||
|
||||
@@ -249,10 +249,14 @@ class MarketingFileManager {
|
||||
emptyState.style.display = 'none';
|
||||
|
||||
try {
|
||||
// Use proper folder ID (null for root, or the folder ID)
|
||||
const folderId = this.currentFolder ? this.currentFolder : 'null';
|
||||
// Add cache busting to prevent browser caching
|
||||
let url = `index.php?page=marketing&action=marketing_files&folder_id=${folderId}&limit=50&_t=${Date.now()}`;
|
||||
let url = `index.php?page=marketing&action=marketing_files&limit=50&_t=${Date.now()}`;
|
||||
|
||||
// Only filter by folder if no tag filter is active (tag search is across all folders)
|
||||
if (!this.filters.tag) {
|
||||
const folderId = this.currentFolder ? this.currentFolder : 'null';
|
||||
url += `&folder_id=${folderId}`;
|
||||
}
|
||||
|
||||
if (this.filters.search) {
|
||||
url += `&search=${encodeURIComponent(this.filters.search)}`;
|
||||
@@ -298,13 +302,25 @@ class MarketingFileManager {
|
||||
}
|
||||
|
||||
if (files.length === 0) {
|
||||
// No files after filtering, check for subfolders
|
||||
const subfolders = this.getSubfolders(this.currentFolder);
|
||||
if (subfolders.length > 0) {
|
||||
this.renderFolderTiles(subfolders);
|
||||
} else {
|
||||
emptyState.style.display = 'block';
|
||||
}
|
||||
} else {
|
||||
this.renderFiles(files);
|
||||
}
|
||||
} else {
|
||||
// No files, check for subfolders
|
||||
const subfolders = this.getSubfolders(this.currentFolder);
|
||||
if (subfolders.length > 0) {
|
||||
this.renderFolderTiles(subfolders);
|
||||
} else {
|
||||
emptyState.style.display = 'block';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading files:', error);
|
||||
this.showToast('Error loading files', 'error');
|
||||
@@ -379,13 +395,74 @@ class MarketingFileManager {
|
||||
});
|
||||
}
|
||||
|
||||
getSubfolders(folderId) {
|
||||
// Find immediate children of the specified folder
|
||||
if (!folderId || folderId === '') {
|
||||
// Root folder - return top-level folders
|
||||
return this.folders;
|
||||
}
|
||||
|
||||
// Recursively search for the folder and return its children
|
||||
const findFolder = (folders, targetId) => {
|
||||
for (const folder of folders) {
|
||||
if (folder.id === targetId) {
|
||||
return folder.children || [];
|
||||
}
|
||||
if (folder.children && folder.children.length > 0) {
|
||||
const found = findFolder(folder.children, targetId);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
return findFolder(this.folders, folderId);
|
||||
}
|
||||
|
||||
renderFolderTiles(subfolders) {
|
||||
const container = document.getElementById('filesContainer');
|
||||
container.innerHTML = '';
|
||||
|
||||
subfolders.forEach(folder => {
|
||||
const folderElement = this.createFolderTileElement(folder);
|
||||
container.appendChild(folderElement);
|
||||
});
|
||||
}
|
||||
|
||||
createFolderTileElement(folder) {
|
||||
const folderElement = document.createElement('div');
|
||||
folderElement.className = `folder-tile ${this.viewMode}-item`;
|
||||
folderElement.setAttribute('data-folder-id', folder.id);
|
||||
|
||||
folderElement.innerHTML = `
|
||||
<div class="folder-tile-icon">
|
||||
<i class="fa fa-folder"></i>
|
||||
</div>
|
||||
<div class="folder-tile-info">
|
||||
<div class="folder-tile-name" title="${this.escapeHtml(folder.folder_name)}">
|
||||
${this.escapeHtml(folder.folder_name)}
|
||||
</div>
|
||||
<div class="folder-tile-meta">
|
||||
<span class="folder-file-count">${folder.file_count || 0} files</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Click to navigate to folder
|
||||
folderElement.addEventListener('click', () => {
|
||||
this.selectFolder(folder.id);
|
||||
});
|
||||
|
||||
return folderElement;
|
||||
}
|
||||
|
||||
createFileElement(file) {
|
||||
const fileElement = document.createElement('div');
|
||||
fileElement.className = `file-item ${this.viewMode}-item`;
|
||||
fileElement.setAttribute('data-file-id', file.id);
|
||||
|
||||
const thumbnail = this.getThumbnail(file);
|
||||
const tags = file.tags.map(tag => `<span class="tag">${this.escapeHtml(tag)}</span>`).join('');
|
||||
const tags = file.tags.map(tag => `<span class="tag clickable" data-tag="${this.escapeHtml(tag)}">${this.escapeHtml(tag)}</span>`).join('');
|
||||
|
||||
fileElement.innerHTML = `
|
||||
<div class="file-thumbnail">
|
||||
@@ -430,6 +507,15 @@ class MarketingFileManager {
|
||||
this.editFile(file);
|
||||
});
|
||||
|
||||
// Make tags clickable to filter by tag
|
||||
fileElement.querySelectorAll('.tag.clickable').forEach(tagElement => {
|
||||
tagElement.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const tagName = tagElement.getAttribute('data-tag');
|
||||
this.filterByTag(tagName);
|
||||
});
|
||||
});
|
||||
|
||||
fileElement.addEventListener('dblclick', () => {
|
||||
this.previewFile(file);
|
||||
});
|
||||
@@ -852,6 +938,32 @@ class MarketingFileManager {
|
||||
this.loadFiles();
|
||||
}
|
||||
|
||||
filterByTag(tagName) {
|
||||
// Set the tag filter
|
||||
this.filters.tag = tagName;
|
||||
|
||||
// Update the dropdown to show the selected tag
|
||||
const tagSelect = document.getElementById('tagFilter');
|
||||
if (tagSelect) {
|
||||
tagSelect.value = tagName;
|
||||
}
|
||||
|
||||
// Clear folder selection to search across all folders
|
||||
this.currentFolder = '';
|
||||
|
||||
// Update folder tree UI to show root as active
|
||||
document.querySelectorAll('.folder-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
const rootFolder = document.querySelector('.folder-item.root');
|
||||
if (rootFolder) {
|
||||
rootFolder.classList.add('active');
|
||||
}
|
||||
|
||||
// Reload files with the tag filter
|
||||
this.loadFiles();
|
||||
}
|
||||
|
||||
populateTagFilter(tags) {
|
||||
const select = document.getElementById('tagFilter');
|
||||
select.innerHTML = '<option value="">All Tags</option>';
|
||||
|
||||
@@ -100,6 +100,45 @@ if (document.readyState === 'loading') {
|
||||
checkBrowserCompatibility();
|
||||
}
|
||||
|
||||
// Shared serial port reference for upload.js to use
|
||||
window.sharedSerialPort = null;
|
||||
|
||||
// Override requestPort to minimize user prompts
|
||||
// This intercepts all requestPort calls (including from upload.js) to reuse authorized ports
|
||||
if ('serial' in navigator) {
|
||||
const originalRequestPort = navigator.serial.requestPort.bind(navigator.serial);
|
||||
|
||||
navigator.serial.requestPort = async function(options) {
|
||||
// If we have a shared port, return it instead of prompting
|
||||
if (window.sharedSerialPort) {
|
||||
console.log('Using shared serial port (no prompt needed)');
|
||||
return window.sharedSerialPort;
|
||||
}
|
||||
|
||||
// Try already-authorized ports matching the filters
|
||||
const ports = await navigator.serial.getPorts();
|
||||
if (ports.length > 0 && options?.filters) {
|
||||
const match = ports.find(p => {
|
||||
const info = p.getInfo();
|
||||
return options.filters.some(f =>
|
||||
info.usbVendorId === f.usbVendorId &&
|
||||
info.usbProductId === f.usbProductId
|
||||
);
|
||||
});
|
||||
if (match) {
|
||||
console.log('Using previously authorized port (no prompt needed)');
|
||||
window.sharedSerialPort = match;
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: original prompt behavior
|
||||
const port = await originalRequestPort(options);
|
||||
window.sharedSerialPort = port; // Store for future use
|
||||
return port;
|
||||
};
|
||||
}
|
||||
|
||||
// Function to log communication to API (reused from scripts.js)
|
||||
async function logCommunication(data, direction) {
|
||||
// Only log if debug mode is enabled
|
||||
@@ -400,7 +439,11 @@ async function closePortAfterRead() {
|
||||
await port.close();
|
||||
await logCommunication('Port closed successfully', 'info');
|
||||
|
||||
// Reset for next connection
|
||||
// Keep port reference in sharedSerialPort for upload.js to reuse
|
||||
// This prevents the need for another user prompt during firmware upload
|
||||
window.sharedSerialPort = port;
|
||||
|
||||
// Reset local variables for next connection
|
||||
reader = null;
|
||||
writer = null;
|
||||
readableStreamClosed = null;
|
||||
@@ -410,7 +453,12 @@ async function closePortAfterRead() {
|
||||
console.error('Error closing port after read:', error);
|
||||
await logCommunication(`Error closing port: ${error.message}`, 'error');
|
||||
|
||||
// Force reset even on error
|
||||
// Keep port reference even on error if port exists
|
||||
if (port) {
|
||||
window.sharedSerialPort = port;
|
||||
}
|
||||
|
||||
// Force reset local variables even on error
|
||||
reader = null;
|
||||
writer = null;
|
||||
readableStreamClosed = null;
|
||||
|
||||
@@ -440,9 +440,15 @@ $view .= '<div class="content-block">
|
||||
<td>'.getRelativeTime($responses->created).'</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:25%;">'.$general_updated.'</td>
|
||||
<td><a href="#" onclick="openLogModal(); return false;" class="link-with-icon">'.getRelativeTime($responses->updated).'<i class="fa-solid fa-up-right-from-square"></i></a></td>
|
||||
</tr>
|
||||
<td style="width:25%;">'.$general_updated.'</td>';
|
||||
|
||||
if ($update_allowed === 1){
|
||||
$view .= '<td><a href="#" onclick="openLogModal(); return false;" class="link-with-icon">'.getRelativeTime($responses->updated).'<i class="fa-solid fa-up-right-from-square"></i></a></td>';
|
||||
} else {
|
||||
$view .= '<td>'.getRelativeTime($responses->updated).'</td>';
|
||||
}
|
||||
|
||||
$view .= ' </tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -104,7 +104,7 @@ if (isset($_POST['email_invoice'])) {
|
||||
$attachment = $dompdf->output();
|
||||
$attachment_name = $file_name . '.pdf';
|
||||
|
||||
$header_redirect = 'Location: index.php?page=order&id=' . $order_id . '&success=invoice_sent';
|
||||
$header_redirect = 'Location: index.php?page=order&txn_id=' . $order_id . '&success=invoice_sent';
|
||||
|
||||
// Send to PHPMailer
|
||||
send_mail($to, $subject, $message, $attachment, $attachment_name);
|
||||
@@ -120,7 +120,7 @@ if (isset($_POST['email_invoice_to_admin'])) {
|
||||
$attachment = $dompdf->output();
|
||||
$attachment_name = $file_name . '.pdf';
|
||||
|
||||
$header_redirect = 'Location: index.php?page=order&id=' . $order_id . '&success=invoice_sent_admin';
|
||||
$header_redirect = 'Location: index.php?page=order&txn_id=' . $order_id . '&success=invoice_sent_admin';
|
||||
|
||||
// Send to bookkeeping if configured
|
||||
if (invoice_bookkeeping && email_bookkeeping) {
|
||||
@@ -144,7 +144,7 @@ if (isset($_GET['show_invoice'])) {
|
||||
}
|
||||
|
||||
// If no action specified, redirect back
|
||||
header('Location: index.php?page=order&id=' . $order_number);
|
||||
header('Location: index.php?page=order&txn_id=' . $order_number);
|
||||
exit;
|
||||
|
||||
?>
|
||||
43
index.php
43
index.php
@@ -106,23 +106,28 @@ if (isset($_GET['page']) && $_GET['page'] == 'logout') {
|
||||
die();
|
||||
}
|
||||
|
||||
//=====================================
|
||||
//DEFINE WHERE TO SEND THE USER TO. GET first assigned view in the profile if not available use dashboard
|
||||
/*=====================================
|
||||
$allowed_views = explode(',',$_SESSION['authorization']['profile']);
|
||||
$ignoreViews = ['profile','assets','sales'];
|
||||
|
||||
// If dashboard is in the profile, prioritize it
|
||||
if (in_array('dashboard', $allowed_views) && file_exists('dashboard.php')) {
|
||||
$allowed_views = 'dashboard';
|
||||
} else {
|
||||
$allowed_views = findExistingView($allowed_views, 'dashboard', $ignoreViews);
|
||||
}
|
||||
*/
|
||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// SIMPLE ROUTING SYSTEM
|
||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
$page = $_GET['page'] ?? 'dashboard';
|
||||
if (isset($_GET['page'])) {
|
||||
$page = $_GET['page'];
|
||||
} else {
|
||||
// Get first available page from user's permissions using the menu structure
|
||||
$default_page = null;
|
||||
if (!empty($_SESSION['authorization']['permissions'])) {
|
||||
include_once dirname(__FILE__).'/settings/settingsmenu.php';
|
||||
$filteredMenu = filterMenuByPermissions($main_menu, $_SESSION['authorization']['permissions']);
|
||||
|
||||
// Get first menu item's URL as default page
|
||||
foreach ($filteredMenu as $section) {
|
||||
if (isset($section['main_menu']['url'])) {
|
||||
$default_page = $section['main_menu']['url'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$page = $default_page ?? 'dashboard';
|
||||
}
|
||||
|
||||
// Sanitize page parameter to prevent directory traversal
|
||||
$page = preg_replace('/[^a-zA-Z0-9_-]/', '', $page);
|
||||
@@ -135,10 +140,6 @@ try {
|
||||
$file_exists = file_exists($page_file);
|
||||
$is_allowed = $file_exists ? isAllowed($page, $_SESSION['authorization']['permissions'], $_SESSION['authorization']['permission'], 'R') : 0;
|
||||
|
||||
if (debug) {
|
||||
debuglog("Routing: page={$page}, file_exists={$file_exists}, is_allowed={$is_allowed}");
|
||||
}
|
||||
|
||||
if ($file_exists && $is_allowed !== 0) {
|
||||
include $page_file;
|
||||
} else {
|
||||
@@ -166,9 +167,6 @@ try {
|
||||
<i class="' . $error_icon . '"></i>
|
||||
</div>
|
||||
<p style="color: var(--gray-500, #6b7280); margin-bottom: 30px;">Please check the URL or navigate using the menu.</p>
|
||||
<a href="index.php?page=dashboard" class="btn">
|
||||
<i class="fa-solid fa-house"></i> Return to Dashboard
|
||||
</a>
|
||||
</div>';
|
||||
template_footer();
|
||||
}
|
||||
@@ -195,9 +193,6 @@ try {
|
||||
</div>
|
||||
<p style="color: var(--gray-500, #6b7280); margin-bottom: 30px;">Please try again or contact the system administrator.</p>
|
||||
<div style="display: flex; gap: 10px; justify-content: center;">
|
||||
<a href="index.php?page=dashboard" class="btn">
|
||||
<i class="fa-solid fa-house"></i> Return to Dashboard
|
||||
</a>
|
||||
<button onclick="location.reload()" class="btn">
|
||||
<i class="fa-solid fa-rotate-right"></i> Reload Page
|
||||
</button>
|
||||
|
||||
13
login.php
13
login.php
@@ -79,12 +79,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
//Decode Payload
|
||||
if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = '400';}
|
||||
|
||||
if ($responses === 'NOK'){
|
||||
if ($responses === 'NOK' || $responses === 'NULL' || $responses === 'NULL '){
|
||||
$retry++;
|
||||
$password_err = $password_err_1 ?? 'Not authorized, please retry';
|
||||
} elseif ($responses == '1'){
|
||||
$password_err = $password_err_2 ?? 'Too many login attempts. User blocked, please contact your administrator';
|
||||
} else {
|
||||
} elseif (!empty($responses['userkey']) && ctype_xdigit($responses['userkey'])) {
|
||||
// Start a new session
|
||||
session_start();
|
||||
|
||||
@@ -93,14 +93,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$_SESSION['authorization'] = $responses;
|
||||
|
||||
$language_user = trim($_SESSION['authorization']['language']) ?? 'US';
|
||||
if($responses->profile == 'firmwaretool,products_software,application'){
|
||||
header('location: index.php?page=firmwaretool');
|
||||
|
||||
header('location: index.php?language='.$language_user.'');
|
||||
exit();
|
||||
|
||||
} else {
|
||||
header('location: index.php?language='.$language_user.'');
|
||||
exit();
|
||||
}
|
||||
$retry++;
|
||||
$password_err = $password_err_1 ?? 'Not authorized, please retry';
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -85,7 +85,7 @@ $view = '
|
||||
//
|
||||
//------------------------------------
|
||||
if ($update_allowed_edit === 1){
|
||||
$view .= '<a href="index.php?page=order_manage&id='.$_GET['id'].'" class="btn">✏️</a>';
|
||||
$view .= '<a href="index.php?page=order_manage&id='.$order['header']['id'].'" class="btn">✏️</a>';
|
||||
}
|
||||
|
||||
$view .= '</div>';
|
||||
@@ -310,7 +310,7 @@ $view .='
|
||||
<i class="fa-solid fa-bars fa-sm"></i>Giftcards
|
||||
</div>
|
||||
<div class="table order-table">
|
||||
<a href="index.php?page=order&id=' . $_GET['id'] . '&add_giftcard" class="btn">Relate giftcards</a>
|
||||
<a href="index.php?page=order&id=' . $order['header']['id'] . '&add_giftcard" class="btn">Relate giftcards</a>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -17,6 +17,7 @@ if (isAllowed($page,$_SESSION['authorization']['permissions'],$_SESSION['authori
|
||||
exit;
|
||||
}
|
||||
//PAGE Security
|
||||
$page = 'partner';
|
||||
$update_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'U');
|
||||
$delete_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'D');
|
||||
$create_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'C');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
//=================================================================
|
||||
//Software version SERVICE Tool====================================
|
||||
//=================================================================
|
||||
/*=================================================================
|
||||
$latest_version = getLatestVersion('EPSK01',$clientsecret) ?? '';
|
||||
|
||||
$service_tool_current_version = ($latest_version !='') ? $latest_version['version'] : '';
|
||||
@@ -11,7 +11,7 @@ $software_download_url = 'https://'.$_SERVER['SERVER_NAME'].'/firmware'.'/';
|
||||
|
||||
//getSoftware (legacy)
|
||||
$software_url = ($latest_version !='') ? $latest_version['source'] : 'https://'.$_SERVER['SERVER_NAME'].'/firmware'.'/'.$service_tool_current_filename;
|
||||
|
||||
*/
|
||||
//=================================================================
|
||||
//SERVICE Tool manual ===================================
|
||||
//=================================================================
|
||||
@@ -90,9 +90,9 @@ $init = array(
|
||||
"ManualURL"=> $manual_url,
|
||||
"termsURL"=> "https://emergency-plug.com/en/terms-and-conditions",
|
||||
"Application" => array(
|
||||
"current_version" => $service_tool_current_version,
|
||||
"current_filename" => $service_tool_current_filename,
|
||||
"location" => $software_download_url
|
||||
"current_version" => '',
|
||||
"current_filename" => '',
|
||||
"location" => ''
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -197,14 +197,10 @@ $view .= '
|
||||
</div>';
|
||||
|
||||
|
||||
if (isset($_GET['equipmentID'])){$returnpage = 'equipment&equipmentID='.$_GET['equipmentID']; } else {$returnpage = 'dashboard';}
|
||||
|
||||
|
||||
//SHOW BACK BUTTON ONLY FOR PORTAL USERS
|
||||
if (isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'R') != 0){
|
||||
$view .= '
|
||||
<div class="title-actions">
|
||||
<a href="index.php?page='.$returnpage.'" class="btn alt mar-right-2"><i class="fa-solid fa-arrow-left"></i></a>
|
||||
<button class="btn" onclick="showInstructions()" style="">
|
||||
<i class="fa-solid fa-circle-question"></i>
|
||||
</button>
|
||||
|
||||
@@ -591,6 +591,8 @@ main .content-block-wrapper .content-block {
|
||||
width: 100%;
|
||||
margin: 0 10px;
|
||||
border-radius: 3px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
main .content-block-wrapper .content-block:first-child {
|
||||
@@ -3140,6 +3142,61 @@ main .content-block .button-container {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
/* Generic Modal Styles */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal .modal-content {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
margin: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.modal .modal-header {
|
||||
padding: 20px 25px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.modal .modal-header h3 {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.modal .modal-body {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.modal .modal-body p {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.btn.danger {
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn.danger:hover {
|
||||
background-color: #c0392b;
|
||||
}
|
||||
|
||||
/* Registration Modal Styles */
|
||||
|
||||
.reg-modal {
|
||||
|
||||
@@ -402,6 +402,94 @@
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.tag.clickable {
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.tag.clickable:hover {
|
||||
background: var(--color-primary, #007cba);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Folder Tiles */
|
||||
.folder-tile {
|
||||
background: var(--color-white, #fff);
|
||||
border: 1px solid var(--color-border, #dee2e6);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.folder-tile:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--color-primary, #005655);
|
||||
}
|
||||
|
||||
.folder-tile.grid-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.folder-tile.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.folder-tile-icon {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-light-grey, #f8f9fa);
|
||||
border-radius: 4px;
|
||||
font-size: 4rem;
|
||||
color: var(--color-primary, #005655);
|
||||
}
|
||||
|
||||
.folder-tile.list-item .folder-tile-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
flex-shrink: 0;
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.folder-tile-info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.folder-tile.list-item .folder-tile-info {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.folder-tile-name {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.folder-tile-meta {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-light, #6c757d);
|
||||
}
|
||||
|
||||
.folder-tile.list-item .folder-tile-meta {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
/* Loading and Empty States */
|
||||
.loading-indicator, .empty-state {
|
||||
display: flex;
|
||||
|
||||
216
user.php
216
user.php
@@ -12,33 +12,25 @@ 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['authorization']['permissions'],$_SESSION['authorization']['permission'],'R') === 0){
|
||||
header('location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
//PAGE Security
|
||||
$page_manage = 'user_manage';
|
||||
$update_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'U');
|
||||
$update_allowed_edit = isAllowed($page_manage ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'U');
|
||||
$delete_allowed = isAllowed($page_manage ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'D');
|
||||
$create_allowed = isAllowed($page_manage ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'C');
|
||||
|
||||
//GET Details from URL
|
||||
$user_ID = $_GET['id'] ?? '';
|
||||
|
||||
if ($user_ID == ''){
|
||||
header('location: index.php?page=users');
|
||||
exit;
|
||||
}
|
||||
|
||||
//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];
|
||||
// Determine if this is a new user creation
|
||||
$is_new_user = empty($user_ID);
|
||||
|
||||
//Helper function to convert service hex string to 1/0
|
||||
function isServiceActive($service) {
|
||||
@@ -49,13 +41,53 @@ function isServiceActive($service) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$service_active = isServiceActive($user->service);
|
||||
if ($is_new_user) {
|
||||
// Check create permission for new users
|
||||
if ($create_allowed !== 1) {
|
||||
header('location: index.php?page=users');
|
||||
exit;
|
||||
}
|
||||
// Create empty user object with default values
|
||||
$user = (object)[
|
||||
'rowID' => '',
|
||||
'username' => '',
|
||||
'email' => '',
|
||||
'userkey' => '1',
|
||||
'view' => 3,
|
||||
'settings' => '',
|
||||
'service' => 0,
|
||||
'language' => '',
|
||||
'login_count' => 0,
|
||||
'partnerhierarchy' => json_encode($_SESSION['authorization']['partnerhierarchy'] ?? new stdClass()),
|
||||
'created' => null,
|
||||
'updated' => null,
|
||||
'lastlogin' => null,
|
||||
'updatedby' => null
|
||||
];
|
||||
$service_active = 0;
|
||||
$role_assignments = null;
|
||||
} else {
|
||||
//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] ?? null;
|
||||
|
||||
//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;}
|
||||
// If user not found, redirect
|
||||
if ($user === null) {
|
||||
header('location: index.php?page=users');
|
||||
exit;
|
||||
}
|
||||
|
||||
$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';
|
||||
@@ -70,10 +102,56 @@ if (!empty($all_roles_response)){
|
||||
$all_roles = [];
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// Handle POST for creating new user
|
||||
//------------------------------
|
||||
if (isset($_POST['create_user']) && $create_allowed === 1 && $is_new_user) {
|
||||
// Build user data for new user
|
||||
$user_data = [
|
||||
'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' => 0,
|
||||
'salesid' => $_POST['salesid'] ?? '',
|
||||
'soldto' => $_POST['soldto'] ?? '',
|
||||
'shipto' => $_POST['shipto'] ?? '',
|
||||
'location' => $_POST['location'] ?? ''
|
||||
];
|
||||
|
||||
$data = json_encode($user_data, JSON_UNESCAPED_UNICODE);
|
||||
$response = ioServer('/v2/users', $data);
|
||||
|
||||
// Get the new user ID from the response
|
||||
$new_user = json_decode($response);
|
||||
$new_user_id = $new_user->id ?? null;
|
||||
|
||||
// Save role assignments for new user if we have an ID and roles are selected
|
||||
if ($new_user_id && !empty($_POST['roles'])) {
|
||||
$role_data = [
|
||||
'batch_update' => true,
|
||||
'user_id' => (int)$new_user_id,
|
||||
'roles' => array_map('intval', $_POST['roles'])
|
||||
];
|
||||
$data = json_encode($role_data, JSON_UNESCAPED_UNICODE);
|
||||
ioServer('/v2/user_role_assignments', $data);
|
||||
}
|
||||
|
||||
if ($new_user_id) {
|
||||
header('Location: index.php?page=user&id='.$new_user_id.'&success_msg=1');
|
||||
} else {
|
||||
header('Location: index.php?page=users&success_msg=1');
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// Handle POST for inline edit (user AND roles)
|
||||
//------------------------------
|
||||
if (isset($_POST['save_user']) && $update_allowed_edit === 1) {
|
||||
if (isset($_POST['save_user']) && $update_allowed === 1 && !$is_new_user) {
|
||||
// Build user data using existing field names
|
||||
$user_data = [
|
||||
'id' => $user_ID,
|
||||
@@ -109,7 +187,7 @@ if (isset($_POST['save_user']) && $update_allowed_edit === 1) {
|
||||
}
|
||||
|
||||
// Handle password reset
|
||||
if (isset($_POST['reset']) && $update_allowed_edit === 1) {
|
||||
if (isset($_POST['reset']) && $update_allowed === 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');
|
||||
@@ -117,7 +195,7 @@ if (isset($_POST['reset']) && $update_allowed_edit === 1) {
|
||||
}
|
||||
|
||||
// Handle unblock
|
||||
if (isset($_POST['unblock']) && $update_allowed_edit === 1) {
|
||||
if (isset($_POST['unblock']) && $update_allowed === 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');
|
||||
@@ -172,13 +250,24 @@ if (isset($_GET['success_msg'])) {
|
||||
}
|
||||
|
||||
template_header(($user_title ?? 'User'), 'user', 'view');
|
||||
|
||||
if ($is_new_user) {
|
||||
$page_title = ($user_new ?? 'New User');
|
||||
} else {
|
||||
$page_title = ($user_h2 ?? 'User').' - '.$user->username;
|
||||
}
|
||||
|
||||
$view = '
|
||||
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
|
||||
<h2 class="responsive-width-100">'.($user_h2 ?? 'User').' - '.$user->username.'</h2>
|
||||
<h2 class="responsive-width-100">'.$page_title.'</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){
|
||||
if ($is_new_user) {
|
||||
// New user mode - show save button directly
|
||||
$view .= '<button type="submit" form="userForm" id="saveBtn" class="btn">💾</button>';
|
||||
} elseif ($update_allowed === 1) {
|
||||
// Edit mode - show edit/save toggle
|
||||
$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>';
|
||||
}
|
||||
@@ -194,12 +283,17 @@ if (isset($success_msg)){
|
||||
}
|
||||
|
||||
// Start form wrapper for edit mode
|
||||
$form_action = $is_new_user ? 'create_user' : 'save_user';
|
||||
$view .= '<form id="userForm" action="" method="post">
|
||||
<input type="hidden" name="save_user" value="1">
|
||||
<input type="hidden" name="'.$form_action.'" value="1">
|
||||
<input type="hidden" name="id" value="'.$user_ID.'">';
|
||||
|
||||
$view .= '<div class="content-block-wrapper">';
|
||||
|
||||
// Display styles for view/edit mode (new users start in edit mode)
|
||||
$view_style = $is_new_user ? 'display:none;' : '';
|
||||
$edit_style = $is_new_user ? '' : 'display:none;';
|
||||
|
||||
// User Information Block
|
||||
$view .= ' <div class="content-block order-details">
|
||||
<div class="block-header">
|
||||
@@ -208,8 +302,8 @@ $view .= ' <div class="content-block order-details">
|
||||
<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;">
|
||||
<span class="view-mode status '.$status_class.'" style="'.$view_style.'">'.$status_text.'</span>
|
||||
<select class="edit-mode" name="userkey" style="'.$edit_style.'">
|
||||
<option value="1"'.($is_active ? ' selected' : '').'>'.($enabled ?? 'Active').'</option>
|
||||
<option value="0"'.(!$is_active ? ' selected' : '').'>'.($disabled ?? 'Inactive').'</option>
|
||||
</select>
|
||||
@@ -218,22 +312,22 @@ $view .= ' <div class="content-block order-details">
|
||||
<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>
|
||||
<span class="view-mode" style="'.$view_style.'">'.$user->username.'</span>
|
||||
<input type="text" class="edit-mode" name="username" value="'.$user->username.'" style="'.$edit_style.'" 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>
|
||||
<span class="view-mode" style="'.$view_style.'">'.$user->email.'</span>
|
||||
<input type="email" class="edit-mode" name="email" value="'.$user->email.'" style="'.$edit_style.'" 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;">
|
||||
<span class="view-mode" style="'.$view_style.'">'.($user->language ?? '-').'</span>
|
||||
<select class="edit-mode" name="language" style="'.$edit_style.'">
|
||||
<option value="">-</option>';
|
||||
foreach ($supportedLanguages as $language){
|
||||
$view .= '<option value="'.$language.'"'.(($user->language == $language) ? ' selected' : '').'>'.$language.'</option>';
|
||||
@@ -249,7 +343,7 @@ $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">';
|
||||
<div class="view-mode-roles" style="'.($is_new_user ? 'display:none;' : '').'">';
|
||||
|
||||
// Get list of already assigned role IDs
|
||||
$assigned_role_ids = [];
|
||||
@@ -290,9 +384,9 @@ if (!empty($role_assignments)){
|
||||
|
||||
$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;">';
|
||||
// EDIT MODE - Show all roles with checkboxes (only if user has edit permission or is new user)
|
||||
if (($update_allowed === 1 || $is_new_user) && !empty($all_roles)){
|
||||
$view .= '<div class="edit-mode-roles" style="'.($is_new_user ? '' : 'display:none;').'">';
|
||||
|
||||
foreach ($all_roles as $role){
|
||||
$is_checked = in_array($role->rowID, $assigned_role_ids) ? ' checked' : '';
|
||||
@@ -326,7 +420,7 @@ $view .= '<div class="content-block">
|
||||
<tr>
|
||||
<td style="width:25%;">'.($User_permission ?? 'Permission Level').'</td>
|
||||
<td>
|
||||
<span class="view-mode">';
|
||||
<span class="view-mode" style="'.$view_style.'">';
|
||||
|
||||
// Display permission level text
|
||||
switch($user->view){
|
||||
@@ -339,7 +433,7 @@ switch($user->view){
|
||||
}
|
||||
|
||||
$view .= '</span>
|
||||
<select class="edit-mode" name="view" style="display:none;">
|
||||
<select class="edit-mode" name="view" style="'.$edit_style.'">
|
||||
<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>';
|
||||
@@ -358,10 +452,10 @@ $view .= ' </select>
|
||||
<tr>
|
||||
<td style="width:25%;">'.($User_profile ?? 'Profile').'</td>
|
||||
<td>
|
||||
<span class="view-mode">'.($user->settings ?? '-').'</span>';
|
||||
<span class="view-mode" style="'.$view_style.'">'.($user->settings ?? '-').'</span>';
|
||||
|
||||
if ($_SESSION['authorization']['permission'] == 3 || $_SESSION['authorization']['permission'] == 4){
|
||||
$view .= '<select class="edit-mode" name="settings" style="display:none;">
|
||||
$view .= '<select class="edit-mode" name="settings" style="'.$edit_style.'">
|
||||
<option value="">-</option>';
|
||||
foreach ($all_profiles as $profile) {
|
||||
$view .= '<option value="'.$profile.'"'.($user->settings == $profile ? ' selected' : '').'>'.$profile.'</option>';
|
||||
@@ -376,8 +470,8 @@ $view .= ' </td>
|
||||
<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;">
|
||||
<span class="view-mode" style="'.$view_style.'">'.(($service_active == 1) ? ($enabled ?? 'Enabled') : ($disabled ?? 'Disabled')).'</span>
|
||||
<select class="edit-mode" name="service" style="'.$edit_style.'">
|
||||
<option value="1"'.(($service_active == 1) ? ' selected' : '').'>'.($enabled ?? 'Enabled').'</option>
|
||||
<option value="0"'.(($service_active == 0) ? ' selected' : '').'>'.($disabled ?? 'Disabled').'</option>
|
||||
</select>
|
||||
@@ -404,15 +498,15 @@ if ($_SESSION['authorization']['permission'] == 3 || $_SESSION['authorization'][
|
||||
$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>
|
||||
<span class="view-mode" style="'.$view_style.'">'.($partner_data->salesid ?? '-').'</span>
|
||||
<span class="edit-mode" style="'.$edit_style.'">'.$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>
|
||||
<span class="view-mode" style="'.$view_style.'">'.($partner_data->soldto ?? '-').'</span>
|
||||
<span class="edit-mode" style="'.$edit_style.'">'.$soldto_dropdown.'</span>
|
||||
</td>
|
||||
</tr>';
|
||||
}
|
||||
@@ -423,23 +517,24 @@ $location_dropdown = listPartner('location', $_SESSION['authorization']['permiss
|
||||
$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>
|
||||
<span class="view-mode" style="'.$view_style.'">'.($partner_data->shipto ?? '-').'</span>
|
||||
<span class="edit-mode" style="'.$edit_style.'">'.$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>
|
||||
<span class="view-mode" style="'.$view_style.'">'.($partner_data->location ?? '-').'</span>
|
||||
<span class="edit-mode" style="'.$edit_style.'">'.$location_dropdown.'</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>';
|
||||
|
||||
// Metadata Block
|
||||
$view .= '<div class="content-block">
|
||||
// Metadata Block (hide for new users)
|
||||
if (!$is_new_user) {
|
||||
$view .= '<div class="content-block">
|
||||
<div class="block-header">
|
||||
<i class="fa-solid fa-bars fa-sm"></i>'.($tab3 ?? 'Details').'
|
||||
</div>
|
||||
@@ -466,22 +561,23 @@ $view .= '<div class="content-block">
|
||||
<td>
|
||||
<span class="view-mode">'.$user->login_count.'</span>';
|
||||
|
||||
if ($_SESSION['authorization']['permission'] == 3 || $_SESSION['authorization']['permission'] == 4){
|
||||
if ($_SESSION['authorization']['permission'] == 3 || $_SESSION['authorization']['permission'] == 4){
|
||||
$view .= '<input type="number" class="edit-mode" name="login_count" value="'.$user->login_count.'" style="display:none; width: 80px;">';
|
||||
} else {
|
||||
} else {
|
||||
$view .= '<input type="hidden" name="login_count" value="'.$user->login_count.'">';
|
||||
}
|
||||
}
|
||||
|
||||
$view .= ' </td>
|
||||
$view .= ' </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>';
|
||||
}
|
||||
$view .= '</form>
|
||||
';
|
||||
|
||||
// Actions Block (outside form for separate actions)
|
||||
if ($update_allowed_edit === 1){
|
||||
// Actions Block (outside form for separate actions, hide for new users)
|
||||
if ($update_allowed === 1 && !$is_new_user){
|
||||
$view .= '<div class="content-block">
|
||||
<div class="block-header">
|
||||
<i class="fa-solid fa-bolt fa-sm"></i>'.($general_actions ?? 'Actions').'
|
||||
|
||||
163
user_role.php
163
user_role.php
@@ -24,6 +24,17 @@ $update_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_S
|
||||
$update_allowed_edit = isAllowed($page_manage ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'U');
|
||||
$delete_allowed = isAllowed($page_manage ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'D');
|
||||
$create_allowed = isAllowed($page_manage ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'C');
|
||||
$system_role_allowed = isAllowed('user_roles' ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'D');
|
||||
|
||||
//Handle AJAX request for role permissions (copy functionality)
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'get_role_permissions' && isset($_GET['source_role_id'])) {
|
||||
header('Content-Type: application/json');
|
||||
$source_role_id = intval($_GET['source_role_id']);
|
||||
$api_url = '/v2/role_access_permissions/role_id='.$source_role_id;
|
||||
$role_perms = ioServer($api_url,'');
|
||||
echo $role_perms;
|
||||
exit;
|
||||
}
|
||||
|
||||
//GET Details from URL
|
||||
$GET_VALUES = urlGETdetails($_GET) ?? '';
|
||||
@@ -63,17 +74,28 @@ $assignments = ioServer($api_url,'');
|
||||
//Decode Payload
|
||||
if (!empty($assignments)){$assignments = json_decode($assignments);}else{$assignments = null;}
|
||||
|
||||
//CALL TO API FOR All User Roles (for copy dropdown)
|
||||
$api_url = '/v2/user_roles/status=1&all=';
|
||||
$all_roles = ioServer($api_url,'');
|
||||
//Decode Payload
|
||||
if (!empty($all_roles)){$all_roles = json_decode($all_roles);}else{$all_roles = 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([
|
||||
// Update role info (name, description, status, system role)
|
||||
$role_data_array = [
|
||||
'rowID' => $role_id,
|
||||
'name' => $_POST['name'] ?? '',
|
||||
'description' => $_POST['description'] ?? '',
|
||||
'is_active' => $_POST['is_active'] ?? 1
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
];
|
||||
// Only allow is_system to be changed if user has delete permission on user_roles
|
||||
if ($system_role_allowed === 1) {
|
||||
$role_data_array['is_system'] = isset($_POST['is_system']) ? 1 : 0;
|
||||
}
|
||||
$role_data = json_encode($role_data_array, JSON_UNESCAPED_UNICODE);
|
||||
ioServer('/v2/user_roles', $role_data);
|
||||
|
||||
// Process permission updates
|
||||
@@ -132,6 +154,21 @@ if (isset($_POST['save_permissions']) && $update_allowed_edit === 1) {
|
||||
exit;
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// Handle POST for delete
|
||||
//------------------------------
|
||||
if (isset($_POST['delete_role']) && $delete_allowed === 1) {
|
||||
$role_data = json_encode([
|
||||
'rowID' => $role_id,
|
||||
'delete' => 'delete'
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
ioServer('/v2/user_roles', $role_data);
|
||||
|
||||
// Redirect to roles list with success message
|
||||
header('Location: index.php?page='.$_SESSION['origin'].'&success_msg=3');
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------
|
||||
//Variables
|
||||
@@ -161,7 +198,11 @@ $view = '
|
||||
|
||||
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 .= '<button type="submit" form="permissionsForm" id="saveBtn" class="btn mar-right-2" style="display:none;">💾</button>';
|
||||
}
|
||||
|
||||
if ($delete_allowed === 1){
|
||||
$view .= '<a href="javascript:void(0);" id="deleteBtn" class="btn alt" onclick="confirmDeleteRole()">🗑️</a>';
|
||||
}
|
||||
|
||||
$view .= '</div>';
|
||||
@@ -174,6 +215,32 @@ if (isset($success_msg)){
|
||||
</div>';
|
||||
}
|
||||
|
||||
// Delete form (hidden)
|
||||
if ($delete_allowed === 1){
|
||||
$view .= '<form id="deleteRoleForm" action="" method="post" style="display:none;">
|
||||
<input type="hidden" name="delete_role" value="1">
|
||||
<input type="hidden" name="rowID" value="'.$role_id.'">
|
||||
</form>';
|
||||
|
||||
// Delete confirmation modal
|
||||
$view .= '<div id="deleteModal" class="modal" style="display:none;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3><i class="fa-solid fa-triangle-exclamation" style="color:#e74c3c;"></i> '.($confirm_delete_title ?? 'Confirm Delete').'</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>'.($confirm_delete_role ?? 'Are you sure you want to delete this role?').'</p>
|
||||
<p><strong>'.$responses->name.'</strong></p>
|
||||
<p class="warning-text" style="color:#e74c3c; margin-top:10px;">'.($delete_role_warning ?? 'This will also remove all permissions and user assignments associated with this role.').'</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn alt" onclick="closeDeleteModal()">'.($cancel ?? 'Cancel').'</button>
|
||||
<button type="button" class="btn danger" onclick="executeDeleteRole()">'.($delete ?? 'Delete').'</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
// Start form wrapper for edit mode
|
||||
$view .= '<form id="permissionsForm" action="" method="post">
|
||||
<input type="hidden" name="save_permissions" value="1">
|
||||
@@ -210,6 +277,31 @@ $view .= ' <div class="content-block order-details">
|
||||
<textarea class="edit-mode" name="description" style="display:none;">'.($responses->description ?? '').'</textarea>
|
||||
</p>
|
||||
</div>
|
||||
<div class="order-detail">
|
||||
<h3>'.($role_system ?? 'System Role').'</h3>
|
||||
<p>
|
||||
<span class="'.($system_role_allowed === 1 ? 'view-mode' : '').'">'.($responses->is_system == 1 ? '<i class="fa-solid fa-check" style="color:green;"></i> '.($yes ?? 'Yes') : '<i class="fa-solid fa-times" style="color:red;"></i> '.($no ?? 'No')).'</span>
|
||||
'.($system_role_allowed === 1 ? '<label class="edit-mode" style="display:none;">
|
||||
<input type="checkbox" name="is_system" value="1"'.($responses->is_system == 1 ? ' checked' : '').'> '.($role_system_label ?? 'Mark as system role').'
|
||||
</label>' : '').'
|
||||
</p>
|
||||
</div>
|
||||
<div class="order-detail edit-mode-block" style="display:none;">
|
||||
<h3>'.($copy_from_role ?? 'Copy Permissions From').'</h3>
|
||||
<p>
|
||||
<select id="copyFromRole" onchange="copyPermissionsFromRole(this.value)" style="width:100%; max-width:300px;">
|
||||
<option value="">'.($select_role ?? '-- Select Role --').'</option>';
|
||||
if (!empty($all_roles)){
|
||||
foreach ($all_roles as $r){
|
||||
if ($r->rowID != $role_id){
|
||||
$view .= '<option value="'.$r->rowID.'">'.$r->name.'</option>';
|
||||
}
|
||||
}
|
||||
}
|
||||
$view .= ' </select>
|
||||
<small style="display:block; margin-top:5px; color:#666;">'.($copy_permissions_hint ?? 'Selecting a role will override current permissions').'</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
@@ -350,17 +442,20 @@ function togglePermissionsEdit() {
|
||||
var saveBtn = document.getElementById("saveBtn");
|
||||
var viewElements = document.querySelectorAll(".view-mode");
|
||||
var editElements = document.querySelectorAll(".edit-mode");
|
||||
var editBlockElements = document.querySelectorAll(".edit-mode-block");
|
||||
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 < editBlockElements.length; i++) { editBlockElements[i].style.display = "block"; }
|
||||
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 < editBlockElements.length; i++) { editBlockElements[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";
|
||||
@@ -378,6 +473,66 @@ function toggleColumn(type) {
|
||||
for (var i = 0; i < checkboxes.length; i++) {
|
||||
checkboxes[i].checked = !allChecked;
|
||||
}
|
||||
}
|
||||
async function copyPermissionsFromRole(roleId) {
|
||||
if (!roleId) return;
|
||||
|
||||
if (!confirm("'.($confirm_copy_permissions ?? 'This will override all current permission settings. Continue?').'")) {
|
||||
document.getElementById("copyFromRole").value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Call PHP page which will use ioServer to get permissions
|
||||
const response = await fetch("index.php?page=user_role&action=get_role_permissions&source_role_id=" + roleId);
|
||||
if (!response.ok) throw new Error("Failed to fetch");
|
||||
const permissions = await response.json();
|
||||
|
||||
// Create a lookup map of permissions by access_id
|
||||
var permMap = {};
|
||||
if (permissions && permissions.length > 0) {
|
||||
for (var i = 0; i < permissions.length; i++) {
|
||||
permMap[permissions[i].access_id] = permissions[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Get all permission checkboxes and reset them
|
||||
var allCheckboxes = document.querySelectorAll("input[type=checkbox][name^=\\"permissions[\\"]");
|
||||
for (var i = 0; i < allCheckboxes.length; i++) {
|
||||
allCheckboxes[i].checked = false;
|
||||
}
|
||||
|
||||
// Apply copied permissions
|
||||
for (var accessId in permMap) {
|
||||
var perm = permMap[accessId];
|
||||
var cbCreate = document.querySelector("input[name=\\"permissions[" + accessId + "][C]\\"]");
|
||||
var cbRead = document.querySelector("input[name=\\"permissions[" + accessId + "][R]\\"]");
|
||||
var cbUpdate = document.querySelector("input[name=\\"permissions[" + accessId + "][U]\\"]");
|
||||
var cbDelete = document.querySelector("input[name=\\"permissions[" + accessId + "][D]\\"]");
|
||||
|
||||
if (cbCreate && perm.can_create == 1) cbCreate.checked = true;
|
||||
if (cbRead && perm.can_read == 1) cbRead.checked = true;
|
||||
if (cbUpdate && perm.can_update == 1) cbUpdate.checked = true;
|
||||
if (cbDelete && perm.can_delete == 1) cbDelete.checked = true;
|
||||
}
|
||||
|
||||
// Reset dropdown
|
||||
document.getElementById("copyFromRole").value = "";
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error copying permissions:", error);
|
||||
alert("'.($error_copy_permissions ?? 'Failed to copy permissions. Please try again.').'");
|
||||
document.getElementById("copyFromRole").value = "";
|
||||
}
|
||||
}
|
||||
function confirmDeleteRole() {
|
||||
document.getElementById("deleteModal").style.display = "flex";
|
||||
}
|
||||
function closeDeleteModal() {
|
||||
document.getElementById("deleteModal").style.display = "none";
|
||||
}
|
||||
function executeDeleteRole() {
|
||||
document.getElementById("deleteRoleForm").submit();
|
||||
}';
|
||||
|
||||
template_footer($js);
|
||||
|
||||
@@ -23,6 +23,7 @@ if (isAllowed($page,$_SESSION['authorization']['permissions'],$_SESSION['authori
|
||||
exit;
|
||||
}
|
||||
//PAGE Security
|
||||
$page = 'user';
|
||||
$update_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'U');
|
||||
$delete_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'D');
|
||||
$create_allowed = isAllowed($page ,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'C');
|
||||
|
||||
@@ -157,8 +157,8 @@ try {
|
||||
|
||||
// Create license
|
||||
$sql = 'INSERT INTO products_software_licenses
|
||||
(version_id, license_type, license_key, status, starts_at, expires_at, transaction_id, created, createdby)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
(version_id, license_type, license_key, status, starts_at, expires_at, transaction_id,accounthierarchy, created, createdby)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
$item['item_id'], // version_id
|
||||
@@ -168,6 +168,7 @@ try {
|
||||
date('Y-m-d H:i:s'),
|
||||
'2099-12-31 23:59:59', // effectively permanent
|
||||
$orderId,
|
||||
'{"salesid":"21-Total Safety Solutions B.V.","soldto":""}',
|
||||
date('Y-m-d H:i:s'),
|
||||
'webhook' // created by webhook
|
||||
]);
|
||||
|
||||
@@ -203,8 +203,8 @@ try {
|
||||
|
||||
// Create license
|
||||
$sql = 'INSERT INTO products_software_licenses
|
||||
(version_id, license_type, license_key, status, starts_at, expires_at, transaction_id, created, createdby)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
(version_id, license_type, license_key, status, starts_at, expires_at, transaction_id, accounthierarchy,created, createdby)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
$item['item_id'], // version_id
|
||||
@@ -214,6 +214,7 @@ try {
|
||||
date('Y-m-d H:i:s'),
|
||||
'2099-12-31 23:59:59', // effectively permanent
|
||||
$orderId,
|
||||
'{"salesid":"21-Total Safety Solutions B.V.","soldto":""}',
|
||||
date('Y-m-d H:i:s'),
|
||||
'webhook_paypal' // created by PayPal webhook
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user