From e33cf7ee440af5ae1788935c9b4d53956d33a81d Mon Sep 17 00:00:00 2001 From: smarcet Date: Mon, 10 Feb 2020 18:39:20 -0300 Subject: [PATCH] RSVP endpoints POST api/v1/summits/{id}/members/me/schedule/{event_id}/rsvp Payload anwers: array of answer DTO answer DTO question_id: int value: string or string array ( depending on type of question multivalue or not) Required Scopes REALM_BASE_URL/summits/write PUT api/v1/summits/{id}/members/me/schedule/{event_id}/rsvp Payload anwers: array of answer DTO answer DTO question_id: int value: string or string array ( depending on type of question multivalue or not) Required Scopes REALM_BASE_URL/summits/write DELETE api/v1/summits/{id}/members/me/schedule/{event_id}/rsvp Required Scopes REALM_BASE_URL/summits/write Change-Id: I9ea4388effd44617e5122e1b1a23c9c74473d2e6 --- app/Events/RSVPAction.php | 41 +++ app/Events/RSVPCreated.php | 22 ++ app/Events/RSVPUpdated.php | 22 ++ .../OAuth2SummitMembersApiController.php | 269 ++++++++++++++---- ...Auth2BearerAccessTokenRequestValidator.php | 12 +- app/Http/routes.php | 8 +- app/Mail/Schedule/RSVPMail.php | 82 ++++++ app/Mail/Schedule/RSVPRegularSeatMail.php | 40 +++ app/Mail/Schedule/RSVPWaitListSeatMail.php | 40 +++ app/ModelSerializers/OwnMemberSerializer.php | 11 +- app/ModelSerializers/SerializerRegistry.php | 1 + .../Summit/RSVP/RSVPAnswerSerializer.php | 63 ++++ .../Summit/RSVP/RSVPSerializer.php | 66 ++++- .../Summit/SummitEventSerializer.php | 18 +- .../Foundation/Summit/Events/RSVP/RSVP.php | 162 +++++++++-- .../Summit/Events/RSVP/RSVPAnswer.php | 98 +++++-- .../RSVPCheckBoxListQuestionTemplate.php | 14 + .../RSVPDropDownQuestionTemplate.php | 21 ++ .../RSVPMemberEmailQuestionTemplate.php | 13 + .../RSVPMemberFirstNameQuestionTemplate.php | 10 + .../RSVPMemberLastNameQuestionTemplate.php | 10 + .../RSVPMultiValueQuestionTemplate.php | 6 +- .../RSVP/Templates/RSVPQuestionTemplate.php | 8 + .../RSVPRadioButtonListQuestionTemplate.php | 13 + .../RSVPSingleValueTemplateQuestion.php | 11 + .../Events/RSVP/Templates/RSVPTemplate.php | 2 +- .../RSVPTextAreaQuestionTemplate.php | 10 + .../Templates/RSVPTextBoxQuestionTemplate.php | 1 + .../Foundation/Summit/Events/SummitEvent.php | 116 ++++++++ .../Summit/Factories/SummitRSVPFactory.php | 104 +++++++ app/Models/OAuth2/IResourceServerContext.php | 41 +-- app/Models/OAuth2/ResourceServerContext.php | 16 ++ app/Providers/AppServiceProvider.php | 62 +++- app/Providers/EventServiceProvider.php | 41 ++- app/Services/Model/ISummitService.php | 41 ++- app/Services/Model/SummitService.php | 189 ++++++++++-- config/schedule.php | 13 + .../model/Version20191212002736.php | 4 +- .../model/Version20200212125943.php | 49 ++++ database/seeds/ApiEndpointsSeeder.php | 20 +- .../schedule/rsvp_regular_seat.blade.php | 23 ++ .../emails/schedule/rsvp_wait_seat.blade.php | 26 ++ tests/OAuth2RSVPSummitEventApiTest.php | 130 +++++++++ tests/OAuth2SummitApiTest.php | 48 ---- tests/ProtectedApiTest.php | 2 +- 45 files changed, 1764 insertions(+), 235 deletions(-) create mode 100644 app/Events/RSVPAction.php create mode 100644 app/Events/RSVPCreated.php create mode 100644 app/Events/RSVPUpdated.php create mode 100644 app/Mail/Schedule/RSVPMail.php create mode 100644 app/Mail/Schedule/RSVPRegularSeatMail.php create mode 100644 app/Mail/Schedule/RSVPWaitListSeatMail.php create mode 100644 app/ModelSerializers/Summit/RSVP/RSVPAnswerSerializer.php create mode 100644 app/Models/Foundation/Summit/Factories/SummitRSVPFactory.php create mode 100644 config/schedule.php create mode 100644 database/migrations/model/Version20200212125943.php create mode 100644 resources/views/emails/schedule/rsvp_regular_seat.blade.php create mode 100644 resources/views/emails/schedule/rsvp_wait_seat.blade.php create mode 100644 tests/OAuth2RSVPSummitEventApiTest.php diff --git a/app/Events/RSVPAction.php b/app/Events/RSVPAction.php new file mode 100644 index 00000000..aad508f3 --- /dev/null +++ b/app/Events/RSVPAction.php @@ -0,0 +1,41 @@ +rsvp_id = $rsvp->getId(); + parent::__construct($rsvp->getEventId()); + } + + /** + * @return int + */ + public function getRsvpId(): int + { + return $this->rsvp_id; + } + +} \ No newline at end of file diff --git a/app/Events/RSVPCreated.php b/app/Events/RSVPCreated.php new file mode 100644 index 00000000..d3e6c0e1 --- /dev/null +++ b/app/Events/RSVPCreated.php @@ -0,0 +1,22 @@ +summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); - - $current_member = $this->resource_server_context->getCurrentUser(); - if (is_null($current_member)) return $this->error403(); - - $event = $summit->getScheduleEvent(intval($event_id)); - - if (is_null($event)) { - return $this->error404(); - } - - $this->summit_service->unRSVPEvent($summit, $current_member, $event_id); - - return $this->deleted(); - - } - 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(\HTTP401UnauthorizedException $ex3) - { - Log::warning($ex3); - return $this->error401(); - } - catch (Exception $ex) { - Log::error($ex); - return $this->error500($ex); - } - - } - /** * @param $summit_id * @return \Illuminate\Http\JsonResponse|mixed @@ -711,4 +664,222 @@ final class OAuth2SummitMembersApiController extends OAuth2ProtectedController } } + /** + * @param array $payload + * @return array + */ + private function validateRSVPEventUri(array $payload){ + if(!isset($payload['event_uri']) || empty($payload['event_uri'])){ + Log::debug("validateRSVPEventUri: event uri not set , trying to get from Referer"); + $payload['event_uri'] = Request::instance()->header('Referer', null); + } + + if(isset($payload['event_uri']) && !empty($payload['event_uri'])){ + $allowed_return_uris = $this->resource_server_context->getAllowedReturnUris(); + if(!empty($allowed_return_uris)){ + Log::debug(sprintf("validateRSVPEventUri: event_uri %s allowed_return_uris %s", $payload['event_uri'], $allowed_return_uris)); + // validate the event_uri against the allowed returned uris of the current client + // check using host name + $test_host = parse_url($payload['event_uri'], PHP_URL_HOST); + $valid_event_uri = false; + foreach(explode(",", $allowed_return_uris) as $allowed_uri){ + if($test_host == parse_url($allowed_uri, PHP_URL_HOST)){ + $valid_event_uri = true; + Log::debug(sprintf("validateRSVPEventUri: valid host %s", $test_host)); + break; + } + } + if(!$valid_event_uri){ + unset($payload['event_uri'] ); + } + } + } + + return $payload; + } + + /** + * @param $summit_id + * @param $member_id + * @param $event_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addEventRSVP($summit_id, $member_id, $event_id){ + try { + if(!Request::isJson()) return $this->error400(); + + $data = Input::json(); + $payload = $data->all(); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, [ + 'answers' => 'sometimes|rsvp_answer_dto_array', + 'event_uri' => 'sometimes|url', + ]); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $event = $summit->getScheduleEvent(intval($event_id)); + + if (is_null($event)) { + return $this->error404(); + } + + $rsvp = $this->summit_service->addRSVP($summit, $current_member, $event_id, $this->validateRSVPEventUri($payload)); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($rsvp)->serialize + ( + Request::input('expand', '') + )); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $member_id + * @param $event_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updateEventRSVP($summit_id, $member_id, $event_id){ + try { + if(!Request::isJson()) return $this->error400(); + $origin = Request::instance()->headers->get('Origin', null); + $data = Input::json(); + $payload = $data->all(); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, [ + 'answers' => 'sometimes|rsvp_answer_dto_array', + 'event_uri' => 'sometimes|url', + ]); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $event = $summit->getScheduleEvent(intval($event_id)); + + if (is_null($event)) { + return $this->error404(); + } + + $rsvp = $this->summit_service->updateRSVP($summit, $current_member, $event_id, $this->validateRSVPEventUri($payload)); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($rsvp)->serialize + ( + Request::input('expand', '') + )); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $member_id + * @param $event_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function deleteEventRSVP($summit_id, $member_id, $event_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $event = $summit->getScheduleEvent(intval($event_id)); + + if (is_null($event)) { + return $this->error404(); + } + + $this->summit_service->unRSVPEvent($summit, $current_member, $event_id); + + return $this->deleted(); + + } + 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(\HTTP401UnauthorizedException $ex3) + { + Log::warning($ex3); + return $this->error401(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + + } + } \ No newline at end of file diff --git a/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php b/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php index 8db9d7a0..1ba01178 100644 --- a/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php +++ b/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php @@ -186,11 +186,13 @@ class OAuth2BearerAccessTokenRequestValidator Log::debug('setting resource server context ...'); //set context for api and continue processing $context = [ - 'access_token' => $access_token_value, - 'expires_in' => $token_info->getLifetime(), - 'client_id' => $token_info->getClientId(), - 'scope' => $token_info->getScope(), - 'application_type' => $token_info->getApplicationType() + 'access_token' => $access_token_value, + 'expires_in' => $token_info->getLifetime(), + 'client_id' => $token_info->getClientId(), + 'scope' => $token_info->getScope(), + 'application_type' => $token_info->getApplicationType(), + 'allowed_origins' => $token_info->getAllowedOrigins(), + 'allowed_return_uris' => $token_info->getAllowedReturnUris() ]; if (!is_null($token_info->getUserId())) diff --git a/app/Http/routes.php b/app/Http/routes.php index 5fa0c9bc..e50f0d42 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -587,7 +587,13 @@ Route::group([ Route::get('', 'OAuth2SummitMembersApiController@getMemberScheduleSummitEvents')->where('member_id', 'me'); Route::group(array('prefix' => '{event_id}'), function (){ - Route::delete('/rsvp', 'OAuth2SummitMembersApiController@deleteEventRSVP')->where('member_id', 'me'); + + Route::group(array('prefix' => 'rsvp'), function (){ + Route::post('', 'OAuth2SummitMembersApiController@addEventRSVP')->where('member_id', 'me'); + Route::put('', 'OAuth2SummitMembersApiController@updateEventRSVP')->where('member_id', 'me'); + Route::delete('', 'OAuth2SummitMembersApiController@deleteEventRSVP')->where('member_id', 'me'); + }); + Route::post('', 'OAuth2SummitMembersApiController@addEventToMemberSchedule')->where('member_id', 'me'); Route::delete('', 'OAuth2SummitMembersApiController@removeEventFromMemberSchedule')->where('member_id', 'me'); }); diff --git a/app/Mail/Schedule/RSVPMail.php b/app/Mail/Schedule/RSVPMail.php new file mode 100644 index 00000000..1fb17e53 --- /dev/null +++ b/app/Mail/Schedule/RSVPMail.php @@ -0,0 +1,82 @@ +getEvent(); + $summit = $event->getSummit(); + $owner = $rsvp->getOwner(); + $this->owner_fullname = $owner->getFullName(); + $this->owner_email = $owner->getEmail(); + $this->event_title = $event->getTitle(); + $this->event_date = $event->getDateNice(); + $this->confirmation_number = $rsvp->getConfirmationNumber(); + $this->summit_name = $summit->getName(); + $event_uri = $rsvp->getEventUri(); + if(!empty($event_uri)){ + // we got a valid origin + $this->event_uri = $event_uri; + } + } +} \ No newline at end of file diff --git a/app/Mail/Schedule/RSVPRegularSeatMail.php b/app/Mail/Schedule/RSVPRegularSeatMail.php new file mode 100644 index 00000000..8741f4dd --- /dev/null +++ b/app/Mail/Schedule/RSVPRegularSeatMail.php @@ -0,0 +1,40 @@ +summit_name); + $from = Config::get("mail.from"); + if(empty($from)){ + throw new \InvalidArgumentException("mail.from is not set"); + } + return $this->from($from) + ->to($this->owner_email) + ->subject($subject) + ->view('emails.schedule.rsvp_regular_seat'); + } +} \ No newline at end of file diff --git a/app/Mail/Schedule/RSVPWaitListSeatMail.php b/app/Mail/Schedule/RSVPWaitListSeatMail.php new file mode 100644 index 00000000..7737c39f --- /dev/null +++ b/app/Mail/Schedule/RSVPWaitListSeatMail.php @@ -0,0 +1,40 @@ +summit_name); + $from = Config::get("mail.from"); + if(empty($from)){ + throw new \InvalidArgumentException("mail.from is not set"); + } + return $this->from($from) + ->to($this->owner_email) + ->subject($subject) + ->view('emails.schedule.rsvp_wait_seat'); + } +} \ No newline at end of file diff --git a/app/ModelSerializers/OwnMemberSerializer.php b/app/ModelSerializers/OwnMemberSerializer.php index edabf704..1ce0c165 100644 --- a/app/ModelSerializers/OwnMemberSerializer.php +++ b/app/ModelSerializers/OwnMemberSerializer.php @@ -11,8 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use Libs\ModelSerializers\AbstractSerializer; use models\main\Member; - /** * Class OwnMemberSerializer * @package ModelSerializers @@ -120,9 +120,10 @@ final class OwnMemberSerializer extends AbstractMemberSerializer } if (!empty($expand)) { - $exp_expand = explode(',', $expand); - foreach ($exp_expand as $relation) { - switch (trim($relation)) { + + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { case 'attendee': { if (!is_null($attendee)) @@ -180,7 +181,7 @@ final class OwnMemberSerializer extends AbstractMemberSerializer foreach ($member->getRsvpBySummit($summit) as $rsvp){ $rsvps[] = SerializerRegistry::getInstance() ->getSerializer($rsvp) - ->serialize($expand); + ->serialize(AbstractSerializer::filterExpandByPrefix($relation, $expand)); } $values['rsvp'] = $rsvps; } diff --git a/app/ModelSerializers/SerializerRegistry.php b/app/ModelSerializers/SerializerRegistry.php index 1d6f7fe6..8f8da740 100644 --- a/app/ModelSerializers/SerializerRegistry.php +++ b/app/ModelSerializers/SerializerRegistry.php @@ -167,6 +167,7 @@ final class SerializerRegistry // RSVP $this->registry['RSVP'] = RSVPSerializer::class; + $this->registry['RSVPAnswer'] = RSVPAnswerSerializer::class; $this->registry['RSVPTemplate'] = RSVPTemplateSerializer::class; $this->registry['RSVPQuestionValueTemplate'] = RSVPQuestionValueTemplateSerializer::class; diff --git a/app/ModelSerializers/Summit/RSVP/RSVPAnswerSerializer.php b/app/ModelSerializers/Summit/RSVP/RSVPAnswerSerializer.php new file mode 100644 index 00000000..770ebcba --- /dev/null +++ b/app/ModelSerializers/Summit/RSVP/RSVPAnswerSerializer.php @@ -0,0 +1,63 @@ + 'value:json_string', + 'RSVPId' => 'rsvp_id:json_int', + 'QuestionId' => 'question_id:json_string', + 'Created' => 'created:datetime_epoch', + ]; + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) + { + $answer = $this->object; + if(! $answer instanceof RSVPAnswer) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { + case 'rsvp': { + unset($values['rsvp_id']); + $values['rsvp_id'] = SerializerRegistry::getInstance()->getSerializer($answer->getRsvp())->serialize(AbstractSerializer::filterExpandByPrefix($relation, $expand)); + } + break; + case 'question': { + unset($values['question_id']); + $values['question'] = SerializerRegistry::getInstance()->getSerializer($answer->getQuestion())->serialize(AbstractSerializer::filterExpandByPrefix($relation, $expand)); + } + break; + } + } + } + + return $values; + } + +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/RSVP/RSVPSerializer.php b/app/ModelSerializers/Summit/RSVP/RSVPSerializer.php index b55ce4bc..f2b661ec 100644 --- a/app/ModelSerializers/Summit/RSVP/RSVPSerializer.php +++ b/app/ModelSerializers/Summit/RSVP/RSVPSerializer.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use Libs\ModelSerializers\AbstractSerializer; +use models\summit\RSVP; /** * Class RSVPSerializer * @package ModelSerializers @@ -18,10 +20,64 @@ final class RSVPSerializer extends SilverStripeSerializer { protected static $array_mappings = [ - - 'OwnerId' => 'owner_id:json_int', - 'EventId' => 'event_id:json_int', - 'SeatType' => 'seat_type:json_string', - 'Created' => 'created:datetime_epoch', + 'OwnerId' => 'owner_id:json_int', + 'EventId' => 'event_id:json_int', + 'SeatType' => 'seat_type:json_string', + 'Created' => 'created:datetime_epoch', + 'ConfirmationNumber' => 'confirmation_number:json_string', + 'EventUri' => 'event_uri:json_string', ]; + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) + { + $rsvp = $this->object; + if(! $rsvp instanceof RSVP) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + $answers = []; + foreach ($rsvp->getAnswers() as $answer){ + $answers[] = $answer->getId(); + } + $values['answers'] = $answers; + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { + + case 'owner': { + if(!$rsvp->hasOwner()) continue; + unset($values['owner_id']); + $values['owner'] = SerializerRegistry::getInstance()->getSerializer($rsvp->getOwner())->serialize(AbstractSerializer::filterExpandByPrefix($relation, $expand)); + } + break; + case 'event': { + if(!$rsvp->hasEvent()) continue; + unset($values['event_id']); + $values['event'] = SerializerRegistry::getInstance()->getSerializer($rsvp->getEvent())->serialize(AbstractSerializer::filterExpandByPrefix($relation, $expand)); + } + break; + + case 'answers':{ + $answers = []; + foreach ($rsvp->getAnswers() as $answer){ + $answers[] = SerializerRegistry::getInstance()->getSerializer($answer)->serialize(AbstractSerializer::filterExpandByPrefix($relation, $expand)); + } + $values['answers'] = $answers; + } + break; + } + } + } + + return $values; + } + } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitEventSerializer.php b/app/ModelSerializers/Summit/SummitEventSerializer.php index a6318e0a..e6849d76 100644 --- a/app/ModelSerializers/Summit/SummitEventSerializer.php +++ b/app/ModelSerializers/Summit/SummitEventSerializer.php @@ -11,9 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - use Libs\ModelSerializers\AbstractSerializer; -use libs\utils\JsonUtils; use models\summit\SummitEvent; /** * Class SummitEventSerializer @@ -39,13 +37,14 @@ class SummitEventSerializer extends SilverStripeSerializer 'RSVPTemplateId' => 'rsvp_template_id:json_int', 'RSVPMaxUserNumber' => 'rsvp_max_user_number:json_int', 'RSVPMaxUserWaitListNumber' => 'rsvp_max_user_wait_list_number:json_int', + 'RSVPRegularCount' => 'rsvp_regular_count:json_int', + 'RSVPWaitCount' => 'rsvp_wait_count:json_int', 'ExternalRSVP' => 'rsvp_external:json_boolean', 'CategoryId' => 'track_id:json_int', 'Occupancy' => 'occupancy:json_string' ]; protected static $allowed_fields = [ - 'id', 'title', 'description', @@ -67,6 +66,8 @@ class SummitEventSerializer extends SilverStripeSerializer 'rsvp_max_user_number', 'rsvp_max_user_wait_list_number', 'occupancy', + 'rsvp_regular_count', + 'rsvp_wait_count', ]; protected static $allowed_relations = [ @@ -107,7 +108,7 @@ class SummitEventSerializer extends SilverStripeSerializer $relation = trim($relation); switch ($relation) { case 'feedback': { - $feedback = array(); + $feedback = []; foreach ($event->getFeedback() as $f) { $feedback[] = SerializerRegistry::getInstance()->getSerializer($f)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); } @@ -121,8 +122,15 @@ class SummitEventSerializer extends SilverStripeSerializer } } break; + case 'rsvp_template': { + if($event->hasRSVPTemplate()){ + unset($values['rsvp_template_id']); + $values['rsvp_template'] = SerializerRegistry::getInstance()->getSerializer($event->getRSVPTemplate())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + } + break; case 'sponsors': { - $sponsors = array(); + $sponsors = []; foreach ($event->getSponsors() as $s) { $sponsors[] = SerializerRegistry::getInstance()->getSerializer($s)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); } diff --git a/app/Models/Foundation/Summit/Events/RSVP/RSVP.php b/app/Models/Foundation/Summit/Events/RSVP/RSVP.php index 1651b8d8..dc0fcbb0 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/RSVP.php +++ b/app/Models/Foundation/Summit/Events/RSVP/RSVP.php @@ -11,10 +11,13 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use Doctrine\Common\Collections\Criteria; +use App\Models\Foundation\Summit\Events\RSVP\RSVPQuestionTemplate; +use models\exceptions\ValidationException; use models\main\Member; use models\utils\SilverstripeBaseModel; -use Doctrine\ORM\Mapping AS ORM; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\ORM\Mapping AS ORM; /** * @ORM\Entity * @ORM\Table(name="RSVP") @@ -24,37 +27,69 @@ use Doctrine\Common\Collections\ArrayCollection; */ class RSVP extends SilverstripeBaseModel { - public function __construct() - { - parent::__construct(); - $this->answers = new ArrayCollection(); - } + + const SeatTypeRegular = 'Regular'; + const SeatTypeWaitList = 'WaitList'; + + const ValidSeatTypes = [self::SeatTypeRegular, self::SeatTypeWaitList]; /** - * @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="rsvp", fetch="LAZY") + * @ORM\Column(name="SeatType", type="string") + * @var string + */ + protected $seat_type; + + /** + * @ORM\Column(name="EventUri", type="string") + * @var string + */ + protected $event_uri; + + /** + * @ORM\Column(name="BeenEmailed", type="boolean") + * @var bool + */ + protected $been_emailed; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="rsvp") * @ORM\JoinColumn(name="SubmittedByID", referencedColumnName="ID", onDelete="CASCADE") * @var Member */ private $owner; /** - * @ORM\ManyToOne(targetEntity="models\summit\SummitEvent", inversedBy="rsvp", fetch="LAZY") + * @ORM\ManyToOne(targetEntity="models\summit\SummitEvent", inversedBy="rsvp") * @ORM\JoinColumn(name="EventID", referencedColumnName="ID", onDelete="CASCADE") * @var SummitEvent */ private $event; /** - * @ORM\Column(name="SeatType", type="string") - */ - protected $seat_type; - - /** - * @ORM\OneToMany(targetEntity="models\summit\RSVPAnswer", mappedBy="rsvp", cascade={"persist", "remove"}) + * @ORM\OneToMany(targetEntity="models\summit\RSVPAnswer", mappedBy="rsvp", cascade={"persist", "remove"}, orphanRemoval=true) * @var RSVPAnswer[] */ protected $answers; + /** + * RSVP constructor. + */ + public function __construct() + { + parent::__construct(); + $this->seat_type = null; + $this->answers = new ArrayCollection(); + $this->been_emailed = false; + $this->event_uri = null; + } + + /** + * @return bool + */ + public function hasSeatTypeSet():bool{ + return !empty($this->seat_type); + } + /** * @return ArrayCollection */ @@ -86,7 +121,6 @@ class RSVP extends SilverstripeBaseModel $this->owner = $owner; } - /** * @return SummitEvent */ @@ -107,6 +141,13 @@ class RSVP extends SilverstripeBaseModel } } + /** + * @return bool + */ + public function hasEvent(){ + return $this->getEventId() > 0; + } + /** * @return bool */ @@ -134,19 +175,102 @@ class RSVP extends SilverstripeBaseModel } /** - * @return mixed + * @return string */ - public function getSeatType() + public function getSeatType():?string { return $this->seat_type; } /** - * @param mixed $seat_type + * @param string $seat_type + * @throws ValidationException */ - public function setSeatType($seat_type) + public function setSeatType(string $seat_type) { + if(!in_array($seat_type, self::ValidSeatTypes)) + throw new ValidationException(sprintf("Seat type %s is not valid."), $seat_type); $this->seat_type = $seat_type; } + /** + * @return bool + */ + public function isBeenEmailed(): bool + { + return $this->been_emailed; + } + + /** + * @param bool $been_emailed + */ + public function setBeenEmailed(bool $been_emailed): void + { + $this->been_emailed = $been_emailed; + } + + public function clearEvent(){ + $this->event = null; + } + + public function clearOwner(){ + $this->owner = null; + } + + /** + * @param RSVPQuestionTemplate $question + * @return RSVPAnswer|null + */ + public function findAnswerByQuestion(RSVPQuestionTemplate $question):?RSVPAnswer{ + $criteria = Criteria::create(); + $criteria = $criteria->where(Criteria::expr()->eq('question', $question)); + $answer = $this->answers->matching($criteria)->first(); + return !$answer ? null:$answer; + } + + public function addAnswer(RSVPAnswer $answer){ + if($this->answers->contains($answer)) return; + $this->answers->add($answer); + $answer->setRsvp($this); + } + + public function removeAnswer(RSVPAnswer $answer){ + if(!$this->answers->contains($answer)) return; + $this->answers->removeElement($answer); + $answer->clearRSVP(); + } + + public function clearAnswers(){ + $this->answers->clear(); + } + + /** + * @return string|null + */ + public function getConfirmationNumber():?string{ + if(!$this->hasEvent()) return null; + if(!$this->getEvent()->hasSummit()) return null; + $summit = $this->event->getSummit(); + $summit_title = substr($summit->getName(),0,3); + $summit_year = $summit->getLocalBeginDate()->format('y'); + return strtoupper($summit_title).$summit_year.$this->id; + } + + /** + * @return string + */ + public function getEventUri(): ?string + { + return $this->event_uri; + } + + /** + * @param string $event_uri + */ + public function setEventUri(string $event_uri): void + { + $this->event_uri = $event_uri; + } + + } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/RSVPAnswer.php b/app/Models/Foundation/Summit/Events/RSVP/RSVPAnswer.php index cef24ff7..1264a728 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/RSVPAnswer.php +++ b/app/Models/Foundation/Summit/Events/RSVP/RSVPAnswer.php @@ -11,11 +11,10 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - +use App\Models\Foundation\Summit\Events\RSVP\RSVPMultiValueQuestionTemplate; +use App\Models\Foundation\Summit\Events\RSVP\RSVPQuestionTemplate; use models\utils\SilverstripeBaseModel; use Doctrine\ORM\Mapping AS ORM; -use Doctrine\Common\Collections\ArrayCollection; - /** * @ORM\Entity * @ORM\Table(name="RSVPAnswer") @@ -24,13 +23,6 @@ use Doctrine\Common\Collections\ArrayCollection; */ class RSVPAnswer extends SilverstripeBaseModel { - /** - * @ORM\ManyToOne(targetEntity="models\summit\RSVP", inversedBy="answers", fetch="LAZY") - * @ORM\JoinColumn(name="RSVPID", referencedColumnName="ID", onDelete="CASCADE") - * @var SummitAttendee - */ - private $rsvp; - /** * @ORM\Column(name="Value", type="string") * @var string @@ -38,34 +30,35 @@ class RSVPAnswer extends SilverstripeBaseModel private $value; /** - * @return SummitAttendee + * @ORM\ManyToOne(targetEntity="models\summit\RSVP", inversedBy="answers") + * @ORM\JoinColumn(name="RSVPID", referencedColumnName="ID", onDelete="CASCADE") + * @var RSVP */ - public function getRsvp() - { - return $this->rsvp; - } + private $rsvp; /** - * @param SummitAttendee $rsvp + * @ORM\ManyToOne(targetEntity="App\Models\Foundation\Summit\Events\RSVP\RSVPQuestionTemplate") + * @ORM\JoinColumn(name="QuestionID", referencedColumnName="ID") + * @var RSVPQuestionTemplate */ - public function setRsvp($rsvp) - { - $this->rsvp = $rsvp; - } + private $question; /** - * @return string + * @return string|null */ - public function getValue() + public function getValue():?string { return $this->value; } /** - * @param string $value + * @param array|string $value */ public function setValue($value) { + if (is_array($value)) { + $value = implode(',', $value); + } $this->value = $value; } @@ -74,20 +67,65 @@ class RSVPAnswer extends SilverstripeBaseModel */ public function getQuestionId() { - return $this->question_id; + try{ + return $this->question->getId(); + } + catch(\Exception $ex){ + return 0; + } } /** - * @param int $question_id + * @return int */ - public function setQuestionId($question_id) + public function getRSVPId() { - $this->question_id = $question_id; + try{ + return $this->rsvp->getId(); + } + catch(\Exception $ex){ + return 0; + } } /** - * @ORM\Column(name="QuestionID", type="integer") - * @var int + * @return RSVP */ - private $question_id; + public function getRsvp(): RSVP + { + return $this->rsvp; + } + + /** + * @param RSVP $rsvp + */ + public function setRsvp(RSVP $rsvp): void + { + $this->rsvp = $rsvp; + } + + /** + * @return RSVPQuestionTemplate + */ + public function getQuestion(): RSVPQuestionTemplate + { + return $this->question; + } + + /** + * @param RSVPQuestionTemplate $question + */ + public function setQuestion(RSVPQuestionTemplate $question): void + { + $this->question = $question; + } + + public function clearRSVP(){ + $this->rsvp = null; + } + + public function clearQuestion(){ + $this->question = null; + } + } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPCheckBoxListQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPCheckBoxListQuestionTemplate.php index 5268b82a..2c0c9868 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPCheckBoxListQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPCheckBoxListQuestionTemplate.php @@ -38,4 +38,18 @@ class RSVPCheckBoxListQuestionTemplate extends RSVPMultiValueQuestionTemplate public static function getMetadata(){ return array_merge(RSVPMultiValueQuestionTemplate::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(!is_array($value)) return false; + foreach($value as $valId){ + $val = $this->getValueById(intval($valId)); + if(is_null($val)) return false; + } + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPDropDownQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPDropDownQuestionTemplate.php index 464b6206..9a079c52 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPDropDownQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPDropDownQuestionTemplate.php @@ -117,4 +117,25 @@ class RSVPDropDownQuestionTemplate extends RSVPMultiValueQuestionTemplate public static function getMetadata(){ return array_merge(RSVPMultiValueQuestionTemplate::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(!$this->is_multiselect){ + if(!is_string($value)) return false; + $valId = intval($value); + $val = $this->getValueById($valId); + if(is_null($val)) return false; + return true; + } + if(!is_array($value)) return false; + foreach($value as $valId){ + $val = $this->getValueById(intval($valId)); + if(is_null($val)) return false; + } + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberEmailQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberEmailQuestionTemplate.php index 4cbcd3de..20e58a86 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberEmailQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberEmailQuestionTemplate.php @@ -38,4 +38,17 @@ class RSVPMemberEmailQuestionTemplate extends RSVPTextBoxQuestionTemplate public static function getMetadata(){ return array_merge(RSVPTextBoxQuestionTemplate::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(!is_string($value)) return false; + if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { + return false; + } + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberFirstNameQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberFirstNameQuestionTemplate.php index b28c5fe4..5dbf8808 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberFirstNameQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberFirstNameQuestionTemplate.php @@ -38,4 +38,14 @@ class RSVPMemberFirstNameQuestionTemplate extends RSVPTextBoxQuestionTemplate public static function getMetadata(){ return array_merge(RSVPTextBoxQuestionTemplate::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(!is_string($value)) return false; + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberLastNameQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberLastNameQuestionTemplate.php index 399359bd..637b3943 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberLastNameQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMemberLastNameQuestionTemplate.php @@ -38,4 +38,14 @@ class RSVPMemberLastNameQuestionTemplate extends RSVPTextBoxQuestionTemplate public static function getMetadata(){ return array_merge(RSVPTextBoxQuestionTemplate::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(!is_string($value)) return false; + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php index b11fe44d..9b5e3040 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php @@ -29,20 +29,20 @@ class RSVPMultiValueQuestionTemplate extends RSVPQuestionTemplate * @ORM\Column(name="EmptyString", type="string") * @var string */ - private $empty_string; + protected $empty_string; /** * @ORM\OneToMany(targetEntity="RSVPQuestionValueTemplate", mappedBy="owner", cascade={"persist", "remove"}, orphanRemoval=true) * @var RSVPQuestionValueTemplate[] */ - private $values; + protected $values; /** * @ORM\ManyToOne(targetEntity="RSVPQuestionValueTemplate", fetch="EXTRA_LAZY") * @ORM\JoinColumn(name="DefaultValueID", referencedColumnName="ID") * @var RSVPQuestionValueTemplate */ - private $default_value; + protected $default_value; /** * @return string diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionTemplate.php index d52dd0e7..be23add5 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionTemplate.php @@ -213,4 +213,12 @@ class RSVPQuestionTemplate extends SilverstripeBaseModel implements IOrderable return self::$metadata; } + /** + * @param array|string|null $value + * @return bool + */ + public function isValidValue($value):bool { + return true; + } + } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPRadioButtonListQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPRadioButtonListQuestionTemplate.php index 448cf9fc..128f40c4 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPRadioButtonListQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPRadioButtonListQuestionTemplate.php @@ -38,4 +38,17 @@ class RSVPRadioButtonListQuestionTemplate extends RSVPMultiValueQuestionTemplate public static function getMetadata(){ return array_merge(RSVPMultiValueQuestionTemplate::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(!is_string($value)) return false; + $valId = intval($value); + $val = $this->getValueById($valId); + if(is_null($val)) return false; + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPSingleValueTemplateQuestion.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPSingleValueTemplateQuestion.php index 0f0af774..4685682d 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPSingleValueTemplateQuestion.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPSingleValueTemplateQuestion.php @@ -62,4 +62,15 @@ class RSVPSingleValueTemplateQuestion extends RSVPQuestionTemplate public static function getMetadata(){ return array_merge(RSVPQuestionTemplate::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(empty($value) && !$this->is_mandatory) return true; + if(!is_string($value)) return false; + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTemplate.php index 2c343ccd..2853c708 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTemplate.php @@ -134,7 +134,7 @@ class RSVPTemplate extends SilverstripeBaseModel } /** - * @return RSVPQuestionTemplate[] + * @return ArrayCollection|\Doctrine\Common\Collections\Collection */ public function getQuestions() { diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextAreaQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextAreaQuestionTemplate.php index 6cb815fe..9f260d56 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextAreaQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextAreaQuestionTemplate.php @@ -38,4 +38,14 @@ class RSVPTextAreaQuestionTemplate extends RSVPSingleValueTemplateQuestion public static function getMetadata(){ return array_merge(RSVPSingleValueTemplateQuestion::getMetadata(), self::$metadata); } + + /** + * @param array|string $value + * @return bool + */ + public function isValidValue($value): bool + { + if(!is_string($value)) return false; + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextBoxQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextBoxQuestionTemplate.php index b403fe0f..0aeeec16 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextBoxQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPTextBoxQuestionTemplate.php @@ -38,4 +38,5 @@ class RSVPTextBoxQuestionTemplate extends RSVPSingleValueTemplateQuestion public static function getMetadata(){ return array_merge(RSVPSingleValueTemplateQuestion::getMetadata(), self::$metadata); } + } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/SummitEvent.php b/app/Models/Foundation/Summit/Events/SummitEvent.php index 1fd022fb..7d47d65e 100644 --- a/app/Models/Foundation/Summit/Events/SummitEvent.php +++ b/app/Models/Foundation/Summit/Events/SummitEvent.php @@ -957,4 +957,120 @@ class SummitEvent extends SilverstripeBaseModel $this->external_id = $external_id; } + /** + * @return string + * @throws ValidationException + */ + public function getCurrentRSVPSubmissionSeatType():string{ + + if(!$this->hasRSVPTemplate()) + throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); + + if(!$this->getRSVPTemplate()->isEnabled()){ + throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); + } + + $count_regular = $this->getRSVPSeatTypeCount(RSVP::SeatTypeRegular); + if($count_regular < intval($this->rsvp_max_user_number)) return RSVP::SeatTypeRegular; + $count_wait = $this->getRSVPSeatTypeCount(RSVP::SeatTypeWaitList); + if($count_wait < intval($this->rsvp_max_user_wait_list_number)) return RSVP::SeatTypeWaitList; + throw new ValidationException(sprintf("Event %s is Full.", $this->id)); + } + + /** + * @param string $seat_type + * @return int + */ + public function getRSVPSeatTypeCount(string $seat_type):int{ + $criteria = Criteria::create(); + $criteria = $criteria->where(Criteria::expr()->eq('seat_type', $seat_type)); + return $this->rsvp->matching($criteria)->count(); + } + + /** + * @param string $seat_type + * @return bool + */ + public function couldAddSeatType(string $seat_type):bool{ + switch($seat_type){ + case RSVP::SeatTypeRegular: { + $count_regular = $this->getRSVPSeatTypeCount(RSVP::SeatTypeRegular); + return $count_regular < intval($this->rsvp_max_user_number); + } + case RSVP::SeatTypeWaitList: { + $count_wait = $this->getRSVPSeatTypeCount(RSVP::SeatTypeWaitList); + return $count_wait < intval($this->rsvp_max_user_wait_list_number); + } + } + return false; + } + + public function getRSVPRegularCount():?int{ + return $this->getRSVPSeatTypeCount(RSVP::SeatTypeRegular); + } + + public function getRSVPWaitCount():?int{ + return $this->getRSVPSeatTypeCount(RSVP::SeatTypeWaitList); + } + + /** + * @param RSVP $rsvp + * @throws ValidationException + */ + public function addRSVPSubmission(RSVP $rsvp){ + if(!$this->hasRSVPTemplate()){ + throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); + } + + if(!$this->getRSVPTemplate()->isEnabled()){ + throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); + } + + if($this->rsvp->contains($rsvp)) return; + $this->rsvp->add($rsvp); + $rsvp->setEvent($this); + } + + /** + * @param RSVP $rsvp + */ + public function removeRSVPSubmission(RSVP $rsvp){ + if(!$this->rsvp->contains($rsvp)) return; + $this->rsvp->removeElement($rsvp); + $rsvp->clearEvent(); + } + + /** + * @return string + */ + public function getStartDateNice():string + { + $start_date = $this->getLocalStartDate(); + if(empty($start_date)) return 'TBD'; + return $start_date->format("Y-m-d H:i:s"); + } + + /** + * @return string + */ + public function getEndDateNice():string + { + $end_date = $this->getLocalEndDate(); + if(empty($end_date)) return 'TBD'; + return $end_date->format("Y-m-d H:i:s"); + } + + /** + * @return string + */ + public function getDateNice():string { + $start_date = $this->getStartDateNice(); + $end_date = $this->getEndDateNice(); + $date_nice = ''; + + if ($start_date == 'TBD' || $end_date == 'TBD') return $start_date; + + $date_nice = date('l, F j, g:ia', strtotime($start_date)).'-'.date('g:ia', strtotime($end_date)); + return $date_nice; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitRSVPFactory.php b/app/Models/Foundation/Summit/Factories/SummitRSVPFactory.php new file mode 100644 index 00000000..469cf4e8 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitRSVPFactory.php @@ -0,0 +1,104 @@ +setOwner($owner); + + if(!$rsvp->hasSeatTypeSet()) + $rsvp->setSeatType($summitEvent->getCurrentRSVPSubmissionSeatType()); + + $template = $summitEvent->getRSVPTemplate(); + + if(isset($data['event_uri']) && !empty($data['event_uri'])){ + $rsvp->setEventUri($data['event_uri']); + } + + $answers = $data['answers'] ?? []; + + // restructuring for a quick search + if(count($answers)){ + $bucket = []; + foreach ($answers as $answer_dto){ + $bucket[intval($answer_dto['question_id'])] = $answer_dto; + } + $answers = $bucket; + } + + foreach($template->getQuestions() as $question){ + + if(!$question instanceof RSVPQuestionTemplate) continue; + $answer_dto = $answers[$question->getId()] ?? null; + $value = $answer_dto['value'] ?? null; + + if($question->isMandatory() && + ( + is_null($value) || + (is_string($value) && empty($value)) || + (is_array($value)) && count($value) == 0 + ) + ) + throw new ValidationException(sprintf("Question '%s' is mandatory.", $question->getLabel())); + + $answer = $rsvp->findAnswerByQuestion($question); + if(is_null($answer)) + $answer = new RSVPAnswer(); + + if(!$question->isValidValue($value)) + throw new ValidationException(sprintf("Value is not valid for Question '%s'.", $question->getLabel())); + + $answer->setValue($value); + $answer->setQuestion($question); + $rsvp->addAnswer($answer); + } + + $summitEvent->addRSVPSubmission($rsvp); + + return $rsvp; + } +} \ No newline at end of file diff --git a/app/Models/OAuth2/IResourceServerContext.php b/app/Models/OAuth2/IResourceServerContext.php index 591edf93..8d4c87f7 100644 --- a/app/Models/OAuth2/IResourceServerContext.php +++ b/app/Models/OAuth2/IResourceServerContext.php @@ -1,20 +1,17 @@ getAuthContextVar('access_token'); } + /** + * @return null|string + */ + public function getAllowedOrigins() + { + return $this->getAuthContextVar('allowed_origins'); + } + + /** + * @return null|string + */ + public function getAllowedReturnUris() + { + return $this->getAuthContextVar('allowed_return_uris'); + } + /** * @return null|string */ diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 60a99b8b..6354684c 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -82,6 +82,17 @@ class AppServiceProvider extends ServiceProvider 'groups' => 'sometimes|int_array', ]; + + static $rsvp_answer_dto_fields = [ + 'question_id', + 'value', + ]; + + static $rsvp_answer_validation_rules = [ + 'question_id' => 'required|integer', + 'value' => 'sometimes|string_or_string_array', + ]; + /** * Bootstrap any application services. * @return void @@ -178,10 +189,32 @@ class AppServiceProvider extends ServiceProvider $validator->addReplacer('string_array', function($message, $attribute, $rule, $parameters) use ($validator) { return sprintf("%s should be an array of strings", $attribute); }); - if(!is_array($value)) return false; + if(!is_array($value)) + return false; foreach($value as $element) { - if(!is_string($element)) return false; + if(!is_string($element)) + return false; + } + return true; + }); + + Validator::extend('string_or_string_array', function($attribute, $value, $parameters, $validator) + { + $validator->addReplacer('string_or_string_array', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf("%s should be a string or an array of strings", $attribute); + }); + + if(is_string($value)) + return true; + + if(!is_array($value)) + return false; + + foreach($value as $element) + { + if(!is_string($element)) + return false; } return true; }); @@ -618,6 +651,31 @@ class AppServiceProvider extends ServiceProvider Validator::extend('greater_than', function ($attribute, $value, $otherValue) { return intval($value) > intval($otherValue[0]); }); + + Validator::extend('rsvp_answer_dto_array', function($attribute, $value, $parameters, $validator) + { + $validator->addReplacer('rsvp_answer_dto_array', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf + ( + "%s should be an array of rsvp answer data {question_id : int, value: string, values: string array}", + $attribute); + }); + if(!is_array($value)) return false; + foreach($value as $element) + { + foreach($element as $key => $element_val){ + if(!in_array($key, self::$rsvp_answer_dto_fields)) + return false; + } + + // Creates a Validator instance and validates the data. + $validation = Validator::make($element, self::$rsvp_answer_validation_rules); + + if($validation->fails()) + return false; + } + return true; + }); } /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 1507cfc2..186d074d 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -14,6 +14,8 @@ use App\EntityPersisters\AdminSummitEventActionSyncWorkRequestPersister; use App\EntityPersisters\AdminSummitLocationActionSyncWorkRequestPersister; use App\EntityPersisters\EntityEventPersister; +use App\Events\RSVPCreated; +use App\Events\RSVPUpdated; use App\Factories\CalendarAdminActionSyncWorkRequest\AdminSummitLocationActionSyncWorkRequestFactory; use App\Factories\CalendarAdminActionSyncWorkRequest\SummitEventDeletedCalendarSyncWorkRequestFactory; use App\Factories\CalendarAdminActionSyncWorkRequest\SummitEventUpdatedCalendarSyncWorkRequestFactory; @@ -44,13 +46,16 @@ use App\Mail\BookableRoomReservationPaymentConfirmedEmail; use App\Mail\BookableRoomReservationRefundAcceptedEmail; use App\Mail\BookableRoomReservationRefundRequestedAdminEmail; use App\Mail\BookableRoomReservationRefundRequestedOwnerEmail; +use App\Mail\Schedule\RSVPRegularSeatMail; +use App\Mail\Schedule\RSVPWaitListSeatMail; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Mail; use LaravelDoctrine\ORM\Facades\EntityManager; +use models\main\Member; +use models\summit\RSVP; use models\summit\SummitRoomReservation; - /** * Class EventServiceProvider * @package App\Providers @@ -376,5 +381,39 @@ final class EventServiceProvider extends ServiceProvider if(is_null($reservation) || ! $reservation instanceof SummitRoomReservation) return; Mail::send(new BookableRoomReservationCanceledEmail($reservation)); }); + + Event::listen(RSVPCreated::class, function($event){ + if(!$event instanceof RSVPCreated) return; + + $rsvp_id = $event->getRsvpId(); + + $rsvp_repository = EntityManager::getRepository(RSVP::class); + + $rsvp = $rsvp_repository->find($rsvp_id); + if(is_null($rsvp) || ! $rsvp instanceof RSVP) return; + + if($rsvp->getSeatType() == RSVP::SeatTypeRegular) + Mail::send(new RSVPRegularSeatMail($rsvp)); + + if($rsvp->getSeatType() == RSVP::SeatTypeWaitList) + Mail::send(new RSVPWaitListSeatMail($rsvp)); + }); + + Event::listen(RSVPUpdated::class, function($event){ + if(!$event instanceof RSVPUpdated) return; + + $rsvp_id = $event->getRsvpId(); + + $rsvp_repository = EntityManager::getRepository(RSVP::class); + + $rsvp = $rsvp_repository->find($rsvp_id); + if(is_null($rsvp) || ! $rsvp instanceof RSVP) return; + + if($rsvp->getSeatType() == RSVP::SeatTypeRegular) + Mail::send(new RSVPRegularSeatMail($rsvp)); + + if($rsvp->getSeatType() == RSVP::SeatTypeWaitList) + Mail::send(new RSVPWaitListSeatMail($rsvp)); + }); } } diff --git a/app/Services/Model/ISummitService.php b/app/Services/Model/ISummitService.php index 97f8153f..1069e40d 100644 --- a/app/Services/Model/ISummitService.php +++ b/app/Services/Model/ISummitService.php @@ -17,6 +17,7 @@ use models\exceptions\ValidationException; use models\main\File; use models\main\Member; use models\summit\ConfirmationExternalOrderRequest; +use models\summit\RSVP; use models\summit\Summit; use models\summit\SummitAttendee; use models\summit\SummitBookableVenueRoomAttributeType; @@ -143,14 +144,6 @@ interface ISummitService */ public function addEventToMemberFavorites(Summit $summit, Member $member, $event_id); - /** - * @param Summit $summit - * @param Member $member - * @param $event_id - * @return bool - */ - public function unRSVPEvent(Summit $summit, Member $member, $event_id); - /** * @param Summit $summit * @param int $event_id @@ -352,4 +345,36 @@ interface ISummitService * @throws EntityNotFoundException */ public function deleteSummitLogo(int $summit_id):void; + + /** + * @param Summit $summit + * @param Member $member + * @param int $event_id + * @param array $data + * @return RSVP + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function addRSVP(Summit $summit, Member $member, int $event_id, array $data):RSVP; + + /** + * @param Summit $summit + * @param Member $member + * @param int $event_id + * @param array $data + * @return RSVP + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function updateRSVP(Summit $summit, Member $member, int $event_id, array $data):RSVP; + + /** + * @param Summit $summit + * @param Member $member + * @param int $event_id + * @return bool + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function unRSVPEvent(Summit $summit, Member $member, int $event_id); } \ No newline at end of file diff --git a/app/Services/Model/SummitService.php b/app/Services/Model/SummitService.php index e2010e63..216c5a1b 100644 --- a/app/Services/Model/SummitService.php +++ b/app/Services/Model/SummitService.php @@ -15,10 +15,13 @@ use App\Events\MyFavoritesAdd; use App\Events\MyFavoritesRemove; use App\Events\MyScheduleAdd; use App\Events\MyScheduleRemove; +use App\Events\RSVPCreated; +use App\Events\RSVPUpdated; use App\Events\SummitDeleted; use App\Events\SummitUpdated; use App\Http\Utils\IFileUploader; use App\Models\Foundation\Summit\Factories\SummitFactory; +use App\Models\Foundation\Summit\Factories\SummitRSVPFactory; use App\Models\Foundation\Summit\Repositories\IDefaultSummitEventTypeRepository; use App\Models\Utils\IntervalParser; use App\Permissions\IPermissionsManager; @@ -52,6 +55,7 @@ use models\summit\ISummitEventRepository; use models\summit\ISummitRepository; use models\summit\Presentation; use models\summit\PresentationType; +use models\summit\RSVP; use models\summit\Summit; use models\summit\SummitAttendee; use models\summit\SummitAttendeeTicket; @@ -1227,37 +1231,6 @@ final class SummitService extends AbstractService implements ISummitService }); } - /** - * @param Summit $summit - * @param Member $member - * @param $event_id - * @return bool - */ - public function unRSVPEvent(Summit $summit, Member $member, $event_id) - { - return $this->tx_service->transaction(function () use ($summit, $member, $event_id) { - - $event = $summit->getScheduleEvent($event_id); - if (is_null($event)) { - throw new EntityNotFoundException('event not found on summit!'); - } - - if(!Summit::allowToSee($event, $member)) - throw new EntityNotFoundException('event not found on summit!'); - - $rsvp = $member->getRsvpByEvent($event_id); - - if(is_null($rsvp)) - throw new ValidationException(sprintf("rsvp for event id %s does not exist for your member", $event_id)); - - $this->rsvp_repository->delete($rsvp); - - $this->removeEventFromMemberSchedule($summit, $member, $event_id ,false); - - return true; - }); - } - /** * @param Summit $summit * @param int $event_id @@ -2128,4 +2101,158 @@ final class SummitService extends AbstractService implements ISummitService $summit->clearLogo(); }); } + + /** + * @param Summit $summit + * @param Member $member + * @param int $event_id + * @param array $data + * @return RSVP + * @throws Exception + */ + public function addRSVP(Summit $summit, Member $member, int $event_id, array $data): RSVP + { + $rsvp = $this->tx_service->transaction(function () use ($summit, $member, $event_id, $data) { + + $event = $this->event_repository->getByIdExclusiveLock($event_id); + + if (is_null($event) || !$event instanceof SummitEvent) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + if ($event->getSummitId() != $summit->getId()) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + if(!Summit::allowToSee($event, $member)) + throw new EntityNotFoundException('Event not found on summit.'); + + if (!$event->hasRSVPTemplate()) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + // add to schedule the RSVP event + if (!$member->isOnSchedule($event)) { + $this->addEventToMemberSchedule($summit, $member, $event_id, false); + } + + $old_rsvp = $member->getRsvpByEvent($event_id); + + if (!is_null($old_rsvp)) + throw new ValidationException + ( + sprintf + ( + "Member %s already submitted an rsvp for event %s on summit %s.", + $member->getId(), + $event_id, + $summit->getId() + ) + ); + + // create RSVP + + return SummitRSVPFactory::build($event, $member, $data); + }); + + Event::fire(new RSVPCreated($rsvp)); + + return $rsvp; + } + + /** + * @param Summit $summit + * @param Member $member + * @param int $event_id + * @param array $data + * @return RSVP + * @throws Exception + */ + public function updateRSVP(Summit $summit, Member $member, int $event_id, array $data): RSVP + { + return $this->tx_service->transaction(function () use ($summit, $member, $event_id, $data) { + + $event = $this->event_repository->getByIdExclusiveLock($event_id); + + if (is_null($event) || !$event instanceof SummitEvent) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + if ($event->getSummitId() != $summit->getId()) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + if (!Summit::allowToSee($event, $member)) + throw new EntityNotFoundException('Event not found on summit.'); + + if (!$event->hasRSVPTemplate()) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + // add to schedule the RSVP event + if (!$member->isOnSchedule($event)) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + $rsvp = $member->getRsvpByEvent($event->getId()); + + if (is_null($rsvp)) + throw new ValidationException + ( + sprintf + ( + "Member %s did not submitted an rsvp for event %s on summit %s.", + $member->getId(), + $event_id, + $summit->getId() + ) + ); + + // update RSVP + + $rsvp = SummitRSVPFactory::populate($rsvp, $event, $member, $data); + + Event::fire(new RSVPUpdated($rsvp)); + + return $rsvp; + }); + } + + /** + * @param Summit $summit + * @param Member $member + * @param int $event_id + * @return bool|mixed + * @throws Exception + */ + public function unRSVPEvent(Summit $summit, Member $member, int $event_id) + { + return $this->tx_service->transaction(function () use ($summit, $member, $event_id) { + + $event = $this->event_repository->getByIdExclusiveLock($event_id); + + if (is_null($event) || !$event instanceof SummitEvent) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + if ($event->getSummitId() != $summit->getId()) { + throw new EntityNotFoundException('Event not found on summit.'); + } + + if(!Summit::allowToSee($event, $member)) + throw new EntityNotFoundException('Event not found on summit.'); + + $rsvp = $member->getRsvpByEvent($event_id); + + if(is_null($rsvp)) + throw new ValidationException(sprintf("RSVP for event id %s does not exist for your member.", $event_id)); + + $this->rsvp_repository->delete($rsvp); + + $this->removeEventFromMemberSchedule($summit, $member, $event_id ,false); + + return true; + }); + } + } \ No newline at end of file diff --git a/config/schedule.php b/config/schedule.php new file mode 100644 index 00000000..3413aa6b --- /dev/null +++ b/config/schedule.php @@ -0,0 +1,13 @@ +hasTable("RSVP") && !$builder->hasColumn("RSVP", "EventUri")) { + $builder->table('RSVP', function (Table $table) { + $table->string("EventUri")->setNotnull(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($schema->hasTable("RSVP") && $builder->hasColumn("RSVP", "EventUri")) { + $builder->table('RSVP', function (Table $table) { + $table->dropColumn("EventUri"); + }); + } + } +} diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index 2c20b909..2b1b3c2f 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -3953,11 +3953,29 @@ class ApiEndpointsSeeder extends Seeder 'http_method' => 'POST', 'scopes' => [sprintf('%s/me/summits/events/favorites/add', $current_realm)], ], + [ + 'name' => 'add-rsvp-member', + 'route' => '/api/v1/summits/{id}/members/{member_id}/schedule/{event_id}/rsvp', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + ], + [ + 'name' => 'update-rsvp-member', + 'route' => '/api/v1/summits/{id}/members/{member_id}/schedule/{event_id}/rsvp', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + ], [ 'name' => 'delete-rsvp-member', 'route' => '/api/v1/summits/{id}/members/{member_id}/schedule/{event_id}/rsvp', 'http_method' => 'DELETE', - 'scopes' => [sprintf(SummitScopes::WriteSummitData, $current_realm)], + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], ], [ 'name' => 'remove-from-own-member-favorites', diff --git a/resources/views/emails/schedule/rsvp_regular_seat.blade.php b/resources/views/emails/schedule/rsvp_regular_seat.blade.php new file mode 100644 index 00000000..bf4f80b4 --- /dev/null +++ b/resources/views/emails/schedule/rsvp_regular_seat.blade.php @@ -0,0 +1,23 @@ + + + + + + +

Thank you for your RSVP to {!! $event_title !!} at {!! $event_date !!} . For your convenience, we have added this to My Schedule within the Summit Management tool.

+@if(!empty($event_uri)) +

Be sure to synch it to your calendar by going here.

+@endif +Please present a printed copy of this email at the entrance where the event is being held.

+ +******************************************************************************************
+

+ Attendee: {!! $owner_fullname !!}
+ Event: {!! $event_title !!}
+ Confirmation #: {!! $confirmation_number !!}
+

+******************************************************************************************
+ +

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

+ + diff --git a/resources/views/emails/schedule/rsvp_wait_seat.blade.php b/resources/views/emails/schedule/rsvp_wait_seat.blade.php new file mode 100644 index 00000000..b3bbd8bc --- /dev/null +++ b/resources/views/emails/schedule/rsvp_wait_seat.blade.php @@ -0,0 +1,26 @@ + + + + + + +

Thank you for signing up to {!! $event_title !!}< at {!! $event_date !!} At the moment, this class is full. + However, you've been added to the waitlist. If space becomes available, the Workshop presenter will contact you to let you know.

+ +

For your convenience, we have added this to My Schedule within the Summit Management tool.

+Be sure to synch it to your calendar by going here. + +If you are removed from the waitlist, please present a printed copy of this email at the entrance where the event is being held.

+ +******************************************************************************************
+

+ Attendee: {!! $owner_fullname !!}
+ Event: {!! $event_title !!}
+ Confirmation #: {!! $confirmation_number !!}
+

+******************************************************************************************
+ + +

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

+ + diff --git a/tests/OAuth2RSVPSummitEventApiTest.php b/tests/OAuth2RSVPSummitEventApiTest.php new file mode 100644 index 00000000..f1464c73 --- /dev/null +++ b/tests/OAuth2RSVPSummitEventApiTest.php @@ -0,0 +1,130 @@ + $summit_id, + 'member_id' => 'me', + 'event_id' => $event_id, + ); + + $headers = array + ( + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json", + "HTTP_Referer" => "https://www.openstack.org/summit/shanghai-2019/summit-schedule/events/".$event_id + ); + + $payload = [ + 'answers' => [ + [ + 'question_id' => 209, + 'value' => 'smarcet@gmail.com', + ], + [ + 'question_id' => 210, + 'value' => 'Sebastian', + ], + [ + 'question_id' => 211, + 'value' => 'Marcet', + ], + [ + 'question_id' => 212, + 'value' => 'Dev', + ], + [ + 'question_id' => 213, + 'value' => 'Tipit', + ], + [ + 'question_id' => 214, + 'value' => '+5491133943659', + ], + [ + 'question_id' => 215, + 'value' => [ + '150', '151' + ], + ], + [ + 'question_id' => 216, + 'value' => '155', + ], + [ + 'question_id' => 218, + 'value' => '161', + ], + [ + 'question_id' => 219, + 'value' => 'N/A', + ], + ] + ]; + + $response = $this->action + ( + "POST", + "OAuth2SummitMembersApiController@addEventRSVP", + $params, + [], + [], + [], + $headers, + json_encode($payload) + ); + $rsvp = $response->getContent(); + + $this->assertResponseStatus(201); + + return $rsvp; + } + + public function testCurrentSummitMyMemberScheduleUnRSVP($summit_id = 27, $event_id = 24344) + { + $params = array + ( + 'id' => $summit_id, + 'member_id' => 'me', + 'event_id' => $event_id + ); + + $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); + $response = $this->action( + "DELETE", + "OAuth2SummitMembersApiController@deleteEventRSVP", + $params, + array(), + array(), + array(), + $headers + ); + $content = $response->getContent(); + $this->assertResponseStatus(204); + } + +} \ No newline at end of file diff --git a/tests/OAuth2SummitApiTest.php b/tests/OAuth2SummitApiTest.php index 1f81c7e3..f38c5394 100644 --- a/tests/OAuth2SummitApiTest.php +++ b/tests/OAuth2SummitApiTest.php @@ -686,29 +686,6 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertResponseStatus(204); } - public function testCurrentSummitMyAttendeeScheduleUnRSVP($event_id = 18639, $summit_id = 22) - { - //$this->testCurrentSummitMyAttendeeAddToSchedule($event_id, $summit_id); - $params = array - ( - 'id' => $summit_id, - 'attendee_id' => 'me', - 'event_id' => $event_id - ); - - $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); - $response = $this->action( - "DELETE", - "OAuth2SummitAttendeesApiController@deleteEventRSVP", - $params, - array(), - array(), - array(), - $headers - ); - $content = $response->getContent(); - $this->assertResponseStatus(204); - } public function testGetMySpeakerFromCurrentSummit() { @@ -1444,31 +1421,6 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertResponseStatus(204); } - public function testCurrentSummitMyMemberScheduleUnRSVP($event_id = 18639, $summit_id = 22) - { - //$this->testCurrentSummitMyAttendeeAddToSchedule($event_id, $summit_id); - $params = array - ( - 'id' => $summit_id, - 'member_id' => 'me', - 'event_id' => $event_id - ); - - $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); - $response = $this->action( - "DELETE", - "OAuth2SummitMembersApiController@deleteEventRSVP", - $params, - array(), - array(), - array(), - $headers - ); - $content = $response->getContent(); - $this->assertResponseStatus(204); - } - - public function testAddPresentationSlide($summit_id=25){ $repo = EntityManager::getRepository(\models\summit\Summit::class); diff --git a/tests/ProtectedApiTest.php b/tests/ProtectedApiTest.php index 0a5e7d80..cce35a14 100644 --- a/tests/ProtectedApiTest.php +++ b/tests/ProtectedApiTest.php @@ -81,7 +81,7 @@ class AccessTokenServiceStub implements IAccessTokenService 'user_external_id' => '13867', 'expires_in' => 3600, 'application_type' => 'WEB_APPLICATION', - 'allowed_return_uris' => '', + 'allowed_return_uris' => 'https://www.openstack.org/OpenStackIdAuthenticator,https://www.openstack.org/Security/login', 'allowed_origins' => '' ] );