LPA-Health-V1.4-28-Feb-2026

This commit is contained in:
Flatlogic Bot 2026-03-01 01:15:48 +00:00
parent 5fae92efe8
commit 41e72d1c86
11 changed files with 930 additions and 17 deletions

View File

@ -1,5 +1,6 @@
<?php <?php
session_start(); session_start();
// Check if user is Super User
if (!isset($_SESSION["user_id"]) || ($_SESSION["user_role"] ?? '') !== 'Super User') { if (!isset($_SESSION["user_id"]) || ($_SESSION["user_role"] ?? '') !== 'Super User') {
header("Location: login.php"); header("Location: login.php");
exit; exit;
@ -12,6 +13,7 @@ $lpas_count = 0;
$users = []; $users = [];
$lpas = []; $lpas = [];
$migration_history = []; $migration_history = [];
$backups = [];
try { try {
$db = db(); $db = db();
@ -29,9 +31,25 @@ try {
try { try {
$migration_history = $db->query("SELECT * FROM migration_history ORDER BY executed_at DESC")->fetchAll(); $migration_history = $db->query("SELECT * FROM migration_history ORDER BY executed_at DESC")->fetchAll();
} catch (PDOException $e) { } catch (PDOException $e) {
// migration_history might not exist yet if installer hasn't run or table not created
$migration_history = []; $migration_history = [];
} }
// Get backups from filesystem
$backups_dir = __DIR__ . '/backups';
if (is_dir($backups_dir)) {
$backup_files = glob($backups_dir . '/backup_*.sql');
foreach ($backup_files as $file) {
$backups[] = [
'filename' => basename($file),
'size' => round(filesize($file) / 1024, 2) . ' KB',
'created_at' => filemtime($file)
];
}
// Sort by created_at descending
usort($backups, function($a, $b) {
return $b['created_at'] - $a['created_at'];
});
}
} catch (PDOException $e) { } catch (PDOException $e) {
error_log($e->getMessage()); error_log($e->getMessage());
} }
@ -132,8 +150,9 @@ try {
<th class="ps-4">Name</th> <th class="ps-4">Name</th>
<th>Email</th> <th>Email</th>
<th>Role</th> <th>Role</th>
<th>Credits</th>
<th>Verified</th> <th>Verified</th>
<th class="text-end pe-4">Joined</th> <th class="text-end pe-4">Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -146,6 +165,9 @@ try {
<?php echo htmlspecialchars($u['role'] ?? 'Standard User'); ?> <?php echo htmlspecialchars($u['role'] ?? 'Standard User'); ?>
</span> </span>
</td> </td>
<td>
<span class="fw-bold text-primary"><?php echo (int)($u['credits'] ?? 0); ?></span>
</td>
<td> <td>
<?php if ($u['is_verified']): ?> <?php if ($u['is_verified']): ?>
<span class="text-success small"> <span class="text-success small">
@ -155,7 +177,9 @@ try {
<span class="text-muted small">No</span> <span class="text-muted small">No</span>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td class="text-end pe-4 text-muted small"><?php echo date('M d, Y', strtotime($u['created_at'])); ?></td> <td class="text-end pe-4">
<button onclick="showCreditModal(<?php echo $u['id']; ?>, '<?php echo htmlspecialchars($u['name'] ?? $u['email']); ?>', <?php echo (int)($u['credits'] ?? 0); ?>)" class="btn btn-sm btn-outline-primary px-3 rounded-pill">Adjust Credits</button>
</td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>
@ -217,8 +241,8 @@ try {
</div> </div>
</div> </div>
<div class="col-lg-12 mt-5"> <div class="col-lg-6 mt-5">
<div class="card border-0 shadow-sm mb-5"> <div class="card border-0 shadow-sm mb-5 h-100">
<div class="card-header bg-white py-3 border-bottom-0"> <div class="card-header bg-white py-3 border-bottom-0">
<h5 class="fw-bold mb-0">Migration History</h5> <h5 class="fw-bold mb-0">Migration History</h5>
</div> </div>
@ -246,11 +270,117 @@ try {
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-6 mt-5">
<div class="card border-0 shadow-sm mb-5 h-100">
<div class="card-header bg-white py-3 border-bottom-0 d-flex justify-content-between align-items-center">
<h5 class="fw-bold mb-0">Backups</h5>
<span class="badge rounded-pill bg-light text-muted fw-normal">Last 5 kept</span>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr class="small text-uppercase tracking-wider">
<th class="ps-4">File Name</th>
<th>Size</th>
<th class="text-end pe-4">Actions</th>
</tr>
</thead>
<tbody>
<?php if (count($backups) > 0): ?>
<?php foreach ($backups as $b): ?>
<tr>
<td class="ps-4">
<div class="fw-medium small"><?php echo htmlspecialchars($b['filename']); ?></div>
<div class="text-muted" style="font-size: 0.75rem;"><?php echo date('M d, Y H:i', $b['created_at']); ?></div>
</td>
<td class="text-muted small"><?php echo $b['size']; ?></td>
<td class="text-end pe-4">
<a href="api/download_backup.php?filename=<?php echo urlencode($b['filename']); ?>" class="btn btn-sm btn-link text-primary text-decoration-none p-0">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-1"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
Download
</a>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="3" class="text-center py-4 text-muted small">No backups found. Backups are created automatically before migrations.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Credit Adjustment Modal -->
<div class="modal fade" id="creditModal" tabindex="-1" aria-labelledby="creditModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow-lg rounded-4">
<div class="modal-header border-bottom-0 pb-0">
<h5 class="modal-title fw-bold" id="creditModalLabel">Adjust Credits</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body pt-3">
<p class="text-muted small mb-4">Adjust LPA credits for <strong id="modalUserName"></strong>. Current balance: <strong id="modalCurrentCredits"></strong></p>
<form id="creditForm">
<input type="hidden" id="modalUserId" name="user_id">
<div class="mb-3">
<label class="form-label small fw-bold text-uppercase">Action</label>
<select class="form-select rounded-3" name="action" id="creditAction">
<option value="add">Add Credits (+)</option>
<option value="set">Set Total Credits (=)</option>
</select>
</div>
<div class="mb-4">
<label class="form-label small fw-bold text-uppercase">Amount</label>
<input type="number" class="form-control rounded-3" name="credits" id="creditAmount" min="0" value="1" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary py-2 rounded-pill fw-bold">Update Credits</button>
</div>
</form>
</div>
</div>
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script> <script>
const creditModal = new bootstrap.Modal(document.getElementById('creditModal'));
function showCreditModal(id, name, current) {
document.getElementById('modalUserId').value = id;
document.getElementById('modalUserName').textContent = name;
document.getElementById('modalCurrentCredits').textContent = current;
document.getElementById('creditAmount').value = 1;
creditModal.show();
}
document.getElementById('creditForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('api/allocate_credits.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Error: ' + data.error);
}
})
.catch(error => {
console.error('Error:', error);
alert('An unexpected error occurred.');
});
});
function deleteLPA(id) { function deleteLPA(id) {
if (confirm('Are you sure you want to delete this LPA application? This action cannot be undone.')) { if (confirm('Are you sure you want to delete this LPA application? This action cannot be undone.')) {
fetch('api/delete_lpa.php', { fetch('api/delete_lpa.php', {
@ -280,7 +410,7 @@ try {
} }
function runMigrations() { function runMigrations() {
if (!confirm('Run database migrations? This will execute all SQL files in db/migrations/ and may take a moment.')) return; if (!confirm('Run database migrations? A database backup will be created automatically before proceeding.')) return;
const alertBox = document.getElementById('migration-alert'); const alertBox = document.getElementById('migration-alert');
const messageEl = document.getElementById('migration-message'); const messageEl = document.getElementById('migration-message');
@ -292,9 +422,10 @@ try {
.then(data => { .then(data => {
alertBox.style.display = 'block'; alertBox.style.display = 'block';
if (data.success) { if (data.success) {
messageEl.textContent = data.message + ' Page will reload in 2 seconds.'; const backupMsg = data.backup ? ` Backup created: ${data.backup}.` : '';
messageEl.textContent = data.message + backupMsg + ' Page will reload in 3 seconds.';
messageEl.parentElement.className = 'alert alert-success alert-dismissible fade show rounded-3 shadow-sm border-0 mb-4'; messageEl.parentElement.className = 'alert alert-success alert-dismissible fade show rounded-3 shadow-sm border-0 mb-4';
setTimeout(() => location.reload(), 2000); setTimeout(() => location.reload(), 3000);
} else { } else {
messageEl.textContent = 'Error: ' + data.error; messageEl.textContent = 'Error: ' + data.error;
messageEl.parentElement.className = 'alert alert-danger alert-dismissible fade show rounded-3 shadow-sm border-0 mb-4'; messageEl.parentElement.className = 'alert alert-danger alert-dismissible fade show rounded-3 shadow-sm border-0 mb-4';

39
api/allocate_credits.php Normal file
View File

@ -0,0 +1,39 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
session_start();
// Security: Only Super Users can allocate credits
if (!isset($_SESSION["user_id"]) || ($_SESSION["user_role"] ?? '') !== 'Super User') {
echo json_encode(['success' => false, 'error' => 'Unauthorized access.']);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$target_user_id = isset($_POST['user_id']) ? (int)$_POST['user_id'] : null;
$credits = isset($_POST['credits']) ? (int)$_POST['credits'] : 0;
$action = $_POST['action'] ?? 'set'; // 'set' or 'add'
if (!$target_user_id) {
echo json_encode(['success' => false, 'error' => 'User ID is required.']);
exit;
}
try {
if ($action === 'add') {
$stmt = db()->prepare("UPDATE users SET credits = credits + ? WHERE id = ?");
$stmt->execute([$credits, $target_user_id]);
$message = "Successfully added $credits credits.";
} else {
$stmt = db()->prepare("UPDATE users SET credits = ? WHERE id = ?");
$stmt->execute([$credits, $target_user_id]);
$message = "Successfully set credits to $credits.";
}
echo json_encode(['success' => true, 'message' => $message]);
} catch (PDOException $e) {
echo json_encode(['success' => false, 'error' => 'Database error: ' . $e->getMessage()]);
}
} else {
echo json_encode(['success' => false, 'error' => 'Invalid request method.']);
}

46
api/download_backup.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/**
* Secure Backup Download API
*
* Only accessible by authenticated administrators.
*/
session_start();
// Authentication and role-based access control
if (!isset($_SESSION['user_id']) || !isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
http_response_code(403);
echo json_encode(['error' => 'Forbidden: Only administrators can access this resource.']);
exit;
}
// Input validation
if (!isset($_GET['filename'])) {
http_response_code(400);
echo json_encode(['error' => 'Bad Request: Filename is required.']);
exit;
}
$filename = basename($_GET['filename']); // Prevent directory traversal
$backups_dir = realpath(__DIR__ . '/../backups');
$filepath = "{$backups_dir}/{$filename}";
// Security check: ensure the file exists and is within the backups directory
if (!$backups_dir || !file_exists($filepath) || strpos(realpath($filepath), $backups_dir) !== 0) {
http_response_code(404);
echo json_encode(['error' => 'Not Found: Backup file not found or access denied.']);
exit;
}
// Determine content type
header('Content-Description: File Transfer');
header('Content-Type: application/sql');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
// Stream the file for download
readfile($filepath);
exit;

View File

@ -8,23 +8,27 @@ if (!isset($_SESSION["user_id"]) || ($_SESSION["user_role"] ?? '') !== 'Super Us
} }
require_once '../db/config.php'; require_once '../db/config.php';
require_once '../db/backup_helper.php';
try { try {
$db = db(); $db = db();
// 1. Ensure migration_history table exists // 1. Perform database backup before migrations
$backup_info = backup_db();
// 2. Ensure migration_history table exists
$db->exec("CREATE TABLE IF NOT EXISTS migration_history ( $db->exec("CREATE TABLE IF NOT EXISTS migration_history (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
filename VARCHAR(255) NOT NULL UNIQUE, filename VARCHAR(255) NOT NULL UNIQUE,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;");
// 2. Scan migrations directory // 3. Scan migrations directory
$migrations_dir = __DIR__ . '/../db/migrations/'; $migrations_dir = __DIR__ . '/../db/migrations/';
$migration_files = glob($migrations_dir . '*.sql'); $migration_files = glob($migrations_dir . '*.sql');
sort($migration_files); sort($migration_files);
// 3. Get list of already executed migrations // 4. Get list of already executed migrations
$stmt = $db->query("SELECT filename FROM migration_history"); $stmt = $db->query("SELECT filename FROM migration_history");
$executed_migrations = $stmt->fetchAll(PDO::FETCH_COLUMN); $executed_migrations = $stmt->fetchAll(PDO::FETCH_COLUMN);
@ -56,7 +60,8 @@ try {
echo json_encode([ echo json_encode([
'success' => true, 'success' => true,
'message' => "Migration process complete.", 'message' => "Backup and migration process complete.",
'backup' => $backup_info['filename'],
'executed' => $executed_count, 'executed' => $executed_count,
'skipped' => $skipped_count, 'skipped' => $skipped_count,
'new_migrations' => $new_migrations 'new_migrations' => $new_migrations
@ -64,6 +69,6 @@ try {
} catch (Exception $e) { } catch (Exception $e) {
echo json_encode([ echo json_encode([
'success' => false, 'success' => false,
'error' => 'Migration failed: ' . $e->getMessage() 'error' => 'Migration/Backup failed: ' . $e->getMessage()
]); ]);
} }

View File

@ -121,10 +121,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$stmt->execute([$lpa_type, $donor_name, $other_names, $donor_dob, $customer_email, $address1, $address2, $town, $postcode, $user_id, $lpa_id]); $stmt->execute([$lpa_type, $donor_name, $other_names, $donor_dob, $customer_email, $address1, $address2, $town, $postcode, $user_id, $lpa_id]);
$id = $lpa_id; $id = $lpa_id;
} else { } else {
// Create new - CHECK CREDITS
$userCheck = db()->prepare("SELECT credits FROM users WHERE id = ?");
$userCheck->execute([$user_id]);
$userData = $userCheck->fetch();
if (!$userData || (int)$userData['credits'] < 1) {
echo json_encode(['success' => false, 'error' => 'You do not have enough credits to start a new LPA application. Please contact your administrator.']);
exit;
}
// Create new // Create new
$stmt = db()->prepare("INSERT INTO lpa_applications (practice_id, user_id, lpa_type, donor_name, other_names, donor_dob, customer_email, donor_address_line1, donor_address_line2, donor_town, donor_postcode, step_reached) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt = db()->prepare("INSERT INTO lpa_applications (practice_id, user_id, lpa_type, donor_name, other_names, donor_dob, customer_email, donor_address_line1, donor_address_line2, donor_town, donor_postcode, step_reached) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([1, $user_id, $lpa_type, $donor_name, $other_names, $donor_dob, $customer_email, $address1, $address2, $town, $postcode, 1]); $stmt->execute([1, $user_id, $lpa_type, $donor_name, $other_names, $donor_dob, $customer_email, $address1, $address2, $town, $postcode, 1]);
$id = db()->lastInsertId(); $id = db()->lastInsertId();
// DECREMENT CREDITS
$updateCredits = db()->prepare("UPDATE users SET credits = credits - 1 WHERE id = ?");
$updateCredits->execute([$user_id]);
} }
echo json_encode(['success' => true, 'id' => (int)$id, 'next_step' => 2, 'message' => 'Step 1 saved successfully.']); echo json_encode(['success' => true, 'id' => (int)$id, 'next_step' => 2, 'message' => 'Step 1 saved successfully.']);

View File

@ -12,6 +12,19 @@ $project_name = $_SERVER['PROJECT_NAME'] ?? 'LPA Online';
$step = isset($_GET['step']) ? (int)$_GET['step'] : 1; $step = isset($_GET['step']) ? (int)$_GET['step'] : 1;
$lpa_id = isset($_GET['id']) ? (int)$_GET['id'] : null; $lpa_id = isset($_GET['id']) ? (int)$_GET['id'] : null;
// If starting a NEW LPA (Step 1, no ID), check for credits
if ($step === 1 && !$lpa_id) {
$credits_stmt = db()->prepare("SELECT credits FROM users WHERE id = ?");
$credits_stmt->execute([$user_id]);
$credits = (int)$credits_stmt->fetchColumn();
if ($credits < 1) {
// Redirect back to dashboard with error
header("Location: dashboard.php?error=no_credits");
exit;
}
}
$lpa_data = null; $lpa_data = null;
if ($lpa_id) { if ($lpa_id) {
$stmt = db()->prepare("SELECT * FROM lpa_applications WHERE id = ?"); $stmt = db()->prepare("SELECT * FROM lpa_applications WHERE id = ?");
@ -1020,7 +1033,7 @@ foreach ($notified_persons as $np) {
<div class="mt-5 d-flex justify-content-between align-items-center"> <div class="mt-5 d-flex justify-content-between align-items-center">
<a href="apply.php?step=11&id=<?php echo $lpa_id; ?>" class="btn btn-link text-decoration-none text-muted p-0">Back to Step 11</a> <a href="apply.php?step=11&id=<?php echo $lpa_id; ?>" class="btn btn-link text-decoration-none text-muted p-0">Back to Step 11</a>
<button type="submit" class="btn btn-primary btn-lg px-5">Continue to Step 13</button> <button type="submit" class="btn btn-primary btn-lg px-5">Continue to Step 12</button>
</div> </div>
</form> </form>
<?php elseif ($step === 13): ?> <?php elseif ($step === 13): ?>

View File

@ -0,0 +1,280 @@
/*M!999999\- enable the sandbox mode */
-- MariaDB dump 10.19 Distrib 10.11.14-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: 127.0.0.1 Database: app_37684
-- ------------------------------------------------------
-- Server version 10.11.14-MariaDB-0+deb12u2
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `lpa_applications`
--
DROP TABLE IF EXISTS `lpa_applications`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `lpa_applications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`practice_id` int(11) DEFAULT 1,
`user_id` int(11) DEFAULT NULL,
`customer_email` varchar(255) DEFAULT NULL,
`lpa_type` enum('Health & Welfare','Property & Financial') NOT NULL,
`donor_name` varchar(255) DEFAULT NULL,
`other_names` varchar(255) DEFAULT NULL,
`donor_dob` date DEFAULT NULL,
`donor_address_line1` varchar(255) DEFAULT NULL,
`donor_address_line2` varchar(255) DEFAULT NULL,
`donor_town` varchar(255) DEFAULT NULL,
`donor_postcode` varchar(20) DEFAULT NULL,
`donor_phone` varchar(20) DEFAULT NULL,
`status` enum('draft','completed') DEFAULT 'draft',
`step_reached` int(11) DEFAULT 1,
`attorney_decision_type` varchar(255) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`life_sustaining_treatment` enum('Option A','Option B') DEFAULT NULL,
`witness_title` varchar(20) DEFAULT NULL,
`witness_first_name` varchar(255) DEFAULT NULL,
`witness_last_name` varchar(255) DEFAULT NULL,
`witness_address_line1` varchar(255) DEFAULT NULL,
`witness_address_line2` varchar(255) DEFAULT NULL,
`witness_address_line3` varchar(255) DEFAULT NULL,
`witness_postcode` varchar(20) DEFAULT NULL,
`preferences` text DEFAULT NULL,
`instructions` text DEFAULT NULL,
`certificate_provider_title` varchar(20) DEFAULT NULL,
`certificate_provider_first_name` varchar(255) DEFAULT NULL,
`certificate_provider_last_name` varchar(255) DEFAULT NULL,
`certificate_provider_address_line1` varchar(255) DEFAULT NULL,
`certificate_provider_address_line2` varchar(255) DEFAULT NULL,
`certificate_provider_address_line3` varchar(255) DEFAULT NULL,
`certificate_provider_postcode` varchar(20) DEFAULT NULL,
`registration_who` varchar(20) DEFAULT NULL,
`registering_attorneys_ids` text DEFAULT NULL,
`correspondence_who` varchar(20) DEFAULT NULL,
`correspondence_attorney_id` int(11) DEFAULT NULL,
`correspondence_title` varchar(20) DEFAULT NULL,
`correspondence_first_name` varchar(255) DEFAULT NULL,
`correspondence_last_name` varchar(255) DEFAULT NULL,
`correspondence_company_name` varchar(255) DEFAULT NULL,
`correspondence_address_line1` varchar(255) DEFAULT NULL,
`correspondence_address_line2` varchar(255) DEFAULT NULL,
`correspondence_address_line3` varchar(255) DEFAULT NULL,
`correspondence_postcode` varchar(20) DEFAULT NULL,
`correspondence_contact_preference` varchar(50) DEFAULT NULL,
`correspondence_phone` varchar(20) DEFAULT NULL,
`correspondence_email` varchar(255) DEFAULT NULL,
`payment_method` varchar(20) DEFAULT NULL,
`payment_phone` varchar(20) DEFAULT NULL,
`reduced_fee_eligibility` varchar(10) DEFAULT NULL,
`is_repeat_application` tinyint(1) DEFAULT 0,
`repeat_case_number` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_user_id` (`user_id`),
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `lpa_applications`
--
LOCK TABLES `lpa_applications` WRITE;
/*!40000 ALTER TABLE `lpa_applications` DISABLE KEYS */;
/*!40000 ALTER TABLE `lpa_applications` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `lpa_attorneys`
--
DROP TABLE IF EXISTS `lpa_attorneys`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `lpa_attorneys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`lpa_id` int(11) NOT NULL,
`type` enum('primary','replacement') DEFAULT 'primary',
`title` varchar(20) DEFAULT NULL,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`dob` date NOT NULL,
`address_line1` varchar(255) NOT NULL,
`address_line2` varchar(255) DEFAULT NULL,
`address_line3` varchar(255) DEFAULT NULL,
`town` varchar(255) NOT NULL,
`postcode` varchar(20) NOT NULL,
`relationship` varchar(100) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
`witness_title` varchar(255) DEFAULT NULL,
`witness_first_name` varchar(255) DEFAULT NULL,
`witness_last_name` varchar(255) DEFAULT NULL,
`witness_address_line1` varchar(255) DEFAULT NULL,
`witness_address_line2` varchar(255) DEFAULT NULL,
`witness_address_line3` varchar(255) DEFAULT NULL,
`witness_postcode` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `lpa_id` (`lpa_id`),
CONSTRAINT `lpa_attorneys_ibfk_1` FOREIGN KEY (`lpa_id`) REFERENCES `lpa_applications` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `lpa_attorneys`
--
LOCK TABLES `lpa_attorneys` WRITE;
/*!40000 ALTER TABLE `lpa_attorneys` DISABLE KEYS */;
/*!40000 ALTER TABLE `lpa_attorneys` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `lpa_notified_persons`
--
DROP TABLE IF EXISTS `lpa_notified_persons`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `lpa_notified_persons` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`application_id` int(11) NOT NULL,
`title` varchar(20) DEFAULT NULL,
`first_name` varchar(100) DEFAULT NULL,
`last_name` varchar(100) DEFAULT NULL,
`address_line1` varchar(255) DEFAULT NULL,
`address_line2` varchar(255) DEFAULT NULL,
`address_line3` varchar(255) DEFAULT NULL,
`postcode` varchar(20) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `lpa_notified_persons`
--
LOCK TABLES `lpa_notified_persons` WRITE;
/*!40000 ALTER TABLE `lpa_notified_persons` DISABLE KEYS */;
/*!40000 ALTER TABLE `lpa_notified_persons` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `migration_history`
--
DROP TABLE IF EXISTS `migration_history`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `migration_history` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`filename` varchar(255) NOT NULL,
`executed_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `filename` (`filename`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `migration_history`
--
LOCK TABLES `migration_history` WRITE;
/*!40000 ALTER TABLE `migration_history` DISABLE KEYS */;
INSERT INTO `migration_history` VALUES
(1,'01_create_users_table.sql','2026-03-01 00:57:47'),
(2,'02_update_users_for_signup.sql','2026-03-01 00:57:47'),
(3,'03_add_reset_password_fields.sql','2026-03-01 00:57:47'),
(4,'04_add_role_column.sql','2026-03-01 00:57:47'),
(5,'05_add_user_id_to_lpa_applications.sql','2026-03-01 00:57:47'),
(6,'06_create_migration_history_table.sql','2026-03-01 00:57:47');
/*!40000 ALTER TABLE `migration_history` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `practices`
--
DROP TABLE IF EXISTS `practices`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `practices` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`slug` varchar(100) NOT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `slug` (`slug`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `practices`
--
LOCK TABLES `practices` WRITE;
/*!40000 ALTER TABLE `practices` DISABLE KEYS */;
INSERT INTO `practices` VALUES
(1,'Elite Estate Planning','elite-estate','2026-02-28 17:36:29');
/*!40000 ALTER TABLE `practices` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `users`
--
DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
`is_verified` tinyint(1) DEFAULT 0,
`verification_token` varchar(64) DEFAULT NULL,
`role` enum('Standard User','Super User') DEFAULT 'Standard User',
`reset_token` varchar(64) DEFAULT NULL,
`reset_expires_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `users`
--
LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
INSERT INTO `users` VALUES
(1,NULL,'test@example.com','$2y$10$xeVgbO3f09/R4FF0bEwqSeTH3bdNp1CcDLE6R27Slc6yNBHK8Cxq.','2026-02-28 23:23:36',1,NULL,'Standard User',NULL,NULL),
(3,'Admin','advice@estateguardians.co.uk','$2y$10$.vu3rXV4RHCa4JIs2GVa/OJvfe4c2dhLOgb60Uw0boPHRCVeDKtq6','2026-03-01 00:00:01',1,NULL,'Super User',NULL,NULL),
(4,'Neel Shah (Profitise)','neel@profitise.co','$2y$10$332.cCj/4WY6.1r6aPQe1ed4QBwl4AYODFtiEeHymgCrvVapiU956','2026-03-01 00:16:28',1,NULL,'Standard User',NULL,NULL),
(5,'Neel Shah','neel@neel.me.uk','$2y$10$6.jb/U/rjKYfXJSwzfdmquJBqjij.RDqlhYKmZNnELnNgyA635u0.','2026-03-01 00:36:13',1,NULL,'Standard User',NULL,NULL),
(6,'Cogent FS','cogentfs@gmail.com','$2y$10$g23tK9toSrpgqQKXF7902eK7P5Hg98VtYZd4lB4O1Vpi/XtY.KlEq','2026-03-01 00:39:16',1,NULL,'Standard User',NULL,NULL);
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2026-03-01 0:59:11

View File

@ -0,0 +1,280 @@
/*M!999999\- enable the sandbox mode */
-- MariaDB dump 10.19 Distrib 10.11.14-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: 127.0.0.1 Database: app_37684
-- ------------------------------------------------------
-- Server version 10.11.14-MariaDB-0+deb12u2
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `lpa_applications`
--
DROP TABLE IF EXISTS `lpa_applications`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `lpa_applications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`practice_id` int(11) DEFAULT 1,
`user_id` int(11) DEFAULT NULL,
`customer_email` varchar(255) DEFAULT NULL,
`lpa_type` enum('Health & Welfare','Property & Financial') NOT NULL,
`donor_name` varchar(255) DEFAULT NULL,
`other_names` varchar(255) DEFAULT NULL,
`donor_dob` date DEFAULT NULL,
`donor_address_line1` varchar(255) DEFAULT NULL,
`donor_address_line2` varchar(255) DEFAULT NULL,
`donor_town` varchar(255) DEFAULT NULL,
`donor_postcode` varchar(20) DEFAULT NULL,
`donor_phone` varchar(20) DEFAULT NULL,
`status` enum('draft','completed') DEFAULT 'draft',
`step_reached` int(11) DEFAULT 1,
`attorney_decision_type` varchar(255) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`life_sustaining_treatment` enum('Option A','Option B') DEFAULT NULL,
`witness_title` varchar(20) DEFAULT NULL,
`witness_first_name` varchar(255) DEFAULT NULL,
`witness_last_name` varchar(255) DEFAULT NULL,
`witness_address_line1` varchar(255) DEFAULT NULL,
`witness_address_line2` varchar(255) DEFAULT NULL,
`witness_address_line3` varchar(255) DEFAULT NULL,
`witness_postcode` varchar(20) DEFAULT NULL,
`preferences` text DEFAULT NULL,
`instructions` text DEFAULT NULL,
`certificate_provider_title` varchar(20) DEFAULT NULL,
`certificate_provider_first_name` varchar(255) DEFAULT NULL,
`certificate_provider_last_name` varchar(255) DEFAULT NULL,
`certificate_provider_address_line1` varchar(255) DEFAULT NULL,
`certificate_provider_address_line2` varchar(255) DEFAULT NULL,
`certificate_provider_address_line3` varchar(255) DEFAULT NULL,
`certificate_provider_postcode` varchar(20) DEFAULT NULL,
`registration_who` varchar(20) DEFAULT NULL,
`registering_attorneys_ids` text DEFAULT NULL,
`correspondence_who` varchar(20) DEFAULT NULL,
`correspondence_attorney_id` int(11) DEFAULT NULL,
`correspondence_title` varchar(20) DEFAULT NULL,
`correspondence_first_name` varchar(255) DEFAULT NULL,
`correspondence_last_name` varchar(255) DEFAULT NULL,
`correspondence_company_name` varchar(255) DEFAULT NULL,
`correspondence_address_line1` varchar(255) DEFAULT NULL,
`correspondence_address_line2` varchar(255) DEFAULT NULL,
`correspondence_address_line3` varchar(255) DEFAULT NULL,
`correspondence_postcode` varchar(20) DEFAULT NULL,
`correspondence_contact_preference` varchar(50) DEFAULT NULL,
`correspondence_phone` varchar(20) DEFAULT NULL,
`correspondence_email` varchar(255) DEFAULT NULL,
`payment_method` varchar(20) DEFAULT NULL,
`payment_phone` varchar(20) DEFAULT NULL,
`reduced_fee_eligibility` varchar(10) DEFAULT NULL,
`is_repeat_application` tinyint(1) DEFAULT 0,
`repeat_case_number` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_user_id` (`user_id`),
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `lpa_applications`
--
LOCK TABLES `lpa_applications` WRITE;
/*!40000 ALTER TABLE `lpa_applications` DISABLE KEYS */;
/*!40000 ALTER TABLE `lpa_applications` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `lpa_attorneys`
--
DROP TABLE IF EXISTS `lpa_attorneys`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `lpa_attorneys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`lpa_id` int(11) NOT NULL,
`type` enum('primary','replacement') DEFAULT 'primary',
`title` varchar(20) DEFAULT NULL,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`dob` date NOT NULL,
`address_line1` varchar(255) NOT NULL,
`address_line2` varchar(255) DEFAULT NULL,
`address_line3` varchar(255) DEFAULT NULL,
`town` varchar(255) NOT NULL,
`postcode` varchar(20) NOT NULL,
`relationship` varchar(100) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
`witness_title` varchar(255) DEFAULT NULL,
`witness_first_name` varchar(255) DEFAULT NULL,
`witness_last_name` varchar(255) DEFAULT NULL,
`witness_address_line1` varchar(255) DEFAULT NULL,
`witness_address_line2` varchar(255) DEFAULT NULL,
`witness_address_line3` varchar(255) DEFAULT NULL,
`witness_postcode` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `lpa_id` (`lpa_id`),
CONSTRAINT `lpa_attorneys_ibfk_1` FOREIGN KEY (`lpa_id`) REFERENCES `lpa_applications` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `lpa_attorneys`
--
LOCK TABLES `lpa_attorneys` WRITE;
/*!40000 ALTER TABLE `lpa_attorneys` DISABLE KEYS */;
/*!40000 ALTER TABLE `lpa_attorneys` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `lpa_notified_persons`
--
DROP TABLE IF EXISTS `lpa_notified_persons`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `lpa_notified_persons` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`application_id` int(11) NOT NULL,
`title` varchar(20) DEFAULT NULL,
`first_name` varchar(100) DEFAULT NULL,
`last_name` varchar(100) DEFAULT NULL,
`address_line1` varchar(255) DEFAULT NULL,
`address_line2` varchar(255) DEFAULT NULL,
`address_line3` varchar(255) DEFAULT NULL,
`postcode` varchar(20) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `lpa_notified_persons`
--
LOCK TABLES `lpa_notified_persons` WRITE;
/*!40000 ALTER TABLE `lpa_notified_persons` DISABLE KEYS */;
/*!40000 ALTER TABLE `lpa_notified_persons` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `migration_history`
--
DROP TABLE IF EXISTS `migration_history`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `migration_history` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`filename` varchar(255) NOT NULL,
`executed_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `filename` (`filename`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `migration_history`
--
LOCK TABLES `migration_history` WRITE;
/*!40000 ALTER TABLE `migration_history` DISABLE KEYS */;
INSERT INTO `migration_history` VALUES
(1,'01_create_users_table.sql','2026-03-01 00:57:47'),
(2,'02_update_users_for_signup.sql','2026-03-01 00:57:47'),
(3,'03_add_reset_password_fields.sql','2026-03-01 00:57:47'),
(4,'04_add_role_column.sql','2026-03-01 00:57:47'),
(5,'05_add_user_id_to_lpa_applications.sql','2026-03-01 00:57:47'),
(6,'06_create_migration_history_table.sql','2026-03-01 00:57:47');
/*!40000 ALTER TABLE `migration_history` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `practices`
--
DROP TABLE IF EXISTS `practices`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `practices` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`slug` varchar(100) NOT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `slug` (`slug`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `practices`
--
LOCK TABLES `practices` WRITE;
/*!40000 ALTER TABLE `practices` DISABLE KEYS */;
INSERT INTO `practices` VALUES
(1,'Elite Estate Planning','elite-estate','2026-02-28 17:36:29');
/*!40000 ALTER TABLE `practices` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `users`
--
DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(),
`is_verified` tinyint(1) DEFAULT 0,
`verification_token` varchar(64) DEFAULT NULL,
`role` enum('Standard User','Super User') DEFAULT 'Standard User',
`reset_token` varchar(64) DEFAULT NULL,
`reset_expires_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `users`
--
LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
INSERT INTO `users` VALUES
(1,NULL,'test@example.com','$2y$10$xeVgbO3f09/R4FF0bEwqSeTH3bdNp1CcDLE6R27Slc6yNBHK8Cxq.','2026-02-28 23:23:36',1,NULL,'Standard User',NULL,NULL),
(3,'Admin','advice@estateguardians.co.uk','$2y$10$.vu3rXV4RHCa4JIs2GVa/OJvfe4c2dhLOgb60Uw0boPHRCVeDKtq6','2026-03-01 00:00:01',1,NULL,'Super User',NULL,NULL),
(4,'Neel Shah (Profitise)','neel@profitise.co','$2y$10$332.cCj/4WY6.1r6aPQe1ed4QBwl4AYODFtiEeHymgCrvVapiU956','2026-03-01 00:16:28',1,NULL,'Standard User',NULL,NULL),
(5,'Neel Shah','neel@neel.me.uk','$2y$10$6.jb/U/rjKYfXJSwzfdmquJBqjij.RDqlhYKmZNnELnNgyA635u0.','2026-03-01 00:36:13',1,NULL,'Standard User',NULL,NULL),
(6,'Cogent FS','cogentfs@gmail.com','$2y$10$g23tK9toSrpgqQKXF7902eK7P5Hg98VtYZd4lB4O1Vpi/XtY.KlEq','2026-03-01 00:39:16',1,NULL,'Standard User',NULL,NULL);
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2026-03-01 1:03:59

View File

@ -9,8 +9,15 @@ $project_name = $_SERVER['PROJECT_NAME'] ?? 'LPA Online';
$user_id = $_SESSION["user_id"]; $user_id = $_SESSION["user_id"];
$lpas = []; $lpas = [];
$user_credits = 0;
try { try {
$stmt = db()->prepare("SELECT * FROM lpa_applications WHERE user_id = ? ORDER BY created_at DESC"); $db = db();
// Get user credits
$user_stmt = $db->prepare("SELECT credits FROM users WHERE id = ?");
$user_stmt->execute([$user_id]);
$user_credits = $user_stmt->fetchColumn() ?: 0;
$stmt = $db->prepare("SELECT * FROM lpa_applications WHERE user_id = ? ORDER BY created_at DESC");
$stmt->execute([$user_id]); $stmt->execute([$user_id]);
$lpas = $stmt->fetchAll(); $lpas = $stmt->fetchAll();
} catch (PDOException $e) { } catch (PDOException $e) {
@ -49,13 +56,27 @@ try {
<h1 class="h3 fw-bold mb-1">Your Applications</h1> <h1 class="h3 fw-bold mb-1">Your Applications</h1>
<p class="text-muted small mb-0">Track and manage your Lasting Powers of Attorney progress.</p> <p class="text-muted small mb-0">Track and manage your Lasting Powers of Attorney progress.</p>
</div> </div>
<div class="col-auto"> <div class="col-auto d-flex align-items-center">
<div class="me-4 text-end">
<span class="text-muted small d-block mb-0 text-uppercase tracking-wider fw-bold">Available Credits</span>
<h4 class="fw-bold mb-0 text-primary"><?php echo (int)$user_credits; ?> <span class="text-muted h6 fw-normal">LPA<?php echo $user_credits != 1 ? 's' : ''; ?></span></h4>
</div>
<?php if (count($lpas) > 0): ?> <?php if (count($lpas) > 0): ?>
<a href="/apply.php" class="btn btn-outline-primary px-4 rounded-pill">New Application</a> <a href="/apply.php" class="btn btn-outline-primary px-4 rounded-pill">New Application</a>
<?php endif; ?> <?php endif; ?>
</div> </div>
</div> </div>
<?php if (isset($_GET['error']) && $_GET['error'] === 'no_credits'): ?>
<div class="alert alert-danger alert-dismissible fade show border-0 shadow-sm mb-4" role="alert">
<div class="d-flex align-items-center">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
<span><strong>Insufficient Credits:</strong> You do not have enough credits to start a new LPA application. Please contact your administrator to allocate more credits.</span>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if (isset($_GET['completed_step'])): ?> <?php if (isset($_GET['completed_step'])): ?>
<div class="alert alert-success alert-dismissible fade show border-0 shadow-sm mb-4" role="alert"> <div class="alert alert-success alert-dismissible fade show border-0 shadow-sm mb-4" role="alert">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">

82
db/backup_helper.php Normal file
View File

@ -0,0 +1,82 @@
<?php
/**
* Database Backup Helper
*
* Provides functionality to back up the current database to the /backups directory.
*/
function backup_db() {
// Determine path to backups directory (relative to db/config.php's folder)
$backups_dir = realpath(__DIR__ . '/../backups');
// Ensure the backups directory exists
if (!$backups_dir) {
$backups_dir = __DIR__ . '/../backups';
if (!is_dir($backups_dir)) {
if (!mkdir($backups_dir, 0775, true)) {
throw new Exception("Could not create backups directory: $backups_dir");
}
}
$backups_dir = realpath($backups_dir);
}
// Load DB config if not already loaded (might be called from various places)
require_once __DIR__ . '/config.php';
$timestamp = date('Y-m-d_H-i-s');
$filename = "backup_{$timestamp}.sql";
$filepath = "{$backups_dir}/{$filename}";
// Use mysqldump to create the backup
$command = sprintf(
'mysqldump --host=%s --user=%s --password=%s %s > %s 2>&1',
escapeshellarg(DB_HOST),
escapeshellarg(DB_USER),
escapeshellarg(DB_PASS),
escapeshellarg(DB_NAME),
escapeshellarg($filepath)
);
$output = [];
$return_var = null;
exec($command, $output, $return_var);
if ($return_var !== 0) {
$error_msg = implode("\n", $output);
throw new Exception("Database backup failed with exit code {$return_var}: " . $error_msg);
}
// Automatic cleanup: keep only the last 5 backups
cleanup_backups($backups_dir, 5);
return [
'filename' => $filename,
'filepath' => $filepath,
'size' => filesize($filepath)
];
}
/**
* Cleanup old backups, keeping only the most recent $keep_count files.
*
* @param string $backups_dir Path to backups directory
* @param int $keep_count Number of backups to retain
*/
function cleanup_backups($backups_dir, $keep_count = 5) {
$files = glob("{$backups_dir}/backup_*.sql");
// Sort by modification time (newest first)
usort($files, function($a, $b) {
return filemtime($b) - filemtime($a);
});
// Remove files beyond the keep count
if (count($files) > $keep_count) {
$files_to_remove = array_slice($files, $keep_count);
foreach ($files_to_remove as $file) {
if (is_file($file)) {
unlink($file);
}
}
}
}

View File

@ -0,0 +1,2 @@
-- Add credits column to users table
ALTER TABLE users ADD COLUMN credits INT DEFAULT 0;