Skip to content

Commit 181d865

Browse files
committed
Adds projects support
issue #149
1 parent b48c31c commit 181d865

File tree

62 files changed

+1247
-153
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1247
-153
lines changed

app/config/cache.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
'default' => env('CACHE_STORAGE', 'roadrunner'),
1111
'aliases' => [
1212
'events' => ['storage' => $defaultStorage, 'prefix' => 'events:'],
13+
'projects' => ['storage' => $defaultStorage, 'prefix' => 'projects:'],
1314
'webhooks' => ['storage' => $defaultStorage, 'prefix' => 'webhooks:'],
1415
'local' => ['storage' => $defaultStorage, 'prefix' => 'local:'],
1516
],
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Migration;
6+
7+
use Cycle\Migrations\Migration;
8+
9+
class OrmDefault5b1ee362e1b19b19f535c6f9da36cb55 extends Migration
10+
{
11+
protected const DATABASE = 'default';
12+
13+
public function up(): void
14+
{
15+
$this->table('events')
16+
->addColumn('project', 'string', ['nullable' => true, 'defaultValue' => null, 'size' => 255])
17+
->dropColumn('project_id')
18+
->update();
19+
}
20+
21+
public function down(): void
22+
{
23+
$this->table('events')
24+
->addColumn('project_id', 'integer', ['nullable' => true, 'defaultValue' => null])
25+
->dropColumn('project')
26+
->update();
27+
}
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Migration;
6+
7+
use Cycle\Migrations\Migration;
8+
9+
class OrmDefault2a897d68b0647d8ad446d9074be5a172 extends Migration
10+
{
11+
protected const DATABASE = 'default';
12+
13+
public function up(): void
14+
{
15+
$this->table('projects')
16+
->addColumn('key', 'string', ['nullable' => false, 'defaultValue' => null, 'size' => 36])
17+
->addColumn('name', 'string', ['nullable' => false, 'defaultValue' => null, 'size' => 255])
18+
->setPrimaryKeys(['key'])
19+
->create();
20+
}
21+
22+
public function down(): void
23+
{
24+
$this->table('projects')->drop();
25+
}
26+
}

app/modules/Events/Domain/Event.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use App\Application\Domain\ValueObjects\Uuid;
99
use Cycle\Annotated\Annotation\Column;
1010
use Cycle\Annotated\Annotation\Entity;
11-
use DateTimeImmutable;
1211

1312
#[Entity(
1413
repository: EventRepositoryInterface::class
@@ -29,8 +28,8 @@ public function __construct(
2928
#[Column(type: 'float')]
3029
private float $timestamp,
3130

32-
#[Column(type: 'integer', nullable: true)]
33-
private ?int $projectId,
31+
#[Column(type: 'string', nullable: true)]
32+
private ?string $project = null,
3433
) {
3534
}
3635

@@ -54,8 +53,8 @@ public function getTimestamp(): float
5453
return $this->timestamp;
5554
}
5655

57-
public function getProjectId(): ?int
56+
public function getProject(): ?string
5857
{
59-
return $this->projectId;
58+
return $this->project;
6059
}
6160
}

app/modules/Events/Domain/Events/EventWasReceived.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ public function __construct(
1515
public string $type,
1616
public array $payload,
1717
public float $timestamp,
18-
public ?int $projectId = null,
18+
public ?string $project = null,
1919
) {
2020
}
2121

2222
public function jsonSerialize(): array
2323
{
2424
return [
25-
'projectId' => $this->projectId,
25+
'project' => $this->project,
2626
'uuid' => (string)$this->uuid,
2727
'type' => $this->type,
2828
'payload' => $this->payload,

app/modules/Events/Interfaces/Commands/StoreEventHandler.php

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55
namespace Modules\Events\Interfaces\Commands;
66

7-
use App\Application\Commands\FindProjectByName;
87
use App\Application\Commands\HandleReceivedEvent;
98
use App\Application\Domain\Entity\Json;
10-
use Carbon\Carbon;
119
use Modules\Events\Domain\Event;
1210
use Modules\Events\Domain\EventRepositoryInterface;
1311
use Modules\Events\Domain\Events\EventWasReceived;
@@ -27,18 +25,13 @@ public function __construct(
2725
#[CommandHandler]
2826
public function handle(HandleReceivedEvent $command): void
2927
{
30-
$projectId = null;
31-
if ($command->project !== null) {
32-
$projectId = $this->queryBus->ask(new FindProjectByName($command->project));
33-
}
34-
3528
$this->events->store(
3629
new Event(
37-
$command->uuid,
38-
$command->type,
39-
new Json($command->payload),
40-
$command->timestamp,
41-
$projectId,
30+
uuid: $command->uuid,
31+
type: $command->type,
32+
payload: new Json($command->payload),
33+
timestamp: $command->timestamp,
34+
project: $command->project,
4235
),
4336
);
4437

@@ -48,7 +41,7 @@ public function handle(HandleReceivedEvent $command): void
4841
type: $command->type,
4942
payload: $command->payload,
5043
timestamp: $command->timestamp,
51-
projectId: $projectId,
44+
project: $command->project,
5245
),
5346
);
5447
}

app/modules/Events/Interfaces/Http/Resources/EventResource.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
new OA\Property(property: 'type', type: 'string'),
1919
new OA\Property(property: 'payload', description: 'Event payload based on type', type: 'object'),
2020
new OA\Property(property: 'timestamp', type: 'float', example: 1630540800.12312),
21+
new OA\Property(property: 'project', description: 'Project', type: 'string', format: 'uuid'),
2122
],
2223
)]
2324
final class EventResource extends JsonResource
@@ -34,7 +35,7 @@ protected function mapData(): array|\JsonSerializable
3435
'type' => $this->data->getType(),
3536
'payload' => $this->data->getPayload(),
3637
'timestamp' => $this->data->getTimestamp(),
37-
'project_id' => $this->data->getProjectId(),
38+
'project' => $this->data->getProject(),
3839
];
3940
}
4041
}

