Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions backend/app/DomainObjects/Enums/ImageTypes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace HiEvents\DomainObjects\Enums;

enum ImageTypes
{
use BaseEnum;

case GENERIC;
}
33 changes: 33 additions & 0 deletions backend/app/Http/Actions/Images/CreateImageAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace HiEvents\Http\Actions\Images;

use HiEvents\Http\Actions\BaseAction;
use HiEvents\Http\Request\Image\CreateImageRequest;
use HiEvents\Resources\Image\ImageResource;
use HiEvents\Services\Application\Handlers\Images\CreateImageHandler;
use HiEvents\Services\Application\Handlers\Images\DTO\CreateImageDTO;
use HiEvents\Services\Infrastructure\Image\Exception\CouldNotUploadImageException;
use Illuminate\Http\JsonResponse;

class CreateImageAction extends BaseAction
{
public function __construct(
public readonly CreateImageHandler $createImageHandler,
)
{
}

/**
* @throws CouldNotUploadImageException
*/
public function __invoke(CreateImageRequest $request): JsonResponse
{
$image = $this->createImageHandler->handle(new CreateImageDTO(
userId: $this->getAuthenticatedUser()->getId(),
image: $request->file('image'),
));

return $this->resourceResponse(ImageResource::class, $image);
}
}
16 changes: 9 additions & 7 deletions backend/app/Http/Request/Event/CreateEventImageRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace HiEvents\Http\Request\Event;

use HiEvents\DomainObjects\Enums\EventImageType;
use HiEvents\Validators\Rules\RulesHelper;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

Expand All @@ -11,14 +12,15 @@ class CreateEventImageRequest extends FormRequest
public function rules(): array
{
return [
'image' => [
'required',
'image',
'max:8192', //8mb
'dimensions:min_width=600,min_height=50,max_width=4000,max_height=4000',
'mimes:jpeg,png,jpg,webp',
],
'image' => RulesHelper::IMAGE_RULES,
'type' => Rule::in(EventImageType::valuesArray()),
];
}

public function messages(): array
{
return [
'image.dimensions' => __('The image must be at least 600 pixels wide and 50 pixels tall, and no more than 4000 pixels wide and 4000 pixels tall.'),
];
}
}
23 changes: 23 additions & 0 deletions backend/app/Http/Request/Image/CreateImageRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace HiEvents\Http\Request\Image;

use HiEvents\Validators\Rules\RulesHelper;
use Illuminate\Foundation\Http\FormRequest;

