move_detect/server/src/Repository/Pdo/PdoUserRepository.php
유창욱 3f2823a764 refactor: rename cloud/ to server/ (cafe24 is web hosting, not cloud)
The PHP app runs on Cafe24 shared web hosting -- calling it 'cloud'
was misleading. Renames the directory, the edge client module, and
every doc/script/identifier that used the term.

- cloud/ -> server/ (incl. server/deploy/build_cafe24_package.sh paths)
- edge/cloudclient.py -> edge/serverclient.py, CloudClient -> ServerClient
- cloud/docs/cloud-deploy.md -> server/docs/server-deploy.md
- CLOUD_* env/config keys -> SERVER_*
- tests renamed to match

Tests: PHP 109 pass (4 skipped), pytest 167 pass. dist/ regenerated.
2026-07-20 11:30:52 +09:00

49 lines
1.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Repository\Pdo;
use App\Repository\UserRepository;
use PDO;
final class PdoUserRepository implements UserRepository
{
public function __construct(private PDO $pdo) {}
public function byUsername(string $username): ?array
{
$st = $this->pdo->prepare(
'SELECT id, username, password_hash, role, site_scope, failed_attempts, locked_until
FROM move_users WHERE username = ? LIMIT 1'
);
$st->execute([$username]);
$row = $st->fetch();
if ($row === false) {
return null;
}
return [
'id' => (int)$row['id'],
'username' => $row['username'],
'password_hash' => $row['password_hash'],
'role' => $row['role'],
'site_scope' => $row['site_scope'],
'failed_attempts' => (int)$row['failed_attempts'],
'locked_until' => (int)$row['locked_until'],
];
}
public function recordFailure(int $userId, int $lockUntil): void
{
// Increment in SQL (not read-then-write in PHP) so concurrent failed
// logins for the same account can't clobber each other's count.
$st = $this->pdo->prepare(
'UPDATE move_users SET failed_attempts = failed_attempts + 1, locked_until = ? WHERE id = ?'
);
$st->execute([$lockUntil, $userId]);
}
public function clearFailures(int $userId): void
{
$st = $this->pdo->prepare('UPDATE move_users SET failed_attempts = 0, locked_until = 0 WHERE id = ?');
$st->execute([$userId]);
}
}