app/modules/Events/Interfaces/Queries/EventsHandler.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ protected static function getScopeFromFindEvents(AskEvents $query): array
1212
if ($query->type !== null) {
1313
$scope['type'] = $query->type;
1414
}
15-
if ($query->projectId !== null) {
16-
$scope['project_id'] = $query->projectId;
15+
if ($query->project !== null) {
16+
$scope['project'] = $query->project;
1717
}
1818

1919
return $scope;

app/modules/HttpDumps/Interfaces/Http/Handler/AnyHttpRequestDump.php

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Modules\HttpDumps\Interfaces\Http\Handler;
66

77
use App\Application\Commands\HandleReceivedEvent;
8+
use App\Application\Event\EventType;
89
use App\Application\Service\HttpHandler\HandlerInterface;
910
use Carbon\Carbon;
1011
use Modules\HttpDumps\Application\EventHandlerInterface;
@@ -16,14 +17,14 @@
1617
use Spiral\Storage\BucketInterface;
1718
use Spiral\Storage\StorageInterface;
1819

19-
final class AnyHttpRequestDump implements HandlerInterface
20+
final readonly class AnyHttpRequestDump implements HandlerInterface
2021
{
21-
private readonly BucketInterface $bucket;
22+
private BucketInterface $bucket;
2223

2324
public function __construct(
24-
private readonly CommandBusInterface $commands,
25-
private readonly EventHandlerInterface $handler,
26-
private readonly ResponseWrapper $responseWrapper,
25+
private CommandBusInterface $commands,
26+
private EventHandlerInterface $handler,
27+
private ResponseWrapper $responseWrapper,
2728
StorageInterface $storage,
2829
) {
2930
$this->bucket = $storage->bucket('attachments');
@@ -34,16 +35,11 @@ public function priority(): int
3435
return 0;
3536
}
3637

37-
private function isValidRequest(ServerRequestInterface $request): bool
38-
{
39-
return $request->getHeaderLine('X-Buggregator-Event') === 'http-dump'
40-
|| $request->getAttribute('event-type') === 'http-dump'
41-
|| $request->getUri()->getUserInfo() === 'http-dump';
42-
}
43-
4438
public function handle(ServerRequestInterface $request, \Closure $next): ResponseInterface
4539
{
46-
if (!$this->isValidRequest($request)) {
40+
$eventType = $this->listenEvent($request);
41+
42+
if ($eventType === null) {
4743
return $next($request);
4844
}
4945

@@ -52,7 +48,7 @@ public function handle(ServerRequestInterface $request, \Closure $next): Respons
5248
$event = $this->handler->handle($payload);
5349

5450
$this->commands->dispatch(
55-
new HandleReceivedEvent(type: 'http-dump', payload: $event),
51+
new HandleReceivedEvent(type: $eventType->type, payload: $event, project: $eventType->project),
5652
);
5753

5854
return $this->responseWrapper->create(200);
@@ -94,4 +90,16 @@ function (UploadedFileInterface $attachment) use ($id) {
9490
],
9591
];
9692
}
93+
94+
private function listenEvent(ServerRequestInterface $request): ?EventType
95+
{
96+
/** @var EventType|null $event */
97+
$event = $request->getAttribute('event');
98+
99+
if ($event?->type === 'http-dump') {
100+
return $event;
101+
}
102+
103+
return null;
104+
}
97105
}

app/modules/Inspector/Application/InspectorBootloader.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@
55
namespace Modules\Inspector\Application;
66

77
use Spiral\Boot\Bootloader\Bootloader;
8+
use Spiral\Boot\EnvironmentInterface;
89

910
final class InspectorBootloader extends Bootloader
1011
{
11-
12+
public function defineSingletons(): array
13+
{
14+
return [
15+
SecretKeyValidator::class => static fn(
16+
EnvironmentInterface $env,
17+
): SecretKeyValidator => new SecretKeyValidator(
18+
secret: $env->get('INSPECTOR_SECRET_KEY'),
19+
),
20+
];
21+
}
1222
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Modules\Inspector\Application;
6+
7+
use Psr\Http\Message\ServerRequestInterface;
8+
use Spiral\Core\Attribute\Singleton;
9+
10+
#[Singleton]
11+
final readonly class SecretKeyValidator
12+
{
13+
public function __construct(
14+
private ?string $secret = null,
15+
) {
16+
}
17+
18+
public function validateRequest(ServerRequestInterface $request): bool
19+
{
20+
if ($this->secret === null) {
21+
return true;
22+
}
23+
24+
if (!$request->hasHeader('X-Inspector-Key')) {
25+
return false;
26+
}
27+
28+
return $this->secret === $request->getHeaderLine('X-Inspector-Key');
29+
}
30+
}

app/modules/Inspector/Interfaces/Http/Handler/EventHandler.php

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
namespace Modules\Inspector\Interfaces\Http\Handler;
66

77
use App\Application\Commands\HandleReceivedEvent;
8+
use App\Application\Event\EventType;
89
use App\Application\Service\HttpHandler\HandlerInterface;
10+
use Modules\Inspector\Application\SecretKeyValidator;
911
use Psr\Http\Message\ResponseInterface;
1012
use Psr\Http\Message\ServerRequestInterface;
1113
use Spiral\Cqrs\CommandBusInterface;
@@ -17,6 +19,7 @@
1719
public function __construct(
1820
private ResponseWrapper $responseWrapper,
1921
private CommandBusInterface $commands,
22+
private SecretKeyValidator $secretKeyValidator,
2023
) {
2124
}
2225

@@ -27,10 +30,15 @@ public function priority(): int
2730

2831
public function handle(ServerRequestInterface $request, \Closure $next): ResponseInterface
2932
{
30-
if (!$this->isValidRequest($request)) {
33+
$eventType = $this->listenEvent($request);
34+
if ($eventType === null) {
3135
return $next($request);
3236
}
3337

38+
if (!$this->secretKeyValidator->validateRequest($request)) {
39+
throw new ClientException\ForbiddenException('Invalid secret key');
40+
}
41+
3442
$data = \json_decode(\base64_decode((string)$request->getBody()), true)
3543
?? throw new ClientException\BadRequestException('Invalid data');
3644

@@ -45,19 +53,29 @@ public function handle(ServerRequestInterface $request, \Closure $next): Respons
4553
};
4654

4755
$this->commands->dispatch(
48-
new HandleReceivedEvent(type: 'inspector', payload: $data),
56+
new HandleReceivedEvent(type: $eventType->type, payload: $data, project: $eventType->project),
4957
);
5058

5159
return $this->responseWrapper->create(200);
5260
}
5361

54-
private function isValidRequest(ServerRequestInterface $request): bool
62+
private function listenEvent(ServerRequestInterface $request): ?EventType
5563
{
56-
return $request->getHeaderLine('X-Buggregator-Event') === 'inspector'
57-
|| $request->getAttribute('event-type') === 'inspector'
58-
|| $request->getUri()->getUserInfo() === 'inspector'
59-
|| $request->hasHeader('X-Inspector-Key')
64+
/** @var EventType|null $event */
65+
$event = $request->getAttribute('event');
66+
67+
if ($event?->type === 'inspector') {
68+
return $event;
69+
}
70+
71+
if (
72+
$request->hasHeader('X-Inspector-Key')
6073
|| $request->hasHeader('X-Inspector-Version')
61-
|| \str_ends_with((string)$request->getUri(), 'inspector');
74+
|| \str_ends_with((string)$request->getUri(), 'inspector')
75+
) {
76+
return new EventType(type: 'profiler');
77+
}
78+
79+
return null;
6280
}
6381
}

app/modules/Profiler/Application/EventHandler.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
use Modules\Profiler\Application;
88
use Psr\Container\ContainerInterface;
99

10-
class EventHandler implements Application\EventHandlerInterface
10+
final readonly class EventHandler implements Application\EventHandlerInterface
1111
{
1212
/**
1313
* @param class-string<\Modules\Sentry\Application\EventHandlerInterface>[] $handlers
1414
*/
1515
public function __construct(
16-
private readonly ContainerInterface $container,
17-
private readonly array $handlers
16+
private ContainerInterface $container,
17+
private array $handlers
1818
) {
1919
}
2020

0 commit comments

Comments
 (0)