| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- <?php
- declare(strict_types=1);
- use App\Infrastructure\Db\Migrations\BaseMigration;
- /**
- * SEC_REVIEW F11: add a `disabled_at` nullable timestamp to `users` so an
- * operator can revoke a user without deleting the audit-history row.
- *
- * `NULL` means active; any non-null value means the user is disabled (the
- * stamp is informational — only the predicate `IS NULL` matters at the
- * impersonation boundary). Indexed because both the impersonation
- * 403-check (`SELECT … WHERE id = ?`) and the admin-users list page filter
- * by it; the index is partial on SQLite to keep the live-user lookup
- * branch index-free.
- */
- final class AddDisabledAtToUsers extends BaseMigration
- {
- public function up(): void
- {
- $table = $this->table('users');
- $this->addTimestampColumn($table, 'disabled_at', ['null' => true, 'after' => 'is_local']);
- $table->update();
- // Partial index speeds up the "list disabled users" admin page; the
- // active-user lookup path doesn't need it (PK lookup already).
- if ($this->isMysql()) {
- $this->execute('CREATE INDEX idx_users_disabled_at ON users (disabled_at)');
- } else {
- $this->execute('CREATE INDEX idx_users_disabled_at ON users (disabled_at) WHERE disabled_at IS NOT NULL');
- }
- }
- public function down(): void
- {
- if ($this->isMysql()) {
- $this->execute('DROP INDEX idx_users_disabled_at ON users');
- } else {
- $this->execute('DROP INDEX IF EXISTS idx_users_disabled_at');
- }
- $this->table('users')
- ->removeColumn('disabled_at')
- ->update();
- }
- }
|