class CreateImageRequest extends FormRequest
{
public function rules(): array
{
return [
'image' => RulesHelper::IMAGE_RULES,
];
}

public function messages(): array
{
return [
'image.dimensions' => __('The image must be at least 600 pixels wide and 50 pixels tall, and no more than 4000 pixels wide and 4000 pixels tall.'),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function handle(CreateEventImageDTO $imageData): ImageDomainObject
return $this->createEventImageService->createImage(
eventId: $imageData->event_id,
image: $imageData->image,
type: $imageData->type,
imageType: $imageData->imageType,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class CreateEventImageDTO extends BaseDTO
public function __construct(
public readonly int $event_id,
public readonly UploadedFile $image,
public readonly EventImageType $type,
public readonly EventImageType $imageType,
)
{
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace HiEvents\Services\Application\Handlers\Images;

use HiEvents\DomainObjects\Enums\ImageTypes;
use HiEvents\DomainObjects\ImageDomainObject;
use HiEvents\DomainObjects\UserDomainObject;
use HiEvents\Services\Application\Handlers\Images\DTO\CreateImageDTO;
use HiEvents\Services\Domain\Image\ImageUploadService;
use HiEvents\Services\Infrastructure\Image\Exception\CouldNotUploadImageException;

class CreateImageHandler
{
public function __construct(
private readonly ImageUploadService $imageUploadService,
)
{
}

/**
* @throws CouldNotUploadImageException
*/
public function handle(CreateImageDTO $imageData): ImageDomainObject
{
// For generic images, we associate them with the user
return $this->imageUploadService->upload(
image: $imageData->image,
entityId: $imageData->userId,
entityType: UserDomainObject::class,
imageType: ImageTypes::GENERIC->name,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace HiEvents\Services\Application\Handlers\Images\DTO;

use Illuminate\Http\UploadedFile;

class CreateImageDTO
{
public function __construct(
public readonly int $userId,
public readonly UploadedFile $image,
)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private function createOrganizer(CreateOrganizerDTO $organizerData): OrganizerDo
image: $organizerData->logo,
entityId: $organizer->getId(),
entityType: OrganizerDomainObject::class,
imageType: OrganizerImageType::LOGO->name,
imageType: OrganizerImageType::LOGO,
);
}

Expand Down
8 changes: 4 additions & 4 deletions backend/app/Services/Domain/Event/CreateEventImageService.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public function __construct(
public function createImage(
int $eventId,
UploadedFile $image,
EventImageType $type,
EventImageType $imageType,
): ImageDomainObject
{
return $this->databaseManager->transaction(function () use ($image, $eventId, $type) {
if ($type === EventImageType::EVENT_COVER) {
return $this->databaseManager->transaction(function () use ($entityType, $image, $eventId, $imageType) {
if ($imageType === EventImageType::EVENT_COVER) {
$this->imageRepository->deleteWhere([
'entity_id' => $eventId,
'entity_type' => EventDomainObject::class,
Expand All @@ -43,7 +43,7 @@ public function createImage(
image: $image,
entityId: $eventId,
entityType: EventDomainObject::class,
imageType: $type->name,
imageType: $imageType->name,
);
});
}
Expand Down
6 changes: 3 additions & 3 deletions backend/app/Services/Domain/Image/ImageUploadService.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
use HiEvents\Services\Infrastructure\Image\ImageStorageService;
use Illuminate\Http\UploadedFile;

readonly class ImageUploadService
class ImageUploadService
{
public function __construct(
private ImageStorageService $imageStorageService,
private ImageRepositoryInterface $imageRepository
private readonly ImageStorageService $imageStorageService,
private readonly ImageRepositoryInterface $imageRepository
)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
use Illuminate\Support\Str;
use Psr\Log\LoggerInterface;

readonly class ImageStorageService
class ImageStorageService
{
public function __construct(
private FilesystemManager $filesystemManager,
private Repository $config,
private LoggerInterface $logger,
private readonly FilesystemManager $filesystemManager,
private readonly Repository $config,
private readonly LoggerInterface $logger,
)
{
}
Expand Down
8 changes: 8 additions & 0 deletions backend/app/Validators/Rules/RulesHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,12 @@ class RulesHelper
public const REQUIRED_EMAIL = ['email' , 'required', 'max:100'];

public const OPTIONAL_TEXT_MEDIUM_LENGTH = ['string', 'max:2000', 'nullable'];

public const IMAGE_RULES = [
'required',
'image',
'max:8192', //8mb
'dimensions:min_width=600,min_height=50,max_width=4000,max_height=4000',
'mimes:jpeg,png,jpg,webp',
];
}
4 changes: 4 additions & 0 deletions backend/routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
use HiEvents\Http\Actions\EventSettings\EditEventSettingsAction;
use HiEvents\Http\Actions\EventSettings\GetEventSettingsAction;
use HiEvents\Http\Actions\EventSettings\PartialEditEventSettingsAction;
use HiEvents\Http\Actions\Images\CreateImageAction;
use HiEvents\Http\Actions\Messages\GetMessagesAction;
use HiEvents\Http\Actions\Messages\SendMessageAction;
use HiEvents\Http\Actions\Orders\CancelOrderAction;
Expand Down Expand Up @@ -297,6 +298,9 @@ function (Router $router): void {

// Reports
$router->get('/events/{event_id}/reports/{report_type}', GetReportAction::class);

// Images
$router->post('/images', CreateImageAction::class);
}
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Tests\Unit\Services\Application\Handlers\Images;

use HiEvents\DomainObjects\Enums\ImageTypes;
use HiEvents\DomainObjects\ImageDomainObject;
use HiEvents\DomainObjects\UserDomainObject;
use HiEvents\Services\Application\Handlers\Images\CreateImageHandler;
use HiEvents\Services\Application\Handlers\Images\DTO\CreateImageDTO;
use HiEvents\Services\Domain\Image\ImageUploadService;
use Illuminate\Http\UploadedFile;
use Mockery as m;
use PHPUnit\Framework\TestCase;

class CreateImageHandlerTest extends TestCase
{
private ImageUploadService $imageUploadService;
private CreateImageHandler $handler;

protected function setUp(): void
{
parent::setUp();

$this->imageUploadService = m::mock(ImageUploadService::class);

$this->handler = new CreateImageHandler(
$this->imageUploadService
);
}

public function testHandleSuccessfullyCreatesImage(): void
{
$uploadedFile = m::mock(UploadedFile::class);
$imageDomainObject = m::mock(ImageDomainObject::class);

$dto = new CreateImageDTO(
userId: 42,
image: $uploadedFile
);

$this->imageUploadService
->shouldReceive('upload')
->once()
->withArgs([
$uploadedFile,
42,
UserDomainObject::class,
ImageTypes::GENERIC->name,
])
->andReturn($imageDomainObject);

$result = $this->handler->handle($dto);

$this->assertSame($imageDomainObject, $result);
}
}
Loading