212 lines
7.4 KiB
PHP
212 lines
7.4 KiB
PHP
<?php
|
|
|
|
class UserRepo
|
|
{
|
|
/**
|
|
* Full user list with role-table JOINs for location, supervisorID, supervisorUsername.
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public static function listAll(PDO $pdo): array
|
|
{
|
|
return $pdo->query("
|
|
SELECT u.userID, u.username, u.role, u.entityID, u.mustChangePassword, u.createdAt,
|
|
COALESCE(a.location, s.location, '') AS location,
|
|
c.supervisorID,
|
|
sv.username AS supervisorUsername
|
|
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'
|
|
LEFT JOIN supervisor sv ON sv.supervisorID = c.supervisorID
|
|
ORDER BY u.role, u.username
|
|
")->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Coaches that belong to the given supervisor.
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public static function listBySupervisor(PDO $pdo, string $supervisorID): array
|
|
{
|
|
$svName = self::getSupervisorName($pdo, $supervisorID);
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT u.userID, u.username, u.role, u.entityID, u.mustChangePassword, u.createdAt,
|
|
'' AS location, c.supervisorID, :svname AS supervisorUsername
|
|
FROM users u
|
|
JOIN coach c ON c.coachID = u.entityID AND u.role = 'coach'
|
|
WHERE c.supervisorID = :svid
|
|
ORDER BY u.username
|
|
");
|
|
$stmt->execute([':svid' => $supervisorID, ':svname' => $svName]);
|
|
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* @return list<array{supervisorID: string, username: string, location: string}>
|
|
*/
|
|
public static function listSupervisors(PDO $pdo): array
|
|
{
|
|
return $pdo->query(
|
|
"SELECT supervisorID, username, location FROM supervisor ORDER BY username"
|
|
)->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
public static function findByUsername(PDO $pdo, string $username): ?array
|
|
{
|
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :u");
|
|
$stmt->execute([':u' => $username]);
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
/**
|
|
* @return array{role: string, entityID: string}|null
|
|
*/
|
|
public static function findById(PDO $pdo, string $userID): ?array
|
|
{
|
|
$stmt = $pdo->prepare("SELECT role, entityID FROM users WHERE userID = :uid");
|
|
$stmt->execute([':uid' => $userID]);
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
public static function usernameExists(PDO $pdo, string $username): bool
|
|
{
|
|
$stmt = $pdo->prepare("SELECT 1 FROM users WHERE username = :u");
|
|
$stmt->execute([':u' => $username]);
|
|
|
|
return (bool) $stmt->fetch();
|
|
}
|
|
|
|
public static function supervisorExists(PDO $pdo, string $supervisorID): bool
|
|
{
|
|
$stmt = $pdo->prepare("SELECT 1 FROM supervisor WHERE supervisorID = :sid");
|
|
$stmt->execute([':sid' => $supervisorID]);
|
|
|
|
return (bool) $stmt->fetch();
|
|
}
|
|
|
|
public static function coachBelongsToSupervisor(PDO $pdo, string $coachEntityID, string $supervisorID): bool
|
|
{
|
|
$stmt = $pdo->prepare(
|
|
"SELECT coachID FROM coach WHERE coachID = :cid AND supervisorID = :svid"
|
|
);
|
|
$stmt->execute([':cid' => $coachEntityID, ':svid' => $supervisorID]);
|
|
|
|
return (bool) $stmt->fetch();
|
|
}
|
|
|
|
/**
|
|
* Insert a new user inside a transaction: role-specific table first, then users.
|
|
* Caller is responsible for wrapping in qdb_open(true) / qdb_save().
|
|
*/
|
|
public static function create(
|
|
PDO $pdo,
|
|
string $userID,
|
|
string $entityID,
|
|
string $username,
|
|
string $passwordHash,
|
|
string $role,
|
|
string $location,
|
|
string $supervisorID,
|
|
int $mustChangePassword
|
|
): void {
|
|
$pdo->beginTransaction();
|
|
try {
|
|
switch ($role) {
|
|
case 'admin':
|
|
$pdo->prepare("INSERT INTO admin (adminID, username, location) VALUES (:id, :u, :loc)")
|
|
->execute([':id' => $entityID, ':u' => $username, ':loc' => $location]);
|
|
break;
|
|
case 'supervisor':
|
|
$pdo->prepare("INSERT INTO supervisor (supervisorID, username, location) VALUES (:id, :u, :loc)")
|
|
->execute([':id' => $entityID, ':u' => $username, ':loc' => $location]);
|
|
break;
|
|
case 'coach':
|
|
$pdo->prepare("INSERT INTO coach (coachID, supervisorID, username) VALUES (:id, :sid, :u)")
|
|
->execute([':id' => $entityID, ':sid' => $supervisorID, ':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' => $passwordHash,
|
|
':role' => $role,
|
|
':eid' => $entityID,
|
|
':mcp' => $mustChangePassword,
|
|
':now' => time(),
|
|
]);
|
|
|
|
$pdo->commit();
|
|
} catch (Throwable $e) {
|
|
if ($pdo->inTransaction()) {
|
|
$pdo->rollBack();
|
|
}
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete user + role-specific row in a transaction.
|
|
*/
|
|
public static function delete(PDO $pdo, string $userID, string $role, string $entityID): void
|
|
{
|
|
$pdo->beginTransaction();
|
|
try {
|
|
$pdo->prepare("DELETE FROM users WHERE userID = :uid")
|
|
->execute([':uid' => $userID]);
|
|
|
|
switch ($role) {
|
|
case 'admin':
|
|
$pdo->prepare("DELETE FROM admin WHERE adminID = :id")
|
|
->execute([':id' => $entityID]);
|
|
break;
|
|
case 'supervisor':
|
|
$pdo->prepare("DELETE FROM supervisor WHERE supervisorID = :id")
|
|
->execute([':id' => $entityID]);
|
|
break;
|
|
case 'coach':
|
|
$pdo->prepare("DELETE FROM coach WHERE coachID = :id")
|
|
->execute([':id' => $entityID]);
|
|
break;
|
|
}
|
|
|
|
$pdo->commit();
|
|
} catch (Throwable $e) {
|
|
if ($pdo->inTransaction()) {
|
|
$pdo->rollBack();
|
|
}
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public static function updatePassword(PDO $pdo, string $userID, string $newHash): void
|
|
{
|
|
$pdo->prepare(
|
|
"UPDATE users SET passwordHash = :h, mustChangePassword = 0 WHERE userID = :uid"
|
|
)->execute([':h' => $newHash, ':uid' => $userID]);
|
|
}
|
|
|
|
/**
|
|
* @return string Username or empty string if not found.
|
|
*/
|
|
public static function getSupervisorName(PDO $pdo, string $supervisorID): string
|
|
{
|
|
$stmt = $pdo->prepare("SELECT username FROM supervisor WHERE supervisorID = :svid");
|
|
$stmt->execute([':svid' => $supervisorID]);
|
|
|
|
return $stmt->fetchColumn() ?: '';
|
|
}
|
|
}
|