Added new endpoints to add locations per summit

POST /api/v1/summits/{id}/locations
POST /api/v1/summits/{id}/locations/venues
POST /api/v1/summits/{id}/locations/external-locations
POST /api/v1/summits/{id}/locations/hotels
POST /api/v1/summits/{id}/locations/airports

Required Scopes

'%s/summits/write'
'%s/locations/write'

Payload For SummitVenue

* class_name = SummitVenue
* name (required|string:max:255)
* description (sometimes|string)
* address1 (string|required_without:lng,lat)
* address2 (sometimes|string)
* 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)
* website_url (sometimes|url)
* display_on_site (sometimes|boolean)
* details_page (sometimes|boolean)
* location_message (sometimes|string)
* is_main (sometimes|boolean)

Payload For SummitHotel

* class_name = SummitHotel
* name (required|string:max:255)
* description (sometimes|string)
* address1 (string|required_without:lng,lat)
* address2 (sometimes|string)
* 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)
* website_url (sometimes|url)
* display_on_site (sometimes|boolean)
* details_page (sometimes|boolean)
* location_message (sometimes|string)
* capacity (sometimes|integer:min:0)
* hotel_type (sometimes|in:Primary,Alternate)
* sold_out (sometimes|boolean)
* booking_link (sometimes|url)

Payload For SummitAirport

* class_name = SummitAirport
* name (required|string:max:255)
* description (sometimes|string)
* address1 (string|required_without:lng,lat)
* address2 (sometimes|string)
* 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)
* website_url (sometimes|url)
* display_on_site (sometimes|boolean)
* details_page (sometimes|boolean)
* location_message (sometimes|string)
* capacity (sometimes|integer:min:0)
* airport_type (sometimes|in:International,Domestic)

Payload For SummitExternalLocation

* class_name = SummitExternalLocation
* name (required|string:max:255)
* description (sometimes|string)
* address1 (string|required_without:lng,lat)
* address2 (sometimes|string)
* 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)
* website_url (sometimes|url)
* display_on_site (sometimes|boolean)
* details_page (sometimes|boolean)
* location_message (sometimes|string)
* capacity (sometimes|integer:min:0)

Change-Id: Ie52d6e4864e2cdb1af100e2c325e02e92f1de9bd
This commit is contained in:
Sebastian Marcet 2018-03-01 16:03:23 -03:00
parent 1ebb1cd908
commit 7bd426fac9
38 changed files with 1906 additions and 29 deletions

View File

@ -67,4 +67,5 @@ SSH_USER=
SSH_PUBLIC_KEY=
SSH_PRIVATE_KEY=
SCP_HOST=
SCP_REMOTE_BASE_PATH=/tmp
SCP_REMOTE_BASE_PATH=/tmp
GOOGLE_GEO_CODING_API_KEY=

View File

@ -13,6 +13,7 @@
**/
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\App;
use models\summit\factories\IPresentationVideoFactory;
/**
* Class FactoriesProvider
* @package factories
@ -27,6 +28,6 @@ final class FactoriesProvider extends ServiceProvider
public function register()
{
App::singleton(\models\summit\factories\IPresentationVideoFactory::class, \factories\PresentationVideoFactory::class);
App::singleton(IPresentationVideoFactory::class, PresentationVideoFactory::class);
}
}

View File

@ -1,6 +1,6 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2016 OpenStack Foundation
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@ -11,10 +11,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Http\Utils\PagingConstants;
use App\Models\Foundation\Summit\Locations\SummitLocationConstants;
use App\Models\Foundation\Summit\Repositories\ISummitLocationRepository;
use App\Services\Model\ILocationService;
use Exception;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Log;
@ -27,6 +27,10 @@ use models\summit\IEventFeedbackRepository;
use models\summit\ISpeakerRepository;
use models\summit\ISummitEventRepository;
use models\summit\ISummitRepository;
use models\summit\SummitAirport;
use models\summit\SummitExternalLocation;
use models\summit\SummitHotel;
use models\summit\SummitVenue;
use ModelSerializers\SerializerRegistry;
use services\model\ISummitService;
use utils\Filter;
@ -36,7 +40,6 @@ use utils\FilterParserException;
use utils\OrderParser;
use utils\PagingInfo;
use utils\PagingResponse;
/**
* Class OAuth2SummitLocationsApiController
* @package App\Http\Controllers
@ -46,7 +49,7 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
/**
* @var ISummitService
*/
private $service;
private $summit_service;
/**
* @var ISpeakerRepository
@ -68,7 +71,22 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
*/
private $location_repository;
/**
* @var ILocationService
*/
private $location_service;
/**
* OAuth2SummitLocationsApiController constructor.
* @param ISummitRepository $summit_repository
* @param ISummitEventRepository $event_repository
* @param ISpeakerRepository $speaker_repository
* @param IEventFeedbackRepository $event_feedback_repository
* @param ISummitLocationRepository $location_repository
* @param ISummitService $summit_service
* @param ILocationService $location_service
* @param IResourceServerContext $resource_server_context
*/
public function __construct
(
ISummitRepository $summit_repository,
@ -76,7 +94,8 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
ISpeakerRepository $speaker_repository,
IEventFeedbackRepository $event_feedback_repository,
ISummitLocationRepository $location_repository,
ISummitService $service,
ISummitService $summit_service,
ILocationService $location_service,
IResourceServerContext $resource_server_context
) {
parent::__construct($resource_server_context);
@ -85,7 +104,8 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
$this->event_repository = $event_repository;
$this->event_feedback_repository = $event_feedback_repository;
$this->location_repository = $location_repository;
$this->service = $service;
$this->location_service = $location_service;
$this->summit_service = $summit_service;
}
/**
@ -530,4 +550,212 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
$this->location_repository->getMetadata($summit)
);
}
/***
* Add Locations Endpoints
*/
/**
* @param $summit_id
* @return mixed
*/
public function addLocation($summit_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);
// 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->addLocation($summit, $payload);
return $this->created(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
* @return mixed
*/
public function addVenue($summit_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);
// 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->addLocation($summit, $payload);
return $this->created(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);
}
}
public function addExternalLocation($summit_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);
// 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->addLocation($summit, $payload);
return $this->created(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);
}
}
public function addHotel($summit_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);
// 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->addLocation($summit, $payload);
return $this->created(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);
}
}
public function addAirport($summit_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);
// 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->addLocation($summit, $payload);
return $this->created(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);
}
}
}

