From 0d08280445476c9f6cdb4fde5e1b636c9e4b3b29 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 24 Feb 2022 05:58:01 -0700 Subject: [PATCH 01/12] =?UTF-8?q?=E2=9B=B2=20feat=20Support=20for=20Docume?= =?UTF-8?q?nt=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created Document model - Document.sql to create the actual table - DocumentController to establish routes and actions - A few actions created: - DocumentGetAction - DocumentUpdateAction - DocumentUploadAction - DocumentUploadValidator created - ResponseBodyFactory now includes file uploads [unrelated] - Pin.sql removed - phpcs.xml updated to enforce Line Length to 120 --- .../Document/DocumentController.php | 23 +++++++ .../Document/DocumentGetAction.php | 18 ++++++ .../Document/DocumentUpdateAction.php | 18 ++++++ .../Document/DocumentUploadAction.php | 58 ++++++++++++++++++ .../Document/DocumentUploadValidator.php | 61 +++++++++++++++++++ app/Middleware/RegisterRouteControllers.php | 17 +++--- app/Middleware/ResponseBodyFactory.php | 3 +- app/Models/Document.php | 37 +++++++++++ composer.json | 3 +- phpcs.xml | 8 +++ sql/Document.sql | 18 ++++++ sql/Pin.sql | 16 ----- 12 files changed, 254 insertions(+), 26 deletions(-) create mode 100644 app/Controllers/Document/DocumentController.php create mode 100644 app/Controllers/Document/DocumentGetAction.php create mode 100644 app/Controllers/Document/DocumentUpdateAction.php create mode 100644 app/Controllers/Document/DocumentUploadAction.php create mode 100644 app/Controllers/Document/DocumentUploadValidator.php create mode 100644 app/Models/Document.php create mode 100644 sql/Document.sql delete mode 100644 sql/Pin.sql diff --git a/app/Controllers/Document/DocumentController.php b/app/Controllers/Document/DocumentController.php new file mode 100644 index 0000000..9dfcc70 --- /dev/null +++ b/app/Controllers/Document/DocumentController.php @@ -0,0 +1,23 @@ +post('/document/upload/{client_id}', DocumentUploadAction::class) + ->add(DocumentUploadValidator::class); + + $group->get('/document/{id}', DocumentGetAction::class); + + $group->post('/document', DocumentUpdateAction::class); + } +} diff --git a/app/Controllers/Document/DocumentGetAction.php b/app/Controllers/Document/DocumentGetAction.php new file mode 100644 index 0000000..c6585a9 --- /dev/null +++ b/app/Controllers/Document/DocumentGetAction.php @@ -0,0 +1,18 @@ +model = $model; + } +} diff --git a/app/Controllers/Document/DocumentUpdateAction.php b/app/Controllers/Document/DocumentUpdateAction.php new file mode 100644 index 0000000..0d450a7 --- /dev/null +++ b/app/Controllers/Document/DocumentUpdateAction.php @@ -0,0 +1,18 @@ +model = $model; + } +} diff --git a/app/Controllers/Document/DocumentUploadAction.php b/app/Controllers/Document/DocumentUploadAction.php new file mode 100644 index 0000000..aea63c6 --- /dev/null +++ b/app/Controllers/Document/DocumentUploadAction.php @@ -0,0 +1,58 @@ +getAttribute('response_body'); + $parsedRequest = $responseBody->getParsedRequest(); + /** @var $files UploadedFileInterface[] */ + $files = $parsedRequest['uploaded_files']; + $file = $files['single_file']; + $clientId = $parsedRequest['client_id']; + + $document = clone $this->document; + $document->ResidentId = $clientId; + $document->Size = $file->getSize(); + $document->FileName = $file->getClientFilename() ?? 'unknown'; + $document->MediaType = $file->getClientMediaType(); + $document->Image = $file->getStream()->getContents(); + if ($document->save()) { + $responseBody = $responseBody->setData( + [ + 'Id' => $document->Id, + 'Size' => $document->Size, + 'FileName' => $document->FileName, + 'Type' => $document->MediaType + ] + )->setStatus(ResponseCodes::HTTP_OK); + return $responseBody(); + } + + $responseBody = $responseBody + ->setData(null) + ->setStatus(ResponseCodes::HTTP_INTERNAL_SERVER_ERROR) + ->setMessage('Unable to save file'); + return $responseBody(); + } +} diff --git a/app/Controllers/Document/DocumentUploadValidator.php b/app/Controllers/Document/DocumentUploadValidator.php new file mode 100644 index 0000000..e696fbb --- /dev/null +++ b/app/Controllers/Document/DocumentUploadValidator.php @@ -0,0 +1,61 @@ +getAttribute('response_body'); + $parsedRequest = $responseBody->getParsedRequest(); + /** @var $files UploadedFileInterface[] */ + $files = $parsedRequest['uploaded_files'] ?? []; + + // Only 1 file uploaded + if (count($files) !== 1) { + $responseBody->registerParam('required', 'uploaded_files', 'array', 'There must be only one uploaded file'); + } + + // File is hard coded as 'single_file' + $file = $files['single_file'] ?? null; + + // The single_file array element label is required + if ($file === null) { + $responseBody->registerParam('required', 'single_file', 'file', 'File must be labeled as single_file'); + } + + // File size must be under 100MB + if ($file && $file->getSize() > 104_857_600) { + $responseBody->registerParam('invalid', 'single_file', 'file', 'File size exceeds maximum allowed'); + } + + // client_id is required + $clientId = $parsedRequest['client_id'] ?? null; + if ($clientId === null) { + $responseBody->registerParam('required', 'client_id', 'integer', 'client_id is empty or invalid'); + } + + // If there are any invalid or missing required then send bad request response + if ($responseBody->hasMissingRequiredOrInvalid()) { + $responseBody = $responseBody->setData(null)->setStatus(ResponseCodes::HTTP_BAD_REQUEST); + return $responseBody(); + } + + return $handler->handle($request); + } +} diff --git a/app/Middleware/RegisterRouteControllers.php b/app/Middleware/RegisterRouteControllers.php index 0bda509..698428b 100644 --- a/app/Middleware/RegisterRouteControllers.php +++ b/app/Middleware/RegisterRouteControllers.php @@ -11,29 +11,32 @@ use Willow\Controllers\PillboxItem\PillboxItemController; use Willow\Controllers\Pin\PinController; use Willow\Controllers\Resident\ResidentController; +use Willow\Controllers\Document\DocumentController; class RegisterRouteControllers { public function __construct( private AuthenticateController $authenticateController, - private MedHistoryController $medHistoryController, - private MedicineController $medicineController, - private PillboxController $pillboxController, - private PillboxItemController $pillboxItemController, - private ResidentController $residentController, - private PinController $pinController + private DocumentController $documentController, + private MedHistoryController $medHistoryController, + private MedicineController $medicineController, + private PillboxController $pillboxController, + private PillboxItemController $pillboxItemController, + private PinController $pinController, + private ResidentController $residentController ) { } public function __invoke(RouteCollectorProxy $collectorProxy): self { // Register routes and actions for each controller $this->authenticateController->register($collectorProxy); + $this->documentController->register($collectorProxy); $this->medHistoryController->register($collectorProxy); $this->medicineController->register($collectorProxy); $this->pillboxController->register($collectorProxy); $this->pillboxItemController->register($collectorProxy); - $this->residentController->register($collectorProxy); $this->pinController->register($collectorProxy); + $this->residentController->register($collectorProxy); return $this; } } diff --git a/app/Middleware/ResponseBodyFactory.php b/app/Middleware/ResponseBodyFactory.php index 2ffa31e..8d2a812 100644 --- a/app/Middleware/ResponseBodyFactory.php +++ b/app/Middleware/ResponseBodyFactory.php @@ -28,7 +28,8 @@ public function __invoke(Request $request, RequestHandler $handler): ResponseInt array_merge( $arguments, $request->getQueryParams(), - $request->getParsedBody() ?? [] + $request->getParsedBody() ?? [], + ['uploaded_files' => $request->getUploadedFiles()] ) ) ) diff --git a/app/Models/Document.php b/app/Models/Document.php new file mode 100644 index 0000000..83ac3a9 --- /dev/null +++ b/app/Models/Document.php @@ -0,0 +1,37 @@ + + + + + + + + + diff --git a/sql/Document.sql b/sql/Document.sql new file mode 100644 index 0000000..c2f0f20 --- /dev/null +++ b/sql/Document.sql @@ -0,0 +1,18 @@ +CREATE TABLE `Document` ( + `Id` int NOT NULL AUTO_INCREMENT, + `ResidentId` int NOT NULL, + `UserId` int NOT NULL, + `FileName` varchar(65) NOT NULL, + `MediaType` varchar(65) NULL DEFAULT NULL, + `Size` int NULL DEFAULT NULL, + `Description` varchar(100) NULL DEFAULT NULL, + `Image` longblob, + `Created` timestamp NULL DEFAULT NULL, + `Updated` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`Id`), + KEY `fk_Document_User` (`UserId`), + KEY `fk_Document_Resident` (`ResidentId`), + CONSTRAINT `fk_Document_Resident` FOREIGN KEY (`ResidentId`) REFERENCES `Resident` (`Id`), + CONSTRAINT `fk_Document_User` FOREIGN KEY (`UserId`) REFERENCES `User` (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; diff --git a/sql/Pin.sql b/sql/Pin.sql deleted file mode 100644 index a3719cf..0000000 --- a/sql/Pin.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE `Pin` ( - `Id` int NOT NULL AUTO_INCREMENT, - `ResidentId` int NOT NULL, - `UserId` int NOT NULL, - `PinValue` char(6) NOT NULL, - `Image` longblob, - `Created` timestamp NULL DEFAULT NULL, - `Updated` timestamp NULL DEFAULT NULL, - `deleted_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`Id`), - UNIQUE KEY `unique_pin` (`ResidentId`,`UserId`,`PinValue`), - KEY `fk_Pin_User` (`UserId`), - KEY `fk_Pin_Resident` (`ResidentId`), - CONSTRAINT `fk_Pin_Resident` FOREIGN KEY (`ResidentId`) REFERENCES `Resident` (`Id`), - CONSTRAINT `fk_Pin_User` FOREIGN KEY (`UserId`) REFERENCES `User` (`Id`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; From c0b12f156e58d3a84ba939d573172a592e4fba6c Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 24 Feb 2022 10:44:07 -0700 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9B=B2=20feat=20More=20request=20Valid?= =?UTF-8?q?ations=20added=20in=20DocumentUploadValidator=20and=20phpstan?= =?UTF-8?q?=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Validate `client_id` is an integer type and value and exists [unrelated] - phpstan kept throwing false positives when using: `/** @var $files UploadedFileInterface[] */` so an ignored line comment was added - phpstan `Willow\Models\Document` was added to `universalObjectCratesClasses:` in phpstan.neon --- .../Document/DocumentUploadAction.php | 11 ++++++++--- .../Document/DocumentUploadValidator.php | 17 +++++++++++++---- phpstan.neon | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/Controllers/Document/DocumentUploadAction.php b/app/Controllers/Document/DocumentUploadAction.php index aea63c6..6fc7340 100644 --- a/app/Controllers/Document/DocumentUploadAction.php +++ b/app/Controllers/Document/DocumentUploadAction.php @@ -12,8 +12,7 @@ class DocumentUploadAction { - public function __construct(private Document $document) - { + public function __construct(private Document $document) { } /** @@ -25,9 +24,15 @@ public function __construct(private Document $document) public function __invoke(Request $request, Response $response): ResponseInterface { /** @var ResponseBody $responseBody */ $responseBody = $request->getAttribute('response_body'); + $parsedRequest = $responseBody->getParsedRequest(); - /** @var $files UploadedFileInterface[] */ + + /** + * @var $files UploadedFileInterface[] + * @phpstan-ignore-next-line + */ $files = $parsedRequest['uploaded_files']; + $file = $files['single_file']; $clientId = $parsedRequest['client_id']; diff --git a/app/Controllers/Document/DocumentUploadValidator.php b/app/Controllers/Document/DocumentUploadValidator.php index e696fbb..f9c55f3 100644 --- a/app/Controllers/Document/DocumentUploadValidator.php +++ b/app/Controllers/Document/DocumentUploadValidator.php @@ -10,6 +10,7 @@ use Willow\Middleware\ResponseBody; use Willow\Middleware\ResponseCodes; use JsonException; +use Respect\Validation\Validator as V; class DocumentUploadValidator { @@ -23,10 +24,14 @@ public function __invoke(Request $request, RequestHandler $handler): ResponseInt /** @var ResponseBody $responseBody */ $responseBody = $request->getAttribute('response_body'); $parsedRequest = $responseBody->getParsedRequest(); - /** @var $files UploadedFileInterface[] */ + + /** + * @var $files UploadedFileInterface[] + * @phpstan-ignore-next-line + */ $files = $parsedRequest['uploaded_files'] ?? []; - // Only 1 file uploaded + // Only 1 file allowed to be uploaded if (count($files) !== 1) { $responseBody->registerParam('required', 'uploaded_files', 'array', 'There must be only one uploaded file'); } @@ -44,10 +49,14 @@ public function __invoke(Request $request, RequestHandler $handler): ResponseInt $responseBody->registerParam('invalid', 'single_file', 'file', 'File size exceeds maximum allowed'); } - // client_id is required + // client_id is required and must be an integer $clientId = $parsedRequest['client_id'] ?? null; - if ($clientId === null) { + if (!V::notEmpty()->validate($clientId)) { $responseBody->registerParam('required', 'client_id', 'integer', 'client_id is empty or invalid'); + } else { + if (!V::intType()->intVal()->validate($clientId)) { + $responseBody->registerParam('invalid', 'client_id', 'integer'); + } } // If there are any invalid or missing required then send bad request response diff --git a/phpstan.neon b/phpstan.neon index 7c1ebcb..50d7b3a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -21,3 +21,4 @@ parameters: universalObjectCratesClasses: - Willow\Models\Pin + - Willow\Models\Document From b66b0a3b2d1aac877687175950972cc49bc9c7ab Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 24 Feb 2022 11:44:32 -0700 Subject: [PATCH 03/12] =?UTF-8?q?=E2=9B=B2=20feat=20Remove=20the=20need=20?= =?UTF-8?q?for=20a=20phpstan.neon=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - See: https://stackoverflow.com/a/53758840/4323201 - Model representation classes added for Document, MedHistory, PillboxItem, and Pin models - phpstan.neon file is now just a placeholder since no exceptions need to exist - Actually discovered a 🐛 in PinGenerateAction.php where the `PinValue` field is expecting a string and an integer was being given --- .../Document/DocumentUploadAction.php | 2 ++ app/Controllers/Pillbox/PillboxLogAction.php | 7 ++++- app/Controllers/Pin/PinGenerateAction.php | 4 ++- app/Models/Document.php | 8 ++--- app/Models/DocumentRepresentation.php | 21 +++++++++++++ app/Models/MedHistoryRepresentation.php | 21 +++++++++++++ app/Models/PillboxItemRepresentation.php | 30 +++++++++++++++++++ app/Models/PinRepresentation.php | 18 +++++++++++ phpstan.neon | 25 +--------------- 9 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 app/Models/DocumentRepresentation.php create mode 100644 app/Models/MedHistoryRepresentation.php create mode 100644 app/Models/PillboxItemRepresentation.php create mode 100644 app/Models/PinRepresentation.php diff --git a/app/Controllers/Document/DocumentUploadAction.php b/app/Controllers/Document/DocumentUploadAction.php index 6fc7340..32fb15c 100644 --- a/app/Controllers/Document/DocumentUploadAction.php +++ b/app/Controllers/Document/DocumentUploadAction.php @@ -9,6 +9,7 @@ use Willow\Middleware\ResponseBody; use Willow\Middleware\ResponseCodes; use Willow\Models\Document; +use Willow\Models\DocumentRepresentation; class DocumentUploadAction { @@ -36,6 +37,7 @@ public function __invoke(Request $request, Response $response): ResponseInterfac $file = $files['single_file']; $clientId = $parsedRequest['client_id']; + /** @var Document|DocumentRepresentation $document */ $document = clone $this->document; $document->ResidentId = $clientId; $document->Size = $file->getSize(); diff --git a/app/Controllers/Pillbox/PillboxLogAction.php b/app/Controllers/Pillbox/PillboxLogAction.php index 62e35e7..fd97dc8 100644 --- a/app/Controllers/Pillbox/PillboxLogAction.php +++ b/app/Controllers/Pillbox/PillboxLogAction.php @@ -10,8 +10,10 @@ use Willow\Middleware\ResponseBody; use Willow\Middleware\ResponseCodes; use Willow\Models\MedHistory; +use Willow\Models\MedHistoryRepresentation; use Willow\Models\Medicine; use Willow\Models\PillboxItem; +use Willow\Models\PillboxItemRepresentation; class PillboxLogAction { @@ -36,7 +38,7 @@ public function __invoke(Request $request, Response $response): ResponseInterfac $pillboxId = $body['pillbox_id']; // Pillbox PK /** - * @var PillboxItem[] $pillboxItems + * @var PillboxItem[]|PillboxItemRepresentation[] $pillboxItems * Get a collection of PillboxItems for the given pillboxId */ $pillboxItems = $this->pillboxItem->where('PillboxId', '=', $pillboxId)->get(); @@ -54,6 +56,9 @@ public function __invoke(Request $request, Response $response): ResponseInterfac $medicineModel = $this->medicine->find($medicineId); // We only log active medications if ($medicineModel && $medicineModel->Active) { + /** + * @var MedHistoryRepresentation|MedHistory $medHistoryModel + */ $medHistoryModel = clone $this->medHistory; $medHistoryModel->PillboxItemId = $id; $medHistoryModel->ResidentId = $pillboxItem->ResidentId; diff --git a/app/Controllers/Pin/PinGenerateAction.php b/app/Controllers/Pin/PinGenerateAction.php index a1186eb..0834e01 100644 --- a/app/Controllers/Pin/PinGenerateAction.php +++ b/app/Controllers/Pin/PinGenerateAction.php @@ -11,6 +11,7 @@ use Willow\Middleware\ResponseBody; use Willow\Middleware\ResponseCodes; use Willow\Models\Pin; +use Willow\Models\PinRepresentation; class PinGenerateAction { @@ -38,9 +39,10 @@ public function __invoke(Request $request, Response $response, array $args): Res $parsedRequest = $responseBody->getParsedRequest(); $clientId = $parsedRequest['client_id']; + /** @var Pin|PinRepresentation $pinModel */ $pinModel = clone $this->pin; do { - $pinValue = random_int(10 ** (self::DIGIT_COUNT - 1), (10 ** self::DIGIT_COUNT) -1); + $pinValue = (string)random_int(10 ** (self::DIGIT_COUNT - 1), (10 ** self::DIGIT_COUNT) -1); $pinExists = $this->pin ->where('ResidentId', '=', $clientId) ->where('PinValue', '=', $pinValue) diff --git a/app/Models/Document.php b/app/Models/Document.php index 83ac3a9..e007a62 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -18,12 +18,12 @@ #[ApplyModelColumnAttribute('Updated', 'DateTime', null, ['CE'], 'NULL')] #[ApplyModelColumnAttribute('deleted_at', 'DateTime', null, ['CE'], 'NULL')] /** - * @property integer $Id // Primary Key - * @property string $ResidentId // Resident FK - * @property string $UserId // User FK + * @property int $Id // Primary Key + * @property int $ResidentId // Resident FK + * @property int $UserId // User FK * @property string $FileName // The file name including the extention * @property string $MediaType // The mime type - * @property integer $Size // Size of the file in bytes + * @property int $Size // Size of the file in bytes * @property string $Description // A description of the file * @property string $Image // File image as a blob * @property DateTime $Created diff --git a/app/Models/DocumentRepresentation.php b/app/Models/DocumentRepresentation.php new file mode 100644 index 0000000..fb83018 --- /dev/null +++ b/app/Models/DocumentRepresentation.php @@ -0,0 +1,21 @@ + Date: Fri, 25 Feb 2022 03:10:48 -0700 Subject: [PATCH 04/12] =?UTF-8?q?=E2=9B=B2=20feat=20Added=20`uploaded=5Ffi?= =?UTF-8?q?les`=20as=20an=20allowed=20parameter=20key=20to=20several=20mod?= =?UTF-8?q?ules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuthenticatePostValidator.php - ModelDefaultRules.php - PinAuthenticateValidator.php - SearchValidatorBase.php --- app/Controllers/Authenticate/AuthenticatePostValidator.php | 4 ++-- app/Controllers/Pin/PinAuthenticateValidator.php | 2 +- app/Controllers/SearchValidatorBase.php | 1 + app/Models/ModelDefaultRules.php | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Controllers/Authenticate/AuthenticatePostValidator.php b/app/Controllers/Authenticate/AuthenticatePostValidator.php index d69fe04..9e64391 100644 --- a/app/Controllers/Authenticate/AuthenticatePostValidator.php +++ b/app/Controllers/Authenticate/AuthenticatePostValidator.php @@ -13,7 +13,7 @@ class AuthenticatePostValidator { - private const ALLOWED = ['username', 'password', 'id']; + private const ALLOWED = ['username', 'password', 'id', 'uploaded_files']; /** * @throws JsonException @@ -40,7 +40,7 @@ public function __invoke(Request $request, RequestHandler $handler): ResponseInt } // id can be part of the request, but it MUST be null/empty - if (V::exists()->validate($parsedRequest['id']) && V::notEmpty()->validate($parsedRequest['id'])) { + if (V::key('id')->validate($parsedRequest) && V::notEmpty()->validate($parsedRequest['id'])) { $responseBody->registerParam('invalid', 'id', 'null'); } diff --git a/app/Controllers/Pin/PinAuthenticateValidator.php b/app/Controllers/Pin/PinAuthenticateValidator.php index f816995..3425974 100644 --- a/app/Controllers/Pin/PinAuthenticateValidator.php +++ b/app/Controllers/Pin/PinAuthenticateValidator.php @@ -13,7 +13,7 @@ class PinAuthenticateValidator { - private const ALLOWED = ['pin_value']; + private const ALLOWED = ['pin_value', 'uploaded_files']; /** * @throws JsonException diff --git a/app/Controllers/SearchValidatorBase.php b/app/Controllers/SearchValidatorBase.php index 81ee733..7f59626 100644 --- a/app/Controllers/SearchValidatorBase.php +++ b/app/Controllers/SearchValidatorBase.php @@ -15,6 +15,7 @@ class SearchValidatorBase extends ActionBase private const ALLOWED_PARAMETER_KEYS = [ 'api_key', 'id', + 'uploaded_files', 'crossJoin', 'distinct', 'first', diff --git a/app/Models/ModelDefaultRules.php b/app/Models/ModelDefaultRules.php index 69512a7..ba056dd 100644 --- a/app/Models/ModelDefaultRules.php +++ b/app/Models/ModelDefaultRules.php @@ -10,7 +10,7 @@ class ModelDefaultRules /** * Allowed request parameters that are not column names */ - private const WHITE_LIST = ['id', 'api_key']; + private const WHITE_LIST = ['id', 'api_key', 'uploaded_files']; /** * @param ResponseBody $responseBody From b5dc557a3b986f9ce886f86247c9122021edff05 Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 2 Mar 2022 05:22:07 -0700 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=8C=80=20refactor=20Since=20`docume?= =?UTF-8?q?nt`=20is=20a=20reserved=20word=20in=20JS=20(duh)=20=F0=9F=A4=A6?= =?UTF-8?q?=20Changed=20everything=20to=20`File`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Document/DocumentController.php | 23 -------- .../Document/DocumentGetAction.php | 18 ------ .../Document/DocumentUpdateAction.php | 18 ------ app/Controllers/File/FIleUpdateAction.php | 18 ++++++ app/Controllers/File/FileController.php | 27 +++++++++ app/Controllers/File/FileDeleteAction.php | 18 ++++++ app/Controllers/File/FileGetAction.php | 18 ++++++ app/Controllers/File/FileLoadAction.php | 58 +++++++++++++++++++ .../FileUploadAction.php} | 14 ++--- .../FileValidator.php} | 8 +-- app/Controllers/Resident/ClientLoadAction.php | 17 ++++-- app/Middleware/RegisterRouteControllers.php | 6 +- app/Models/{Document.php => File.php} | 4 +- ...resentation.php => FileRepresentation.php} | 2 +- sql/Document.sql | 18 ------ sql/File.sql | 18 ++++++ 16 files changed, 186 insertions(+), 99 deletions(-) delete mode 100644 app/Controllers/Document/DocumentController.php delete mode 100644 app/Controllers/Document/DocumentGetAction.php delete mode 100644 app/Controllers/Document/DocumentUpdateAction.php create mode 100644 app/Controllers/File/FIleUpdateAction.php create mode 100644 app/Controllers/File/FileController.php create mode 100644 app/Controllers/File/FileDeleteAction.php create mode 100644 app/Controllers/File/FileGetAction.php create mode 100644 app/Controllers/File/FileLoadAction.php rename app/Controllers/{Document/DocumentUploadAction.php => File/FileUploadAction.php} (85%) rename app/Controllers/{Document/DocumentUploadValidator.php => File/FileValidator.php} (93%) rename app/Models/{Document.php => File.php} (95%) rename app/Models/{DocumentRepresentation.php => FileRepresentation.php} (95%) delete mode 100644 sql/Document.sql create mode 100644 sql/File.sql diff --git a/app/Controllers/Document/DocumentController.php b/app/Controllers/Document/DocumentController.php deleted file mode 100644 index 9dfcc70..0000000 --- a/app/Controllers/Document/DocumentController.php +++ /dev/null @@ -1,23 +0,0 @@ -post('/document/upload/{client_id}', DocumentUploadAction::class) - ->add(DocumentUploadValidator::class); - - $group->get('/document/{id}', DocumentGetAction::class); - - $group->post('/document', DocumentUpdateAction::class); - } -} diff --git a/app/Controllers/Document/DocumentGetAction.php b/app/Controllers/Document/DocumentGetAction.php deleted file mode 100644 index c6585a9..0000000 --- a/app/Controllers/Document/DocumentGetAction.php +++ /dev/null @@ -1,18 +0,0 @@ -model = $model; - } -} diff --git a/app/Controllers/Document/DocumentUpdateAction.php b/app/Controllers/Document/DocumentUpdateAction.php deleted file mode 100644 index 0d450a7..0000000 --- a/app/Controllers/Document/DocumentUpdateAction.php +++ /dev/null @@ -1,18 +0,0 @@ -model = $model; - } -} diff --git a/app/Controllers/File/FIleUpdateAction.php b/app/Controllers/File/FIleUpdateAction.php new file mode 100644 index 0000000..e225482 --- /dev/null +++ b/app/Controllers/File/FIleUpdateAction.php @@ -0,0 +1,18 @@ +model = $model; + } +} diff --git a/app/Controllers/File/FileController.php b/app/Controllers/File/FileController.php new file mode 100644 index 0000000..0f6aa67 --- /dev/null +++ b/app/Controllers/File/FileController.php @@ -0,0 +1,27 @@ +post('/file/upload/{client_id}', FileUploadAction::class) + ->add(FileValidator::class); + + $group->get('/file/{id}', FileGetAction::class); + + $group->post('/file', FIleUpdateAction::class); + + $group->delete('/file/{id}', FileDeleteAction::class); + + $group->get('/file/load/{client_id}', FileLoadAction::class); + } +} diff --git a/app/Controllers/File/FileDeleteAction.php b/app/Controllers/File/FileDeleteAction.php new file mode 100644 index 0000000..479c8ae --- /dev/null +++ b/app/Controllers/File/FileDeleteAction.php @@ -0,0 +1,18 @@ +model = $model; + } +} diff --git a/app/Controllers/File/FileGetAction.php b/app/Controllers/File/FileGetAction.php new file mode 100644 index 0000000..a554fe0 --- /dev/null +++ b/app/Controllers/File/FileGetAction.php @@ -0,0 +1,18 @@ +model = $model; + } +} diff --git a/app/Controllers/File/FileLoadAction.php b/app/Controllers/File/FileLoadAction.php new file mode 100644 index 0000000..ec5074a --- /dev/null +++ b/app/Controllers/File/FileLoadAction.php @@ -0,0 +1,58 @@ +getAttribute('response_body'); + + // Load all models for the given client_id + $document = $this->document->clone(); + $documents = $document + ->where('ResidentId', '=', $args['client_id']) + ->get(['Id', 'ResidentId', 'FileName','MediaType', 'Size', 'Created', 'Updated']); + + // If the record is not found then 404 error, otherwise status is 200. + if ($documents !== null && count($documents) > 0) { + $data = $documents->toArray(); + $status = ResponseCodes::HTTP_OK; + } else { + $data = null; + $status = ResponseCodes::HTTP_NOT_FOUND; + } + + // Set the status and data of the ResponseBody + $responseBody = $responseBody + ->setData($data) + ->setStatus($status); + + // Return the response as JSON + return $responseBody(); + } +} diff --git a/app/Controllers/Document/DocumentUploadAction.php b/app/Controllers/File/FileUploadAction.php similarity index 85% rename from app/Controllers/Document/DocumentUploadAction.php rename to app/Controllers/File/FileUploadAction.php index 32fb15c..8cacb4f 100644 --- a/app/Controllers/Document/DocumentUploadAction.php +++ b/app/Controllers/File/FileUploadAction.php @@ -1,5 +1,5 @@ document; + /** @var File|FileRepresentation $document */ + $document = clone $this->file; $document->ResidentId = $clientId; $document->Size = $file->getSize(); $document->FileName = $file->getClientFilename() ?? 'unknown'; diff --git a/app/Controllers/Document/DocumentUploadValidator.php b/app/Controllers/File/FileValidator.php similarity index 93% rename from app/Controllers/Document/DocumentUploadValidator.php rename to app/Controllers/File/FileValidator.php index f9c55f3..16f3a3f 100644 --- a/app/Controllers/Document/DocumentUploadValidator.php +++ b/app/Controllers/File/FileValidator.php @@ -1,7 +1,7 @@ validate($clientId)) { $responseBody->registerParam('required', 'client_id', 'integer', 'client_id is empty or invalid'); } else { - if (!V::intType()->intVal()->validate($clientId)) { - $responseBody->registerParam('invalid', 'client_id', 'integer'); + if (!V::intVal()->validate($clientId)) { + $responseBody->registerParam('invalid', 'client_id', 'integer', 'client_id must be an integer'); } } diff --git a/app/Controllers/Resident/ClientLoadAction.php b/app/Controllers/Resident/ClientLoadAction.php index 0ab324d..87e155f 100644 --- a/app/Controllers/Resident/ClientLoadAction.php +++ b/app/Controllers/Resident/ClientLoadAction.php @@ -10,6 +10,7 @@ use Slim\Psr7\Response; use Willow\Middleware\ResponseBody; use Willow\Middleware\ResponseCodes; +use Willow\Models\File; use Willow\Models\MedHistory; use Willow\Models\Medicine; use Willow\Models\Pillbox; @@ -19,11 +20,12 @@ class ClientLoadAction { public function __construct( - private Resident $client, - private Medicine $medicine, - private MedHistory $medHistory, - private Pillbox $pillbox, - private PillboxItem $pillboxItem + private File $file, + private MedHistory $medHistory, + private Medicine $medicine, + private Pillbox $pillbox, + private PillboxItem $pillboxItem, + private Resident $client ) { } @@ -49,6 +51,11 @@ public function __invoke(Request $request, Response $response, array $args): Res $status = ResponseCodes::HTTP_OK; $data = [ 'clientInfo' => $client->attributesToArray(), + 'fileList' => $this->file + ->where('ResidentId', '=', $clientId) + ->orderBy('Updated', 'asc') + ->get(['Id', 'ResidentId', 'FileName','MediaType', 'Size', 'Created', 'Updated']) + ->toArray(), 'medicineList' => $this->medicine ->where('ResidentId', '=', $clientId) ->orderBy('Drug', 'asc') diff --git a/app/Middleware/RegisterRouteControllers.php b/app/Middleware/RegisterRouteControllers.php index 698428b..3226102 100644 --- a/app/Middleware/RegisterRouteControllers.php +++ b/app/Middleware/RegisterRouteControllers.php @@ -11,13 +11,13 @@ use Willow\Controllers\PillboxItem\PillboxItemController; use Willow\Controllers\Pin\PinController; use Willow\Controllers\Resident\ResidentController; -use Willow\Controllers\Document\DocumentController; +use Willow\Controllers\File\FileController; class RegisterRouteControllers { public function __construct( private AuthenticateController $authenticateController, - private DocumentController $documentController, + private FileController $fileController, private MedHistoryController $medHistoryController, private MedicineController $medicineController, private PillboxController $pillboxController, @@ -30,7 +30,7 @@ public function __construct( public function __invoke(RouteCollectorProxy $collectorProxy): self { // Register routes and actions for each controller $this->authenticateController->register($collectorProxy); - $this->documentController->register($collectorProxy); + $this->fileController->register($collectorProxy); $this->medHistoryController->register($collectorProxy); $this->medicineController->register($collectorProxy); $this->pillboxController->register($collectorProxy); diff --git a/app/Models/Document.php b/app/Models/File.php similarity index 95% rename from app/Models/Document.php rename to app/Models/File.php index e007a62..0cde82c 100644 --- a/app/Models/Document.php +++ b/app/Models/File.php @@ -30,8 +30,8 @@ * @property DateTime $Updated * @property DateTime $deleted_at */ -class Document extends ModelBase +class File extends ModelBase { - protected $table = 'Document'; + protected $table = 'File'; } diff --git a/app/Models/DocumentRepresentation.php b/app/Models/FileRepresentation.php similarity index 95% rename from app/Models/DocumentRepresentation.php rename to app/Models/FileRepresentation.php index fb83018..03416fe 100644 --- a/app/Models/DocumentRepresentation.php +++ b/app/Models/FileRepresentation.php @@ -5,7 +5,7 @@ use DateTime; -class DocumentRepresentation +class FileRepresentation { public int $Id; // Primary Key public int $ResidentId; // Resident FK diff --git a/sql/Document.sql b/sql/Document.sql deleted file mode 100644 index c2f0f20..0000000 --- a/sql/Document.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE `Document` ( - `Id` int NOT NULL AUTO_INCREMENT, - `ResidentId` int NOT NULL, - `UserId` int NOT NULL, - `FileName` varchar(65) NOT NULL, - `MediaType` varchar(65) NULL DEFAULT NULL, - `Size` int NULL DEFAULT NULL, - `Description` varchar(100) NULL DEFAULT NULL, - `Image` longblob, - `Created` timestamp NULL DEFAULT NULL, - `Updated` timestamp NULL DEFAULT NULL, - `deleted_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`Id`), - KEY `fk_Document_User` (`UserId`), - KEY `fk_Document_Resident` (`ResidentId`), - CONSTRAINT `fk_Document_Resident` FOREIGN KEY (`ResidentId`) REFERENCES `Resident` (`Id`), - CONSTRAINT `fk_Document_User` FOREIGN KEY (`UserId`) REFERENCES `User` (`Id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; diff --git a/sql/File.sql b/sql/File.sql new file mode 100644 index 0000000..38eeea1 --- /dev/null +++ b/sql/File.sql @@ -0,0 +1,18 @@ +CREATE TABLE `File` ( + `Id` int NOT NULL AUTO_INCREMENT, + `ResidentId` int NOT NULL, + `UserId` int NOT NULL, + `FileName` varchar(65) NOT NULL, + `MediaType` varchar(65) DEFAULT NULL, + `Size` int DEFAULT NULL, + `Description` varchar(100) DEFAULT NULL, + `Image` longblob, + `Created` timestamp NULL DEFAULT NULL, + `Updated` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`Id`), + KEY `fk_File_User_idx` (`UserId`), + KEY `fk_File_Resident_idx` (`ResidentId`), + CONSTRAINT `fk_File_Resident` FOREIGN KEY (`ResidentId`) REFERENCES `Resident` (`Id`), + CONSTRAINT `fk_File_User` FOREIGN KEY (`UserId`) REFERENCES `User` (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; From 633315e62b63ce4e0f75b31b322caf42ef5a3942 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 3 Mar 2022 05:24:13 -0700 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=8C=80=20refactor=20Changed=20some?= =?UTF-8?q?=20names=20of=20files=20to=20be=20standard=20and=20made=20the?= =?UTF-8?q?=20`File.Image`=20hidden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/File/FileController.php | 2 +- app/Controllers/File/FileLoadAction.php | 11 ++++++----- .../{FIleUpdateAction.php => FileUpdateAction.php} | 2 +- app/Controllers/Resident/ClientLoadAction.php | 2 +- app/Models/File.php | 3 ++- 5 files changed, 11 insertions(+), 9 deletions(-) rename app/Controllers/File/{FIleUpdateAction.php => FileUpdateAction.php} (86%) diff --git a/app/Controllers/File/FileController.php b/app/Controllers/File/FileController.php index 0f6aa67..a593060 100644 --- a/app/Controllers/File/FileController.php +++ b/app/Controllers/File/FileController.php @@ -18,7 +18,7 @@ final public function register(RouteCollectorProxyInterface $group): void { $group->get('/file/{id}', FileGetAction::class); - $group->post('/file', FIleUpdateAction::class); + $group->post('/file', FileUpdateAction::class); $group->delete('/file/{id}', FileDeleteAction::class); diff --git a/app/Controllers/File/FileLoadAction.php b/app/Controllers/File/FileLoadAction.php index ec5074a..189309c 100644 --- a/app/Controllers/File/FileLoadAction.php +++ b/app/Controllers/File/FileLoadAction.php @@ -14,10 +14,10 @@ class FileLoadAction { /** - * FileGetAction constructor. - * @param File $document + * FileLoadAction - helper action to quickly rehydrate just the File records for a client + * @param File $file File model */ - public function __construct(private File $document) { + public function __construct(private File $file) { } /** @@ -33,9 +33,10 @@ public function __invoke(Request $request, Response $response, array $args): Res $responseBody = $request->getAttribute('response_body'); // Load all models for the given client_id - $document = $this->document->clone(); - $documents = $document + $file = $this->file->clone(); + $documents = $file ->where('ResidentId', '=', $args['client_id']) + ->orderBy('Updated', 'desc') ->get(['Id', 'ResidentId', 'FileName','MediaType', 'Size', 'Created', 'Updated']); // If the record is not found then 404 error, otherwise status is 200. diff --git a/app/Controllers/File/FIleUpdateAction.php b/app/Controllers/File/FileUpdateAction.php similarity index 86% rename from app/Controllers/File/FIleUpdateAction.php rename to app/Controllers/File/FileUpdateAction.php index e225482..a372dac 100644 --- a/app/Controllers/File/FIleUpdateAction.php +++ b/app/Controllers/File/FileUpdateAction.php @@ -6,7 +6,7 @@ use Willow\Controllers\WriteActionBase; use Willow\Models\File; -class FIleUpdateAction extends WriteActionBase +class FileUpdateAction extends WriteActionBase { /** * FIleUpdateAction constructor. diff --git a/app/Controllers/Resident/ClientLoadAction.php b/app/Controllers/Resident/ClientLoadAction.php index 87e155f..ece5857 100644 --- a/app/Controllers/Resident/ClientLoadAction.php +++ b/app/Controllers/Resident/ClientLoadAction.php @@ -53,7 +53,7 @@ public function __invoke(Request $request, Response $response, array $args): Res 'clientInfo' => $client->attributesToArray(), 'fileList' => $this->file ->where('ResidentId', '=', $clientId) - ->orderBy('Updated', 'asc') + ->orderBy('Updated', 'desc') ->get(['Id', 'ResidentId', 'FileName','MediaType', 'Size', 'Created', 'Updated']) ->toArray(), 'medicineList' => $this->medicine diff --git a/app/Models/File.php b/app/Models/File.php index 0cde82c..5bc9608 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -13,7 +13,7 @@ #[ApplyModelColumnAttribute('MediaType', 'string', 65)] // The mime type #[ApplyModelColumnAttribute('Size', 'int', null)] // The size of the file in bytes #[ApplyModelColumnAttribute('Description', 'string', 65)] // A description of the file -#[ApplyModelColumnAttribute('Image', 'string', null)] // File image as a blob +#[ApplyModelColumnAttribute('Image', 'string', null, ['HIDDEN'])] // File image as a blob #[ApplyModelColumnAttribute('Created', 'DateTime', null, ['CE'], 'NULL')] #[ApplyModelColumnAttribute('Updated', 'DateTime', null, ['CE'], 'NULL')] #[ApplyModelColumnAttribute('deleted_at', 'DateTime', null, ['CE'], 'NULL')] @@ -32,6 +32,7 @@ */ class File extends ModelBase { + protected $hidden = ['Image']; protected $table = 'File'; } From 0a98c828f659a64e4ad517c67e23246613428382 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 3 Mar 2022 05:35:19 -0700 Subject: [PATCH 07/12] =?UTF-8?q?=F0=9F=90=9B=20bug=20`File.Description`?= =?UTF-8?q?=20missing=20in=20FileLoadAction=20and=20ClientLoadAction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/File/FileLoadAction.php | 2 +- app/Controllers/Resident/ClientLoadAction.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Controllers/File/FileLoadAction.php b/app/Controllers/File/FileLoadAction.php index 189309c..6a898cf 100644 --- a/app/Controllers/File/FileLoadAction.php +++ b/app/Controllers/File/FileLoadAction.php @@ -37,7 +37,7 @@ public function __invoke(Request $request, Response $response, array $args): Res $documents = $file ->where('ResidentId', '=', $args['client_id']) ->orderBy('Updated', 'desc') - ->get(['Id', 'ResidentId', 'FileName','MediaType', 'Size', 'Created', 'Updated']); + ->get(['Id', 'ResidentId', 'FileName', 'Description', 'MediaType', 'Size', 'Created', 'Updated']); // If the record is not found then 404 error, otherwise status is 200. if ($documents !== null && count($documents) > 0) { diff --git a/app/Controllers/Resident/ClientLoadAction.php b/app/Controllers/Resident/ClientLoadAction.php index ece5857..98788b9 100644 --- a/app/Controllers/Resident/ClientLoadAction.php +++ b/app/Controllers/Resident/ClientLoadAction.php @@ -54,7 +54,7 @@ public function __invoke(Request $request, Response $response, array $args): Res 'fileList' => $this->file ->where('ResidentId', '=', $clientId) ->orderBy('Updated', 'desc') - ->get(['Id', 'ResidentId', 'FileName','MediaType', 'Size', 'Created', 'Updated']) + ->get(['Id', 'ResidentId', 'FileName', 'Description', 'MediaType', 'Size', 'Created', 'Updated']) ->toArray(), 'medicineList' => $this->medicine ->where('ResidentId', '=', $clientId) From 7e229421a2f6dbe5d6cb2ec32e545a39e7867266 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 3 Mar 2022 05:43:58 -0700 Subject: [PATCH 08/12] =?UTF-8?q?=E2=9B=B2=20feat=20Override=20`File.Descr?= =?UTF-8?q?iption`=20to=20null=20if=20empty=20string=20is=20given?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Unrelated] - Code formatting in Medicine.php model --- app/Models/File.php | 13 +++++++++++++ app/Models/Medicine.php | 1 + 2 files changed, 14 insertions(+) diff --git a/app/Models/File.php b/app/Models/File.php index 5bc9608..93146e8 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -33,6 +33,19 @@ class File extends ModelBase { protected $hidden = ['Image']; + protected $table = 'File'; + + /** + * Override Description field to null if empty string + * @param string|null $value + */ + final public function setDescriptionAttribute(?string $value): void { + if (empty($value)) { + $this->attributes['Description'] = null; + } else { + $this->attributes['Description'] = $value; + } + } } diff --git a/app/Models/Medicine.php b/app/Models/Medicine.php index 6bb07a7..2f5c42d 100644 --- a/app/Models/Medicine.php +++ b/app/Models/Medicine.php @@ -53,6 +53,7 @@ class Medicine extends ModelBase final public function setDrugAttribute(string $value): void { $this->attributes['Drug'] = trim($value); } + /** * Override Strength field to null if empty string * @param string|null $value From 1925a417a14ff8a3807b1ca42b243514eb607d04 Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 5 Mar 2022 03:22:47 -0700 Subject: [PATCH 09/12] =?UTF-8?q?=E2=9B=B2=20feat=20Added=20'file/download?= =?UTF-8?q?'=20route=20and=20`FileDownloadAction()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See: https://dev.to/nauleyco/how-to-download-a-csv-file-with-slim-4-21a7 --- app/Controllers/File/FileController.php | 2 + app/Controllers/File/FileDownloadAction.php | 61 +++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 app/Controllers/File/FileDownloadAction.php diff --git a/app/Controllers/File/FileController.php b/app/Controllers/File/FileController.php index a593060..74431a3 100644 --- a/app/Controllers/File/FileController.php +++ b/app/Controllers/File/FileController.php @@ -16,6 +16,8 @@ final public function register(RouteCollectorProxyInterface $group): void { $group->post('/file/upload/{client_id}', FileUploadAction::class) ->add(FileValidator::class); + $group->get('/file/download/{id}', FileDownloadAction::class); + $group->get('/file/{id}', FileGetAction::class); $group->post('/file', FileUpdateAction::class); diff --git a/app/Controllers/File/FileDownloadAction.php b/app/Controllers/File/FileDownloadAction.php new file mode 100644 index 0000000..3e00eec --- /dev/null +++ b/app/Controllers/File/FileDownloadAction.php @@ -0,0 +1,61 @@ +getAttribute('response_body'); + + + /** + * Load the File Model with the given id (PK) + * @var File|FileRepresentation|null $fileModel + */ + $fileModel = $this->file->makeVisible('Image')->find($args['id']); + + // If the record is not found then 404 error, otherwise status is 200. + if ($fileModel === null) { + $responseBody = $responseBody + ->setData(null) + ->setStatus(ResponseCodes::HTTP_NOT_FOUND); + return $responseBody(); + } + + return $response + ->withHeader('Content-Type', 'application/octet-stream') + ->withHeader('Content-Disposition', 'attachment; filename="' . $fileModel->FileName . '"') + ->withAddedHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->withHeader('Cache-Control', 'post-check=0, pre-check=0') + ->withHeader('Pragma', 'no-cache') + ->withBody((new StreamFactory())->createStream($fileModel->Image)); + } +} From 3aa4dd2ce5aded74d69d936ba32908d28315e5a5 Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 5 Mar 2022 03:39:00 -0700 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=8C=80=20refactor=20Changed=20the?= =?UTF-8?q?=20name=20and=20code=20of=20`FileValidator`=20to=20`FileUploadV?= =?UTF-8?q?alidator`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/File/FileController.php | 2 +- .../File/{FileValidator.php => FileUploadValidator.php} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/Controllers/File/{FileValidator.php => FileUploadValidator.php} (98%) diff --git a/app/Controllers/File/FileController.php b/app/Controllers/File/FileController.php index 74431a3..ea0f6e5 100644 --- a/app/Controllers/File/FileController.php +++ b/app/Controllers/File/FileController.php @@ -14,7 +14,7 @@ class FileController implements IController */ final public function register(RouteCollectorProxyInterface $group): void { $group->post('/file/upload/{client_id}', FileUploadAction::class) - ->add(FileValidator::class); + ->add(FileUploadValidator::class); $group->get('/file/download/{id}', FileDownloadAction::class); diff --git a/app/Controllers/File/FileValidator.php b/app/Controllers/File/FileUploadValidator.php similarity index 98% rename from app/Controllers/File/FileValidator.php rename to app/Controllers/File/FileUploadValidator.php index 16f3a3f..868531a 100644 --- a/app/Controllers/File/FileValidator.php +++ b/app/Controllers/File/FileUploadValidator.php @@ -12,7 +12,7 @@ use JsonException; use Respect\Validation\Validator as V; -class FileValidator +class FileUploadValidator { /** * @param Request $request From e3da342452355fddfa505d739cd2f5d7b274014c Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 5 Mar 2022 12:58:28 -0700 Subject: [PATCH 11/12] =?UTF-8?q?=E2=9B=B2=20feat=20Delete=20operations=20?= =?UTF-8?q?can=20now=20optionally=20destroy=20a=20record=20permanently=20(?= =?UTF-8?q?non-soft=20delete)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pass a query string of `force=true` to permanently destroy the record --- app/Controllers/DeleteActionBase.php | 16 +++++++++++----- app/Models/ModelBase.php | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/Controllers/DeleteActionBase.php b/app/Controllers/DeleteActionBase.php index 21c6f13..8c3bc31 100644 --- a/app/Controllers/DeleteActionBase.php +++ b/app/Controllers/DeleteActionBase.php @@ -23,13 +23,19 @@ abstract class DeleteActionBase extends ActionBase public function __invoke(Request $request, Response $response, array $args): ResponseInterface { /** @var ResponseBody $responseBody */ $responseBody = $request->getAttribute('response_body'); + $parsedRequest = $responseBody->getParsedRequest(); $model = $this->model; + $id = $args['id']; + $model = $model->find($id); - // Destroy the model given the id. - if ($model::destroy($args['id']) === 1) { - $status = ResponseCodes::HTTP_OK; - } else { - $status = ResponseCodes::HTTP_NOT_FOUND; + $status = ResponseCodes::HTTP_NOT_FOUND; + if ($model !== null) { + if (array_key_exists('force', $parsedRequest) && $parsedRequest['force'] === "true") { + $isDeleted = $model->forceDelete(); + } else { + $isDeleted = $model->delete(); + } + $status= $isDeleted ? ResponseCodes::HTTP_OK : ResponseCodes::HTTP_INTERNAL_SERVER_ERROR; } // Set the status and data of the ResponseBody diff --git a/app/Models/ModelBase.php b/app/Models/ModelBase.php index a361950..d8ce739 100644 --- a/app/Models/ModelBase.php +++ b/app/Models/ModelBase.php @@ -27,7 +27,7 @@ protected static function booted(): void { static::addGlobalScope(new UserScope()); // Save the authenticated UserId value to the model - static::saving(function ($model) { + static::saving(static function ($model) { $model->UserId = UserScope::getUserId(); }); } From 33d5b4d6cd74634f4136813afe2440225b974d5c Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 5 Mar 2022 20:44:02 -0700 Subject: [PATCH 12/12] =?UTF-8?q?=E2=9B=B2=20feat=20Document=20Management?= =?UTF-8?q?=20(upload/download=20files)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ⛲ DeleteActionBase force permanent delete option - 🗄 File Table Schema - 🚚 'file' Routes and actions added [Unrelated] - Version upgrade of `illuminate/database` - Version upgrade of `illuminate/events' --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index bd9bded..15ff89d 100644 --- a/composer.json +++ b/composer.json @@ -18,8 +18,8 @@ "require": { "ext-json": "*", "ext-pdo": "*", - "illuminate/database": "^v8.77.1", - "illuminate/events": "^v8.77.1", + "illuminate/database": "^v8.83.3", + "illuminate/events": "^v8.83.3", "php": "^8.0 || 8.1", "php-di/php-di": "^6.3.5", "psr/container": "^1.1.2",