diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php index 3f2f62c8..0f0f99fa 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php @@ -164,8 +164,8 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController 'class_name' => ['=='], 'name' => ['==', '=@'], 'description' => ['=@'], - 'address1' => ['=@'], - 'address2' => ['=@'], + 'address_1' => ['=@'], + 'address_2' => ['=@'], 'zip_code' => ['==','=@'], 'city' => ['==','=@'], 'state' => ['==','=@'], @@ -599,6 +599,7 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController return $this->error500($ex); } } + /** * @param $summit_id * @return mixed @@ -642,6 +643,10 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController } } + /** + * @param $summit_id + * @return mixed + */ public function addExternalLocation($summit_id){ try { if(!Request::isJson()) return $this->error403(); @@ -681,6 +686,10 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController } } + /** + * @param $summit_id + * @return mixed + */ public function addHotel($summit_id){ try { if(!Request::isJson()) return $this->error403(); @@ -720,6 +729,10 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController } } + /** + * @param $summit_id + * @return mixed + */ public function addAirport($summit_id){ try { if(!Request::isJson()) return $this->error403(); @@ -758,4 +771,238 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController return $this->error500($ex); } } + + /** + * Update Location Endpoints + */ + + /** + * @param $summit_id + * @param $location_id + * @return mixed + */ + public function updateLocation($summit_id, $location_id){ + try { + + if(!Request::isJson()) return $this->error403(); + $payload = Input::json()->all(); + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $rules = SummitLocationValidationRulesFactory::build($payload, true); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $location = $this->location_service->updateLocation($summit, $location_id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($location)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $venue_id + * @return mixed + */ + public function updateVenue($summit_id, $venue_id){ + try { + + if(!Request::isJson()) return $this->error403(); + $payload = Input::json()->all(); + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $payload['class_name'] = SummitVenue::ClassName; + $rules = SummitLocationValidationRulesFactory::build($payload, true); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $location = $this->location_service->updateLocation($summit, $venue_id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($location)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $hotel_id + * @return mixed + */ + public function updateHotel($summit_id, $hotel_id){ + try { + + if(!Request::isJson()) return $this->error403(); + $payload = Input::json()->all(); + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $payload['class_name'] = SummitHotel::ClassName; + $rules = SummitLocationValidationRulesFactory::build($payload, true); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $location = $this->location_service->updateLocation($summit, $hotel_id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($location)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $airport_id + * @return mixed + */ + public function updateAirport($summit_id, $airport_id){ + try { + + if(!Request::isJson()) return $this->error403(); + $payload = Input::json()->all(); + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $payload['class_name'] = SummitAirport::ClassName; + $rules = SummitLocationValidationRulesFactory::build($payload, true); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $location = $this->location_service->updateLocation($summit, $airport_id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($location)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $external_location_id + * @return mixed + */ + public function updateExternalLocation($summit_id, $external_location_id){ + try { + + if(!Request::isJson()) return $this->error403(); + $payload = Input::json()->all(); + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $payload['class_name'] = SummitExternalLocation::ClassName; + $rules = SummitLocationValidationRulesFactory::build($payload, true); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $location = $this->location_service->updateLocation($summit, $external_location_id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($location)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/SummitAbstractLocationValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/SummitAbstractLocationValidationRulesFactory.php index 4fdf6ec7..2c3bdf06 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/SummitAbstractLocationValidationRulesFactory.php +++ b/app/Http/Controllers/Apis/Protected/Summit/SummitAbstractLocationValidationRulesFactory.php @@ -24,17 +24,18 @@ final class SummitAbstractLocationValidationRulesFactory * @return array */ public static function build(array $data, $update = false){ - $name_rule = 'required|string|max:255'; if($update){ - $name_rule = 'sometimes|string|max:255'; + return [ + 'name' => 'sometimes|string|max:255', + 'description' => 'sometimes|string', + 'order' => 'sometimes|integer|min:1' + ]; } - $rules = [ - 'name' => $name_rule, + return [ + 'name' => 'required|string|max:255', 'description' => 'sometimes|string', ]; - - return $rules; } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/SummitGeoLocatedLocationValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/SummitGeoLocatedLocationValidationRulesFactory.php index d66a9dc0..3d90006b 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/SummitGeoLocatedLocationValidationRulesFactory.php +++ b/app/Http/Controllers/Apis/Protected/Summit/SummitGeoLocatedLocationValidationRulesFactory.php @@ -32,9 +32,9 @@ final class SummitGeoLocatedLocationValidationRulesFactory 'address_1' => 'sometimes|string', 'address_2' => 'sometimes|string', 'zip_code' => 'sometimes|string', - 'city' => 'string|required_with:address1', - 'state' => 'string|required_with:address1', - 'country' => 'string|required_with:address1', + 'city' => 'string|required_with:address_1', + 'state' => 'string|required_with:address_1', + 'country' => 'country_iso_alpha2_code|required_with:address_1', 'website_url' => 'sometimes|url', 'lng' => 'sometimes|geo_longitude|required_with:lat', 'lat' => 'sometimes|geo_latitude|required_with:lng', @@ -50,9 +50,9 @@ final class SummitGeoLocatedLocationValidationRulesFactory 'zip_code' => 'sometimes|string', 'city' => 'string|required_without:lng,lat', 'state' => 'string|required_without:lng,lat', - 'country' => 'string|required_without:lng,lat', - 'lng' => 'geo_longitude|required_with:lat|required_without:address1,city,state,country', - 'lat' => 'geo_latitude|required_with:lng|required_without:address1,city,state,country', + 'country' => 'country_iso_alpha2_code|required_without:lng,lat', + 'lng' => 'geo_longitude|required_with:lat|required_without:address_1,city,state,country', + 'lat' => 'geo_latitude|required_with:lng|required_without:address_1,city,state,country', 'website_url' => 'sometimes|url', 'display_on_site' => 'sometimes|boolean', 'details_page' => 'sometimes|boolean', diff --git a/app/Http/routes.php b/app/Http/routes.php index fcd87fa0..788aab39 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -282,19 +282,44 @@ Route::group([ Route::group(['prefix' => 'locations'], function () { Route::get('', 'OAuth2SummitLocationsApiController@getLocations'); - Route::post('', 'OAuth2SummitLocationsApiController@addLocation'); - Route::get('venues', 'OAuth2SummitLocationsApiController@getVenues'); - Route::get('external-locations', 'OAuth2SummitLocationsApiController@getExternalLocations'); - Route::get('hotels', 'OAuth2SummitLocationsApiController@getHotels'); - Route::get('airports', 'OAuth2SummitLocationsApiController@getAirports'); + Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addLocation']); Route::get('metadata', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@getMetadata']); - Route::post('venues', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addVenue']); - Route::post('external-locations', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addExternalLocation']); - Route::post('hotels', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addHotel']); - Route::post('airports', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addAirport']); + + Route::group(['prefix' => 'venues'], function () { + Route::get('', 'OAuth2SummitLocationsApiController@getVenues'); + Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addVenue']); + Route::group(['prefix' => '{venue_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@updateVenue']); + }); + }); + + Route::group(['prefix' => 'airports'], function () { + Route::get('', 'OAuth2SummitLocationsApiController@getAirports'); + Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addAirport']); + Route::group(['prefix' => '{airport_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@updateAirport']); + }); + }); + + Route::group(['prefix' => 'hotels'], function () { + Route::get('', 'OAuth2SummitLocationsApiController@getHotels'); + Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addExternalLocation']); + Route::group(['prefix' => '{hotel_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@updateExternalLocation']); + }); + }); + + Route::group(['prefix' => 'external-locations'], function () { + Route::get('', 'OAuth2SummitLocationsApiController@getExternalLocations'); + Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@addHotel']); + Route::group(['prefix' => '{external_location_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@updateHotel']); + }); + }); Route::group(['prefix' => '{location_id}'], function () { Route::get('', 'OAuth2SummitLocationsApiController@getLocation'); + Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@updateLocation']); Route::get('/events/published','OAuth2SummitLocationsApiController@getLocationPublishedEvents')->where('location_id', 'tbd|[0-9]+'); Route::get('/events','OAuth2SummitLocationsApiController@getLocationEvents')->where('location_id', 'tbd|[0-9]+'); }); diff --git a/app/ModelSerializers/Locations/SummitGeoLocatedLocationSerializer.php b/app/ModelSerializers/Locations/SummitGeoLocatedLocationSerializer.php index 64d600ad..20597b46 100644 --- a/app/ModelSerializers/Locations/SummitGeoLocatedLocationSerializer.php +++ b/app/ModelSerializers/Locations/SummitGeoLocatedLocationSerializer.php @@ -21,14 +21,18 @@ class SummitGeoLocatedLocationSerializer extends SummitAbstractLocationSerialize { protected static $array_mappings = array ( - 'Address1' => 'address_1:json_string', - 'Address2' => 'address_2:json_string', - 'ZipCode' => 'zip_code', - 'City' => 'city:json_string', - 'State' => 'state:json_string', - 'Country' => 'country:json_string', - 'Lng' => 'lng', - 'Lat' => 'lat', + 'Address1' => 'address_1:json_string', + 'Address2' => 'address_2:json_string', + 'ZipCode' => 'zip_code', + 'City' => 'city:json_string', + 'State' => 'state:json_string', + 'Country' => 'country:json_string', + 'Lng' => 'lng', + 'Lat' => 'lat', + 'WebsiteUrl' => 'website_url:json_string', + 'DisplayOnSite' => 'display_on_site:json_boolean', + 'DetailsPage' => 'details_page:json_boolean', + 'LocationMessage' => 'location_message:json_string', ); /** diff --git a/app/Models/Foundation/Summit/Factories/SummitLocationFactory.php b/app/Models/Foundation/Summit/Factories/SummitLocationFactory.php index 91fb4e59..4c0d8c6e 100644 --- a/app/Models/Foundation/Summit/Factories/SummitLocationFactory.php +++ b/app/Models/Foundation/Summit/Factories/SummitLocationFactory.php @@ -201,4 +201,25 @@ final class SummitLocationFactory return $airport; } + + /** + * @param SummitAbstractLocation $location + * @param array $data + * @return SummitAbstractLocation + */ + public static function populate(SummitAbstractLocation $location, array $data){ + if($location instanceof SummitVenue){ + return self::populateSummitVenue($location, $data); + } + if($location instanceof SummitHotel){ + return self::populateSummitHotel($location, $data); + } + if($location instanceof SummitAirport){ + return self::populateSummitAirport($location, $data); + } + if($location instanceof SummitExternalLocation){ + return self::populateSummitExternalLocation($location, $data); + } + return $location; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Locations/SummitHotel.php b/app/Models/Foundation/Summit/Locations/SummitHotel.php index 21ba8ebc..99e8bb71 100644 --- a/app/Models/Foundation/Summit/Locations/SummitHotel.php +++ b/app/Models/Foundation/Summit/Locations/SummitHotel.php @@ -114,8 +114,8 @@ class SummitHotel extends SummitExternalLocation public function __construct() { parent::__construct(); - $this->sold_out = false; - $this->type = self::HotelTypePrimary; + $this->sold_out = false; + $this->hotel_type = self::HotelTypePrimary; } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Summit.php b/app/Models/Foundation/Summit/Summit.php index fab4fb55..d44f43b1 100644 --- a/app/Models/Foundation/Summit/Summit.php +++ b/app/Models/Foundation/Summit/Summit.php @@ -1668,4 +1668,43 @@ SQL; $rsvp_template = $this->rsvp_templates->matching($criteria)->first(); return $rsvp_template === false ? null : $rsvp_template; } + + /** + * @param SummitAbstractLocation $location + * @param int $new_order + * @throws ValidationException + */ + public function recalculateLocationOrder(SummitAbstractLocation $location, $new_order){ + + $former_order = $location->getOrder(); + $criteria = Criteria::create(); + $criteria->orderBy(['order'=> 'ASC']); + $locations = $this->locations->matching($criteria)->toArray(); + $max_order = count($locations); + + $filtered_locations = []; + + foreach($locations as $l){ + if($l instanceof SummitVenue || $l instanceof SummitHotel || $l instanceof SummitAirport || $l instanceof SummitExternalLocation) + $filtered_locations[] = $l; + } + if($new_order > $max_order) + throw new ValidationException(sprintf("max order is %s", $max_order)); + + unset($filtered_locations[$former_order - 1]); + + $filtered_locations = array_merge + ( + array_slice($filtered_locations, 0, $new_order -1 , true) , + [$location] , + array_slice($filtered_locations, $new_order -1 , count($filtered_locations) - $new_order - 1, true) + ); + + $order = 1; + foreach($filtered_locations as $l){ + $l->setOrder($order); + $order++; + } + + } } \ No newline at end of file diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 91d9feb7..2aaa0b9c 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -270,6 +270,265 @@ class AppServiceProvider extends ServiceProvider $value = floatval($value); return !($value < -180.00 || $value > 180.00); }); + + Validator::extend('country_iso_alpha2_code', function($attribute, $value, $parameters, $validator) + { + $countries = + [ + 'AF' => 'Afghanistan', + 'AX' => 'Aland Islands', + 'AL' => 'Albania', + 'DZ' => 'Algeria', + 'AS' => 'American Samoa', + 'AD' => 'Andorra', + 'AO' => 'Angola', + 'AI' => 'Anguilla', + 'AQ' => 'Antarctica', + 'AG' => 'Antigua And Barbuda', + 'AR' => 'Argentina', + 'AM' => 'Armenia', + 'AW' => 'Aruba', + 'AU' => 'Australia', + 'AT' => 'Austria', + 'AZ' => 'Azerbaijan', + 'BS' => 'Bahamas', + 'BH' => 'Bahrain', + 'BD' => 'Bangladesh', + 'BB' => 'Barbados', + 'BY' => 'Belarus', + 'BE' => 'Belgium', + 'BZ' => 'Belize', + 'BJ' => 'Benin', + 'BM' => 'Bermuda', + 'BT' => 'Bhutan', + 'BO' => 'Bolivia', + 'BA' => 'Bosnia And Herzegovina', + 'BW' => 'Botswana', + 'BV' => 'Bouvet Island', + 'BR' => 'Brazil', + 'IO' => 'British Indian Ocean Territory', + 'BN' => 'Brunei Darussalam', + 'BG' => 'Bulgaria', + 'BF' => 'Burkina Faso', + 'BI' => 'Burundi', + 'KH' => 'Cambodia', + 'CM' => 'Cameroon', + 'CA' => 'Canada', + 'CV' => 'Cape Verde', + 'KY' => 'Cayman Islands', + 'CF' => 'Central African Republic', + 'TD' => 'Chad', + 'CL' => 'Chile', + 'CN' => 'China', + 'CX' => 'Christmas Island', + 'CC' => 'Cocos (Keeling) Islands', + 'CO' => 'Colombia', + 'KM' => 'Comoros', + 'CG' => 'Congo', + 'CD' => 'Congo, Democratic Republic', + 'CK' => 'Cook Islands', + 'CR' => 'Costa Rica', + 'CI' => 'Cote D\'Ivoire', + 'HR' => 'Croatia', + 'CU' => 'Cuba', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DK' => 'Denmark', + 'DJ' => 'Djibouti', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'EC' => 'Ecuador', + 'EG' => 'Egypt', + 'SV' => 'El Salvador', + 'GQ' => 'Equatorial Guinea', + 'ER' => 'Eritrea', + 'EE' => 'Estonia', + 'ET' => 'Ethiopia', + 'FK' => 'Falkland Islands (Malvinas)', + 'FO' => 'Faroe Islands', + 'FJ' => 'Fiji', + 'FI' => 'Finland', + 'FR' => 'France', + 'GF' => 'French Guiana', + 'PF' => 'French Polynesia', + 'TF' => 'French Southern Territories', + 'GA' => 'Gabon', + 'GM' => 'Gambia', + 'GE' => 'Georgia', + 'DE' => 'Germany', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GR' => 'Greece', + 'GL' => 'Greenland', + 'GD' => 'Grenada', + 'GP' => 'Guadeloupe', + 'GU' => 'Guam', + 'GT' => 'Guatemala', + 'GG' => 'Guernsey', + 'GN' => 'Guinea', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HT' => 'Haiti', + 'HM' => 'Heard Island & Mcdonald Islands', + 'VA' => 'Holy See (Vatican City State)', + 'HN' => 'Honduras', + 'HK' => 'Hong Kong', + 'HU' => 'Hungary', + 'IS' => 'Iceland', + 'IN' => 'India', + 'ID' => 'Indonesia', + 'IR' => 'Iran, Islamic Republic Of', + 'IQ' => 'Iraq', + 'IE' => 'Ireland', + 'IM' => 'Isle Of Man', + 'IL' => 'Israel', + 'IT' => 'Italy', + 'JM' => 'Jamaica', + 'JP' => 'Japan', + 'JE' => 'Jersey', + 'JO' => 'Jordan', + 'KZ' => 'Kazakhstan', + 'KE' => 'Kenya', + 'KI' => 'Kiribati', + 'KR' => 'Korea', + 'KW' => 'Kuwait', + 'KG' => 'Kyrgyzstan', + 'LA' => 'Lao People\'s Democratic Republic', + 'LV' => 'Latvia', + 'LB' => 'Lebanon', + 'LS' => 'Lesotho', + 'LR' => 'Liberia', + 'LY' => 'Libyan Arab Jamahiriya', + 'LI' => 'Liechtenstein', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'MO' => 'Macao', + 'MK' => 'Macedonia', + 'MG' => 'Madagascar', + 'MW' => 'Malawi', + 'MY' => 'Malaysia', + 'MV' => 'Maldives', + 'ML' => 'Mali', + 'MT' => 'Malta', + 'MH' => 'Marshall Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MU' => 'Mauritius', + 'YT' => 'Mayotte', + 'MX' => 'Mexico', + 'FM' => 'Micronesia, Federated States Of', + 'MD' => 'Moldova', + 'MC' => 'Monaco', + 'MN' => 'Mongolia', + 'ME' => 'Montenegro', + 'MS' => 'Montserrat', + 'MA' => 'Morocco', + 'MZ' => 'Mozambique', + 'MM' => 'Myanmar', + 'NA' => 'Namibia', + 'NR' => 'Nauru', + 'NP' => 'Nepal', + 'NL' => 'Netherlands', + 'AN' => 'Netherlands Antilles', + 'NC' => 'New Caledonia', + 'NZ' => 'New Zealand', + 'NI' => 'Nicaragua', + 'NE' => 'Niger', + 'NG' => 'Nigeria', + 'NU' => 'Niue', + 'NF' => 'Norfolk Island', + 'MP' => 'Northern Mariana Islands', + 'NO' => 'Norway', + 'OM' => 'Oman', + 'PK' => 'Pakistan', + 'PW' => 'Palau', + 'PS' => 'Palestinian Territory, Occupied', + 'PA' => 'Panama', + 'PG' => 'Papua New Guinea', + 'PY' => 'Paraguay', + 'PE' => 'Peru', + 'PH' => 'Philippines', + 'PN' => 'Pitcairn', + 'PL' => 'Poland', + 'PT' => 'Portugal', + 'PR' => 'Puerto Rico', + 'QA' => 'Qatar', + 'RE' => 'Reunion', + 'RO' => 'Romania', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'BL' => 'Saint Barthelemy', + 'SH' => 'Saint Helena', + 'KN' => 'Saint Kitts And Nevis', + 'LC' => 'Saint Lucia', + 'MF' => 'Saint Martin', + 'PM' => 'Saint Pierre And Miquelon', + 'VC' => 'Saint Vincent And Grenadines', + 'WS' => 'Samoa', + 'SM' => 'San Marino', + 'ST' => 'Sao Tome And Principe', + 'SA' => 'Saudi Arabia', + 'SN' => 'Senegal', + 'RS' => 'Serbia', + 'SC' => 'Seychelles', + 'SL' => 'Sierra Leone', + 'SG' => 'Singapore', + 'SK' => 'Slovakia', + 'SI' => 'Slovenia', + 'SB' => 'Solomon Islands', + 'SO' => 'Somalia', + 'ZA' => 'South Africa', + 'GS' => 'South Georgia And Sandwich Isl.', + 'ES' => 'Spain', + 'LK' => 'Sri Lanka', + 'SD' => 'Sudan', + 'SR' => 'Suriname', + 'SJ' => 'Svalbard And Jan Mayen', + 'SZ' => 'Swaziland', + 'SE' => 'Sweden', + 'CH' => 'Switzerland', + 'SY' => 'Syrian Arab Republic', + 'TW' => 'Taiwan', + 'TJ' => 'Tajikistan', + 'TZ' => 'Tanzania', + 'TH' => 'Thailand', + 'TL' => 'Timor-Leste', + 'TG' => 'Togo', + 'TK' => 'Tokelau', + 'TO' => 'Tonga', + 'TT' => 'Trinidad And Tobago', + 'TN' => 'Tunisia', + 'TR' => 'Turkey', + 'TM' => 'Turkmenistan', + 'TC' => 'Turks And Caicos Islands', + 'TV' => 'Tuvalu', + 'UG' => 'Uganda', + 'UA' => 'Ukraine', + 'AE' => 'United Arab Emirates', + 'GB' => 'United Kingdom', + 'US' => 'United States', + 'UM' => 'United States Outlying Islands', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VU' => 'Vanuatu', + 'VE' => 'Venezuela', + 'VN' => 'Viet Nam', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'WF' => 'Wallis And Futuna', + 'EH' => 'Western Sahara', + 'YE' => 'Yemen', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', + ]; + + $validator->addReplacer('country_iso_alpha2_code', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf("%s should be a valid country iso code", $attribute); + }); + + $value = trim($value); + return isset($countries[$value]); + }); } /** diff --git a/app/Repositories/Summit/DoctrineSummitLocationRepository.php b/app/Repositories/Summit/DoctrineSummitLocationRepository.php index f902a702..db06cb11 100644 --- a/app/Repositories/Summit/DoctrineSummitLocationRepository.php +++ b/app/Repositories/Summit/DoctrineSummitLocationRepository.php @@ -52,8 +52,8 @@ final class DoctrineSummitLocationRepository return [ 'name' => 'al.name:json_string', 'description' => 'al.description:json_string', - 'address1' => 'gll.address1:json_string', - 'address2' => 'gll.address2:json_string', + 'address_1' => 'gll.address1:json_string', + 'address_2' => 'gll.address2:json_string', 'zip_code' => 'gll.zip_code:json_string', 'city' => 'gll.city:json_string', 'state' => 'gll.state:json_string', diff --git a/app/Services/Apis/GoogleGeoCodingAPI.php b/app/Services/Apis/GoogleGeoCodingAPI.php index 888c1e1b..9951f12d 100644 --- a/app/Services/Apis/GoogleGeoCodingAPI.php +++ b/app/Services/Apis/GoogleGeoCodingAPI.php @@ -195,7 +195,7 @@ final class GoogleGeoCodingAPI implements IGeoCodingAPI break; } if($comp_type == 'country'){ - $components['country'] = $component['long_name']; + $components['country'] = $component['short_name']; break; } if($comp_type == 'postal_code'){ diff --git a/app/Services/Model/ILocationService.php b/app/Services/Model/ILocationService.php index dcc17b75..4f3fffa0 100644 --- a/app/Services/Model/ILocationService.php +++ b/app/Services/Model/ILocationService.php @@ -30,4 +30,14 @@ interface ILocationService * @throws ValidationException */ public function addLocation(Summit $summit, array $data); + + /** + * @param Summit $summit + * @param int $location_id + * @param array $data + * @return SummitAbstractLocation + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateLocation(Summit $summit, $location_id, array $data); } \ No newline at end of file diff --git a/app/Services/Model/LocationService.php b/app/Services/Model/LocationService.php index 6aea0c64..6c3569f7 100644 --- a/app/Services/Model/LocationService.php +++ b/app/Services/Model/LocationService.php @@ -133,4 +133,84 @@ final class LocationService implements ILocationService return $location; }); } + + /** + * @param Summit $summit + * @param int $location_id + * @param array $data + * @return SummitAbstractLocation + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateLocation(Summit $summit, $location_id, array $data) + { + return $this->tx_service->transaction(function() use($summit, $location_id, $data){ + + if(isset($data['name'])) { + $old_location = $summit->getLocationByName(trim($data['name'])); + + if (!is_null($old_location) && $old_location->getId() != $location_id) { + throw new ValidationException + ( + trans + ( + 'validation_errors.LocationService.updateLocation.LocationNameAlreadyExists', + [ + 'summit_id' => $summit->getId() + ] + ) + ); + } + } + + $location = $summit->getLocation($location_id); + if(is_null($location)){ + throw new EntityNotFoundException( + trans + ( + 'validation_errors.LocationService.updateLocation.LocationNotFoundOnSummit', + [ + 'summit_id' => $summit->getId(), + 'location_id' => $location_id, + ] + ) + ); + } + + $location = SummitLocationFactory::populate($location, $data); + + if($location instanceof SummitGeoLocatedLocation && (isset($data['address_1']) || isset($data['lat']))) { + try { + $geo_location_strategy = GeoLocationStrategyFactory::build($location); + $geo_location_strategy->doGeoLocation($location, $this->geo_coding_api); + } + catch (GeoCodingApiException $ex1){ + Log::warning($ex1->getMessage()); + $validation_msg = trans('validation_errors.LocationService.addLocation.geoCodingGenericError'); + switch ($ex1->getStatus()){ + case IGeoCodingAPI::ResponseStatusZeroResults: { + $validation_msg = trans('validation_errors.LocationService.addLocation.InvalidAddressOrCoordinates'); + } + break; + case IGeoCodingAPI::ResponseStatusOverQueryLimit: { + $validation_msg = trans('validation_errors.LocationService.addLocation.OverQuotaLimit'); + } + break; + } + throw new ValidationException($validation_msg); + } + catch(\Exception $ex){ + Log::warning($ex->getMessage()); + throw $ex; + } + } + + if(isset($data['order']) && intval($data['order']) != $location->getOrder()){ + // request to update order + $summit->recalculateLocationOrder($location, intval($data['order'])); + } + + return $location; + }); + } } \ No newline at end of file diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index 3ced9eb4..25c48912 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -482,6 +482,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::WriteLocationsData, $current_realm) ], ], + [ + 'name' => 'update-location', + 'route' => '/api/v1/summits/{id}/locations/{location_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteLocationsData, $current_realm) + ], + ], [ 'name' => 'get-locations-metadata', 'route' => '/api/v1/summits/{id}/locations/metadata', @@ -509,6 +518,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::WriteLocationsData, $current_realm) ], ], + [ + 'name' => 'update-venue', + 'route' => '/api/v1/summits/{id}/locations/venues/{venue_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteLocationsData, $current_realm) + ], + ], [ 'name' => 'get-external-locations', 'route' => '/api/v1/summits/{id}/locations/external-locations', @@ -527,6 +545,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::WriteLocationsData, $current_realm) ], ], + [ + 'name' => 'update-external-location', + 'route' => '/api/v1/summits/{id}/locations/external-locations/{external_location_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteLocationsData, $current_realm) + ], + ], [ 'name' => 'get-hotels', 'route' => '/api/v1/summits/{id}/locations/hotels', @@ -545,6 +572,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::WriteLocationsData, $current_realm) ], ], + [ + 'name' => 'update-hotel', + 'route' => '/api/v1/summits/{id}/locations/hotels/{hotel_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteLocationsData, $current_realm) + ], + ], [ 'name' => 'get-airports', 'route' => '/api/v1/summits/{id}/locations/airports', @@ -563,6 +599,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::WriteLocationsData, $current_realm) ], ], + [ + 'name' => 'update-airport', + 'route' => '/api/v1/summits/{id}/locations/airports/{airport_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteLocationsData, $current_realm) + ], + ], [ 'name' => 'get-location', 'route' => '/api/v1/summits/{id}/locations/{location_id}', diff --git a/resources/lang/en/validation_errors.php b/resources/lang/en/validation_errors.php index 043a8036..588096da 100644 --- a/resources/lang/en/validation_errors.php +++ b/resources/lang/en/validation_errors.php @@ -30,5 +30,7 @@ return [ 'LocationService.addLocation.InvalidClassName' => 'invalid class name', 'LocationService.addLocation.InvalidAddressOrCoordinates' => 'was passed a non-existent address', 'LocationService.addLocation.OverQuotaLimit' => 'geocode api over rate limit, try again later', - 'LocationService.addLocation.geoCodingGenericError' => 'geocode api generic error' + 'LocationService.addLocation.geoCodingGenericError' => 'geocode api generic error', + 'LocationService.updateLocation.LocationNameAlreadyExists' => 'there is already another location with same name for summit :summit_id', + 'LocationService.updateLocation.LocationNotFoundOnSummit' => 'location :location_id not found on summit :summit_id', ]; \ No newline at end of file diff --git a/tests/OAuth2SummitLocationsApiTest.php b/tests/OAuth2SummitLocationsApiTest.php index 4100d769..980ecb97 100644 --- a/tests/OAuth2SummitLocationsApiTest.php +++ b/tests/OAuth2SummitLocationsApiTest.php @@ -540,7 +540,7 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest * @param int $summit_id * @return mixed */ - public function testAddLocationHotelLatLng($summit_id = 24){ + public function testAddLocationHotelAddress($summit_id = 24){ $params = [ 'id' => $summit_id, @@ -550,10 +550,10 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest $data = [ 'name' => $name, - 'address1' => 'H. de Malvinas 1724', + 'address_1' => 'H. de Malvinas 1724', 'city' => 'Lanus Este', 'state' => 'Buenos Aires', - 'country' => 'Argentina', + 'country' => 'AR', 'zip_code' => '1824', 'class_name' => \models\summit\SummitHotel::ClassName, 'hotel_type' => \models\summit\SummitHotel::HotelTypePrimary, @@ -582,4 +582,42 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest $this->assertTrue(!is_null($location)); return $location; } + + public function testUpdateLocationHotelOrder($summit_id = 24){ + + $hotel = $this->testAddLocationHotelAddress($summit_id); + $new_order = 9; + $params = [ + 'id' => $summit_id, + 'location_id' => $hotel->id + ]; + + $data = [ + 'order' => $new_order, + 'class_name' => \models\summit\SummitHotel::ClassName, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitLocationsApiController@updateLocation", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $location = json_decode($content); + $this->assertTrue(!is_null($location)); + $this->assertTrue($location->order == $new_order); + return $location; + } } \ No newline at end of file