prepare('SELECT id FROM users WHERE username=? OR email=?');
$chk->execute([$new_username, $new_email]);
if ($chk->fetch()) {
$errors[] = 'Username or email already in use.';
} else {
$hash = password_hash($new_password, PASSWORD_BCRYPT);
$pdo->prepare("
INSERT INTO users (username,email,password_hash,display_name,role,rosary_limit,email_confirmed)
VALUES (?,?,?,?,?,?,1)
")->execute([$new_username, $new_email, $hash, $new_display_name ?: $new_username, $new_role, $new_limit]);
$messages[] = "User '{$new_username}' created.";
}
}
}
// ── Update user ──────────────────────────────────────────────────────────
if ($action === 'update_user') {
$target_id = (int)($_POST['target_id'] ?? 0);
$upd_display = trim($_POST['upd_display_name'] ?? '');
$upd_email = trim($_POST['upd_email'] ?? '');
$upd_role = $_POST['upd_role'] ?? '';
$upd_limit = (int)($_POST['upd_rosary_limit'] ?? 1);
// Fetch target to check if superadmin
$tgt = $pdo->prepare('SELECT * FROM users WHERE id=?');
$tgt->execute([$target_id]);
$tgt = $tgt->fetch();
if (!$tgt) {
$errors[] = 'User not found.';
} else {
// Role protection
$allowed_roles = $is_super ? ['user','superuser','admin','superadmin'] : ['user','superuser'];
if (!in_array($upd_role, $allowed_roles, true)) $upd_role = $tgt['role'];
// Non-superadmin cannot change superadmin's role
if (!$is_super && $tgt['role'] === 'superadmin') {
$errors[] = 'Cannot modify a superadmin account.';
} else {
if (!filter_var($upd_email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Invalid email.';
} else {
$chk = $pdo->prepare('SELECT id FROM users WHERE email=? AND id!=?');
$chk->execute([$upd_email, $target_id]);
if ($chk->fetch()) {
$errors[] = 'Email already in use by another account.';
} else {
$pdo->prepare('UPDATE users SET display_name=?,email=?,role=?,rosary_limit=? WHERE id=?')
->execute([$upd_display, $upd_email, $upd_role, $upd_limit, $target_id]);
$messages[] = "User '{$tgt['username']}' updated.";
}
}
}
}
}
// ── Reset password ───────────────────────────────────────────────────────
if ($action === 'reset_password') {
$target_id = (int)($_POST['target_id'] ?? 0);
$new_pass = $_POST['new_pass'] ?? '';
if (strlen($new_pass) < 8) {
$errors[] = 'New password must be at least 8 characters.';
} else {
$hash = password_hash($new_pass, PASSWORD_BCRYPT);
$pdo->prepare('UPDATE users SET password_hash=? WHERE id=?')->execute([$hash, $target_id]);
$messages[] = 'Password reset successfully.';
}
}
// ── Resend confirmation email ─────────────────────────────────────────────
if ($action === 'resend_confirmation') {
$target_id = (int)($_POST['target_id'] ?? 0);
$tgt = $pdo->prepare('SELECT * FROM users WHERE id = ? AND email_confirmed = 0');
$tgt->execute([$target_id]);
$tgt = $tgt->fetch();
if (!$tgt) {
$errors[] = 'User not found or already confirmed.';
} else {
$smtp_host = get_setting('smtp_host');
if ($smtp_host === '') {
// No SMTP — confirm directly
$pdo->prepare('UPDATE users SET email_confirmed = 1, confirm_token = NULL WHERE id = ?')
->execute([$target_id]);
$messages[] = "No SMTP configured — {$tgt['username']} has been confirmed directly.";
} else {
$token = bin2hex(random_bytes(32));
$site_url = rtrim(get_setting('site_url'), '/');
$site_name = get_setting('site_name', APP_NAME);
$link = $site_url . '/confirm?token=' . urlencode($token);
$disp = $tgt['display_name'] ?: $tgt['username'];
$pdo->prepare('UPDATE users SET confirm_token = ? WHERE id = ?')
->execute([$token, $target_id]);
$body_html = "
Confirm your email
Hello, " . htmlspecialchars($disp) . "!
An administrator has resent your confirmation email for {$site_name}. Click the button below to confirm your email address and activate your account:
Confirm Email
Or copy this link: " . htmlspecialchars($link) . "
If you did not register, ignore this email.
";
$html = email_template('Confirm your email — ' . $site_name, $body_html);
$ok = send_email($tgt['email'], $disp, 'Confirm your email — ' . $site_name, $html);
if ($ok) {
$messages[] = "Confirmation email resent to {$tgt['email']}.";
} else {
$errors[] = 'Failed to send email. Check your SMTP settings.';
}
}
}
}
// ── Delete user ──────────────────────────────────────────────────────────
if ($action === 'delete_user') {
$target_id = (int)($_POST['target_id'] ?? 0);
if ($target_id === $uid) {
$errors[] = 'You cannot delete your own account.';
} else {
$tgt = $pdo->prepare('SELECT role,username FROM users WHERE id=?');
$tgt->execute([$target_id]);
$tgt = $tgt->fetch();
if ($tgt && $tgt['role'] === 'superadmin' && !$is_super) {
$errors[] = 'Cannot delete a superadmin account.';
} elseif ($tgt) {
$pdo->prepare('DELETE FROM users WHERE id=?')->execute([$target_id]);
$messages[] = "User '{$tgt['username']}' deleted.";
}
}
}
}
// ── Load all users with rosary counts ────────────────────────────────────────
$users = $pdo->query("
SELECT u.*,
(SELECT COUNT(*) FROM sessions WHERE user_id=u.id AND occasion != 'novena_deceased') +
(SELECT COUNT(*) FROM novena_groups WHERE user_id=u.id)
AS rosary_count
FROM users u
ORDER BY u.created_at DESC
")->fetchAll();
$role_labels = ['superadmin'=>'Superadmin','admin'=>'Admin','superuser'=>'Superuser','user'=>'User'];
$role_colors = [
'superadmin' => '#dc2626',
'admin' => '#ea580c',
'superuser' => '#2563eb',
'user' => '#6b7280',
];
?>
Users — = htmlspecialchars($site_name) ?>
✓ = htmlspecialchars($m) ?>
= htmlspecialchars($e) ?>
Users (= count($users) ?>)
| Username |
Display Name |
Email |
Role |
Limit |
Rosaries |
Joined |
Actions |
= htmlspecialchars($u['username']) ?>
= !$u['email_confirmed'] ? ' Unconfirmed' : '' ?>
|
= htmlspecialchars($u['display_name'] ?? '') ?> |
= htmlspecialchars($u['email']) ?> |
= htmlspecialchars($role_labels[$u['role']] ?? $u['role']) ?>
|
= $u['rosary_limit'] < 0 ? '∞' : (int)$u['rosary_limit'] ?> |
= (int)$u['rosary_count'] ?> |
= date('M j, Y', strtotime($u['created_at'])) ?> |
|