View File

@ -0,0 +1,40 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SummitAbstractLocationValidationRulesFactory
* @package App\Http\Controllers
*/
final class SummitAbstractLocationValidationRulesFactory
{
/**
* @param array $data
* @param bool $update
* @return array
*/
public static function build(array $data, $update = false){
$name_rule = 'required|string|max:255';
if($update){
$name_rule = 'sometimes|string|max:255';
}
$rules = [
'name' => $name_rule,
'description' => 'sometimes|string',
];
return $rules;
}
}

View File

@ -0,0 +1,36 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use models\summit\SummitAirport;
/**
* Class SummitAirportValidationRulesFactory
* @package App\Http\Controllers
*/
final class SummitAirportValidationRulesFactory
{
/**
* @param array $data
* @param bool $update
* @return array
*/
public static function build(array $data, $update = false){
$rules = SummitExternalLocationValidationRulesFactory::build($data, $update);
return array_merge([
'airport_type' => sprintf('sometimes|in:%s,%s',SummitAirport::AirportTypeInternational, SummitAirport::AirportTypeDomestic),
], $rules);
}
}

View File

@ -0,0 +1,35 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SummitExternalLocationValidationRulesFactory
* @package App\Http\Controllers
*/
final class SummitExternalLocationValidationRulesFactory
{
/**
* @param array $data
* @param bool $update
* @return array
*/
public static function build(array $data, $update = false){
$rules = SummitGeoLocatedLocationValidationRulesFactory::build($data, $update);
return array_merge([
'capacity' => 'sometimes|integer|min:0'
], $rules);
}
}

View File

@ -0,0 +1,62 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SummitGeoLocatedLocationValidationRulesFactory
* @package App\Http\Controllers
*/
final class SummitGeoLocatedLocationValidationRulesFactory
{
/**
* @param array $data
* @param bool $update
* @return array
*/
public static function build(array $data, $update = false){
$rules = SummitAbstractLocationValidationRulesFactory::build($data, $update);
if($update) {
return array_merge([
'address1' => 'sometimes|string',
'address2' => 'sometimes|string',
'zip_code' => 'sometimes|string',
'city' => 'string|required_with:address1',
'state' => 'string|required_with:address1',
'country' => 'string|required_with:address1',
'website_url' => 'sometimes|url',
'lng' => 'sometimes|geo_longitude|required_with:lat',
'lat' => 'sometimes|geo_latitude|required_with:lng',
'display_on_site' => 'sometimes|boolean',
'details_page' => 'sometimes|boolean',
'location_message' => 'sometimes|string',
], $rules);
}
return array_merge([
'address1' => 'string|required_without:lng,lat',
'address2' => 'sometimes|string',
'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',
'website_url' => 'sometimes|url',
'display_on_site' => 'sometimes|boolean',
'details_page' => 'sometimes|boolean',
'location_message' => 'sometimes|string',
], $rules);
}
}

View File

@ -0,0 +1,36 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use models\summit\SummitHotel;
/**
* Class SummitHotelValidationRulesFactory
* @package App\Http\Controllers
*/
final class SummitHotelValidationRulesFactory
{
/**
* @param array $data
* @param bool $update
* @return array
*/
public static function build(array $data, $update = false){
$rules = SummitExternalLocationValidationRulesFactory::build($data, $update);
return array_merge([
'hotel_type' => sprintf('sometimes|in:%s,%s',SummitHotel::HotelTypePrimary, SummitHotel::HotelTypeAlternate),
'sold_out' => 'sometimes|boolean',
'booking_link' => 'sometimes|url'
], $rules);
}
}

View File

@ -0,0 +1,60 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use models\exceptions\ValidationException;
use models\summit\SummitAirport;
use models\summit\SummitExternalLocation;
use models\summit\SummitHotel;
use models\summit\SummitVenue;
/**
* Class SummitLocationValidationRulesFactory
* @package App\Http\Controllers
*/
final class SummitLocationValidationRulesFactory
{
/**
* @param array $data
* @param bool $update
* @return array
* @throws ValidationException
*/
public static function build(array $data, $update = false){
if(!isset($data['class_name']))
throw new ValidationException('class_name is not set');
switch($data['class_name']){
case SummitVenue::ClassName: {
return SummitVenueValidationRulesFactory::build($data, $update);
}
break;
case SummitAirport::ClassName: {
return SummitAirportValidationRulesFactory::build($data, $update);
}
break;
case SummitHotel::ClassName: {
return SummitHotelValidationRulesFactory::build($data, $update);
}
break;
case SummitExternalLocation::ClassName: {
return SummitExternalLocationValidationRulesFactory::build($data, $update);
}
break;
default:{
throw new ValidationException('invalid class_name param');
}
break;
}
return [];
}
}

View File

@ -0,0 +1,31 @@
<?php namespace App\Http\Controllers;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SummitVenueValidationRulesFactory
* @package App\Http\Controllers
*/
final class SummitVenueValidationRulesFactory
{
/**
* @param array $data
* @param bool $update
* @return array
*/
public static function build(array $data, $update = false){
$rules = SummitGeoLocatedLocationValidationRulesFactory::build($data, $update);
$venues_rules = ['is_main' => 'sometimes|boolean'];
return array_merge($venues_rules, $rules);
}
}

View File

