Added endpoints to create/update RSVP templates by summit

POST /api/v1/summits/{id}/rsvp-templates

Payload

* title (required|string|max:255)
* is_enabled (required|boolean)

PUT /api/v1/summits/{id}/rsvp-templates/{template_id}

Payload

* title (sometimes|string|max:255)
* is_enabled (sometimes|boolean)

Change-Id: I8d379bd796382ec75fef238ad2e2b9681d51e909
This commit is contained in:
Sebastian Marcet 2018-03-29 11:06:47 -03:00
parent cc63b26987
commit e6af97c7e8
12 changed files with 405 additions and 4 deletions

View File

@ -11,8 +11,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Events\SummitTicketTypeAction;
use Illuminate\Support\Facades\App;
use models\main\IMemberRepository;
use models\oauth2\IResourceServerContext;
use models\summit\ISummitRepository;

View File

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

View File

@ -21,6 +21,7 @@ use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Validator;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\IMemberRepository;
use models\oauth2\IResourceServerContext;
use models\summit\ISummitRepository;
use ModelSerializers\SerializerRegistry;
@ -51,10 +52,16 @@ final class OAuth2SummitRSVPTemplatesApiController extends OAuth2ProtectedContro
*/
private $rsvp_template_service;
/**
* @var IMemberRepository
*/
private $member_repository;
/**
* OAuth2SummitRSVPTemplatesApiController constructor.
* @param ISummitRepository $summit_repository
* @param IRSVPTemplateRepository $rsvp_template_repository
* @param IMemberRepository $member_repository
* @param IRSVPTemplateService $rsvp_template_service
* @param IResourceServerContext $resource_server_context
*/
@ -62,16 +69,22 @@ final class OAuth2SummitRSVPTemplatesApiController extends OAuth2ProtectedContro
(
ISummitRepository $summit_repository,
IRSVPTemplateRepository $rsvp_template_repository,
IMemberRepository $member_repository,
IRSVPTemplateService $rsvp_template_service,
IResourceServerContext $resource_server_context
)
{
parent::__construct($resource_server_context);
$this->summit_repository = $summit_repository;
$this->member_repository = $member_repository;
$this->rsvp_template_service = $rsvp_template_service;
$this->rsvp_template_repository = $rsvp_template_repository;
}
/**
* Template endpoints
*/
/**
* @param $summit_id
* @return mixed
@ -235,6 +248,102 @@ final class OAuth2SummitRSVPTemplatesApiController extends OAuth2ProtectedContro
}
}
/**
* @param $summit_id
* @return mixed
*/
public function addRSVPTemplate($summit_id){
try {
if(!Request::isJson()) return $this->error400();
$payload = Input::json()->all();
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$rules = SummitRSVPTemplateValidationRulesFactory::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
);
}
$current_member = null;
if(!is_null($this->resource_server_context->getCurrentUserExternalId())){
$current_member = $this->member_repository->getById($this->resource_server_context->getCurrentUserExternalId());
}
$template = $this->rsvp_template_service->addTemplate($summit, $current_member, $payload);
return $this->created(SerializerRegistry::getInstance()->getSerializer($template)->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);
}
}
/**
* @param $summit_id
* @param $template_id
* @return mixed
*/
public function updateRSVPTemplate($summit_id, $template_id){
try {
if(!Request::isJson()) return $this->error400();
$payload = Input::json()->all();
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$rules = SummitRSVPTemplateValidationRulesFactory::build($payload, true);
// Creates a Validator instance and validates the data.
$validation = Validator::make($payload, $rules);
if ($validation->fails()) {
$messages = $validation->messages()->toArray();
return $this->error412
(
$messages
);
}
$template = $this->rsvp_template_service->updateTemplate($summit, $template_id, $payload);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($template)->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);
}
}
/**
* Questions endpoints
*/
@ -457,7 +566,7 @@ final class OAuth2SummitRSVPTemplatesApiController extends OAuth2ProtectedContro
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$rules = SummitRSVPTemplateQuestionValueValidationRulesFactory::build($payload, true);
$rules = SummitRSVPTemplateQuestionValueValidationRulesFactory::build($payload);
// Creates a Validator instance and validates the data.
$validation = Validator::make($payload, $rules);

View File

