Skip to content

Commit

Permalink
upload file from controller with e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
rigonlucas committed Sep 6, 2024
1 parent e6b3cfc commit a068730
Show file tree
Hide file tree
Showing 17 changed files with 305 additions and 37 deletions.
23 changes: 0 additions & 23 deletions app/Http/Controllers/V1/Project/UploadFileController.php

This file was deleted.

72 changes: 72 additions & 0 deletions app/Http/Controllers/V1/Project/UploadProjectFileController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace App\Http\Controllers\V1\Project;

use App\Http\Controllers\Controller;
use App\Http\Requests\V1\Project\UploadProjectFileRequest;
use Core\Application\Common\Inputs\FiletInput;
use Core\Application\File\Gateways\FileCommandInterface;
use Core\Application\Project\Commons\Gateways\ProjectMapperInterface;
use Core\Domain\Enum\File\ContextFileEnum;
use Core\Domain\Enum\File\ExtensionsEnum;
use Core\Domain\Enum\File\TypeFileEnum;
use Core\Domain\ValueObjects\BytesValueObject;
use Core\Presentation\Http\Errors\ErrorPresenter;
use Core\Services\Framework\FrameworkContract;
use Core\Support\Exceptions\OutputErrorException;
use Core\Support\Http\ResponseStatus;
use Infra\Handlers\UseCases\Project\Upload\UploadProjectFileHandler;
use Ramsey\Uuid\Uuid;

class UploadProjectFileController extends Controller
{
public function __construct(
private readonly FrameworkContract $framework,
private readonly FileCommandInterface $fileCommand,
private readonly ProjectMapperInterface $projectMapper
) {
}

public function __invoke(UploadProjectFileRequest $request, string $uuid)
{
$uploadedFile = $request->file('file');
$input = new FiletInput(
name: $uploadedFile->name,
type: TypeFileEnum::DOCUMENT,
size: new BytesValueObject($uploadedFile->getSize()),
extension: ExtensionsEnum::from($uploadedFile->getClientOriginalExtension()),
contextFile: ContextFileEnum::PROJECT,
uuid: Uuid::fromString($uuid)
);
try {
$this->framework->transactionManager()->beginTransaction();

$projectFileHandler = new UploadProjectFileHandler(
framework: $this->framework,
fileProjectCommand: $this->fileCommand,
projectMapper: $this->projectMapper
);
$fileEntity = $projectFileHandler->handle($input, $uploadedFile);

$this->framework->transactionManager()->commit();
} catch (OutputErrorException $outputErrorException) {
$this->framework->transactionManager()->rollBack();
return response()->json(
data: (new ErrorPresenter(
message: $outputErrorException->getMessage(),
errors: $outputErrorException->getErrors()
))->toArray(),
status: $outputErrorException->getCode()
);
}

return response()->json(
data: [
'uuid' => $fileEntity->getUuid()->toString(),
'project_uuid' => $uuid,
'file_name' => $fileEntity->getUlidFileName() . '.' . $fileEntity->getExtension()->value,
],
status: ResponseStatus::OK->value
);
}
}
21 changes: 21 additions & 0 deletions app/Http/Requests/V1/Project/UploadProjectFileRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace App\Http\Requests\V1\Project;

use Illuminate\Foundation\Http\FormRequest;

class UploadProjectFileRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}

public function rules(): array
{
return [
'project_uuid' => ['required', 'uuid'],
'file' => ['required', 'file'],
];
}
}
4 changes: 2 additions & 2 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Providers;

use App\Http\Controllers\V1\Project\UploadFileController;
use App\Http\Controllers\V1\Project\UploadProjectFileController;
use Core\Application\Account\Commons\Gateways\AccountCommandInterface;
use Core\Application\Account\Commons\Gateways\AccountMapperInterface;
use Core\Application\File\Gateways\FileCommandInterface;
Expand Down Expand Up @@ -73,7 +73,7 @@ private function registerDataBaseBinds(): void

$this->app->bind(ProjectFileMapperInterface::class, ProjectFileMapper::class);

