Initial commit — Rosary Presenter App

Full source for loveandrosary.com: slide-based Rosary/novena/Divine Mercy
Chaplet presentation tool with multi-user roles, SVG bead ring, audio uploads,
donate strip, and public session profiles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 18:44:08 -07:00
commit 663fde3909
46 changed files with 10902 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
<?php
/**
* includes/auth.php — multi-user role-based authentication.
*/
function _auth_start(): void {
if (session_status() === PHP_SESSION_NONE) session_start();
}
/** Redirect to login if not authenticated. */
function require_auth(): void {
_auth_start();
if (empty($_SESSION['user_id'])) {
header('Location: ' . BASE_URL . '/login');
exit;
}
}
/** Redirect/abort if user doesn't have the minimum role. */
function require_role(string $min_role): void {
require_auth();
if (!has_role($min_role)) {
http_response_code(403);
echo '<!DOCTYPE html><html><body style="font-family:system-ui;max-width:500px;margin:60px auto;text-align:center">'
. '<h1 style="color:#dc2626">Access Denied</h1>'
. '<p>You do not have permission to view this page.</p>'
. '<a href="' . BASE_URL . '/admin/">&#8592; Dashboard</a></body></html>';
exit;
}
}
/** True if current session user has at least $min_role. */
function has_role(string $min): bool {
_auth_start();
$levels = ['user' => 1, 'superuser' => 2, 'admin' => 3, 'superadmin' => 4];
return ($levels[$_SESSION['role'] ?? ''] ?? 0) >= ($levels[$min] ?? 999);
}
/** Return current user data from session (or empty defaults). */
function current_user(): array {
_auth_start();
return [
'id' => $_SESSION['user_id'] ?? null,
'username' => $_SESSION['username'] ?? '',
'email' => $_SESSION['email'] ?? '',
'role' => $_SESSION['role'] ?? '',
'display_name' => $_SESSION['display_name'] ?? '',
'rosary_limit' => $_SESSION['rosary_limit'] ?? 1,
];
}
/**
* Check if user can create another rosary.
* Novenas count as 1 regardless of number of days.
* Returns true if under limit (or limit is -1 = unlimited).
*/
function can_create_rosary(int $user_id, int $limit): bool {
if ($limit < 0) return true; // unlimited
$pdo = get_pdo();
$st = $pdo->prepare("
SELECT
(SELECT COUNT(*) FROM sessions WHERE user_id = ? AND occasion != 'novena_deceased') +
(SELECT COUNT(*) FROM novena_groups WHERE user_id = ?)
AS total
");
$st->execute([$user_id, $user_id]);
return (int)$st->fetchColumn() < $limit;
}