@ -170,8 +170,10 @@ Route::group([
// rsvp templates
Route::group(['prefix' => 'rsvp-templates'], function () {
Route::get('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@getAllBySummit']);
Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@addRSVPTemplate']);
Route::group(['prefix' => '{template_id}'], function () {
Route::get('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@getRSVPTemplate']);
Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@updateRSVPTemplate']);
Route::delete('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@deleteRSVPTemplate']);
Route::group(['prefix' => 'questions'], function () {
Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@addRSVPTemplateQuestion']);

View File

@ -21,9 +21,8 @@ use ModelSerializers\SilverStripeSerializer;
final class RSVPTemplateSerializer extends SilverStripeSerializer
{
protected static $array_mappings = [
'Title' => 'title:json_string',
'Enabled' => 'is_enable:json_boolean',
'Enabled' => 'is_enabled:json_boolean',
'CreatedById' => 'created_by_id:json_int',
'SummitId' => 'summit_id:json_int',
];

View File

@ -0,0 +1,44 @@
<?php namespace App\Models\Foundation\Summit\Factories;
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Models\Foundation\Summit\Events\RSVP\RSVPTemplate;
/**
* Class SummitRSVPTemplateFactory
* @package App\Models\Foundation\Summit\Factories
*/
final class SummitRSVPTemplateFactory
{
/**
* @param array $data
* @return RSVPTemplate
*/
public static function build(array $data){
return self::populate(new RSVPTemplate, $data);
}
/**
* @param RSVPTemplate $template
* @param array $data
* @return RSVPTemplate
*/
public static function populate(RSVPTemplate $template, array $data){
if(isset($data['title']))
$template->setTitle(trim($data['title']));
if(isset($data['is_enabled']))
$template->setIsEnabled(boolval($data['is_enabled']));
return $template;
}
}

View File

@ -1751,11 +1751,35 @@ SQL;
return $rsvp_template === false ? null : $rsvp_template;
}
/**
* @param string $rsvp_template_title
* @return RSVPTemplate|null
*/
public function getRSVPTemplateByTitle($rsvp_template_title){
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('title', trim($rsvp_template_title)));
$rsvp_template = $this->rsvp_templates->matching($criteria)->first();
return $rsvp_template === false ? null : $rsvp_template;
}
/**
* @param RSVPTemplate $template
* @return $this
*/
public function addRSVPTemplate(RSVPTemplate $template){
if($this->rsvp_templates->contains($template)) return;
$this->rsvp_templates->add($template);
$template->setSummit($this);
return $this;
}
/**
* @param RSVPTemplate $template
* @return $this
*/
public function removeRSVPTemplate(RSVPTemplate $template){
if(!$this->rsvp_templates->contains($template)) return;
$this->rsvp_templates->removeElement($template);
$template->clearSummit();
return $this;

View File

@ -13,8 +13,10 @@
**/
use App\Models\Foundation\Summit\Events\RSVP\RSVPQuestionTemplate;
use App\Models\Foundation\Summit\Events\RSVP\RSVPQuestionValueTemplate;
use App\Models\Foundation\Summit\Events\RSVP\RSVPTemplate;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\Member;
use models\summit\Summit;
/**
* Interface IRSVPTemplateService
@ -22,6 +24,26 @@ use models\summit\Summit;
*/
interface IRSVPTemplateService
{
/**
* @param Summit $summit
* @param Member|null $creator
* @param array $payload
* @return RSVPTemplate
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function addTemplate(Summit $summit, Member $creator, array $payload);
/**
* @param Summit $summit
* @param int $template_id
* @param array $payload
* @return RSVPTemplate
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function updateTemplate(Summit $summit, $template_id, array $payload);
/**
* @param Summit $summit
* @param int $template_id

View File

@ -14,12 +14,15 @@
use App\Models\Foundation\Summit\Events\RSVP\RSVPMultiValueQuestionTemplate;
use App\Models\Foundation\Summit\Events\RSVP\RSVPQuestionTemplate;
use App\Models\Foundation\Summit\Events\RSVP\RSVPQuestionValueTemplate;
use App\Models\Foundation\Summit\Events\RSVP\RSVPTemplate;
use App\Models\Foundation\Summit\Factories\SummitRSVPTemplateFactory;
use App\Models\Foundation\Summit\Factories\SummitRSVPTemplateQuestionFactory;
use App\Models\Foundation\Summit\Factories\SummitRSVPTemplateQuestionValueFactory;
use App\Models\Foundation\Summit\Repositories\IRSVPTemplateRepository;
use libs\utils\ITransactionService;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\Member;
use models\summit\Summit;
/**
* Class RSVPTemplateService
@ -45,6 +48,88 @@ final class RSVPTemplateService
$this->rsvp_template_repository = $rsvp_template_repository;
}
/**
* @param Summit $summit
* @param Member|null $creator
* @param array $payload
* @return RSVPTemplate
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function addTemplate(Summit $summit, Member $creator, array $payload)
{
return $this->tx_service->transaction(function() use($summit, $creator, $payload){
$former_template = $summit->getRSVPTemplateByTitle($payload['title']);
if(!is_null($former_template)){
throw new ValidationException
(
trans('validation_errors.RSVPTemplateService.addTemplate.TitleAlreadyExists'),
[
'title' => $payload['title'],
'summit_id' => $summit->getId()
]
);
}
$template = SummitRSVPTemplateFactory::build($payload);
if(!is_null($creator))
$template->setCreatedBy($creator);
$summit->addRSVPTemplate($template);
return $template;
});
}
/**
* @param Summit $summit
* @param int $template_id
* @param array $payload
* @return RSVPTemplate
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function updateTemplate(Summit $summit, $template_id, array $payload)
{
return $this->tx_service->transaction(function() use($summit, $template_id, $payload){
if(isset($payload['title'])) {
$former_template = $summit->getRSVPTemplateByTitle($payload['title']);
if (!is_null($former_template) && $former_template->getId() != $template_id) {
throw new ValidationException
(
trans('validation_errors.RSVPTemplateService.updateTemplate.TitleAlreadyExists',
[
'title' => $payload['title'],
'summit_id' => $summit->getId()
]
)
);
}
}
$template = $summit->getRSVPTemplateById($template_id);
if(is_null($template)){
throw new EntityNotFoundException
(
trans('not_found_errors.RSVPTemplateService.updateTemplate.TemplateNotFound',
[
'template_id' => $template_id,
'summit_id' => $summit->getId()
]
)
);
}
return SummitRSVPTemplateFactory::populate($template, $payload);
});
}
/**
* @param Summit $summit
* @param int $template_id
@ -508,4 +593,5 @@ final class RSVPTemplateService
});
}
}

View File

@ -42,6 +42,7 @@ return [
'LocationService.deleteLocationImage.LocationNotFound' => 'location :location_id not found on summit :summit_id',
'LocationService.deleteLocationImage.ImageNotFound' => 'image :image_id not found on location :location_id',
// RSVPTemplateService
'RSVPTemplateService.updateTemplate.TemplateNotFound' => 'template :template_id not found on summit :summit_id',
'RSVPTemplateService.deleteTemplate.TemplateNotFound' => 'template :template_id not found on summit :summit_id',
'RSVPTemplateService.addQuestion.TemplateNotFound' => 'template :template_id not found on summit :summit_id',
'RSVPTemplateService.updateQuestion.TemplateNotFound' => 'template :template_id not found on summit :summit_id',

View File

@ -55,6 +55,8 @@ 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',
'RSVPTemplateService.addTemplate.TitleAlreadyExists' => 'title :title already exists on summit :summit_id',
'RSVPTemplateService.updateTemplate.TitleAlreadyExists' => 'title :title already exists on summit :summit_id',
// SummitTicketTypeService
'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',
@ -63,4 +65,6 @@ return [
'SummitTicketTypeService.seedSummitTicketTypesFromEventBrite.MissingExternalId' => 'summit :summit_is has not set external id (eventbrite)',
// PresentationCategoryGroupService
'PresentationCategoryGroupService.addTrackGroup.NameAlreadyExists' => 'name :name already exists for summit :summit_id',
];

View File

@ -82,6 +82,83 @@ final class OAuth2SummitRSVPTemplateApiTest extends ProtectedApiTest
return $rsvp_template;
}
public function testAddRSVPTemplate($summit_id = 24){
$params = [
'id' => $summit_id,
];
$title = str_random(16).'_rsvp_template_title';
$data = [
'title' => $title,
'is_enabled' => false,
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"POST",
"OAuth2SummitRSVPTemplatesApiController@addRSVPTemplate",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$template = json_decode($content);
$this->assertTrue(!is_null($template));
$this->assertTrue($template->title == $title);
return $template;
}
public function testUpdateRSVPTemplate($summit_id = 24){
$template = $this->testAddRSVPTemplate($summit_id);
$params = [
'id' => $summit_id,
'template_id' => $template->id
];
$data = [
'is_enabled' => true,
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"PUT",
"OAuth2SummitRSVPTemplatesApiController@updateRSVPTemplate",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$template = json_decode($content);
$this->assertTrue(!is_null($template));
$this->assertTrue($template->is_enabled == true);
return $template;
}
public function testDeleteRSVPTemplate($summit_id = 23){
$template = $this->testGetRSVPTemplateById($summit_id);