API: Rename rooms to locations and start/end to starts_at/ends_at

This commit is contained in:
Igor Scheller 2023-11-03 19:03:31 +01:00 committed by Michael Weimann
parent 2e38b55167
commit 497c1772f7
6 changed files with 70 additions and 68 deletions

View File

@ -121,8 +121,8 @@ $route->addGroup(
$route->get('/angeltypes', 'Api\AngelTypeController@index'); $route->get('/angeltypes', 'Api\AngelTypeController@index');
$route->get('/news', 'Api\NewsController@index'); $route->get('/news', 'Api\NewsController@index');
$route->get('/rooms', 'Api\RoomsController@index'); $route->get('/locations', 'Api\LocationsController@index');
$route->get('/rooms/{room_id:\d+}/shifts', 'Api\ShiftsController@entriesByRoom'); $route->get('/locations/{location_id:\d+}/shifts', 'Api\ShiftsController@entriesByLocation');
$route->addRoute( $route->addRoute(
['POST', 'PUT', 'DELETE', 'PATCH'], ['POST', 'PUT', 'DELETE', 'PATCH'],

View File

@ -140,7 +140,7 @@ components:
- created_at - created_at
- updated_at - updated_at
- url - url
Room: Location:
type: object type: object
properties: properties:
id: id:
@ -151,8 +151,8 @@ components:
example: Heaven example: Heaven
url: url:
type: string type: string
example: https://example.com/rooms/42 example: https://example.com/location/42
description: Link of the room start page description: Link of the location page
required: required:
- id - id
- name - name
@ -172,18 +172,18 @@ components:
description: | description: |
Shift description, should be added to the shift type description as it might be empty. Shift description, should be added to the shift type description as it might be empty.
Normally contains additional information for a specific shift / task. Normally contains additional information for a specific shift / task.
start: starts_at:
type: string type: string
format: date-time format: date-time
description: DateTime in ISO-8601 format description: DateTime in ISO-8601 format
example: 2023-05-13T14:00:00.000000Z example: 2023-05-13T14:00:00.000000Z
end: ends_at:
type: string type: string
format: date-time format: date-time
description: DateTime in ISO-8601 format description: DateTime in ISO-8601 format
example: 2023-05-13T16:00:00.000000Z23 example: 2023-05-13T16:00:00.000000Z23
room: location:
$ref: '#/components/schemas/Room' $ref: '#/components/schemas/Location'
shift_type: shift_type:
$ref: '#/components/schemas/ShiftType' $ref: '#/components/schemas/ShiftType'
created_at: created_at:
@ -211,9 +211,9 @@ components:
- id - id
- title - title
- description - description
- start - starts_at
- end - ends_at
- room - location
- shift_type - shift_type
- created_at - created_at
- updated_at - updated_at
@ -349,11 +349,11 @@ paths:
'403': '403':
$ref: '#/components/responses/ForbiddenError' $ref: '#/components/responses/ForbiddenError'
/rooms: /locations:
get: get:
tags: tags:
- shift - shift
summary: Get a list of rooms summary: Get a list of locations
responses: responses:
'200': '200':
description: Ok description: Ok
@ -365,25 +365,25 @@ paths:
data: data:
type: array type: array
items: items:
$ref: '#/components/schemas/Room' $ref: '#/components/schemas/Location'
'401': '401':
$ref: '#/components/responses/UnauthorizedError' $ref: '#/components/responses/UnauthorizedError'
'403': '403':
$ref: '#/components/responses/ForbiddenError' $ref: '#/components/responses/ForbiddenError'
/rooms/{id}/shifts: /locations/{id}/shifts:
parameters: parameters:
- name: id - name: id
in: path in: path
required: true required: true
description: The rooms identifier description: The locations identifier
example: 42 example: 42
schema: schema:
type: integer type: integer
get: get:
tags: tags:
- shift - shift
summary: Get all shifts in the requested room summary: Get all shifts in the requested location
responses: responses:
'200': '200':
description: Ok description: Ok

View File

@ -5,18 +5,18 @@ declare(strict_types=1);
namespace Engelsystem\Controllers\Api; namespace Engelsystem\Controllers\Api;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Models\Room; use Engelsystem\Models\Location;
class RoomsController extends ApiController class LocationsController extends ApiController
{ {
public function index(): Response public function index(): Response
{ {
$models = Room::query() $models = Location::query()
->orderBy('name') ->orderBy('name')
->get(['id', 'name']); ->get(['id', 'name']);
$models->map(function (Room $model): void { $models->map(function (Location $model): void {
$model->url = $this->url->to('/rooms', ['action' => 'view', 'room_id' => $model->id]); $model->url = $this->url->to('/locations', ['action' => 'view', 'location_id' => $model->id]);
}); });
$data = ['data' => $models]; $data = ['data' => $models];

View File

@ -6,23 +6,23 @@ namespace Engelsystem\Controllers\Api;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Models\Room; use Engelsystem\Models\Location;
use Engelsystem\Models\Shifts\NeededAngelType; use Engelsystem\Models\Shifts\NeededAngelType;
use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\Shift;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
class ShiftsController extends ApiController class ShiftsController extends ApiController
{ {
public function entriesByRoom(Request $request): Response public function entriesByLocation(Request $request): Response
{ {
$roomId = (int) $request->getAttribute('room_id'); $locationId = (int) $request->getAttribute('location_id');
/** @var Room $room */ /** @var Location $location */
$room = Room::findOrFail($roomId); $location = Location::findOrFail($locationId);
/** @var Shift[]|Collection $shifts */ /** @var Shift[]|Collection $shifts */
$shifts = $room->shifts() $shifts = $location->shifts()
->with([ ->with([
'neededAngelTypes.angelType', 'neededAngelTypes.angelType',
'room', 'location.neededAngelTypes.angelType',
'shiftEntries.angelType', 'shiftEntries.angelType',
'shiftEntries.user.contact', 'shiftEntries.user.contact',
'shiftEntries.user.personalData', 'shiftEntries.user.personalData',
@ -70,16 +70,16 @@ class ShiftsController extends ApiController
]; ];
} }
$roomData = $room->only(['id', 'name']); $locationData = $location->only(['id', 'name']);
$roomData['url'] = $this->url->to('/rooms', ['action' => 'view', 'room_id' => $room->id]); $locationData['url'] = $this->url->to('/locations', ['action' => 'view', 'location_id' => $location->id]);
$shiftEntries[] = [ $shiftEntries[] = [
'id' => $shift->id, 'id' => $shift->id,
'title' => $shift->title, 'title' => $shift->title,
'description' => $shift->description, 'description' => $shift->description,
'start' => $shift->start, 'starts_at' => $shift->start,
'end' => $shift->end, 'ends_at' => $shift->end,
'room' => $roomData, 'location' => $locationData,
'shift_type' => $shift->shiftType->only(['id', 'name', 'description']), 'shift_type' => $shift->shiftType->only(['id', 'name', 'description']),
'created_at' => $shift->created_at, 'created_at' => $shift->created_at,
'updated_at' => $shift->updated_at, 'updated_at' => $shift->updated_at,
@ -101,8 +101,8 @@ class ShiftsController extends ApiController
// From shift // From shift
$neededAngelTypes = $shift->neededAngelTypes; $neededAngelTypes = $shift->neededAngelTypes;
// Add from room // Add from location
foreach ($shift->room->neededAngelTypes as $neededAngelType) { foreach ($shift->location->neededAngelTypes as $neededAngelType) {
/** @var NeededAngelType $existingNeededAngelType */ /** @var NeededAngelType $existingNeededAngelType */
$existingNeededAngelType = $neededAngelTypes $existingNeededAngelType = $neededAngelTypes
->where('angel_type_id', $neededAngelType->angel_type_id) ->where('angel_type_id', $neededAngelType->angel_type_id)
@ -112,7 +112,7 @@ class ShiftsController extends ApiController
continue; continue;
} }
$existingNeededAngelType->room_id = $shift->room->id; $existingNeededAngelType->location_id = $shift->location->id;
$existingNeededAngelType->count += $neededAngelType->count; $existingNeededAngelType->count += $neededAngelType->count;
} }

View File

@ -4,24 +4,23 @@ declare(strict_types=1);
namespace Engelsystem\Test\Unit\Controllers\Api; namespace Engelsystem\Test\Unit\Controllers\Api;
use Engelsystem\Controllers\Api\RoomsController; use Engelsystem\Controllers\Api\LocationsController;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Models\Room; use Engelsystem\Models\Location;
class RoomsControllerTest extends ApiBaseControllerTest class LocationsControllerTest extends ApiBaseControllerTest
{ {
/** /**
* @covers \Engelsystem\Controllers\Api\RoomsController::index * @covers \Engelsystem\Controllers\Api\LocationsController::index
*/ */
public function testIndex(): void public function testIndex(): void
{ {
$this->initDatabase(); $items = Location::factory(3)->create();
$items = Room::factory(3)->create();
$controller = new RoomsController(new Response(), $this->url); $controller = new LocationsController(new Response(), $this->url);
$response = $controller->index(); $response = $controller->index();
$this->validateApiResponse('/rooms', 'get', $response); $this->validateApiResponse('/locations', 'get', $response);
$this->assertEquals(['application/json'], $response->getHeader('content-type')); $this->assertEquals(['application/json'], $response->getHeader('content-type'));
$this->assertJson($response->getContent()); $this->assertJson($response->getContent());

View File

@ -8,7 +8,7 @@ use Engelsystem\Controllers\Api\ShiftsController;
use Engelsystem\Helpers\Carbon; use Engelsystem\Helpers\Carbon;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Models\Room; use Engelsystem\Models\Location;
use Engelsystem\Models\Shifts\NeededAngelType; use Engelsystem\Models\Shifts\NeededAngelType;
use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\Shift;
use Engelsystem\Models\Shifts\ShiftEntry; use Engelsystem\Models\Shifts\ShiftEntry;
@ -19,55 +19,58 @@ use Engelsystem\Models\User\User;
class ShiftsControllerTest extends ApiBaseControllerTest class ShiftsControllerTest extends ApiBaseControllerTest
{ {
/** /**
* @covers \Engelsystem\Controllers\Api\ShiftsController::entriesByRoom * @covers \Engelsystem\Controllers\Api\ShiftsController::entriesByLocation
* @covers \Engelsystem\Controllers\Api\ShiftsController::getNeededAngelTypes * @covers \Engelsystem\Controllers\Api\ShiftsController::getNeededAngelTypes
*/ */
public function testEntriesByRoom(): void public function testEntriesByLocation(): void
{ {
$this->initDatabase(); $this->initDatabase();
/** @var Room $room */ /** @var Location $location */
$room = Room::factory()->create(); $location = Location::factory()->create();
// Shifts // Shifts
/** @var Shift $shiftA */ /** @var Shift $shiftA */
$shiftA = Shift::factory(1) $shiftA = Shift::factory(1)
->create(['room_id' => $room->id, 'start' => Carbon::now()->subHour()]) ->create(['location_id' => $location->id, 'start' => Carbon::now()->subHour()])
->first(); ->first();
/** @var Shift $shiftB */ /** @var Shift $shiftB */
$shiftB = Shift::factory(1) $shiftB = Shift::factory(1)
->create(['room_id' => $room->id, 'start' => Carbon::now()->addHour()]) ->create(['location_id' => $location->id, 'start' => Carbon::now()->addHour()])
->first(); ->first();
// "Empty" entry to be skipped // "Empty" entry to be skipped
NeededAngelType::factory(1)->create(['room_id' => null, 'shift_id' => $shiftA->id, 'count' => 0]); NeededAngelType::factory(1)->create(['location_id' => null, 'shift_id' => $shiftA->id, 'count' => 0]);
// Needed entry by shift // Needed entry by shift
/** @var NeededAngelType $byShift */ /** @var NeededAngelType $byShift */
$byShift = NeededAngelType::factory(2) $byShift = NeededAngelType::factory(2)
->create(['room_id' => null, 'shift_id' => $shiftA->id, 'count' => 2]) ->create(['location_id' => null, 'shift_id' => $shiftA->id, 'count' => 2])
->first(); ->first();
// Needed entry by room // Needed entry by location
/** @var NeededAngelType $byRoom */ /** @var NeededAngelType $byLocation */
$byRoom = NeededAngelType::factory(1) $byLocation = NeededAngelType::factory(1)
->create(['room_id' => $room->id, 'shift_id' => null, 'count' => 3]) ->create(['location_id' => $location->id, 'shift_id' => null, 'count' => 3])
->first(); ->first();
// Added by both // Added by both
NeededAngelType::factory(1) NeededAngelType::factory(1)
->create([ ->create([
'room_id' => $room->id, 'shift_id' => null, 'angel_type_id' => $byShift->angel_type_id, 'count' => 3, 'location_id' => $location->id,
'shift_id' => null,
'angel_type_id' => $byShift->angel_type_id,
'count' => 3,
]) ])
->first(); ->first();
// By shift // By shift
ShiftEntry::factory(2)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byShift->angel_type_id]); ShiftEntry::factory(2)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byShift->angel_type_id]);
// By room // By location
ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byRoom->angel_type_id]); ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byLocation->angel_type_id]);
// Additional (not required by shift nor room) // Additional (not required by shift nor location)
ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id]); ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id]);
foreach (User::all() as $user) { foreach (User::all() as $user) {
@ -78,12 +81,12 @@ class ShiftsControllerTest extends ApiBaseControllerTest
} }
$request = new Request(); $request = new Request();
$request = $request->withAttribute('room_id', $room->id); $request = $request->withAttribute('location_id', $location->id);
$controller = new ShiftsController(new Response(), $this->url); $controller = new ShiftsController(new Response(), $this->url);
$response = $controller->entriesByRoom($request); $response = $controller->entriesByLocation($request);
$this->validateApiResponse('/rooms/{id}/shifts', 'get', $response); $this->validateApiResponse('/locations/{id}/shifts', 'get', $response);
$this->assertEquals(['application/json'], $response->getHeader('content-type')); $this->assertEquals(['application/json'], $response->getHeader('content-type'));
$this->assertJson($response->getContent()); $this->assertJson($response->getContent());
@ -95,7 +98,7 @@ class ShiftsControllerTest extends ApiBaseControllerTest
// First shift // First shift
$shiftAData = $data['data'][0]; $shiftAData = $data['data'][0];
$this->assertEquals($shiftA->title, $shiftAData['title'], 'Title is equal'); $this->assertEquals($shiftA->title, $shiftAData['title'], 'Title is equal');
$this->assertEquals($room->id, $shiftAData['room']['id'], 'Same room'); $this->assertEquals($location->id, $shiftAData['location']['id'], 'Same location');
$this->assertEquals($shiftA->shiftType->id, $shiftAData['shift_type']['id'], 'Shift type equals'); $this->assertEquals($shiftA->shiftType->id, $shiftAData['shift_type']['id'], 'Shift type equals');
$this->assertCount(4, $shiftAData['entries']); $this->assertCount(4, $shiftAData['entries']);
// Has users // Has users
@ -112,7 +115,7 @@ class ShiftsControllerTest extends ApiBaseControllerTest
// Second (empty) shift // Second (empty) shift
$shiftBData = $data['data'][1]; $shiftBData = $data['data'][1];
$this->assertEquals($shiftB->title, $shiftBData['title'], 'Title is equal'); $this->assertEquals($shiftB->title, $shiftBData['title'], 'Title is equal');
$this->assertEquals($room->id, $shiftBData['room']['id'], 'Same room'); $this->assertEquals($location->id, $shiftBData['location']['id'], 'Same location');
$this->assertEquals($shiftB->shiftType->id, $shiftBData['shift_type']['id'], 'Shift type equals'); $this->assertEquals($shiftB->shiftType->id, $shiftBData['shift_type']['id'], 'Shift type equals');
$this->assertCount(2, $shiftBData['entries']); $this->assertCount(2, $shiftBData['entries']);
// No users // No users