$this->app->when([UploadFileController::class])
$this->app->when([UploadProjectFileController::class])
->needs(FileCommandInterface::class)
->give(FileProjectCommand::class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Core\Domain\ValueObjects\BytesValueObject;
use Ramsey\Uuid\UuidInterface;

readonly class ProjecFiletInput
readonly class FiletInput
{

public function __construct(
Expand Down
2 changes: 2 additions & 0 deletions core/Application/File/Gateways/FileCommandInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
interface FileCommandInterface
{
public function create(FileEntity $projectFileEntity, UuidInterface $referenciaUuid): FileEntity;

public function confirmUploadFile(FileEntity $fileEntity): void;
}
5 changes: 3 additions & 2 deletions core/Application/Project/Upload/ProjectUploadFileUseCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Core\Application\Project\Upload;

use Core\Application\Common\Inputs\ProjecFiletInput;
use Core\Application\Common\Inputs\FiletInput;
use Core\Application\File\Gateways\FileCommandInterface;
use Core\Application\Project\Commons\Exceptions\ProjectNotFoundException;
use Core\Application\Project\Commons\Gateways\ProjectMapperInterface;
Expand All @@ -25,7 +25,7 @@ public function __construct(
* @throws ForbidenException
* @throws ProjectNotFoundException
*/
public function execute(ProjecFiletInput $projecFiletInput, UserEntity $authUserEntity): FileEntity
public function execute(FiletInput $projecFiletInput, UserEntity $authUserEntity): FileEntity
{
$projectEntity = $this->projectMapper->findByUuid($projecFiletInput->uuid, $authUserEntity);
if (!$projectEntity) {
Expand All @@ -38,6 +38,7 @@ public function execute(ProjecFiletInput $projecFiletInput, UserEntity $authUser

$projectFileEntity = FileEntity::forCreate(
uuid: $this->framework->uuid()->uuid7Generate(),
entityUuid: $projectEntity->getUuid(),
name: $projecFiletInput->name,
type: $projecFiletInput->type,
size: $projecFiletInput->size,
Expand Down
18 changes: 18 additions & 0 deletions core/Domain/Entities/File/Root/FileEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class FileEntity


private UuidInterface $uuid;
private UuidInterface $entityUuid;
private string $ulidFileName;
private string $name;
private FilePathValueObjectInterface $path;
Expand Down Expand Up @@ -116,11 +117,28 @@ public function getUlidFileName(): string
return $this->ulidFileName;
}

public function getEntityUuid(): UuidInterface
{
return $this->entityUuid;
}

public function setEntityUuid(UuidInterface $entityUuid): FileEntity
{
$this->entityUuid = $entityUuid;
return $this;
}

public function confirmUpload(): void
{
$this->status = StatusFileEnum::FINISHED;
}

private function applyPathMask(): void
{
$this->path->apply(
$this->getUserEntity()->getAccount()->getUuid(),
$this->context,
$this->entityUuid,
$this->ulidFileName = Ulid::generate(),
$this->extension->value
);
Expand Down
2 changes: 2 additions & 0 deletions core/Domain/Entities/File/Root/FileEntityBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ trait FileEntityBuilder
{
public static function forCreate(
UuidInterface $uuid,
UuidInterface $entityUuid,
string $name,
TypeFileEnum $type,
BytesValueObject $size,
Expand All @@ -30,6 +31,7 @@ public static function forCreate(
$projectFileEntity->setExtension($extension);
$projectFileEntity->setUserEntity($userEntity);
$projectFileEntity->setContext($context);
$projectFileEntity->setEntityUuid($entityUuid);
$projectFileEntity->setStatus(StatusFileEnum::PENDING);
$projectFileEntity->setPath(new DefaultPathValueObject());

Expand Down
11 changes: 9 additions & 2 deletions core/Domain/ValueObjects/File/DefaultPathValueObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ class DefaultPathValueObject implements FilePathValueObjectInterface
{
/**
* This mask is used to generate the path of the file in the storage
* @example {ACCOUNT_UUID}/{CONTEXT}/{FILE_UUID}.{EXTENSION}
* @example {ACCOUNT_UUID}/{CONTEXT}/{PROJECT_UUID}/{FILE_UUID}.{EXTENSION}
*/
private const string FILE_PATH_MASK = '%s/%s/%s.%s';
private const string FILE_PATH_MASK = '%s/%s/%s/%s.%s';
private ?string $path = null;

public function getPath(): string
Expand All @@ -22,13 +22,15 @@ public function getPath(): string
public function apply(
UuidInterface $accountUuid,
ContextFileEnum $contextEnum,
UuidInterface $entityUuid,
string $fileName,
string $fileExtension
): self {
$this->path = sprintf(
self::FILE_PATH_MASK,
$accountUuid->toString(),
$contextEnum->value,
$entityUuid->toString(),
$fileName,
$fileExtension
);
Expand All @@ -40,4 +42,9 @@ public function __toString(): string
{
return $this->path;
}

public function getBasePath(): string
{
// TODO: Implement getBasePath() method.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public function getPath(): string;
public function apply(
UuidInterface $accountUuid,
ContextFileEnum $contextEnum,
UuidInterface $entityUuid,
string $fileName,
string $fileExtension
): self;
Expand Down
7 changes: 7 additions & 0 deletions infra/Database/File/Command/FileProjectCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,11 @@ public function create(FileEntity $projectFileEntity, UuidInterface $referenciaU

return $projectFileEntity;
}

public function confirmUploadFile(FileEntity $fileEntity): void
{
$projectFile = ProjectFile::query()->where('uuid', $fileEntity->getUuid())->first();
$projectFile->status = $fileEntity->getStatus()->value;
$projectFile->save();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Infra\Handlers\UseCases\Project\Upload;

use Core\Application\Common\Inputs\FiletInput;
use Core\Application\File\Gateways\FileCommandInterface;
use Core\Application\Project\Commons\Gateways\ProjectMapperInterface;
use Core\Application\Project\Upload\ProjectUploadFileUseCase;
use Core\Domain\Entities\File\Root\FileEntity;
use Core\Services\Framework\FrameworkContract;
use Core\Support\Http\ResponseStatus;
use Exception;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

class UploadProjectFileHandler
{
public function __construct(
private readonly FrameworkContract $framework,
private readonly FileCommandInterface $fileProjectCommand,
private readonly ProjectMapperInterface $projectMapper
) {
}

public function handle(FiletInput $projecFiletInput, UploadedFile $file): FileEntity
{
$fileEntity = $this->applyRegisterFile($projecFiletInput);
$this->pushFile($fileEntity, $file);
$this->checkIfFileWasSaved($fileEntity);

return $fileEntity;
}

private function applyRegisterFile(FiletInput $projecFiletInput): FileEntity
{
$projectUploadFileUseCase = new ProjectUploadFileUseCase(
framework: $this->framework,
fileCommand: $this->fileProjectCommand,
projectMapper: $this->projectMapper
);
return $projectUploadFileUseCase->execute($projecFiletInput, $this->framework->auth()->user());
}

private function pushFile(FileEntity $fileEntity, UploadedFile $file): void
{
$directory = dirname($fileEntity->getPath());
$baseName = basename($fileEntity->getPath());

Storage::disk(config('filesystems.default'))
->putFileAs(
$directory,
$file,
$baseName
);
}

private function checkIfFileWasSaved(FileEntity $fileEntity): void
{
$fileExists = Storage::disk(config('filesystems.default'))->exists($fileEntity->getPath());
if (!$fileExists) {
throw new Exception(
message: 'File not found in storage',
code: ResponseStatus::INTERNAL_SERVER_ERROR->value
);
}
$fileEntity->confirmUpload();
$this->fileProjectCommand->confirmUploadFile($fileEntity);
}
}
5 changes: 5 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use App\Http\Controllers\V1\Project\CreateProjectController;
use App\Http\Controllers\V1\Project\UpdateProjectController;
use App\Http\Controllers\V1\Project\UploadProjectFileController;
use App\Http\Controllers\V1\User\ChangeUserRoleController;
use App\Http\Controllers\V1\User\CreateUserController;
use App\Http\Controllers\V1\User\ShowUserController;
Expand Down Expand Up @@ -37,6 +38,10 @@
Route::put('/update/{uuid}', [UpdateProjectController::class, '__invoke'])
->whereUuid('uuid')
->name('api.v1.project.update');
//create a route for upload file
Route::post('/{uuid}/upload-file', [UploadProjectFileController::class, '__invoke'])
->whereUuid('uuid')
->name('api.v1.project.upload-file');
});
});

Expand Down
Loading

0 comments on commit a068730

Please sign in to comment.