From e35c0fb5d7be5e8e99d033348f65f828e8dca006 Mon Sep 17 00:00:00 2001 From: Sebastian Marcet Date: Tue, 20 Mar 2018 18:37:41 -0300 Subject: [PATCH] Added endpoints GET /api/v1/summits/{id}/rsvp-templates/{template_id}/questions/{question_id}/values/{value_id} PUT /api/v1/summits/{id}/rsvp-templates/{template_id}/questions/{question_id}/values/{value_id} Payload * label (sometimes|string) * value (sometimes|string) * order (sometimes|integer|min:1) Change-Id: I835a09644dc7c0da0ccd3f4d6ed48035af9b174f --- app/Console/Commands/SummitJsonGenerator.php | 2 +- ...OAuth2SummitRSVPTemplatesApiController.php | 99 +++++++++++++++- app/Http/routes.php | 3 +- .../Foundation/Main/OrderableChilds.php | 12 +- .../RSVPMultiValueQuestionTemplate.php | 35 +----- .../Templates/RSVPQuestionValueTemplate.php | 3 +- app/Services/Model/IRSVPTemplateService.php | 13 +++ app/Services/Model/RSVPTemplateService.php | 107 ++++++++++++++++++ tests/OAuth2SummitRSVPTemplateApiTest.php | 39 +++++++ 9 files changed, 271 insertions(+), 42 deletions(-) diff --git a/app/Console/Commands/SummitJsonGenerator.php b/app/Console/Commands/SummitJsonGenerator.php index 7ebfd375..183b9162 100644 --- a/app/Console/Commands/SummitJsonGenerator.php +++ b/app/Console/Commands/SummitJsonGenerator.php @@ -109,7 +109,7 @@ final class SummitJsonGenerator extends Command { $key_current = sprintf('/api/v1/summits/%s.expand=%s','current', urlencode($expand)); $key_id = sprintf('/api/v1/summits/%s.expand=%s', $summit->getIdentifier(), urlencode($expand)); - $cache_lifetime = intval(Config::get('cache_api_response.get_summit_response_lifetime', 300)); + $cache_lifetime = intval(Config::get('cache_api_response.get_summit_response_lifetime', 600)); if($summit->isActive()) { diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRSVPTemplatesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRSVPTemplatesApiController.php index f56c5ea7..c81899fb 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRSVPTemplatesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRSVPTemplatesApiController.php @@ -12,6 +12,7 @@ * limitations under the License. **/ use App\Http\Utils\PagingConstants; +use App\Models\Foundation\Summit\Events\RSVP\RSVPMultiValueQuestionTemplate; use App\Models\Foundation\Summit\Repositories\IRSVPTemplateRepository; use App\Services\Model\IRSVPTemplateService; use Illuminate\Support\Facades\Input; @@ -247,7 +248,6 @@ final class OAuth2SummitRSVPTemplatesApiController extends OAuth2ProtectedContro public function getRSVPTemplateQuestion($summit_id, $template_id, $question_id){ try { - $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); @@ -401,6 +401,53 @@ final class OAuth2SummitRSVPTemplatesApiController extends OAuth2ProtectedContro * values endpoints */ + /** + * @param $summit_id + * @param $template_id + * @param $question_id + * @param $value_id + * @return mixed + */ + public function getRSVPTemplateQuestionValue($summit_id, $template_id, $question_id, $value_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $template = $summit->getRSVPTemplateById($template_id); + if (is_null($template)) return $this->error404(); + + $question = $template->getQuestionById($question_id); + if (is_null($question)) return $this->error404(); + + if (!$question instanceof RSVPMultiValueQuestionTemplate) return $this->error404(); + + $value = $question->getValueById($value_id); + if (is_null($value)) return $this->error404(); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($value)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $template_id + * @param $question_id + * @return mixed + */ public function addRSVPTemplateQuestionValue($summit_id, $template_id, $question_id){ try { @@ -410,7 +457,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); + $rules = SummitRSVPTemplateQuestionValueValidationRulesFactory::build($payload, true); // Creates a Validator instance and validates the data. $validation = Validator::make($payload, $rules); @@ -441,4 +488,52 @@ final class OAuth2SummitRSVPTemplatesApiController extends OAuth2ProtectedContro return $this->error500($ex); } } + + /** + * @param $summit_id + * @param $template_id + * @param $question_id + * @param $value_id + * @return mixed + */ + public function updateRSVPTemplateQuestionValue($summit_id, $template_id, $question_id, $value_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 = SummitRSVPTemplateQuestionValueValidationRulesFactory::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 + ); + } + + $value = $this->rsvp_template_service->updateQuestionValue($summit, $template_id, $question_id, $value_id, $payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($value)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } } \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index ea913030..10d8f3cb 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -180,7 +180,8 @@ Route::group([ Route::group(['prefix' => 'values'], function () { Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@addRSVPTemplateQuestionValue']); Route::group(['prefix' => '{value_id}'], function () { - + Route::get('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@getRSVPTemplateQuestionValue']); + Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitRSVPTemplatesApiController@updateRSVPTemplateQuestionValue']); }); }); }); diff --git a/app/Models/Foundation/Main/OrderableChilds.php b/app/Models/Foundation/Main/OrderableChilds.php index 1b06bfdb..6ed946eb 100644 --- a/app/Models/Foundation/Main/OrderableChilds.php +++ b/app/Models/Foundation/Main/OrderableChilds.php @@ -11,8 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\Selectable; use models\exceptions\ValidationException; /** * Trait OrderableChilds @@ -21,12 +21,12 @@ use models\exceptions\ValidationException; trait OrderableChilds { /** - * @param ArrayCollection $collection + * @param Selectable $collection * @param IOrderable $element * @param $new_order * @throws ValidationException */ - private static function recalculateOrderFor(ArrayCollection $collection, IOrderable $element, $new_order){ + private static function recalculateOrderFor(Selectable $collection, IOrderable $element, $new_order){ $criteria = Criteria::create(); $criteria->orderBy(['order'=> 'ASC']); @@ -48,13 +48,13 @@ trait OrderableChilds $elements = array_merge ( array_slice($elements, 0, $new_order -1 , true) , - [$elements] , + [$element] , array_slice($elements, $new_order -1 , count($elements), true) ); $order = 1; - foreach($elements as $q){ - $q->setOrder($order); + foreach($elements as $e){ + $e->setOrder($order); $order++; } } diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php index 295c3715..d473767f 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPMultiValueQuestionTemplate.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Models\Foundation\Main\OrderableChilds; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\Mapping AS ORM; @@ -159,43 +160,15 @@ class RSVPMultiValueQuestionTemplate extends RSVPQuestionTemplate return $this; } + use OrderableChilds; + /** * @param RSVPQuestionValueTemplate $value * @param int $new_order * @throws ValidationException */ public function recalculateValueOrder(RSVPQuestionValueTemplate $value, $new_order){ - - $criteria = Criteria::create(); - $criteria->orderBy(['order'=> 'ASC']); - - $values = $this->values->matching($criteria)->toArray(); - $values = array_slice($values,0, count($values), false); - $max_order = count($values); - $former_order = 1; - - foreach ($values as $v){ - if($v->getId() == $value->getId()) break; - $former_order++; - } - - if($new_order > $max_order) - throw new ValidationException(sprintf("max order is %s", $max_order)); - - unset($values[$former_order - 1]); - - $values = array_merge - ( - array_slice($values, 0, $new_order -1 , true) , - [$values] , - array_slice($values, $new_order -1 , count($values), true) - ); - - $order = 1; - foreach($values as $v){ - $v->setOrder($order); - $order++; - } + self::recalculateOrderFor($this->values, $value, $new_order); } /** diff --git a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionValueTemplate.php b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionValueTemplate.php index b7f94e12..faf0d692 100644 --- a/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionValueTemplate.php +++ b/app/Models/Foundation/Summit/Events/RSVP/Templates/RSVPQuestionValueTemplate.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Models\Foundation\Main\IOrderable; use models\utils\SilverstripeBaseModel; use Doctrine\ORM\Mapping AS ORM; /** @@ -19,7 +20,7 @@ use Doctrine\ORM\Mapping AS ORM; * Class RSVPQuestionValueTemplate * @package App\Models\Foundation\Summit\Events\RSVP */ -class RSVPQuestionValueTemplate extends SilverstripeBaseModel +class RSVPQuestionValueTemplate extends SilverstripeBaseModel implements IOrderable { /** * @ORM\Column(name="Value", type="string") diff --git a/app/Services/Model/IRSVPTemplateService.php b/app/Services/Model/IRSVPTemplateService.php index 32bcb3e9..127825dc 100644 --- a/app/Services/Model/IRSVPTemplateService.php +++ b/app/Services/Model/IRSVPTemplateService.php @@ -73,4 +73,17 @@ interface IRSVPTemplateService */ public function addQuestionValue($summit, $template_id, $question_id, $payload); + + /** + * @param Summit $summit + * @param int $template_id + * @param int $question_id + * @param int $value_id + * @param array $payload + * @return RSVPQuestionValueTemplate + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateQuestionValue($summit, $template_id, $question_id, $value_id, $payload); + } \ No newline at end of file diff --git a/app/Services/Model/RSVPTemplateService.php b/app/Services/Model/RSVPTemplateService.php index 0c3ed1d6..7aac4f8b 100644 --- a/app/Services/Model/RSVPTemplateService.php +++ b/app/Services/Model/RSVPTemplateService.php @@ -321,6 +321,113 @@ final class RSVPTemplateService implements IRSVPTemplateService $question->addValue($value); + return $value; + }); + } + + /** + * @param Summit $summit + * @param int $template_id + * @param int $question_id + * @param int $value_id + * @param array $data + * @return RSVPQuestionValueTemplate + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateQuestionValue($summit, $template_id, $question_id, $value_id, $data) + { + return $this->tx_service->transaction(function() use($summit, $template_id, $question_id, $value_id, $data){ + + $template = $summit->getRSVPTemplateById($template_id); + + if(is_null($template)) + throw new EntityNotFoundException + ( + trans + ( + 'not_found_errors.RSVPTemplateService.updateQuestionValue.TemplateNotFound', + [ + 'summit_id' => $summit->getId(), + 'template_id' => $template_id, + ] + ) + ); + + $question = $template->getQuestionById($question_id); + if(is_null($question)) + throw new EntityNotFoundException + ( + trans + ( + 'not_found_errors.RSVPTemplateService.updateQuestionValue.QuestionNotFound', + [ + 'summit_id' => $summit->getId(), + 'template_id' => $template_id, + 'question_id' => $question_id, + ] + ) + ); + + if(!$question instanceof RSVPMultiValueQuestionTemplate){ + throw new EntityNotFoundException + ( + trans + ( + 'not_found_errors.RSVPTemplateService.updateQuestionValue.QuestionNotFound', + [ + 'summit_id' => $summit->getId(), + 'template_id' => $template_id, + 'question_id' => $question_id, + ] + ) + ); + } + + if(isset($data['value'])) { + $former_value = $question->getValueByValue($data['value']); + if (!is_null($former_value) && $former_value->getId() != $value_id) { + throw new ValidationException + ( + trans + ( + 'validation_errors.RSVPTemplateService.updateQuestionValue.ValueAlreadyExist', + [ + 'summit_id' => $summit->getId(), + 'template_id' => $template_id, + 'question_id' => $question_id, + 'value' => $data['value'] + ] + ) + ); + } + } + + $value = $question->getValueById($value_id); + if(is_null($value)) + throw new EntityNotFoundException + ( + trans + ( + 'not_found_errors.RSVPTemplateService.updateQuestionValue.ValueNotFound', + [ + 'summit_id' => $summit->getId(), + 'template_id' => $template_id, + 'question_id' => $question_id, + 'value_id' => $value_id, + ] + ) + ); + + $value = SummitRSVPTemplateQuestionValueFactory::populate($value, $data); + + + if (isset($data['order']) && intval($data['order']) != $value->getOrder()) { + // request to update order + $question->recalculateValueOrder($value, intval($data['order'])); + } + + return $value; }); } diff --git a/tests/OAuth2SummitRSVPTemplateApiTest.php b/tests/OAuth2SummitRSVPTemplateApiTest.php index 11636099..cbb1f313 100644 --- a/tests/OAuth2SummitRSVPTemplateApiTest.php +++ b/tests/OAuth2SummitRSVPTemplateApiTest.php @@ -308,4 +308,43 @@ final class OAuth2SummitRSVPTemplateApiTest extends ProtectedApiTest $this->assertTrue(!is_null($value)); return $value; } + + public function testUpdateRSVPQuestionValue($summit_id = 24, $template_id = 13, $question_id = 86){ + + $value = $this->testAddRSVPQuestionValue($summit_id, $template_id, $question_id); + + $params = [ + 'id' => $summit_id, + 'template_id' => $template_id, + 'question_id' => $question_id, + 'value_id' => $value->id + ]; + + $data = [ + 'order' => 3 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitRSVPTemplatesApiController@updateRSVPTemplateQuestionValue", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $value = json_decode($content); + $this->assertTrue(!is_null($value)); + $this->assertTrue($value->order == 3); + return $value; + } } \ No newline at end of file