From 0f7f49deb8b8ea4ad9513cf12a67c12b5955917c Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Sun, 29 Mar 2020 11:21:21 +0100 Subject: [PATCH 01/22] Set quantity to zero for simple items - Set quantity to zero. - Reformat the alidation rules --- config/api/category/validation.php | 11 ++- config/api/item-category/validation.php | 5 +- config/api/item-subcategory/validation.php | 5 +- .../validation.php | 71 +++++++++++++++---- .../item-type-simple-expense/validation.php | 37 ++++++++-- .../api/item-type-simple-item/validation.php | 38 ++++++++-- config/api/request-error-log/validation.php | 33 +++++++-- config/api/resource-type/validation.php | 6 +- config/api/subcategory/validation.php | 7 +- 9 files changed, 176 insertions(+), 37 deletions(-) diff --git a/config/api/category/validation.php b/config/api/category/validation.php index 6e036308..36581719 100644 --- a/config/api/category/validation.php +++ b/config/api/category/validation.php @@ -5,7 +5,10 @@ return [ 'POST' => [ 'fields' => [ - 'description' => 'required|string' + 'description' => [ + 'required', + 'string' + ] ], 'messages' => [ 'name.unique' => 'category/validation.name-unique' @@ -13,7 +16,11 @@ ], 'PATCH' => [ 'fields' => [ - 'description' => 'sometimes|string|max:255' + 'description' => [ + 'sometimes', + 'string', + 'max:255' + ] ], 'messages' => [ 'name.unique' => 'category/validation.name-unique' diff --git a/config/api/item-category/validation.php b/config/api/item-category/validation.php index c299cc20..d2de5cae 100644 --- a/config/api/item-category/validation.php +++ b/config/api/item-category/validation.php @@ -5,7 +5,10 @@ return [ 'POST' => [ 'fields' => [ - 'category_id' => 'required|exists:category,id' + 'category_id' => [ + 'required', + 'exists:category,id' + ] ], 'messages' => [ 'category_id.required' => 'item-category/validation.category_id-required', diff --git a/config/api/item-subcategory/validation.php b/config/api/item-subcategory/validation.php index b116e37a..d21805e3 100644 --- a/config/api/item-subcategory/validation.php +++ b/config/api/item-subcategory/validation.php @@ -5,7 +5,10 @@ return [ 'POST' => [ 'fields' => [ - 'subcategory_id' => 'required|exists:sub_category,id' + 'subcategory_id' => [ + 'required', + 'exists:sub_category,id' + ] ], 'messages' => [ 'subcategory_id.required' => 'item-subcategory/validation.subcategory_id-required', diff --git a/config/api/item-type-allocated-expense/validation.php b/config/api/item-type-allocated-expense/validation.php index d90c3128..ae4b0bc4 100644 --- a/config/api/item-type-allocated-expense/validation.php +++ b/config/api/item-type-allocated-expense/validation.php @@ -5,12 +5,35 @@ return [ 'POST' => [ 'fields' => [ - 'name' => 'required|string|max:255', - 'description' => 'sometimes|string|max:255', - 'effective_date' => 'required|date_format:Y-m-d', - 'publish_after' => 'sometimes|date_format:Y-m-d', - 'total' => 'required|string|regex:/^\d+\.\d{2}$/', - 'percentage' => 'sometimes|required|integer|between:1,100' + 'name' => [ + 'required', + 'string', + 'max:255' + ], + 'description' => [ + 'sometimes', + 'string', + 'max:255' + ], + 'effective_date' => [ + 'required', + 'date_format:Y-m-d' + ], + 'publish_after' => [ + 'sometimes', + 'date_format:Y-m-d' + ], + 'total' => [ + 'required', + 'string', + 'regex:/^\d+\.\d{2}$/' + ], + 'percentage' => [ + 'sometimes', + 'required', + 'integer', + 'between:1,100' + ] ], 'messages' => [ 'total.regex' => 'item-type-allocated-expense/validation.total-regex' @@ -18,12 +41,36 @@ ], 'PATCH' => [ 'fields' => [ - 'name' => 'sometimes|string|max:255', - 'description' => 'sometimes|string|max:255', - 'effective_date' => 'sometimes|date_format:Y-m-d', - 'publish_after' => 'sometimes|date_format:Y-m-d', - 'total' => 'sometimes|string|regex:/^\d+\.\d{2}$/', - 'percentage' => 'sometimes|integer|between:1,100' + 'name' => [ + 'sometimes', + 'string', + 'max:255' + ], + 'description' => [ + 'sometimes', + 'nullable', + 'string', + 'max:255' + ], + 'effective_date' => [ + 'sometimes', + 'date_format:Y-m-d' + ], + 'publish_after' => [ + 'sometimes', + 'nullable', + 'date_format:Y-m-d' + ], + 'total' => [ + 'sometimes', + 'string', + 'regex:/^\d+\.\d{2}$/' + ], + 'percentage' => [ + 'sometimes', + 'integer', + 'between:1,100' + ] ], 'messages' => [ 'total.regex' => 'item-type-allocated-expense/validation.total-regex' diff --git a/config/api/item-type-simple-expense/validation.php b/config/api/item-type-simple-expense/validation.php index 4540a7df..4c8e520a 100644 --- a/config/api/item-type-simple-expense/validation.php +++ b/config/api/item-type-simple-expense/validation.php @@ -5,9 +5,21 @@ return [ 'POST' => [ 'fields' => [ - 'name' => 'required|string|max:255', - 'description' => 'sometimes|string|max:255', - 'total' => 'required|string|regex:/^\d+\.\d{2}$/', + 'name' => [ + 'required', + 'string', + 'max:255' + ], + 'description' => [ + 'sometimes', + 'string', + 'max:255' + ], + 'total' => [ + 'required', + 'string', + 'regex:/^\d+\.\d{2}$/' + ], ], 'messages' => [ 'total.regex' => 'item-type-simple-expense/validation.total-regex' @@ -15,9 +27,22 @@ ], 'PATCH' => [ 'fields' => [ - 'name' => 'sometimes|string|max:255', - 'description' => 'sometimes|string|max:255', - 'total' => 'sometimes|string|regex:/^\d+\.\d{2}$/', + 'name' => [ + 'sometimes', + 'string', + 'max:255' + ], + 'description' => [ + 'sometimes', + 'nullable', + 'string', + 'max:255' + ], + 'total' => [ + 'sometimes', + 'string', + 'regex:/^\d+\.\d{2}$/' + ], ], 'messages' => [ 'total.regex' => 'item-type-simple-expense/validation.total-regex' diff --git a/config/api/item-type-simple-item/validation.php b/config/api/item-type-simple-item/validation.php index 0c890c74..9244d1e1 100644 --- a/config/api/item-type-simple-item/validation.php +++ b/config/api/item-type-simple-item/validation.php @@ -5,17 +5,41 @@ return [ 'POST' => [ 'fields' => [ - 'name' => 'required|string|max:255', - 'description' => 'sometimes|string|max:255', - 'quantity' => 'required|integer|min:1', - ], + 'name' => + 'required', + 'string', + 'max:255' + ], + 'description' => [ + 'sometimes', + 'string', + 'max:255' + ], + 'quantity' => [ + 'required', + 'integer', + 'min:0' + ], 'messages' => [] ], 'PATCH' => [ 'fields' => [ - 'name' => 'sometimes|string|max:255', - 'description' => 'sometimes|string|max:255', - 'quantity' => 'sometimes|integer|min:1', + 'name' => [ + 'sometimes', + 'string', + 'max:255' + ], + 'description' => [ + 'sometimes', + 'nullable', + 'string', + 'max:255', + ], + 'quantity' => [ + 'sometimes', + 'integer', + 'min:0', + ] ], 'messages' => [] ] diff --git a/config/api/request-error-log/validation.php b/config/api/request-error-log/validation.php index e1f2a9dd..eca63c50 100644 --- a/config/api/request-error-log/validation.php +++ b/config/api/request-error-log/validation.php @@ -5,12 +5,33 @@ return [ 'POST' => [ 'fields' => [ - 'method' => 'required|string', - 'expected_status_code' => 'required|integer|between:100,530', - 'returned_status_code' => 'required|integer|between:100,530', - 'request_uri' => 'required|string', - 'source' => 'required|string|in:website,api,app,legacy,postman', - 'debug' => 'sometimes|string' + 'method' => [ + 'required', + 'string' + ], + 'expected_status_code' => [ + 'required', + 'integer', + 'between:100,530' + ], + 'returned_status_code' => [ + 'required', + 'integer', + 'between:100,530' + ], + 'request_uri' => [ + 'required', + 'string' + ], + 'source' => [ + 'required', + 'string', + 'in:website,api,app,legacy,postman' + ], + 'debug' => [ + 'sometimes', + 'string' + ] ], 'messages' => [] ] diff --git a/config/api/resource-type/validation.php b/config/api/resource-type/validation.php index 664a4148..a4026720 100644 --- a/config/api/resource-type/validation.php +++ b/config/api/resource-type/validation.php @@ -14,7 +14,11 @@ ], 'PATCH' => [ 'fields' => [ - 'description' => 'sometimes|string|max:255', + 'description' => [ + 'sometimes', + 'string', + 'max:255' + ], 'public' => 'sometimes|boolean' ], 'messages' => [ diff --git a/config/api/subcategory/validation.php b/config/api/subcategory/validation.php index d732b4e2..afb5879e 100644 --- a/config/api/subcategory/validation.php +++ b/config/api/subcategory/validation.php @@ -13,7 +13,12 @@ ], 'PATCH' => [ 'fields' => [ - 'description' => 'sometimes|string|max:255' + 'description' => + [ + 'sometimes', + 'string', + 'max:255' + ] ], 'messages' => [ 'name.unique' => 'subcategory/validation.name-unique' From f558f74f32991261677419afa30808b57f7791db Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Sun, 29 Mar 2020 12:40:19 +0100 Subject: [PATCH 02/22] 409 for constraint errors - Constraint error should be a 409 --- app/Utilities/Response.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Utilities/Response.php b/app/Utilities/Response.php index af6b9c18..b2cacdd2 100644 --- a/app/Utilities/Response.php +++ b/app/Utilities/Response.php @@ -3,9 +3,9 @@ namespace App\Utilities; -use App; use Exception; use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\App; /** * Utility class to return default responses, we want some consistency @@ -109,7 +109,7 @@ static public function foreignKeyConstraintError($message = '', ?Exception $e = response()->json( $response, - 500 + 409 )->send(); exit; } From 4c7568232c28e5d653acee5c163e2ba5fb9639b1 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Sun, 29 Mar 2020 13:11:33 +0100 Subject: [PATCH 03/22] Add partial transfer table - Added migration for the partial transfer table --- ...0_03_29_124056_create_partial_transfer.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 database/migrations/2020_03_29_124056_create_partial_transfer.php diff --git a/database/migrations/2020_03_29_124056_create_partial_transfer.php b/database/migrations/2020_03_29_124056_create_partial_transfer.php new file mode 100644 index 00000000..c7f4a134 --- /dev/null +++ b/database/migrations/2020_03_29_124056_create_partial_transfer.php @@ -0,0 +1,46 @@ +charset = 'utf8mb4'; + $table->collation = 'utf8mb4_unicode_ci'; + + $table->bigIncrements('id'); + $table->unsignedBigInteger('resource_type_id'); + $table->unsignedBigInteger('from'); + $table->unsignedBigInteger('to'); + $table->unsignedBigInteger('item_id'); + $table->unsignedTinyInteger('percentage'); + $table->unsignedBigInteger('transferred_by'); + $table->timestamps(); + $table->foreign('resource_type_id')->references('id')->on('resource_type'); + $table->foreign('from')->references('id')->on('resource'); + $table->foreign('to')->references('id')->on('resource'); + $table->foreign('item_id')->references('id')->on('item'); + $table->foreign('transferred_by')->references('id')->on('users'); + $table->unique(['resource_type_id', 'from', 'item_id'], 'unique_partial_transfer'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('partial_transfer'); + } +} From ca325aa6084543282e1e3bd9f6d2a89d95922b09 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Sun, 29 Mar 2020 13:49:35 +0100 Subject: [PATCH 04/22] Partial transfer config files - Tweak the field description in an OPTIONS request. - Added the config and language files for the partial transfer endpoint --- config/api/item-partial-transfer/fields.php | 27 +++++++++++++++++++ .../api/item-partial-transfer/validation.php | 11 ++++++++ .../lang/en/item-partial-transfer/fields.php | 8 ++++++ .../en/item-partial-transfer/validation.php | 6 +++++ resources/lang/en/item-transfer/fields.php | 5 +++- 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 config/api/item-partial-transfer/fields.php create mode 100644 config/api/item-partial-transfer/validation.php create mode 100644 resources/lang/en/item-partial-transfer/fields.php create mode 100644 resources/lang/en/item-partial-transfer/validation.php diff --git a/config/api/item-partial-transfer/fields.php b/config/api/item-partial-transfer/fields.php new file mode 100644 index 00000000..2675d739 --- /dev/null +++ b/config/api/item-partial-transfer/fields.php @@ -0,0 +1,27 @@ + [ + 'field' => 'resource_id', + 'title' => 'item-partial-transfer/fields.title-resource_id', + 'description' => 'item-partial-transfer/fields.description-resource_id', + 'type' => 'string', + 'validation' => [ + 'length' => 10 + ], + 'required' => true + ], + 'percentage' => [ + 'field' => 'percentage', + 'title' => 'item-partial-transfer/fields.title-percentage', + 'description' => 'item-partial-transfer/fields.description-percentage', + 'type' => 'integer', + 'validation' => [ + 'min' => 1, + 'max' => 99 + ], + 'required' => true + ] +]; diff --git a/config/api/item-partial-transfer/validation.php b/config/api/item-partial-transfer/validation.php new file mode 100644 index 00000000..009a49dd --- /dev/null +++ b/config/api/item-partial-transfer/validation.php @@ -0,0 +1,11 @@ + [ + 'messages' => [ + 'resource_id.exists' => 'item-partial-transfer/validation.resource_id-exists' + ] + ] +]; diff --git a/resources/lang/en/item-partial-transfer/fields.php b/resources/lang/en/item-partial-transfer/fields.php new file mode 100644 index 00000000..4045064c --- /dev/null +++ b/resources/lang/en/item-partial-transfer/fields.php @@ -0,0 +1,8 @@ + 'Resource id', + 'description-resource_id' => 'Resource to partially transfer the item to' +]; diff --git a/resources/lang/en/item-partial-transfer/validation.php b/resources/lang/en/item-partial-transfer/validation.php new file mode 100644 index 00000000..a8bdf0d4 --- /dev/null +++ b/resources/lang/en/item-partial-transfer/validation.php @@ -0,0 +1,6 @@ + 'The provided resource does not belong to the current resource type or you are trying to move the item to the same resource', +]; diff --git a/resources/lang/en/item-transfer/fields.php b/resources/lang/en/item-transfer/fields.php index 87c2e867..2e99ac2c 100644 --- a/resources/lang/en/item-transfer/fields.php +++ b/resources/lang/en/item-transfer/fields.php @@ -4,5 +4,8 @@ return [ 'title-resource_id' => 'Resource id', - 'description-resource_id' => 'Resource to move the item to' + 'description-resource_id' => 'Resource to transfer the item to', + + 'title-percentage' => 'Percentage', + 'description-percentage' => 'The percentage of the total that should be allocated to the resource' ]; From 79b4c9ec6c4d973bdd36697e82fd03467b5a197c Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Sun, 29 Mar 2020 23:43:39 +0100 Subject: [PATCH 05/22] Partial transfer OPTIONS request - Added the OPTION request for the partial transfer OPTIONS endpoint. - Corrected a description. - Added validator for partial transfer. --- .../ItemPartialTransferController.php | 137 ++++++++++++++++++ .../Controllers/ItemTransferController.php | 2 - app/Validators/Fields/ItemPartialTransfer.php | 74 ++++++++++ .../en/item-partial-transfer/validation.php | 2 +- .../lang/en/item-transfer/validation.php | 2 +- resources/lang/en/route-descriptions.php | 2 + routes/api/private-routes.php | 5 + routes/api/public-routes.php | 5 + 8 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 app/Http/Controllers/ItemPartialTransferController.php create mode 100644 app/Validators/Fields/ItemPartialTransfer.php diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php new file mode 100644 index 00000000..70484e66 --- /dev/null +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -0,0 +1,137 @@ + + * @copyright Dean Blackborough 2018-2020 + * @license https://github.com/costs-to-expect/api/blob/master/LICENSE + */ +class ItemPartialTransferController extends Controller +{ + public function transfer( + string $resource_type_id, + string $resource_id, + string $item_id + ): JsonResponse + { + Route::item( + $resource_type_id, + $resource_id, + $item_id, + $this->permitted_resource_types, + true + ); + + $validator = (new ItemPartialTransferValidator)->create( + [ + 'resource_type_id' => $resource_type_id, + 'existing_resource_id' => $resource_id + ] + ); + UtilityRequest::validateAndReturnErrors($validator); + + try { + $new_resource_id = $this->hash->decode('resource', request()->input('resource_id')); + + if ($new_resource_id === false) { + UtilityResponse::unableToDecode(); + } + + $item = (new Item())->instance($resource_type_id, $resource_id, $item_id); + $item->resource_id = $new_resource_id; + $item->save(); + } catch (Exception $e) { + UtilityResponse::failedToSaveModelForUpdate(); + } + + // Endpoint should 404 after request so figure 204 better than redirect or 404 + UtilityResponse::successNoContent(); + } + + public function optionsTransfer( + string $resource_type_id, + string $resource_id, + string $item_id + ): JsonResponse + { + Route::item( + $resource_type_id, + $resource_id, + $item_id, + $this->permitted_resource_types + ); + + $permissions = RoutePermission::item( + $resource_type_id, + $resource_id, + $item_id, + $this->permitted_resource_types + ); + + $post = Post::init()-> + setFields('api.item-partial-transfer.fields')-> + setFieldsData( + $this->fieldsData( + $resource_type_id, + $resource_id + ) + )-> + setDescription('route-descriptions.item_partial_transfer_POST')-> + setAuthenticationStatus($permissions['manage'])-> + setAuthenticationRequired(true)-> + option(); + + return $this->optionsResponse($post, 200); + } + + /** + * Generate any conditional POST parameters, will be merged with the + * relevant config/api/[type]/fields.php data array + * + * @param integer $resource_type_id + * @param integer $resource_id + * + * @return array + */ + private function fieldsData( + int $resource_type_id, + int $resource_id + ): array + { + $resources = (new Resource())->resourcesForResourceType( + $resource_type_id, + $resource_id + ); + + $conditional_post_parameters = ['resource_id' => []]; + foreach ($resources as $resource) { + $id = $this->hash->encode('resource', $resource['resource_id']); + + if ($id === false) { + UtilityResponse::unableToDecode(); + } + + $conditional_post_parameters['resource_id']['allowed_values'][$id] = [ + 'value' => $id, + 'name' => $resource['resource_name'], + 'description' => $resource['resource_description'] + ]; + } + + return $conditional_post_parameters; + } +} diff --git a/app/Http/Controllers/ItemTransferController.php b/app/Http/Controllers/ItemTransferController.php index 10a390f9..29447530 100644 --- a/app/Http/Controllers/ItemTransferController.php +++ b/app/Http/Controllers/ItemTransferController.php @@ -22,8 +22,6 @@ */ class ItemTransferController extends Controller { - protected $pagination = []; - public function transfer( string $resource_type_id, string $resource_id, diff --git a/app/Validators/Fields/ItemPartialTransfer.php b/app/Validators/Fields/ItemPartialTransfer.php new file mode 100644 index 00000000..4a056b34 --- /dev/null +++ b/app/Validators/Fields/ItemPartialTransfer.php @@ -0,0 +1,74 @@ + + * @copyright Dean Blackborough 2018-2020 + * @license https://github.com/costs-to-expect/api/blob/master/LICENSE + */ +class ItemPartialTransfer extends BaseValidator +{ + /** + * Return the validator object for the create request + * + * @param array $options + * + * @return Validator + */ + public function create(array $options = []): Validator + { + $this->requiredIndexes([ + 'resource_type_id', + 'existing_resource_id' + ], + $options + ); + + $decode = $this->hash->resource()->decode(request()->input('resource_id')); + $resource_id = null; + if (count($decode) === 1) { + $resource_id = $decode[0]; + } + + // We need to merge the decoded resource_id with the POSTed data + return ValidatorFacade::make( + array_merge( + request()->all(), + [ + 'resource_id' => $resource_id, + ] + ), + [ + 'resource_id' => [ + 'required', + Rule::exists('resource', 'id')->where(function ($query) use ($options) + { + $query->where('resource_type_id', '=', $options['resource_type_id'])-> + where('id', '!=', $options['existing_resource_id']); + }), + ], + ], + $this->translateMessages('api.item-partial-transfer.validation.POST.messages') + ); + } + + /** + * @param array $options + * + * @return Validator + */ + public function update(array $options = []): \Illuminate\Contracts\Validation\Validator + { + // TODO: Implement update() method. + } +} diff --git a/resources/lang/en/item-partial-transfer/validation.php b/resources/lang/en/item-partial-transfer/validation.php index a8bdf0d4..63aa0942 100644 --- a/resources/lang/en/item-partial-transfer/validation.php +++ b/resources/lang/en/item-partial-transfer/validation.php @@ -2,5 +2,5 @@ declare(strict_types=1); return [ - 'resource_id-exists' => 'The provided resource does not belong to the current resource type or you are trying to move the item to the same resource', + 'resource_id-exists' => 'The provided resource does not belong to the current resource type or you are trying to partially transfer the item to the same resource', ]; diff --git a/resources/lang/en/item-transfer/validation.php b/resources/lang/en/item-transfer/validation.php index 9057d035..f495093d 100644 --- a/resources/lang/en/item-transfer/validation.php +++ b/resources/lang/en/item-transfer/validation.php @@ -3,5 +3,5 @@ declare(strict_types=1); return [ - 'resource_id-exists' => 'The provided resource does not belong to the current resource type or you are trying to move the item to the same resource', + 'resource_id-exists' => 'The provided resource does not belong to the current resource type or you are trying to transfer the item to the same resource', ]; diff --git a/resources/lang/en/route-descriptions.php b/resources/lang/en/route-descriptions.php index 32f67af2..d2228c95 100644 --- a/resources/lang/en/route-descriptions.php +++ b/resources/lang/en/route-descriptions.php @@ -55,6 +55,8 @@ 'item_transfer_POST' => 'Transfer an item to another resource', + 'item_partial_transfer_POST' => 'Portion a percentage of the costs for an item to another resource', + 'permitted_user_GET_index' => 'Return the permitted users', 'permitted_user_POST' => 'Assign a permitted user', diff --git a/routes/api/private-routes.php b/routes/api/private-routes.php index 7bdc2358..44108dbf 100644 --- a/routes/api/private-routes.php +++ b/routes/api/private-routes.php @@ -52,6 +52,11 @@ function () { 'ItemSubcategoryController@create' ); + Route::post( + 'resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/partial-transfer', + 'ItemPartialTransferController@transfer' + ); + Route::post( 'resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer', 'ItemTransferController@transfer' diff --git a/routes/api/public-routes.php b/routes/api/public-routes.php index 5457cfd5..69d8c5ce 100644 --- a/routes/api/public-routes.php +++ b/routes/api/public-routes.php @@ -174,6 +174,11 @@ function () { 'ItemController@optionsShow' ); + Route::options( + 'resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/partial-transfer', + 'ItemPartialTransferController@optionsTransfer' + ); + Route::options( 'resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer', 'ItemTransferController@optionsTransfer' From 41582d48e21647c50fcc9c11d8fc6a0b4a741c57 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Mon, 30 Mar 2020 15:20:06 +0100 Subject: [PATCH 06/22] Rename transfer table - Model for item partial transfer table. - Text corrections - Renamed migration and table --- app/Models/ItemPartialTransfer.php | 23 +++++++++++++++++++ ...9_124056_create_item_partial_transfer.php} | 6 ++--- .../lang/en/item-partial-transfer/fields.php | 5 +++- resources/lang/en/route-descriptions.php | 2 +- 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 app/Models/ItemPartialTransfer.php rename database/migrations/{2020_03_29_124056_create_partial_transfer.php => 2020_03_29_124056_create_item_partial_transfer.php} (89%) diff --git a/app/Models/ItemPartialTransfer.php b/app/Models/ItemPartialTransfer.php new file mode 100644 index 00000000..ee252168 --- /dev/null +++ b/app/Models/ItemPartialTransfer.php @@ -0,0 +1,23 @@ + + * @copyright Dean Blackborough 2018-2020 + * @license https://github.com/costs-to-expect/api/blob/master/LICENSE + */ +class ItemPartialTransfer extends Model +{ + protected $table = 'item_partial_transfer'; + + protected $guarded = ['id', 'created_at', 'updated_at']; +} diff --git a/database/migrations/2020_03_29_124056_create_partial_transfer.php b/database/migrations/2020_03_29_124056_create_item_partial_transfer.php similarity index 89% rename from database/migrations/2020_03_29_124056_create_partial_transfer.php rename to database/migrations/2020_03_29_124056_create_item_partial_transfer.php index c7f4a134..38e53e70 100644 --- a/database/migrations/2020_03_29_124056_create_partial_transfer.php +++ b/database/migrations/2020_03_29_124056_create_item_partial_transfer.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreatePartialTransfer extends Migration +class CreateItemPartialTransfer extends Migration { /** * Run the migrations. @@ -13,7 +13,7 @@ class CreatePartialTransfer extends Migration */ public function up() { - Schema::create('partial_transfer', function (Blueprint $table) { + Schema::create('item_partial_transfer', function (Blueprint $table) { $table->charset = 'utf8mb4'; $table->collation = 'utf8mb4_unicode_ci'; @@ -30,7 +30,7 @@ public function up() $table->foreign('to')->references('id')->on('resource'); $table->foreign('item_id')->references('id')->on('item'); $table->foreign('transferred_by')->references('id')->on('users'); - $table->unique(['resource_type_id', 'from', 'item_id'], 'unique_partial_transfer'); + $table->unique(['resource_type_id', 'from', 'item_id'], 'unique_item_partial_transfer'); }); } diff --git a/resources/lang/en/item-partial-transfer/fields.php b/resources/lang/en/item-partial-transfer/fields.php index 4045064c..c4b06129 100644 --- a/resources/lang/en/item-partial-transfer/fields.php +++ b/resources/lang/en/item-partial-transfer/fields.php @@ -4,5 +4,8 @@ return [ 'title-resource_id' => 'Resource id', - 'description-resource_id' => 'Resource to partially transfer the item to' + 'description-resource_id' => 'Resource to partially transfer the item to', + + 'title-percentage' => 'Percentage', + 'description-percentage' => 'Percentage of the total to transfer to the given resource' ]; diff --git a/resources/lang/en/route-descriptions.php b/resources/lang/en/route-descriptions.php index d2228c95..852af567 100644 --- a/resources/lang/en/route-descriptions.php +++ b/resources/lang/en/route-descriptions.php @@ -55,7 +55,7 @@ 'item_transfer_POST' => 'Transfer an item to another resource', - 'item_partial_transfer_POST' => 'Portion a percentage of the costs for an item to another resource', + 'item_partial_transfer_POST' => 'Portion a percentage of the total for an item to another resource', 'permitted_user_GET_index' => 'Return the permitted users', 'permitted_user_POST' => 'Assign a permitted user', From 98a66608aa1d32a87d7f7df6feabf9b012ef1c40 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Mon, 30 Mar 2020 16:06:10 +0100 Subject: [PATCH 07/22] Partial transfer - Added the ability to store partial transfer. - Updated a response message, also being used to catch key errors --- app/Http/Controllers/ItemController.php | 2 +- .../ItemPartialTransferController.php | 32 ++++++++++++------- app/Models/ItemPartialTransfer.php | 1 - app/Validators/Fields/ItemPartialTransfer.php | 22 +++++++------ .../api/item-partial-transfer/validation.php | 7 ++++ resources/lang/en/responses.php | 2 +- 6 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index adc4d8cb..ea520ba6 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -415,7 +415,7 @@ public function update( UtilityResponse::failedToSaveModelForUpdate(); } - UtilityResponse::successNoContent(); + return UtilityResponse::successNoContent(); } /** diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index 70484e66..3e920884 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Models\Item; +use App\Models\ItemPartialTransfer; use App\Models\Resource; use App\Option\Post; use App\Utilities\Request as UtilityRequest; @@ -11,7 +12,9 @@ use App\Validators\Fields\ItemPartialTransfer as ItemPartialTransferValidator; use App\Validators\Route; use Exception; +use Illuminate\Database\QueryException; use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\Auth; /** * Partial transfer of items @@ -44,22 +47,29 @@ public function transfer( ); UtilityRequest::validateAndReturnErrors($validator); - try { - $new_resource_id = $this->hash->decode('resource', request()->input('resource_id')); + $new_resource_id = $this->hash->decode('resource', request()->input('resource_id')); - if ($new_resource_id === false) { - UtilityResponse::unableToDecode(); - } + if ($new_resource_id === false) { + UtilityResponse::unableToDecode(); + } - $item = (new Item())->instance($resource_type_id, $resource_id, $item_id); - $item->resource_id = $new_resource_id; - $item->save(); + try { + $partial_transfer = new ItemPartialTransfer([ + 'resource_type_id' => $resource_type_id, + 'from' => intval($resource_id), + 'to' => $new_resource_id, + 'item_id' => $item_id, + 'percentage' => request()->input('percentage'), + 'transferred_by' => Auth::user()->id + ]); + $partial_transfer->save(); + } catch (QueryException $e) { + UtilityResponse::foreignKeyConstraintError(); } catch (Exception $e) { - UtilityResponse::failedToSaveModelForUpdate(); + UtilityResponse::failedToSaveModelForCreate(); } - // Endpoint should 404 after request so figure 204 better than redirect or 404 - UtilityResponse::successNoContent(); + return UtilityResponse::successNoContent(); } public function optionsTransfer( diff --git a/app/Models/ItemPartialTransfer.php b/app/Models/ItemPartialTransfer.php index ee252168..5fb1a5cf 100644 --- a/app/Models/ItemPartialTransfer.php +++ b/app/Models/ItemPartialTransfer.php @@ -3,7 +3,6 @@ namespace App\Models; -use App\Utilities\Model as ModelUtility; use Illuminate\Database\Eloquent\Builder as QueryBuilder; use Illuminate\Database\Eloquent\Model; diff --git a/app/Validators/Fields/ItemPartialTransfer.php b/app/Validators/Fields/ItemPartialTransfer.php index 4a056b34..b6dfcec0 100644 --- a/app/Validators/Fields/ItemPartialTransfer.php +++ b/app/Validators/Fields/ItemPartialTransfer.php @@ -5,6 +5,7 @@ use App\Validators\Fields\Validator as BaseValidator; use Illuminate\Contracts\Validation\Validator; +use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Validator as ValidatorFacade; use Illuminate\Validation\Rule; @@ -48,16 +49,19 @@ public function create(array $options = []): Validator 'resource_id' => $resource_id, ] ), - [ - 'resource_id' => [ - 'required', - Rule::exists('resource', 'id')->where(function ($query) use ($options) - { - $query->where('resource_type_id', '=', $options['resource_type_id'])-> - where('id', '!=', $options['existing_resource_id']); - }), + array_merge( + [ + 'resource_id' => [ + 'required', + Rule::exists('resource', 'id')->where(function ($query) use ($options) + { + $query->where('resource_type_id', '=', $options['resource_type_id'])-> + where('id', '!=', $options['existing_resource_id']); + }), + ], ], - ], + Config::get('api.item-partial-transfer.validation.POST.fields') + ), $this->translateMessages('api.item-partial-transfer.validation.POST.messages') ); } diff --git a/config/api/item-partial-transfer/validation.php b/config/api/item-partial-transfer/validation.php index 009a49dd..30b59233 100644 --- a/config/api/item-partial-transfer/validation.php +++ b/config/api/item-partial-transfer/validation.php @@ -4,6 +4,13 @@ return [ 'POST' => [ + 'fields' => [ + 'percentage' => [ + 'required', + 'integer', + 'between:1,99' + ] + ], 'messages' => [ 'resource_id.exists' => 'item-partial-transfer/validation.resource_id-exists' ] diff --git a/resources/lang/en/responses.php b/resources/lang/en/responses.php index 31176c89..ef1dd7e0 100644 --- a/resources/lang/en/responses.php +++ b/resources/lang/en/responses.php @@ -6,7 +6,7 @@ 'not-found' => 'The requested resource does not exist.', 'not-found-entity' => 'The requested `:type` does not exist.', 'not-found-or-not-accessible-entity' => 'The requested `:type` does not exist or is not accessible with your permissions.', - 'constraint' => 'Unable to handle your request, dependent data exists.', + 'constraint' => 'Unable to handle your request, dependent data exists or the result is being limited by a key.', 'model-select-failure' => 'Unable to handle your request, an error occurred when selecting the data to complete your request.', 'model-save-failure-update' => 'Unable to handle your request, an error occurred when processing your update request.', 'model-save-failure-create' => 'Unable to handle your request, an error occurred when processing your create request.', From f7d1616cc1768b6fcb0e5ac19bbcccd37fd854a6 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Mon, 30 Mar 2020 16:07:59 +0100 Subject: [PATCH 08/22] Update README.md - Added new route to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c8d165c3..5ca13077 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,8 @@ additionally, the same is true if you are assigned to a resource type. | GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/subcategory/{item_subcategory_id} | | OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/subcategory/{item_subcategory_id} | | DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/sub_category/{item_subcategory_id} | +| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/partial-transfer | +| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/partial-transfer | | OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer | | POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer | | GET/HEAD | v2/request/error-log | From c54eb38fca0836fbd4930921ed87c93350de0234 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Tue, 31 Mar 2020 11:37:29 +0100 Subject: [PATCH 09/22] Refactoring - Renamed the parameters for the route validators --- app/Validators/Route.php | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/app/Validators/Route.php b/app/Validators/Route.php index 8a288d72..7842a964 100644 --- a/app/Validators/Route.php +++ b/app/Validators/Route.php @@ -29,16 +29,16 @@ class Route * @param integer $resource_type_id * @param integer $category_id * @param array $permitted_resource_types - * @param bool $manage + * @param bool $write */ static public function category( int $resource_type_id, int $category_id, array $permitted_resource_types, - bool $manage = false + bool $write = false ) { - if ($manage === false) { + if ($write === false) { if ( Category::existsToUserForViewing( $resource_type_id, @@ -70,17 +70,17 @@ static public function category( * @param integer $category_id * @param integer $subcategory_id * @param array $permitted_resource_types - * @param bool $manage + * @param bool $write */ static public function subcategory( int $resource_type_id, int $category_id, int $subcategory_id, array $permitted_resource_types, - $manage = false + $write = false ) { - if ($manage === false) { + if ($write === false) { if ( Subcategory::existsToUserForViewing( $resource_type_id, @@ -111,15 +111,15 @@ static public function subcategory( * * @param $resource_type_id * @param array $permitted_resource_types - * @param bool $manage + * @param bool $write */ static public function resourceType( $resource_type_id, array $permitted_resource_types, - bool $manage = false + bool $write = false ) { - if ($manage === false) { + if ($write === false) { if ( ResourceType::existsToUserForViewing( (int) $resource_type_id, @@ -147,16 +147,16 @@ static public function resourceType( * @param $resource_type_id * @param $resource_id * @param array $permitted_resource_types - * @param bool $manage + * @param bool $write */ static public function resource( $resource_type_id, $resource_id, array $permitted_resource_types, - bool $manage = false + bool $write = false ) { - if ($manage === false) { + if ($write === false) { if ( Resource::existsToUserForViewing( (int) $resource_type_id, @@ -187,17 +187,17 @@ static public function resource( * @param $resource_id * @param $item_id * @param array $permitted_resource_types - * @param bool $manage + * @param bool $write */ static public function item( $resource_type_id, $resource_id, $item_id, array $permitted_resource_types, - bool $manage = false + bool $write = false ) { - if ($manage === false) { + if ($write === false) { if ( Item::existsToUserForViewing( (int) $resource_type_id, @@ -231,7 +231,7 @@ static public function item( * @param $item_id * @param $item_category_id, * @param array $permitted_resource_types - * @param bool $manage + * @param bool $write */ static public function itemCategory( $resource_type_id, @@ -239,9 +239,9 @@ static public function itemCategory( $item_id, $item_category_id, array $permitted_resource_types, - bool $manage = false + bool $write = false ) { - if ($manage === false) { + if ($write === false) { if ( ItemCategory::existsToUserForViewing( (int) $resource_type_id, @@ -293,7 +293,7 @@ static public function itemType($item_type_id) * @param $item_category_id * @param $item_subcategory_id * @param array $permitted_resource_types - * @param bool $manage + * @param bool $write */ static public function itemSubcategory( $resource_type_id, @@ -302,9 +302,9 @@ static public function itemSubcategory( $item_category_id, $item_subcategory_id, array $permitted_resource_types, - bool $manage = false + bool $write = false ) { - if ($manage === false) { + if ($write === false) { if ( ItemSubcategory::existsToUserForViewing( (int) $resource_type_id, From e2af044ddf14b601b3ce6ef24498f238e3bcdbde Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Tue, 31 Mar 2020 11:47:33 +0100 Subject: [PATCH 10/22] Log item transfer - Added migration for item_transfer table. - Log a item transfer in the table. --- .../Controllers/ItemTransferController.php | 14 ++++++ app/Models/ItemTransfer.php | 22 +++++++++ ...2020_03_31_103855_create_item_transfer.php | 45 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 app/Models/ItemTransfer.php create mode 100644 database/migrations/2020_03_31_103855_create_item_transfer.php diff --git a/app/Http/Controllers/ItemTransferController.php b/app/Http/Controllers/ItemTransferController.php index 29447530..03dee1b9 100644 --- a/app/Http/Controllers/ItemTransferController.php +++ b/app/Http/Controllers/ItemTransferController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Models\Item; +use App\Models\ItemTransfer; use App\Models\Resource; use App\Option\Post; use App\Utilities\Request as UtilityRequest; @@ -11,7 +12,9 @@ use App\Validators\Fields\ItemTransfer as ItemTransferValidator; use App\Validators\Route; use Exception; +use Illuminate\Database\QueryException; use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\Auth; /** * Transfer items @@ -54,6 +57,17 @@ public function transfer( $item = (new Item())->instance($resource_type_id, $resource_id, $item_id); $item->resource_id = $new_resource_id; $item->save(); + + $item_transfer = new ItemTransfer([ + 'resource_type_id' => $resource_type_id, + 'from' => intval($resource_id), + 'to' => $new_resource_id, + 'item_id' => $item_id, + 'transferred_by' => Auth::user()->id + ]); + $item_transfer->save(); + } catch (QueryException $e) { + UtilityResponse::foreignKeyConstraintError(); } catch (Exception $e) { UtilityResponse::failedToSaveModelForUpdate(); } diff --git a/app/Models/ItemTransfer.php b/app/Models/ItemTransfer.php new file mode 100644 index 00000000..d1881dd1 --- /dev/null +++ b/app/Models/ItemTransfer.php @@ -0,0 +1,22 @@ + + * @copyright Dean Blackborough 2018-2020 + * @license https://github.com/costs-to-expect/api/blob/master/LICENSE + */ +class ItemTransfer extends Model +{ + protected $table = 'item_transfer'; + + protected $guarded = ['id', 'created_at', 'updated_at']; +} diff --git a/database/migrations/2020_03_31_103855_create_item_transfer.php b/database/migrations/2020_03_31_103855_create_item_transfer.php new file mode 100644 index 00000000..bff12d28 --- /dev/null +++ b/database/migrations/2020_03_31_103855_create_item_transfer.php @@ -0,0 +1,45 @@ +charset = 'utf8mb4'; + $table->collation = 'utf8mb4_unicode_ci'; + + $table->bigIncrements('id'); + $table->unsignedBigInteger('resource_type_id'); + $table->unsignedBigInteger('from'); + $table->unsignedBigInteger('to'); + $table->unsignedBigInteger('item_id'); + $table->unsignedBigInteger('transferred_by'); + $table->timestamps(); + $table->foreign('resource_type_id')->references('id')->on('resource_type'); + $table->foreign('from')->references('id')->on('resource'); + $table->foreign('to')->references('id')->on('resource'); + $table->foreign('item_id')->references('id')->on('item'); + $table->foreign('transferred_by')->references('id')->on('users'); + $table->unique(['resource_type_id', 'from', 'item_id'], 'unique_item_partial_transfer'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} From 90787bd94fe405c7b9c2f3a58414e6f27c881f9b Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Tue, 31 Mar 2020 12:24:30 +0100 Subject: [PATCH 11/22] Working on partial-transfers collection - Moved a route in the routes file. - Added OPTIONS for `resource-types/[id]/partial-transfers` route - Working on GET for `resource-types/[id]/partial-transfers` route - Removed a use statement --- .../ItemPartialTransferController.php | 89 ++++++++++++++++++- app/Models/ItemPartialTransfer.php | 73 +++++++++++++++ resources/lang/en/route-descriptions.php | 1 + routes/api/public-routes.php | 30 ++++--- 4 files changed, 182 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index 3e920884..37d20030 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -2,10 +2,12 @@ namespace App\Http\Controllers; -use App\Models\Item; use App\Models\ItemPartialTransfer; use App\Models\Resource; +use App\Option\Get; use App\Option\Post; +use App\Utilities\Header; +use App\Utilities\Pagination as UtilityPagination; use App\Utilities\Request as UtilityRequest; use App\Utilities\Response as UtilityResponse; use App\Utilities\RoutePermission; @@ -25,6 +27,60 @@ */ class ItemPartialTransferController extends Controller { + /** + * Return the categories collection + * + * @param string $resource_type_id + * + * @return JsonResponse + */ + public function index($resource_type_id): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $total = (new ItemPartialTransfer())->total( + (int) $resource_type_id, + $this->permitted_resource_types, + $this->include_public + ); + + $pagination = UtilityPagination::init( + request()->path(), + $total, + 10, + $this->allow_entire_collection + )-> + paging(); + + $transfers = (new ItemPartialTransfer())->paginatedCollection( + (int) $resource_type_id, + $this->permitted_resource_types, + $this->include_public, + $pagination['offset'], + $pagination['limit'] + ); + + $headers = new Header(); + $headers->collection($pagination, count($transfers), $total); + + var_dump($transfers); + die; + + /*return response()->json( + array_map( + function($category) { + return (new CategoryTransformer($category))->toArray(); + }, + $categories + ), + 200, + $headers->headers() + );*/ + } + public function transfer( string $resource_type_id, string $resource_id, @@ -72,6 +128,37 @@ public function transfer( return UtilityResponse::successNoContent(); } + /** + * Generate the OPTIONS request for the category list + * + * @param $resource_type_id + * + * @return JsonResponse + */ + public function optionsIndex($resource_type_id): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $permissions = RoutePermission::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $get = Get::init()-> + setPagination(true)-> + setAuthenticationStatus($permissions['view'])-> + setDescription('route-descriptions.item_partial_transfer_GET')-> + option(); + + return $this->optionsResponse( + $get, + 200 + ); + } + public function optionsTransfer( string $resource_type_id, string $resource_id, diff --git a/app/Models/ItemPartialTransfer.php b/app/Models/ItemPartialTransfer.php index 5fb1a5cf..32e32180 100644 --- a/app/Models/ItemPartialTransfer.php +++ b/app/Models/ItemPartialTransfer.php @@ -3,6 +3,7 @@ namespace App\Models; +use App\Utilities\Model as ModelUtility; use Illuminate\Database\Eloquent\Builder as QueryBuilder; use Illuminate\Database\Eloquent\Model; @@ -19,4 +20,76 @@ class ItemPartialTransfer extends Model protected $table = 'item_partial_transfer'; protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Return the paginated collection + * + * @param integer $resource_type_id + * @param array $permitted_resource_types + * @param boolean $include_public Should we include categories assigned to public resources + * @param integer $offset + * @param integer $limit + * + * @return array + */ + public function paginatedCollection( + int $resource_type_id, + array $permitted_resource_types, + bool $include_public, + int $offset = 0, + int $limit = 10 + ): array { + $collection = $this->select( + $this->table . '.id', + $this->table . '.percentage', + $this->table . '.created_at' + )-> + join("resource_type",$this->table . ".resource_type_id","resource_type.id")-> + join("resource AS from_resource",$this->table . ".from","from_resource.id")-> + join("resource AS to_resource",$this->table . ".to","to_resource.id")-> + join("item",$this->table . ".item_id","item.id")-> + join("users",$this->table . ".transferred_by","users.id")-> + where($this->table .'.resource_type_id', '=', $resource_type_id); + + $collection = ModelUtility::applyResourceTypeCollectionCondition( + $collection, + $permitted_resource_types, + $include_public + ); + + $collection->offset($offset); + $collection->limit($limit); + + return $collection->get()->toArray(); + } + + /** + * @param integer $resource_type_id + * @param array $permitted_resource_types + * @param boolean $include_public + * + * @return integer + */ + public function total( + int $resource_type_id, + array $permitted_resource_types, + bool $include_public + ): int + { + $collection = $this->select($this->table . '.id')-> + join("resource_type",$this->table . ".resource_type_id","resource_type.id")-> + join("resource AS from_resource",$this->table . ".from","from_resource.id")-> + join("resource AS to_resource",$this->table . ".to","to_resource.id")-> + join("item",$this->table . ".item_id","item.id")-> + join("users",$this->table . ".transferred_by","users.id")-> + where($this->table .'.resource_type_id', '=', $resource_type_id); + + $collection = ModelUtility::applyResourceTypeCollectionCondition( + $collection, + $permitted_resource_types, + $include_public + ); + + return $collection->count(); + } } diff --git a/resources/lang/en/route-descriptions.php b/resources/lang/en/route-descriptions.php index 852af567..8a2a469d 100644 --- a/resources/lang/en/route-descriptions.php +++ b/resources/lang/en/route-descriptions.php @@ -55,6 +55,7 @@ 'item_transfer_POST' => 'Transfer an item to another resource', + 'item_partial_transfer_GET' => 'Return the partial transfers for the selected resource type', 'item_partial_transfer_POST' => 'Portion a percentage of the total for an item to another resource', 'permitted_user_GET_index' => 'Return the permitted users', diff --git a/routes/api/public-routes.php b/routes/api/public-routes.php index 69d8c5ce..c3e39c56 100644 --- a/routes/api/public-routes.php +++ b/routes/api/public-routes.php @@ -74,16 +74,6 @@ function () { 'ResourceTypeController@optionsShow' ); - Route::get( - 'resource-types/{resource_type_id}/permitted-users', - 'PermittedUserController@index' - ); - - Route::options( - 'resource-types/{resource_type_id}/permitted-users', - 'PermittedUserController@optionsIndex' - ); - Route::get( 'resource-types/{resource_type_id}/categories', 'CategoryController@index' @@ -134,6 +124,26 @@ function () { 'ResourceTypeItemController@optionsIndex' ); + Route::get( + 'resource-types/{resource_type_id}/partial-transfers', + 'ItemPartialTransferController@index' + ); + + Route::options( + 'resource-types/{resource_type_id}/partial-transfers', + 'ItemPartialTransferController@optionsIndex' + ); + + Route::get( + 'resource-types/{resource_type_id}/permitted-users', + 'PermittedUserController@index' + ); + + Route::options( + 'resource-types/{resource_type_id}/permitted-users', + 'PermittedUserController@optionsIndex' + ); + Route::get( 'resource-types/{resource_type_id}/resources', 'ResourceController@index' From ec99ea9dc808c03e35e2980492434179878562db Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Tue, 31 Mar 2020 14:00:02 +0100 Subject: [PATCH 12/22] Item partial transfers collection - Added partial transfers collection. - Added salts for the additional ids we are expsoing. - Added the transformer for partial transfers. --- .env.example | 3 ++ .../ItemPartialTransferController.php | 14 +++--- app/Models/ItemPartialTransfer.php | 9 +++- .../Transformers/ItemPartialTransfer.php | 49 +++++++++++++++++++ app/Utilities/Hash.php | 41 ++++++++++++++-- config/api/app/hashids.php | 5 +- 6 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 app/Models/Transformers/ItemPartialTransfer.php diff --git a/.env.example b/.env.example index ea7790cb..70ae8a7e 100644 --- a/.env.example +++ b/.env.example @@ -12,9 +12,12 @@ APP_HASH_SALT_RESOURCE_TYPE= APP_HASH_SALT_RESOURCE= APP_HASH_SALT_ITEM= APP_HASH_SALT_ITEM_CATEGORY= +APP_HASH_SALT_ITEM_PARTIAL_TRANSFER= APP_HASH_SALT_ITEM_SUBCATEGORY= +APP_HASH_SALT_ITEM_TRANSFER= APP_HASH_SALT_ITEM_TYPE= APP_HASH_SALT_PERMITTED_USER= +APP_HASH_SALT_USER= LOG_CHANNEL=stack diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index 37d20030..dd752e69 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -4,6 +4,7 @@ use App\Models\ItemPartialTransfer; use App\Models\Resource; +use App\Models\Transformers\ItemPartialTransfer as ItemPartialTransferTransformer; use App\Option\Get; use App\Option\Post; use App\Utilities\Header; @@ -66,19 +67,16 @@ public function index($resource_type_id): JsonResponse $headers = new Header(); $headers->collection($pagination, count($transfers), $total); - var_dump($transfers); - die; - - /*return response()->json( + return response()->json( array_map( - function($category) { - return (new CategoryTransformer($category))->toArray(); + function($transfer) { + return (new ItemPartialTransferTransformer($transfer))->toArray(); }, - $categories + $transfers ), 200, $headers->headers() - );*/ + ); } public function transfer( diff --git a/app/Models/ItemPartialTransfer.php b/app/Models/ItemPartialTransfer.php index 32e32180..5384da8f 100644 --- a/app/Models/ItemPartialTransfer.php +++ b/app/Models/ItemPartialTransfer.php @@ -42,7 +42,14 @@ public function paginatedCollection( $collection = $this->select( $this->table . '.id', $this->table . '.percentage', - $this->table . '.created_at' + $this->table . '.item_id', + $this->table . '.created_at', + 'from_resource.id AS from_resource_id', + 'from_resource.name AS from_resource_name', + 'to_resource.id AS to_resource_id', + 'to_resource.name AS to_resource_name', + 'users.id AS user_id', + 'users.name AS user_name' )-> join("resource_type",$this->table . ".resource_type_id","resource_type.id")-> join("resource AS from_resource",$this->table . ".from","from_resource.id")-> diff --git a/app/Models/Transformers/ItemPartialTransfer.php b/app/Models/Transformers/ItemPartialTransfer.php new file mode 100644 index 00000000..49227b5f --- /dev/null +++ b/app/Models/Transformers/ItemPartialTransfer.php @@ -0,0 +1,49 @@ + + * @copyright Dean Blackborough 2018-2020 + * @license https://github.com/costs-to-expect/api/blob/master/LICENSE + */ +class ItemPartialTransfer extends Transformer +{ + private $data_to_transform; + + public function __construct(array $data_to_transform) + { + parent::__construct(); + + $this->data_to_transform = $data_to_transform; + } + + public function toArray(): array + { + return [ + 'id' => $this->hash->itemPartialTransfer()->encode($this->data_to_transform['id']), + 'from' => [ + 'id' => $this->hash->resource()->encode($this->data_to_transform['from_resource_id']), + 'name' => $this->data_to_transform['from_resource_name'], + ], + 'to' => [ + 'id' => $this->hash->resource()->encode($this->data_to_transform['to_resource_id']), + 'name' => $this->data_to_transform['to_resource_name'], + ], + 'item' => [ + 'id' => $this->hash->item()->encode($this->data_to_transform['item_id']) + ], + 'percentage' => intval($this->data_to_transform['percentage']), + 'transferred' => [ + 'at' => $this->data_to_transform['created_at'], + 'user' => [ + 'id' => $this->hash->user()->encode($this->data_to_transform['user_id']), + 'name' => $this->data_to_transform['user_name'] + ] + ] + ]; + } +} diff --git a/app/Utilities/Hash.php b/app/Utilities/Hash.php index 09bcc8ce..5d43d64a 100644 --- a/app/Utilities/Hash.php +++ b/app/Utilities/Hash.php @@ -42,9 +42,12 @@ private function setUp() $this->hashers['resource'] = new Hashids($config['resource'], $min_length); $this->hashers['item'] = new Hashids($config['item'], $min_length); $this->hashers['item_category'] = new Hashids($config['item_category'], $min_length); - $this->hashers['item_sub_category'] = new Hashids($config['item_subcategory'], $min_length); + $this->hashers['item_partial_transfer'] = new Hashids($config['item_partial_transfer'], $min_length); + $this->hashers['item_subcategory'] = new Hashids($config['item_subcategory'], $min_length); + $this->hashers['item_transfer'] = new Hashids($config['item_transfer'], $min_length); $this->hashers['item_type'] = new Hashids($config['item_type'], $min_length); $this->hashers['permitted_user'] = new Hashids($config['permitted_user'], $min_length); + $this->hashers['user'] = new Hashids($config['user'], $min_length); } /** @@ -142,6 +145,16 @@ public function itemCategory(): Hashids return $this->hashers['item_category']; } + /** + * Helper method to return the item partial transfer hash object + * + * @return Hashids + */ + public function itemPartialTransfer(): Hashids + { + return $this->hashers['item_partial_transfer']; + } + /** * Helper method to return the item sub category hash object * @@ -149,11 +162,21 @@ public function itemCategory(): Hashids */ public function itemSubCategory(): Hashids { - return $this->hashers['item_sub_category']; + return $this->hashers['item_subcategory']; } /** - * Helper method to return the item type + * Helper method to return the item transfer hash object + * + * @return Hashids + */ + public function itemTransfer(): Hashids + { + return $this->hashers['item_transfer']; + } + + /** + * Helper method to return the item type object * * @return Hashids */ @@ -163,7 +186,7 @@ public function itemType(): Hashids } /** - * Helper method to return the permitted user + * Helper method to return the permitted user object * * @return Hashids */ @@ -171,4 +194,14 @@ public function permittedUser(): Hashids { return $this->hashers['permitted_user']; } + + /** + * Helper method to return the user object + * + * @return Hashids + */ + public function user(): Hashids + { + return $this->hashers['user']; + } } diff --git a/config/api/app/hashids.php b/config/api/app/hashids.php index 9163adae..9629171a 100644 --- a/config/api/app/hashids.php +++ b/config/api/app/hashids.php @@ -10,7 +10,10 @@ 'resource' => env('APP_HASH_SALT_RESOURCE'), 'item' => env('APP_HASH_SALT_ITEM'), 'item_category' => env('APP_HASH_SALT_ITEM_CATEGORY'), + 'item_partial_transfer' => env('APP_HASH_SALT_ITEM_PARTIAL_TRANSFER'), 'item_subcategory' => env('APP_HASH_SALT_ITEM_SUBCATEGORY'), + 'item_transfer' => env('APP_HASH_SALT_ITEM_TRANSFER'), 'item_type' => env('APP_HASH_SALT_ITEM_TYPE'), - 'permitted_user' => env('APP_HASH_SALT_PERMITTED_USER') + 'permitted_user' => env('APP_HASH_SALT_PERMITTED_USER'), + 'user' => env('APP_HASH_SALT_USER') ]; From 98e88b33e986516aebd064956a63864d1ec0104e Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Tue, 31 Mar 2020 15:03:42 +0100 Subject: [PATCH 13/22] View single item transfer - Added show for partial item transfer --- .../ItemPartialTransferController.php | 70 ++++++++++++++++++- .../Middleware/ConvertRouteParameters.php | 1 + app/Models/ItemPartialTransfer.php | 41 +++++++++++ resources/lang/en/entities.php | 1 + resources/lang/en/route-descriptions.php | 3 +- routes/api/public-routes.php | 10 +++ 6 files changed, 124 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index dd752e69..af74f781 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -79,6 +79,43 @@ function($transfer) { ); } + /** + * Return a single item partial transfer + * + * @param $resource_type_id + * @param $item_partial_transfer_id + * + * @return JsonResponse + */ + public function show( + $resource_type_id, + $item_partial_transfer_id + ): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $item_partial_transfer = (new ItemPartialTransfer())->single( + (int) $resource_type_id, + (int) $item_partial_transfer_id + ); + + if ($item_partial_transfer === null) { + UtilityResponse::notFound(trans('entities.item_partial_transfer')); + } + + $headers = new Header(); + $headers->item(); + + return response()->json( + (new ItemPartialTransferTransformer($item_partial_transfer))->toArray(), + 200, + $headers->headers() + ); + } + public function transfer( string $resource_type_id, string $resource_id, @@ -148,7 +185,7 @@ public function optionsIndex($resource_type_id): JsonResponse $get = Get::init()-> setPagination(true)-> setAuthenticationStatus($permissions['view'])-> - setDescription('route-descriptions.item_partial_transfer_GET')-> + setDescription('route-descriptions.item_partial_transfer_GET_index')-> option(); return $this->optionsResponse( @@ -157,6 +194,37 @@ public function optionsIndex($resource_type_id): JsonResponse ); } + /** + * Generate the OPTIONS request for a specific category + * + * @param $resource_type_id + * @param $category_id + * + * @return JsonResponse + */ + public function optionsShow($resource_type_id, $category_id): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $permissions = RoutePermission::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $get = Get::init()-> + setDescription('route-descriptions.item_partial_transfer_GET_show')-> + setAuthenticationStatus($permissions['view'])-> + option(); + + return $this->optionsResponse( + $get, + 200 + ); + } + public function optionsTransfer( string $resource_type_id, string $resource_id, diff --git a/app/Http/Middleware/ConvertRouteParameters.php b/app/Http/Middleware/ConvertRouteParameters.php index b7d2d3f3..5db95f80 100644 --- a/app/Http/Middleware/ConvertRouteParameters.php +++ b/app/Http/Middleware/ConvertRouteParameters.php @@ -35,6 +35,7 @@ public function handle($request, Closure $next) 'resource_id' => new Hashids($config['resource'], $min_length), 'item_id' => new Hashids($config['item'], $min_length), 'item_category_id' => new Hashids($config['item_category'], $min_length), + 'item_partial_transfer_id' => new Hashids($config['item_partial_transfer'], $min_length), 'item_subcategory_id' => new Hashids($config['item_subcategory'], $min_length), 'item_type_id' => new Hashids($config['item_type'], $min_length), ]; diff --git a/app/Models/ItemPartialTransfer.php b/app/Models/ItemPartialTransfer.php index 5384da8f..229b822b 100644 --- a/app/Models/ItemPartialTransfer.php +++ b/app/Models/ItemPartialTransfer.php @@ -70,6 +70,47 @@ public function paginatedCollection( return $collection->get()->toArray(); } + /** + * Return a single partial transfer + * + * @param integer $resource_type_id + * @param integer $item_partial_transfer_id + * + * @return array|null + */ + public function single( + int $resource_type_id, + int $item_partial_transfer_id + ): ?array + { + $result = $this->join("resource_type",$this->table . ".resource_type_id","resource_type.id")-> + join("resource AS from_resource",$this->table . ".from","from_resource.id")-> + join("resource AS to_resource",$this->table . ".to","to_resource.id")-> + join("item",$this->table . ".item_id","item.id")-> + join("users",$this->table . ".transferred_by","users.id")-> + where($this->table .'.resource_type_id', '=', $resource_type_id)-> + where($this->table .'.id', '=', $item_partial_transfer_id)-> + select( + $this->table . '.id', + $this->table . '.percentage', + $this->table . '.item_id', + $this->table . '.created_at', + 'from_resource.id AS from_resource_id', + 'from_resource.name AS from_resource_name', + 'to_resource.id AS to_resource_id', + 'to_resource.name AS to_resource_name', + 'users.id AS user_id', + 'users.name AS user_name' + )-> + first(); + + if ($result === null) { + return null; + } else { + return $result->toArray(); + } + } + /** * @param integer $resource_type_id * @param array $permitted_resource_types diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 063c3ae6..915480bf 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -9,6 +9,7 @@ 'subcategory' => 'Subcategory', 'item' => 'Item (Expense)', 'item-category' => 'Assigned Category', + 'item-partial-transfer' => 'Item Partial Transfer', 'item-subcategory' => 'Assigned Subcategory', 'item-type' => 'Item type' ]; diff --git a/resources/lang/en/route-descriptions.php b/resources/lang/en/route-descriptions.php index 8a2a469d..6315d176 100644 --- a/resources/lang/en/route-descriptions.php +++ b/resources/lang/en/route-descriptions.php @@ -55,7 +55,8 @@ 'item_transfer_POST' => 'Transfer an item to another resource', - 'item_partial_transfer_GET' => 'Return the partial transfers for the selected resource type', + 'item_partial_transfer_GET_index' => 'Return the partial transfers for the selected resource type', + 'item_partial_transfer_GET_show' => 'Return the requested partial transfer', 'item_partial_transfer_POST' => 'Portion a percentage of the total for an item to another resource', 'permitted_user_GET_index' => 'Return the permitted users', diff --git a/routes/api/public-routes.php b/routes/api/public-routes.php index c3e39c56..e320c716 100644 --- a/routes/api/public-routes.php +++ b/routes/api/public-routes.php @@ -134,6 +134,16 @@ function () { 'ItemPartialTransferController@optionsIndex' ); + Route::get( + 'resource-types/{resource_type_id}/partial-transfers/{item_partial_transfer_id}', + 'ItemPartialTransferController@show' + ); + + Route::options( + 'resource-types/{resource_type_id}/partial-transfers/{item_partial_transfer_id}', + 'ItemPartialTransferController@optionsShow' + ); + Route::get( 'resource-types/{resource_type_id}/permitted-users', 'PermittedUserController@index' From b13a0bf5b8aba1d81561dc9704a4d163edfbe9b8 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Tue, 31 Mar 2020 15:05:52 +0100 Subject: [PATCH 14/22] Fixed parameter and comments - Corrected an id - Corrected comments --- app/Http/Controllers/ItemPartialTransferController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index af74f781..1786e6e6 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -164,7 +164,7 @@ public function transfer( } /** - * Generate the OPTIONS request for the category list + * Generate the OPTIONS request for the partial transfers collection * * @param $resource_type_id * @@ -195,14 +195,14 @@ public function optionsIndex($resource_type_id): JsonResponse } /** - * Generate the OPTIONS request for a specific category + * Generate the OPTIONS request for a specific item partial transfer * * @param $resource_type_id - * @param $category_id + * @param $item_partial_transfer_id * * @return JsonResponse */ - public function optionsShow($resource_type_id, $category_id): JsonResponse + public function optionsShow($resource_type_id, $item_partial_transfer_id): JsonResponse { Route::resourceType( (int) $resource_type_id, From b319f4c5848c3ddaa64aa02f5fb5a39745716ce7 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Tue, 31 Mar 2020 16:05:34 +0100 Subject: [PATCH 15/22] Item transfer - Working on item transfer route --- .../Controllers/ItemTransferController.php | 226 +++++++++++++++--- .../Middleware/ConvertRouteParameters.php | 1 + app/Models/ItemPartialTransfer.php | 2 +- app/Models/ItemTransfer.php | 119 +++++++++ app/Models/Transformers/ItemTransfer.php | 48 ++++ resources/lang/en/entities.php | 1 + resources/lang/en/route-descriptions.php | 2 + routes/api/public-routes.php | 10 + 8 files changed, 372 insertions(+), 37 deletions(-) create mode 100644 app/Models/Transformers/ItemTransfer.php diff --git a/app/Http/Controllers/ItemTransferController.php b/app/Http/Controllers/ItemTransferController.php index 03dee1b9..3437bf5f 100644 --- a/app/Http/Controllers/ItemTransferController.php +++ b/app/Http/Controllers/ItemTransferController.php @@ -5,7 +5,11 @@ use App\Models\Item; use App\Models\ItemTransfer; use App\Models\Resource; +use App\Models\Transformers\ItemTransfer as ItemTransferTransformer; +use App\Option\Get; use App\Option\Post; +use App\Utilities\Header; +use App\Utilities\Pagination as UtilityPagination; use App\Utilities\Request as UtilityRequest; use App\Utilities\Response as UtilityResponse; use App\Utilities\RoutePermission; @@ -25,6 +29,192 @@ */ class ItemTransferController extends Controller { + /** + * Return the item transfers collection + * + * @param string $resource_type_id + * + * @return JsonResponse + */ + public function index($resource_type_id): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $total = (new ItemTransfer())->total( + (int) $resource_type_id, + $this->permitted_resource_types, + $this->include_public + ); + + $pagination = UtilityPagination::init( + request()->path(), + $total, + 10, + $this->allow_entire_collection + )-> + paging(); + + $transfers = (new ItemTransfer())->paginatedCollection( + (int) $resource_type_id, + $this->permitted_resource_types, + $this->include_public, + $pagination['offset'], + $pagination['limit'] + ); + + $headers = new Header(); + $headers->collection($pagination, count($transfers), $total); + + return response()->json( + array_map( + function($transfer) { + return (new ItemTransfer($transfer))->toArray(); + }, + $transfers + ), + 200, + $headers->headers() + ); + } + + /** + * Generate the OPTIONS request for the transfers collection + * + * @param $resource_type_id + * + * @return JsonResponse + */ + public function optionsIndex($resource_type_id): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $permissions = RoutePermission::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $get = Get::init()-> + setPagination(true)-> + setAuthenticationStatus($permissions['view'])-> + setDescription('route-descriptions.item_transfer_GET_index')-> + option(); + + return $this->optionsResponse( + $get, + 200 + ); + } + + /** + * Generate the OPTIONS request for a specific item transfer + * + * @param $resource_type_id + * @param $item_transfer_id + * + * @return JsonResponse + */ + public function optionsShow($resource_type_id, $item_transfer_id): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $permissions = RoutePermission::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $get = Get::init()-> + setDescription('route-descriptions.item_transfer_GET_show')-> + setAuthenticationStatus($permissions['view'])-> + option(); + + return $this->optionsResponse( + $get, + 200 + ); + } + + public function optionsTransfer( + string $resource_type_id, + string $resource_id, + string $item_id + ): JsonResponse + { + Route::item( + $resource_type_id, + $resource_id, + $item_id, + $this->permitted_resource_types + ); + + $permissions = RoutePermission::item( + $resource_type_id, + $resource_id, + $item_id, + $this->permitted_resource_types + ); + + $post = Post::init()-> + setFields('api.item-transfer.fields')-> + setFieldsData( + $this->fieldsData( + $resource_type_id, + $resource_id + ) + )-> + setDescription('route-descriptions.item_transfer_POST')-> + setAuthenticationStatus($permissions['manage'])-> + setAuthenticationRequired(true)-> + option(); + + return $this->optionsResponse($post, 200); + } + + /** + * Return a single item transfer + * + * @param $resource_type_id + * @param $item_transfer_id + * + * @return JsonResponse + */ + public function show( + $resource_type_id, + $item_transfer_id + ): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types + ); + + $item_transfer = (new ItemTransfer())->single( + (int) $resource_type_id, + (int) $item_transfer_id + ); + + if ($item_transfer === null) { + UtilityResponse::notFound(trans('entities.item_transfer')); + } + + $headers = new Header(); + $headers->item(); + + return response()->json( + (new ItemTransferTransformer($item_transfer))->toArray(), + 200, + $headers->headers() + ); + } + public function transfer( string $resource_type_id, string $resource_id, @@ -76,42 +266,6 @@ public function transfer( UtilityResponse::successNoContent(); } - public function optionsTransfer( - string $resource_type_id, - string $resource_id, - string $item_id - ): JsonResponse - { - Route::item( - $resource_type_id, - $resource_id, - $item_id, - $this->permitted_resource_types - ); - - $permissions = RoutePermission::item( - $resource_type_id, - $resource_id, - $item_id, - $this->permitted_resource_types - ); - - $post = Post::init()-> - setFields('api.item-transfer.fields')-> - setFieldsData( - $this->fieldsData( - $resource_type_id, - $resource_id - ) - )-> - setDescription('route-descriptions.item_transfer_POST')-> - setAuthenticationStatus($permissions['manage'])-> - setAuthenticationRequired(true)-> - option(); - - return $this->optionsResponse($post, 200); - } - /** * Generate any conditional POST parameters, will be merged with the * relevant config/api/[type]/fields.php data array diff --git a/app/Http/Middleware/ConvertRouteParameters.php b/app/Http/Middleware/ConvertRouteParameters.php index 5db95f80..92beeae8 100644 --- a/app/Http/Middleware/ConvertRouteParameters.php +++ b/app/Http/Middleware/ConvertRouteParameters.php @@ -37,6 +37,7 @@ public function handle($request, Closure $next) 'item_category_id' => new Hashids($config['item_category'], $min_length), 'item_partial_transfer_id' => new Hashids($config['item_partial_transfer'], $min_length), 'item_subcategory_id' => new Hashids($config['item_subcategory'], $min_length), + 'item_transfer_id' => new Hashids($config['item_transfer'], $min_length), 'item_type_id' => new Hashids($config['item_type'], $min_length), ]; diff --git a/app/Models/ItemPartialTransfer.php b/app/Models/ItemPartialTransfer.php index 229b822b..66883381 100644 --- a/app/Models/ItemPartialTransfer.php +++ b/app/Models/ItemPartialTransfer.php @@ -26,7 +26,7 @@ class ItemPartialTransfer extends Model * * @param integer $resource_type_id * @param array $permitted_resource_types - * @param boolean $include_public Should we include categories assigned to public resources + * @param boolean $include_public * @param integer $offset * @param integer $limit * diff --git a/app/Models/ItemTransfer.php b/app/Models/ItemTransfer.php index d1881dd1..05acdb79 100644 --- a/app/Models/ItemTransfer.php +++ b/app/Models/ItemTransfer.php @@ -3,6 +3,7 @@ namespace App\Models; +use App\Utilities\Model as ModelUtility; use Illuminate\Database\Eloquent\Builder as QueryBuilder; use Illuminate\Database\Eloquent\Model; @@ -19,4 +20,122 @@ class ItemTransfer extends Model protected $table = 'item_transfer'; protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Return the paginated collection + * + * @param integer $resource_type_id + * @param array $permitted_resource_types + * @param boolean $include_public + * @param integer $offset + * @param integer $limit + * + * @return array + */ + public function paginatedCollection( + int $resource_type_id, + array $permitted_resource_types, + bool $include_public, + int $offset = 0, + int $limit = 10 + ): array { + $collection = $this->select( + $this->table . '.id', + $this->table . '.item_id', + $this->table . '.created_at', + 'from_resource.id AS from_resource_id', + 'from_resource.name AS from_resource_name', + 'to_resource.id AS to_resource_id', + 'to_resource.name AS to_resource_name', + 'users.id AS user_id', + 'users.name AS user_name' + )-> + join("resource_type",$this->table . ".resource_type_id","resource_type.id")-> + join("resource AS from_resource",$this->table . ".from","from_resource.id")-> + join("resource AS to_resource",$this->table . ".to","to_resource.id")-> + join("item",$this->table . ".item_id","item.id")-> + join("users",$this->table . ".transferred_by","users.id")-> + where($this->table .'.resource_type_id', '=', $resource_type_id); + + $collection = ModelUtility::applyResourceTypeCollectionCondition( + $collection, + $permitted_resource_types, + $include_public + ); + + $collection->offset($offset); + $collection->limit($limit); + + return $collection->get()->toArray(); + } + + /** + * Return a single partial transfer + * + * @param integer $resource_type_id + * @param integer $item_partial_transfer_id + * + * @return array|null + */ + public function single( + int $resource_type_id, + int $item_partial_transfer_id + ): ?array + { + $result = $this->join("resource_type",$this->table . ".resource_type_id","resource_type.id")-> + join("resource AS from_resource",$this->table . ".from","from_resource.id")-> + join("resource AS to_resource",$this->table . ".to","to_resource.id")-> + join("item",$this->table . ".item_id","item.id")-> + join("users",$this->table . ".transferred_by","users.id")-> + where($this->table .'.resource_type_id', '=', $resource_type_id)-> + where($this->table .'.id', '=', $item_partial_transfer_id)-> + select( + $this->table . '.id', + $this->table . '.item_id', + $this->table . '.created_at', + 'from_resource.id AS from_resource_id', + 'from_resource.name AS from_resource_name', + 'to_resource.id AS to_resource_id', + 'to_resource.name AS to_resource_name', + 'users.id AS user_id', + 'users.name AS user_name' + )-> + first(); + + if ($result === null) { + return null; + } else { + return $result->toArray(); + } + } + + /** + * @param integer $resource_type_id + * @param array $permitted_resource_types + * @param boolean $include_public + * + * @return integer + */ + public function total( + int $resource_type_id, + array $permitted_resource_types, + bool $include_public + ): int + { + $collection = $this->select($this->table . '.id')-> + join("resource_type",$this->table . ".resource_type_id","resource_type.id")-> + join("resource AS from_resource",$this->table . ".from","from_resource.id")-> + join("resource AS to_resource",$this->table . ".to","to_resource.id")-> + join("item",$this->table . ".item_id","item.id")-> + join("users",$this->table . ".transferred_by","users.id")-> + where($this->table .'.resource_type_id', '=', $resource_type_id); + + $collection = ModelUtility::applyResourceTypeCollectionCondition( + $collection, + $permitted_resource_types, + $include_public + ); + + return $collection->count(); + } } diff --git a/app/Models/Transformers/ItemTransfer.php b/app/Models/Transformers/ItemTransfer.php new file mode 100644 index 00000000..9cca74ad --- /dev/null +++ b/app/Models/Transformers/ItemTransfer.php @@ -0,0 +1,48 @@ + + * @copyright Dean Blackborough 2018-2020 + * @license https://github.com/costs-to-expect/api/blob/master/LICENSE + */ +class ItemTransfer extends Transformer +{ + private $data_to_transform; + + public function __construct(array $data_to_transform) + { + parent::__construct(); + + $this->data_to_transform = $data_to_transform; + } + + public function toArray(): array + { + return [ + 'id' => $this->hash->itemPartialTransfer()->encode($this->data_to_transform['id']), + 'from' => [ + 'id' => $this->hash->resource()->encode($this->data_to_transform['from_resource_id']), + 'name' => $this->data_to_transform['from_resource_name'], + ], + 'to' => [ + 'id' => $this->hash->resource()->encode($this->data_to_transform['to_resource_id']), + 'name' => $this->data_to_transform['to_resource_name'], + ], + 'item' => [ + 'id' => $this->hash->item()->encode($this->data_to_transform['item_id']) + ], + 'transferred' => [ + 'at' => $this->data_to_transform['created_at'], + 'user' => [ + 'id' => $this->hash->user()->encode($this->data_to_transform['user_id']), + 'name' => $this->data_to_transform['user_name'] + ] + ] + ]; + } +} diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 915480bf..b56450a2 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -11,5 +11,6 @@ 'item-category' => 'Assigned Category', 'item-partial-transfer' => 'Item Partial Transfer', 'item-subcategory' => 'Assigned Subcategory', + 'item-transfer' => 'Item Transfer', 'item-type' => 'Item type' ]; diff --git a/resources/lang/en/route-descriptions.php b/resources/lang/en/route-descriptions.php index 6315d176..52cd3b05 100644 --- a/resources/lang/en/route-descriptions.php +++ b/resources/lang/en/route-descriptions.php @@ -53,6 +53,8 @@ 'item_sub_category_PATCH' => 'Update the subcategory assigned to the selected item', 'item_sub_category_DELETE' => 'Delete the subcategory assigned to the selected item', + 'item_transfer_GET_index' => 'Return the transfers for the selected resource type', + 'item_transfer_GET_show' => 'Return the requested transfer', 'item_transfer_POST' => 'Transfer an item to another resource', 'item_partial_transfer_GET_index' => 'Return the partial transfers for the selected resource type', diff --git a/routes/api/public-routes.php b/routes/api/public-routes.php index e320c716..f9f58b8f 100644 --- a/routes/api/public-routes.php +++ b/routes/api/public-routes.php @@ -244,6 +244,16 @@ function () { 'ItemSubcategoryController@optionsShow' ); + Route::options( + 'resource-types/{resource_type_id}/transfers', + 'ItemTransferController@optionsIndex' + ); + + Route::get( + 'resource-types/{resource_type_id}/transfers/{item_transfer_id}', + 'ItemTransferController@show' + ); + // Request access and error logs Route::options( 'request/error-log', From 8dc7af82022fec922637b18106dd6ebe25dc820c Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Wed, 1 Apr 2020 00:15:13 +0100 Subject: [PATCH 16/22] Refactoring - General review of some core classes. --- .../ItemPartialTransferController.php | 4 +- .../Controllers/ItemTransferController.php | 51 ++++++++++--------- app/Option/Delete.php | 12 ++--- app/Option/Get.php | 28 +++++----- app/Option/Patch.php | 16 +++--- app/Option/Post.php | 16 +++--- app/Utilities/General.php | 16 ++---- app/Utilities/Hash.php | 12 ++--- app/Utilities/Model.php | 3 ++ app/Utilities/Pagination.php | 32 ++++++------ app/Utilities/Request.php | 4 +- app/Utilities/Response.php | 32 ++++++------ app/Utilities/RoutePermission.php | 14 ++--- 13 files changed, 119 insertions(+), 121 deletions(-) diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index 1786e6e6..5df7dc72 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -69,7 +69,7 @@ public function index($resource_type_id): JsonResponse return response()->json( array_map( - function($transfer) { + static function($transfer) { return (new ItemPartialTransferTransformer($transfer))->toArray(); }, $transfers @@ -147,7 +147,7 @@ public function transfer( try { $partial_transfer = new ItemPartialTransfer([ 'resource_type_id' => $resource_type_id, - 'from' => intval($resource_id), + 'from' => (int) $resource_id, 'to' => $new_resource_id, 'item_id' => $item_id, 'percentage' => request()->input('percentage'), diff --git a/app/Http/Controllers/ItemTransferController.php b/app/Http/Controllers/ItemTransferController.php index 3437bf5f..37bd8dab 100644 --- a/app/Http/Controllers/ItemTransferController.php +++ b/app/Http/Controllers/ItemTransferController.php @@ -70,7 +70,7 @@ public function index($resource_type_id): JsonResponse return response()->json( array_map( - function($transfer) { + static function($transfer) { return (new ItemTransfer($transfer))->toArray(); }, $transfers @@ -100,10 +100,10 @@ public function optionsIndex($resource_type_id): JsonResponse ); $get = Get::init()-> - setPagination(true)-> - setAuthenticationStatus($permissions['view'])-> - setDescription('route-descriptions.item_transfer_GET_index')-> - option(); + setPagination(true)-> + setAuthenticationStatus($permissions['view'])-> + setDescription('route-descriptions.item_transfer_GET_index')-> + option(); return $this->optionsResponse( $get, @@ -132,9 +132,9 @@ public function optionsShow($resource_type_id, $item_transfer_id): JsonResponse ); $get = Get::init()-> - setDescription('route-descriptions.item_transfer_GET_show')-> - setAuthenticationStatus($permissions['view'])-> - option(); + setDescription('route-descriptions.item_transfer_GET_show')-> + setAuthenticationStatus($permissions['view'])-> + option(); return $this->optionsResponse( $get, @@ -163,17 +163,17 @@ public function optionsTransfer( ); $post = Post::init()-> - setFields('api.item-transfer.fields')-> - setFieldsData( - $this->fieldsData( - $resource_type_id, - $resource_id - ) - )-> - setDescription('route-descriptions.item_transfer_POST')-> - setAuthenticationStatus($permissions['manage'])-> - setAuthenticationRequired(true)-> - option(); + setFields('api.item-transfer.fields')-> + setFieldsData( + $this->fieldsData( + $resource_type_id, + $resource_id + ) + )-> + setDescription('route-descriptions.item_transfer_POST')-> + setAuthenticationStatus($permissions['manage'])-> + setAuthenticationRequired(true)-> + option(); return $this->optionsResponse($post, 200); } @@ -245,12 +245,16 @@ public function transfer( } $item = (new Item())->instance($resource_type_id, $resource_id, $item_id); - $item->resource_id = $new_resource_id; - $item->save(); + if ($item !== null) { + $item->resource_id = $new_resource_id; + $item->save(); + } else { + UtilityResponse::failedToSelectModelForUpdate(); + } $item_transfer = new ItemTransfer([ 'resource_type_id' => $resource_type_id, - 'from' => intval($resource_id), + 'from' => (int) $resource_id, 'to' => $new_resource_id, 'item_id' => $item_id, 'transferred_by' => Auth::user()->id @@ -262,8 +266,7 @@ public function transfer( UtilityResponse::failedToSaveModelForUpdate(); } - // Endpoint should 404 after request so figure 204 better than redirect or 404 - UtilityResponse::successNoContent(); + return UtilityResponse::successNoContent(); } /** diff --git a/app/Option/Delete.php b/app/Option/Delete.php index 70a20392..4be252fc 100644 --- a/app/Option/Delete.php +++ b/app/Option/Delete.php @@ -13,7 +13,7 @@ */ class Delete extends Option { - static private function reset() + private static function reset(): void { self::resetBase(); @@ -21,20 +21,20 @@ static private function reset() self::$description = null; } - static public function init(): Delete + public static function init(): Delete { - self::$instance = new Delete(); - self::$instance->reset(); + self::$instance = new self(); + self::$instance::reset(); return self::$instance; } - static protected function build() + protected static function build() { // Not necessary for this simple Option } - static public function option(): array + public static function option(): array { return [ 'DELETE' => [ diff --git a/app/Option/Get.php b/app/Option/Get.php index 55b93f5a..f5192a58 100644 --- a/app/Option/Get.php +++ b/app/Option/Get.php @@ -70,9 +70,9 @@ class Get extends Option */ static private $sortable_parameters; - static private function reset() + private static function reset(): void { - self::resetBase();; + self::resetBase(); self::$localised_parameters = []; @@ -89,15 +89,15 @@ static private function reset() self::$sortable_parameters = []; } - static public function init(): Get + public static function init(): Get { - self::$instance = new Get(); - self::$instance->reset(); + self::$instance = new self(); + self::$instance::reset(); return self::$instance; } - static public function setFilterable( + public static function setFilterable( string $config_path ): Get { @@ -110,7 +110,7 @@ static public function setFilterable( return self::$instance; } - static public function setPagination( + public static function setPagination( bool $status = false ): Get { @@ -121,7 +121,7 @@ static public function setPagination( return self::$instance; } - static public function setPaginationOverride( + public static function setPaginationOverride( bool $status = false ): Get { @@ -132,7 +132,7 @@ static public function setPaginationOverride( return self::$instance; } - static public function setParameters( + public static function setParameters( string $config_path ): Get { @@ -141,7 +141,7 @@ static public function setParameters( return self::$instance; } - static public function setParametersData( + public static function setParametersData( array $parameters = [] ): Get { @@ -150,7 +150,7 @@ static public function setParametersData( return self::$instance; } - static public function setSearchable( + public static function setSearchable( string $config_path ): Get { @@ -163,7 +163,7 @@ static public function setSearchable( return self::$instance; } - static public function setSortable( + public static function setSortable( string $config_path ): Get { @@ -176,7 +176,7 @@ static public function setSortable( return self::$instance; } - static protected function build() + protected static function build() { self::$localised_parameters = []; @@ -198,7 +198,7 @@ static protected function build() } } - static public function option(): array + public static function option(): array { self::build(); diff --git a/app/Option/Patch.php b/app/Option/Patch.php index 9599f6fd..706c1d20 100644 --- a/app/Option/Patch.php +++ b/app/Option/Patch.php @@ -30,7 +30,7 @@ class Patch extends Option */ static private $fields; - static private function reset() + private static function reset(): void { self::resetBase(); @@ -39,16 +39,16 @@ static private function reset() self::$localised_fields = []; } - static public function init(): Patch + public static function init(): Patch { - self::$instance = new Patch(); - self::$instance->reset(); + self::$instance = new self(); + self::$instance::reset(); return self::$instance; } - static public function setFieldsData( + public static function setFieldsData( array $fields = [] ): Patch { @@ -57,7 +57,7 @@ static public function setFieldsData( return self::$instance; } - static public function setFields( + public static function setFields( string $config_path ): Patch { @@ -65,7 +65,7 @@ static public function setFields( return self::$instance; } - static protected function build() + protected static function build() { self::$localised_fields = []; @@ -84,7 +84,7 @@ static protected function build() } } - static public function option(): array + public static function option(): array { self::build(); diff --git a/app/Option/Post.php b/app/Option/Post.php index 9e491118..61d07d76 100644 --- a/app/Option/Post.php +++ b/app/Option/Post.php @@ -30,7 +30,7 @@ class Post extends Option */ static private $localised_fields; - static private function reset() + private static function reset(): void { self::resetBase(); @@ -39,15 +39,15 @@ static private function reset() self::$localised_fields = []; } - static public function init(): Post + public static function init(): Post { - self::$instance = new Post(); - self::$instance->reset(); + self::$instance = new self(); + self::$instance::reset(); return self::$instance; } - static public function setFieldsData( + public static function setFieldsData( array $parameters = [] ): Post { @@ -56,7 +56,7 @@ static public function setFieldsData( return self::$instance; } - static public function setFields( + public static function setFields( string $config_path ): Post { @@ -65,7 +65,7 @@ static public function setFields( return self::$instance; } - static protected function build() + protected static function build() { self::$localised_fields = []; @@ -83,7 +83,7 @@ static protected function build() } } - static public function option(): array + public static function option(): array { self::build(); diff --git a/app/Utilities/General.php b/app/Utilities/General.php index 239221b9..2996201f 100644 --- a/app/Utilities/General.php +++ b/app/Utilities/General.php @@ -22,13 +22,9 @@ class General * * @return bool */ - static public function booleanValue($value): bool + public static function booleanValue($value): bool { - if (filter_var($value, FILTER_VALIDATE_BOOLEAN) === true) { - return true; - } - - return false; + return filter_var($value, FILTER_VALIDATE_BOOLEAN) === true; } /** @@ -40,14 +36,10 @@ static public function booleanValue($value): bool * * @return bool */ - static public function isBooleanValue($value): bool + public static function isBooleanValue($value): bool { $filtered = filter_var($value, FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE); - if ($filtered === true || $filtered === false) { - return true; - } - - return false; + return $filtered === true || $filtered === false; } } diff --git a/app/Utilities/Hash.php b/app/Utilities/Hash.php index 5d43d64a..fd6530db 100644 --- a/app/Utilities/Hash.php +++ b/app/Utilities/Hash.php @@ -60,9 +60,9 @@ public function encode(string $type, int $parameter) { if (array_key_exists($type, $this->hashers) === true) { return $this->hashers[$type]->encode($parameter); - } else { - return false; } + + return false; } /** @@ -76,13 +76,13 @@ public function decode(string $type, string $parameter) if (array_key_exists($type, $this->hashers) === true) { $id = $this->hashers[$type]->decode($parameter); if (is_array($id) && array_key_exists(0, $id)) { - return intval($id[0]); - } else { - return false; + return (int) $id[0]; } - } else { + return false; } + + return false; } /** diff --git a/app/Utilities/Model.php b/app/Utilities/Model.php index 50592c1e..90ca25d1 100644 --- a/app/Utilities/Model.php +++ b/app/Utilities/Model.php @@ -3,6 +3,8 @@ namespace App\Utilities; +use Illuminate\Database\Query\Builder as QueryBuilder; + /** * Model helper class * @@ -10,6 +12,7 @@ * they gain more than a few functions and the creation of a library makes * sense. * + * @mixin QueryBuilder * @author Dean Blackborough * @copyright Dean Blackborough 2018-2020 * @license https://github.com/costs-to-expect/api/blob/master/LICENSE diff --git a/app/Utilities/Pagination.php b/app/Utilities/Pagination.php index 9c6bf21b..de700ad3 100644 --- a/app/Utilities/Pagination.php +++ b/app/Utilities/Pagination.php @@ -18,7 +18,7 @@ */ class Pagination { - private static $instance = null; + private static $instance; /** * @var array @@ -79,7 +79,7 @@ public static function init( ): Pagination { if (self::$instance === null) { - self::$instance = new Pagination; + self::$instance = new self; } self::$parameters = []; @@ -153,13 +153,13 @@ public static function paging(): array 'offset' => self::$offset, 'limit' => self::$limit ]; - } else { - return [ - 'links' => $pagination_uris, - 'offset' => 0, - 'limit' => self::$total - ]; } + + return [ + 'links' => $pagination_uris, + 'offset' => 0, + 'limit' => self::$total + ]; } /** @@ -173,7 +173,7 @@ private static function processParameters(): string if (count(self::$parameters) > 0) { foreach (self::$parameters as $parameter => $parameter_value) { if ($parameter_value !== null) { - if (strlen($parameters) > 0) { + if ($parameters !== '') { $parameters .= '&'; } @@ -192,7 +192,7 @@ private static function processParameters(): string } } - if (strlen($parameters) > 0) { + if ($parameters !== '') { $parameters .= '&'; } @@ -204,14 +204,14 @@ private static function processParameters(): string * * @return string */ - private static function processSortParameters() + private static function processSortParameters(): string { $sort_parameters = ''; foreach (self::$sort_parameters as $field => $order) { $sort_parameters .= '|' . $field . ':' . $order; } - if (strlen($sort_parameters) > 0) { + if ($sort_parameters !== '') { $sort_parameters = 'sort=' . ltrim($sort_parameters, '|') . '&'; } @@ -223,14 +223,14 @@ private static function processSortParameters() * * @return string */ - private static function processSearchParameters() + private static function processSearchParameters(): string { $search_parameters = ''; foreach (self::$search_parameters as $field => $partial_term) { $search_parameters .= '|' . $field . ':' . urlencode($partial_term); } - if (strlen($search_parameters) > 0) { + if ($search_parameters !== '') { $search_parameters = 'search=' . ltrim($search_parameters, '|') . '&'; } @@ -244,8 +244,8 @@ private static function processSearchParameters() */ private static function render(): array { - self::$offset = intval(request()->query('offset', 0)); - self::$limit = intval(request()->query('limit', self::$limit)); + self::$offset = (int) request()->query('offset', 0); + self::$limit = (int) request()->query('limit', self::$limit); if (self::$allow_override === true) { self::$collection = General::booleanValue(request()->query('collection', false)); } diff --git a/app/Utilities/Request.php b/app/Utilities/Request.php index 13439a67..3ef77717 100644 --- a/app/Utilities/Request.php +++ b/app/Utilities/Request.php @@ -33,7 +33,7 @@ public static function checkForInvalidFields(array $patchable_fields): ?JsonResp { $invalid_fields = []; foreach (request()->all() as $key => $value) { - if (in_array($key, $patchable_fields) === false) { + if (in_array($key, $patchable_fields, true) === false) { $invalid_fields[] = $key; } } @@ -54,7 +54,7 @@ public static function checkForInvalidFields(array $patchable_fields): ?JsonResp public static function checkForEmptyPatch(): ?JsonResponse { if (count(request()->all()) === 0) { - return UtilityResponse::nothingToPatch();; + return UtilityResponse::nothingToPatch(); } return null; diff --git a/app/Utilities/Response.php b/app/Utilities/Response.php index b2cacdd2..b59b0394 100644 --- a/app/Utilities/Response.php +++ b/app/Utilities/Response.php @@ -23,9 +23,9 @@ class Response { - static protected function addException(array $response, ?Exception $e = null): array + protected static function addException(array $response, ?Exception $e = null): array { - if (App::environment() !== 'production' && $e !== null) { + if ($e !== null && App::environment() !== 'production') { $response['exception'] = [ 'message' => $e->getMessage(), 'file' => $e->getFile(), @@ -45,7 +45,7 @@ static protected function addException(array $response, ?Exception $e = null): a * * @return JsonResponse */ - static public function notFound(?string $type = null, ?Exception $e = null): JsonResponse + public static function notFound(?string $type = null, ?Exception $e = null): JsonResponse { $response = [ 'message' => ($type !== null) ? trans('responses.not-found-entity', ['type'=>$type]) : @@ -71,7 +71,7 @@ static public function notFound(?string $type = null, ?Exception $e = null): Jso * * @return JsonResponse */ - static public function notFoundOrNotAccessible(?string $type = null, ?Exception $e = null): JsonResponse + public static function notFoundOrNotAccessible(?string $type = null, ?Exception $e = null): JsonResponse { $response = [ 'message' => ($type !== null) ? trans('responses.not-found-or-not-accessible-entity', ['type'=>$type]) : @@ -97,7 +97,7 @@ static public function notFoundOrNotAccessible(?string $type = null, ?Exception * * @return JsonResponse */ - static public function foreignKeyConstraintError($message = '', ?Exception $e = null): JsonResponse + public static function foreignKeyConstraintError($message = '', ?Exception $e = null): JsonResponse { $response = [ 'message' => (strlen($message) > 0) ? $message : trans('responses.constraint') @@ -124,7 +124,7 @@ static public function foreignKeyConstraintError($message = '', ?Exception $e = * * @return JsonResponse */ - static public function failedToSelectModelForUpdate(?Exception $e = null): JsonResponse + public static function failedToSelectModelForUpdate(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.model-select-failure'), @@ -151,7 +151,7 @@ static public function failedToSelectModelForUpdate(?Exception $e = null): JsonR * * @return JsonResponse */ - static public function failedToSaveModelForUpdate(?Exception $e = null): JsonResponse + public static function failedToSaveModelForUpdate(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.model-save-failure-update'), @@ -175,7 +175,7 @@ static public function failedToSaveModelForUpdate(?Exception $e = null): JsonRes * * @return JsonResponse */ - static public function authenticationRequired(?Exception $e = null): JsonResponse + public static function authenticationRequired(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.authentication-required') @@ -202,7 +202,7 @@ static public function authenticationRequired(?Exception $e = null): JsonRespons * * @return JsonResponse */ - static public function failedToSaveModelForCreate(?Exception $e = null): JsonResponse + public static function failedToSaveModelForCreate(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.model-save-failure-create'), @@ -227,7 +227,7 @@ static public function failedToSaveModelForCreate(?Exception $e = null): JsonRes * * @return JsonResponse */ - static public function unableToDecode(?Exception $e = null): JsonResponse + public static function unableToDecode(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.decode-error') @@ -251,7 +251,7 @@ static public function unableToDecode(?Exception $e = null): JsonResponse * * @return JsonResponse */ - static public function successNoContent(?Exception $e = null): JsonResponse + public static function successNoContent(?Exception $e = null): JsonResponse { $response = []; @@ -271,7 +271,7 @@ static public function successNoContent(?Exception $e = null): JsonResponse * * @return JsonResponse */ - static public function successEmptyContent(bool $array = false, ?Exception $e = null): JsonResponse + public static function successEmptyContent(bool $array = false, ?Exception $e = null): JsonResponse { $response = ($array === true ? [] : null); @@ -290,7 +290,7 @@ static public function successEmptyContent(bool $array = false, ?Exception $e = * * @return JsonResponse */ - static public function nothingToPatch(?Exception $e = null) + public static function nothingToPatch(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.patch-empty') @@ -315,7 +315,7 @@ static public function nothingToPatch(?Exception $e = null) * * @return JsonResponse */ - static public function invalidFieldsInRequest(array $invalid_fields, ?Exception $e = null): JsonResponse + public static function invalidFieldsInRequest(array $invalid_fields, ?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.patch-invalid'), @@ -340,7 +340,7 @@ static public function invalidFieldsInRequest(array $invalid_fields, ?Exception * * @return JsonResponse */ - static public function maintenance(?Exception $e = null): JsonResponse + public static function maintenance(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.maintenance') @@ -365,7 +365,7 @@ static public function maintenance(?Exception $e = null): JsonResponse * * @return JsonResponse */ - static public function validationErrors(array $validation_errors, ?Exception $e = null): JsonResponse + public static function validationErrors(array $validation_errors, ?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.validation'), diff --git a/app/Utilities/RoutePermission.php b/app/Utilities/RoutePermission.php index 5570d6cd..9f14958c 100644 --- a/app/Utilities/RoutePermission.php +++ b/app/Utilities/RoutePermission.php @@ -30,7 +30,7 @@ class RoutePermission * * @return array Two indexes, view and manage, values for both boolean */ - static public function category( + public static function category( $resource_type_id, $category_id, array $permitted_resource_types @@ -62,7 +62,7 @@ static public function category( * * @return array Two indexes, view and manage, values for both boolean */ - static public function subcategory( + public static function subcategory( $resource_type_id, $category_id, $subcategory_id, @@ -94,7 +94,7 @@ static public function subcategory( * * @return array Two indexes, view and manage, values for both boolean */ - static public function resourceType( + public static function resourceType( $resource_type_id, array $permitted_resource_types ): array @@ -121,7 +121,7 @@ static public function resourceType( * * @return array Two indexes, view and manage, values for both boolean */ - static public function resource( + public static function resource( $resource_type_id, $resource_id, array $permitted_resource_types @@ -152,7 +152,7 @@ static public function resource( * * @return array Two indexes, view and manage, values for both boolean */ - static public function item( + public static function item( $resource_type_id, $resource_id, $item_id, @@ -187,7 +187,7 @@ static public function item( * * @return array Two indexes, view and manage, values for both boolean */ - static public function itemCategory( + public static function itemCategory( $resource_type_id, $resource_id, $item_id, @@ -226,7 +226,7 @@ static public function itemCategory( * * @return array Two indexes, view and manage, values for both boolean */ - static public function itemSubcategory( + public static function itemSubcategory( $resource_type_id, $resource_id, $item_id, From 1a40095d38b9a11e560c21b2f780328eef240626 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Wed, 1 Apr 2020 00:42:34 +0100 Subject: [PATCH 17/22] Item transfers - Transfers fixes --- app/Http/Controllers/ItemTransferController.php | 14 +++++++------- app/Models/Transformers/ItemTransfer.php | 2 +- resources/lang/en/route-descriptions.php | 4 ++-- routes/api/public-routes.php | 10 ++++++++++ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/ItemTransferController.php b/app/Http/Controllers/ItemTransferController.php index 37bd8dab..80ce8b0c 100644 --- a/app/Http/Controllers/ItemTransferController.php +++ b/app/Http/Controllers/ItemTransferController.php @@ -50,12 +50,12 @@ public function index($resource_type_id): JsonResponse ); $pagination = UtilityPagination::init( - request()->path(), - $total, - 10, - $this->allow_entire_collection - )-> - paging(); + request()->path(), + $total, + 10, + $this->allow_entire_collection + )-> + paging(); $transfers = (new ItemTransfer())->paginatedCollection( (int) $resource_type_id, @@ -71,7 +71,7 @@ public function index($resource_type_id): JsonResponse return response()->json( array_map( static function($transfer) { - return (new ItemTransfer($transfer))->toArray(); + return (new ItemTransferTransformer($transfer))->toArray(); }, $transfers ), diff --git a/app/Models/Transformers/ItemTransfer.php b/app/Models/Transformers/ItemTransfer.php index 9cca74ad..30217cec 100644 --- a/app/Models/Transformers/ItemTransfer.php +++ b/app/Models/Transformers/ItemTransfer.php @@ -24,7 +24,7 @@ public function __construct(array $data_to_transform) public function toArray(): array { return [ - 'id' => $this->hash->itemPartialTransfer()->encode($this->data_to_transform['id']), + 'id' => $this->hash->itemTransfer()->encode($this->data_to_transform['id']), 'from' => [ 'id' => $this->hash->resource()->encode($this->data_to_transform['from_resource_id']), 'name' => $this->data_to_transform['from_resource_name'], diff --git a/resources/lang/en/route-descriptions.php b/resources/lang/en/route-descriptions.php index 52cd3b05..4ef4c92e 100644 --- a/resources/lang/en/route-descriptions.php +++ b/resources/lang/en/route-descriptions.php @@ -54,11 +54,11 @@ 'item_sub_category_DELETE' => 'Delete the subcategory assigned to the selected item', 'item_transfer_GET_index' => 'Return the transfers for the selected resource type', - 'item_transfer_GET_show' => 'Return the requested transfer', + 'item_transfer_GET_show' => 'Return the selected transfer', 'item_transfer_POST' => 'Transfer an item to another resource', 'item_partial_transfer_GET_index' => 'Return the partial transfers for the selected resource type', - 'item_partial_transfer_GET_show' => 'Return the requested partial transfer', + 'item_partial_transfer_GET_show' => 'Return the selected partial transfer', 'item_partial_transfer_POST' => 'Portion a percentage of the total for an item to another resource', 'permitted_user_GET_index' => 'Return the permitted users', diff --git a/routes/api/public-routes.php b/routes/api/public-routes.php index f9f58b8f..a27ca7f7 100644 --- a/routes/api/public-routes.php +++ b/routes/api/public-routes.php @@ -249,6 +249,16 @@ function () { 'ItemTransferController@optionsIndex' ); + Route::get( + 'resource-types/{resource_type_id}/transfers', + 'ItemTransferController@index' + ); + + Route::options( + 'resource-types/{resource_type_id}/transfers/{item_transfer_id}', + 'ItemTransferController@optionsShow' + ); + Route::get( 'resource-types/{resource_type_id}/transfers/{item_transfer_id}', 'ItemTransferController@show' From 1ccb72c537eb8a0b5972847066e981b17c2add3d Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Wed, 1 Apr 2020 11:51:19 +0100 Subject: [PATCH 18/22] Renamed method - Renamed a response method as it is used for patch and delete. --- app/Http/Controllers/CategoryController.php | 2 +- app/Http/Controllers/ItemController.php | 2 +- app/Http/Controllers/ItemTransferController.php | 2 +- app/Http/Controllers/ResourceController.php | 2 +- app/Http/Controllers/ResourceTypeController.php | 2 +- app/Http/Controllers/SubcategoryController.php | 2 +- app/Utilities/Response.php | 4 ++-- resources/lang/en/route-descriptions.php | 3 ++- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php index d8c395cc..ca57edb4 100644 --- a/app/Http/Controllers/CategoryController.php +++ b/app/Http/Controllers/CategoryController.php @@ -337,7 +337,7 @@ public function update($resource_type_id, $category_id): JsonResponse $category = (new Category())->instance($category_id); if ($category === null) { - UtilityResponse::failedToSelectModelForUpdate(); + UtilityResponse::failedToSelectModelForUpdateOrDelete(); } UtilityRequest::checkForEmptyPatch(); diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index ea520ba6..9618b590 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -402,7 +402,7 @@ public function update( $item_type = $item_interface->instance((int) $item_id); if ($item === null || $item_type === null) { - UtilityResponse::failedToSelectModelForUpdate(); + UtilityResponse::failedToSelectModelForUpdateOrDelete(); } try { diff --git a/app/Http/Controllers/ItemTransferController.php b/app/Http/Controllers/ItemTransferController.php index 80ce8b0c..6ffcf66e 100644 --- a/app/Http/Controllers/ItemTransferController.php +++ b/app/Http/Controllers/ItemTransferController.php @@ -249,7 +249,7 @@ public function transfer( $item->resource_id = $new_resource_id; $item->save(); } else { - UtilityResponse::failedToSelectModelForUpdate(); + UtilityResponse::failedToSelectModelForUpdateOrDelete(); } $item_transfer = new ItemTransfer([ diff --git a/app/Http/Controllers/ResourceController.php b/app/Http/Controllers/ResourceController.php index eccd1b79..8bc0e175 100644 --- a/app/Http/Controllers/ResourceController.php +++ b/app/Http/Controllers/ResourceController.php @@ -327,7 +327,7 @@ public function update( $resource = (new Resource())->instance($resource_type_id, $resource_id); if ($resource === null) { - UtilityResponse::failedToSelectModelForUpdate(); + UtilityResponse::failedToSelectModelForUpdateOrDelete(); } UtilityRequest::checkForEmptyPatch(); diff --git a/app/Http/Controllers/ResourceTypeController.php b/app/Http/Controllers/ResourceTypeController.php index 97a469b9..e2a96990 100644 --- a/app/Http/Controllers/ResourceTypeController.php +++ b/app/Http/Controllers/ResourceTypeController.php @@ -327,7 +327,7 @@ public function update( $resource_type = (new ResourceType())->instance($resource_type_id); if ($resource_type === null) { - UtilityResponse::failedToSelectModelForUpdate(); + UtilityResponse::failedToSelectModelForUpdateOrDelete(); } UtilityRequest::checkForEmptyPatch(); diff --git a/app/Http/Controllers/SubcategoryController.php b/app/Http/Controllers/SubcategoryController.php index a78a7456..511e32a1 100644 --- a/app/Http/Controllers/SubcategoryController.php +++ b/app/Http/Controllers/SubcategoryController.php @@ -352,7 +352,7 @@ public function update( $subcategory = (new Subcategory())->instance($category_id, $subcategory_id); if ($subcategory === null) { - UtilityResponse::failedToSelectModelForUpdate(); + UtilityResponse::failedToSelectModelForUpdateOrDelete(); } UtilityRequest::checkForEmptyPatch(); diff --git a/app/Utilities/Response.php b/app/Utilities/Response.php index b59b0394..eee715d9 100644 --- a/app/Utilities/Response.php +++ b/app/Utilities/Response.php @@ -115,7 +115,7 @@ public static function foreignKeyConstraintError($message = '', ?Exception $e = } /** - * 500 error, unable to select the data ready to update + * 500 error, unable to select the data ready to enable us to update or delete * * Until we add logging this is an unknown server error, later we will * add MySQL error logging @@ -124,7 +124,7 @@ public static function foreignKeyConstraintError($message = '', ?Exception $e = * * @return JsonResponse */ - public static function failedToSelectModelForUpdate(?Exception $e = null): JsonResponse + public static function failedToSelectModelForUpdateOrDelete(?Exception $e = null): JsonResponse { $response = [ 'message' => trans('responses.model-select-failure'), diff --git a/resources/lang/en/route-descriptions.php b/resources/lang/en/route-descriptions.php index 4ef4c92e..79ab8357 100644 --- a/resources/lang/en/route-descriptions.php +++ b/resources/lang/en/route-descriptions.php @@ -59,7 +59,8 @@ 'item_partial_transfer_GET_index' => 'Return the partial transfers for the selected resource type', 'item_partial_transfer_GET_show' => 'Return the selected partial transfer', - 'item_partial_transfer_POST' => 'Portion a percentage of the total for an item to another resource', + 'item_partial_transfer_POST' => 'Reassign a percentage of the total for an item to another resource', + 'item_partial_transfer_DELETE' => 'Delete the selected partial transfer', 'permitted_user_GET_index' => 'Return the permitted users', 'permitted_user_POST' => 'Assign a permitted user', From 89a157e2101d46e86cad055a3ca60aed4f0e73bd Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Wed, 1 Apr 2020 11:56:50 +0100 Subject: [PATCH 19/22] Delete partial transfers - Added a delete endpoint for partial transfers --- .../ItemPartialTransferController.php | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index 5df7dc72..dfcd7763 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -5,6 +5,7 @@ use App\Models\ItemPartialTransfer; use App\Models\Resource; use App\Models\Transformers\ItemPartialTransfer as ItemPartialTransferTransformer; +use App\Option\Delete; use App\Option\Get; use App\Option\Post; use App\Utilities\Header; @@ -79,6 +80,41 @@ static function($transfer) { ); } + /** + * Delete the requested partial transfer + * + * @param $resource_type_id + * @param $item_partial_transfer_id + * + * @return JsonResponse + */ + public function delete( + $resource_type_id, + $item_partial_transfer_id + ): JsonResponse + { + Route::resourceType( + (int) $resource_type_id, + $this->permitted_resource_types, + true + ); + + try { + $partial_transfer = (new ItemPartialTransfer())->find($item_partial_transfer_id); + + if ($partial_transfer !== null) { + $partial_transfer->delete(); + return UtilityResponse::successNoContent(); + } + + return UtilityResponse::failedToSelectModelForUpdateOrDelete(); + } catch (QueryException $e) { + return UtilityResponse::foreignKeyConstraintError(); + } catch (Exception $e) { + return UtilityResponse::notFound(trans('entities.item-partial-transfer'), $e); + } + } + /** * Return a single item partial transfer * @@ -215,12 +251,18 @@ public function optionsShow($resource_type_id, $item_partial_transfer_id): JsonR ); $get = Get::init()-> - setDescription('route-descriptions.item_partial_transfer_GET_show')-> - setAuthenticationStatus($permissions['view'])-> - option(); + setDescription('route-descriptions.item_partial_transfer_GET_show')-> + setAuthenticationStatus($permissions['view'])-> + option(); + + $delete = Delete::init()-> + setAuthenticationRequired(true)-> + setAuthenticationStatus($permissions['manage'])-> + setDescription('route-descriptions.item_partial_transfer_DELETE')-> + option(); return $this->optionsResponse( - $get, + $get + $delete, 200 ); } From 6f6a3c2dae01bbf81b30337a65f77f32c377bbe5 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Wed, 1 Apr 2020 15:28:58 +0100 Subject: [PATCH 20/22] Minor fixes - Remove commented out try/catch - Transfer and Partial transfer should return a 201, not a 204. --- app/Http/Controllers/CategoryController.php | 8 ++++---- .../ItemPartialTransferController.php | 19 ++++++++++++++++--- .../Controllers/ItemTransferController.php | 8 ++++---- ...29_124056_create_item_partial_transfer.php | 10 +++++----- ...2020_03_31_103855_create_item_transfer.php | 10 +++++----- routes/api/private-routes.php | 5 +++++ 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php index ca57edb4..09823cf8 100644 --- a/app/Http/Controllers/CategoryController.php +++ b/app/Http/Controllers/CategoryController.php @@ -269,16 +269,16 @@ public function create($resource_type_id): JsonResponse ]); UtilityRequest::validateAndReturnErrors($validator); - //try { + try { $category = new Category([ 'name' => request()->input('name'), 'description' => request()->input('description'), 'resource_type_id' => $resource_type_id ]); $category->save(); - //} catch (Exception $e) { - // UtilityResponse::failedToSaveModelForCreate(); - //} + } catch (Exception $e) { + UtilityResponse::failedToSaveModelForCreate(); + } return response()->json( (new CategoryTransformer((new Category)->instanceToArray($category)))->toArray(), diff --git a/app/Http/Controllers/ItemPartialTransferController.php b/app/Http/Controllers/ItemPartialTransferController.php index dfcd7763..20638202 100644 --- a/app/Http/Controllers/ItemPartialTransferController.php +++ b/app/Http/Controllers/ItemPartialTransferController.php @@ -19,6 +19,7 @@ use Illuminate\Database\QueryException; use Illuminate\Http\JsonResponse; use Illuminate\Support\Facades\Auth; +use Monolog\Utils; /** * Partial transfer of items @@ -191,12 +192,24 @@ public function transfer( ]); $partial_transfer->save(); } catch (QueryException $e) { - UtilityResponse::foreignKeyConstraintError(); + return UtilityResponse::foreignKeyConstraintError(); } catch (Exception $e) { - UtilityResponse::failedToSaveModelForCreate(); + return UtilityResponse::failedToSaveModelForCreate(); } - return UtilityResponse::successNoContent(); + $item_partial_transfer = (new ItemPartialTransfer())->single( + (int) $resource_type_id, + (int) $partial_transfer->id + ); + + if ($item_partial_transfer === null) { + return UtilityResponse::notFound(trans('entities.item_partial_transfer')); + } + + return response()->json( + (new ItemPartialTransferTransformer($item_partial_transfer))->toArray(), + 201 + ); } /** diff --git a/app/Http/Controllers/ItemTransferController.php b/app/Http/Controllers/ItemTransferController.php index 6ffcf66e..ddbb1eef 100644 --- a/app/Http/Controllers/ItemTransferController.php +++ b/app/Http/Controllers/ItemTransferController.php @@ -241,7 +241,7 @@ public function transfer( $new_resource_id = $this->hash->decode('resource', request()->input('resource_id')); if ($new_resource_id === false) { - UtilityResponse::unableToDecode(); + return UtilityResponse::unableToDecode(); } $item = (new Item())->instance($resource_type_id, $resource_id, $item_id); @@ -249,7 +249,7 @@ public function transfer( $item->resource_id = $new_resource_id; $item->save(); } else { - UtilityResponse::failedToSelectModelForUpdateOrDelete(); + return UtilityResponse::failedToSelectModelForUpdateOrDelete(); } $item_transfer = new ItemTransfer([ @@ -261,9 +261,9 @@ public function transfer( ]); $item_transfer->save(); } catch (QueryException $e) { - UtilityResponse::foreignKeyConstraintError(); + return UtilityResponse::foreignKeyConstraintError(); } catch (Exception $e) { - UtilityResponse::failedToSaveModelForUpdate(); + return UtilityResponse::failedToSaveModelForUpdate(); } return UtilityResponse::successNoContent(); diff --git a/database/migrations/2020_03_29_124056_create_item_partial_transfer.php b/database/migrations/2020_03_29_124056_create_item_partial_transfer.php index 38e53e70..03b450d9 100644 --- a/database/migrations/2020_03_29_124056_create_item_partial_transfer.php +++ b/database/migrations/2020_03_29_124056_create_item_partial_transfer.php @@ -25,11 +25,11 @@ public function up() $table->unsignedTinyInteger('percentage'); $table->unsignedBigInteger('transferred_by'); $table->timestamps(); - $table->foreign('resource_type_id')->references('id')->on('resource_type'); - $table->foreign('from')->references('id')->on('resource'); - $table->foreign('to')->references('id')->on('resource'); - $table->foreign('item_id')->references('id')->on('item'); - $table->foreign('transferred_by')->references('id')->on('users'); + $table->foreign('resource_type_id')->references('id')->on('resource_type')->onDelete('cascade'); + $table->foreign('from')->references('id')->on('resource')->onDelete('cascade'); + $table->foreign('to')->references('id')->on('resource')->onDelete('cascade'); + $table->foreign('item_id')->references('id')->on('item')->onDelete('cascade'); + $table->foreign('transferred_by')->references('id')->on('users')->onDelete('cascade'); $table->unique(['resource_type_id', 'from', 'item_id'], 'unique_item_partial_transfer'); }); } diff --git a/database/migrations/2020_03_31_103855_create_item_transfer.php b/database/migrations/2020_03_31_103855_create_item_transfer.php index bff12d28..116c2962 100644 --- a/database/migrations/2020_03_31_103855_create_item_transfer.php +++ b/database/migrations/2020_03_31_103855_create_item_transfer.php @@ -24,11 +24,11 @@ public function up() $table->unsignedBigInteger('item_id'); $table->unsignedBigInteger('transferred_by'); $table->timestamps(); - $table->foreign('resource_type_id')->references('id')->on('resource_type'); - $table->foreign('from')->references('id')->on('resource'); - $table->foreign('to')->references('id')->on('resource'); - $table->foreign('item_id')->references('id')->on('item'); - $table->foreign('transferred_by')->references('id')->on('users'); + $table->foreign('resource_type_id')->references('id')->on('resource_type')->onDelete('cascade'); + $table->foreign('from')->references('id')->on('resource')->onDelete('cascade'); + $table->foreign('to')->references('id')->on('resource')->onDelete('cascade'); + $table->foreign('item_id')->references('id')->on('item')->onDelete('cascade'); + $table->foreign('transferred_by')->references('id')->on('users')->onDelete('cascade'); $table->unique(['resource_type_id', 'from', 'item_id'], 'unique_item_partial_transfer'); }); } diff --git a/routes/api/private-routes.php b/routes/api/private-routes.php index 44108dbf..d442141d 100644 --- a/routes/api/private-routes.php +++ b/routes/api/private-routes.php @@ -77,6 +77,11 @@ function () { 'SubcategoryController@delete' ); + Route::delete( + 'resource-types/{resource_type_id}/partial-transfers/{item_partial_transfer_id}', + 'ItemPartialTransferController@delete' + ); + Route::delete( 'resource-types/{resource_type_id}/resources/{resource_id}', 'ResourceController@delete' From 06a6715fce3c1cf20da20337c367aa172c363224 Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Wed, 1 Apr 2020 15:29:19 +0100 Subject: [PATCH 21/22] Release - Updated the changelog. - Set the version --- CHANGELOG.md | 21 ++++++++++++++ config/api/app/version.php | 4 +-- resources/views/welcome.blade.php | 48 ++++++++++--------------------- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94f20211..48ac2ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ The complete changelog for the Costs to Expect REST API, our changelog follows the format defined at https://keepachangelog.com/en/1.0.0/ +## [v2.10.0] - 2020-04-01 +### Added +- We have added a new route, `/resource_types/[id]/resources/[id]/items/[id]/partial-transfer`; A partial transfer allows you to transfer a percentage of the `total` for an item from one resource to another. +- We have added an `item_transfer` table; the table will log which items were transferred and by whom. +- We have added a partial transfers collection; the route is `/resource_types/[id]/partial-transfers`. +- We have added a partial transfers item view; the route is `/resource_types/[id]/partial-transfers/[id]`. +- We have added a transfers collection; the route is `/resource_types/[id]/transfers`. +- We have added a transfers item view; the route is `/resource_types/[id]/transfers/[id]`. +- We have added a delete endpoint for partial transfers. + +### Changed +- We have reformatted the validation rules in the configuration files; easier to read and simpler to add additional rules. +- We have switched the HTTP status code for a "Constraint error" from 500 to 409. +- We have tweaked the description for the resource field in the `/resource_types/[id]/resources/[id]/items/[id]/transfer` OPTIONS request. +- We have renamed the third parameter of the route validation methods; we changed the name from `$manage` to `$write`. +- We have renamed a response helper method; it was not clear from the name that the method is used for updates and delete. + +### Fixed +- It is possible to set the quantity for a `simple-item` item as zero. +- It is possible to clear optional values in a PATCH request. + ## [v2.09.4] - 2020-03-25 ### Changed - When a response includes additional data via the include parameters, we include the URI fragment for that data. diff --git a/config/api/app/version.php b/config/api/app/version.php index bb685199..b36c97ef 100644 --- a/config/api/app/version.php +++ b/config/api/app/version.php @@ -3,9 +3,9 @@ declare(strict_types=1); return [ - 'version'=> '2.09.4', + 'version'=> '2.10.0', 'prefix' => 'v2', - 'release_date' => '2020-03-25', + 'release_date' => '2020-04-01', 'changelog' => [ 'api' => '/v2/changelog', 'markdown' => 'https://github.com/costs-to-expect/api/blob/master/CHANGELOG.md' diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index a44aff59..978547ba 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -204,7 +204,7 @@ function gtag(){dataLayer.push(arguments);}
-

Latest feature release [v2.09.0]

+

Latest feature release [v2.10.0]

The latest release of the Costs to Expect API is {{ $version }}; we released it on the {{ date('jS M Y', strtotime($date)) }}.

@@ -215,48 +215,30 @@ function gtag(){dataLayer.push(arguments);}

Added

    -
  • We have added range filtering to the `items` collection; initially, we have added support for filtering for the `effective_date` of `allocated expense` items.
  • -
  • We have added range filtering to the resource type `items` collection; as above, we have added `effective_date` filtering.
  • -
  • We have added support for range filtering to the `items` and `resource type item` summary routes.
  • -
  • We have added an X-Filter header to show the valid filters applied to a collection.
  • -
  • We have added a link to Costs to Expect blog; the blog is a central repository for all product updates and somewhere to talk about our products.
  • -
  • We have added a `FilterParameters` class to fetch any filter parameters from the URI and validate the format and values.
  • +
  • We have added a new route, `/resource_types/[id]/resources/[id]/items/[id]/partial-transfer`; A partial transfer allows you to transfer a percentage of the `total` for an item from one resource to another.
  • +
  • We have added an `item_transfer` table; the table will log which items were transferred and by whom.
  • +
  • We have added a partial transfers collection; the route is `/resource_types/[id]/partial-transfers`.
  • +
  • We have added a partial transfers item view; the route is `/resource_types/[id]/partial-transfers/[id]`.
  • +
  • We have added a transfers collection; the route is `/resource_types/[id]/transfers`.
  • +
  • We have added a transfers item view; the route is `/resource_types/[id]/transfers/[id]`.
  • +
  • We have added a delete endpoint for partial transfers.

Changed

    -
  • We have refreshed the landing page, we have added updated text for each of the products within the service.
  • -
  • We have tweaked the stying for the landing page.
  • -
  • We have renamed the data methods in the `Option` subclasses, the conditional prefix is confusing.
  • -
  • We have added an `interface` for the item model classes.
  • -
  • We have added an `interface` for the resource type item model classes.
  • -
  • We have renamed the existing Interfaces, more straightforward names.
  • -
  • We have added additional Interfaces interfaces for the summary models.
  • -
  • We have refactored several model classes to again, simplify the naming.
  • -
  • We have corrected multiple summary config files, unnecessary structure.
  • -
  • We have unified the parameters for related item methods.
  • -
  • We have switched to a new font; the font is more legible at small screen sizes, and, it looks cool.
  • -
  • We have reviewed our HTTP headers; Content-Language missing along with other expected headers.
  • -
  • We log the id of the user that added a user to the 'permitted_user' table; this is to help later with permitted user management.
  • -
  • We have updated the API to the most recent version of Laravel 6.
  • -
  • We have updated the `resource-types/[id]/resources/[id]/items/[id]` GET endpoint; the `include-categories` and `include-subcategories` can be included in the request for 'allocated-expense' and 'simple-expense' type items.
  • -
  • When a response includes additional data via the include parameters, we include the URI fragment for that data.
  • +
  • We have reformatted the validation rules in the configuration files; easier to read and simpler to add additional rules.
  • +
  • We have switched the HTTP status code for a "Constraint error" from 500 to 409.
  • +
  • We have tweaked the description for the resource field in the `/resource_types/[id]/resources/[id]/items/[id]/transfer` OPTIONS request.
  • +
  • We have renamed the third parameter of the route validation methods; we changed the name from `$manage` to `$write`.
  • +
  • We have renamed a response helper method; it was not clear from the name that the method is used for updates and delete.

Fixed

    -
  • We have updated the `Option/Get` class, the `sort`, `search` and `filter` parameters will only display if there are viable parameters.
  • -
  • The `description` field for the `simple-item` type should be nullable.
  • -
  • Card data missing from head.
  • -
  • Google analytics missing.
  • -
- -

Removed

- -
    -
  • We have removed the layout file, not used as there is only one view file for the API.
  • +
  • It is possible to set the quantity for a `simple-item` item as zero.
  • +
  • It is possible to clear optional values in a PATCH request.
From cb98d1c09670f5e8487d37e057e4973316b25c0c Mon Sep 17 00:00:00 2001 From: Dean Blackborough Date: Wed, 1 Apr 2020 15:38:53 +0100 Subject: [PATCH 22/22] Updated routes - Updated the routes in the README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 5ca13077..707ecefe 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,12 @@ additionally, the same is true if you are assigned to a resource type. | DELETE | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories/{subcategory_id} | | GET/HEAD | v2/resource-types/{resource_type_id}/items | | OPTIONS | v2/resource-types/{resource_type_id}/items | +| GET/HEAD | v2/resource-types/{resource_type_id}/partial-transfers | +| OPTIONS | v2/resource-types/{resource_type_id}/partial-transfers | +| GET/HEAD | v2/resource-types/{resource_type_id}/partial-transfers/{item_partial_transfer_id} | +| OPTIONS | v2/resource-types/{resource_type_id}/partial-transfers/{item_partial_transfer_id} | +| DELETE | v2/resource-types/{resource_type_id}/partial-transfers/{item_partial_transfer_id} | +| GET/HEAD | v2/resource-types/{resource_type_id}/permitted-users | | OPTIONS | v2/resource-types/{resource_type_id}/permitted-users | | GET/HEAD | v2/resource-types/{resource_type_id}/resources | | OPTIONS | v2/resource-types/{resource_type_id}/resources | @@ -157,6 +163,10 @@ additionally, the same is true if you are assigned to a resource type. | POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/partial-transfer | | OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer | | POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer | +| GET/HEAD | v2/resource-types/{resource_type_id}/transfers | +| OPTIONS | v2/resource-types/{resource_type_id}/transfers | +| GET/HEAD | v2/resource-types/{resource_type_id}/transfers/{item_transfer_id} | +| OPTIONS | v2/resource-types/{resource_type_id}/transfers/{item_transfer_id} | | GET/HEAD | v2/request/error-log | | OPTIONS | v2/request/error-log | | POST | v2/request/error-log |