From b5a1bf71093ec13cb4d63349792e263b352cc194 Mon Sep 17 00:00:00 2001 From: Sebastian Marcet Date: Tue, 23 Jan 2018 13:15:40 -0300 Subject: [PATCH] added new endpoint promo code email send POST /api/v1/summits/{id}/promo-codes/{promo_code_id}/mail Change-Id: I96a75856c9822339914b64855782f5d08a844701 --- .../OAuth2SummitPromoCodesApiController.php | 24 ++++++ app/Http/routes.php | 1 + app/Models/Foundation/Main/Member.php | 12 +++ .../MemberSummitRegistrationPromoCode.php | 17 +++- .../Model/ISummitPromoCodeService.php | 11 +++ app/Services/Model/SpeakerService.php | 2 +- app/Services/Model/SummitPromoCodeService.php | 85 +++++++++++++++++-- database/seeds/ApiEndpointsSeeder.php | 9 ++ resources/lang/en/not_found_errors.php | 17 ++++ resources/lang/en/validation_errors.php | 20 +++++ tests/OAuth2PromoCodesApiTest.php | 72 ++++++++++++++++ 11 files changed, 259 insertions(+), 11 deletions(-) create mode 100644 resources/lang/en/not_found_errors.php create mode 100644 resources/lang/en/validation_errors.php diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitPromoCodesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitPromoCodesApiController.php index c2850e53..ffaa0d3f 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitPromoCodesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitPromoCodesApiController.php @@ -363,4 +363,28 @@ final class OAuth2SummitPromoCodesApiController extends OAuth2ProtectedControlle return $this->error500($ex); } } + + /** + * @param $summit_id + * @param $promo_code_id + * @return mixed + */ + public function sendPromoCodeMail($summit_id, $promo_code_id) + { + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $mail_request = $this->promo_code_service->sendPromoCodeMail($summit, $promo_code_id); + return $this->ok($mail_request->getId()); + } catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } catch (EntityNotFoundException $ex2) { + Log::warning($ex2); + return $this->error404(array('message' => $ex2->getMessage())); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } } \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index 4982f0c6..d9ab2f29 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -338,6 +338,7 @@ Route::group([ Route::group(['prefix' => '{promo_code_id}'], function () { Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitPromoCodesApiController@updatePromoCodeBySummit']); Route::delete('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitPromoCodesApiController@deletePromoCodeBySummit']); + Route::post('mail', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitPromoCodesApiController@sendPromoCodeMail']); }); }); diff --git a/app/Models/Foundation/Main/Member.php b/app/Models/Foundation/Main/Member.php index 196e7494..69baab85 100644 --- a/app/Models/Foundation/Main/Member.php +++ b/app/Models/Foundation/Main/Member.php @@ -1058,4 +1058,16 @@ SQL; $this->rsvp->removeElement($rsvp); return $this; } + + /** + * @return string + */ + public function getFullName(){ + $fullname = $this->first_name; + if(!empty($this->last_name)){ + if(!empty($fullname)) $fullname .= ', '; + $fullname .= $this->last_name; + } + return $fullname; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/PromoCodes/MemberSummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/PromoCodes/MemberSummitRegistrationPromoCode.php index 3ab0184f..fa0a9d15 100644 --- a/app/Models/Foundation/Summit/PromoCodes/MemberSummitRegistrationPromoCode.php +++ b/app/Models/Foundation/Summit/PromoCodes/MemberSummitRegistrationPromoCode.php @@ -88,11 +88,24 @@ class MemberSummitRegistrationPromoCode extends SummitRegistrationPromoCode } /** - * @return mixed + * @return string|null */ public function getEmail() { - return $this->email; + if(!empty($this->email)) return $this->email; + if($this->hasOwner()) return $this->getOwner()->getEmail(); + return null; + } + + public function getFullName(){ + $fullname = $this->first_name; + if(!empty($this->last_name)){ + if(!empty($fullname)) $fullname .= ', '; + $fullname .= $this->last_name; + } + if(!empty($fullname)) return $fullname; + if($this->hasOwner()) return $this->getOwner()->getFullName(); + return null; } /** diff --git a/app/Services/Model/ISummitPromoCodeService.php b/app/Services/Model/ISummitPromoCodeService.php index 4fe8529a..835c36ef 100644 --- a/app/Services/Model/ISummitPromoCodeService.php +++ b/app/Services/Model/ISummitPromoCodeService.php @@ -13,6 +13,7 @@ **/ use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; +use models\main\EmailCreationRequest; use models\main\Member; use models\summit\Summit; use models\summit\SummitRegistrationPromoCode; @@ -51,4 +52,14 @@ interface ISummitPromoCodeService * @throws ValidationException */ public function deletePromoCode(Summit $summit, $promo_code_id); + + + /** + * @param Summit $summit + * @param int $promo_code_id + * @return EmailCreationRequest + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function sendPromoCodeMail(Summit $summit, $promo_code_id); } \ No newline at end of file diff --git a/app/Services/Model/SpeakerService.php b/app/Services/Model/SpeakerService.php index fa8bbbab..a48bb4a5 100644 --- a/app/Services/Model/SpeakerService.php +++ b/app/Services/Model/SpeakerService.php @@ -65,12 +65,12 @@ final class SpeakerService implements ISpeakerService * @var IEmailCreationRequestRepository */ private $email_creation_request_repository; + /** * @var ITransactionService */ private $tx_service; - /** * SpeakerService constructor. * @param ISpeakerRepository $speaker_repository diff --git a/app/Services/Model/SummitPromoCodeService.php b/app/Services/Model/SummitPromoCodeService.php index 833591e1..f3efe3d0 100644 --- a/app/Services/Model/SummitPromoCodeService.php +++ b/app/Services/Model/SummitPromoCodeService.php @@ -15,11 +15,16 @@ use App\Models\Foundation\Summit\Factories\SummitPromoCodeFactory; use libs\utils\ITransactionService; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; +use models\main\EmailCreationRequest; use models\main\ICompanyRepository; +use models\main\IEmailCreationRequestRepository; use models\main\IMemberRepository; use models\main\Member; +use models\main\MemberPromoCodeEmailCreationRequest; use models\summit\ISpeakerRepository; use models\summit\ISummitRegistrationPromoCodeRepository; +use models\summit\MemberSummitRegistrationPromoCode; +use models\summit\SpeakerSummitRegistrationPromoCode; use models\summit\Summit; use models\summit\SummitRegistrationPromoCode; use services\model\ISummitPromoCodeService; @@ -49,6 +54,11 @@ final class SummitPromoCodeService implements ISummitPromoCodeService */ private $speaker_repository; + /** + * @var IEmailCreationRequestRepository + */ + private $email_creation_request_repository; + /** * @var ITransactionService */ @@ -60,6 +70,7 @@ final class SummitPromoCodeService implements ISummitPromoCodeService * @param IMemberRepository $member_repository * @param ICompanyRepository $company_repository * @param ISpeakerRepository $speaker_repository + * @param IEmailCreationRequestRepository $email_creation_request_repository * @param ITransactionService $tx_service */ public function __construct @@ -68,14 +79,16 @@ final class SummitPromoCodeService implements ISummitPromoCodeService IMemberRepository $member_repository, ICompanyRepository $company_repository, ISpeakerRepository $speaker_repository, + IEmailCreationRequestRepository $email_creation_request_repository, ITransactionService $tx_service ) { - $this->promo_code_repository = $promo_code_repository; - $this->member_repository = $member_repository; - $this->company_repository = $company_repository; - $this->speaker_repository = $speaker_repository; - $this->tx_service = $tx_service; + $this->promo_code_repository = $promo_code_repository; + $this->member_repository = $member_repository; + $this->company_repository = $company_repository; + $this->speaker_repository = $speaker_repository; + $this->email_creation_request_repository = $email_creation_request_repository; + $this->tx_service = $tx_service; } /** @@ -186,16 +199,72 @@ final class SummitPromoCodeService implements ISummitPromoCodeService $promo_code = $summit->getPromoCodeById($promo_code_id); if(is_null($promo_code)) - throw new EntityNotFoundException(sprintf("promo code id %s does not belongs to summit id %s", $promo_code_id, $summit->getId())); + throw new EntityNotFoundException + ( + trans + ( + 'not_found_errors.promo_code_delete_code_not_found', + [ 'promo_code_id' => $promo_code_id, 'summit_id' => $summit->getId()] + ) + ); if ($promo_code->isEmailSent()) - throw new EntityValidationException("Cannot delete a code that has been already sent."); + throw new ValidationException(trans('validation_errors.promo_code_delete_already_sent')); if ($promo_code->isRedeemed()) - throw new EntityValidationException("Cannot delete a code that has been already redeemed."); + throw new ValidationException(trans('validation_errors.promo_code_delete_already_redeemed')); $summit->removePromoCode($promo_code); }); } + + /** + * @param Summit $summit + * @param int $promo_code_id + * @return EmailCreationRequest + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function sendPromoCodeMail(Summit $summit, $promo_code_id) + { + return $this->tx_service->transaction(function() use($promo_code_id, $summit){ + + $promo_code = $summit->getPromoCodeById($promo_code_id); + if(is_null($promo_code)) + throw new EntityNotFoundException(trans('not_found_errors.promo_code_email_code_not_found', [ 'promo_code_id' => $promo_code_id, 'summit_id' => $summit->getId()])); + + if ($promo_code->isEmailSent()) + throw new ValidationException(trans('validation_errors.promo_code_email_send_already_sent')); + + $name = null; + $email = null; + + if($promo_code instanceof SpeakerSummitRegistrationPromoCode){ + $name = $promo_code->getSpeaker()->getFullName(); + $email = $promo_code->getSpeaker()->getEmail(); + } + if($promo_code instanceof MemberSummitRegistrationPromoCode){ + $name = $promo_code->getFullName(); + $email = $promo_code->getEmail(); + } + + if(empty($name)){ + throw new ValidationException(trans("validation_errors.promo_code_email_send_empty_email")); + } + + if(empty($name)){ + throw new ValidationException(trans("validation_errors.promo_code_email_send_empty_name")); + } + + // create email request + $email_request = new MemberPromoCodeEmailCreationRequest(); + $email_request->setPromoCode($promo_code); + $email_request->setEmail($name); + $email_request->setName($email); + $this->email_creation_request_repository->add($email_request); + $promo_code->setEmailSent(true); + return $email_request; + }); + } } \ No newline at end of file diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index ba62aa3b..890d9892 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -694,6 +694,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::WriteSummitData, $current_realm) ], ], + [ + 'name' => 'send-promo-code-mail', + 'route' => '/api/v1/summits/{id}/promo-codes/{promo_code_id}/mail', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WritePromoCodeData, $current_realm), + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + ], [ 'name' => 'get-promo-codes-metadata', 'route' => '/api/v1/summits/{id}/promo-codes/metadata', diff --git a/resources/lang/en/not_found_errors.php b/resources/lang/en/not_found_errors.php new file mode 100644 index 00000000..903a38e1 --- /dev/null +++ b/resources/lang/en/not_found_errors.php @@ -0,0 +1,17 @@ + '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.', +]; \ No newline at end of file diff --git a/resources/lang/en/validation_errors.php b/resources/lang/en/validation_errors.php new file mode 100644 index 00000000..261f19f7 --- /dev/null +++ b/resources/lang/en/validation_errors.php @@ -0,0 +1,20 @@ + 'Cannot delete a code that has been already sent.', + 'promo_code_delete_already_redeemed' => 'Cannot delete a code that has been already redeemed.', + 'promo_code_email_send_already_sent' => 'Cannot resend a code that has been already sent.', + '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.', +]; \ No newline at end of file diff --git a/tests/OAuth2PromoCodesApiTest.php b/tests/OAuth2PromoCodesApiTest.php index 27b8cb17..b2407070 100644 --- a/tests/OAuth2PromoCodesApiTest.php +++ b/tests/OAuth2PromoCodesApiTest.php @@ -307,4 +307,76 @@ final class OAuth2PromoCodesApiTest extends ProtectedApiTest $content = $response->getContent(); $this->assertResponseStatus(204); } + + public function testEmailPromoCode($summit_id = 23){ + + $code = str_random(16).'_PROMOCODE_TEST'; + $promo_code = $this->testAddPromoCode($summit_id, $code); + $params = [ + 'id' => $summit_id, + 'promo_code_id' => $promo_code->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitPromoCodesApiController@sendPromoCodeMail", + $params, + [], + [], + [], + $headers + + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + } + + public function testEmailPromoCodeSendTwice($summit_id = 23){ + + $code = str_random(16).'_PROMOCODE_TEST'; + $promo_code = $this->testAddPromoCode($summit_id, $code); + $params = [ + 'id' => $summit_id, + 'promo_code_id' => $promo_code->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitPromoCodesApiController@sendPromoCodeMail", + $params, + [], + [], + [], + $headers + + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + $response = $this->action( + "POST", + "OAuth2SummitPromoCodesApiController@sendPromoCodeMail", + $params, + [], + [], + [], + $headers + + ); + + $content = $response->getContent(); + $this->assertResponseStatus(412); + } } \ No newline at end of file