diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php index 34d2619e..682f5d49 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php @@ -378,7 +378,7 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'email' => 'sometimes|string|max:50', 'on_site_phone' => 'sometimes|string|max:50', 'registered' => 'sometimes|boolean', - 'confirmed' => 'sometimes|boolean', + 'is_confirmed' => 'sometimes|boolean', 'checked_in' => 'sometimes|boolean', 'registration_code' => 'sometimes|string', ); @@ -447,7 +447,7 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'email' => 'sometimes|string|max:50', 'on_site_phone' => 'sometimes|string|max:50', 'registered' => 'sometimes|boolean', - 'confirmed' => 'sometimes|boolean', + 'is_confirmed' => 'sometimes|boolean', 'checked_in' => 'sometimes|boolean', 'registration_code' => 'sometimes|string', ); diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersAssistanceApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersAssistanceApiController.php index c811c225..5a7b3bc5 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersAssistanceApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersAssistanceApiController.php @@ -20,13 +20,14 @@ use Illuminate\Support\Facades\Validator; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\oauth2\IResourceServerContext; +use models\summit\ISpeakerRepository; use models\summit\ISummitRepository; use ModelSerializers\SerializerRegistry; use services\model\ISpeakerService; use utils\FilterParser; use utils\OrderParser; use utils\PagingInfo; - +use Exception; /** * Class OAuth2SummitSpeakersAssistanceApiController * @package App\Http\Controllers @@ -43,6 +44,11 @@ final class OAuth2SummitSpeakersAssistanceApiController extends OAuth2ProtectedC */ private $speakers_assistance_repository; + /** + * @var ISpeakerRepository + */ + private $speaker_repository; + /** * @var ISpeakerService */ @@ -53,13 +59,15 @@ final class OAuth2SummitSpeakersAssistanceApiController extends OAuth2ProtectedC ( ISummitRepository $summit_repository, IPresentationSpeakerSummitAssistanceConfirmationRequestRepository $speakers_assistance_repository, + ISpeakerRepository $speaker_repository, ISpeakerService $service, IResourceServerContext $resource_server_context ) { parent::__construct($resource_server_context); - $this->summit_repository = $summit_repository; - $this->service = $service; + $this->summit_repository = $summit_repository; + $this->speaker_repository = $speaker_repository; + $this->service = $service; $this->speakers_assistance_repository = $speakers_assistance_repository; } @@ -152,12 +160,63 @@ final class OAuth2SummitSpeakersAssistanceApiController extends OAuth2ProtectedC } } + /** + * @param $summit_id + * @return mixed + */ + public function addSpeakerSummitAssistance($summit_id) + { + try { + if(!Request::isJson()) return $this->error403(); + $data = Input::json()->all(); + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $rules = [ + 'speaker_id' => 'required:integer', + 'on_site_phone' => 'sometimes|string|max:50', + 'registered' => 'sometimes|boolean', + 'is_confirmed' => 'sometimes|boolean', + 'checked_in' => 'sometimes|boolean', + ]; + // Creates a Validator instance and validates the data. + $validation = Validator::make($data, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $speaker_assistance = $this->service->addSpeakerAssistance($summit, $data); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($speaker_assistance)->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 $assistance_id * @return mixed */ - public function deleteSpeakerSummitAssistanceSummit($summit_id, $assistance_id) + public function deleteSpeakerSummitAssistance($summit_id, $assistance_id) { try { @@ -179,4 +238,5 @@ final class OAuth2SummitSpeakersAssistanceApiController extends OAuth2ProtectedC } } + } \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index f5eec98d..4ce67d3d 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -217,12 +217,12 @@ Route::group([ // speakers assistance Route::group(['prefix' => 'speakers-assistances'], function () { Route::get('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitSpeakersAssistanceApiController@getBySummit']); + Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitSpeakersAssistanceApiController@addSpeakerSummitAssistance']); Route::group(['prefix' => '{assistance_id}'], function () { - Route::delete('',[ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitSpeakersAssistanceApiController@deleteSpeakerSummitAssistanceSummit']); + Route::delete('',[ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitSpeakersAssistanceApiController@deleteSpeakerSummitAssistance']); }); }); - // events Route::group(array('prefix' => 'events'), function () { diff --git a/app/ModelSerializers/SilverStripeSerializer.php b/app/ModelSerializers/SilverStripeSerializer.php index b1fa3581..dfc72d56 100644 --- a/app/ModelSerializers/SilverStripeSerializer.php +++ b/app/ModelSerializers/SilverStripeSerializer.php @@ -3,7 +3,7 @@ * Copyright 2016 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 + * You may obtain a copy of the License atN * 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, @@ -11,17 +11,17 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - use Libs\ModelSerializers\AbstractSerializer; - /** * Class SilverStripeSerializer * @package ModelSerializers */ class SilverStripeSerializer extends AbstractSerializer { - protected static $array_mappings = array - ( - 'Id' => 'id:json_int', - ); + protected static $array_mappings = [ + + 'Id' => 'id:json_int', + 'Created' => 'created:datetime_epoch', + 'LastEdited' => 'last_edited:datetime_epoch', + ]; } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php b/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php index 29d4f0fd..4c11a8a1 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php +++ b/app/Models/Foundation/Summit/Events/Presentations/PresentationSpeaker.php @@ -100,7 +100,6 @@ class PresentationSpeaker extends SilverstripeBaseModel */ private $notes; - /** * @ORM\Column(name="OrgHasCloud", type="boolean") */ @@ -607,6 +606,14 @@ class PresentationSpeaker extends SilverstripeBaseModel return $res === false ? null : $res; } + /** + * @param Summit $summit + * @return bool + */ + public function hasAssistanceFor(Summit $summit){ + return $this->getAssistanceFor($summit) != null; + } + /** * @return mixed */ @@ -635,6 +642,44 @@ class PresentationSpeaker extends SilverstripeBaseModel return $request; } + /** + * @param Summit $summit + * @return bool + */ + public function isSpeakerOfSummit(Summit $summit){ + + $query = <<getEM()); + $rsm->addRootEntityFromClassMetadata(\models\summit\Summit::class, 's'); + + // build rsm here + $native_query = $this->getEM()->createNativeQuery($query, $rsm); + + + $native_query->setParameter("speaker_id", $this->id); + $native_query->setParameter("summit_id", $summit->getId()); + + $summits = $native_query->getResult(); + + return count($summits) > 0; + } + /** * @return Summit[] */ @@ -645,7 +690,8 @@ SELECT DISTINCT Summit.* FROM Presentation_Speakers INNER JOIN Presentation ON Presentation.ID = Presentation_Speakers.PresentationID INNER JOIN SummitEvent ON SummitEvent.ID = Presentation.ID INNER JOIN Summit ON Summit.ID = SummitEvent.SummitID -WHERE SummitEvent.Published = 1 AND Presentation_Speakers.PresentationSpeakerID = :speaker_id; +WHERE SummitEvent.Published = 1 AND +( Presentation_Speakers.PresentationSpeakerID = :speaker_id OR Presentation.ModeratorID = :speaker_id ) SQL; $rsm = new ResultSetMappingBuilder($this->getEM()); diff --git a/app/Services/Model/ISpeakerService.php b/app/Services/Model/ISpeakerService.php index e13a539a..bddb91f7 100644 --- a/app/Services/Model/ISpeakerService.php +++ b/app/Services/Model/ISpeakerService.php @@ -15,6 +15,7 @@ use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\main\File; use models\summit\PresentationSpeaker; +use models\summit\PresentationSpeakerSummitAssistanceConfirmationRequest; use models\summit\SpeakerSummitRegistrationPromoCode; use models\summit\Summit; use Illuminate\Http\UploadedFile; @@ -91,6 +92,15 @@ interface ISpeakerService */ public function deleteSpeaker($speaker_id); + /** + * @param Summit $summit + * @param array $data + * @throws ValidationException + * @throws EntityNotFoundException + * @return PresentationSpeakerSummitAssistanceConfirmationRequest + */ + public function addSpeakerAssistance(Summit $summit, array $data); + /** * @param Summit $summit * @param int $assistance_id diff --git a/app/Services/Model/SpeakerService.php b/app/Services/Model/SpeakerService.php index 54f8d43d..8fffddb7 100644 --- a/app/Services/Model/SpeakerService.php +++ b/app/Services/Model/SpeakerService.php @@ -203,7 +203,7 @@ final class SpeakerService implements ISpeakerService $on_site_phone = isset($data['on_site_phone']) ? trim($data['on_site_phone']) : null; $registered = isset($data['registered']) ? 1 : 0; $checked_in = isset($data['checked_in']) ? 1 : 0; - $confirmed = isset($data['confirmed']) ? 1 : 0; + $confirmed = isset($data['is_confirmed']) ? 1 : 0; $summit_assistance->setOnSitePhone($on_site_phone); $summit_assistance->setRegistered($registered); @@ -710,4 +710,47 @@ final class SpeakerService implements ISpeakerService $this->speakers_assistance_repository->delete($assistance); }); } + + /** + * @param Summit $summit + * @param array $data + * @throws ValidationException + * @throws EntityNotFoundException + * @return PresentationSpeakerSummitAssistanceConfirmationRequest + */ + public function addSpeakerAssistance(Summit $summit, array $data) + { + return $this->tx_service->transaction(function() use($data, $summit){ + + $speaker_id = intval($data['speaker_id']); + $speaker = $this->speaker_repository->getById($speaker_id); + + if(is_null($speaker)) + throw new EntityNotFoundException(trans('not_found_errors.add_speaker_assistance_speaker_not_found', ['speaker_id' => $speaker_id])); + + if(!$speaker->isSpeakerOfSummit($summit)){ + throw new ValidationException(trans('validation_errors.add_speaker_assistance_speaker_is_not_on_summit', + [ + 'speaker_id' => $speaker_id, + 'summit_id' => $summit->getId() + ] + )); + } + + if($speaker->hasAssistanceFor($summit)) + throw new ValidationException(trans('validation_errors.add_speaker_assistance_speaker_already_has_assistance', + [ + 'speaker_id' => $speaker_id, + 'summit_id' => $summit->getId() + ] + )); + + $assistance = $speaker->buildAssistanceFor($summit); + $speaker->addSummitAssistance( + $this->updateSummitAssistance($assistance, $data) + ); + + return $assistance; + }); + } } \ No newline at end of file diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index c03d4e09..30baa42d 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -752,9 +752,17 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], ], - // summit speakers assistances [ - 'name' => 'delete-speaker-assistance-by-id', + 'name' => 'add-speaker-assistance', + 'route' => '/api/v1/summits/{id}/speakers-assistances', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitSpeakerAssistanceData, $current_realm), + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + ], + [ + 'name' => 'delete-speaker-assistance', 'route' => '/api/v1/summits/{id}/speakers-assistances/{assistance_id}', 'http_method' => 'DELETE', 'scopes' => [ diff --git a/resources/lang/en/not_found_errors.php b/resources/lang/en/not_found_errors.php index 903a38e1..4cd8d636 100644 --- a/resources/lang/en/not_found_errors.php +++ b/resources/lang/en/not_found_errors.php @@ -14,4 +14,5 @@ return [ 'promo_code_delete_code_not_found' => 'promo code id :promo_code_id does not belongs to summit id :summit_id.', 'promo_code_email_code_not_found' => 'promo code id :promo_code_id does not belongs to summit id :summit_id.', + 'add_speaker_assistance_speaker_not_found' => 'speaker id :speaker_id not found', ]; \ No newline at end of file diff --git a/resources/lang/en/validation_errors.php b/resources/lang/en/validation_errors.php index 09bc24b4..b58b0647 100644 --- a/resources/lang/en/validation_errors.php +++ b/resources/lang/en/validation_errors.php @@ -18,4 +18,6 @@ return [ 'promo_code_email_send_empty_email' => 'Cannot find an email address for the promocode owner.', 'promo_code_email_send_empty_name' => 'Cannot find a name for the promocode owner.', 'speaker_assistance_delete_already_confirmed' => 'Cannot delete summit assistance :assistance_id because is already confirmed by speaker :speaker_id', + 'add_speaker_assistance_speaker_already_has_assistance' => 'speaker id :speaker_id already has an assistance for summit id :summit_id', + 'add_speaker_assistance_speaker_is_not_on_summit' => 'speaker id :speaker_id is not related to summit id :summit_id ( is not assigned as speaker of any published presentations nor its assigned as moderator)', ]; \ No newline at end of file diff --git a/tests/OAuth2SpeakersAssistancesApiTest.php b/tests/OAuth2SpeakersAssistancesApiTest.php index 49078dd0..23d266a2 100644 --- a/tests/OAuth2SpeakersAssistancesApiTest.php +++ b/tests/OAuth2SpeakersAssistancesApiTest.php @@ -133,7 +133,7 @@ class OAuth2SpeakersAssistancesApiTest extends ProtectedApiTest $response = $this->action( "DELETE", - "OAuth2SummitSpeakersAssistanceApiController@deleteSpeakerSummitAssistanceSummit", + "OAuth2SummitSpeakersAssistanceApiController@deleteSpeakerSummitAssistance", $params, [], [], @@ -146,4 +146,36 @@ class OAuth2SpeakersAssistancesApiTest extends ProtectedApiTest $this->assertResponseStatus(204); } + public function testAddSummitAssistance($summit_id = 23){ + $params = [ + 'id' => $summit_id, + ]; + + $data = [ + 'speaker_id' => 1 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitSpeakersAssistanceApiController@addSpeakerSummitAssistance", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $assistance = json_decode($content); + $this->assertTrue(!is_null($assistance)); + return $assistance; + } + } \ No newline at end of file