diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitTicketTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitTicketTypeValidationRulesFactory.php new file mode 100644 index 00000000..8397119b --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitTicketTypeValidationRulesFactory.php @@ -0,0 +1,42 @@ + 'sometimes|string', + 'description' => 'sometimes|string', + 'external_id' => 'sometimes|string|max:255', + ]; + } + + return [ + 'name' => 'required|string', + 'description' => 'sometimes|string', + 'external_id' => 'required|string|max:255', + ]; + } + + +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php index ab00f6f0..6787c608 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php @@ -259,4 +259,50 @@ final class OAuth2SummitsTicketTypesApiController extends OAuth2ProtectedControl } } + public function addTicketTypeBySummit($summit_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(); + + $rules = SummitTicketTypeValidationRulesFactory::build($payload); + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $ticket_type = $this->ticket_type_service->addTicketType($summit, $payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($ticket_type)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412([$ex1->getMessage()]); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(['message'=> $ex2->getMessage()]); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + + public function seedDefaultTicketTypesBySummit($summit_id){ + + } + } \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index 0240a9c7..b6ead67f 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -425,6 +425,8 @@ Route::group([ Route::group(['prefix' => 'ticket-types'], function () { Route::get('', 'OAuth2SummitsTicketTypesApiController@getAllBySummit'); Route::get('csv', 'OAuth2SummitsTicketTypesApiController@getAllBySummitCSV'); + Route::post('seed-defaults', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitsTicketTypesApiController@seedDefaultTicketTypesBySummit']); + Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitsTicketTypesApiController@addTicketTypeBySummit']); }); // external orders diff --git a/app/Models/Foundation/Summit/Factories/SummitTicketTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitTicketTypeFactory.php new file mode 100644 index 00000000..067a86c9 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitTicketTypeFactory.php @@ -0,0 +1,47 @@ +setName(trim($data['name'])); + + if(isset($data['description'])) + $ticket_type->setDescription(trim($data['description'])); + + if(isset($data['external_id'])) + $ticket_type->setExternalId(trim($data['external_id'])); + + return $ticket_type; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Summit.php b/app/Models/Foundation/Summit/Summit.php index 1ce20e56..e9d08cfd 100644 --- a/app/Models/Foundation/Summit/Summit.php +++ b/app/Models/Foundation/Summit/Summit.php @@ -1677,6 +1677,52 @@ SQL; return $this; } + /** + * @param SummitTicketType $ticket_type + * @return $this + */ + public function addTicketType(SummitTicketType $ticket_type) + { + $this->ticket_types->add($ticket_type); + $ticket_type->setSummit($this); + return $this; + } + + + /** + * @param SummitTicketType $ticket_type + * @return $this + */ + public function removeTicketType(SummitTicketType $ticket_type) + { + $this->ticket_types->remove($ticket_type); + $ticket_type->clearSummit($this); + return $this; + } + + /** + * @param string $name + * @return SummitTicketType|null + */ + public function getTicketTypeByName($name){ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($name))); + $res = $this->ticket_types->matching($criteria)->first(); + return $res === false ? null : $res; + } + + + /** + * @param int $id + * @return SummitTicketType|null + */ + public function getTicketTypeById($id){ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($id))); + $res = $this->ticket_types->matching($criteria)->first(); + return $res === false ? null : $res; + } + /** * @param int $rsvp_template_id * @return RSVPTemplate|null diff --git a/app/Security/SummitScopes.php b/app/Security/SummitScopes.php index e57cc8e6..61af47fd 100644 --- a/app/Security/SummitScopes.php +++ b/app/Security/SummitScopes.php @@ -46,4 +46,6 @@ final class SummitScopes const WriteLocationBannersData = '%s/locations/banners/write'; const WriteSummitSpeakerAssistanceData = '%s/summit-speaker-assistance/write'; + + const WriteTicketTypeData = '%s/ticket-types/write'; } \ No newline at end of file diff --git a/app/Services/Model/ISummitTicketTypeService.php b/app/Services/Model/ISummitTicketTypeService.php index d0186e64..74bcb16f 100644 --- a/app/Services/Model/ISummitTicketTypeService.php +++ b/app/Services/Model/ISummitTicketTypeService.php @@ -11,8 +11,22 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - +use models\exceptions\EntityNotFoundException; +use models\exceptions\ValidationException; +use models\summit\Summit; +use models\summit\SummitTicketType; +/** + * Interface ISummitTicketTypeService + * @package App\Services\Model + */ interface ISummitTicketTypeService { - + /** + * @param Summit $summit + * @param array $data + * @return SummitTicketType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addTicketType(Summit $summit, array $data); } \ No newline at end of file diff --git a/app/Services/Model/SummitTicketTypeService.php b/app/Services/Model/SummitTicketTypeService.php index 47f1a812..d4b1f5ba 100644 --- a/app/Services/Model/SummitTicketTypeService.php +++ b/app/Services/Model/SummitTicketTypeService.php @@ -11,7 +11,13 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - +use App\Models\Foundation\Summit\Factories\SummitTicketTypeFactory; +use libs\utils\ITransactionService; +use models\exceptions\EntityNotFoundException; +use models\exceptions\ValidationException; +use models\summit\ISummitTicketTypeRepository; +use models\summit\Summit; +use models\summit\SummitTicketType; /** * Class SummitTicketTypeService * @package App\Services\Model @@ -21,4 +27,72 @@ final class SummitTicketTypeService implements ISummitTicketTypeService { + /** + * @var ISummitTicketTypeRepository + */ + private $repository; + + /** + * SummitTicketTypeService constructor. + * @param ISummitTicketTypeRepository $repository + * @param ITransactionService $tx_service + */ + public function __construct + ( + ISummitTicketTypeRepository $repository, + ITransactionService $tx_service + ) + { + parent::__construct($tx_service); + $this->repository = $repository; + } + + /** + * @param Summit $summit + * @param array $data + * @return SummitTicketType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addTicketType(Summit $summit, array $data) + { + return $this->tx_service->transaction(function() use ($summit, $data){ + + $former_ticket_type = $summit->getTicketTypeByName(trim($data['name'])); + + if(!is_null($former_ticket_type)){ + throw new ValidationException + ( + trans + ( + 'validation_errors.SummitTicketTypeService.addTicketType.NameAlreadyExists' + ), + [ + 'name' => trim($data['name']), + 'summit_id' => $summit->getId() + ] + ); + } + + $former_ticket_type = $summit->getTicketTypeByExternalId(trim($data['external_id'])); + if(!is_null($former_ticket_type)){ + throw new ValidationException + ( + trans + ( + 'validation_errors.SummitTicketTypeService.addTicketType.ExternalIdAlreadyExists' + ), + [ + 'external_id' => trim($data['external_id']), + 'summit_id' => $summit->getId() + ] + ); + } + + $ticket_type = SummitTicketTypeFactory::build($data); + + $summit->addTicketType($ticket_type); + return $ticket_type; + }); + } } \ No newline at end of file diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index da65d970..a64b6ef2 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -1123,6 +1123,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], ], + [ + 'name' => 'add-ticket-type', + 'route' => '/api/v1/summits/{id}/ticket-types', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteTicketTypeData, $current_realm), + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + ], // track groups array( 'name' => 'get-track-groups', diff --git a/resources/lang/en/validation_errors.php b/resources/lang/en/validation_errors.php index 9d63e23c..a6afabaf 100644 --- a/resources/lang/en/validation_errors.php +++ b/resources/lang/en/validation_errors.php @@ -55,4 +55,6 @@ return [ 'RSVPTemplateService.addQuestion.QuestionNameAlreadyExists' => 'question name :name already exists for template :template_id', 'RSVPTemplateService.updateQuestion.QuestionNameAlreadyExists' => 'question name :name already exists for template :template_id', 'RSVPTemplateService.addQuestionValue.ValueAlreadyExist' => 'value :value already exists on question :question_id', + 'SummitTicketTypeService.addTicketType.NameAlreadyExists' => 'ticket name :name already exists on summit :summit_id', + 'SummitTicketTypeService.addTicketType.ExternalIdAlreadyExists' => 'ticket external id :external_id already exists on summit :summit_id', ]; \ No newline at end of file diff --git a/tests/OAuth2TicketTypesApiTest.php b/tests/OAuth2TicketTypesApiTest.php index 7f43b09e..1351009f 100644 --- a/tests/OAuth2TicketTypesApiTest.php +++ b/tests/OAuth2TicketTypesApiTest.php @@ -49,4 +49,41 @@ final class OAuth2TicketTypesApiTest extends ProtectedApiTest return $ticket_types; } + public function testAddTicketType($summit_id = 24){ + $params = [ + 'id' => $summit_id, + ]; + + $name = str_random(16).'_ticket_type'; + $external_id = str_random(16).'_external_id'; + + $data = [ + 'name' => $name, + 'external_id' => $external_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitsTicketTypesApiController@addTicketTypeBySummit", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $ticket_type = json_decode($content); + $this->assertTrue(!is_null($ticket_type)); + $this->assertTrue($ticket_type->name == $name); + $this->assertTrue($ticket_type->external_id == $external_id); + return $ticket_type; + } } \ No newline at end of file