395 lines
14 KiB
PHP
395 lines
14 KiB
PHP
<?php
|
|
// asset.php
|
|
session_start();
|
|
require_once '../config.php';
|
|
|
|
// Optional: enable during debugging only (remove or comment in production)
|
|
# ini_set('display_errors', 1);
|
|
# ini_set('display_startup_errors', 1);
|
|
# error_reporting(E_ALL);
|
|
|
|
// --- Security check ---
|
|
if (!isset($_SESSION['user_email'])) {
|
|
header('Location: index.php');
|
|
exit();
|
|
}
|
|
|
|
// --- Company from session ---
|
|
$company = $_SESSION['company'] ?? '';
|
|
if ($company === '') {
|
|
http_response_code(400);
|
|
exit('No company assigned in session.');
|
|
}
|
|
$table = 'assets'; // Fixed table name
|
|
|
|
// --- Row id ---
|
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
|
http_response_code(400);
|
|
exit('Invalid record ID');
|
|
}
|
|
$recordId = (int) $_GET['id'];
|
|
|
|
// --- Admin check from session ---
|
|
$role = $_SESSION['role'] ?? 'user';
|
|
$isAdmin = ($role === 'admin' || $role === 'superadmin');
|
|
$currentUserEmail = $_SESSION['user_email'] ?? '';
|
|
$currentUserEmail = $_SESSION['user_email'] ?? '';
|
|
|
|
// --- Helper functions ---
|
|
// --- DB Connection ---
|
|
try {
|
|
$pdo = new PDO(
|
|
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
|
|
DB_USER,
|
|
DB_PASS,
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
|
|
);
|
|
} catch (PDOException $e) {
|
|
die("DB Connection failed: " . $e->getMessage());
|
|
}
|
|
|
|
require_once '../s3_client.php';
|
|
$s3 = new S3Client();
|
|
|
|
// --- Helper functions (Local DB & S3) ---
|
|
function get_row($pdo, $table, $id, $company)
|
|
{
|
|
$stmt = $pdo->prepare("SELECT * FROM `$table` WHERE Id = :id AND company = :company");
|
|
$stmt->execute([':id' => $id, ':company' => $company]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
|
|
}
|
|
|
|
function update_row($pdo, $table, $id, $data, $company)
|
|
{
|
|
if (empty($data))
|
|
return;
|
|
$set = [];
|
|
$params = [':id' => $id, ':company' => $company];
|
|
foreach ($data as $col => $val) {
|
|
$set[] = "`$col` = :$col";
|
|
$params[":$col"] = $val;
|
|
}
|
|
$sql = "UPDATE `$table` SET " . implode(', ', $set) . " WHERE Id = :id AND company = :company";
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
}
|
|
|
|
function get_files($pdo, $table, $id)
|
|
{
|
|
$stmt = $pdo->prepare("SELECT * FROM device_files WHERE device_id = :id AND device_table = 'assets'");
|
|
$stmt->execute([':id' => $id]);
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
function upload_file($pdo, $s3, $table, $id, $file)
|
|
{
|
|
$fileName = $file['name'];
|
|
$tmpName = $file['tmp_name'];
|
|
$mime = $file['type'];
|
|
$size = $file['size'];
|
|
|
|
// Generate unique key
|
|
$key = "uploads/$table/$id/" . uniqid() . '_' . $fileName;
|
|
|
|
$result = $s3->uploadFile($tmpName, $key, $mime);
|
|
|
|
if ($result['success']) {
|
|
$stmt = $pdo->prepare("INSERT INTO device_files (device_id, device_table, file_path, file_name, mime_type, size) VALUES (:did, :dtab, :path, :name, :mime, :size)");
|
|
$stmt->execute([
|
|
':did' => $id,
|
|
':dtab' => 'assets',
|
|
':path' => $key,
|
|
':name' => $fileName,
|
|
':mime' => $mime,
|
|
':size' => $size
|
|
]);
|
|
return ['success' => true];
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
function delete_file($pdo, $s3, $fileId)
|
|
{
|
|
$stmt = $pdo->prepare("SELECT * FROM device_files WHERE id = :id");
|
|
$stmt->execute([':id' => $fileId]);
|
|
$file = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($file) {
|
|
if ($s3->deleteFile($file['file_path'])) {
|
|
$del = $pdo->prepare("DELETE FROM device_files WHERE id = :id");
|
|
$del->execute([':id' => $fileId]);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// --- Handle file actions ---
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
if ($role === 'user') {
|
|
die('Access Denied: Read-only user.');
|
|
}
|
|
if (isset($_FILES['new_file'])) {
|
|
$file = $_FILES['new_file'];
|
|
if ($file['error'] === UPLOAD_ERR_OK) {
|
|
$result = upload_file($pdo, $s3, $table, $recordId, $file);
|
|
if (!$result['success']) {
|
|
die("S3 Upload Failed. Code: " . $result['code'] . " | Message: " . htmlspecialchars($result['message']));
|
|
}
|
|
} else {
|
|
die("File upload error code: " . $file['error']);
|
|
}
|
|
header("Location: asset.php?id=" . urlencode((string) $recordId));
|
|
exit();
|
|
}
|
|
if (isset($_POST['delete_file'])) {
|
|
delete_file($pdo, $s3, $_POST['delete_file']);
|
|
header("Location: asset.php?id=" . urlencode((string) $recordId));
|
|
exit();
|
|
}
|
|
}
|
|
|
|
// --- Row data ---
|
|
$row = get_row($pdo, $table, $recordId, $company);
|
|
if ($role === 'user' && ($row['UserEmail'] ?? '') !== $currentUserEmail) {
|
|
die('Access Denied: You do not own this asset.');
|
|
}
|
|
$files = get_files($pdo, $table, $recordId);
|
|
|
|
$companyUsers = [];
|
|
if ($role === 'admin' || $role === 'manager' || $role === 'superadmin') {
|
|
// Fetch all users for this company to populate the dropdown
|
|
$uStmt = $pdo->prepare("SELECT email FROM users WHERE company = :comp ORDER BY email ASC");
|
|
$uStmt->execute([':comp' => $company]);
|
|
$companyUsers = $uStmt->fetchAll(PDO::FETCH_COLUMN);
|
|
}
|
|
function escape($v)
|
|
{
|
|
return htmlspecialchars((string) ($v ?? ''), ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
// Serial number for title/h2; fall back to record id if empty
|
|
$serial = trim((string) ($row['SN'] ?? ''));
|
|
$serialForTitle = $serial !== '' ? $serial : (string) $recordId;
|
|
|
|
// --- Columns config ---
|
|
// Reordered: Term first, then LastSeen, then UserEmail, then rest.
|
|
$columns = [
|
|
'Id',
|
|
'UUID',
|
|
'SN',
|
|
'OS',
|
|
'OSVersion',
|
|
'Hostname',
|
|
'Mobile',
|
|
'Manufacturer',
|
|
'Term',
|
|
'LastSeen',
|
|
'UserEmail',
|
|
'BYOD',
|
|
'Status',
|
|
'Warranty',
|
|
'Asset',
|
|
'PurchaseDate',
|
|
'CypherID',
|
|
'CypherKey',
|
|
'Notes'
|
|
];
|
|
|
|
// Insert the new read-only, view-only columns immediately after CypherKey (or append if not present)
|
|
$newReadOnlyCols = [
|
|
'CPUs',
|
|
'HDs',
|
|
'HDsTypes',
|
|
'HDsSpacesGB',
|
|
'NetworkAdapters',
|
|
'MACAddresses',
|
|
'ESETComponents',
|
|
'PrimaryLocalIP',
|
|
'PrimaryRemoteIP'
|
|
];
|
|
$idx = array_search('CypherKey', $columns, true);
|
|
if ($idx !== false) {
|
|
array_splice($columns, $idx + 1, 0, $newReadOnlyCols);
|
|
} else {
|
|
// Non-admin or CypherKey absent: still show these new fields
|
|
$columns = array_merge($columns, $newReadOnlyCols);
|
|
}
|
|
|
|
$hidden = ['Id'];
|
|
$editable = ['UserEmail', 'Status', 'Warranty', 'Asset', 'PurchaseDate', 'BYOD'];
|
|
|
|
// Role-based editability
|
|
if ($role === 'user') {
|
|
$editable = [];
|
|
} else {
|
|
// Manager, Admin, Superadmin can edit Notes
|
|
if (in_array($role, ['manager', 'admin', 'superadmin'])) {
|
|
$editable[] = 'Notes';
|
|
}
|
|
// Admin, Superadmin can edit Cypher fields
|
|
if (in_array($role, ['admin', 'superadmin'])) {
|
|
$editable[] = 'CypherID';
|
|
$editable[] = 'CypherKey';
|
|
}
|
|
}
|
|
// Mark the requested fields as read-only (view-only)
|
|
$readonly = array_merge(
|
|
['Hostname'],
|
|
[
|
|
'CPUs',
|
|
'HDs',
|
|
'HDsTypes',
|
|
'HDsSpacesGB',
|
|
'NetworkAdapters',
|
|
'MACAddresses',
|
|
'ESETComponents',
|
|
'PrimaryLocalIP',
|
|
'PrimaryRemoteIP'
|
|
]
|
|
);
|
|
|
|
$display = array_filter($columns, fn($c) => !in_array($c, $hidden, true));
|
|
|
|
$status_options = ["In Use", "In Stock", "In Repair", "Replaced", "Decommissioned", "Lost or Stolen"];
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>CMDB Row Details (SN #<?php echo escape($serialForTitle); ?>)</title>
|
|
<link rel="stylesheet" href="style.css">
|
|
</head>
|
|
|
|
<body class="asset-page">
|
|
<a href="main.php" class="back-link">← Back to CMDB Company: <?php echo escape($company); ?></a>
|
|
<h2>CMDB Row Details (SN #<?php echo escape($serialForTitle); ?>)</h2>
|
|
|
|
<form method="post" action="save_row.php" class="form-section">
|
|
<input type="hidden" name="row[Id]" value="<?php echo escape($row['Id'] ?? $recordId); ?>">
|
|
<input type="hidden" name="row[UUID]" value="<?php echo escape($row['UUID'] ?? ''); ?>">
|
|
|
|
<table class="details-table">
|
|
<tbody>
|
|
<?php foreach ($display as $col): ?>
|
|
<tr>
|
|
<th><?php echo escape($col); ?></th>
|
|
<td>
|
|
<?php
|
|
$value = $row[$col] ?? '';
|
|
|
|
// Mobile: show "True"/"False" explicitly
|
|
if ($col === 'Mobile') {
|
|
$norm = is_bool($value) ? $value : strtolower(trim((string) $value));
|
|
$isMobile = is_bool($norm) ? $norm : in_array($norm, ['true', '1', 'yes', 'on'], true);
|
|
echo $isMobile ? 'True' : 'False';
|
|
|
|
} elseif ($col === 'Term') {
|
|
$count = is_array($row['Term'] ?? null) ? count($row['Term']) : 0;
|
|
echo $count ? "$count file" . ($count > 1 ? 's' : '') : 'No files';
|
|
|
|
} elseif ($col === 'SN') {
|
|
echo escape($value);
|
|
|
|
} elseif (in_array($col, $editable, true)) {
|
|
|
|
if ($col === 'BYOD') {
|
|
$v = strtolower(trim((string) $value));
|
|
$isTrue = in_array($v, ['true', '1', 'yes', 'on'], true);
|
|
?>
|
|
<select name="row[BYOD]">
|
|
<option value="true" <?php echo $isTrue ? 'selected' : ''; ?>>True</option>
|
|
<option value="false" <?php echo !$isTrue ? 'selected' : ''; ?>>False</option>
|
|
</select>
|
|
<?php } elseif ($col === 'Status') { ?>
|
|
<select name="row[Status]">
|
|
<option value="" <?php echo ($value === '' || is_null($value)) ? 'selected' : ''; ?>></option>
|
|
<?php foreach ($status_options as $opt): ?>
|
|
<option value="<?php echo escape($opt); ?>" <?php echo ($value === $opt) ? 'selected' : ''; ?>>
|
|
<?php echo escape($opt); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<?php } elseif ($col === 'UserEmail') { ?>
|
|
<select name="row[UserEmail]">
|
|
<option value="" <?php echo ($value === '') ? 'selected' : ''; ?>></option>
|
|
<?php foreach ($companyUsers as $uEmail): ?>
|
|
<option value="<?php echo escape($uEmail); ?>" <?php echo ($value === $uEmail) ? 'selected' : ''; ?>>
|
|
<?php echo escape($uEmail); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<?php } elseif ($col === 'Warranty' || $col === 'PurchaseDate') { ?>
|
|
<input type="date" name="row[<?php echo escape($col); ?>]"
|
|
value="<?php echo escape($value); ?>">
|
|
<?php } elseif ($col === 'Notes') { ?>
|
|
<textarea name="row[<?php echo escape($col); ?>]" rows="5" style="width: 100%;"><?php echo escape($value); ?></textarea>
|
|
<?php } else { ?>
|
|
<input type="text" name="row[<?php echo escape($col); ?>]"
|
|
value="<?php echo escape($value); ?>">
|
|
<?php }
|
|
|
|
} elseif (in_array($col, $readonly, true)) {
|
|
echo is_array($value) ? escape(json_encode($value)) : escape($value);
|
|
|
|
} elseif ($col === 'BYOD') {
|
|
$v = strtolower(trim((string) $value));
|
|
$isTrue = in_array($v, ['true', '1', 'yes', 'on'], true);
|
|
echo $isTrue ? 'True' : 'False';
|
|
|
|
} else {
|
|
echo is_array($value) ? escape(json_encode($value)) : escape($value);
|
|
}
|
|
?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="save-section">
|
|
<?php if ($role !== 'user'): ?>
|
|
<button type="submit">Save Changes</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Files Upload -->
|
|
<?php if ($role !== 'user'): ?>
|
|
<div class="upload-box">
|
|
<h3>Upload New File</h3>
|
|
<form method="post" enctype="multipart/form-data">
|
|
<input type="file" name="new_file" required>
|
|
<button type="submit" class="upload">Upload</button>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Existing Files -->
|
|
<div class="existing-files">
|
|
<h3>Existing Files</h3>
|
|
<div class="file-list">
|
|
<?php if (is_array($files) && count($files)):
|
|
foreach ($files as $f):
|
|
$url = $s3->getPresignedUrl($f['file_path']);
|
|
$title = $f['file_name'];
|
|
$delete = $f['id'];
|
|
?>
|
|
<div class="file-item">
|
|
<a href="<?php echo escape($url); ?>" target="_blank"><?php echo escape($title); ?></a>
|
|
<?php if ($role !== 'user'): ?>
|
|
<form method="post" style="display:inline;">
|
|
<input type="hidden" name="delete_file" value="<?php echo escape($delete); ?>">
|
|
<button type="submit" onclick="return confirm('Delete this file?');">Delete</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endforeach; else: ?>
|
|
<div>No files found.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
|
|
</html>
|