From 5690750664addf6452cb97f7a14c44810b1e349d Mon Sep 17 00:00:00 2001 From: Felicitus Date: Mon, 11 Jan 2016 15:25:49 +0100 Subject: [PATCH] Added exception if stockLevels is found within the JSON data and added unit test, relates to #551 --- app/config/config_partkeepr.yml | 12 ++- .../PartBundle/Action/PartPutAction.php | 82 +++++++++++++++++++ .../PartBundle/Resources/config/actions.xml | 4 + .../Tests/Issues/StockHistoryLostTest.php | 73 +++++++++++++++++ 4 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 src/PartKeepr/PartBundle/Action/PartPutAction.php create mode 100644 src/PartKeepr/PartBundle/Tests/Issues/StockHistoryLostTest.php diff --git a/app/config/config_partkeepr.yml b/app/config/config_partkeepr.yml index d4a989e69..571d2119e 100644 --- a/app/config/config_partkeepr.yml +++ b/app/config/config_partkeepr.yml @@ -283,11 +283,17 @@ services: factory: [ "@api.operation_factory", "createItemOperation" ] arguments: [ "@resource.part", "GET" ] - resource.part.item_operation.put: + resource.part.item_operation.custom_put: class: "Dunglas\ApiBundle\Api\Operation\Operation" public: false factory: [ "@api.operation_factory", "createItemOperation" ] - arguments: [ "@resource.part", "PUT" ] + arguments: + - "@resource.part" + - [ "PUT" ] + - "/parts/{id}" + - "partkeepr.part.put" + - "PartPut" + resource.part.item_operation.delete: class: "Dunglas\ApiBundle\Api\Operation\Operation" @@ -334,7 +340,7 @@ services: tags: [ { name: "api.resource" } ] calls: - method: "initItemOperations" - arguments: [ [ "@resource.part.item_operation.get", "@resource.part.item_operation.put", "@resource.part.item_operation.delete", "@resource.part.item_operation.add_stock", "@resource.part.item_operation.remove_stock", "@resource.part.item_operation.set_stock" ] ] + arguments: [ [ "@resource.part.item_operation.get", "@resource.part.item_operation.custom_put", "@resource.part.item_operation.delete", "@resource.part.item_operation.add_stock", "@resource.part.item_operation.remove_stock", "@resource.part.item_operation.set_stock" ] ] - method: "initCollectionOperations" arguments: [ [ "@resource.part.collection_operation.get", "@resource.part.collection_operation.custom_post" ] ] - method: "initFilters" diff --git a/src/PartKeepr/PartBundle/Action/PartPutAction.php b/src/PartKeepr/PartBundle/Action/PartPutAction.php new file mode 100644 index 000000000..c9fc0636a --- /dev/null +++ b/src/PartKeepr/PartBundle/Action/PartPutAction.php @@ -0,0 +1,82 @@ +dataProvider = $dataProvider; + $this->serializer = $serializer; + } + + /** + * Create a new item. + * + * @param Request $request + * @param string|int $id + * + * @return mixed + * + * @throws NotFoundHttpException + * @throws RuntimeException + * @throws UserProtectedException + * @throws UserLimitReachedException + * @throws \Exception If a stockLevels attribute is found in the request + */ + public function __invoke(Request $request, $id) + { + /** + * @var $resourceType ResourceInterface + */ + list($resourceType, $format) = $this->extractAttributes($request); + + /** + * Workaround to ensure stockLevels are not overwritten in a PUT request. + * @see https://github.com/partkeepr/PartKeepr/issues/551 + */ + $data = json_decode($request->getContent()); + + if (property_exists($data, "stockLevels")) { + throw new \Exception("stockLevels may not be written in a PUT request!"); + } + + $data = $this->getItem($this->dataProvider, $resourceType, $id); + + $context = $resourceType->getDenormalizationContext(); + $context['object_to_populate'] = $data; + + $data = $this->serializer->deserialize( + $request->getContent(), + $resourceType->getEntityClass(), + $format, + $context + ); + + return $data; + } +} diff --git a/src/PartKeepr/PartBundle/Resources/config/actions.xml b/src/PartKeepr/PartBundle/Resources/config/actions.xml index 32036b0db..8fd4bcce6 100644 --- a/src/PartKeepr/PartBundle/Resources/config/actions.xml +++ b/src/PartKeepr/PartBundle/Resources/config/actions.xml @@ -8,6 +8,10 @@ + + + + diff --git a/src/PartKeepr/PartBundle/Tests/Issues/StockHistoryLostTest.php b/src/PartKeepr/PartBundle/Tests/Issues/StockHistoryLostTest.php new file mode 100644 index 000000000..3e38355fd --- /dev/null +++ b/src/PartKeepr/PartBundle/Tests/Issues/StockHistoryLostTest.php @@ -0,0 +1,73 @@ +fixtures = $this->loadFixtures( + array( + 'PartKeepr\StorageLocationBundle\DataFixtures\CategoryDataLoader', + 'PartKeepr\StorageLocationBundle\DataFixtures\StorageLocationLoader', + 'PartKeepr\PartBundle\DataFixtures\CategoryDataLoader', + 'PartKeepr\PartBundle\DataFixtures\PartDataLoader', + 'PartKeepr\AuthBundle\DataFixtures\LoadUserData', + 'PartKeepr\ManufacturerBundle\Tests\DataFixtures\ManufacturerDataLoader', + 'PartKeepr\DistributorBundle\Tests\DataFixtures\DistributorDataLoader', + ) + )->getReferenceRepository(); + } + + public function testStockHistory () { + $client = static::makeClient(true); + + /** + * @var $part1 Part + */ + $part1 = $this->fixtures->getReference("part.1"); + + $stockLevel = new StockEntry(); + $stockLevel->setPart($part1); + $stockLevel->setStockLevel(5); + + $fosUser = $this->fixtures->getReference("user.admin"); + $userService = $this->getContainer()->get("partkeepr.userservice"); + $user = $userService->getProxyUser($fosUser->getUsername(), $userService->getBuiltinProvider(), true); + + $stockLevel->setUser($user); + $part1->addStockLevel($stockLevel); + + $this->getContainer()->get("doctrine.orm.default_entity_manager")->flush(); + + $iriCoverter = $this->getContainer()->get("api.iri_converter"); + $iri = $iriCoverter->getIriFromItem($part1); + + $client->request("GET", $iri); + + $response = $client->getResponse()->getContent(); + $responseObj = json_decode($response, true); + $responseObj["stockLevels"] = array(); + + $client->request("PUT", $iri, array(), array(), array(), json_encode($responseObj)); + + $this->assertEquals(500, $client->getResponse()->getStatusCode()); + + $this->getContainer()->get("doctrine.orm.default_entity_manager")->refresh($part1); + $this->assertEquals(1, count($part1->getStockLevels())); + } +}