new system prototype
This commit is contained in:
176
seed_user.php
Normal file
176
seed_user.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
// CLI tool for creating users of any role.
|
||||
//
|
||||
// Usage:
|
||||
// php seed_user.php admin <username> <password> [location]
|
||||
// php seed_user.php supervisor <username> <password> [location]
|
||||
// php seed_user.php coach <username> <password> <supervisorID>
|
||||
//
|
||||
// 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 = <<<USAGE
|
||||
Usage:
|
||||
php seed_user.php admin <username> <password> [location]
|
||||
php seed_user.php supervisor <username> <password> [location]
|
||||
php seed_user.php coach <username> <password> <supervisorID>
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user