Reimplemented shifts json export

This commit is contained in:
Igor Scheller 2023-01-29 02:12:40 +01:00 committed by Michael Weimann
parent b0b4cb54ec
commit 7eccf2c535
7 changed files with 141 additions and 91 deletions

View File

@ -100,6 +100,7 @@ $route->get('/api[/{resource:.+}]', 'ApiController@index');
$route->get('/atom', 'FeedController@atom'); $route->get('/atom', 'FeedController@atom');
$route->get('/ical', 'FeedController@ical'); $route->get('/ical', 'FeedController@ical');
$route->get('/rss', 'FeedController@rss'); $route->get('/rss', 'FeedController@rss');
$route->get('/shifts-json-export', 'FeedController@shifts');
// Design // Design
$route->get('/design', 'DesignController@index'); $route->get('/design', 'DesignController@index');

View File

@ -1,7 +1,5 @@
<?php <?php
use Carbon\CarbonTimeZone;
use Engelsystem\Http\Exceptions\HttpForbidden;
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\Shifts\NeededAngelType; use Engelsystem\Models\Shifts\NeededAngelType;
use Engelsystem\Models\Shifts\ScheduleShift; use Engelsystem\Models\Shifts\ScheduleShift;
@ -378,84 +376,3 @@ function shift_next_controller()
throw_redirect(page_link_to('user_shifts')); throw_redirect(page_link_to('user_shifts'));
} }
/**
* Export filtered shifts via JSON.
* (Like shifts view)
*/
function shifts_json_export_controller()
{
$user = auth()->userFromApi();
if (!$user) {
throw new HttpForbidden('{"error":"Missing or invalid ?key="}', ['content-type' => 'application/json']);
}
if (!auth()->can('shifts_json_export')) {
throw new HttpForbidden('{"error":"Not allowed"}', ['content-type' => 'application/json']);
}
$shifts = Shifts_by_user(auth()->user()->id);
$shifts->sortBy('start_date');
$timeZone = CarbonTimeZone::create(config('timezone'));
$shiftsData = [];
foreach ($shifts as $shift) {
// Data required for the Fahrplan app integration https://github.com/johnjohndoe/engelsystem
// See engelsystem-base/src/main/kotlin/info/metadude/kotlin/library/engelsystem/models/Shift.kt
$data = [
// Name of the shift (type)
'name' => $shift->shiftType->name,
// Shift / Talk title
'title' => $shift->title,
// Shift description
'description' => $shift->description,
// Users comment
'Comment' => $shift->user_comment,
// Shift id
'SID' => $shift->id,
// Shift type id
'shifttype_id' => $shift->shift_type_id,
// Talk URL
'URL' => $shift->url,
// Room name
'Name' => $shift->room->name,
// Location map url
'map_url' => $shift->room->map_url,
// Start timestamp
/** @deprecated start_date should be used */
'start' => $shift->start->timestamp,
// Start date
'start_date' => $shift->start->toRfc3339String(),
// End timestamp
/** @deprecated end_date should be used */
'end' => $shift->end->timestamp,
// End date
'end_date' => $shift->end->toRfc3339String(),
// Timezone offset like "+01:00"
/** @deprecated should be retrieved from start_date or end_date */
'timezone' => $timeZone->toOffsetName(),
// The events timezone like "Europe/Berlin"
'event_timezone' => $timeZone->getName(),
];
$shiftsData[] = [
// Model data
...$shift->toArray(),
// legacy fields (ignoring created / updated (at/by) data)
'RID' => $shift->room_id,
// Fahrplan app required data
...$data
];
}
header('Content-Type: application/json; charset=utf-8');
raw_output(json_encode($shiftsData));
}

View File

