DSP Project first push, date: 29/01/2026
This commit is contained in:
341
data_user/browse_datasources.php
Normal file
341
data_user/browse_datasources.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
// data_user/browse_datasources.php
|
||||
// This page allows users (including guests) to browse available data sources.
|
||||
|
||||
// Enable detailed error reporting for debugging purposes (log only)
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0);
|
||||
|
||||
// Check if a session is not already active before starting one.
|
||||
// This prevents the "session already active" notice.
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Use __DIR__ to get the absolute path to this file's directory,
|
||||
// ensuring the path to the required files is always correct.
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once(__DIR__ . '/../includes/auth.php');
|
||||
require_once(__DIR__ . '/../classes/DataSource.php');
|
||||
require_once(__DIR__ . '/../classes/Classifications.php');
|
||||
require_once(__DIR__ . '/../classes/User.php');
|
||||
require_once(__DIR__ . '/../classes/Permission.php'); // Correctly include the Permission class
|
||||
|
||||
// Check if user is logged in
|
||||
$is_logged_in = isset($_SESSION['user_id']);
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
$person_id = $_SESSION['person_id'] ?? null;
|
||||
$username = $_SESSION['username'] ?? null;
|
||||
$usernameLabel = $username ? htmlspecialchars($username, ENT_QUOTES, 'UTF-8') : 'Guest';
|
||||
|
||||
$currentPage = basename($_SERVER['PHP_SELF']);
|
||||
|
||||
// Instantiate classes
|
||||
$dataSourceManager = new DataSource($pdo);
|
||||
$classificationManager = new Classifications($pdo);
|
||||
$userManager = new User($pdo);
|
||||
$permissionManager = new Permission($pdo); // Instantiate the Permission class
|
||||
|
||||
// Get user details if logged in
|
||||
$currentUserDetails = $is_logged_in ? $userManager->getUserDetails($user_id) : null;
|
||||
|
||||
$uploadsWebPath = '../uploads/datasources/';
|
||||
|
||||
// Get filter parameters from GET request
|
||||
$filter_category_id = $_GET['category_id'] ?? null;
|
||||
if ($filter_category_id !== null) {
|
||||
$filter_category_id = filter_var($filter_category_id, FILTER_VALIDATE_INT);
|
||||
if ($filter_category_id === false) {
|
||||
$filter_category_id = null;
|
||||
}
|
||||
}
|
||||
$search_query = htmlspecialchars($_GET['search'] ?? '', ENT_QUOTES, 'UTF-8');
|
||||
|
||||
// Fetch data sources based on filters
|
||||
$data_sources = [];
|
||||
try {
|
||||
$data_sources = $dataSourceManager->getDataSources(
|
||||
null, // No owner filter for public browsing
|
||||
'Active',
|
||||
$filter_category_id,
|
||||
$search_query
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
set_message('Error retrieving data sources: ' . $e->getMessage(), 'danger');
|
||||
}
|
||||
|
||||
// Fetch all categories for the filter dropdown
|
||||
$all_categories = [];
|
||||
try {
|
||||
$all_categories = $classificationManager->getAllCategories();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error fetching categories for browse_datasources: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!-- Header -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/header_user.php");
|
||||
?>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<!-- Sidebar -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/nav_user.php");
|
||||
?>
|
||||
<!-- Page Content -->
|
||||
<div class="main-content">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4 rounded-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"> Browse All Data</a>
|
||||
<div class="d-flex">
|
||||
<span class="navbar-text me-3">
|
||||
Welcome, <?php echo $usernameLabel; ?>!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-<?= $_SESSION['message_type'] ?> alert-dismissible fade show rounded" role="alert">
|
||||
<?= $_SESSION['message'] ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['message']);
|
||||
unset($_SESSION['message_type']);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Filter and Search Form -->
|
||||
<div class="card shadow-sm rounded mb-4 p-3">
|
||||
<div class="card-body">
|
||||
<form action="browse_datasources.php" method="GET" class="row g-3 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label for="categoryFilter" class="form-label">Filter by Category:</label>
|
||||
<select class="form-select rounded" id="categoryFilter" name="category_id">
|
||||
<option value="">All Categories</option>
|
||||
<?php foreach ($all_categories as $category): ?>
|
||||
<option value="<?php echo htmlspecialchars($category['pkdspscate_id']); ?>"
|
||||
<?php echo ($filter_category_id == $category['pkdspscate_id']) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($category['dspscate_title_en']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<label for="searchQuery" class="form-label">Search by Title/Description:</label>
|
||||
<input type="text" class="form-control rounded" id="searchQuery" name="search"
|
||||
value="<?php echo htmlspecialchars($search_query); ?>" placeholder="Enter keywords...">
|
||||
</div>
|
||||
<div class="col-md-3 d-grid">
|
||||
<button type="submit" class="btn btn-primary rounded">
|
||||
<i class="fas fa-filter me-2"></i> Apply Filters
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Sources List -->
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mt-4">
|
||||
<?php if (!empty($data_sources)): ?>
|
||||
<?php foreach ($data_sources as $ds): ?>
|
||||
<div class="col">
|
||||
<div class="card h-100 shadow-sm rounded">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title text-primary"><?php echo htmlspecialchars($ds['dspsds_title_en']); ?></h5>
|
||||
<h6 class="card-subtitle mb-2 text-muted">Category: <?php echo htmlspecialchars($ds['category_name']); ?></h6>
|
||||
<h6 class="card-subtitle mb-2 text-muted">Type: <?php echo htmlspecialchars($ds['data_type_name']); ?></h6>
|
||||
<p class="card-text flex-grow-1"><?php echo htmlspecialchars(substr($ds['dspsds_description'], 0, 150)) . (strlen($ds['dspsds_description']) > 150 ? '...' : ''); ?></p>
|
||||
<div class="mt-auto">
|
||||
<ul class="list-unstyled small text-muted">
|
||||
<li><i class="fas fa-user me-1"></i> Data Owner: <?php echo htmlspecialchars($ds['isp_firstname_en'] . ' ' . $ds['isp_lastname_en']); ?></li>
|
||||
<li><i class="fas fa-calendar-alt me-1"></i> Published:
|
||||
<?php if (!empty($ds['dspsds_public_date'])): ?>
|
||||
<?= htmlspecialchars(date('M d, Y', strtotime($ds['dspsds_public_date']))); ?>
|
||||
<?php else: ?>
|
||||
Not specified
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
</ul>
|
||||
<?php
|
||||
$supportingFiles = [
|
||||
'dspsds_filename1' => ['label' => 'Questionnaire / Data Dictionary', 'icon' => 'fa-clipboard-list'],
|
||||
'dspsds_filename2' => ['label' => 'Protocol / User Guide', 'icon' => 'fa-book'],
|
||||
'dspsds_filename3' => ['label' => 'Other Supporting Document', 'icon' => 'fa-file-alt'],
|
||||
];
|
||||
?>
|
||||
<div class="bg-light-subtle border rounded p-3 mb-3">
|
||||
<span class="d-block text-uppercase text-muted fw-semibold small mb-2">Supporting Documents</span>
|
||||
<ul class="list-unstyled mb-0 small">
|
||||
<?php foreach ($supportingFiles as $column => $meta): ?>
|
||||
<?php
|
||||
$fileName = $ds[$column] ?? '';
|
||||
$label = $meta['label'];
|
||||
$icon = $meta['icon'];
|
||||
?>
|
||||
<li class="mb-2">
|
||||
<i class="fas <?= htmlspecialchars($icon, ENT_QUOTES, 'UTF-8') ?> me-1"></i>
|
||||
<?php if (!empty($fileName)): ?>
|
||||
<?php
|
||||
$isUrl = preg_match('/^https?:\/\//i', $fileName) === 1;
|
||||
$linkTarget = $isUrl ? $fileName : $uploadsWebPath . rawurlencode($fileName);
|
||||
?>
|
||||
<a href="<?= htmlspecialchars($linkTarget, ENT_QUOTES, 'UTF-8') ?>" target="_blank" rel="noopener">
|
||||
<?= htmlspecialchars($label) ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<span class="text-muted"><?= htmlspecialchars($label) ?> (Not provided)</span>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php if ($is_logged_in): ?>
|
||||
<?php
|
||||
$has_read_permission = false;
|
||||
$has_download_permission = false;
|
||||
try {
|
||||
$has_read_permission = $permissionManager->hasPermission($person_id, $ds['pkdspsds_id'], 'Read');
|
||||
$has_download_permission = $permissionManager->hasPermission($person_id, $ds['pkdspsds_id'], 'Download');
|
||||
} catch (Exception $e) {
|
||||
error_log("Permission check error for user " . $person_id . " on DS " . $ds['pkdspsds_id'] . ": " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
<?php if ($has_read_permission): ?>
|
||||
<a href="#" class="btn btn-sm btn-outline-success rounded me-2 disabled">
|
||||
<i class="fas fa-check-circle me-1"></i> Read Access Granted
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<button type="button" class="btn btn-sm btn-success rounded me-2" data-bs-toggle="modal" data-bs-target="#requestPermissionModal"
|
||||
data-ds-id="<?php echo htmlspecialchars($ds['pkdspsds_id']); ?>"
|
||||
data-ds-title="<?php echo htmlspecialchars($ds['dspsds_title_en']); ?>"
|
||||
data-permission-type="Read">
|
||||
<i class="fas fa-file-alt me-1"></i> Request Read Access
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($has_download_permission): ?>
|
||||
<a href="download.php?dspsds_id=<?php echo htmlspecialchars($ds['pkdspsds_id']); ?>" class="btn btn-sm btn-outline-primary rounded">
|
||||
<i class="fas fa-download me-1"></i> Download File
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<button type="button" class="btn btn-sm btn-primary rounded" data-bs-toggle="modal" data-bs-target="#requestPermissionModal"
|
||||
data-ds-id="<?php echo htmlspecialchars($ds['pkdspsds_id']); ?>"
|
||||
data-ds-title="<?php echo htmlspecialchars($ds['dspsds_title_en']); ?>"
|
||||
data-permission-type="Download">
|
||||
<i class="fas fa-cloud-download-alt me-1"></i> Request Download
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<button type="button" class="btn btn-sm btn-secondary rounded" data-bs-toggle="modal" data-bs-target="#loginModal">
|
||||
<i class="fas fa-sign-in-alt me-1"></i> Login to Request Access
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info rounded text-center">
|
||||
No active data sources found matching your criteria.
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Request Permission Modal -->
|
||||
<div class="modal fade" id="requestPermissionModal" tabindex="-1" aria-labelledby="requestPermissionModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded shadow-lg">
|
||||
<div class="modal-header bg-success text-white rounded-top">
|
||||
<h5 class="modal-title" id="requestPermissionModalLabel">Request Data Access Permission</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form action="../data_user/process_request_permission.php" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="data_source_id" id="modalDataSourceId">
|
||||
<input type="hidden" name="permission_type" id="modalPermissionType">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="modalDataSourceTitle" class="form-label">Data Source</label>
|
||||
<input type="text" class="form-control rounded" id="modalDataSourceTitle" readonly>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="modalRequestedPermission" class="form-label">Requested Permission</label>
|
||||
<input type="text" class="form-control rounded" id="modalRequestedPermission" readonly>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="requestNotes" class="form-label">Reason for Request (Required)</label>
|
||||
<textarea class="form-control rounded-3" id="requestNotes" name="notes" rows="4" placeholder="Please explain why you need this data and how you plan to use it." required></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="proofFile" class="form-label">Upload Proof (PDF only)</label>
|
||||
<input type="file" class="form-control rounded" id="proofFile" name="proof_file" accept="application/pdf" required>
|
||||
<div class="form-text">Attach an official letter, approval memo, or supporting document in PDF format (max 10 MB).</div>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-success rounded">Submit Request</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Login Modal for guests -->
|
||||
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded shadow-lg">
|
||||
<div class="modal-header bg-primary text-white rounded-top">
|
||||
<h5 class="modal-title" id="loginModalLabel">Login Required</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center p-4">
|
||||
<p>You must be logged in to request access to data sources.</p>
|
||||
<a href="../index.php?page=login" class="btn btn-primary rounded me-2">Login</a>
|
||||
<a href="../index.php?page=register" class="btn btn-outline-primary rounded">Register</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<?php
|
||||
// Include Footer file for owner pages
|
||||
include_once("../includes/footer_user.php");
|
||||
?>
|
||||
<script>
|
||||
// JavaScript to populate the permission request modal
|
||||
var requestPermissionModal = document.getElementById('requestPermissionModal');
|
||||
if (requestPermissionModal) {
|
||||
requestPermissionModal.addEventListener('show.bs.modal', function (event) {
|
||||
var button = event.relatedTarget; // Button that triggered the modal
|
||||
var dsId = button.getAttribute('data-ds-id');
|
||||
var dsTitle = button.getAttribute('data-ds-title');
|
||||
var permissionType = button.getAttribute('data-permission-type');
|
||||
|
||||
var modalDataSourceId = requestPermissionModal.querySelector('#modalDataSourceId');
|
||||
var modalDataSourceTitle = requestPermissionModal.querySelector('#modalDataSourceTitle');
|
||||
var modalPermissionType = requestPermissionModal.querySelector('#modalPermissionType');
|
||||
var modalRequestedPermission = requestPermissionModal.querySelector('#modalRequestedPermission');
|
||||
|
||||
modalDataSourceId.value = dsId;
|
||||
modalDataSourceTitle.value = dsTitle;
|
||||
modalPermissionType.value = permissionType;
|
||||
modalRequestedPermission.value = permissionType; // Display the type in the modal
|
||||
requestPermissionModal.querySelector('#requestNotes').value = ''; // Clear notes on new open
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
166
data_user/dashboard.php
Normal file
166
data_user/dashboard.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
// data_user/dashboard.php
|
||||
session_start();
|
||||
require_once '../config.php';
|
||||
require_once '../includes/auth.php';
|
||||
require_once '../classes/DataSource.php'; // For data source related counts
|
||||
|
||||
// Ensure only Data Users can access this dashboard
|
||||
redirect_if_not_role('Data User');
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$person_id = $_SESSION['person_id'];
|
||||
$username = $_SESSION['username'];
|
||||
$user_status = $_SESSION['user_status'];
|
||||
|
||||
$data_source_manager = new DataSource($pdo);
|
||||
|
||||
// Get counts for Data User
|
||||
$approved_datasources_count = 0;
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COUNT(DISTINCT dp.fkdspsds_id)
|
||||
FROM dsps_tbl_datasource_permission dp
|
||||
WHERE dp.fkisp_id_of = :person_id AND dp.dspsdsp_status = 'Approved'
|
||||
");
|
||||
$stmt->execute(['person_id' => $person_id]);
|
||||
$approved_datasources_count = $stmt->fetchColumn();
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error fetching approved datasources count: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$pending_requests_count = 0;
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COUNT(dp.pkdspsdsp_id)
|
||||
FROM dsps_tbl_datasource_permission dp
|
||||
WHERE dp.fkisp_id_of = :person_id AND dp.dspsdsp_status = 'Pending'
|
||||
");
|
||||
$stmt->execute(['person_id' => $person_id]);
|
||||
$pending_requests_count = $stmt->fetchColumn();
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error fetching pending requests count: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$my_downloads_count = 0;
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COUNT(*) FROM dsps_tbl_datasource_used
|
||||
WHERE fkisp_id_of = :person_id AND dspsdspused_action = 'Downloaded'
|
||||
");
|
||||
$stmt->execute(['person_id' => $person_id]);
|
||||
$my_downloads_count = $stmt->fetchColumn();
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error fetching my downloads count: " . $e->getMessage());
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!-- Header -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/header_user.php");
|
||||
?>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<!-- Sidebar -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/nav_user.php");
|
||||
?>
|
||||
<!-- Page Content -->
|
||||
<div class="main-content">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4 rounded-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"> Dashboard</a>
|
||||
<div class="d-flex">
|
||||
<span class="navbar-text me-3">
|
||||
Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?>!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-<?= $_SESSION['message_type'] ?> alert-dismissible fade show rounded" role="alert">
|
||||
<?= $_SESSION['message'] ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['message']);
|
||||
unset($_SESSION['message_type']);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm rounded">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-success"><i class="fas fa-check-circle me-2"></i> Approved Data Sources</h5>
|
||||
<p class="card-text fs-2"><?= $approved_datasources_count ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm rounded">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-warning"><i class="fas fa-hourglass-start me-2"></i> Pending Requests</h5>
|
||||
<p class="card-text fs-2"><?= $pending_requests_count ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm rounded">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-info"><i class="fas fa-download me-2"></i> My Total Downloads</h5>
|
||||
<p class="card-text fs-2"><?= $my_downloads_count ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<h3>Quick Actions</h3>
|
||||
<div class="d-flex flex-wrap gap-3">
|
||||
<a href="browse_datasources.php" class="btn btn-primary rounded"><i class="fas fa-search me-2"></i> Browse All Data</a>
|
||||
<a href="my_permissions.php" class="btn btn-warning rounded"><i class="fas fa-handshake me-2"></i> View My Permissions</a>
|
||||
<a href="my_downloads.php" class="btn btn-info rounded"><i class="fas fa-download me-2"></i> My Download History</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Placeholder for recently accessed data sources -->
|
||||
<div class="mt-5">
|
||||
<h3>Recently Accessed Data Sources</h3>
|
||||
<ul class="list-group shadow-sm rounded">
|
||||
<?php
|
||||
// Example recent activities (replace with actual data from dsps_tbl_datasource_used)
|
||||
// You'd need to fetch these from the database, filtered by fkisp_id_of = $person_id
|
||||
$recent_accesses = [
|
||||
['title' => 'Health Survey 2023', 'action' => 'Downloaded', 'time' => '1 hour ago'],
|
||||
['title' => 'Education Statistics 2022', 'action' => 'Viewed Details', 'time' => 'Yesterday'],
|
||||
['title' => 'Climate Data Phnom Penh', 'action' => 'Ran Analysis', 'time' => '3 days ago'],
|
||||
];
|
||||
if (!empty($recent_accesses)) {
|
||||
foreach ($recent_accesses as $access) {
|
||||
echo '<li class="list-group-item d-flex justify-content-between align-items-center">';
|
||||
echo htmlspecialchars($access['title']) . ' - ' . htmlspecialchars($access['action']);
|
||||
echo '<span class="badge bg-secondary">' . htmlspecialchars($access['time']) . '</span>';
|
||||
echo '</li>';
|
||||
}
|
||||
} else {
|
||||
echo '<li class="list-group-item text-center text-muted">No recent activity.</li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<?php
|
||||
// Include Footer file for owner pages
|
||||
include_once("../includes/footer_user.php");
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
109
data_user/download.php
Normal file
109
data_user/download.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
// This script handles the file download and logs the action to the database.
|
||||
|
||||
// Start the session to access user info
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
require_once '../config.php';
|
||||
require_once '../includes/auth.php'; // Make sure your auth.php includes a redirect_if_not_logged_in or similar function
|
||||
|
||||
// --- 1. Get User and Datasource IDs ---
|
||||
// Ensure the user is logged in
|
||||
redirect_if_not_logged_in('../login.php');
|
||||
|
||||
// Get the user's person_id from the session
|
||||
$person_id = $_SESSION['person_id'];
|
||||
|
||||
// Get the datasource_id from the URL parameter
|
||||
$datasource_id = $_GET['dspsds_id'] ?? null;
|
||||
|
||||
// Validate the datasource_id
|
||||
if (!$datasource_id || !filter_var($datasource_id, FILTER_VALIDATE_INT)) {
|
||||
die("Invalid or missing datasource ID.");
|
||||
}
|
||||
|
||||
// --- 2. Log the Download Action ---
|
||||
// This code inserts a new record for every download.
|
||||
try {
|
||||
$sql_insert = "
|
||||
INSERT INTO dsps_tbl_datasource_used
|
||||
(fkdspsdsused_id, fkisp_id_of, dspsdspused_action)
|
||||
VALUES
|
||||
(?, ?, ?)
|
||||
";
|
||||
$stmt_insert = $pdo->prepare($sql_insert);
|
||||
$action = "Downloaded";
|
||||
$stmt_insert->execute([$datasource_id, $person_id, $action]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// We now log the error and set a user-facing message
|
||||
error_log("Error logging download: " . $e->getMessage());
|
||||
// Redirect with an error message, but still try to serve the file
|
||||
set_message("An error occurred while logging the download.", "danger");
|
||||
// We do not die here, as we still want to try and serve the file
|
||||
}
|
||||
|
||||
// --- 3. Retrieve File Path and Name ---
|
||||
$file_path = null;
|
||||
$file_name = null;
|
||||
try {
|
||||
$sql_select = "
|
||||
SELECT dspsds_filename, dspsds_title_en
|
||||
FROM dsps_tbl_datasource
|
||||
WHERE pkdspsds_id = ?
|
||||
";
|
||||
$stmt = $pdo->prepare($sql_select);
|
||||
$stmt->execute([$datasource_id]);
|
||||
$row = $stmt->fetch();
|
||||
|
||||
if ($row) {
|
||||
$file_name = $row['dspsds_filename'];
|
||||
$download_label = $row['dspsds_title_en'] ?: 'datasource_' . $datasource_id;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error retrieving file info: " . $e->getMessage());
|
||||
die("An error occurred while retrieving file information.");
|
||||
}
|
||||
|
||||
if (empty($file_name)) {
|
||||
die("File not found in the database.");
|
||||
}
|
||||
|
||||
if (preg_match('/^https?:\\/\\//i', $file_name)) {
|
||||
header('Location: ' . $file_name);
|
||||
exit;
|
||||
}
|
||||
|
||||
$uploadsDir = realpath(__DIR__ . '/../uploads/datasources');
|
||||
if (!$uploadsDir) {
|
||||
error_log('Uploads directory not found for download.');
|
||||
die('File storage directory is unavailable.');
|
||||
}
|
||||
|
||||
$file_path = $uploadsDir . '/' . $file_name;
|
||||
|
||||
// --- 4. Serve the File to the User ---
|
||||
// Check if the file exists on the server
|
||||
if (file_exists($file_path)) {
|
||||
// Set headers to force a download
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename="' . basename($download_label . '_' . $file_name) . '"');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
header('Content-Length: ' . filesize($file_path));
|
||||
|
||||
if (ob_get_level()) {
|
||||
ob_clean();
|
||||
}
|
||||
flush();
|
||||
|
||||
// Read the file and send it to the output buffer
|
||||
readfile($file_path);
|
||||
exit;
|
||||
} else {
|
||||
die("The file could not be found on the server at the specified path.");
|
||||
}
|
||||
?>
|
||||
58
data_user/indexTesting.php
Normal file
58
data_user/indexTesting.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// dsp26072025/index.php
|
||||
// This is the main front controller for the application.
|
||||
|
||||
// Define the base path for consistent includes
|
||||
// This will correctly point to the root directory of your project
|
||||
define('BASE_PATH', __DIR__ . '/');
|
||||
|
||||
// Start the session once at the very beginning
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Global Dependencies - All pages will have access to these.
|
||||
// NOTE: Make sure these files exist in the specified paths.
|
||||
require_once BASE_PATH . 'config.php';
|
||||
require_once BASE_PATH . 'includes/auth.php';
|
||||
require_once BASE_PATH . 'includes/functions.php';
|
||||
require_once BASE_PATH . 'classes/DataSource.php';
|
||||
require_once BASE_PATH . 'classes/Classifications.php';
|
||||
require_once BASE_PATH . 'classes/User.php';
|
||||
require_once BASE_PATH . 'classes/Permission.php';
|
||||
require_once BASE_PATH . 'classes/Request.php';
|
||||
require_once BASE_PATH . 'classes/Log.php';
|
||||
|
||||
// Get the requested page from the URL. Default to 'dashboard' if not set.
|
||||
$page = $_GET['page'] ?? 'dashboard';
|
||||
|
||||
// A simple routing system to include the correct file
|
||||
switch ($page) {
|
||||
case 'dashboard':
|
||||
include BASE_PATH . 'data_user/dashboard.php';
|
||||
break;
|
||||
case 'browse_datasources':
|
||||
include BASE_PATH . 'data_user/browse_datasources.php';
|
||||
break;
|
||||
case 'my_permissions':
|
||||
include BASE_PATH . 'data_user/my_permissions.php';
|
||||
break;
|
||||
case 'my_downloads':
|
||||
include BASE_PATH . 'data_user/my_downloads.php';
|
||||
break;
|
||||
case 'login':
|
||||
include BASE_PATH . 'data_user/login.php';
|
||||
break;
|
||||
case 'register':
|
||||
include BASE_PATH . 'data_user/register.php';
|
||||
break;
|
||||
case 'process_request_permission':
|
||||
include BASE_PATH . 'data_user/process_request_permission.php';
|
||||
break;
|
||||
default:
|
||||
// Handle pages not found
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
include BASE_PATH . 'data_user/404.php';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
134
data_user/my_downloads.php
Normal file
134
data_user/my_downloads.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
// data_user/my_downloads.php
|
||||
session_start();
|
||||
require_once '../config.php';
|
||||
require_once '../includes/auth.php';
|
||||
require_once '../classes/DataSource.php';
|
||||
|
||||
// Ensure only Data Users can access this page
|
||||
redirect_if_not_role('Data User');
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$person_id = $_SESSION['person_id']; // This is the correct ID to use for the join
|
||||
$username = $_SESSION['username'];
|
||||
|
||||
$data_source_manager = new DataSource($pdo);
|
||||
|
||||
// Fetch download history for the current user
|
||||
$download_history = [];
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT dsu.*,
|
||||
ds.dspsds_title_en,
|
||||
ds.dspsds_filename,
|
||||
tds.dspstds_name_en
|
||||
FROM dsps_tbl_datasource_used dsu
|
||||
JOIN dsps_tbl_datasource ds
|
||||
ON dsu.fkdspsdsused_id = ds.pkdspsds_id
|
||||
JOIN dsps_tbl_typedatasource tds
|
||||
ON ds.fkdspstds_id = tds.pkdspstds_id
|
||||
WHERE dsu.fkisp_id_of = :person_id
|
||||
AND dsu.dspsdspused_action = 'Downloaded'
|
||||
ORDER BY dsu.dspsdspused_datetime DESC
|
||||
");
|
||||
$stmt->execute(['person_id' => $person_id]);
|
||||
$download_history = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error fetching download history: " . $e->getMessage());
|
||||
set_message("Error fetching download history.", "danger");
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!-- Header -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/header_user.php");
|
||||
?>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<!-- Sidebar -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/nav_user.php");
|
||||
?>
|
||||
<!-- Page Content -->
|
||||
<div class="main-content">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4 rounded-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"> My Downloads History</a>
|
||||
<div class="d-flex">
|
||||
<span class="navbar-text me-3">
|
||||
Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?>!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-<?= $_SESSION['message_type'] ?> alert-dismissible fade show rounded" role="alert">
|
||||
<?= $_SESSION['message'] ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['message']);
|
||||
unset($_SESSION['message_type']);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm rounded">
|
||||
<div class="card-header bg-light rounded-top">
|
||||
<h5 class="mb-0">Downloaded Data Sources</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (!empty($download_history)): ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Data Source</th>
|
||||
<th>Type</th>
|
||||
<th>Download Date</th>
|
||||
<th>File</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($download_history as $item): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($item['dspsds_title_en']) ?></td>
|
||||
<td><?= htmlspecialchars($item['dspstds_name_en']) ?></td>
|
||||
<td><?= date('Y-m-d H:i', strtotime($item['dspsdspused_datetime'])) ?></td>
|
||||
<td>
|
||||
<?php if (!empty($item['dspsds_filename'])): ?>
|
||||
<!--
|
||||
This is the CORRECTED line. It now points to download.php
|
||||
and passes the ID of the data source.
|
||||
-->
|
||||
<a href="download.php?dspsds_id=<?= htmlspecialchars($item['fkdspsdsused_id']) ?>" class="btn btn-sm btn-outline-primary text-dark badge">
|
||||
<i class="fas fa-download me-1"></i> Download Again
|
||||
</a>
|
||||
<?php else: ?>
|
||||
N/A (API or no direct file)
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info rounded mb-0">You have not downloaded any data sources yet.</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<?php
|
||||
// Include Footer file for owner pages
|
||||
include_once("../includes/footer_user.php");
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
150
data_user/my_permissions.php
Normal file
150
data_user/my_permissions.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
// data_user/my_permissions.php
|
||||
// This page shows the user a list of all their data access requests and their statuses.
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
session_start();
|
||||
require_once '../config.php';
|
||||
// We'll assume these files exist based on your original code
|
||||
require_once '../includes/auth.php';
|
||||
require_once '../classes/Permission.php';
|
||||
require_once '../classes/User.php';
|
||||
|
||||
// Redirect if not logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: ../index.php?page=login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$person_id = $_SESSION['person_id'];
|
||||
$username = $_SESSION['username'];
|
||||
|
||||
$currentPage = basename($_SERVER['PHP_SELF']);
|
||||
|
||||
// Instantiate classes
|
||||
$permissionManager = new Permission($pdo);
|
||||
$userManager = new User($pdo);
|
||||
|
||||
// Get user details
|
||||
$currentUserDetails = $userManager->getUserDetails($user_id);
|
||||
|
||||
// Fetch all permission requests for the logged-in user
|
||||
$permissionRequests = [];
|
||||
try {
|
||||
$permissionRequests = $permissionManager->getPermissionsByPersonId($person_id);
|
||||
} catch (Exception $e) {
|
||||
set_message('Error retrieving permission requests: ' . $e->getMessage(), 'danger');
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!-- Header -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/header_user.php");
|
||||
?>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<!-- Sidebar -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/nav_user.php");
|
||||
?>
|
||||
<!-- Page Content -->
|
||||
<div class="main-content">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4 rounded-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"> My Permissions</a>
|
||||
<div class="d-flex">
|
||||
<span class="navbar-text me-3">
|
||||
Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?>!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-<?= $_SESSION['message_type'] ?> alert-dismissible fade show rounded" role="alert">
|
||||
<?= $_SESSION['message'] ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['message']);
|
||||
unset($_SESSION['message_type']);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm rounded-lg">
|
||||
<div class="card-body p-4">
|
||||
<?php if (!empty($permissionRequests)): ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-borderless align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th scope="col">Data Source</th>
|
||||
<th scope="col">Requested For</th>
|
||||
<th scope="col">Date Submitted</th>
|
||||
<th scope="col">Proof</th>
|
||||
<th scope="col">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($permissionRequests as $request): ?>
|
||||
<tr>
|
||||
<td class="fw-bold"><?= htmlspecialchars($request['ds_title']) ?></td>
|
||||
<td><?= htmlspecialchars($request['dspspr_permission_type']) ?></td>
|
||||
<td><?= htmlspecialchars(date('M d, Y', strtotime($request['dspspr_request_date']))) ?></td>
|
||||
<td>
|
||||
<?php if (!empty($request['dspspr_proof_path'])): ?>
|
||||
<a href="../uploads/<?= htmlspecialchars($request['dspspr_proof_path']) ?>" class="btn btn-sm btn-outline-primary rounded-pill" target="_blank" rel="noopener">
|
||||
<i class="fas fa-file-pdf me-1"></i> View
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">N/A</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$status_class = '';
|
||||
switch ($request['dspspr_status']) {
|
||||
case 'Approved':
|
||||
$status_class = 'bg-success badge text-white';
|
||||
break;
|
||||
case 'Pending':
|
||||
$status_class = 'bg-warning badge text-dark';
|
||||
break;
|
||||
case 'Denied':
|
||||
$status_class = 'bg-danger badge text-white';
|
||||
break;
|
||||
default:
|
||||
$status_class = 'bg-secondary badge text-white';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<span class="status-badge <?= $status_class ?>"><?= htmlspecialchars($request['dspspr_status']) ?></span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info text-center rounded m-0">
|
||||
You have not submitted any permission requests yet. <a href="browse_datasources.php" class="alert-link">Browse data sources</a> to get started.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<?php
|
||||
// Include Footer file for owner pages
|
||||
include_once("../includes/footer_user.php");
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
147
data_user/process_request_permission.php
Normal file
147
data_user/process_request_permission.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
// data_user/process_request_permission.php
|
||||
// This script handles the submission of data access permission requests.
|
||||
|
||||
// Enable detailed error reporting for debugging purposes
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
// Start a session if one is not already active
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Check if the request method is POST. If not, redirect to prevent direct access.
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
// Redirect to the home page or an error page
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Use __DIR__ to get the absolute path to this file's directory,
|
||||
// ensuring the path to the required files is always correct.
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once(__DIR__ . '/../includes/auth.php'); // Not strictly needed, but good practice
|
||||
require_once(__DIR__ . '/../classes/Permission.php');
|
||||
require_once(__DIR__ . '/../classes/User.php');
|
||||
|
||||
/**
|
||||
* Handles the upload of a proof document.
|
||||
*
|
||||
* @param array|null $file The uploaded file array from $_FILES.
|
||||
* @param int $personId The requesting user's person ID to help namespace the file.
|
||||
* @return string Relative path (within uploads) to the stored file.
|
||||
*/
|
||||
function handle_proof_upload(?array $file, int $personId): string {
|
||||
if ($file === null || ($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
|
||||
set_and_redirect('Please upload a PDF proof document for your request.', 'danger');
|
||||
}
|
||||
|
||||
if ($file['error'] !== UPLOAD_ERR_OK) {
|
||||
set_and_redirect('There was a problem uploading your proof document. Please try again.', 'danger');
|
||||
}
|
||||
|
||||
$maxSize = 10 * 1024 * 1024; // 10 MB
|
||||
if (($file['size'] ?? 0) > $maxSize) {
|
||||
set_and_redirect('Proof files must be smaller than 10 MB.', 'danger');
|
||||
}
|
||||
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($file['tmp_name']) ?: '';
|
||||
if ($mimeType !== 'application/pdf') {
|
||||
set_and_redirect('Only PDF files are accepted as proof.', 'danger');
|
||||
}
|
||||
|
||||
$uploadDir = __DIR__ . '/../uploads/permission_proofs';
|
||||
if (!is_dir($uploadDir) && !mkdir($uploadDir, 0775, true)) {
|
||||
set_and_redirect('Unable to create the proof upload directory. Contact an administrator.', 'danger');
|
||||
}
|
||||
|
||||
if (!is_writable($uploadDir)) {
|
||||
set_and_redirect('The proof upload directory is not writable. Contact an administrator.', 'danger');
|
||||
}
|
||||
|
||||
$random = bin2hex(random_bytes(8));
|
||||
$filename = sprintf('%d_%s.pdf', $personId, $random);
|
||||
$destination = $uploadDir . '/' . $filename;
|
||||
|
||||
if (!move_uploaded_file($file['tmp_name'], $destination)) {
|
||||
set_and_redirect('Failed to store your proof document. Please try again.', 'danger');
|
||||
}
|
||||
|
||||
return 'permission_proofs/' . $filename;
|
||||
}
|
||||
|
||||
// A helper function to set a session message and redirect
|
||||
function set_and_redirect($message, $type, $page = 'browse_datasources.php') {
|
||||
$_SESSION['message'] = $message;
|
||||
$_SESSION['message_type'] = $type;
|
||||
// Check if headers have already been sent.
|
||||
// This is the most common reason for redirects to fail.
|
||||
if (headers_sent()) {
|
||||
echo "<div class='alert alert-danger'>Redirect failed. Headers already sent. Please go back to <a href='$page'>the previous page</a> to view the message.</div>";
|
||||
echo "Message: " . htmlspecialchars($message);
|
||||
exit;
|
||||
} else {
|
||||
header('Location: ' . $page);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Check if the user is logged in
|
||||
if (!isset($_SESSION['person_id']) || !isset($_SESSION['user_id'])) {
|
||||
set_and_redirect('You must be logged in to request permission.', 'danger');
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$person_id = $_SESSION['person_id'];
|
||||
|
||||
// 2. Validate and sanitize POST data
|
||||
$dataSourceId = filter_input(INPUT_POST, 'data_source_id', FILTER_VALIDATE_INT);
|
||||
|
||||
// Replace deprecated FILTER_SANITIZE_STRING
|
||||
$permissionType = trim(filter_input(INPUT_POST, 'permission_type', FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW));
|
||||
$notes = trim(filter_input(INPUT_POST, 'notes', FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW));
|
||||
|
||||
// Check if required fields are missing or invalid
|
||||
if (!$dataSourceId || empty($permissionType) || empty($notes)) {
|
||||
set_and_redirect('Invalid or missing request details. Please try again.', 'danger');
|
||||
}
|
||||
|
||||
$proofPath = handle_proof_upload($_FILES['proof_file'] ?? null, $person_id);
|
||||
|
||||
// 3. Instantiate the Permission class and process the request
|
||||
try {
|
||||
$permissionManager = new Permission($pdo);
|
||||
|
||||
// Check if a similar request (for the same user, DS, and type) already exists.
|
||||
$existingRequest = $permissionManager->getPendingRequest($person_id, $dataSourceId, $permissionType);
|
||||
|
||||
if ($existingRequest) {
|
||||
set_and_redirect('A request for this permission type is already pending.', 'warning');
|
||||
}
|
||||
|
||||
// Attempt to add the new permission request to the database.
|
||||
$success = $permissionManager->addPermissionRequest(
|
||||
$person_id,
|
||||
$dataSourceId,
|
||||
$permissionType,
|
||||
'Pending', // Set status to Pending
|
||||
$notes,
|
||||
$proofPath
|
||||
);
|
||||
|
||||
if ($success) {
|
||||
set_and_redirect('Your request for ' . htmlspecialchars($permissionType) . ' access has been submitted successfully.', 'success');
|
||||
} else {
|
||||
set_and_redirect('Failed to submit your request. Please try again later.', 'danger');
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Log the detailed error for debugging, but show a generic message to the user.
|
||||
error_log("Error submitting permission request: " . $e->getMessage());
|
||||
set_and_redirect('An unexpected error occurred. Please try again.', 'danger');
|
||||
}
|
||||
|
||||
?>
|
||||
161
data_user/r_in_jupyter.php
Normal file
161
data_user/r_in_jupyter.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
// data_user/r_in_jupyter.php
|
||||
session_start();
|
||||
require_once '../config.php';
|
||||
require_once '../includes/auth.php';
|
||||
require_once '../classes/DataSource.php';
|
||||
require_once '../includes/jupyter_helpers.php';
|
||||
|
||||
redirect_if_not_role('Data User');
|
||||
|
||||
$hasRJupyterAccess = has_r_access();
|
||||
$workspaceSync = ['synced' => [], 'missing' => [], 'workspace_dir' => null];
|
||||
$workspaceRelativeDir = null;
|
||||
$workspaceError = null;
|
||||
|
||||
if ($hasRJupyterAccess && isset($_SESSION['person_id'])) {
|
||||
$dataSourceManager = new DataSource($pdo);
|
||||
try {
|
||||
$workspaceSync = $dataSourceManager->prepareJupyterWorkspace(
|
||||
(int) $_SESSION['person_id'],
|
||||
dirname(__DIR__) . '/uploads/jupyter_workspace'
|
||||
);
|
||||
$workspaceRelativeDir = 'datasources/user_' . (int) $_SESSION['person_id'];
|
||||
} catch (Exception $e) {
|
||||
$workspaceError = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$jupyterBaseUrl = dsp_jupyter_base_url();
|
||||
$jupyterToken = dsp_jupyter_token();
|
||||
$jupyterIframeUrl = dsp_jupyter_iframe_url(
|
||||
$jupyterBaseUrl,
|
||||
$jupyterToken,
|
||||
isset($_SESSION['person_id']) ? (int) $_SESSION['person_id'] : null
|
||||
);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<?php include_once("../includes/header_user.php"); ?>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<?php include_once("../includes/nav_user.php"); ?>
|
||||
|
||||
<div class="main-content">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4 rounded-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">R in JupyterHub</a>
|
||||
<div class="d-flex">
|
||||
<span class="navbar-text me-3">
|
||||
Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?>!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-<?= $_SESSION['message_type'] ?> alert-dismissible fade show rounded" role="alert">
|
||||
<?= $_SESSION['message'] ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['message'], $_SESSION['message_type']);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm rounded mb-4">
|
||||
<div class="card-header bg-light rounded-top d-flex align-items-center justify-content-between">
|
||||
<h5 class="mb-0">R Notebook Workspace</h5>
|
||||
<?php if ($hasRJupyterAccess): ?>
|
||||
<span class="badge bg-success-subtle text-success rounded-pill"><i class="fas fa-flask me-1"></i> Enabled</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-warning-subtle text-warning rounded-pill"><i class="fas fa-lock me-1"></i> Disabled</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if ($hasRJupyterAccess): ?>
|
||||
<?php if ($workspaceError): ?>
|
||||
<div class="alert alert-danger rounded mb-3">
|
||||
<strong>Workspace error:</strong> <?= htmlspecialchars($workspaceError) ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p class="mb-3">
|
||||
Approved datasets are available inside Jupyter at
|
||||
<code><?= htmlspecialchars($workspaceRelativeDir ?: 'datasources') ?></code>.
|
||||
Only data sources you have Approved access to will appear.
|
||||
</p>
|
||||
<?php if (!empty($workspaceSync['synced'])): ?>
|
||||
<div class="table-responsive mb-3">
|
||||
<table class="table table-sm table-striped align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Data Source</th>
|
||||
<th>Data Type</th>
|
||||
<th>Category</th>
|
||||
<th>Filename</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($workspaceSync['synced'] as $idx => $syncedItem): ?>
|
||||
<tr>
|
||||
<td><?= $idx + 1 ?></td>
|
||||
<td><?= htmlspecialchars($syncedItem['title']) ?></td>
|
||||
<td><?= htmlspecialchars($syncedItem['data_type'] ?? 'N/A') ?></td>
|
||||
<td><?= htmlspecialchars($syncedItem['category'] ?? 'N/A') ?></td>
|
||||
<td><code><?= htmlspecialchars(basename($syncedItem['relative_path'])) ?></code></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info rounded mb-3">
|
||||
You currently have no Approved data sources. Request access from DAC Staff or Data Owners to populate this workspace.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($workspaceSync['missing'])): ?>
|
||||
<div class="alert alert-warning rounded mb-3">
|
||||
<strong>Some datasets were skipped:</strong>
|
||||
<ul class="mb-0">
|
||||
<?php foreach ($workspaceSync['missing'] as $missingItem): ?>
|
||||
<li><?= htmlspecialchars($missingItem['title']) ?> — <?= htmlspecialchars($missingItem['reason']) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<p class="mb-3">
|
||||
Use the embedded JupyterLab session to explore approved datasets, run R notebooks, or collaborate with Data Owners and DAC Staff.
|
||||
</p>
|
||||
<div class="ratio ratio-16x9 border rounded overflow-hidden">
|
||||
<iframe
|
||||
src="<?= htmlspecialchars($jupyterIframeUrl, ENT_QUOTES, 'UTF-8') ?>"
|
||||
title="R in JupyterHub"
|
||||
allowfullscreen
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
></iframe>
|
||||
</div>
|
||||
<p class="mt-3 mb-0">
|
||||
Need more space? <a href="<?= htmlspecialchars($jupyterIframeUrl, ENT_QUOTES, 'UTF-8') ?>" target="_blank" rel="noopener">Open Jupyter in a new tab</a>.
|
||||
</p>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-warning rounded d-flex align-items-start gap-3">
|
||||
<i class="fas fa-circle-info mt-1"></i>
|
||||
<div>
|
||||
<strong>R in JupyterHub is currently disabled for your account.</strong><br>
|
||||
Request R/Jupyter access from DAC Staff so you can run notebooks directly from this portal.
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-0">
|
||||
After your access is approved, revisit this page to launch the notebook workspace.
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include_once("../includes/footer_user.php"); ?>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user