API: Added user info and shifts by user and angeltype, simplified neededAngelTypes
This commit is contained in:
parent
4de882ef85
commit
02f998fc38
|
@ -123,10 +123,16 @@ $route->addGroup(
|
||||||
$route->get('/openapi', 'Api\IndexController@openApiV0');
|
$route->get('/openapi', 'Api\IndexController@openApiV0');
|
||||||
|
|
||||||
$route->get('/angeltypes', 'Api\AngelTypeController@index');
|
$route->get('/angeltypes', 'Api\AngelTypeController@index');
|
||||||
$route->get('/news', 'Api\NewsController@index');
|
$route->get('/angeltypes/{angeltype_id:\d+}/shifts', 'Api\ShiftsController@entriesByAngeltype');
|
||||||
|
|
||||||
$route->get('/locations', 'Api\LocationsController@index');
|
$route->get('/locations', 'Api\LocationsController@index');
|
||||||
$route->get('/locations/{location_id:\d+}/shifts', 'Api\ShiftsController@entriesByLocation');
|
$route->get('/locations/{location_id:\d+}/shifts', 'Api\ShiftsController@entriesByLocation');
|
||||||
|
|
||||||
|
$route->get('/news', 'Api\NewsController@index');
|
||||||
|
|
||||||
|
$route->get('/users/self', 'Api\UsersController@self');
|
||||||
$route->get('/users/{user_id:\d+}/angeltypes', 'Api\AngelTypeController@ofUser');
|
$route->get('/users/{user_id:\d+}/angeltypes', 'Api\AngelTypeController@ofUser');
|
||||||
|
$route->get('/users/{user_id:\d+}/shifts', 'Api\ShiftsController@entriesByUser');
|
||||||
|
|
||||||
$route->addRoute(
|
$route->addRoute(
|
||||||
['POST', 'PUT', 'DELETE', 'PATCH'],
|
['POST', 'PUT', 'DELETE', 'PATCH'],
|
||||||
|
|
|
@ -21,10 +21,14 @@ servers:
|
||||||
description: Your local dev instance
|
description: Your local dev instance
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
|
- name: angeltype
|
||||||
|
description: Angeltypes
|
||||||
|
- name: location
|
||||||
|
description: Event locations
|
||||||
- name: news
|
- name: news
|
||||||
description: News and meeting announcements
|
description: News and meeting announcements
|
||||||
- name: shift
|
- name: shift
|
||||||
description: Event shifts and location
|
description: Event shifts
|
||||||
- name: user
|
- name: user
|
||||||
description: User information
|
description: User information
|
||||||
|
|
||||||
|
@ -321,6 +325,55 @@ components:
|
||||||
- pronoun
|
- pronoun
|
||||||
- contact
|
- contact
|
||||||
- url
|
- url
|
||||||
|
UserDetail:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/components/schemas/User'
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
example: user@example.com
|
||||||
|
tshirt:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
example: XL
|
||||||
|
dates:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
planned_arrival:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
format: date-time
|
||||||
|
description: DateTime in ISO-8601 format
|
||||||
|
example: 2023-05-13T00:00:00.000000Z
|
||||||
|
planned_departure:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
format: date-time
|
||||||
|
description: DateTime in ISO-8601 format
|
||||||
|
example: 2023-05-23T00:00:00.000000Z
|
||||||
|
arrival:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
format: date-time
|
||||||
|
description: Actual arrival date, DateTime in ISO-8601 format
|
||||||
|
example: 2023-05-23T13:37:42.000000Z
|
||||||
|
required:
|
||||||
|
- planned_arrival
|
||||||
|
- planned_departure
|
||||||
|
- arrival
|
||||||
|
language:
|
||||||
|
type: string
|
||||||
|
example: en_US
|
||||||
|
arrived:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
required:
|
||||||
|
- email
|
||||||
|
- tshirt
|
||||||
|
- dates
|
||||||
|
- language
|
||||||
|
- arrived
|
||||||
|
|
||||||
security:
|
security:
|
||||||
- bearerAuth: [ ]
|
- bearerAuth: [ ]
|
||||||
|
@ -329,7 +382,7 @@ paths:
|
||||||
/angeltypes:
|
/angeltypes:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- shift
|
- angeltype
|
||||||
summary: Get a list of angeltypes
|
summary: Get a list of angeltypes
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
|
@ -348,6 +401,33 @@ paths:
|
||||||
'403':
|
'403':
|
||||||
$ref: '#/components/responses/ForbiddenError'
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
|
||||||
|
/angeltypes/{id}/shifts:
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The angeltype identifier
|
||||||
|
example: 42
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- angeltype
|
||||||
|
- shift
|
||||||
|
summary: Get all shifts of the requested angeltype
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Shift'
|
||||||
|
|
||||||
/news:
|
/news:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
@ -373,7 +453,7 @@ paths:
|
||||||
/locations:
|
/locations:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- shift
|
- location
|
||||||
summary: Get a list of locations
|
summary: Get a list of locations
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
|
@ -403,6 +483,7 @@ paths:
|
||||||
type: integer
|
type: integer
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
- location
|
||||||
- shift
|
- shift
|
||||||
summary: Get all shifts in the requested location
|
summary: Get all shifts in the requested location
|
||||||
responses:
|
responses:
|
||||||
|
@ -424,6 +505,28 @@ paths:
|
||||||
'404':
|
'404':
|
||||||
$ref: '#/components/responses/NotFoundError'
|
$ref: '#/components/responses/NotFoundError'
|
||||||
|
|
||||||
|
/users/self:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
summary: Get the requesting users information
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
$ref: '#/components/schemas/UserDetail'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/NotFoundError'
|
||||||
|
|
||||||
/users/{id}/angeltypes:
|
/users/{id}/angeltypes:
|
||||||
parameters:
|
parameters:
|
||||||
- name: id
|
- name: id
|
||||||
|
@ -435,6 +538,7 @@ paths:
|
||||||
type: integer
|
type: integer
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
- angeltype
|
||||||
- user
|
- user
|
||||||
summary: Get the users angel types
|
summary: Get the users angel types
|
||||||
responses:
|
responses:
|
||||||
|
@ -456,6 +560,39 @@ paths:
|
||||||
'404':
|
'404':
|
||||||
$ref: '#/components/responses/NotFoundError'
|
$ref: '#/components/responses/NotFoundError'
|
||||||
|
|
||||||
|
/users/{id}/shifts:
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The user identifier
|
||||||
|
example: 42
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- shift
|
||||||
|
- user
|
||||||
|
summary: Get all shifts of the requested user
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Shift'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/NotFoundError'
|
||||||
|
|
||||||
/openapi:
|
/openapi:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Controllers\Api\Resources;
|
||||||
|
|
||||||
|
class UserDetailResource extends UserResource
|
||||||
|
{
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return array_merge(parent::toArray(), [
|
||||||
|
'email' => $this->model->contact->email ?: $this->model->email,
|
||||||
|
'tshirt' => $this->model->personalData->shirt_size,
|
||||||
|
'language' => $this->model->settings->language,
|
||||||
|
'arrived' => $this->model->state->arrived,
|
||||||
|
'dates' => [
|
||||||
|
'planned_arrival' => $this->model->personalData->planned_arrival_date,
|
||||||
|
'planned_departure' => $this->model->personalData->planned_departure_date,
|
||||||
|
'arrival' => $this->model->state->arrival_date,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,13 +10,44 @@ use Engelsystem\Controllers\Api\Resources\ShiftWithEntriesResource;
|
||||||
use Engelsystem\Controllers\Api\Resources\UserResource;
|
use Engelsystem\Controllers\Api\Resources\UserResource;
|
||||||
use Engelsystem\Http\Request;
|
use Engelsystem\Http\Request;
|
||||||
use Engelsystem\Http\Response;
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Models\AngelType;
|
||||||
use Engelsystem\Models\Location;
|
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\User\User;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
class ShiftsController extends ApiController
|
class ShiftsController extends ApiController
|
||||||
{
|
{
|
||||||
|
public function entriesByAngeltype(Request $request): Response
|
||||||
|
{
|
||||||
|
$id = (int) $request->getAttribute('angeltype_id');
|
||||||
|
/** @var AngelType $angeltype */
|
||||||
|
$angeltype = AngelType::findOrFail($id);
|
||||||
|
/** @var ShiftEntry[]|Collection $shifts */
|
||||||
|
$shiftEntries = $angeltype->shiftEntries()
|
||||||
|
->with([
|
||||||
|
'shift.neededAngelTypes.angelType',
|
||||||
|
'shift.location.neededAngelTypes.angelType',
|
||||||
|
'shift.shiftEntries.angelType',
|
||||||
|
'shift.shiftEntries.user.contact',
|
||||||
|
'shift.shiftEntries.user.personalData',
|
||||||
|
'shift.shiftType',
|
||||||
|
'shift.schedule',
|
||||||
|
])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
/** @var Shift[]|Collection $shifts */
|
||||||
|
$shifts = Collection::make(
|
||||||
|
$shiftEntries
|
||||||
|
->pluck('shift')
|
||||||
|
->sortBy('start')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->shiftEntriesResponse($shifts);
|
||||||
|
}
|
||||||
|
|
||||||
public function entriesByLocation(Request $request): Response
|
public function entriesByLocation(Request $request): Response
|
||||||
{
|
{
|
||||||
$locationId = (int) $request->getAttribute('location_id');
|
$locationId = (int) $request->getAttribute('location_id');
|
||||||
|
@ -31,10 +62,45 @@ class ShiftsController extends ApiController
|
||||||
'shiftEntries.user.contact',
|
'shiftEntries.user.contact',
|
||||||
'shiftEntries.user.personalData',
|
'shiftEntries.user.personalData',
|
||||||
'shiftType',
|
'shiftType',
|
||||||
|
'schedule',
|
||||||
])
|
])
|
||||||
->orderBy('start')
|
->orderBy('start')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
return $this->shiftEntriesResponse($shifts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function entriesByUser(Request $request): Response
|
||||||
|
{
|
||||||
|
$id = (int) $request->getAttribute('user_id');
|
||||||
|
/** @var User $user */
|
||||||
|
$user = User::findOrFail($id);
|
||||||
|
/** @var ShiftEntry[]|Collection $shifts */
|
||||||
|
$shiftEntries = $user->shiftEntries()
|
||||||
|
->with([
|
||||||
|
'shift.neededAngelTypes.angelType',
|
||||||
|
'shift.location.neededAngelTypes.angelType',
|
||||||
|
'shift.shiftEntries.angelType',
|
||||||
|
'shift.shiftEntries.user.contact',
|
||||||
|
'shift.shiftEntries.user.personalData',
|
||||||
|
'shift.shiftType',
|
||||||
|
'shift.schedule',
|
||||||
|
])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
/** @var Shift[]|Collection $shifts */
|
||||||
|
$shifts = Collection::make(
|
||||||
|
$shiftEntries
|
||||||
|
->pluck('shift')
|
||||||
|
->sortBy('start')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->shiftEntriesResponse($shifts);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function shiftEntriesResponse(Collection $shifts): Response
|
||||||
|
{
|
||||||
|
/** @var Collection|Shift[] $shifts */
|
||||||
$shiftEntries = [];
|
$shiftEntries = [];
|
||||||
// Blob of not-optimized mediocre pseudo-serialization
|
// Blob of not-optimized mediocre pseudo-serialization
|
||||||
foreach ($shifts as $shift) {
|
foreach ($shifts as $shift) {
|
||||||
|
@ -58,7 +124,7 @@ class ShiftsController extends ApiController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$locationData = new LocationResource($location);
|
$locationData = new LocationResource($shift->location);
|
||||||
$shiftEntries[] = (new ShiftWithEntriesResource($shift))->toArray($locationData, $entries);
|
$shiftEntries[] = (new ShiftWithEntriesResource($shift))->toArray($locationData, $entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,22 +138,12 @@ class ShiftsController extends ApiController
|
||||||
*/
|
*/
|
||||||
protected function getNeededAngelTypes(Shift $shift): Collection
|
protected function getNeededAngelTypes(Shift $shift): Collection
|
||||||
{
|
{
|
||||||
// From shift
|
if (!$shift->schedule) {
|
||||||
|
// Get from shift
|
||||||
$neededAngelTypes = $shift->neededAngelTypes;
|
$neededAngelTypes = $shift->neededAngelTypes;
|
||||||
|
} else {
|
||||||
// Add from location
|
// Load instead from location
|
||||||
foreach ($shift->location->neededAngelTypes as $neededAngelType) {
|
$neededAngelTypes = $shift->location->neededAngelTypes;
|
||||||
/** @var NeededAngelType $existingNeededAngelType */
|
|
||||||
$existingNeededAngelType = $neededAngelTypes
|
|
||||||
->where('angel_type_id', $neededAngelType->angel_type_id)
|
|
||||||
->first();
|
|
||||||
if (!$existingNeededAngelType) {
|
|
||||||
$neededAngelTypes[] = clone $neededAngelType;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$existingNeededAngelType->location_id = $shift->location->id;
|
|
||||||
$existingNeededAngelType->count += $neededAngelType->count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add needed angeltypes from additionally added users
|
// Add needed angeltypes from additionally added users
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Controllers\Api;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\Api\Resources\UserDetailResource;
|
||||||
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
|
||||||
|
class UsersController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(Response $response, protected Authenticator $auth)
|
||||||
|
{
|
||||||
|
parent::__construct($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function self(): Response
|
||||||
|
{
|
||||||
|
$user = $this->auth->user();
|
||||||
|
|
||||||
|
$data = ['data' => (new UserDetailResource($user))->toArray()];
|
||||||
|
return $this->response
|
||||||
|
->withContent(json_encode($data));
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ use Engelsystem\Http\Request;
|
||||||
use Engelsystem\Http\Response;
|
use Engelsystem\Http\Response;
|
||||||
use Engelsystem\Models\Location;
|
use Engelsystem\Models\Location;
|
||||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||||
|
use Engelsystem\Models\Shifts\Schedule;
|
||||||
|
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||||
use Engelsystem\Models\Shifts\Shift;
|
use Engelsystem\Models\Shifts\Shift;
|
||||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||||
use Engelsystem\Models\User\Contact;
|
use Engelsystem\Models\User\Contact;
|
||||||
|
@ -18,8 +20,13 @@ use Engelsystem\Models\User\User;
|
||||||
|
|
||||||
class ShiftsControllerTest extends ApiBaseControllerTest
|
class ShiftsControllerTest extends ApiBaseControllerTest
|
||||||
{
|
{
|
||||||
|
protected Location $location;
|
||||||
|
protected Shift $shiftA;
|
||||||
|
protected Shift $shiftB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \Engelsystem\Controllers\Api\ShiftsController::entriesByLocation
|
* @covers \Engelsystem\Controllers\Api\ShiftsController::entriesByLocation
|
||||||
|
* @covers \Engelsystem\Controllers\Api\ShiftsController::shiftEntriesResponse
|
||||||
* @covers \Engelsystem\Controllers\Api\Resources\ShiftResource::toArray
|
* @covers \Engelsystem\Controllers\Api\Resources\ShiftResource::toArray
|
||||||
* @covers \Engelsystem\Controllers\Api\Resources\ShiftTypeResource::toArray
|
* @covers \Engelsystem\Controllers\Api\Resources\ShiftTypeResource::toArray
|
||||||
* @covers \Engelsystem\Controllers\Api\Resources\ShiftWithEntriesResource::toArray
|
* @covers \Engelsystem\Controllers\Api\Resources\ShiftWithEntriesResource::toArray
|
||||||
|
@ -29,64 +36,8 @@ class ShiftsControllerTest extends ApiBaseControllerTest
|
||||||
*/
|
*/
|
||||||
public function testEntriesByLocation(): void
|
public function testEntriesByLocation(): void
|
||||||
{
|
{
|
||||||
$this->initDatabase();
|
|
||||||
|
|
||||||
/** @var Location $location */
|
|
||||||
$location = Location::factory()->create();
|
|
||||||
|
|
||||||
// Shifts
|
|
||||||
/** @var Shift $shiftA */
|
|
||||||
$shiftA = Shift::factory(1)
|
|
||||||
->create(['location_id' => $location->id, 'start' => Carbon::now()->subHour()])
|
|
||||||
->first();
|
|
||||||
/** @var Shift $shiftB */
|
|
||||||
$shiftB = Shift::factory(1)
|
|
||||||
->create(['location_id' => $location->id, 'start' => Carbon::now()->addHour()])
|
|
||||||
->first();
|
|
||||||
|
|
||||||
// "Empty" entry to be skipped
|
|
||||||
NeededAngelType::factory(1)->create(['location_id' => null, 'shift_id' => $shiftA->id, 'count' => 0]);
|
|
||||||
|
|
||||||
// Needed entry by shift
|
|
||||||
/** @var NeededAngelType $byShift */
|
|
||||||
$byShift = NeededAngelType::factory(2)
|
|
||||||
->create(['location_id' => null, 'shift_id' => $shiftA->id, 'count' => 2])
|
|
||||||
->first();
|
|
||||||
|
|
||||||
// Needed entry by location
|
|
||||||
/** @var NeededAngelType $byLocation */
|
|
||||||
$byLocation = NeededAngelType::factory(1)
|
|
||||||
->create(['location_id' => $location->id, 'shift_id' => null, 'count' => 3])
|
|
||||||
->first();
|
|
||||||
|
|
||||||
// Added by both
|
|
||||||
NeededAngelType::factory(1)
|
|
||||||
->create([
|
|
||||||
'location_id' => $location->id,
|
|
||||||
'shift_id' => null,
|
|
||||||
'angel_type_id' => $byShift->angel_type_id,
|
|
||||||
'count' => 3,
|
|
||||||
])
|
|
||||||
->first();
|
|
||||||
|
|
||||||
// By shift
|
|
||||||
ShiftEntry::factory(2)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byShift->angel_type_id]);
|
|
||||||
|
|
||||||
// By location
|
|
||||||
ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byLocation->angel_type_id]);
|
|
||||||
|
|
||||||
// Additional (not required by shift nor location)
|
|
||||||
ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id]);
|
|
||||||
|
|
||||||
foreach (User::all() as $user) {
|
|
||||||
// Generate user data
|
|
||||||
/** @var User $user */
|
|
||||||
PersonalData::factory()->create(['user_id' => $user->id]);
|
|
||||||
Contact::factory()->create(['user_id' => $user->id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = new Request();
|
$request = new Request();
|
||||||
$request = $request->withAttribute('location_id', $location->id);
|
$request = $request->withAttribute('location_id', $this->location->id);
|
||||||
|
|
||||||
$controller = new ShiftsController(new Response());
|
$controller = new ShiftsController(new Response());
|
||||||
|
|
||||||
|
@ -102,15 +53,15 @@ 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($this->shiftA->title, $shiftAData['title'], 'Title is equal');
|
||||||
$this->assertEquals($location->id, $shiftAData['location']['id'], 'Same location');
|
$this->assertEquals($this->location->id, $shiftAData['location']['id'], 'Same location');
|
||||||
$this->assertEquals($shiftA->shiftType->id, $shiftAData['shift_type']['id'], 'Shift type equals');
|
$this->assertEquals($this->shiftA->shiftType->id, $shiftAData['shift_type']['id'], 'Shift type equals');
|
||||||
$this->assertCount(4, $shiftAData['entries']);
|
$this->assertCount(4, $shiftAData['entries']);
|
||||||
// Has users
|
// Has users
|
||||||
$entriesA = collect($shiftAData['entries'])->sortBy('type.id');
|
$entriesA = collect($shiftAData['entries'])->sortBy('type.id');
|
||||||
$entry = $entriesA[0];
|
$entry = $entriesA[0];
|
||||||
$this->assertCount(2, $entry['users']);
|
$this->assertCount(2, $entry['users']);
|
||||||
$this->assertEquals(5, $entry['needs']);
|
$this->assertEquals(2, $entry['needs']);
|
||||||
$user = $entry['users'][0];
|
$user = $entry['users'][0];
|
||||||
$this->assertEquals('/users?action=view&user_id=' . $user['id'], $user['url']);
|
$this->assertEquals('/users?action=view&user_id=' . $user['id'], $user['url']);
|
||||||
$this->assertCount(0, $entriesA[1]['users']);
|
$this->assertCount(0, $entriesA[1]['users']);
|
||||||
|
@ -119,12 +70,130 @@ 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($this->shiftB->title, $shiftBData['title'], 'Title is equal');
|
||||||
$this->assertEquals($location->id, $shiftBData['location']['id'], 'Same location');
|
$this->assertEquals($this->location->id, $shiftBData['location']['id'], 'Same location');
|
||||||
$this->assertEquals($shiftB->shiftType->id, $shiftBData['shift_type']['id'], 'Shift type equals');
|
$this->assertEquals($this->shiftB->shiftType->id, $shiftBData['shift_type']['id'], 'Shift type equals');
|
||||||
$this->assertCount(2, $shiftBData['entries']);
|
$this->assertCount(2, $shiftBData['entries']);
|
||||||
// No users
|
// No users
|
||||||
$entriesB = collect($shiftBData['entries'])->sortBy('type.id');
|
$entriesB = collect($shiftBData['entries'])->sortBy('type.id');
|
||||||
$this->assertCount(0, $entriesB[0]['users']);
|
$this->assertCount(0, $entriesB[0]['users']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Api\ShiftsController::entriesByAngeltype
|
||||||
|
*/
|
||||||
|
public function testEntriesByAngeltype(): void
|
||||||
|
{
|
||||||
|
/** @var ShiftEntry $firstEntry */
|
||||||
|
$firstEntry = $this->shiftA->shiftEntries->first();
|
||||||
|
|
||||||
|
$request = new Request();
|
||||||
|
$request = $request->withAttribute('angeltype_id', $firstEntry->angelType->id);
|
||||||
|
|
||||||
|
$controller = new ShiftsController(new Response());
|
||||||
|
|
||||||
|
$response = $controller->entriesByAngeltype($request);
|
||||||
|
$this->validateApiResponse('/angeltypes/{id}/shifts', 'get', $response);
|
||||||
|
|
||||||
|
$this->assertEquals(['application/json'], $response->getHeader('content-type'));
|
||||||
|
$this->assertJson($response->getContent());
|
||||||
|
|
||||||
|
$data = json_decode($response->getContent(), true);
|
||||||
|
$this->assertArrayHasKey('data', $data);
|
||||||
|
$this->assertCount(2, $data['data']);
|
||||||
|
|
||||||
|
$shift = $data['data'][0];
|
||||||
|
$this->assertTrue(count($shift['entries']) >= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Api\ShiftsController::entriesByUser
|
||||||
|
*/
|
||||||
|
public function testEntriesByUser(): void
|
||||||
|
{
|
||||||
|
/** @var ShiftEntry $firstEntry */
|
||||||
|
$firstEntry = $this->shiftA->shiftEntries->first();
|
||||||
|
|
||||||
|
$request = new Request();
|
||||||
|
$request = $request->withAttribute('user_id', $firstEntry->user->id);
|
||||||
|
|
||||||
|
$controller = new ShiftsController(new Response());
|
||||||
|
|
||||||
|
$response = $controller->entriesByUser($request);
|
||||||
|
$this->validateApiResponse('/users/{id}/shifts', 'get', $response);
|
||||||
|
|
||||||
|
$this->assertEquals(['application/json'], $response->getHeader('content-type'));
|
||||||
|
$this->assertJson($response->getContent());
|
||||||
|
|
||||||
|
$data = json_decode($response->getContent(), true);
|
||||||
|
$this->assertArrayHasKey('data', $data);
|
||||||
|
$this->assertCount(1, $data['data']);
|
||||||
|
|
||||||
|
$shift = $data['data'][0];
|
||||||
|
$this->assertTrue(count($shift['entries']) >= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->location = Location::factory()->create();
|
||||||
|
$schedule = Schedule::factory()->create();
|
||||||
|
|
||||||
|
// Shifts
|
||||||
|
$this->shiftA = Shift::factory(1)
|
||||||
|
->create(['location_id' => $this->location->id, 'start' => Carbon::now()->subHour()])
|
||||||
|
->first();
|
||||||
|
$this->shiftB = Shift::factory(1)
|
||||||
|
->create(['location_id' => $this->location->id, 'start' => Carbon::now()->addHour()])
|
||||||
|
->first();
|
||||||
|
(new ScheduleShift(['shift_id' => $this->shiftB->id, 'schedule_id' => $schedule->id, 'guid' => 'a']))->save();
|
||||||
|
|
||||||
|
// "Empty" entry to be skipped
|
||||||
|
NeededAngelType::factory(1)->create(['location_id' => null, 'shift_id' => $this->shiftA->id, 'count' => 0]);
|
||||||
|
|
||||||
|
// Needed entry by shift
|
||||||
|
/** @var NeededAngelType $byShift */
|
||||||
|
$byShift = NeededAngelType::factory(2)
|
||||||
|
->create(['location_id' => null, 'shift_id' => $this->shiftA->id, 'count' => 2])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// Needed entry by location
|
||||||
|
/** @var NeededAngelType $byLocation */
|
||||||
|
$byLocation = NeededAngelType::factory(1)
|
||||||
|
->create(['location_id' => $this->location->id, 'shift_id' => null, 'count' => 3])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// Added by both
|
||||||
|
NeededAngelType::factory(1)
|
||||||
|
->create([
|
||||||
|
'location_id' => $this->location->id,
|
||||||
|
'shift_id' => null,
|
||||||
|
'angel_type_id' => $byShift->angel_type_id,
|
||||||
|
'count' => 3,
|
||||||
|
])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// By shift
|
||||||
|
ShiftEntry::factory(2)->create([
|
||||||
|
'shift_id' => $this->shiftA->id,
|
||||||
|
'angel_type_id' => $byShift->angel_type_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// By location
|
||||||
|
ShiftEntry::factory(1)->create([
|
||||||
|
'shift_id' => $this->shiftA->id,
|
||||||
|
'angel_type_id' => $byLocation->angel_type_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Additional (not required by shift nor location)
|
||||||
|
ShiftEntry::factory(1)->create(['shift_id' => $this->shiftA->id]);
|
||||||
|
|
||||||
|
foreach (User::all() as $user) {
|
||||||
|
// Generate user data
|
||||||
|
/** @var User $user */
|
||||||
|
PersonalData::factory()->create(['user_id' => $user->id]);
|
||||||
|
Contact::factory()->create(['user_id' => $user->id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Controllers\Api;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\Api\UsersController;
|
||||||
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Models\User\Contact;
|
||||||
|
use Engelsystem\Models\User\PersonalData;
|
||||||
|
use Engelsystem\Models\User\Settings;
|
||||||
|
use Engelsystem\Models\User\State;
|
||||||
|
use Engelsystem\Models\User\User;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
|
||||||
|
class UsersControllerTest extends ApiBaseControllerTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Api\UsersController::__construct
|
||||||
|
* @covers \Engelsystem\Controllers\Api\UsersController::self
|
||||||
|
* @covers \Engelsystem\Controllers\Api\Resources\UserDetailResource::toArray
|
||||||
|
*/
|
||||||
|
public function testSelf(): void
|
||||||
|
{
|
||||||
|
$user = User::factory()
|
||||||
|
->has(Contact::factory())
|
||||||
|
->has(PersonalData::factory())
|
||||||
|
->has(Settings::factory())
|
||||||
|
->has(State::factory())
|
||||||
|
->create();
|
||||||
|
|
||||||
|
/** @var Authenticator|MockObject $auth */
|
||||||
|
$auth = $this->createMock(Authenticator::class);
|
||||||
|
$this->setExpects($auth, 'user', null, $user);
|
||||||
|
|
||||||
|
$controller = new UsersController(new Response(), $auth);
|
||||||
|
|
||||||
|
$response = $controller->self();
|
||||||
|
$this->validateApiResponse('/users/self', 'get', $response);
|
||||||
|
|
||||||
|
$this->assertEquals(['application/json'], $response->getHeader('content-type'));
|
||||||
|
$this->assertJson($response->getContent());
|
||||||
|
|
||||||
|
$data = json_decode($response->getContent(), true);
|
||||||
|
$this->assertArrayHasKey('data', $data);
|
||||||
|
$this->assertArrayHasKey('id', $data['data']);
|
||||||
|
$this->assertEquals($user->id, $data['data']['id']);
|
||||||
|
$this->assertArrayHasKey('dates', $data['data']);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue