* fixed bugs

* added filter owner_name and owner_email to get reservations endpoint
* added endpoint get reservation per id

GET /api/v1/summits/all/locations/bookable-rooms/all/reservations/{id}

* added endpoint get all reservations by summit CSV

GET /api/v1/summits/{id}/locations/bookable-rooms/all/reservations/csv

Change-Id: I44f658998f4b81c5d6b5d568eb0e2f2fef2b04a9
This commit is contained in:
smarcet 2019-06-26 12:28:42 -03:00
parent fe546f4702
commit 694135c214
7 changed files with 332 additions and 65 deletions

View File

@ -11,6 +11,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Http\Utils\BooleanCellFormatter;
use App\Http\Utils\EpochCellFormatter;
use App\Http\Utils\PagingConstants;
use Exception;
use Illuminate\Support\Facades\Input;
@ -37,6 +40,41 @@ use Illuminate\Http\Request as LaravelRequest;
*/
trait SummitBookableVenueRoomApi
{
/**
* @param $id
* @return mixed
*/
public function getReservationById($id){
try {
$expand = Request::input('expand', '');
$relations = Request::input('relations', '');
$relations = !empty($relations) ? explode(',', $relations) : [];
$reservation = $this->reservation_repository->getById($id);
if (is_null($reservation)) {
return $this->error404();
}
return $this->ok(SerializerRegistry::getInstance()->getSerializer($reservation)->serialize($expand,[], $relations));
}
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
* @return \Illuminate\Http\JsonResponse|mixed
@ -178,6 +216,8 @@ trait SummitBookableVenueRoomApi
'room_name' => ['==', '=@'],
'room_id' => ['=='],
'owner_id' => ['=='],
'owner_name' => ['==', '=@'],
'owner_email' => ['==', '=@'],
'status' => ['=='],
'start_datetime' => ['>', '<', '<=', '>=', '=='],
'end_datetime' => ['>', '<', '<=', '>=', '=='],
@ -188,6 +228,8 @@ trait SummitBookableVenueRoomApi
$filter->validate([
'status' => sprintf('sometimes|in:%s',implode(',', SummitRoomReservation::$valid_status)),
'room_name' => 'sometimes|string',
'owner_name' => 'sometimes|string',
'owner_email' => 'sometimes|string',
'summit_id' => 'sometimes|integer',
'room_id' => 'sometimes|integer',
'owner_id' => 'sometimes|string',
@ -247,6 +289,108 @@ trait SummitBookableVenueRoomApi
return $this->error500($ex);
}
}
/**
* @param $summit_id
* @return mixed
*/
public function getAllReservationsBySummitCSV($summit_id){
try {
$summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
// default values
$page = 1;
$per_page = PHP_INT_MAX;
$filter = null;
if (Input::has('filter')) {
$filter = FilterParser::parse(Input::get('filter'), [
'summit_id' => ['=='],
'room_name' => ['==', '=@'],
'room_id' => ['=='],
'owner_id' => ['=='],
'owner_name' => ['==', '=@'],
'owner_email' => ['==', '=@'],
'status' => ['=='],
'start_datetime' => ['>', '<', '<=', '>=', '=='],
'end_datetime' => ['>', '<', '<=', '>=', '=='],
]);
}
if(is_null($filter)) $filter = new Filter();
$filter->validate([
'status' => sprintf('sometimes|in:%s',implode(',', SummitRoomReservation::$valid_status)),
'room_name' => 'sometimes|string',
'owner_name' => 'sometimes|string',
'owner_email' => 'sometimes|string',
'summit_id' => 'sometimes|integer',
'room_id' => 'sometimes|integer',
'owner_id' => 'sometimes|string',
'start_datetime' => 'sometimes|required|date_format:U',
'end_datetime' => 'sometimes|required_with:start_datetime|date_format:U|after:start_datetime',
], [
'status.in' => sprintf
(
":attribute has an invalid value ( valid values are %s )",
implode(", ", SummitRoomReservation::$valid_status)
)
]);
$order = null;
if (Input::has('order'))
{
$order = OrderParser::parse(Input::get('order'), [
'id',
'start_datetime',
'end_datetime',
]);
}
$data = $this->reservation_repository->getAllBySummitByPage($summit, new PagingInfo($page, $per_page), $filter, $order);
$filename = "bookable-rooms-reservations-" . date('Ymd');
$list = $data->toArray();
return $this->export
(
'csv',
$filename,
$list['data'],
[
'created' => new EpochCellFormatter,
'last_edited' => new EpochCellFormatter,
'start_datetime' => new EpochCellFormatter,
'end_datetime' => new EpochCellFormatter,
]
);
}
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
* @param $venue_id

View File

@ -94,6 +94,11 @@ Route::group([
Route::group(['prefix' => 'selection-plans'], function () {
Route::get('current/{status}', ['uses' => 'OAuth2SummitSelectionPlansApiController@getCurrentSelectionPlanByStatus'])->where('status', 'submission|selection|voting');
});
Route::group(['prefix' => 'locations'], function () {
// GET /api/v1/summits/all/locations/bookable-rooms/all/reservations/{id}
Route::get('bookable-rooms/all/reservations/{id}', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@getReservationById']);
});
});
Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitApiController@addSummit']);
@ -326,6 +331,8 @@ Route::group([
Route::group(['prefix' => 'reservations'], function () {
// GET /api/v1/summits/{id}/locations/bookable-rooms/all/reservations
Route::get('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@getAllReservationsBySummit']);
// GET /api/v1/summits/{id}/locations/bookable-rooms/all/reservations/csv
Route::get('csv', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitLocationsApiController@getAllReservationsBySummitCSV']);
// GET /api/v1/summits/{id}/locations/bookable-rooms/all/reservations/me
Route::get('me', 'OAuth2SummitLocationsApiController@getMyBookableVenueRoomReservations');
Route::group(['prefix' => '{reservation_id}'], function () {
@ -495,7 +502,7 @@ Route::group([
Route::group(['prefix' => '{value_id}'], function () {
Route::get('', 'OAuth2SummitBookableRoomsAttributeTypeApiController@getBookableRoomAttributeValue');
Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitBookableRoomsAttributeTypeApiController@updateBookableRoomAttributeValue']);
Route::delete('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitBookableRoomsAttributeTypeApiController@udeleteBookableRoomAttributeValue']);
Route::delete('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitBookableRoomsAttributeTypeApiController@deleteBookableRoomAttributeValue']);
});
});
});

View File

@ -27,7 +27,7 @@ final class BookableRoomReservationCanceledEmail extends AbstractBookableRoomRes
{
$subject = Config::get("mail.bookable_room_reservation_canceled_email_subject");
if(empty($subject))
$subject = sprintf("[%s] Your Reservation had canceled", Config::get('app.app_name'));
$subject = sprintf("[%s] Your Room Reservation had been canceled", Config::get('app.app_name'));
return $this->from(Config::get("mail.from"))
->to($this->reservation->getOwner()->getEmail())

View File

@ -21,17 +21,16 @@ use ModelSerializers\SilverStripeSerializer;
final class SummitRoomReservationSerializer extends SilverStripeSerializer
{
protected static $array_mappings = [
'RoomId' => 'room_id:json_int',
'OwnerId' => 'owner_id:json_int',
'Amount' => 'amount:json_int',
'Currency' => 'currency:json_string',
'Status' => 'status:json_string',
'StartDatetime' => 'start_datetime:datetime_epoch',
'EndDatetime' => 'end_datetime:datetime_epoch',
'LocalStartDatetime' => 'local_start_datetime:datetime_epoch',
'LocalEndDatetime' => 'local_end_datetime:datetime_epoch',
'ApprovedPaymentDate' => 'approved_payment_date:datetime_epoch',
'LastError' => 'last_error:json_string',
'RoomId' => 'room_id:json_int',
'OwnerId' => 'owner_id:json_int',
'Amount' => 'amount:json_int',
'RefundedAmount' => 'refunded_amount:json_int',
'Currency' => 'currency:json_string',
'Status' => 'status:json_string',
'StartDatetime' => 'start_datetime:datetime_epoch',
'EndDatetime' => 'end_datetime:datetime_epoch',
'ApprovedPaymentDate' => 'approved_payment_date:datetime_epoch',
'LastError' => 'last_error:json_string',
'PaymentGatewayClientToken' => 'payment_gateway_client_token:json_string'
];

View File

@ -22,7 +22,6 @@ use utils\Filter;
use utils\Order;
use utils\PagingInfo;
use utils\PagingResponse;
/**
* Class DoctrineSummitRoomReservationRepository
* @package App\Repositories\Summit
@ -68,6 +67,18 @@ class DoctrineSummitRoomReservationRepository
'o',
"o.id :operator :value"
),
'owner_name' => new DoctrineJoinFilterMapping
(
'e.owner',
'o',
"LOWER(CONCAT(o.first_name, ' ', o.last_name)) :operator ':value'"
),
'owner_email' => new DoctrineJoinFilterMapping
(
'e.owner',
'o',
"o.email :operator :value"
),
];
}

View File

@ -38,38 +38,6 @@ class ApiEndpointsSeeder extends Seeder
$this->seedTrackQuestionTemplateEndpoints();
}
/**
* @param string $api_name
* @param array $endpoints_info
*/
private function seedApiEndpoints($api_name, array $endpoints_info){
$api = EntityManager::getRepository(\App\Models\ResourceServer\Api::class)->findOneBy(['name' => $api_name]);
if(is_null($api)) return;
foreach($endpoints_info as $endpoint_info){
$endpoint = new ApiEndpoint();
$endpoint->setName($endpoint_info['name']);
$endpoint->setRoute($endpoint_info['route']);
$endpoint->setHttpMethod($endpoint_info['http_method']);
$endpoint->setActive(true);
$endpoint->setAllowCors(true);
$endpoint->setAllowCredentials(true);
$endpoint->setApi($api);
foreach($endpoint_info['scopes'] as $scope_name){
$scope = EntityManager::getRepository(\App\Models\ResourceServer\ApiScope::class)->findOneBy(['name' => $scope_name]);
if(is_null($scope)) continue;
$endpoint->addScope($scope);
}
EntityManager::persist($endpoint);
}
EntityManager::flush();
}
private function seedSummitEndpoints()
{
$current_realm = Config::get('app.scope_base_realm');
@ -1180,6 +1148,15 @@ class ApiEndpointsSeeder extends Seeder
sprintf(SummitScopes::ReadMyBookableRoomsReservationData, $current_realm),
],
],
[
'name' => 'get-bookable-venue-room-reservations-by-id',
'route' => '/api/v1/summits/all/locations/bookable-rooms/all/reservations/{id}',
'http_method' => 'GET',
'scopes' => [
sprintf(SummitScopes::ReadBookableRoomsData, $current_realm),
sprintf(SummitScopes::ReadAllSummitData, $current_realm)
],
],
[
'name' => 'cancel-my-bookable-venue-room-reservation',
'route' => '/api/v1/summits/{id}/locations/bookable-rooms/all/reservations/{reservation_id}',
@ -1206,6 +1183,15 @@ class ApiEndpointsSeeder extends Seeder
sprintf(SummitScopes::ReadSummitData, $current_realm),
],
],
[
'name' => 'get-bookable-venue-room-reservations-by-summit-csv',
'route' => '/api/v1/summits/{id}/locations/bookable-rooms/all/reservations/csv',
'http_method' => 'GET',
'scopes' => [
sprintf(SummitScopes::ReadAllSummitData, $current_realm),
sprintf(SummitScopes::ReadSummitData, $current_realm),
],
],
[
'name' => 'get-bookable-venue-room-reservation',
'route' => '/api/v1/summits/{id}/locations/bookable-rooms/{room_id}/reservations/{reservation_id}',
@ -2313,6 +2299,38 @@ class ApiEndpointsSeeder extends Seeder
]);
}
/**
* @param string $api_name
* @param array $endpoints_info
*/
private function seedApiEndpoints($api_name, array $endpoints_info){
$api = EntityManager::getRepository(\App\Models\ResourceServer\Api::class)->findOneBy(['name' => $api_name]);
if(is_null($api)) return;
foreach($endpoints_info as $endpoint_info){
$endpoint = new ApiEndpoint();
$endpoint->setName($endpoint_info['name']);
$endpoint->setRoute($endpoint_info['route']);
$endpoint->setHttpMethod($endpoint_info['http_method']);
$endpoint->setActive(true);
$endpoint->setAllowCors(true);
$endpoint->setAllowCredentials(true);
$endpoint->setApi($api);
foreach($endpoint_info['scopes'] as $scope_name){
$scope = EntityManager::getRepository(\App\Models\ResourceServer\ApiScope::class)->findOneBy(['name' => $scope_name]);
if(is_null($scope)) continue;
$endpoint->addScope($scope);
}
EntityManager::persist($endpoint);
}
EntityManager::flush();
}
private function seedMemberEndpoints(){
$current_realm = Config::get('app.scope_base_realm');
@ -2451,6 +2469,25 @@ class ApiEndpointsSeeder extends Seeder
);
}
private function seedGroupsEndpoints(){
$current_realm = Config::get('app.scope_base_realm');
$this->seedApiEndpoints('groups', [
// members
[
'name' => 'get-groups',
'route' => '/api/v1/groups',
'http_method' => 'GET',
'scopes' => [
sprintf(SummitScopes::ReadAllSummitData, $current_realm),
sprintf(SummitScopes::ReadSummitData, $current_realm),
sprintf('%s/groups/read', $current_realm)
],
]
]
);
}
private function seedOrganizationsEndpoints(){
$current_realm = Config::get('app.scope_base_realm');
@ -2481,25 +2518,6 @@ class ApiEndpointsSeeder extends Seeder
);
}
private function seedGroupsEndpoints(){
$current_realm = Config::get('app.scope_base_realm');
$this->seedApiEndpoints('groups', [
// members
[
'name' => 'get-groups',
'route' => '/api/v1/groups',
'http_method' => 'GET',
'scopes' => [
sprintf(SummitScopes::ReadAllSummitData, $current_realm),
sprintf(SummitScopes::ReadSummitData, $current_realm),
sprintf('%s/groups/read', $current_realm)
],
]
]
);
}
public function seedTrackQuestionTemplateEndpoints(){
$current_realm = Config::get('app.scope_base_realm');

View File

@ -1708,4 +1708,92 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest
$reservations = json_decode($content);
$this->assertTrue(!is_null($reservations));
}
public function testGetAllReservationsBySummitAndOwnerName($summit_id =27){
$params = [
'id' => $summit_id,
'filter' => 'status==Canceled,owner_name=@Sebastian'
];
$headers =
[
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action
(
"GET",
"OAuth2SummitLocationsApiController@getAllReservationsBySummit",
$params,
[],
[],
[],
$headers
);
$content = $response->getContent();
$this->assertResponseStatus(200);
$reservations = json_decode($content);
$this->assertTrue(!is_null($reservations));
}
public function testGetAllReservationsBySummitAndOwnerNameCSV($summit_id =27){
$params = [
'id' => $summit_id,
'filter' => 'status==Canceled,owner_name=@Sebastian'
];
$headers =
[
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action
(
"GET",
"OAuth2SummitLocationsApiController@getAllReservationsBySummitCSV",
$params,
[],
[],
[],
$headers
);
$csv = $response->getContent();
$this->assertResponseStatus(200);
$this->assertTrue(!empty($csv));
}
public function testGetReservationById($id = 2){
$params = [
'id' => $id,
'filter' => 'status==Canceled,owner_name=@Sebastian'
];
$headers =
[
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action
(
"GET",
"OAuth2SummitLocationsApiController@getReservationById",
$params,
[],
[],
[],
$headers
);
$content = $response->getContent();
$this->assertResponseStatus(200);
$reservation = json_decode($content);
$this->assertTrue(!is_null($reservation));
}
}