From dc8a44a14d3f6b948cfe6600fc3929378798547d Mon Sep 17 00:00:00 2001 From: Sebastian Marcet Date: Thu, 8 Mar 2018 08:01:19 -0300 Subject: [PATCH] Added endpoint to delete banners per location DELETE /api/v1/summits/{id}/locations/{location_id}/banners/{banner_id} Required scopes * '%s/summits/write' * '%s/locations/write' * '%s/locations/banners/write' Change-Id: Ie5624461efed22419c8c4b39f529ea6805c4e448 --- Libs/Utils/HTMLCleaner.php | 2 +- .../OAuth2SummitLocationsApiController.php | 178 +++++++++--------- ...itLocationBannerValidationRulesFactory.php | 18 +- .../SummitLocationValidationRulesFactory.php | 17 +- app/Http/Utils/Filters/Filter.php | 57 +++++- tests/OAuth2SummitLocationsApiTest.php | 65 +++++++ 6 files changed, 232 insertions(+), 105 deletions(-) diff --git a/Libs/Utils/HTMLCleaner.php b/Libs/Utils/HTMLCleaner.php index 2d6808b1..a85ad55b 100644 --- a/Libs/Utils/HTMLCleaner.php +++ b/Libs/Utils/HTMLCleaner.php @@ -29,7 +29,7 @@ final class HTMLCleaner { $config = \HTMLPurifier_Config::createDefault(); // Remove any CSS or inline styles - $config->set('CSS.AllowedProperties', array()); + $config->set('CSS.AllowedProperties', []); $purifier = new \HTMLPurifier($config); foreach($fields as $field){ if(!isset($data[$field])) continue; diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php index 5902a622..fb6607b4 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php @@ -121,36 +121,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController $this->summit_service = $summit_service; } - /** - * @param $filter_element - * @return bool - */ - private function validateClassName($filter_element){ - if($filter_element instanceof FilterElement){ - return in_array($filter_element->getValue(), SummitLocationConstants::$valid_class_names); - } - $valid = true; - foreach($filter_element[0] as $elem){ - $valid = $valid && in_array($elem->getValue(), SummitLocationConstants::$valid_class_names); - } - return $valid; - } - - /** - * @param $filter_element - * @return bool - */ - private function validateBannerClassName($filter_element){ - if($filter_element instanceof FilterElement){ - return in_array($filter_element->getValue(), SummitLocationBannerConstants::$valid_class_names); - } - $valid = true; - foreach($filter_element[0] as $elem){ - $valid = $valid && in_array($elem->getValue(), SummitLocationBannerConstants::$valid_class_names); - } - return $valid; - } - /** * @param $summit_id * @return mixed @@ -202,6 +172,27 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController 'is_main' => ['=='], ]); } + if(is_null($filter)) $filter = new Filter(); + + $filter->validate([ + 'class_name' => sprintf('sometimes|in:%s',implode(',', SummitLocationConstants::$valid_class_names)), + 'name' => 'sometimes|string', + 'description' => 'sometimes|string', + 'address_1' => 'sometimes|string', + 'address_2' => 'sometimes|string', + 'zip_code' => 'sometimes|string', + 'city' => 'sometimes|string', + 'state' => 'sometimes|string', + 'country' => 'sometimes|string', + 'sold_out' => 'sometimes|boolean', + 'is_main' => 'sometimes|boolean', + ], [ + 'class_name.in' => sprintf + ( + ":attribute has an invalid value ( valid values are %s )", + implode(", ", SummitLocationConstants::$valid_class_names) + ) + ]); $order = null; @@ -214,18 +205,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController ]); } - if(is_null($filter)) $filter = new Filter(); - - if($filter->hasFilter("class_name") && !$this->validateClassName($filter->getFilter("class_name"))){ - throw new ValidationException( - sprintf - ( - "class_name filter has an invalid value ( valid values are %s", - implode(", ", SummitLocationConstants::$valid_class_names) - ) - ); - } - $data = $this->location_repository->getBySummit($summit, new PagingInfo($page, $per_page), $filter, $order); return $this->ok @@ -278,7 +257,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController $locations[] = SerializerRegistry::getInstance()->getSerializer($location)->serialize(); } - $response = new PagingResponse ( count($locations), @@ -769,16 +747,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController ); } - if(!in_array($payload["class_name"], SummitLocationConstants::$valid_class_names) ){ - throw new ValidationException( - sprintf - ( - "class_name has an invalid value ( valid values are %s", - implode(", ", SummitLocationConstants::$valid_class_names) - ) - ); - } - $location = $this->location_service->addLocation($summit, $payload); return $this->created(SerializerRegistry::getInstance()->getSerializer($location)->serialize()); @@ -1139,16 +1107,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController ); } - if(!in_array($payload["class_name"], SummitLocationConstants::$valid_class_names) ){ - throw new ValidationException( - sprintf - ( - "class_name has an invalid value ( valid values are %s", - implode(", ", SummitLocationConstants::$valid_class_names) - ) - ); - } - $location = $this->location_service->updateLocation($summit, $location_id, $payload); return $this->updated(SerializerRegistry::getInstance()->getSerializer($location)->serialize()); @@ -1634,6 +1592,24 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController ]); } + if(is_null($filter)) $filter = new Filter(); + + $filter->validate([ + 'class_name' => sprintf('sometimes|in:%s',implode(',', SummitLocationBannerConstants::$valid_class_names)), + 'title' => 'sometimes|string', + 'content' => 'sometimes|string', + 'type' => sprintf('sometimes|in:%s',implode(',', SummitLocationBannerConstants::$valid_types)), + 'enabled' => 'sometimes|boolean', + 'start_date' => 'sometimes|date_format:U', + 'end_date' => 'sometimes|date_format:U', + ], [ + 'class_name.in' => sprintf + ( + ":attribute has an invalid value ( valid values are %s )", + implode(", ", SummitLocationBannerConstants::$valid_class_names) + ) + ]); + $order = null; if (Input::has('order')) @@ -1646,18 +1622,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController ]); } - if(is_null($filter)) $filter = new Filter(); - - if($filter->hasFilter("class_name") && !$this->validateBannerClassName($filter->getFilter("class_name"))){ - throw new ValidationException( - sprintf - ( - "class_name filter has an invalid value ( valid values are %s", - implode(", ", SummitLocationBannerConstants::$valid_class_names) - ) - ); - } - $data = $this->location_banners_repository->getBySummitLocation($location, new PagingInfo($page, $per_page), $filter, $order); return $this->ok @@ -1708,7 +1672,14 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController $rules = SummitLocationBannerValidationRulesFactory::build($payload); // Creates a Validator instance and validates the data. - $validation = Validator::make($payload, $rules); + $messages = [ + 'class_name.in' => sprintf + ( + ":attribute has an invalid value ( valid values are %s )", + implode(", ", SummitLocationBannerConstants::$valid_class_names) + ) + ]; + $validation = Validator::make($payload, $rules, $messages); if ($validation->fails()) { $messages = $validation->messages()->toArray(); @@ -1719,17 +1690,15 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController ); } - if(!in_array($payload["class_name"], SummitLocationBannerConstants::$valid_class_names) ){ - throw new ValidationException( - sprintf - ( - "class_name has an invalid value ( valid values are %s", - implode(", ", SummitLocationBannerConstants::$valid_class_names) - ) - ); - } - - $banner = $this->location_service->addLocationBanner($summit, $location_id, HTMLCleaner::cleanData($payload, ['title', 'content'])); + $banner = $this->location_service->addLocationBanner + ( + $summit, + $location_id, + HTMLCleaner::cleanData + ( + $payload, ['title', 'content'] + ) + ); return $this->created(SerializerRegistry::getInstance()->getSerializer($banner)->serialize()); } @@ -1747,4 +1716,39 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController return $this->error500($ex); } } + + /** + * @param $summit_id + * @param $location_id + * @param $banner_id + * @return mixed + */ + public function deleteLocationBanner($summit_id, $location_id, $banner_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $this->location_service->deleteLocationBanner($summit, $location_id, $banner_id); + + return $this->deleted(); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412([$ex1->getMessage()]); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(['message'=> $ex2->getMessage()]); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function updateLocationBanner($summit, $location_id, $banner_id){ + + } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/SummitLocationBannerValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/SummitLocationBannerValidationRulesFactory.php index 4027f6c8..c1bbfb1b 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/SummitLocationBannerValidationRulesFactory.php +++ b/app/Http/Controllers/Apis/Protected/Summit/SummitLocationBannerValidationRulesFactory.php @@ -33,18 +33,20 @@ final class SummitLocationBannerValidationRulesFactory throw new ValidationException('class_name is not set'); $base_rules = [ - 'title' => 'required|string', - 'content' => 'required|string', - 'type' => sprintf('required|in:%s', implode(",", SummitLocationBannerConstants::$valid_types)), - 'enabled' => 'required|boolean' + 'class_name' => sprintf('required|in%s', implode(", ", SummitLocationBannerConstants::$valid_class_names)), + 'title' => 'required|string', + 'content' => 'required|string', + 'type' => sprintf('required|in:%s', implode(",", SummitLocationBannerConstants::$valid_types)), + 'enabled' => 'required|boolean' ]; if($update){ $base_rules = [ - 'title' => 'sometimes|string', - 'content' => 'sometimes|string', - 'type' => sprintf('sometimes|in:%s', implode(",", SummitLocationBannerConstants::$valid_types)), - 'enabled' => 'sometimes|boolean' + 'class_name' => sprintf('required|in%s', implode(", ", SummitLocationBannerConstants::$valid_class_names)), + 'title' => 'sometimes|string', + 'content' => 'sometimes|string', + 'type' => sprintf('sometimes|in:%s', implode(",", SummitLocationBannerConstants::$valid_types)), + 'enabled' => 'sometimes|boolean' ]; } diff --git a/app/Http/Controllers/Apis/Protected/Summit/SummitLocationValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/SummitLocationValidationRulesFactory.php index e98cd654..2e6491a0 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/SummitLocationValidationRulesFactory.php +++ b/app/Http/Controllers/Apis/Protected/Summit/SummitLocationValidationRulesFactory.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Models\Foundation\Summit\Locations\SummitLocationConstants; use models\exceptions\ValidationException; use models\summit\SummitAirport; use models\summit\SummitExternalLocation; @@ -32,26 +33,30 @@ final class SummitLocationValidationRulesFactory public static function build(array $data, $update = false){ if(!isset($data['class_name'])) - throw new ValidationException('class_name is not set'); + throw new ValidationException('class_name is required'); + + $base_rules = [ + 'class_name' => sprintf('required|in:%s', implode(", ", SummitLocationConstants::$valid_class_names)) + ]; switch($data['class_name']){ case SummitVenue::ClassName: { - return SummitVenueValidationRulesFactory::build($data, $update); + return array_merge($base_rules, SummitVenueValidationRulesFactory::build($data, $update)); } break; case SummitAirport::ClassName: { - return SummitAirportValidationRulesFactory::build($data, $update); + return array_merge($base_rules, SummitAirportValidationRulesFactory::build($data, $update)); } break; case SummitHotel::ClassName: { - return SummitHotelValidationRulesFactory::build($data, $update); + return array_merge($base_rules, SummitHotelValidationRulesFactory::build($data, $update)); } break; case SummitExternalLocation::ClassName: { - return SummitExternalLocationValidationRulesFactory::build($data, $update); + return array_merge(SummitExternalLocationValidationRulesFactory::build($data, $update)); } case SummitVenueRoom::ClassName: { - return SummitVenueRoomValidationRulesFactory::build($data, $update); + return array_merge(SummitVenueRoomValidationRulesFactory::build($data, $update)); } break; default:{ diff --git a/app/Http/Utils/Filters/Filter.php b/app/Http/Utils/Filters/Filter.php index 6e9fa328..c72404ab 100644 --- a/app/Http/Utils/Filters/Filter.php +++ b/app/Http/Utils/Filters/Filter.php @@ -15,6 +15,8 @@ use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\QueryBuilder; +use Illuminate\Support\Facades\Validator; +use models\exceptions\ValidationException; /** * Class Filter @@ -25,12 +27,12 @@ final class Filter /** * @var array */ - private $filters = array(); + private $filters = []; /** * @var array */ - private $bindings = array(); + private $bindings = []; public function __construct(array $filters = []) { @@ -98,7 +100,7 @@ final class Filter */ public function getFlatFilter($field) { - $res = array(); + $res = []; foreach ($this->filters as $filter) { if ($filter instanceof FilterElement && $filter->getField() === $field) { @@ -117,6 +119,55 @@ final class Filter return $res; } + /** + * @return array + */ + public function getFiltersKeyValues(){ + $res = []; + foreach ($this->filters as $filter) { + + if ($filter instanceof FilterElement) { + $res[$filter->getField()] = $filter->getValue(); + } + else if (is_array($filter)) { + // OR + foreach ($filter as $e) { + if ($e instanceof FilterElement) { + if(!isset($res[$e->getField()])) $res[$e->getField()] = []; + $res[$e->getField()][] = $e->getValue(); + } + } + } + } + return $res; + } + + /** + * @param array $rules + * @param array $messages + * @throws ValidationException + */ + public function validate(array $rules, array $messages){ + $filter_key_values = $this->getFiltersKeyValues(); + foreach($rules as $field => $rule) { + if(!isset($filter_key_values[$field])) continue; + $values = $filter_key_values[$field]; + if(!is_array($values)) $values = [$values]; + foreach ($values as $val) { + $validation = Validator::make + ( + [$field => $val], + [$field => $rule], + $messages + ); + if ($validation->fails()) { + $ex = new ValidationException(); + throw $ex->setMessages($validation->messages()->toArray()); + } + } + } + } + /** * @param Criteria $criteria * @param array $mappings diff --git a/tests/OAuth2SummitLocationsApiTest.php b/tests/OAuth2SummitLocationsApiTest.php index f3676501..b73af266 100644 --- a/tests/OAuth2SummitLocationsApiTest.php +++ b/tests/OAuth2SummitLocationsApiTest.php @@ -1148,6 +1148,8 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest $banners = json_decode($content); $this->assertTrue(!is_null($banners)); + + return $banners; } public function testGetLocationBannersFilterByClassName($summit_id = 23, $location_id = 315) @@ -1184,4 +1186,67 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest $banners = json_decode($content); $this->assertTrue(!is_null($banners)); } + + public function testGetLocationBannersFilterByInvalidClassName($summit_id = 23, $location_id = 315) + { + $params = [ + 'id' => $summit_id, + 'location_id' => $location_id, + 'page' => 1, + 'per_page' => 5, + 'order' => '-id', + 'filter' => 'class_name==test,class_name==test2' + ]; + + $headers = + [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action + ( + "GET", + "OAuth2SummitLocationsApiController@getLocationBanners", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + $banners = json_decode($content); + $this->assertTrue(!is_null($banners)); + } + + public function testDeleteLocationBanner($summit_id = 23, $location_id = 315){ + $banners = $this->testGetLocationBanners($summit_id, $location_id); + + $params = [ + 'id' => $summit_id, + 'location_id' => $location_id, + 'banner_id' => $banners->data[0]->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitLocationsApiController@deleteLocationBanner", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } } \ No newline at end of file