[location] // php seed_user.php supervisor [location] // php seed_user.php coach // // Flags: // --force-change Sets mustChangePassword = 1 (default ON, use --no-force-change to skip) // --no-force-change Sets mustChangePassword = 0 if (php_sapi_name() !== 'cli') { http_response_code(403); echo "CLI only\n"; exit(1); } require_once __DIR__ . '/db_init.php'; $usage = << [location] php seed_user.php supervisor [location] php seed_user.php coach Options: --no-force-change Skip requiring password change on first login (default: require change) --list List all existing users instead of creating one USAGE; // Strip flag args $args = []; $mustChangePassword = 1; $listMode = false; foreach (array_slice($argv, 1) as $arg) { if ($arg === '--no-force-change') { $mustChangePassword = 0; continue; } if ($arg === '--force-change') { $mustChangePassword = 1; continue; } if ($arg === '--list') { $listMode = true; continue; } $args[] = $arg; } // List mode if ($listMode) { try { [$pdo, $tmpDb, $lockFp] = qdb_open(false); $rows = $pdo->query( "SELECT u.username, u.role, u.entityID, u.mustChangePassword, COALESCE(a.location, s.location, c.supervisorID) AS detail FROM users u LEFT JOIN admin a ON a.adminID = u.entityID AND u.role = 'admin' LEFT JOIN supervisor s ON s.supervisorID = u.entityID AND u.role = 'supervisor' LEFT JOIN coach c ON c.coachID = u.entityID AND u.role = 'coach' ORDER BY u.role, u.username" )->fetchAll(PDO::FETCH_ASSOC); qdb_discard($tmpDb, $lockFp); if (empty($rows)) { echo "No users found.\n"; exit(0); } printf("%-20s %-12s %-40s %s\n", 'Username', 'Role', 'EntityID', 'Detail / SupervisorID'); echo str_repeat('-', 90) . "\n"; foreach ($rows as $r) { $mustChange = (int)$r['mustChangePassword'] ? ' [must change pw]' : ''; printf("%-20s %-12s %-40s %s%s\n", $r['username'], $r['role'], $r['entityID'], $r['detail'] ?? '', $mustChange ); } exit(0); } catch (Throwable $e) { fwrite(STDERR, "Error: " . $e->getMessage() . "\n"); exit(1); } } if (count($args) < 3) { fwrite(STDERR, $usage); exit(1); } $role = strtolower($args[0]); $username = $args[1]; $password = $args[2]; $extra = $args[3] ?? ''; // location (admin/supervisor) or supervisorID (coach) if (!in_array($role, ['admin', 'supervisor', 'coach'], true)) { fwrite(STDERR, "Error: role must be admin, supervisor, or coach.\n"); exit(1); } if ($username === '' || $password === '') { fwrite(STDERR, $usage); exit(1); } if (strlen($password) < 6) { fwrite(STDERR, "Error: Password must be at least 6 characters.\n"); exit(1); } if ($role === 'coach' && $extra === '') { fwrite(STDERR, "Error: coach requires a supervisorID as the 4th argument.\n"); exit(1); } try { [$pdo, $tmpDb, $lockFp] = qdb_open(true); // Duplicate username check $chk = $pdo->prepare("SELECT userID FROM users WHERE username = :u"); $chk->execute([':u' => $username]); if ($chk->fetch()) { qdb_discard($tmpDb, $lockFp); fwrite(STDERR, "Error: User '$username' already exists.\n"); exit(1); } // For coach, verify supervisorID exists if ($role === 'coach') { $sv = $pdo->prepare("SELECT supervisorID FROM supervisor WHERE supervisorID = :sid"); $sv->execute([':sid' => $extra]); if (!$sv->fetch()) { qdb_discard($tmpDb, $lockFp); fwrite(STDERR, "Error: supervisorID '$extra' not found. Create the supervisor first.\n"); exit(1); } } $entityID = bin2hex(random_bytes(16)); $userID = bin2hex(random_bytes(16)); $hash = password_hash($password, PASSWORD_DEFAULT); $now = time(); $pdo->beginTransaction(); switch ($role) { case 'admin': $pdo->prepare("INSERT INTO admin (adminID, username, location) VALUES (:id, :u, :loc)") ->execute([':id' => $entityID, ':u' => $username, ':loc' => $extra]); break; case 'supervisor': $pdo->prepare("INSERT INTO supervisor (supervisorID, username, location) VALUES (:id, :u, :loc)") ->execute([':id' => $entityID, ':u' => $username, ':loc' => $extra]); break; case 'coach': $pdo->prepare("INSERT INTO coach (coachID, supervisorID, username) VALUES (:id, :sid, :u)") ->execute([':id' => $entityID, ':sid' => $extra, ':u' => $username]); break; } $pdo->prepare( "INSERT INTO users (userID, username, passwordHash, role, entityID, mustChangePassword, createdAt) VALUES (:uid, :u, :hash, :role, :eid, :mcp, :now)" )->execute([ ':uid' => $userID, ':u' => $username, ':hash' => $hash, ':role' => $role, ':eid' => $entityID, ':mcp' => $mustChangePassword, ':now' => $now, ]); $pdo->commit(); $pdo = null; qdb_save($tmpDb, $lockFp); $changeNote = $mustChangePassword ? ' (must change password on first login)' : ''; echo ucfirst($role) . " '$username' created successfully$changeNote.\n"; echo "EntityID: $entityID\n"; } catch (Throwable $e) { if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp); fwrite(STDERR, "Error: " . $e->getMessage() . "\n"); exit(1); }