@ -2,10 +2,12 @@
namespace Engelsystem\Controllers; namespace Engelsystem\Controllers;
use Carbon\CarbonTimeZone;
use Engelsystem\Helpers\Authenticator; use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Engelsystem\Models\News; use Engelsystem\Models\News;
use Engelsystem\Models\Shifts\ShiftEntry;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
class FeedController extends BaseController class FeedController extends BaseController
@ -15,6 +17,7 @@ class FeedController extends BaseController
'atom' => 'atom', 'atom' => 'atom',
'rss' => 'atom', 'rss' => 'atom',
'ical' => 'ical', 'ical' => 'ical',
'shifts' => 'shifts_json_export',
]; ];
public function __construct( public function __construct(
@ -52,6 +55,75 @@ class FeedController extends BaseController
->withView('api/ical', ['shiftEntries' => $shifts]); ->withView('api/ical', ['shiftEntries' => $shifts]);
} }
public function shifts(): Response
{
/** @var Collection|ShiftEntry[] $shiftEntries */
$shiftEntries = $this->getShifts();
$timeZone = CarbonTimeZone::create(config('timezone'));
$response = [];
foreach ($shiftEntries as $entry) {
$shift = $entry->shift;
// Data required for the Fahrplan app integration https://github.com/johnjohndoe/engelsystem
// See engelsystem-base/src/main/kotlin/info/metadude/kotlin/library/engelsystem/models/Shift.kt
// ! All attributes not defined in $data might change at any time !
$data = [
// Name of the shift (type)
'name' => $shift->shiftType->name,
// Shift / Talk title
'title' => $shift->title,
// Shift description
'description' => $shift->description,
// Users comment
'Comment' => $entry->user_comment,
// Shift id
'SID' => $shift->id,
// Shift type id
'shifttype_id' => $shift->shiftType->id,
// Talk URL
'URL' => $shift->url,
// Room id
'RID' => $shift->room->id,
// Room name
'Name' => $shift->room->name,
// Location map url
'map_url' => $shift->room->map_url,
// Start timestamp
/** @deprecated start_date should be used */
'start' => $shift->start->timestamp,
// Start date
'start_date' => $shift->start->toRfc3339String(),
// End timestamp
/** @deprecated end_date should be used */
'end' => $shift->end->timestamp,
// End date
'end_date' => $shift->end->toRfc3339String(),
// Timezone offset like "+01:00"
/** @deprecated should be retrieved from start_date or end_date */
'timezone' => $timeZone->toOffsetName(),
// The events timezone like "Europe/Berlin"
'event_timezone' => $timeZone->getName(),
];
$response[] = [
// Model data
...$entry->toArray(),
// Fahrplan app required data
...$data
];
}
return $this->response
->withAddedHeader('content-type', 'application/json; charset=utf-8')
->withContent(json_encode($response));
}
protected function getNews(): Collection protected function getNews(): Collection
{ {
$news = $this->request->has('meetings') $news = $this->request->has('meetings')

View File

@ -21,7 +21,6 @@ class LegacyMiddleware implements MiddlewareInterface
'rooms', 'rooms',
'shift_entries', 'shift_entries',
'shifts', 'shifts',
'shifts_json_export',
'users', 'users',
'user_driver_licenses', 'user_driver_licenses',
'admin_shifts_history', 'admin_shifts_history',
@ -77,10 +76,6 @@ class LegacyMiddleware implements MiddlewareInterface
protected function loadPage(string $page): array protected function loadPage(string $page): array
{ {
switch ($page) { switch ($page) {
case 'shifts_json_export':
require_once realpath(__DIR__ . '/../../includes/controller/shifts_controller.php');
shifts_json_export_controller();
break;
case 'public_dashboard': case 'public_dashboard':
return public_dashboard_controller(); return public_dashboard_controller();
case 'angeltypes': case 'angeltypes':

View File

@ -51,6 +51,16 @@ class ShiftEntry extends BaseModel
'freeloaded_comment' => '', 'freeloaded_comment' => '',
]; ];
/** @var array<string, string> */
protected $casts = [ // phpcs:ignore
'freeloaded' => 'bool',
];
/** @var array<string> Attributes which should not be serialized */
protected $hidden = [ // phpcs:ignore
'freeloaded_comment',
];
public function shift(): BelongsTo public function shift(): BelongsTo
{ {
return $this->belongsTo(Shift::class); return $this->belongsTo(Shift::class);

View File

@ -110,6 +110,59 @@ class FeedControllerTest extends ControllerTest
$controller->ical(); $controller->ical();
} }
/**
* @covers \Engelsystem\Controllers\FeedController::shifts
* @covers \Engelsystem\Controllers\FeedController::getShifts
*/
public function testShifts(): void
{
$this->request = $this->request->withQueryParams(['key' => 'fo0']);
$this->auth = new Authenticator(
$this->request,
new Session(new MockArraySessionStorage()),
new User(),
);
$controller = new FeedController($this->auth, $this->request, $this->response);
/** @var User $user */
$user = User::factory()->create(['api_key' => 'fo0']);
ShiftEntry::factory(3)->create(['user_id' => $user->id]);
$this->setExpects(
$this->response,
'withAddedHeader',
['content-type', 'application/json; charset=utf-8'],
$this->response
);
$this->response->expects($this->once())
->method('withContent')
->willReturnCallback(function ($jsonData) {
$data = json_decode($jsonData, true);
$this->assertIsArray($data);
$this->assertCount(3, $data);
$this->assertTrue($data[0]['start'] < $data[1]['start']);
// Ensure dates exist used by Fahrplan app
foreach (
[
'name', 'title', 'description',
'Comment',
'SID', 'shifttype_id', 'URL',
'RID', 'Name', 'map_url',
'start', 'start_date', 'end', 'end_date',
'timezone', 'event_timezone',
] as $requiredAttribute
) {
$this->assertArrayHasKey($requiredAttribute, $data[0]);
}
return $this->response;
});
$controller->shifts();
}
public function getNewsMeetingsDataProvider(): array public function getNewsMeetingsDataProvider(): array
{ {

View File

@ -33,5 +33,7 @@ class ShiftEntryTest extends ModelTest
$this->assertEquals($shift->id, $model->shift->id); $this->assertEquals($shift->id, $model->shift->id);
$this->assertEquals($angelType->id, $model->angelType->id); $this->assertEquals($angelType->id, $model->angelType->id);
$this->assertEquals($user->id, $model->user->id); $this->assertEquals($user->id, $model->user->id);
$this->assertArrayNotHasKey('freeloaded_comment', $model->toArray());
} }
} }