|
@@ -1,4 +1,5 @@
|
|
|
<?php
|
|
<?php
|
|
|
|
|
+require __DIR__ . '/auth.php';
|
|
|
$dbPath = __DIR__ . '/_private/pl.db';
|
|
$dbPath = __DIR__ . '/_private/pl.db';
|
|
|
$message = '';
|
|
$message = '';
|
|
|
$messageType = '';
|
|
$messageType = '';
|
|
@@ -177,19 +178,69 @@ function importCSV(string $filepath, string $dbPath): array {
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+$configPath = __DIR__ . '/_private/config.php';
|
|
|
|
|
+
|
|
|
|
|
+function loadCodes(string $path): array {
|
|
|
|
|
+ return file_exists($path) ? (require $path) : [];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function saveCodes(string $path, array $codes): void {
|
|
|
|
|
+ $export = "<?php\n// Access codes for P&L viewer.\n// Managed via http://rktbds/upload.php — do not edit by hand.\nreturn " . var_export($codes, true) . ";\n";
|
|
|
|
|
+ file_put_contents($path, $export);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+$accessMsg = '';
|
|
|
|
|
+$accessType = '';
|
|
|
|
|
+
|
|
|
// Handle POST
|
|
// Handle POST
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
|
if (isset($_POST['import_existing'])) {
|
|
if (isset($_POST['import_existing'])) {
|
|
|
$csvPath = __DIR__ . '/May2026PL.csv';
|
|
$csvPath = __DIR__ . '/May2026PL.csv';
|
|
|
$result = importCSV($csvPath, $dbPath);
|
|
$result = importCSV($csvPath, $dbPath);
|
|
|
|
|
+ $message = $result['msg'];
|
|
|
|
|
+ $messageType = $result['ok'] ? 'success' : 'error';
|
|
|
|
|
+
|
|
|
} elseif (isset($_FILES['csvfile']) && $_FILES['csvfile']['error'] === UPLOAD_ERR_OK) {
|
|
} elseif (isset($_FILES['csvfile']) && $_FILES['csvfile']['error'] === UPLOAD_ERR_OK) {
|
|
|
$result = importCSV($_FILES['csvfile']['tmp_name'], $dbPath);
|
|
$result = importCSV($_FILES['csvfile']['tmp_name'], $dbPath);
|
|
|
|
|
+ $message = $result['msg'];
|
|
|
|
|
+ $messageType = $result['ok'] ? 'success' : 'error';
|
|
|
|
|
+
|
|
|
|
|
+ } elseif (isset($_POST['add_code'])) {
|
|
|
|
|
+ $label = trim($_POST['code_label'] ?? '');
|
|
|
|
|
+ $pw = $_POST['code_pw'] ?? '';
|
|
|
|
|
+ $pw2 = $_POST['code_pw2'] ?? '';
|
|
|
|
|
+ if ($label === '') {
|
|
|
|
|
+ $accessMsg = 'Label is required.'; $accessType = 'error';
|
|
|
|
|
+ } elseif (strlen($pw) < 8) {
|
|
|
|
|
+ $accessMsg = 'Access code must be at least 8 characters.'; $accessType = 'error';
|
|
|
|
|
+ } elseif ($pw !== $pw2) {
|
|
|
|
|
+ $accessMsg = 'Access codes do not match.'; $accessType = 'error';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $codes = loadCodes($configPath);
|
|
|
|
|
+ $codes[] = ['label' => $label, 'hash' => password_hash($pw, PASSWORD_BCRYPT)];
|
|
|
|
|
+ saveCodes($configPath, $codes);
|
|
|
|
|
+ $accessMsg = "Access code for \"" . htmlspecialchars($label) . "\" added.";
|
|
|
|
|
+ $accessType = 'success';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } elseif (isset($_POST['remove_code'])) {
|
|
|
|
|
+ $idx = (int)$_POST['remove_code'];
|
|
|
|
|
+ $codes = loadCodes($configPath);
|
|
|
|
|
+ if (count($codes) <= 1) {
|
|
|
|
|
+ $accessMsg = 'Cannot remove the last access code.'; $accessType = 'error';
|
|
|
|
|
+ } elseif (isset($codes[$idx])) {
|
|
|
|
|
+ $label = $codes[$idx]['label'];
|
|
|
|
|
+ array_splice($codes, $idx, 1);
|
|
|
|
|
+ saveCodes($configPath, $codes);
|
|
|
|
|
+ $accessMsg = "Access code for \"" . htmlspecialchars($label) . "\" removed.";
|
|
|
|
|
+ $accessType = 'success';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
} else {
|
|
} else {
|
|
|
$uploadErr = $_FILES['csvfile']['error'] ?? -1;
|
|
$uploadErr = $_FILES['csvfile']['error'] ?? -1;
|
|
|
- $result = ['ok'=>false,'msg'=>'Upload error (code '.$uploadErr.'). Check php.ini upload_max_filesize.'];
|
|
|
|
|
|
|
+ $message = 'Upload error (code '.$uploadErr.'). Check php.ini upload_max_filesize.';
|
|
|
|
|
+ $messageType = 'error';
|
|
|
}
|
|
}
|
|
|
- $message = $result['msg'];
|
|
|
|
|
- $messageType = $result['ok'] ? 'success' : 'error';
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$hasExistingCsv = file_exists(__DIR__ . '/May2026PL.csv');
|
|
$hasExistingCsv = file_exists(__DIR__ . '/May2026PL.csv');
|
|
@@ -273,9 +324,76 @@ input[type=file]:hover{border-color:#94a3b8}
|
|
|
</form>
|
|
</form>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <?php if ($hasDb && !$message): ?>
|
|
|
|
|
- <a href="index.php" class="back">← Back to P&L Viewer</a>
|
|
|
|
|
- <?php endif; ?>
|
|
|
|
|
|
|
+ <!-- ── Access Codes ── -->
|
|
|
|
|
+ <div class="section">
|
|
|
|
|
+ <h2>Access Codes</h2>
|
|
|
|
|
+
|
|
|
|
|
+ <?php if ($accessMsg): ?>
|
|
|
|
|
+ <div class="alert <?= $accessType ?>" style="margin-bottom:14px"><?= $accessMsg ?></div>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+
|
|
|
|
|
+ <?php
|
|
|
|
|
+ $codes = loadCodes($configPath);
|
|
|
|
|
+ if ($codes):
|
|
|
|
|
+ ?>
|
|
|
|
|
+ <table style="width:100%;border-collapse:collapse;margin-bottom:14px;font-size:13px">
|
|
|
|
|
+ <thead>
|
|
|
|
|
+ <tr style="border-bottom:1px solid #e2e8f0">
|
|
|
|
|
+ <th style="text-align:left;padding:4px 8px;color:#64748b;font-weight:600">#</th>
|
|
|
|
|
+ <th style="text-align:left;padding:4px 8px;color:#64748b;font-weight:600">Label</th>
|
|
|
|
|
+ <th></th>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </thead>
|
|
|
|
|
+ <tbody>
|
|
|
|
|
+ <?php foreach ($codes as $i => $code): ?>
|
|
|
|
|
+ <tr style="border-bottom:1px solid #f1f5f9">
|
|
|
|
|
+ <td style="padding:7px 8px;color:#94a3b8"><?= $i + 1 ?></td>
|
|
|
|
|
+ <td style="padding:7px 8px;font-weight:500"><?= htmlspecialchars($code['label']) ?></td>
|
|
|
|
|
+ <td style="padding:7px 8px;text-align:right">
|
|
|
|
|
+ <form method="post" style="display:inline" onsubmit="return confirm('Remove access for \'<?= htmlspecialchars(addslashes($code['label'])) ?>\'?')">
|
|
|
|
|
+ <button type="submit" name="remove_code" value="<?= $i ?>"
|
|
|
|
|
+ style="background:none;border:none;color:#ef4444;font-size:12px;cursor:pointer;font-weight:600"
|
|
|
|
|
+ <?= count($codes) <= 1 ? 'disabled title="Cannot remove last code"' : '' ?>>
|
|
|
|
|
+ Remove
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </form>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <?php endforeach; ?>
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </table>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+
|
|
|
|
|
+ <form method="post" style="display:grid;gap:8px">
|
|
|
|
|
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label style="font-size:11px;font-weight:600;color:#64748b;display:block;margin-bottom:4px">Label (e.g. name)</label>
|
|
|
|
|
+ <input type="text" name="code_label" placeholder="Alice"
|
|
|
|
|
+ style="width:100%;padding:7px 10px;border:1px solid #cbd5e1;border-radius:5px;font-size:13px">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label style="font-size:11px;font-weight:600;color:#64748b;display:block;margin-bottom:4px">Access Code</label>
|
|
|
|
|
+ <input type="password" name="code_pw" placeholder="min 8 characters"
|
|
|
|
|
+ style="width:100%;padding:7px 10px;border:1px solid #cbd5e1;border-radius:5px;font-size:13px">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label style="font-size:11px;font-weight:600;color:#64748b;display:block;margin-bottom:4px">Confirm Access Code</label>
|
|
|
|
|
+ <input type="password" name="code_pw2" placeholder="repeat access code"
|
|
|
|
|
+ style="width:100%;padding:7px 10px;border:1px solid #cbd5e1;border-radius:5px;font-size:13px">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <button type="submit" name="add_code" class="btn btn-primary" style="justify-self:start;margin-top:4px">Add Access Code</button>
|
|
|
|
|
+ </form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-top:4px">
|
|
|
|
|
+ <?php if ($hasDb): ?>
|
|
|
|
|
+ <a href="index.php" class="back">← Back to P&L Viewer</a>
|
|
|
|
|
+ <?php else: ?>
|
|
|
|
|
+ <span></span>
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <a href="logout.php" style="font-size:13px;color:#94a3b8;text-decoration:none">Sign out</a>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</body>
|
|
</body>
|
|
|
</html>
|
|
</html>
|