@ -279,16 +279,21 @@ Route::group([
});
// locations
Route::group(array('prefix' => 'locations'), function () {
Route::group(['prefix' => 'locations'], function () {
Route::get('', 'OAuth2SummitLocationsApiController@getLocations');
Route::get('/venues', 'OAuth2SummitLocationsApiController@getVenues');
Route::get('/external-locations', 'OAuth2SummitLocationsApiController@getExternalLocations');
Route::get('/hotels', 'OAuth2SummitLocationsApiController@getHotels');
Route::get('/airports', 'OAuth2SummitLocationsApiController@getAirports');
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::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(array('prefix' => '{location_id}'), function () {
Route::group(['prefix' => '{location_id}'], function () {
Route::get('', 'OAuth2SummitLocationsApiController@getLocation');
Route::get('/events/published','OAuth2SummitLocationsApiController@getLocationPublishedEvents')->where('location_id', 'tbd|[0-9]+');
Route::get('/events','OAuth2SummitLocationsApiController@getLocationEvents')->where('location_id', 'tbd|[0-9]+');

View File

@ -0,0 +1,204 @@
<?php namespace App\Models\Foundation\Summit\Factories;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use models\exceptions\ValidationException;
use models\summit\SummitAbstractLocation;
use models\summit\SummitAirport;
use models\summit\SummitExternalLocation;
use models\summit\SummitGeoLocatedLocation;
use models\summit\SummitHotel;
use models\summit\SummitVenue;
/**
* Class SummitLocationFactory
* @package App\Models\Foundation\Summit\Factories
*/
final class SummitLocationFactory
{
/**
* @param array $data
* @return SummitAbstractLocation|null
* @throws ValidationException
*/
public static function build(array $data){
if(!isset($data['class_name'])) throw new ValidationException("missing class_name param");
$location = null;
switch($data['class_name']){
case SummitVenue::ClassName :{
$location = self::populateSummitVenue(new SummitVenue, $data);
}
break;
case SummitExternalLocation::ClassName :{
$location = self::populateSummitExternalLocation(new SummitExternalLocation, $data);
}
break;
case SummitHotel::ClassName :{
$location = self::populateSummitHotel(new SummitHotel, $data);
}
break;
case SummitAirport::ClassName :{
$location = self::populateSummitAirport(new SummitAirport, $data);
}
break;
}
return $location;
}
/**
* @param SummitAbstractLocation $location
* @param array $data
* @return SummitAbstractLocation
*/
private static function populateSummitAbstractLocation(SummitAbstractLocation $location, array $data){
if(isset($data['name']))
$location->setName(trim($data['name']));
if(isset($data['description']))
$location->setDescription(trim($data['description']));
return $location;
}
/**
* @param SummitGeoLocatedLocation $location
* @param array $data
* @return SummitGeoLocatedLocation
*/
private static function populateSummitGeoLocatedLocation(SummitGeoLocatedLocation $location, array $data){
if(isset($data['address1']))
$location->setAddress1(trim($data['address1']));
if(isset($data['address2']))
$location->setAddress2(trim($data['address2']));
if(isset($data['zip_code']))
$location->setZipCode(trim($data['zip_code']));
if(isset($data['city']))
$location->setCity(trim($data['city']));
if(isset($data['state']))
$location->setState(trim($data['state']));
if(isset($data['country']))
$location->setCountry(trim($data['country']));
if(isset($data['website_url']))
$location->setWebsiteUrl(trim($data['website_url']));
if(isset($data['lng']))
$location->setLng(trim($data['lng']));
if(isset($data['lat']))
$location->setLat(trim($data['lat']));
if(isset($data['display_on_site']))
$location->setDisplayOnSite(boolval($data['display_on_site']));
if(isset($data['details_page']))
$location->setDetailsPage(boolval($data['details_page']));
if(isset($data['location_message']))
$location->setLocationMessage(trim($data['location_message']));
return $location;
}
/**
* @param SummitVenue $venue
* @param array $data
* @return SummitVenue
*/
public static function populateSummitVenue(SummitVenue $venue, array $data){
self::populateSummitGeoLocatedLocation
(
self::populateSummitAbstractLocation($venue, $data),
$data
);
if(isset($data['is_main']))
$venue->setIsMain(boolval($data['is_main']));
return $venue;
}
/**
* @param SummitExternalLocation $external_location
* @param array $data
* @return SummitExternalLocation
*/
public static function populateSummitExternalLocation(SummitExternalLocation $external_location, array $data){
self::populateSummitGeoLocatedLocation
(
self::populateSummitAbstractLocation($external_location, $data),
$data
);
if(isset($data['capacity']))
$external_location->setCapacity(intval($data['capacity']));
return $external_location;
}
/**
* @param SummitHotel $hotel
* @param array $data
* @return SummitHotel
*/
public static function populateSummitHotel(SummitHotel $hotel, array $data){
self::populateSummitExternalLocation
(
self::populateSummitGeoLocatedLocation
(
self::populateSummitAbstractLocation($hotel, $data),
$data
),
$data
);
if(isset($data['hotel_type']))
$hotel->setHotelType(trim($data['hotel_type']));
if(isset($data['sold_out']))
$hotel->setSoldOut(boolval($data['sold_out']));
if(isset($data['booking_link']))
$hotel->setBookingLink(trim($data['booking_link']));
return $hotel;
}
/**
* @param SummitAirport $airport
* @param array $data
* @return SummitAirport
*/
public static function populateSummitAirport(SummitAirport $airport, array $data){
self::populateSummitExternalLocation
(
self::populateSummitGeoLocatedLocation
(
self::populateSummitAbstractLocation($airport, $data),
$data
),
$data
);
if(isset($data['airport_type']))
$airport->setAirportType(trim($data['airport_type']));
return $airport;
}
}

View File

@ -57,7 +57,7 @@ class SummitAbstractLocation extends SilverstripeBaseModel
protected $type;
/**
* @ORM\Column(name="Order", type="integer")
* @ORM\Column(name="`Order`", type="integer")
*/
protected $order;

View File

@ -20,6 +20,9 @@ use Doctrine\ORM\Mapping AS ORM;
*/
class SummitAirport extends SummitExternalLocation
{
const AirportTypeInternational = 'International';
const AirportTypeDomestic = 'Domestic';
/**
* @return string
*/
@ -52,7 +55,7 @@ class SummitAirport extends SummitExternalLocation
public static $metadata = [
'class_name' => self::ClassName,
'airport_type' => 'string',
'airport_type' => [self::AirportTypeInternational, self::AirportTypeDomestic],
];
/**
@ -61,4 +64,10 @@ class SummitAirport extends SummitExternalLocation
public static function getMetadata(){
return array_merge(SummitExternalLocation::getMetadata(), self::$metadata);
}
public function __construct()
{
parent::__construct();
$this->airport_type = self::AirportTypeInternational;
}
}

View File

@ -66,4 +66,10 @@ class SummitExternalLocation extends SummitGeoLocatedLocation
return array_merge(SummitGeoLocatedLocation::getMetadata(), self::$metadata);
}
public function __construct()
{
parent::__construct();
$this->type = self::TypeExternal;
$this->capacity = 0;
}
}

View File

@ -344,6 +344,8 @@ class SummitGeoLocatedLocation extends SummitAbstractLocation
public function __construct()
{
parent::__construct();
$this->details_page = false;
$this->display_on_site = false;
$this->images = new ArrayCollection();
}
@ -389,4 +391,5 @@ class SummitGeoLocatedLocation extends SummitAbstractLocation
)->first();
return $res === false ? null : $res;
}
}

View File

@ -22,6 +22,10 @@ use Doctrine\ORM\Mapping AS ORM;
*/
class SummitHotel extends SummitExternalLocation
{
const HotelTypePrimary = "Primary";
const HotelTypeAlternate = "Alternate";
/**
* @return string
*/
@ -95,7 +99,7 @@ class SummitHotel extends SummitExternalLocation
public static $metadata = [
'class_name' => self::ClassName,
'hotel_type' => 'string',
'hotel_type' => [self::HotelTypePrimary, self::HotelTypeAlternate],
'sold_out' => 'boolean',
'booking_link' => 'string',
];
@ -107,4 +111,11 @@ class SummitHotel extends SummitExternalLocation
return array_merge(SummitExternalLocation::getMetadata(), self::$metadata);
}
public function __construct()
{
parent::__construct();
$this->sold_out = false;
$this->type = self::HotelTypePrimary;
}
}

View File

@ -34,8 +34,10 @@ class SummitVenue extends SummitGeoLocatedLocation
public function __construct()
{
parent::__construct();
$this->rooms = new ArrayCollection();
$this->floors = new ArrayCollection();
$this->is_main = false;
$this->type = self::TypeInternal;
$this->rooms = new ArrayCollection();
$this->floors = new ArrayCollection();
}
/**

View File

@ -608,11 +608,24 @@ class Summit extends SilverstripeBaseModel
/**
* @param SummitAbstractLocation $location
* @return $this
*/
public function addLocation(SummitAbstractLocation $location)
{
$this->locations->add($location);
$location->setSummit($this);
$location->setOrder($this->getLocationMaxOrder() + 1);
return $this;
}
/**
* @return int
*/
private function getLocationMaxOrder(){
$criteria = Criteria::create();
$criteria->orderBy(['order' => 'DESC']);
$location = $this->locations->matching($criteria)->first();
return $location === false ? 0 : $location->getOrder();
}
/**
@ -633,6 +646,18 @@ class Summit extends SilverstripeBaseModel
});
}
/**
* @param string $name
* @return SummitAbstractLocation|null
*/
public function getLocationByName($name){
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('name', trim($name)));
$location = $this->locations->matching($criteria)->first();
return $location === false ? null : $location;
}
/**
* @return SummitHotel[]
*/

View File

@ -248,6 +248,28 @@ class AppServiceProvider extends ServiceProvider
if(!ctype_xdigit($value)) return false;
return true;
});
Validator::extend('geo_latitude', function($attribute, $value, $parameters, $validator)
{
$validator->addReplacer('geo_latitude', function($message, $attribute, $rule, $parameters) use ($validator) {
return sprintf("%s should be a valid coordinate value (-90.00,+90.00)", $attribute);
});
$value = floatval($value);
return !($value < -90.00 || $value > 90.00);
});
Validator::extend('geo_longitude', function($attribute, $value, $parameters, $validator)
{
$validator->addReplacer('geo_longitude', function($message, $attribute, $rule, $parameters) use ($validator) {
return sprintf("%s should be a valid coordinate value (-180.00,+180.00)", $attribute);
});
$value = floatval($value);
return !($value < -180.00 || $value > 180.00);
});
}
/**

View File

@ -39,5 +39,7 @@ final class SummitScopes
const WriteTracksData = '%s/tracks/write';
const WriteLocationsData = '%s/locations/write';
const WriteSummitSpeakerAssistanceData = '%s/summit-speaker-assistance/write';
}

View File

@ -0,0 +1,64 @@
<?php namespace App\Services\Apis;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class AddressInfo
* @package App\Services\Apis
*/
final class AddressInfo {
private $address;
private $address1;
private $zip_code;
private $state;
private $city;
private $country;
/**
* @param string $address
* @param string $address1
* @param string $zip_code
* @param string $state
* @param string $city
* @param string $country
*/
public function __construct($address,$address1,$zip_code,$state,$city,$country){
$this->address = $address;
$this->address1 = $address1;
$this->zip_code = $zip_code;
$this->state = $state;
$this->city = $city;
$this->country = $country;
}
public function getAddress(){
return array($this->address,$this->address1);
}
public function getZipCode(){
return $this->zip_code;
}
public function getState(){
return $this->state;
}
public function getCity(){
return $this->city;
}
public function getCountry(){
return $this->country;
}
}

View File

@ -15,7 +15,6 @@ use GuzzleHttp\Client;
use Exception;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;
/**
* Class EventbriteAPI
* @package services\apis

View File

@ -0,0 +1,40 @@
<?php namespace App\Services\Apis;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class GeoCodingApiException
* @package App\Services\Apis
*/
final class GeoCodingApiException extends \Exception
{
private $status;
/**
* GeoCodingApiException constructor.
* @param $status
*/
public function __construct($status)
{
parent::__construct($status);
$this->status = $status;
}
/**
* @return string
*/
public function getStatus()
{
return $this->status;
}
}

View File

@ -0,0 +1,57 @@
<?php namespace App\Services\Apis;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class GeoCoordinatesInfo
* @package App\Services\Apis
*/
final class GeoCoordinatesInfo
{
/**
* @var string
*/
private $lat;
/**
* @var string
*/
private $lng;
/**
* GeoCoordinatesInfo constructor.
* @param string $lat
* @param string $lng
*/
public function __construct($lat, $lng)
{
$this->lat = $lat;
$this->lng = $lng;
}
/**
* @return string
*/
public function getLat()
{
return $this->lat;
}
/**
* @return string
*/
public function getLng()
{
return $this->lng;
}
}

View File

@ -0,0 +1,226 @@
<?php namespace App\Services\Apis;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use GuzzleHttp\Client;
use Exception;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;
/**
* Class GoogleGeoCodingAPI
* @see https://developers.google.com/maps/documentation/geocoding/
* Users of the free API:
* 2,500 requests per 24 hour period.
* @package App\Services\Apis
*/
final class GoogleGeoCodingAPI implements IGeoCodingAPI
{
const BaseUrl = 'https://maps.googleapis.com/maps/api/geocode/json';
/**
* @var string
*/
private $api_key;
/**
* @var Client
*/
private $client;
/**
* GoogleGeoCodingAPI constructor.
* @param string $api_key
*/
public function __construct($api_key)
{
$this->api_key = $api_key;
$this->client = new Client();
}
/**
* @param AddressInfo $address_info
* @return GeoCoordinatesInfo
* @throws GeoCodingApiException
*/
public function getGeoCoordinates(AddressInfo $address_info)
{
list($address1, $address2) = $address_info->getAddress();
$address = $address1 . ' ' . $address2;
$city = $address_info->getCity();
$state = $address_info->getState();
if (!empty($city)) {
$address .= ", {$city}";
}
if (!empty($state)) {
$address .= ", {$state}";
}
$zip_code = $address_info->getZipCode();
$country = $address_info->getCountry();
$formatted_city = urlencode($city);
$components = "locality:{$formatted_city}|country:{$country}";
$params = [];
if (!empty($state)) {
$formatted_state = urlencode($state);
$components .= "|administrative_area:{$formatted_state}";
}
if (!empty($address)) {
$formatted_address = urlencode($address);
$components .= "|address:{$formatted_address}";
}
$params['components'] = $components;
if (!empty($zip_code)) {
$params['postal_code'] = urlencode($zip_code);
}
$response = $this->doRequest($params);
if($response['status'] != GoogleGeoCodingAPI::ResponseStatusOK){
throw new GeoCodingApiException($response['status']);
}
return new GeoCoordinatesInfo
(
$response['results'][0]['geometry']['location']['lat'],
$response['results'][0]['geometry']['location']['lng']
);
}
/**
* @param array $params
* @return array
* @throws Exception
* @throws RequestException
*/
private function doRequest(array $params){
try {
$query = [
'key' => $this->api_key
];
foreach ($params as $param => $value) {
$query[$param] = $value;
}
$response = $this->client->get(self::BaseUrl, [
'query' => $query
]
);
if ($response->getStatusCode() !== 200)
throw new Exception('invalid status code!');
$content_type = $response->getHeaderLine('content-type');
if (empty($content_type))
throw new Exception('invalid content type!');
if (!strstr($content_type, 'application/json') )
throw new Exception('invalid content type!');
$json = $response->getBody()->getContents();
return json_decode($json, true);
}
catch(RequestException $ex){
Log::warning($ex->getMessage());
throw $ex;
}
}
/**
* @param GeoCoordinatesInfo $coordinates
* @return AddressInfo
* @throws GeoCodingApiException
*/
public function getAddressInfo(GeoCoordinatesInfo $coordinates)
{
$params = [
'latlng' => sprintf("%s,%s", $coordinates->getLat(), $coordinates->getLng())
];
$response = $this->doRequest($params);
if($response['status'] != IGeoCodingAPI::ResponseStatusOK){
throw new GeoCodingApiException($response['status']);
}
$results = $response['results'];
$street_address = null;
foreach($results as $result){
$types = $result['types'];
foreach($types as $type) {
if ($type == 'street_address') {
$street_address = $result;
break;
}
}
if(!is_null($street_address)) break;
}
if(is_null($street_address))
throw new GeoCodingApiException(IGeoCodingAPI::ResponseStatusZeroResults);
$components = [];
foreach ($street_address['address_components'] as $component){
foreach($component['types'] as $comp_type){
if($comp_type == 'street_number'){
$components['street_number'] = $component['long_name'];
break;
}
if($comp_type == 'route'){
$components['street_name'] = $component['long_name'];
break;
}
if($comp_type == 'locality'){
$components['city'] = $component['long_name'];
break;
}
if($comp_type == 'administrative_area_level_1'){
$components['state'] = $component['long_name'];
break;
}
if($comp_type == 'country'){
$components['country'] = $component['long_name'];
break;
}
if($comp_type == 'postal_code'){
$components['zip_code'] = $component['long_name'];
break;
}
if($comp_type == 'postal_code'){
$components['zip_code'] = $component['long_name'];
break;
}
}
}
if(isset($components['street_name']) && isset($components['street_number'])){
$components['address1'] = sprintf("%s %s", $components['street_name'], $components['street_number']);
}
return new AddressInfo
(
isset($components['address1']) ? $components['address1'] : '',
isset($components['address2']) ? $components['address2'] : '',
isset($components['zip_code']) ? $components['zip_code'] : '',
isset($components['state']) ? $components['state'] : '',
isset($components['city']) ? $components['city'] : '',
isset($components['country']) ? $components['country'] : ''
);
}
}

View File

@ -0,0 +1,67 @@
<?php namespace App\Services\Apis;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface IGeoCodingAPI
* @package App\Services\Apis
*/
interface IGeoCodingAPI
{
/**
* indicates that no errors occurred; the address was successfully parsed
* and at least one geocode was returned.
*/
const ResponseStatusOK = 'OK';
/**
* indicates that the geocode was successful but returned no results.
* This may occur if the geocoder was passed a non-existent address
*/
const ResponseStatusZeroResults = 'ZERO_RESULTS';
/**
* indicates that you are over your quota.
*/
const ResponseStatusOverQueryLimit = 'OVER_QUERY_LIMIT';
/**
* indicates that your request was denied.
*/
const ResponseStatusRequestDenied = 'REQUEST_DENIED';
/**
* generally indicates that the query (address, components or latlng) is missing.
*/
const ResponseStatusInvalidRequest = 'INVALID_REQUEST';
/**
* indicates that the request could not be processed due to a server error.
* The request may succeed if you try again.
*/
const ResponseStatusUnknownError = 'UNKNOWN_ERROR';
/**
* @param AddressInfo $address_info
* @return GeoCoordinatesInfo
* @throws GeoCodingApiException
*/
public function getGeoCoordinates(AddressInfo $address_info);
/**
* @param GeoCoordinatesInfo $coordinates
* @return AddressInfo
* @throws GeoCodingApiException
*/
public function getAddressInfo(GeoCoordinatesInfo $coordinates);
}

View File

@ -0,0 +1,33 @@
<?php namespace App\Services\Model;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\summit\Summit;
use models\summit\SummitAbstractLocation;
use models\summit\SummitVenue;
/**
* Interface ILocationService
* @package App\Services\Model
*/
interface ILocationService
{
/**
* @param Summit $summit
* @param array $data
* @return SummitAbstractLocation
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function addLocation(Summit $summit, array $data);
}

View File

@ -0,0 +1,136 @@
<?php namespace App\Services\Model;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Models\Foundation\Summit\Factories\SummitLocationFactory;
use App\Models\Foundation\Summit\Repositories\ISummitLocationRepository;
use App\Services\Apis\AddressInfo;
use App\Services\Apis\GeoCodingApiException;
use App\Services\Apis\GeoCoordinatesInfo;
use App\Services\Apis\IGeoCodingAPI;
use App\Services\Model\Strategies\GeoLocation\GeoLocationStrategyFactory;
use Illuminate\Support\Facades\Log;
use libs\utils\ITransactionService;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\summit\Summit;
use models\summit\SummitAbstractLocation;
use models\summit\SummitGeoLocatedLocation;
use models\summit\SummitVenue;
/**
* Class LocationService
* @package App\Services\Model
*/
final class LocationService implements ILocationService
{
/**
* @var ISummitLocationRepository
*/
private $location_repository;
/**
* @var ITransactionService
*/
private $tx_service;
/**
* @var IGeoCodingAPI
*/
private $geo_coding_api;
/**
* LocationService constructor.
* @param ISummitLocationRepository $location_repository
* @param IGeoCodingAPI $geo_coding_api
* @param ITransactionService $tx_service
*/
public function __construct
(
ISummitLocationRepository $location_repository,
IGeoCodingAPI $geo_coding_api,
ITransactionService $tx_service
)
{
$this->location_repository = $location_repository;
$this->geo_coding_api = $geo_coding_api;
$this->tx_service = $tx_service;
}
/**
* @param Summit $summit
* @param array $data
* @return SummitAbstractLocation
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function addLocation(Summit $summit, array $data)
{
return $this->tx_service->transaction(function() use($summit, $data){
$old_location = $summit->getLocationByName(trim($data['name']));
if(!is_null($old_location)){
throw new ValidationException
(
trans
(
'validation_errors.LocationService.addLocation.LocationNameAlreadyExists',
[
'summit_id' => $summit->getId()
]
)
);
}
$location = SummitLocationFactory::build($data);
if(is_null($location)){
throw new ValidationException
(
trans
(
'validation_errors.LocationService.addLocation.InvalidClassName'
)
);
}
if($location instanceof SummitGeoLocatedLocation) {
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;
}
}
$summit->addLocation($location);
return $location;
});
}
}

View File

@ -0,0 +1,49 @@
<?php namespace App\Services\Model\Strategies\GeoLocation;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Services\Apis\AddressInfo;
use App\Services\Apis\IGeoCodingAPI;
use models\summit\SummitGeoLocatedLocation;
/**
* Class GeoLocationAddressInfoStrategy
* @package App\Services\Model\Strategies\GeoLocation
*/
final class GeoLocationAddressInfoStrategy implements IGeoLocationStrategy
{
/**
* @param SummitGeoLocatedLocation $location
* @param IGeoCodingAPI $geo_coding_api
* @return SummitGeoLocatedLocation
*/
public function doGeoLocation(SummitGeoLocatedLocation $location, IGeoCodingAPI $geo_coding_api)
{
$response = $geo_coding_api->getGeoCoordinates
(
new AddressInfo
(
$location->getAddress1(),
$location->getAddress2(),
$location->getZipCode(),
$location->getState(),
$location->getCity(),
$location->getCountry()
)
);
$location->setLat($response->getLat());
$location->setLng($response->getLng());
return $location;
}
}

View File

@ -0,0 +1,46 @@
<?php namespace App\Services\Model\Strategies\GeoLocation;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Services\Apis\GeoCoordinatesInfo;
use App\Services\Apis\IGeoCodingAPI;
use models\summit\SummitGeoLocatedLocation;
/**
* Class GeoLocationReverseStrategy
* @package App\Services\Model\Strategies\GeoLocation
*/
final class GeoLocationReverseStrategy implements IGeoLocationStrategy
{
/**
* @param SummitGeoLocatedLocation $location
* @param IGeoCodingAPI $geo_coding_api
* @return SummitGeoLocatedLocation
*/
public function doGeoLocation(SummitGeoLocatedLocation $location, IGeoCodingAPI $geo_coding_api)
{
$response = $geo_coding_api->getAddressInfo
(
new GeoCoordinatesInfo
(
$location->getLat(),
$location->getLng()
)
);
$location->setAddress1($response->getAddress()[0]);
$location->setZipCode($response->getZipCode());
$location->setState($response->getState());
$location->setCity($response->getCity());
$location->setCountry($response->getCountry());
return $location;
}
}

View File

@ -0,0 +1,30 @@
<?php namespace App\Services\Model\Strategies\GeoLocation;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use models\summit\SummitGeoLocatedLocation;
/**
* Class GeoLocationStrategyFactory
* @package App\Services\Model\Strategies\GeoLocation
*/
final class GeoLocationStrategyFactory
{
/**
* @param SummitGeoLocatedLocation $location
* @return IGeoLocationStrategy
*/
public static function build(SummitGeoLocatedLocation $location){
if (!empty($location->getAddress1()))
return new GeoLocationAddressInfoStrategy();
return new GeoLocationReverseStrategy();
}
}

View File

@ -0,0 +1,28 @@
<?php namespace App\Services\Model\Strategies\GeoLocation;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Services\Apis\IGeoCodingAPI;
use models\summit\SummitGeoLocatedLocation;
/**
* Interface IGeoLocationStrategy
* @package App\Services\Model\Strategies\GeoLocation
*/
interface IGeoLocationStrategy
{
/**
* @param SummitGeoLocatedLocation $location
* @param IGeoCodingAPI $geo_coding_api
* @return SummitGeoLocatedLocation
*/
public function doGeoLocation(SummitGeoLocatedLocation $location, IGeoCodingAPI $geo_coding_api);
}

View File

@ -11,11 +11,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Services\Apis\GoogleGeoCodingAPI;
use App\Services\Apis\IGeoCodingAPI;
use App\Services\Model\AttendeeService;
use App\Services\Model\IAttendeeService;
use App\Services\Model\ILocationService;
use App\Services\Model\IMemberService;
use App\Services\Model\ISummitEventTypeService;
use App\Services\Model\ISummitTrackService;
use App\Services\Model\LocationService;
use App\Services\Model\MemberService;
use App\Services\Model\SummitPromoCodeService;
use App\Services\Model\SummitTrackService;
@ -27,12 +31,23 @@ use ModelSerializers\BaseSerializerTypeSelector;
use ModelSerializers\ISerializerTypeSelector;
use services\apis\EventbriteAPI;
use services\apis\FireBaseGCMApi;
use services\apis\IEventbriteAPI;
use services\apis\IPushNotificationApi;
use services\model\IPresentationService;
use services\model\ISpeakerService;
use services\model\ISummitPromoCodeService;
use libs\utils\ICacheService;
use services\model\ISummitService;
use services\model\PresentationService;
use services\model\SpeakerService;
use services\model\SummitService;
use services\utils\RedisCacheService;
/***
* Class ServicesProvider
* @package services
*/
class ServicesProvider extends ServiceProvider
final class ServicesProvider extends ServiceProvider
{
protected $defer = false;
@ -42,7 +57,7 @@ class ServicesProvider extends ServiceProvider
public function register()
{
App::singleton('libs\utils\ICacheService', 'services\utils\RedisCacheService');
App::singleton(ICacheService::class, RedisCacheService::class);
App::singleton(\libs\utils\ITransactionService::class, function(){
return new \services\utils\DoctrineTransactionService('ss');
@ -65,21 +80,21 @@ class ServicesProvider extends ServiceProvider
App::singleton(ISerializerTypeSelector::class, BaseSerializerTypeSelector::class);
App::singleton('services\model\ISummitService', 'services\model\SummitService');
App::singleton(ISummitService::class, SummitService::class);
App::singleton('services\model\ISpeakerService', 'services\model\SpeakerService');
App::singleton(ISpeakerService::class, SpeakerService::class);
App::singleton('services\model\IPresentationService', 'services\model\PresentationService');
App::singleton(IPresentationService::class, PresentationService::class);
App::singleton('services\model\IChatTeamService', 'services\model\ChatTeamService');
App::singleton('services\apis\IEventbriteAPI', function(){
App::singleton(IEventbriteAPI::class, function(){
$api = new EventbriteAPI();
$api->setCredentials(array('token' => Config::get("server.eventbrite_oauth2_personal_token", null)));
return $api;
});
App::singleton('services\apis\IPushNotificationApi', function(){
App::singleton(IPushNotificationApi::class, function(){
$api = new FireBaseGCMApi(Config::get("server.firebase_gcm_server_key", null));
return $api;
});
@ -151,5 +166,18 @@ class ServicesProvider extends ServiceProvider
ISummitTrackService::class,
SummitTrackService::class
);
App::singleton
(
ILocationService::class,
LocationService::class
);
App::singleton(IGeoCodingAPI::class, function(){
return new GoogleGeoCodingAPI
(
Config::get("server.google_geocoding_api_key", null)
);
});
}
}

View File

@ -24,4 +24,5 @@ return array
'firebase_gcm_server_key' => env('FIREBASE_GCM_SERVER_KEY', ''),
'ss_encrypt_key' => env('SS_ENCRYPT_KEY', ''),
'ss_encrypt_cypher' => env('SS_ENCRYPT_CYPHER', ''),
'google_geocoding_api_key' => env('GOOGLE_GEO_CODING_API_KEY', ''),
);

View File

@ -464,7 +464,7 @@ class ApiEndpointsSeeder extends Seeder
'scopes' => [sprintf(SummitScopes::WriteSummitData, $current_realm)],
),
// locations
[
[
'name' => 'get-locations',
'route' => '/api/v1/summits/{id}/locations',
'http_method' => 'GET',
@ -472,7 +472,16 @@ class ApiEndpointsSeeder extends Seeder
sprintf(SummitScopes::ReadSummitData, $current_realm),
sprintf(SummitScopes::ReadAllSummitData, $current_realm)
],
],
],
[
'name' => 'add-location',
'route' => '/api/v1/summits/{id}/locations',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::WriteSummitData, $current_realm),
sprintf(SummitScopes::WriteLocationsData, $current_realm)
],
],
[
'name' => 'get-locations-metadata',
'route' => '/api/v1/summits/{id}/locations/metadata',
@ -491,6 +500,15 @@ class ApiEndpointsSeeder extends Seeder
sprintf(SummitScopes::ReadAllSummitData, $current_realm)
],
],
[
'name' => 'add-venue',
'route' => '/api/v1/summits/{id}/locations/venues',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::WriteSummitData, $current_realm),
sprintf(SummitScopes::WriteLocationsData, $current_realm)
],
],
[
'name' => 'get-external-locations',
'route' => '/api/v1/summits/{id}/locations/external-locations',
@ -500,6 +518,15 @@ class ApiEndpointsSeeder extends Seeder
sprintf(SummitScopes::ReadAllSummitData, $current_realm)
],
],
[
'name' => 'add-external-location',
'route' => '/api/v1/summits/{id}/locations/external-locations',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::WriteSummitData, $current_realm),
sprintf(SummitScopes::WriteLocationsData, $current_realm)
],
],
[
'name' => 'get-hotels',
'route' => '/api/v1/summits/{id}/locations/hotels',
@ -509,6 +536,15 @@ class ApiEndpointsSeeder extends Seeder
sprintf(SummitScopes::ReadAllSummitData, $current_realm)
],
],
[
'name' => 'add-hotel',
'route' => '/api/v1/summits/{id}/locations/hotels',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::WriteSummitData, $current_realm),
sprintf(SummitScopes::WriteLocationsData, $current_realm)
],
],
[
'name' => 'get-airports',
'route' => '/api/v1/summits/{id}/locations/airports',
@ -518,6 +554,15 @@ class ApiEndpointsSeeder extends Seeder
sprintf(SummitScopes::ReadAllSummitData, $current_realm)
],
],
[
'name' => 'add-airport',
'route' => '/api/v1/summits/{id}/locations/airports',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::WriteSummitData, $current_realm),
sprintf(SummitScopes::WriteLocationsData, $current_realm)
],
],
[
'name' => 'get-location',
'route' => '/api/v1/summits/{id}/locations/{location_id}',

View File

@ -26,4 +26,9 @@ return [
'send_speaker_summit_assistance_announcement_mail_code_already_redeemed' => 'promo code :promo_code already redeemed.',
'send_speaker_summit_assistance_announcement_mail_invalid_mail_type' => 'mail type :mail_type is not valid.',
'send_speaker_summit_assistance_promo_code_not_set' => 'speaker :speaker_id has not set a promo code for summit :summit_id, please set one manually.',
'LocationService.addLocation.LocationNameAlreadyExists' => 'there is already another location with same name for summit :summit_id',
'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'
];

View File

@ -378,4 +378,208 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest
$events = json_decode($content);
$this->assertTrue(!is_null($events));
}
public function testAddLocationWithoutClassName($summit_id = 24){
$params = [
'id' => $summit_id,
];
$name = str_random(16).'_location';
$data = [
'name' => $name,
'description' => 'test location',
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"POST",
"OAuth2SummitLocationsApiController@addLocation",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(412);
}
public function testAddLocationVenue($summit_id = 24){
$params = [
'id' => $summit_id,
];
$name = str_random(16).'_location';
$data = [
'name' => $name,
'address1' => 'Nazar 612',
'city' => 'Lanus',
'state' => 'Buenos Aires',
'country' => 'Argentina',
'class_name' => \models\summit\SummitVenue::ClassName,
'description' => 'test location',
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"POST",
"OAuth2SummitLocationsApiController@addLocation",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$location = json_decode($content);
$this->assertTrue(!is_null($location));
return $location;
}
/**
* @param int $summit_id
* @return mixed
*/
public function testAddLocationVenueLatLng($summit_id = 24){
$params = [
'id' => $summit_id,
];
$name = str_random(16).'_location';
$data = [
'name' => $name,
'lat' => '-34.6994795',
'lng' => '-58.3920795',
'class_name' => \models\summit\SummitVenue::ClassName,
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"POST",
"OAuth2SummitLocationsApiController@addLocation",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$location = json_decode($content);
$this->assertTrue(!is_null($location));
return $location;
}
/**
* @param int $summit_id
* @return mixed
*/
public function testAddLocationVenueLatLngInvalid($summit_id = 24){
$params = [
'id' => $summit_id,
];
$name = str_random(16).'_location';
$data = [
'name' => $name,
'lat' => '-134.6994795',
'lng' => '-658.3920795',
'class_name' => \models\summit\SummitVenue::ClassName,
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"POST",
"OAuth2SummitLocationsApiController@addLocation",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(412);
}
/**
* @param int $summit_id
* @return mixed
*/
public function testAddLocationHotelLatLng($summit_id = 24){
$params = [
'id' => $summit_id,
];
$name = str_random(16).'_hotel';
$data = [
'name' => $name,
'address1' => 'H. de Malvinas 1724',
'city' => 'Lanus Este',
'state' => 'Buenos Aires',
'country' => 'Argentina',
'zip_code' => '1824',
'class_name' => \models\summit\SummitHotel::ClassName,
'hotel_type' => \models\summit\SummitHotel::HotelTypePrimary,
'capacity' => 200
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"POST",
"OAuth2SummitLocationsApiController@addLocation",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$location = json_decode($content);
$this->assertTrue(!is_null($location));
return $location;
}
}