| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- <?php
- declare(strict_types=1);
- namespace App\Tests\Integration\Admin;
- use App\Domain\Auth\Role;
- use App\Domain\Auth\TokenKind;
- use App\Tests\Integration\Support\AppTestCase;
- /**
- * `/api/v1/admin/audit-log` end-to-end. Seeds rows directly so the
- * filter coverage doesn't depend on emission timing.
- */
- final class AuditLogControllerTest extends AppTestCase
- {
- public function testListEmpty(): void
- {
- $token = $this->createToken(TokenKind::Admin, Role::Viewer);
- $resp = $this->request('GET', '/api/v1/admin/audit-log', ['Authorization' => 'Bearer ' . $token]);
- self::assertSame(200, $resp->getStatusCode());
- $body = $this->decode($resp);
- self::assertSame([], $body['items']);
- self::assertSame(0, $body['total']);
- }
- public function testListWithFilters(): void
- {
- $now = (new \DateTimeImmutable('now', new \DateTimeZone('UTC')))->format('Y-m-d H:i:s');
- $this->seedAudit('user', '7', 'manual_block.created', 'manual_block', '1', '{"ip":"1.1.1.1"}', $now);
- $this->seedAudit('admin-token', '3', 'category.created', 'category', '2', '{"slug":"x"}', $now);
- $this->seedAudit('user', '7', 'allowlist.created', 'allowlist', '5', '{"ip":"2.2.2.2"}', $now);
- $token = $this->createToken(TokenKind::Admin, Role::Viewer);
- // Filter by actor_kind=user
- $resp = $this->request('GET', '/api/v1/admin/audit-log?actor_kind=user', ['Authorization' => 'Bearer ' . $token]);
- $body = $this->decode($resp);
- self::assertSame(2, $body['total']);
- foreach ($body['items'] as $item) {
- self::assertSame('user', $item['actor_kind']);
- }
- // Filter by action
- $resp = $this->request('GET', '/api/v1/admin/audit-log?action=category.created', ['Authorization' => 'Bearer ' . $token]);
- $body = $this->decode($resp);
- self::assertSame(1, $body['total']);
- self::assertSame('category.created', $body['items'][0]['action']);
- self::assertSame(['slug' => 'x'], $body['items'][0]['details']);
- // Filter by entity_type=manual_block
- $resp = $this->request('GET', '/api/v1/admin/audit-log?entity_type=manual_block', ['Authorization' => 'Bearer ' . $token]);
- $body = $this->decode($resp);
- self::assertSame(1, $body['total']);
- self::assertSame('manual_block', $body['items'][0]['entity_type']);
- }
- public function testInvalidActorKindReturns400(): void
- {
- $token = $this->createToken(TokenKind::Admin, Role::Viewer);
- $resp = $this->request('GET', '/api/v1/admin/audit-log?actor_kind=potato', ['Authorization' => 'Bearer ' . $token]);
- self::assertSame(400, $resp->getStatusCode());
- }
- public function testRequiresViewer(): void
- {
- $resp = $this->request('GET', '/api/v1/admin/audit-log');
- self::assertSame(401, $resp->getStatusCode());
- }
- private function seedAudit(string $kind, ?string $actorId, string $action, string $type, string $id, string $details, string $when): void
- {
- $this->db->insert('audit_log', [
- 'actor_kind' => $kind,
- 'actor_id' => $actorId,
- 'action' => $action,
- 'target_type' => $type,
- 'target_id' => $id,
- 'details_json' => $details,
- 'ip_address' => null,
- 'created_at' => $when,
- ]);
- }
- }
|