Add software availability check API and enhance profile management features
This commit is contained in:
196
api/v2/get/software_available.php
Normal file
196
api/v2/get/software_available.php
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
<?php
|
||||||
|
defined($security_key) or exit;
|
||||||
|
ini_set('display_errors', '1');
|
||||||
|
ini_set('display_startup_errors', '1');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
//------------------------------------------
|
||||||
|
// Software Available Check API
|
||||||
|
// Returns boolean indicating if software updates are available
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
//Connect to DB
|
||||||
|
$pdo = dbConnect($dbname);
|
||||||
|
|
||||||
|
//NEW ARRAY
|
||||||
|
$criterias = [];
|
||||||
|
$clause = '';
|
||||||
|
|
||||||
|
//Check for $_GET variables and build up clause
|
||||||
|
if(isset($get_content) && $get_content!=''){
|
||||||
|
//GET VARIABLES FROM URL
|
||||||
|
$requests = explode("&", $get_content);
|
||||||
|
//Check for keys and values
|
||||||
|
foreach ($requests as $y){
|
||||||
|
$v = explode("=", $y);
|
||||||
|
//INCLUDE VARIABLES IN ARRAY
|
||||||
|
$criterias[$v[0]] = $v[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IF SN IS PROVIDED, CHECK FOR AVAILABLE UPGRADES
|
||||||
|
if (isset($criterias['sn']) && $criterias['sn'] != ''){
|
||||||
|
|
||||||
|
//default response
|
||||||
|
$software_available = "no";
|
||||||
|
|
||||||
|
//check if current version is send and update the equipment record
|
||||||
|
if(isset($criterias['version']) && $criterias['version'] !=''){
|
||||||
|
$sql = 'UPDATE equipment SET sw_version = ?, updatedby = ? WHERE serialnumber = ? ';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$criterias['version'],$username,$criterias['sn']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if current hw_version is send and update the equipment record
|
||||||
|
if(isset($criterias['hw_version']) && $criterias['hw_version'] !=''){
|
||||||
|
$sql = 'UPDATE equipment SET hw_version = ?, updatedby = ? WHERE serialnumber = ? ';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$criterias['hw_version'],$username,$criterias['sn']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//GET EQUIPMENT AND PRODUCT DATA BASED ON SERIAL NUMBER
|
||||||
|
$sql = 'SELECT
|
||||||
|
p.rowID as product_rowid,
|
||||||
|
p.productcode,
|
||||||
|
e.sw_version as current_sw_version,
|
||||||
|
e.hw_version,
|
||||||
|
e.sw_version_license,
|
||||||
|
e.rowID as equipment_rowid
|
||||||
|
FROM equipment e
|
||||||
|
JOIN products p ON e.productrowid = p.rowID
|
||||||
|
WHERE e.serialnumber = ?';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$criterias['sn']]);
|
||||||
|
$equipment_data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$equipment_data) {
|
||||||
|
$messages = ["error" => "No equipment found for serialnumber"];
|
||||||
|
} else {
|
||||||
|
$product_rowid = $equipment_data['product_rowid'];
|
||||||
|
$productcode = $equipment_data['productcode'];
|
||||||
|
$current_sw_version = $equipment_data['current_sw_version'];
|
||||||
|
$hw_version = $equipment_data['hw_version'];
|
||||||
|
$sw_version_license = $equipment_data['sw_version_license'];
|
||||||
|
$equipment_rowid = $equipment_data['equipment_rowid'];
|
||||||
|
|
||||||
|
//GET ALL DATA: active assignments, version details, and upgrade paths
|
||||||
|
//Filter on active status, hw_version compatibility, and exclude current version
|
||||||
|
$sql = 'SELECT
|
||||||
|
psv.rowID as version_id,
|
||||||
|
psv.version,
|
||||||
|
psv.name,
|
||||||
|
psv.description,
|
||||||
|
psv.mandatory,
|
||||||
|
psv.latest,
|
||||||
|
psv.hw_version,
|
||||||
|
psv.file_path,
|
||||||
|
pup.price,
|
||||||
|
pup.currency,
|
||||||
|
pup.from_version_id,
|
||||||
|
from_ver.version as from_version
|
||||||
|
FROM products_software_assignment psa
|
||||||
|
JOIN products_software_versions psv ON psa.software_version_id = psv.rowID
|
||||||
|
LEFT JOIN products_software_upgrade_paths pup ON pup.to_version_id = psv.rowID AND pup.is_active = 1
|
||||||
|
LEFT JOIN products_software_versions from_ver ON pup.from_version_id = from_ver.rowID
|
||||||
|
WHERE psa.product_id = ?
|
||||||
|
AND psa.status = 1
|
||||||
|
AND (psv.hw_version = ? OR psv.hw_version IS NULL OR psv.hw_version = "")
|
||||||
|
AND psv.version != ?';
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$product_rowid, $hw_version, $current_sw_version ?? '']);
|
||||||
|
$versions = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($versions)) {
|
||||||
|
// No versions available
|
||||||
|
$software_available = "no";
|
||||||
|
} else {
|
||||||
|
$has_priced_options = false;
|
||||||
|
$has_latest_version_different = false;
|
||||||
|
|
||||||
|
foreach ($versions as $version) {
|
||||||
|
//Check if this version should be shown (same logic as software_update)
|
||||||
|
$show_version = false;
|
||||||
|
if (!$current_sw_version || $current_sw_version == '') {
|
||||||
|
//No current version - show all
|
||||||
|
$show_version = true;
|
||||||
|
} elseif ($version['from_version'] == $current_sw_version) {
|
||||||
|
//Upgrade path exists from current version
|
||||||
|
$show_version = true;
|
||||||
|
} else {
|
||||||
|
//Check if any upgrade paths exist for this version
|
||||||
|
$sql = 'SELECT COUNT(*) as path_count
|
||||||
|
FROM products_software_upgrade_paths
|
||||||
|
WHERE to_version_id = ? AND is_active = 1';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$version['version_id']]);
|
||||||
|
$path_check = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($path_check['path_count'] == 0) {
|
||||||
|
//No paths exist at all - show as free upgrade
|
||||||
|
$show_version = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($show_version) {
|
||||||
|
//Check if there's a valid license for this upgrade
|
||||||
|
$final_price = $version['price'] ?? '0.00';
|
||||||
|
|
||||||
|
if ($final_price > 0 && $sw_version_license) {
|
||||||
|
//Check if the license is valid
|
||||||
|
$sql = 'SELECT status, start_at, expires_at
|
||||||
|
FROM products_software_licenses
|
||||||
|
WHERE license_key = ? AND equipment_id = ?';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$sw_version_license, $equipment_rowid]);
|
||||||
|
$license = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($license && $license['status'] == 1) {
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$start_at = $license['start_at'];
|
||||||
|
$expires_at = $license['expires_at'];
|
||||||
|
|
||||||
|
//Check if license is within valid date range
|
||||||
|
if ((!$start_at || $start_at <= $now) && (!$expires_at || $expires_at >= $now)) {
|
||||||
|
$final_price = '0.00';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for priced options
|
||||||
|
if ($final_price > 0) {
|
||||||
|
$has_priced_options = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there's a "latest" flagged version that's different from current
|
||||||
|
if ($version['latest'] == 1 && $version['version'] != $current_sw_version) {
|
||||||
|
$has_latest_version_different = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the logic:
|
||||||
|
// 1. If there are priced options -> "yes"
|
||||||
|
// 2. If no priced options but current version != latest flagged version -> "yes"
|
||||||
|
// 3. Default -> "no"
|
||||||
|
if ($has_priced_options) {
|
||||||
|
$software_available = "yes";
|
||||||
|
} elseif ($has_latest_version_different) {
|
||||||
|
$software_available = "yes";
|
||||||
|
} else {
|
||||||
|
$software_available = "no";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages = ["software_available" => $software_available];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$messages = ["error" => "No serialnumber found"];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Encrypt results
|
||||||
|
$messages = json_encode($messages, JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
//Send results
|
||||||
|
echo $messages;
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -1490,6 +1490,7 @@ function getProfile($profile, $permission){
|
|||||||
'com_log' => 'U',
|
'com_log' => 'U',
|
||||||
'software_update' => 'R',
|
'software_update' => 'R',
|
||||||
'software_download' => 'R',
|
'software_download' => 'R',
|
||||||
|
'software_available' => 'R'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Group permissions: [granting_page => [collection => allowed_actions_string]]
|
// Group permissions: [granting_page => [collection => allowed_actions_string]]
|
||||||
|
|||||||
44
logfile.php
44
logfile.php
@@ -7,12 +7,14 @@ if (isAllowed('logfile',$_SESSION['profile'],$_SESSION['permission'],'R') === 0)
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define logs directory path
|
||||||
|
$logs_dir = __DIR__ . '/log/';
|
||||||
|
|
||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
// POST HANDLER - Delete all logs
|
// POST HANDLER - Delete all logs
|
||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
$delete_message = '';
|
$delete_message = '';
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_all_logs'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_all_logs'])) {
|
||||||
$logs_dir = __DIR__ . '/log/';
|
|
||||||
$deleted_count = 0;
|
$deleted_count = 0;
|
||||||
|
|
||||||
if (is_dir($logs_dir)) {
|
if (is_dir($logs_dir)) {
|
||||||
@@ -37,6 +39,28 @@ if (isset($_GET['deleted'])) {
|
|||||||
$delete_message = "Successfully deleted " . intval($_GET['deleted']) . " log file(s).";
|
$delete_message = "Successfully deleted " . intval($_GET['deleted']) . " log file(s).";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// DOWNLOAD HANDLER
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
if (isset($_GET['download']) && $_GET['download']) {
|
||||||
|
$filename = $_GET['download'];
|
||||||
|
$filepath = $logs_dir . $filename;
|
||||||
|
|
||||||
|
// Security check: ensure file exists and is within logs directory
|
||||||
|
if (file_exists($filepath) && strpos(realpath($filepath), realpath($logs_dir)) === 0) {
|
||||||
|
// Set headers for file download
|
||||||
|
header('Content-Type: application/octet-stream');
|
||||||
|
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||||
|
header('Content-Length: ' . filesize($filepath));
|
||||||
|
header('Cache-Control: must-revalidate');
|
||||||
|
header('Pragma: public');
|
||||||
|
|
||||||
|
// Output file content
|
||||||
|
readfile($filepath);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
// GET HANDLER
|
// GET HANDLER
|
||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
@@ -45,7 +69,6 @@ if (isset($_GET['deleted'])) {
|
|||||||
$selected_log = $_GET['log'] ?? '';
|
$selected_log = $_GET['log'] ?? '';
|
||||||
|
|
||||||
// Scan logs directory for all log files
|
// Scan logs directory for all log files
|
||||||
$logs_dir = __DIR__ . '/log/';
|
|
||||||
$log_files = [];
|
$log_files = [];
|
||||||
|
|
||||||
if (is_dir($logs_dir)) {
|
if (is_dir($logs_dir)) {
|
||||||
@@ -113,6 +136,9 @@ if (file_exists($filelocation_webserver)){
|
|||||||
<button type="button" onclick="refreshLog()" class="btn" >
|
<button type="button" onclick="refreshLog()" class="btn" >
|
||||||
<i class="fas fa-sync-alt"></i>
|
<i class="fas fa-sync-alt"></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" onclick="downloadLogFile()" class="btn" style="background: #3498db; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer;">
|
||||||
|
<i class="fas fa-download"></i>
|
||||||
|
</button>
|
||||||
<button type="submit" name="delete_all_logs" onclick="return confirmDeleteAll()" class="btn" style="background: #e74c3c; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer;">
|
<button type="submit" name="delete_all_logs" onclick="return confirmDeleteAll()" class="btn" style="background: #e74c3c; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer;">
|
||||||
<i class="fas fa-trash-alt"></i>
|
<i class="fas fa-trash-alt"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -165,6 +191,20 @@ function loadLogFile(filename) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Download current log file
|
||||||
|
function downloadLogFile() {
|
||||||
|
const selector = document.getElementById('log-file-selector');
|
||||||
|
const selectedFile = selector.value;
|
||||||
|
|
||||||
|
if (selectedFile) {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
url.searchParams.set('download', selectedFile);
|
||||||
|
window.location.href = url.toString();
|
||||||
|
} else {
|
||||||
|
alert('No log file selected to download.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh log functionality
|
// Refresh log functionality
|
||||||
function refreshLog() {
|
function refreshLog() {
|
||||||
const button = event.target.closest('button');
|
const button = event.target.closest('button');
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ $view .= '
|
|||||||
<option value="1"'.($status==1?' selected':'').'>'.$prod_status_1.'</option>
|
<option value="1"'.($status==1?' selected':'').'>'.$prod_status_1.'</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="filter-group search-group">
|
||||||
|
<input type="text" name="search" placeholder="'.$software_version_search.'" value="">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-actions">
|
<div class="filter-actions">
|
||||||
@@ -121,16 +124,6 @@ $view .= '
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="search">
|
|
||||||
<label for="search">
|
|
||||||
<input id="search" type="text" name="search" placeholder="'.$software_version_search.'" value="" class="responsive-width-100">
|
|
||||||
<i class="fas fa-search"></i>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
';
|
';
|
||||||
|
|
||||||
@@ -146,7 +139,6 @@ $view .= '
|
|||||||
<th>Mandatory</th>
|
<th>Mandatory</th>
|
||||||
<th>Latest</th>
|
<th>Latest</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -163,14 +155,13 @@ $view .= '
|
|||||||
foreach ($responses as $response){
|
foreach ($responses as $response){
|
||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
<tr>
|
<tr onclick="window.location.href=\'index.php?page=products_software_version&rowID='.$response->rowID.'\'" style="cursor: pointer;">
|
||||||
<td>'.$response->name.'</td>
|
<td>'.$response->name.'</td>
|
||||||
<td>'.$response->version.'</td>
|
<td>'.$response->version.'</td>
|
||||||
<td>'.$response->hw_version.'</td>
|
<td>'.$response->hw_version.'</td>
|
||||||
<td>'.($response->mandatory ? 'Yes' : 'No').'</td>
|
<td>'.($response->mandatory ? 'Yes' : 'No').'</td>
|
||||||
<td>'.($response->latest ? 'Yes' : 'No').'</td>
|
<td>'.($response->latest ? 'Yes' : 'No').'</td>
|
||||||
<td>'.($response->status ? 'Active' : 'Inactive').'</td>
|
<td>'.($response->status ? 'Active' : 'Inactive').'</td>
|
||||||
<td><a href="index.php?page=products_software_version&rowID='.$response->rowID.'" class="btn_link">View</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
|
|||||||
306
profiles.php
306
profiles.php
@@ -7,6 +7,9 @@ defined(page_security_key) or exit;
|
|||||||
$domain = getDomainName($_SERVER['SERVER_NAME']);
|
$domain = getDomainName($_SERVER['SERVER_NAME']);
|
||||||
$file = ((file_exists(dirname(__FILE__).'/custom/'.$domain.'/settings/settingsprofiles.php')) ? dirname(__FILE__).'/custom/'.$domain.'/settings/settingsprofiles.php' : dirname(__FILE__).'/settings/settingsprofiles.php');
|
$file = ((file_exists(dirname(__FILE__).'/custom/'.$domain.'/settings/settingsprofiles.php')) ? dirname(__FILE__).'/custom/'.$domain.'/settings/settingsprofiles.php' : dirname(__FILE__).'/settings/settingsprofiles.php');
|
||||||
|
|
||||||
|
// Include settings views globally
|
||||||
|
include dirname(__FILE__).'/settings/settingsviews.php';
|
||||||
|
|
||||||
$page = 'profiles';
|
$page = 'profiles';
|
||||||
//Check if allowed
|
//Check if allowed
|
||||||
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
|
if (isAllowed($page,$_SESSION['profile'],$_SESSION['permission'],'R') === 0){
|
||||||
@@ -20,6 +23,71 @@ $contents = file_get_contents($file);
|
|||||||
//empty view
|
//empty view
|
||||||
$view = '';
|
$view = '';
|
||||||
|
|
||||||
|
// Function to scan for new views and update settingsviews.php
|
||||||
|
function scan_and_update_views() {
|
||||||
|
global $all_views;
|
||||||
|
$new_views = [];
|
||||||
|
|
||||||
|
// Scan root PHP files
|
||||||
|
$root_files = glob(dirname(__FILE__) . '/*.php');
|
||||||
|
foreach ($root_files as $file) {
|
||||||
|
$filename = basename($file, '.php');
|
||||||
|
if ($filename !== 'index' && $filename !== 'login' && $filename !== 'logout') {
|
||||||
|
$new_views[] = $filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan API v2 get folder
|
||||||
|
$get_files = glob(dirname(__FILE__) . '/api/v2/get/*.php');
|
||||||
|
foreach ($get_files as $file) {
|
||||||
|
$filename = basename($file, '.php');
|
||||||
|
$new_views[] = $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan API v2 post folder
|
||||||
|
$post_files = glob(dirname(__FILE__) . '/api/v2/post/*.php');
|
||||||
|
foreach ($post_files as $file) {
|
||||||
|
$filename = basename($file, '.php');
|
||||||
|
$new_views[] = $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicates and filter out existing views
|
||||||
|
$new_views = array_unique($new_views);
|
||||||
|
$views_to_add = array_diff($new_views, $all_views);
|
||||||
|
|
||||||
|
if (!empty($views_to_add)) {
|
||||||
|
// Update the all_views array
|
||||||
|
$all_views = array_merge($all_views, $views_to_add);
|
||||||
|
sort($all_views);
|
||||||
|
|
||||||
|
// Update settingsviews.php file
|
||||||
|
$views_file = dirname(__FILE__) . '/settings/settingsviews.php';
|
||||||
|
$new_content = "<?php\n\n// +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
|
||||||
|
$new_content .= "// All individual views and APIs - Profile ++++++++++++++\n";
|
||||||
|
$new_content .= "// +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
|
||||||
|
$new_content .= "\$all_views = [\n";
|
||||||
|
|
||||||
|
foreach ($all_views as $view) {
|
||||||
|
$new_content .= ' "' . $view . "\",\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_content .= "];\n\n?>";
|
||||||
|
|
||||||
|
file_put_contents($views_file, $new_content);
|
||||||
|
|
||||||
|
return count($views_to_add);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle view scanning
|
||||||
|
if (isset($_POST['scan_views'])) {
|
||||||
|
$added_count = scan_and_update_views();
|
||||||
|
header('Location: index.php?page=profiles&views_added=' . $added_count);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Format key function
|
// Format key function
|
||||||
function format_key($key) {
|
function format_key($key) {
|
||||||
$key = str_replace(
|
$key = str_replace(
|
||||||
@@ -31,57 +99,138 @@ function format_key($key) {
|
|||||||
}
|
}
|
||||||
// Format HTML output function
|
// Format HTML output function
|
||||||
function format_var_html($key, $value) {
|
function format_var_html($key, $value) {
|
||||||
|
global $all_views;
|
||||||
|
|
||||||
|
// Ensure all_views is loaded
|
||||||
|
if (!isset($all_views) || !is_array($all_views)) {
|
||||||
include dirname(__FILE__).'/settings/settingsviews.php';
|
include dirname(__FILE__).'/settings/settingsviews.php';
|
||||||
|
}
|
||||||
|
|
||||||
$html = '';
|
$html = '';
|
||||||
$value = htmlspecialchars(trim($value, '\''), ENT_QUOTES);
|
$value = htmlspecialchars(trim($value, '\''), ENT_QUOTES);
|
||||||
|
|
||||||
$profile_contents = explode(',',$value);
|
$profile_contents = explode(',',$value);
|
||||||
|
|
||||||
foreach ($all_views as $view){
|
// Add profile header with bulk select options
|
||||||
$html .= '<div>';
|
$checked_count = count(array_intersect($profile_contents, $all_views));
|
||||||
if (in_array($view, $profile_contents)){
|
$total_count = count($all_views);
|
||||||
$html .= '<input type="checkbox" id="'.$key .'" name="'.$key .'[]" value="'.$view.'" checked> '.$view;
|
|
||||||
} else {
|
$html .= '<div class="profile-header" style="margin-bottom: 10px; padding: 10px; background: #f5f5f5; border-radius: 4px;">';
|
||||||
$html .= '<input type="checkbox" id="'.$key .'" name="'.$key .'[]" value="'.$view.'"> '.$view;
|
$html .= '<h4 style="margin: 0 0 8px 0; color: #333;">Profile: ' . ucwords(str_replace('_', ' ', $key)) . ' (' . $checked_count . '/' . $total_count . ' selected)</h4>';
|
||||||
|
$html .= '<div style="margin-bottom: 8px;">';
|
||||||
|
$html .= '<button type="button" class="btn-small select-all" data-profile="'.$key.'">Select All</button> ';
|
||||||
|
$html .= '<button type="button" class="btn-small select-none" data-profile="'.$key.'">Select None</button>';
|
||||||
|
$html .= '</div></div>';
|
||||||
|
|
||||||
|
// Create a container for the checkboxes with data attributes for filtering
|
||||||
|
$html .= '<div class="profile-checkboxes" data-profile="'.$key.'" style="max-height: 400px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; background: white;">';
|
||||||
|
|
||||||
|
// Group views by category for better organization
|
||||||
|
$grouped_views = [];
|
||||||
|
foreach ($all_views as $view) {
|
||||||
|
$category = 'Other';
|
||||||
|
if (strpos($view, 'equipment') === 0) $category = 'Equipment';
|
||||||
|
elseif (strpos($view, 'product') === 0) $category = 'Products';
|
||||||
|
elseif (strpos($view, 'account') === 0) $category = 'Accounts';
|
||||||
|
elseif (strpos($view, 'user') === 0) $category = 'Users';
|
||||||
|
elseif (strpos($view, 'report') === 0) $category = 'Reports';
|
||||||
|
elseif (strpos($view, 'contract') === 0) $category = 'Contracts';
|
||||||
|
elseif (strpos($view, 'dealer') === 0) $category = 'Dealers';
|
||||||
|
elseif (strpos($view, 'rma') === 0) $category = 'RMA';
|
||||||
|
elseif (in_array($view, ['dashboard', 'profile', 'admin', 'settings', 'config'])) $category = 'Core';
|
||||||
|
|
||||||
|
$grouped_views[$category][] = $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output grouped checkboxes
|
||||||
|
foreach ($grouped_views as $category => $views) {
|
||||||
|
$html .= '<div class="view-category" style="margin-bottom: 15px;">';
|
||||||
|
$html .= '<h5 style="margin: 0 0 5px 0; color: #666; font-size: 12px; text-transform: uppercase; border-bottom: 1px solid #eee; padding-bottom: 3px;">' . $category . '</h5>';
|
||||||
|
|
||||||
|
foreach ($views as $view) {
|
||||||
|
$checked = in_array($view, $profile_contents) ? 'checked' : '';
|
||||||
|
$html .= '<div class="checkbox-item" data-view="'.$view.'" style="display: inline-block; width: 33.33%; margin-bottom: 5px; font-size: 13px;">';
|
||||||
|
$html .= '<label style="cursor: pointer; display: flex; align-items: center;">';
|
||||||
|
$html .= '<input type="checkbox" name="'.$key .'[]" value="'.$view.'" '.$checked.' style="margin-right: 5px;"> ';
|
||||||
|
$html .= '<span>' . $view . '</span>';
|
||||||
|
$html .= '</label>';
|
||||||
$html .= '</div>';
|
$html .= '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$html .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format tabs
|
// Format tabs and content together (interleaved for collapsible functionality)
|
||||||
function format_tabs($contents) {
|
function format_tabs_and_content($contents) {
|
||||||
$rows = explode("\n", $contents);
|
global $all_views;
|
||||||
$tab = '<div class="tabs">';
|
|
||||||
$tab .= '<a href="#" class="active">General</a>';
|
|
||||||
for ($i = 0; $i < count($rows); $i++) {
|
|
||||||
preg_match('/\/\*(.*?)\*\//', $rows[$i], $match);
|
|
||||||
if ($match) {
|
|
||||||
$tab .= '<a href="#">' . $match[1] . '</a>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$tab .= '</div>';
|
|
||||||
return $tab;
|
|
||||||
}
|
|
||||||
// Format form
|
|
||||||
function format_form($contents) {
|
|
||||||
$rows = explode("\n", $contents);
|
|
||||||
$form = '<div class="tab-content active">Each tab represents a profile. Each element in a profile represents a view and or API access.';
|
|
||||||
for ($i = 0; $i < count($rows); $i++) {
|
|
||||||
preg_match('/\/\*(.*?)\*\//', $rows[$i], $match);
|
|
||||||
if ($match) {
|
|
||||||
$form .= '</div><div class="tab-content">';
|
|
||||||
}
|
|
||||||
preg_match('/define\(\'(.*?)\', ?(.*?)\)/', $rows[$i], $match);
|
|
||||||
if ($match) {
|
|
||||||
$form .= format_var_html($match[1], $match[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$form .= '</div>';
|
|
||||||
|
|
||||||
return $form;
|
// Ensure all_views is loaded
|
||||||
|
if (!isset($all_views) || !is_array($all_views)) {
|
||||||
|
include dirname(__FILE__).'/settings/settingsviews.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = explode("\n", $contents);
|
||||||
|
$output = '';
|
||||||
|
$profile_count = 0;
|
||||||
|
|
||||||
|
// Count profiles for performance warning
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
if (preg_match('/\/\*(.*?)\*\//', $row)) {
|
||||||
|
$profile_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add performance notice for large numbers of profiles
|
||||||
|
if ($profile_count > 10) {
|
||||||
|
$output .= '<div class="msg info" style="margin-bottom: 15px;">';
|
||||||
|
$output .= '<i class="fas fa-info-circle"></i>';
|
||||||
|
$output .= '<p>Managing ' . $profile_count . ' profiles.</p>';
|
||||||
|
$output .= '<i class="fa-times fas" style="cursor: pointer;"></i>';
|
||||||
|
$output .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with General tab and its content
|
||||||
|
$output .= '<div class="tabs"><a href="#" class="profile-tab" data-profile="general">General</a></div>';
|
||||||
|
$output .= '<div id="general-content" class="content-block tab-content profile-content" style="display: none;"><div class="form responsive-width-100">';
|
||||||
|
$output .= '<p class="responsive-width-100" style="margin-bottom: 15px; color: #666;">Each tab represents a profile. Each element in a profile represents a view and or API access. Total views available: ' . (isset($all_views) && is_array($all_views) ? count($all_views) : 0) . '</p>';
|
||||||
|
|
||||||
|
// Add scan views functionality
|
||||||
|
$output .= '<div class="responsive-width-100" style="margin-bottom: 20px; padding: 15px; background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 4px;">';
|
||||||
|
$output .= '<button type="submit" name="scan_views" class="btn" style="background: #28a745; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer;">';
|
||||||
|
$output .= '<i class="fas fa-sync-alt"></i>Update views</button>';
|
||||||
|
$output .= '</div>';
|
||||||
|
|
||||||
|
$current_content = '';
|
||||||
|
$current_profile = 'general';
|
||||||
|
|
||||||
|
for ($i = 0; $i < count($rows); $i++) {
|
||||||
|
// Check for tab comment
|
||||||
|
preg_match('/\/\*(.*?)\*\//', $rows[$i], $tab_match);
|
||||||
|
if ($tab_match) {
|
||||||
|
// Close previous content section and start new tab
|
||||||
|
$output .= $current_content . '</div></div>';
|
||||||
|
$current_profile = strtolower(str_replace(' ', '_', $tab_match[1]));
|
||||||
|
$output .= '<div class="tabs"><a href="#" class="profile-tab" data-profile="' . $current_profile . '">' . $tab_match[1] . '</a></div>';
|
||||||
|
$output .= '<div id="' . $current_profile . '-content" class="content-block tab-content profile-content" style="display: none;"><div class="form responsive-width-100">';
|
||||||
|
$current_content = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for define statements
|
||||||
|
preg_match('/define\(\'(.*?)\', ?(.*?)\)/', $rows[$i], $define_match);
|
||||||
|
if ($define_match) {
|
||||||
|
$current_content .= format_var_html($define_match[1], $define_match[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close final content section
|
||||||
|
$output .= $current_content . '</div></div>';
|
||||||
|
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
if (isset($_POST['submit']) && !empty($_POST)) {
|
if (isset($_POST['submit']) && !empty($_POST)) {
|
||||||
//remove submit from POST
|
//remove submit from POST
|
||||||
@@ -115,6 +264,16 @@ if (isset($_GET['success_msg'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle views added message
|
||||||
|
if (isset($_GET['views_added'])) {
|
||||||
|
$added_count = (int)$_GET['views_added'];
|
||||||
|
if ($added_count > 0) {
|
||||||
|
$success_msg = $added_count . ' new views added!';
|
||||||
|
} else {
|
||||||
|
$success_msg = 'No new views found. All views are up to date.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template_header('Profiles', 'profiles');
|
template_header('Profiles', 'profiles');
|
||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
@@ -123,28 +282,77 @@ $view .= '
|
|||||||
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
|
<div class="content-title responsive-flex-wrap responsive-pad-bot-3">
|
||||||
<h2 class="responsive-width-100">Profiles</h2>
|
<h2 class="responsive-width-100">Profiles</h2>
|
||||||
<input type="submit" name="submit" value="💾+" class="btn">
|
<input type="submit" name="submit" value="💾+" class="btn">
|
||||||
</div>
|
</div>';
|
||||||
';
|
|
||||||
|
|
||||||
if (isset($success_msg)){
|
if (isset($success_msg)){
|
||||||
$view .= ' <div class="msg success">
|
$view .= '<div class="msg success">
|
||||||
<i class="fas fa-check-circle"></i>
|
<i class="fas fa-check-circle"></i>
|
||||||
<p>'.$success_msg.'</p>
|
<p>'.$success_msg.'</p>
|
||||||
<i class="fas fa-times"></i>
|
<i class="fa-times fas" style="cursor: pointer;"></i>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$view .= format_tabs($contents);
|
$view .= format_tabs_and_content($contents);
|
||||||
$view .= '<div class="content-block">
|
$view .= '</form>';
|
||||||
<div class="form responsive-width-100">
|
|
||||||
';
|
|
||||||
$view .= format_form($contents);
|
|
||||||
|
|
||||||
|
// Add basic JavaScript functionality
|
||||||
$view .= '
|
$view .= '
|
||||||
</div>
|
<style>
|
||||||
</div>
|
.profile-content { display: none !important; }
|
||||||
</form>
|
.profile-tab { background: #f8f9fa; color: #333; }
|
||||||
';
|
.profile-tab.active { background: #007bff; color: white; }
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
||||||
|
// Ensure all tabs start inactive
|
||||||
|
document.querySelectorAll(".profile-tab").forEach(tab => {
|
||||||
|
tab.classList.remove("active");
|
||||||
|
});
|
||||||
|
document.querySelectorAll(".profile-content").forEach(content => {
|
||||||
|
content.style.display = "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Tab functionality
|
||||||
|
document.addEventListener("click", function(e) {
|
||||||
|
if (e.target.classList.contains("profile-tab")) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Hide all content
|
||||||
|
document.querySelectorAll(".profile-content").forEach(content => {
|
||||||
|
content.style.display = "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove active class from all tabs
|
||||||
|
document.querySelectorAll(".profile-tab").forEach(t => {
|
||||||
|
t.classList.remove("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show selected content and mark tab as active
|
||||||
|
const profileId = e.target.dataset.profile;
|
||||||
|
const content = document.getElementById(profileId + "-content");
|
||||||
|
if (content) {
|
||||||
|
content.style.display = "block";
|
||||||
|
e.target.classList.add("active");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bulk select functionality
|
||||||
|
if (e.target.classList.contains("select-all")) {
|
||||||
|
const profile = e.target.dataset.profile;
|
||||||
|
const checkboxes = document.querySelectorAll("[name=\\"" + profile + "[]\\"]");
|
||||||
|
checkboxes.forEach(cb => cb.checked = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.target.classList.contains("select-none")) {
|
||||||
|
const profile = e.target.dataset.profile;
|
||||||
|
const checkboxes = document.querySelectorAll("[name=\\"" + profile + "[]\\"]");
|
||||||
|
checkboxes.forEach(cb => cb.checked = false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>';
|
||||||
|
|
||||||
//Output
|
//Output
|
||||||
echo $view;
|
echo $view;
|
||||||
|
|||||||
@@ -522,7 +522,6 @@ main .content-block {
|
|||||||
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.1), 0px 1px 2px 0px rgba(0, 0, 0, 0.06);
|
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.1), 0px 1px 2px 0px rgba(0, 0, 0, 0.06);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #e2e8f0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main .content-block:has(.sortable) {
|
main .content-block:has(.sortable) {
|
||||||
@@ -556,7 +555,7 @@ main .content-block .block-header i {
|
|||||||
main .content-block-wrapper {
|
main .content-block-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-top: 25px;
|
padding-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
main .content-block-wrapper .content-block {
|
main .content-block-wrapper .content-block {
|
||||||
@@ -624,7 +623,6 @@ main .tabs ~ .content-block {
|
|||||||
|
|
||||||
main .tab-content {
|
main .tab-content {
|
||||||
display: none;
|
display: none;
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-top: none;
|
border-top: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: max-height 0.3s ease;
|
transition: max-height 0.3s ease;
|
||||||
|
|||||||
Reference in New Issue
Block a user