Files
Rosary/install.php
T
pguzman 663fde3909 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>
2026-05-13 18:44:08 -07:00

219 lines
9.5 KiB
PHP

<?php
/**
* install.php — Full database installer.
* Creates all tables, seeds settings and superadmin account.
* Run once in browser, then DELETE this file.
*/
require_once __DIR__ . '/config/db.php';
$pdo = get_pdo();
$log = [];
$errors = [];
function inst_sql(PDO $pdo, string $label, string $sql, array &$log, array &$errors): void {
try {
$pdo->exec($sql);
$log[] = ['ok', $label];
} catch (PDOException $e) {
if (in_array($e->errorInfo[1], [1060, 1061, 1050], true)) {
$log[] = ['skip', $label . ' (already exists, skipped)'];
} else {
$errors[] = $label . ': ' . $e->getMessage();
$log[] = ['err', $label . ': ' . $e->getMessage()];
}
}
}
// ── 1. sessions ──────────────────────────────────────────────────────────────
inst_sql($pdo, 'Create sessions table', "
CREATE TABLE IF NOT EXISTS sessions (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NULL,
is_public TINYINT(1) NOT NULL DEFAULT 1,
slug VARCHAR(255) NULL,
name VARCHAR(255) NOT NULL,
occasion VARCHAR(50) NOT NULL,
mystery_set VARCHAR(50) NOT NULL,
novena_day TINYINT NULL,
novena_group_id INT NULL,
subject_name VARCHAR(255) NULL,
subject_pronoun VARCHAR(10) NULL,
subject_dates VARCHAR(150) NULL,
photo_path VARCHAR(500) NULL,
is_pinned TINYINT(1) NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
", $log, $errors);
// ── 2. novena_groups ─────────────────────────────────────────────────────────
inst_sql($pdo, 'Create novena_groups table', "
CREATE TABLE IF NOT EXISTS novena_groups (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NULL,
is_public TINYINT(1) NOT NULL DEFAULT 1,
slug VARCHAR(255) NULL,
name VARCHAR(255) NOT NULL,
mystery_set VARCHAR(50) NOT NULL DEFAULT 'sorrowful',
subject_name VARCHAR(255) NULL,
subject_pronoun VARCHAR(10) NULL,
subject_dates VARCHAR(150) NULL,
photo_path VARCHAR(500) NULL,
is_pinned TINYINT(1) NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
", $log, $errors);
// ── 3. users ─────────────────────────────────────────────────────────────────
inst_sql($pdo, 'Create users table', "
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
display_name VARCHAR(100) NULL,
role ENUM('superadmin','admin','superuser','user') NOT NULL DEFAULT 'user',
rosary_limit INT NOT NULL DEFAULT 1,
email_confirmed TINYINT(1) NOT NULL DEFAULT 0,
confirm_token VARCHAR(64) NULL,
reset_token VARCHAR(64) NULL,
reset_expires DATETIME NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
", $log, $errors);
// ── 4. site_settings ─────────────────────────────────────────────────────────
inst_sql($pdo, 'Create site_settings table', "
CREATE TABLE IF NOT EXISTS site_settings (
key_name VARCHAR(100) PRIMARY KEY,
val TEXT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
", $log, $errors);
// ── 5. Seed site_settings ────────────────────────────────────────────────────
$defaults = [
'smtp_host' => '',
'smtp_port' => '587',
'smtp_user' => '',
'smtp_pass' => '',
'smtp_from' => '',
'smtp_from_name' => 'Rosary Presenter',
'site_name' => 'Rosary Presenter',
'site_url' => '',
];
$ins_setting = $pdo->prepare('INSERT IGNORE INTO site_settings (key_name, val) VALUES (?, ?)');
foreach ($defaults as $k => $v) {
try {
$ins_setting->execute([$k, $v]);
$log[] = ['ok', "Seeded site_settings: {$k}"];
} catch (PDOException $e) {
$errors[] = "site_settings {$k}: " . $e->getMessage();
}
}
// ── 6. Seed superadmin ───────────────────────────────────────────────────────
$hash = password_hash('supadmin', PASSWORD_BCRYPT);
try {
$pdo->prepare("
INSERT IGNORE INTO users
(username, email, password_hash, display_name, role, rosary_limit, email_confirmed)
VALUES ('supadmin', 'admin@example.com', ?, 'Super Admin', 'superadmin', -1, 1)
")->execute([$hash]);
$log[] = ['ok', 'Seeded superadmin account (username: supadmin)'];
} catch (PDOException $e) {
$errors[] = 'Seed superadmin: ' . $e->getMessage();
}
$overall_ok = empty($errors);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Install — <?= APP_NAME ?></title>
<style>
*{box-sizing:border-box}
body{font-family:system-ui,-apple-system,sans-serif;background:#f4f4f5;margin:0;padding:32px 16px}
.wrap{max-width:720px;margin:0 auto}
h1{font-size:26px;margin-bottom:4px}
.banner{border-radius:8px;padding:20px 24px;margin-bottom:24px;font-size:15px}
.banner.ok{background:#d1fae5;border:1px solid #6ee7b7;color:#065f46}
.banner.err{background:#fee2e2;border:1px solid #fca5a5;color:#991b1b}
.warn{background:#fef3c7;border:1px solid #fcd34d;color:#92400e;border-radius:8px;padding:16px 20px;margin-bottom:24px;font-weight:600}
.card{background:#fff;border-radius:8px;padding:24px;margin-bottom:20px;box-shadow:0 1px 3px rgba(0,0,0,.07)}
.cred{background:#1e3a5f;color:#e0f2fe;border-radius:6px;padding:16px 20px;font-family:monospace;font-size:15px;line-height:1.9}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{text-align:left;padding:6px 10px;border-bottom:1px solid #e5e7eb}
th{background:#f9fafb;font-weight:600}
.ok{color:#15803d}.err{color:#b91c1c}.skip{color:#d97706}
</style>
</head>
<body>
<div class="wrap">
<h1>&#x271D; <?= APP_NAME ?> — Installer</h1>
<?php if ($overall_ok): ?>
<div class="banner ok">
<strong>Installation complete!</strong> All tables created and seeded successfully.
</div>
<?php else: ?>
<div class="banner err">
<strong>Installation finished with errors.</strong>
Review the log below. Check your credentials in <code>config/db.php</code> and try again.
</div>
<?php endif; ?>
<div class="warn">
&#9888; DELETE <code>install.php</code> from your server immediately after reviewing this page.
</div>
<div class="card">
<h2 style="margin-top:0">Superadmin Credentials</h2>
<div class="cred">
Username: supadmin<br>
Password: supadmin<br>
Role:&nbsp;&nbsp;&nbsp;&nbsp;superadmin (unlimited rosaries)
</div>
<p style="color:#b91c1c;font-weight:600;margin-top:12px">
Change the password immediately — go to
<a href="<?= BASE_URL ?>/admin/profile">/admin/profile</a> after logging in.<br>
Also update the email from <code>admin@example.com</code> to your real address.
</p>
</div>
<div class="card">
<h2 style="margin-top:0">Installation Log</h2>
<table>
<thead><tr><th>Status</th><th>Step</th></tr></thead>
<tbody>
<?php foreach ($log as [$status, $msg]): ?>
<tr>
<td class="<?= $status ?>">
<?= $status === 'ok' ? '&#x2713; OK' : ($status === 'skip' ? '&#8212; SKIP' : '&#x2717; ERROR') ?>
</td>
<td><?= htmlspecialchars($msg) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php if ($overall_ok): ?>
<div class="card">
<h2 style="margin-top:0">Next Steps</h2>
<ol style="line-height:2">
<li>Delete <code>install.php</code> from your server.</li>
<li>Go to <a href="<?= BASE_URL ?>/login">/login</a> — sign in with <strong>supadmin / supadmin</strong>.</li>
<li>Go to <a href="<?= BASE_URL ?>/admin/profile">/admin/profile</a> — change your password and email.</li>
<li>Go to <a href="<?= BASE_URL ?>/admin/settings">/admin/settings</a> — set your site URL and configure SMTP.</li>
</ol>
</div>
<?php endif; ?>
</div>
</body>
</html>