Added Schedule parsing and replaced old Fahrplan importer
Resolves #553 (Change Frab Import from xCal to XML) Resolves #538 (Feature Request: Multi Frab Import)main
parent
377b390c97
commit
42721e9572
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class MigrateAdminSchedulePermissions extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (!$this->schema->hasTable('Privileges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->schema->getConnection()
|
||||
->table('Privileges')
|
||||
->where('name', 'admin_import')
|
||||
->update(
|
||||
[
|
||||
'name' => 'schedule.import',
|
||||
'desc' => 'Import rooms and shifts from schedule.xml',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if (!$this->schema->hasTable('Privileges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->schema->getConnection()
|
||||
->table('Privileges')
|
||||
->where('name', 'schedule.import')
|
||||
->update(
|
||||
[
|
||||
'name' => 'admin_import',
|
||||
'desc' => 'Import rooms and shifts from schedule.xcs/schedule.xcal',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateScheduleShiftTable extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$this->schema->create(
|
||||
'schedules',
|
||||
function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('url');
|
||||
}
|
||||
);
|
||||
|
||||
$this->schema->create(
|
||||
'schedule_shift',
|
||||
function (Blueprint $table) {
|
||||
$table->integer('shift_id')->index()->unique();
|
||||
if ($this->schema->hasTable('Shifts')) {
|
||||
// Legacy table access
|
||||
$table->foreign('shift_id')
|
||||
->references('SID')->on('Shifts')
|
||||
->onUpdate('cascade')
|
||||
->onDelete('cascade');
|
||||
}
|
||||
|
||||
$this->references($table, 'schedules');
|
||||
$table->uuid('guid');
|
||||
}
|
||||
);
|
||||
|
||||
if ($this->schema->hasTable('Shifts')) {
|
||||
$this->schema->table(
|
||||
'Shifts',
|
||||
function (Blueprint $table) {
|
||||
$table->dropColumn('PSID');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->schema->hasTable('Room')) {
|
||||
$this->schema->table(
|
||||
'Room',
|
||||
function (Blueprint $table) {
|
||||
$table->dropColumn('from_frab');
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if ($this->schema->hasTable('Room')) {
|
||||
$this->schema->table(
|
||||
'Room',
|
||||
function (Blueprint $table) {
|
||||
$table->boolean('from_frab')
|
||||
->default(false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->schema->hasTable('Shifts')) {
|
||||
$this->schema->table(
|
||||
'Shifts',
|
||||
function (Blueprint $table) {
|
||||
$table->integer('PSID')
|
||||
->nullable()->default(null)
|
||||
->unique();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$this->schema->drop('schedule_shift');
|
||||
$this->schema->drop('schedules');
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,478 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function admin_import_title()
|
||||
{
|
||||
return __('Frab import');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function admin_import()
|
||||
{
|
||||
global $rooms_import;
|
||||
$user = auth()->user();
|
||||
$html = '';
|
||||
$import_dir = __DIR__ . '/../../import';
|
||||
$request = request();
|
||||
|
||||
$step = 'input';
|
||||
if (
|
||||
$request->has('step')
|
||||
&& in_array($request->input('step'), [
|
||||
'input',
|
||||
'check',
|
||||
'import'
|
||||
])
|
||||
) {
|
||||
$step = $request->input('step');
|
||||
}
|
||||
|
||||
try {
|
||||
$test_handle = @fopen($import_dir . '/tmp', 'w');
|
||||
fclose($test_handle);
|
||||
@unlink($import_dir . '/tmp');
|
||||
} catch (Exception $e) {
|
||||
error(__('Webserver has no write-permission on import directory.'));
|
||||
}
|
||||
|
||||
$import_file = $import_dir . '/import_' . $user->id . '.xml';
|
||||
$shifttype_id = null;
|
||||
$add_minutes_start = 15;
|
||||
$add_minutes_end = 15;
|
||||
|
||||
$shifttypes_source = ShiftTypes();
|
||||
$shifttypes = [];
|
||||
foreach ($shifttypes_source as $shifttype) {
|
||||
$shifttypes[$shifttype['id']] = $shifttype['name'];
|
||||
}
|
||||
|
||||
switch ($step) {
|
||||
case 'input':
|
||||
$valid = false;
|
||||
|
||||
if ($request->hasPostData('submit')) {
|
||||
$valid = true;
|
||||
|
||||
if ($request->has('shifttype_id') && isset($shifttypes[$request->input('shifttype_id')])) {
|
||||
$shifttype_id = $request->input('shifttype_id');
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('Please select a shift type.'));
|
||||
}
|
||||
|
||||
$minutes_start = trim($request->input('add_minutes_start'));
|
||||
if ($request->has('add_minutes_start') && is_numeric($minutes_start)) {
|
||||
$add_minutes_start = $minutes_start;
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('Please enter an amount of minutes to add to a talk\'s begin.'));
|
||||
}
|
||||
|
||||
if ($request->has('add_minutes_end') && is_numeric(trim($request->input('add_minutes_end')))) {
|
||||
$add_minutes_end = trim($request->input('add_minutes_end'));
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('Please enter an amount of minutes to add to a talk\'s end.'));
|
||||
}
|
||||
|
||||
if (isset($_FILES['xcal_file']) && ($_FILES['xcal_file']['error'] == 0)) {
|
||||
if (move_uploaded_file($_FILES['xcal_file']['tmp_name'], $import_file)) {
|
||||
libxml_use_internal_errors(true);
|
||||
if (simplexml_load_file($import_file) === false) {
|
||||
$valid = false;
|
||||
error(__('No valid xml/xcal file provided.'));
|
||||
unlink($import_file);
|
||||
}
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('File upload went wrong.'));
|
||||
}
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('Please provide some data.'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
throw_redirect(
|
||||
page_link_to('admin_import', [
|
||||
'step' => 'check',
|
||||
'shifttype_id' => $shifttype_id,
|
||||
'add_minutes_end' => $add_minutes_end,
|
||||
'add_minutes_start' => $add_minutes_start,
|
||||
])
|
||||
);
|
||||
} else {
|
||||
$html .= div('well well-sm text-center', [
|
||||
__('File Upload')
|
||||
. mute(glyph('arrow-right'))
|
||||
. mute(__('Validation'))
|
||||
. mute(glyph('arrow-right'))
|
||||
. mute(__('Import'))
|
||||
]) . div('row', [
|
||||
div('col-md-offset-3 col-md-6', [
|
||||
form([
|
||||
form_info(
|
||||
'',
|
||||
__('This import will create/update/delete rooms and shifts by given FRAB-export file. The needed file format is xcal.')
|
||||
),
|
||||
form_select('shifttype_id', __('Shifttype'), $shifttypes, $shifttype_id),
|
||||
form_spinner('add_minutes_start', __('Add minutes to start'), $add_minutes_start),
|
||||
form_spinner('add_minutes_end', __('Add minutes to end'), $add_minutes_end),
|
||||
form_file('xcal_file', __('xcal-File (.xcal)')),
|
||||
form_submit('submit', __('Import'))
|
||||
])
|
||||
])
|
||||
]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'check':
|
||||
if (!file_exists($import_file)) {
|
||||
error(__('Missing import file.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
if ($request->has('shifttype_id') && isset($shifttypes[$request->input('shifttype_id')])) {
|
||||
$shifttype_id = $request->input('shifttype_id');
|
||||
} else {
|
||||
error(__('Please select a shift type.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
if ($request->has('add_minutes_start') && is_numeric(trim($request->input('add_minutes_start')))) {
|
||||
$add_minutes_start = trim($request->input('add_minutes_start'));
|
||||
} else {
|
||||
error(__('Please enter an amount of minutes to add to a talk\'s begin.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
if ($request->has('add_minutes_end') && is_numeric(trim($request->input(('add_minutes_end'))))) {
|
||||
$add_minutes_end = trim($request->input('add_minutes_end'));
|
||||
} else {
|
||||
error(__('Please enter an amount of minutes to add to a talk\'s end.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
list($rooms_new, $rooms_deleted) = prepare_rooms($import_file);
|
||||
list($events_new, $events_updated, $events_deleted) = prepare_events(
|
||||
$import_file,
|
||||
$shifttype_id,
|
||||
$add_minutes_start,
|
||||
$add_minutes_end
|
||||
);
|
||||
|
||||
$html .= div(
|
||||
'well well-sm text-center',
|
||||
[
|
||||
'<span class="text-success">' . __('File Upload') . glyph('ok-circle') . '</span>'
|
||||
. mute(glyph('arrow-right'))
|
||||
. __('Validation')
|
||||
. mute(glyph('arrow-right'))
|
||||
. mute(__('Import'))
|
||||
]
|
||||
)
|
||||
. form(
|
||||
[
|
||||
div('row', [
|
||||
div('col-sm-6', [
|
||||
'<h3>' . __('Rooms to create') . '</h3>',
|
||||
table(__('Name'), $rooms_new)
|
||||
]),
|
||||
div('col-sm-6', [
|
||||
'<h3>' . __('Rooms to delete') . '</h3>',
|
||||
table(__('Name'), $rooms_deleted)
|
||||
])
|
||||
]),
|
||||
'<h3>' . __('Shifts to create') . '</h3>',
|
||||
table([
|
||||
'day' => __('Day'),
|
||||
'start' => __('Start'),
|
||||
'end' => __('End'),
|
||||
'shifttype' => __('Shift type'),
|
||||
'title' => __('Title'),
|
||||
'room' => __('Room')
|
||||
], shifts_printable($events_new, $shifttypes)),
|
||||
'<h3>' . __('Shifts to update') . '</h3>',
|
||||
table([
|
||||
'day' => __('Day'),
|
||||
'start' => __('Start'),
|
||||
'end' => __('End'),
|
||||
'shifttype' => __('Shift type'),
|
||||
'title' => __('Title'),
|
||||
'room' => __('Room')
|
||||
], shifts_printable($events_updated, $shifttypes)),
|
||||
'<h3>' . __('Shifts to delete') . '</h3>',
|
||||
table([
|
||||
'day' => __('Day'),
|
||||
'start' => __('Start'),
|
||||
'end' => __('End'),
|
||||
'shifttype' => __('Shift type'),
|
||||
'title' => __('Title'),
|
||||
'room' => __('Room')
|
||||
], shifts_printable($events_deleted, $shifttypes)),
|
||||
form_submit('submit', __('Import'))
|
||||
],
|
||||
page_link_to('admin_import', [
|
||||
'step' => 'import',
|
||||
'shifttype_id' => $shifttype_id,
|
||||
'add_minutes_end' => $add_minutes_end,
|
||||
'add_minutes_start' => $add_minutes_start,
|
||||
])
|
||||
);
|
||||
break;
|
||||
|
||||
case 'import':
|
||||
if (!file_exists($import_file)) {
|
||||
error(__('Missing import file.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
if (!file_exists($import_file)) {
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
if ($request->has('shifttype_id') && isset($shifttypes[$request->input('shifttype_id')])) {
|
||||
$shifttype_id = $request->input('shifttype_id');
|
||||
} else {
|
||||
error(__('Please select a shift type.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
if ($request->has('add_minutes_start') && is_numeric(trim($request->input('add_minutes_start')))) {
|
||||
$add_minutes_start = trim($request->input('add_minutes_start'));
|
||||
} else {
|
||||
error(__('Please enter an amount of minutes to add to a talk\'s begin.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
if ($request->has('add_minutes_end') && is_numeric(trim($request->input('add_minutes_end')))) {
|
||||
$add_minutes_end = trim($request->input('add_minutes_end'));
|
||||
} else {
|
||||
error(__('Please enter an amount of minutes to add to a talk\'s end.'));
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
list($rooms_new, $rooms_deleted) = prepare_rooms($import_file);
|
||||
foreach ($rooms_new as $room) {
|
||||
$result = Room_create($room, true, null, null);
|
||||
$rooms_import[trim($room)] = $result;
|
||||
}
|
||||
foreach ($rooms_deleted as $room) {
|
||||
Room_delete_by_name($room);
|
||||
}
|
||||
|
||||
list($events_new, $events_updated, $events_deleted) = prepare_events(
|
||||
$import_file,
|
||||
$shifttype_id,
|
||||
$add_minutes_start,
|
||||
$add_minutes_end
|
||||
);
|
||||
foreach ($events_new as $event) {
|
||||
Shift_create($event);
|
||||
}
|
||||
|
||||
foreach ($events_updated as $event) {
|
||||
Shift_update_by_psid($event);
|
||||
}
|
||||
|
||||
foreach ($events_deleted as $event) {
|
||||
Shift_delete_by_psid($event['PSID']);
|
||||
}
|
||||
|
||||
engelsystem_log('Frab import done');
|
||||
|
||||
unlink($import_file);
|
||||
|
||||
$html .= div('well well-sm text-center', [
|
||||
'<span class="text-success">' . __('File Upload') . glyph('ok-circle') . '</span>'
|
||||
. mute(glyph('arrow-right'))
|
||||
. '<span class="text-success">' . __('Validation') . glyph('ok-circle') . '</span>'
|
||||
. mute(glyph('arrow-right'))
|
||||
. '<span class="text-success">' . __('Import') . glyph('ok-circle') . '</span>'
|
||||
]) . success(__('It\'s done!'), true);
|
||||
break;
|
||||
default:
|
||||
throw_redirect(page_link_to('admin_import'));
|
||||
}
|
||||
|
||||
return page_with_title(admin_import_title(), [
|
||||
msg(),
|
||||
$html
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return array
|
||||
*/
|
||||
function prepare_rooms($file)
|
||||
{
|
||||
global $rooms_import;
|
||||
$data = read_xml($file);
|
||||
|
||||
// Load rooms from db for compare with input
|
||||
$rooms = Rooms();
|
||||
// Contains rooms from db with from_frab==true
|
||||
$rooms_db = [];
|
||||
// Contains all rooms from db
|
||||
$rooms_db_all = [];
|
||||
// Contains all rooms from db and frab
|
||||
$rooms_import = [];
|
||||
foreach ($rooms as $room) {
|
||||
if ($room['from_frab']) {
|
||||
$rooms_db[] = $room['Name'];
|
||||
}
|
||||
$rooms_db_all[] = $room['Name'];
|
||||
$rooms_import[$room['Name']] = $room['RID'];
|
||||
}
|
||||
|
||||
$events = $data->vcalendar->vevent;
|
||||
$rooms_frab = [];
|
||||
foreach ($events as $event) {
|
||||
$rooms_frab[] = (string)$event->location;
|
||||
if (!isset($rooms_import[trim($event->location)])) {
|
||||
$rooms_import[trim($event->location)] = trim($event->location);
|
||||
}
|
||||
}
|
||||
$rooms_frab = array_unique($rooms_frab);
|
||||
|
||||
$rooms_new = array_diff($rooms_frab, $rooms_db_all);
|
||||
$rooms_deleted = array_diff($rooms_db, $rooms_frab);
|
||||
|
||||
return [
|
||||
$rooms_new,
|
||||
$rooms_deleted
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param int $shifttype_id
|
||||
* @param int $add_minutes_start
|
||||
* @param int $add_minutes_end
|
||||
* @return array
|
||||
*/
|
||||
function prepare_events($file, $shifttype_id, $add_minutes_start, $add_minutes_end)
|
||||
{
|
||||
global $rooms_import;
|
||||
$data = read_xml($file);
|
||||
|
||||
$rooms = Rooms();
|
||||
$rooms_db = [];
|
||||
foreach ($rooms as $room) {
|
||||
$rooms_db[$room['Name']] = $room['RID'];
|
||||
}
|
||||
|
||||
$events = $data->vcalendar->vevent;
|
||||
$shifts_pb = [];
|
||||
foreach ($events as $event) {
|
||||
$event_pb = $event->children('http://pentabarf.org');
|
||||
$event_id = trim($event_pb->{'event-id'});
|
||||
$shifts_pb[$event_id] = [
|
||||
'shifttype_id' => $shifttype_id,
|
||||
'start' => parse_date("Ymd\THis", $event->dtstart) - $add_minutes_start * 60,
|
||||
'end' => parse_date("Ymd\THis", $event->dtend) + $add_minutes_end * 60,
|
||||
'RID' => $rooms_import[trim($event->location)],
|
||||
'title' => trim($event->summary),
|
||||
'URL' => trim($event->url),
|
||||
'PSID' => $event_id
|
||||
];
|
||||
}
|
||||
|
||||
$shifts = Shifts_from_frab();
|
||||
$shifts_db = [];
|
||||
foreach ($shifts as $shift) {
|
||||
$shifts_db[$shift['PSID']] = $shift;
|
||||
}
|
||||
|
||||
$shifts_new = [];
|
||||
$shifts_updated = [];
|
||||
foreach ($shifts_pb as $shift) {
|
||||
if (!isset($shifts_db[$shift['PSID']])) {
|
||||
$shifts_new[] = $shift;
|
||||
} else {
|
||||
$tmp = $shifts_db[$shift['PSID']];
|
||||
if (
|
||||
$shift['shifttype_id'] != $tmp['shifttype_id']
|
||||
|| $shift['title'] != $tmp['title']
|
||||
|| $shift['start'] != $tmp['start']
|
||||
|| $shift['end'] != $tmp['end']
|
||||
|| $shift['RID'] != $tmp['RID']
|
||||
|| $shift['URL'] != $tmp['URL']
|
||||
) {
|
||||
$shifts_updated[] = $shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$shifts_deleted = [];
|
||||
foreach ($shifts_db as $shift) {
|
||||
if (!isset($shifts_pb[$shift['PSID']])) {
|
||||
$shifts_deleted[] = $shift;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
$shifts_new,
|
||||
$shifts_updated,
|
||||
$shifts_deleted
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return SimpleXMLElement
|
||||
*/
|
||||
function read_xml($file)
|
||||
{
|
||||
global $xml_import;
|
||||
if (!isset($xml_import)) {
|
||||
libxml_use_internal_errors(true);
|
||||
$xml_import = simplexml_load_file($file);
|
||||
}
|
||||
return $xml_import;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $shifts
|
||||
* @param array $shifttypes
|
||||
* @return array
|
||||
*/
|
||||
function shifts_printable($shifts, $shifttypes)
|
||||
{
|
||||
global $rooms_import;
|
||||
$rooms = array_flip($rooms_import);
|
||||
|
||||
uasort($shifts, 'shift_sort');
|
||||
|
||||
$shifts_printable = [];
|
||||
foreach ($shifts as $shift) {
|
||||
$shifts_printable[] = [
|
||||
'day' => date('l, Y-m-d', $shift['start']),
|
||||
'start' => date('H:i', $shift['start']),
|
||||
'shifttype' => ShiftType_name_render([
|
||||
'id' => $shift['shifttype_id'],
|
||||
'name' => $shifttypes[$shift['shifttype_id']]
|
||||
]),
|
||||
'title' => shorten($shift['title']),
|
||||
'end' => date('H:i', $shift['end']),
|
||||
'room' => $rooms[$shift['RID']]
|
||||
];
|
||||
}
|
||||
return $shifts_printable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $shift_a
|
||||
* @param array $shift_b
|
||||
* @return int
|
||||
*/
|
||||
function shift_sort($shift_a, $shift_b)
|
||||
{
|
||||
return ($shift_a['start'] < $shift_b['start']) ? -1 : 1;
|
||||
}
|
@ -0,0 +1,612 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Controllers\Admin\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Controllers\BaseController;
|
||||
use Engelsystem\Helpers\Schedule\Event;
|
||||
use Engelsystem\Helpers\Schedule\Room;
|
||||
use Engelsystem\Helpers\Schedule\Schedule;
|
||||
use Engelsystem\Helpers\Schedule\XmlParser;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Models\Shifts\Schedule as ScheduleUrl;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use ErrorException;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use Illuminate\Database\Connection as DatabaseConnection;
|
||||
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
|
||||
use Illuminate\Database\Eloquent\Collection as DatabaseCollection;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class ImportSchedule extends BaseController
|
||||
{
|
||||
/** @var DatabaseConnection */
|
||||
protected $db;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
protected $log;
|
||||
|
||||
/** @var array */
|
||||
protected $permissions = [
|
||||
'schedule.import',
|
||||
];
|
||||
|
||||
/** @var XmlParser */
|
||||
protected $parser;
|
||||
|
||||
/** @var Response */
|
||||
protected $response;
|
||||
|
||||
/** @var SessionInterface */
|
||||
protected $session;
|
||||
|
||||
/** @var string */
|
||||
protected $url = '/admin/schedule';
|
||||
|
||||
/** @var GuzzleClient */
|
||||
protected $guzzle;
|
||||
|
||||
/**
|
||||
* @param Response $response
|
||||
* @param SessionInterface $session
|
||||
* @param GuzzleClient $guzzle
|
||||
* @param XmlParser $parser
|
||||
* @param DatabaseConnection $db
|
||||
* @param LoggerInterface $log
|
||||
*/
|
||||
public function __construct(
|
||||
Response $response,
|
||||
SessionInterface $session,
|
||||
GuzzleClient $guzzle,
|
||||
XmlParser $parser,
|
||||
DatabaseConnection $db,
|
||||
LoggerInterface $log
|
||||
) {
|
||||
$this->guzzle = $guzzle;
|
||||
$this->parser = $parser;
|
||||
$this->response = $response;
|
||||
$this->session = $session;
|
||||
$this->db = $db;
|
||||
$this->log = $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->response->withView(
|
||||
'admin/schedule/index.twig',
|
||||
[
|
||||
'errors' => $this->getFromSession('errors'),
|
||||
'success' => $this->getFromSession('success'),
|
||||
'shift_types' => $this->getShiftTypes(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function loadSchedule(Request $request): Response
|
||||
{
|
||||
try {
|
||||
/**
|
||||
* @var Event[] $newEvents
|
||||
* @var Event[] $changeEvents
|
||||
* @var Event[] $deleteEvents
|
||||
* @var Room[] $newRooms
|
||||
* @var int $shiftType
|
||||
* @var ScheduleUrl $scheduleUrl
|
||||
* @var Schedule $schedule
|
||||
* @var int $minutesBefore
|
||||
* @var int $minutesAfter
|
||||
*/
|
||||
list(
|
||||
$newEvents,
|
||||
$changeEvents,
|
||||
$deleteEvents,
|
||||
$newRooms,
|
||||
$shiftType,
|
||||
$scheduleUrl,
|
||||
$schedule,
|
||||
$minutesBefore,
|
||||
$minutesAfter
|
||||
) = $this->getScheduleData($request);
|
||||
} catch (ErrorException $e) {
|
||||
return back()->with('errors', [$e->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->response->withView(
|
||||
'admin/schedule/load.twig',
|
||||
[
|
||||
'errors' => $this->getFromSession('errors'),
|
||||
'schedule_url' => $scheduleUrl->url,
|
||||
'shift_type' => $shiftType,
|
||||
'minutes_before' => $minutesBefore,
|
||||
'minutes_after' => $minutesAfter,
|
||||
'schedule' => $schedule,
|
||||
'rooms' => [
|
||||
'add' => $newRooms,
|
||||
],
|
||||
'shifts' => [
|
||||
'add' => $newEvents,
|
||||
'update' => $changeEvents,
|
||||
'delete' => $deleteEvents,
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function importSchedule(Request $request): Response
|
||||
{
|
||||
try {
|
||||
/**
|
||||
* @var Event[] $newEvents
|
||||
* @var Event[] $changeEvents
|
||||
* @var Event[] $deleteEvents
|
||||
* @var Room[] $newRooms
|
||||
* @var int $shiftType
|
||||
* @var ScheduleUrl $scheduleUrl
|
||||
*/
|
||||
list(
|
||||
$newEvents,
|
||||
$changeEvents,
|
||||
$deleteEvents,
|
||||
$newRooms,
|
||||
$shiftType,
|
||||
$scheduleUrl
|
||||
) = $this->getScheduleData($request);
|
||||
} catch (ErrorException $e) {
|
||||
return back()->with('errors', [$e->getMessage()]);
|
||||
}
|
||||
|
||||
$this->log('Started schedule "{schedule}" import', ['schedule' => $scheduleUrl->url]);
|
||||
|
||||
foreach ($newRooms as $room) {
|
||||
$this->createRoom($room);
|
||||
}
|
||||
|
||||
$rooms = $this->getAllRooms();
|
||||
foreach ($newEvents as $event) {
|
||||
$this->createEvent(
|
||||
$event,
|
||||
(int)$shiftType,
|
||||
$rooms
|
||||
->where('name', $event->getRoom()->getName())
|
||||
->first(),
|
||||
$scheduleUrl
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($changeEvents as $event) {
|
||||
$this->updateEvent(
|
||||
$event,
|
||||
(int)$shiftType,
|
||||
$rooms
|
||||
->where('name', $event->getRoom()->getName())
|
||||
->first()
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($deleteEvents as $event) {
|
||||
$this->deleteEvent($event);
|
||||
}
|
||||
|
||||
$this->log('Ended schedule "{schedule}" import', ['schedule' => $scheduleUrl->url]);
|
||||
|
||||
return redirect($this->url, 303)
|
||||
->with('success', ['schedule.import.success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Room $room
|
||||
*/
|
||||
protected function createRoom(Room $room): void
|
||||
{
|
||||
$this->db
|
||||
->table('Room')
|
||||
->insert(
|
||||
[
|
||||
'Name' => $room->getName(),
|
||||
]
|
||||
);
|
||||
|
||||
$this->log('Created schedule room "{room}"', ['room' => $room->getName()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Event $shift
|
||||
* @param int $shiftTypeId
|
||||
* @param stdClass $room
|
||||
* @param ScheduleUrl $scheduleUrl
|
||||
*/
|
||||
protected function createEvent(Event $shift, int $shiftTypeId, stdClass $room, ScheduleUrl $scheduleUrl): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$this->db
|
||||
->table('Shifts')
|
||||
->insert(
|
||||
[
|
||||
'title' => $shift->getTitle(),
|
||||
'shifttype_id' => $shiftTypeId,
|
||||
'start' => $shift->getDate()->unix(),
|
||||
'end' => $shift->getEndDate()->unix(),
|
||||
'RID' => $room->id,
|
||||
'URL' => $shift->getUrl(),
|
||||
'created_by_user_id' => $user->id,
|
||||
'created_at_timestamp' => time(),
|
||||
'edited_by_user_id' => null,
|
||||
'edited_at_timestamp' => 0,
|
||||
]
|
||||
);
|
||||
|
||||
$shiftId = $this->db->getDoctrineConnection()->lastInsertId();
|
||||
|
||||
$scheduleShift = new ScheduleShift(['shift_id' => $shiftId, 'guid' => $shift->getGuid()]);
|
||||
$scheduleShift->schedule()->associate($scheduleUrl);
|
||||
$scheduleShift->save();
|
||||
|
||||
$this->log(
|
||||
'Created schedule shift "{shift}" in "{room}" ({from} {to}, {guid})',
|
||||
[
|
||||
'shift' => $shift->getTitle(),
|
||||
'room' => $room->name,
|
||||
'from' => $shift->getDate()->format(Carbon::RFC3339),
|
||||
'to' => $shift->getEndDate()->format(Carbon::RFC3339),
|
||||
'guid' => $shift->getGuid(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Event $shift
|
||||
* @param int $shiftTypeId
|
||||
* @param stdClass $room
|
||||
*/
|
||||
protected function updateEvent(Event $shift, int $shiftTypeId, stdClass $room): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$this->db
|
||||
->table('Shifts')
|
||||
->join('schedule_shift', 'Shifts.SID', 'schedule_shift.shift_id')
|
||||
->where('schedule_shift.guid', $shift->getGuid())
|
||||
->update(
|
||||
[
|
||||
'title' => $shift->getTitle(),
|
||||
'shifttype_id' => $shiftTypeId,
|
||||
'start' => $shift->getDate()->unix(),
|
||||
'end' => $shift->getEndDate()->unix(),
|
||||
'RID' => $room->id,
|
||||
'URL' => $shift->getUrl(),
|
||||
'edited_by_user_id' => $user->id,
|
||||
'edited_at_timestamp' => time(),
|
||||
]
|
||||
);
|
||||
|
||||
$this->log(
|
||||
'Updated schedule shift "{shift}" in "{room}" ({from} {to}, {guid})',
|
||||
[
|
||||
'shift' => $shift->getTitle(),
|
||||
'room' => $room->name,
|
||||
'from' => $shift->getDate()->format(Carbon::RFC3339),
|
||||
'to' => $shift->getEndDate()->format(Carbon::RFC3339),
|
||||
'guid' => $shift->getGuid(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Event $shift
|
||||
*/
|
||||
protected function deleteEvent(Event $shift): void
|
||||
{
|
||||
$this->db
|
||||
->table('Shifts')
|
||||
->join('schedule_shift', 'Shifts.SID', 'schedule_shift.shift_id')
|
||||
->where('schedule_shift.guid', $shift->getGuid())
|
||||
->delete();
|
||||
|
||||
$this->log(
|
||||
'Deleted schedule shift "{shift}" ({from} {to}, {guid})',
|
||||
[
|
||||
'shift' => $shift->getTitle(),
|
||||
'from' => $shift->getDate()->format(Carbon::RFC3339),
|
||||
'to' => $shift->getEndDate()->format(Carbon::RFC3339),
|
||||
'guid' => $shift->getGuid(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Event[]|Room[]|ScheduleUrl|Schedule|string
|
||||
* @throws ErrorException
|
||||
*/
|
||||
protected function getScheduleData(Request $request)
|
||||
{
|
||||
$data = $this->validate(
|
||||
$request,
|
||||
[
|
||||
'schedule-url' => 'required|url',
|
||||
'shift-type' => 'required|int',
|
||||
'minutes-before' => 'optional|int',
|
||||
'minutes-after' => 'optional|int',
|
||||
]
|
||||
);
|
||||
|
||||
$scheduleResponse = $this->guzzle->get($data['schedule-url']);
|
||||
if ($scheduleResponse->getStatusCode() != 200) {
|
||||
throw new ErrorException('schedule.import.request-error');
|
||||
}
|
||||
|
||||
$scheduleData = (string)$scheduleResponse->getBody();
|
||||
if (!$this->parser->load($scheduleData)) {
|
||||
throw new ErrorException('schedule.import.read-error');
|
||||
}
|
||||
|
||||
$shiftType = (int)$data['shift-type'];
|
||||
if (!isset($this->getShiftTypes()[$shiftType])) {
|
||||
throw new ErrorException('schedule.import.invalid-shift-type');
|
||||
}
|
||||
|
||||
$scheduleUrl = $this->getScheduleUrl($data['schedule-url']);
|
||||
$schedule = $this->parser->getSchedule();
|
||||
$minutesBefore = isset($data['minutes-before']) ? (int)$data['minutes-before'] : 15;
|
||||
$minutesAfter = isset($data['minutes-after']) ? (int)$data['minutes-after'] : 15;
|
||||
$newRooms = $this->newRooms($schedule->getRooms());
|
||||
return array_merge(
|
||||
$this->shiftsDiff($schedule, $scheduleUrl, $shiftType, $minutesBefore, $minutesAfter),
|
||||
[$newRooms, $shiftType, $scheduleUrl, $schedule, $minutesBefore, $minutesAfter]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return Collection
|
||||
*/
|
||||
protected function getFromSession(string $name): Collection
|
||||
{
|
||||
$data = Collection::make(Arr::flatten($this->session->get($name, [])));
|
||||
$this->session->remove($name);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Room[] $scheduleRooms
|
||||
* @return Room[]
|
||||
*/
|
||||
protected function newRooms(array $scheduleRooms): array
|
||||
{
|
||||
$newRooms = [];
|
||||
$allRooms = $this->getAllRooms();
|
||||
|
||||
foreach ($scheduleRooms as $room) {
|
||||
if ($allRooms->where('name', $room->getName())->count()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newRooms[] = $room;
|
||||
}
|
||||
|
||||
return $newRooms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Schedule $schedule
|
||||
* @param ScheduleUrl $scheduleUrl
|
||||
* @param int $shiftType
|
||||
* @param int $minutesBefore
|
||||
* @param int $minutesAfter
|
||||
* @return Event[]
|
||||
*/
|
||||
protected function shiftsDiff(
|
||||
Schedule $schedule,
|
||||
ScheduleUrl $scheduleUrl,
|
||||
int $shiftType,
|
||||
int $minutesBefore,
|
||||
int $minutesAfter
|
||||
): array {
|
||||
/** @var Event[] $newEvents */
|
||||
$newEvents = [];
|
||||
/** @var Event[] $changeEvents */
|
||||
$changeEvents = [];
|
||||
/** @var Event[] $scheduleEvents */
|
||||
$scheduleEvents = [];
|
||||
/** @var Event[] $deleteEvents */
|
||||
$deleteEvents = [];
|
||||
$rooms = $this->getAllRooms();
|
||||
|
||||
foreach ($schedule->getDay() as $day) {
|
||||
foreach ($day->getRoom() as $room) {
|
||||
foreach ($room->getEvent() as $event) {
|
||||
$scheduleEvents[$event->getGuid()] = $event;
|
||||
|
||||
$event->getDate()->subMinutes($minutesBefore);
|
||||
$event->getEndDate()->addMinutes($minutesAfter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scheduleEventsGuidList = array_keys($scheduleEvents);
|
||||
$existingShifts = $this->getScheduleShiftsByGuid($scheduleUrl, $scheduleEventsGuidList);
|
||||
foreach ($existingShifts as $shift) {
|
||||
$guid = $shift->guid;
|
||||
$shift = $this->loadShift($shift->shift_id);
|
||||
$event = $scheduleEvents[$guid];
|
||||
|
||||
if (
|
||||
$shift->title != $event->getTitle()
|
||||
|| $shift->shift_type_id != $shiftType
|
||||
|| Carbon::createFromTimestamp($shift->start) != $event->getDate()
|
||||
|| Carbon::createFromTimestamp($shift->end) != $event->getEndDate()
|
||||
|| $shift->room_id != $rooms->where('name', $event->getRoom()->getName())->first()->id
|
||||
|| $shift->url != $event->getUrl()
|
||||
) {
|
||||
$changeEvents[$guid] = $event;
|
||||
}
|
||||
|
||||
unset($scheduleEvents[$guid]);
|
||||
}
|
||||
|
||||
foreach ($scheduleEvents as $scheduleEvent) {
|
||||
$newEvents[$scheduleEvent->getGuid()] = $scheduleEvent;
|
||||
}
|
||||
|
||||
$scheduleShifts = $this->getScheduleShiftsWhereNotGuid($scheduleUrl, $scheduleEventsGuidList);
|
||||
foreach ($scheduleShifts as $shift) {
|
||||
$event = $this->eventFromScheduleShift($shift);
|
||||
$deleteEvents[$event->getGuid()] = $event;
|
||||
}
|
||||
|
||||
return [$newEvents, $changeEvents, $deleteEvents];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScheduleShift $scheduleShift
|
||||
* @return Event
|
||||
*/
|
||||
protected function eventFromScheduleShift(ScheduleShift $scheduleShift): Event
|
||||
{
|
||||
$shift = $this->loadShift($scheduleShift->shift_id);
|
||||
$start = Carbon::createFromTimestamp($shift->start);
|
||||
$end = Carbon::createFromTimestamp($shift->end);
|
||||
$duration = $start->diff($end);
|
||||
|
||||
$event = new Event(
|
||||
$scheduleShift->guid,
|
||||
0,
|
||||
new Room($shift->room_name),
|
||||
$shift->title,
|
||||
'',
|
||||
'n/a',
|
||||
Carbon::createFromTimestamp($shift->start),
|
||||
$start->format('H:i'),
|
||||
$duration->format('%H:%I'),
|
||||
'',
|
||||
'',
|
||||
''
|
||||
);
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
protected function getAllRooms(): Collection
|
||||
{
|
||||
return new Collection($this->db->select('SELECT RID as id, Name as name FROM Room'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScheduleUrl $scheduleUrl
|
||||
* @param string[] $events
|
||||
* @return QueryBuilder[]|DatabaseCollection|ScheduleShift[]
|
||||
*/
|
||||
protected function getScheduleShiftsByGuid(ScheduleUrl $scheduleUrl, array $events)
|
||||
{
|
||||
return ScheduleShift::query()
|
||||
->whereIn('guid', $events)
|
||||
->where('schedule_id', $scheduleUrl->id)
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScheduleUrl $scheduleUrl
|
||||
* @param string[] $events
|
||||
* @return QueryBuilder[]|DatabaseCollection|ScheduleShift[]
|
||||
*/
|
||||
protected function getScheduleShiftsWhereNotGuid(ScheduleUrl $scheduleUrl, array $events)
|
||||
{
|
||||
return ScheduleShift::query()
|
||||
->whereNotIn('guid', $events)
|
||||
->where('schedule_id', $scheduleUrl->id)
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return stdClass|null
|
||||
*/
|
||||
protected function loadShift($id): ?stdClass
|
||||
{
|
||||
return $this->db->selectOne(
|
||||
'
|
||||
SELECT
|
||||
s.SID AS id,
|
||||
s.title,
|
||||
s.start,
|
||||
s.end,
|
||||
s.shifttype_id AS shift_type_id,
|
||||
s.RID AS room_id,
|
||||
r.Name AS room_name,
|
||||
s.URL as url
|
||||
FROM Shifts AS s
|
||||
LEFT JOIN Room r on s.RID = r.RID
|
||||
WHERE SID = ?
|
||||
',
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getShiftTypes()
|
||||
{
|
||||
$return = [];
|
||||
/** @var stdClass[] $shiftTypes */
|
||||
$shiftTypes = $this->db->select('SELECT t.id, t.name FROM ShiftTypes AS t');
|
||||
|
||||
foreach ($shiftTypes as $shiftType) {
|
||||
$return[$shiftType->id] = $shiftType->name;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scheduleUrl
|
||||
* @return ScheduleUrl
|
||||
*/
|
||||
protected function getScheduleUrl(string $scheduleUrl): ScheduleUrl
|
||||
{
|
||||
if (!$schedule = ScheduleUrl::whereUrl($scheduleUrl)->first()) {
|
||||
$schedule = new ScheduleUrl(['url' => $scheduleUrl]);
|
||||
$schedule->save();
|
||||
|
||||
$this->log('Created schedule "{schedule}"', ['schedule' => $schedule->url]);
|
||||
}
|
||||
|
||||
return $schedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*/
|
||||
protected function log(string $message, array $context = []): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
$message = sprintf('%s (%u): %s', $user->name, $user->id, $message);
|
||||
|
||||
$this->log->info($message, $context);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
{% extends 'layouts/app.twig' %}
|
||||
{% import 'macros/base.twig' as m %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
|
||||
{% set title %}{% block title %}{{ __('schedule.import.title') }}{% endblock %}{% endset %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h1>{% block content_title %}{{ title }}{% endblock %}</h1>
|
||||
|
||||
{% for message in errors|default([]) %}
|
||||
{{ m.alert(__(message), 'danger') }}
|
||||
{% endfor %}
|
||||
{% for message in success|default([]) %}
|
||||
{{ m.alert(__(message), 'success') }}
|
||||
{% endfor %}
|
||||
|
||||
<div class="row">
|
||||
{% block row_content %}
|
||||
<form method="POST" action="{{ url('/admin/schedule/load') }}">
|
||||
{{ csrf() }}
|
||||
|
||||
<div class="col-md-12">
|
||||
<p>{{ __('schedule.import.text') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
{{ f.input('schedule-url', __('schedule.url'), 'url', {'required': true}) }}
|
||||
|
||||
{{ f.select('shift-type', shift_types|default([]), __('schedule.shift-type')) }}
|
||||
|
||||
{{ f.input('minutes-before', __('schedule.minutes-before'), 'number', {'value': 15, 'required': true}) }}
|
||||
{{ f.input('minutes-after', __('schedule.minutes-after'), 'number', {'value': 15, 'required': true}) }}
|
||||
|
||||
{{ f.submit(__('form.load_schedule')) }}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,79 @@
|
||||
{% extends 'admin/schedule/index.twig' %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
|
||||
{% block title %}{{ __('schedule.import.load.title') }}{% endblock %}
|
||||
|
||||
{% block row_content %}
|
||||
<form method="POST" action="{{ url('/admin/schedule/import') }}">
|
||||
{{ csrf() }}
|
||||
{{ f.hidden('schedule-url', schedule_url) }}
|
||||
{{ f.hidden('shift-type', shift_type) }}
|
||||
{{ f.hidden('minutes-before', minutes_before) }}
|
||||
{{ f.hidden('minutes-after', minutes_after) }}
|
||||
|
||||
<div class="col-lg-12">
|
||||
<p>{{ __('schedule.import.load.info', [schedule.conference.title, schedule.version]) }}</p>
|
||||
|
||||
<h2>{{ __('schedule.import.rooms.add') }}</h2>
|
||||
{{ _self.roomsTable(rooms.add) }}
|
||||
|
||||
<h2>{{ __('schedule.import.shifts.add') }}</h2>
|
||||
{{ _self.shiftsTable(shifts.add) }}
|
||||
|
||||
<h2>{{ __('schedule.import.shifts.update') }}</h2>
|
||||
{{ _self.shiftsTable(shifts.update) }}
|
||||
|
||||
<h2>{{ __('schedule.import.shifts.delete') }}</h2>
|
||||
{{ _self.shiftsTable(shifts.delete) }}
|
||||
|
||||
{{ f.submit(__('form.import')) }}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% macro roomsTable(rooms) %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('schedule.import.rooms.name') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for room in rooms %}
|
||||
<tr>
|
||||
<td>{{ room.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro shiftsTable(shifts) %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('schedule.import.shift.dates') }}</th>
|
||||
<th>{{ __('schedule.import.shift.type') }}</th>
|
||||
<th>{{ __('schedule.import.shift.title') }}</th>
|
||||
<th>{{ __('schedule.import.shift.room') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for shift in shifts %}
|
||||
<tr>
|
||||
<td>{{ shift.date.format(__('Y-m-d H:i')) }} - {{ shift.endDate.format(__('H:i')) }}</td>
|
||||
<td>{{ shift.type }}</td>
|
||||
<td>{{ shift.title }}{% if shift.subtitle %}<br><small>{{ shift.subtitle }}</small>{% endif %}</td>
|
||||
<td>{{ shift.room.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endmacro %}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Helpers\Schedule;
|
||||
|
||||
trait CalculatesTime
|
||||
{
|
||||
/**
|
||||
* @param string $time
|
||||
* @return int
|
||||
*/
|
||||
protected function secondsFromTime(string $time): int
|
||||
{
|
||||
$seconds = 0;
|
||||
$duration = explode(':', $time);
|
||||
|
||||
foreach (array_slice($duration, 0, 2) as $key => $times) {
|
||||
$seconds += [60 * 60, 60][$key] * $times;
|
||||
}
|
||||
|
||||
return $seconds;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Helpers\Schedule;
|
||||
|
||||
class Conference
|
||||
{
|
||||
use CalculatesTime;
|
||||
|
||||
/** @var string required */
|
||||
protected $title;
|
||||
|
||||
/** @var string required */
|
||||
protected $acronym;
|
||||
|
||||
/** @var string|null */
|
||||
protected $start;
|
||||
|
||||
/** @var string|null */
|
||||
protected $end;
|
||||
|
||||
/** @var int|null */
|
||||
protected $days;
|
||||
|
||||
/** @var string|null */
|
||||
protected $timeslotDuration;
|
||||
|
||||
/** @var string|null */
|
||||
protected $baseUrl;
|
||||
|
||||
/**
|
||||
* Event constructor.
|
||||
*
|
||||
* @param string $title
|
||||
* @param string $acronym
|
||||
* @param string|null $start
|
||||
* @param string|null $end
|
||||
* @param int|null $days
|
||||
* @param string|null $timeslotDuration
|
||||
* @param string|null $baseUrl
|
||||
*/
|
||||
public function __construct(
|
||||
string $title,
|
||||
string $acronym,
|
||||
?string $start = null,
|
||||
?string $end = null,
|
||||
?int $days = null,
|
||||
?string $timeslotDuration = null,
|
||||
?string $baseUrl = null
|
||||
) {
|
||||
$this->title = $title;
|
||||
$this->acronym = $acronym;
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
$this->days = $days;
|
||||
$this->timeslotDuration = $timeslotDuration;
|
||||
$this->baseUrl = $baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAcronym(): string
|
||||
{
|
||||
return $this->acronym;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getStart(): ?string
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getEnd(): ?string
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getDays(): ?int
|
||||
{
|
||||
return $this->days;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getTimeslotDuration(): ?string
|
||||
{
|
||||
return $this->timeslotDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTimeslotDurationSeconds(): ?int
|
||||
{
|
||||
$duration = $this->getTimeslotDuration();
|
||||
if (!$duration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->secondsFromTime($duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getBaseUrl(): ?string
|
||||
{
|
||||
return $this->baseUrl;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Helpers\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Day
|
||||
{
|
||||
/** @var string required */
|
||||
protected $date;
|
||||
|
||||
/** @var Carbon required */
|
||||
protected $start;
|
||||
|
||||
/** @var Carbon required */
|
||||
protected $end;
|
||||
|
||||
/** @var int required */
|
||||
protected $index;
|
||||
|
||||
/** @var Room[] */
|
||||
protected $room;
|
||||
|
||||
/**
|
||||
* Day constructor.
|
||||
*
|
||||
* @param string $date
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param int $index
|
||||
* @param Room[] $rooms
|
||||
*/
|
||||
public function __construct(
|
||||
string $date,
|
||||
Carbon $start,
|
||||
Carbon $end,
|
||||
int $index,
|
||||
array $rooms = []
|
||||
) {
|
||||
$this->date = $date;
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
$this->index = $index;
|
||||
$this->room = $rooms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDate(): string
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getStart(): Carbon
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getEnd(): Carbon
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getIndex(): int
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Room[]
|
||||
*/
|
||||
public function getRoom(): array
|
||||
{
|
||||
return $this->room;
|
||||
}
|
||||
}
|
@ -0,0 +1,337 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Helpers\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Event
|
||||
{
|
||||
use CalculatesTime;
|
||||
|
||||
/** @var string required globally unique */
|
||||
protected $guid;
|
||||
|
||||
/** @var int required globally unique */
|
||||
protected $id;
|
||||
|
||||
/** @var Room required, string in XML */
|
||||
protected $room;
|
||||
|
||||
/** @var string required */
|
||||
protected $title;
|
||||
|
||||
/** @var string required */
|
||||
protected $subtitle;
|
||||
|
||||
/** @var string required */
|
||||
protected $type;
|
||||
|
||||
/** @var Carbon required */
|
||||
protected $date;
|
||||
|
||||
/** @var string required time (hh:mm:ss || hh:mm) */
|
||||
protected $start;
|
||||
|
||||
/** @var string required (h?h:mm:ss || h?h:mm) */
|
||||
protected $duration;
|
||||
|
||||
/** @var string required */
|
||||
protected $abstract;
|
||||
|
||||
/** @var string required globally unique */
|
||||
protected $slug;
|
||||
|
||||
/** @var string required */
|
||||
protected $track;
|
||||
|
||||
/** @var string|null */
|
||||
protected $logo;
|
||||
|
||||
/** @var string[] id => name */
|
||||
protected $persons;
|
||||
|
||||
/** @var string|null two letter code */
|
||||
protected $language;
|
||||
|
||||
/** @var string|null */
|
||||
protected $description;
|
||||
|
||||
/** @var string|null license (and opt out in XML, null if not recorded, empty if no license defined) */
|
||||
protected $recording;
|
||||
|
||||
/** @var array href => title */
|
||||
protected $links;
|
||||
|
||||
/** @var array href => name */
|
||||
protected $attachments;
|
||||
|
||||
/** @var string|null */
|
||||
protected $url;
|
||||
|
||||
/** @var string|null */
|
||||
protected $videoDownloadUrl;
|
||||
|
||||
/** @var Carbon Calculated */
|
||||
protected $endDate;
|
||||
|
||||
/**
|
||||
* Event constructor.
|
||||
*
|
||||
* @param string $guid
|
||||
* @param int $id
|
||||
* @param Room $room
|
||||
* @param string $title
|
||||
* @param string $subtitle
|
||||
* @param string $type
|
||||
* @param Carbon $date
|
||||
* @param string $start
|
||||
* @param string $duration
|
||||
* @param string $abstract
|
||||
* @param string $slug
|
||||
* @param string $track
|
||||
* @param string|null $logo
|
||||
* @param string[] $persons
|
||||
* @param string|null $language
|
||||
* @param string|null $description
|
||||
* @param string|null $recording license
|
||||
* @param array $links
|
||||
* @param array $attachments
|
||||
* @param string|null $url
|
||||
* @param string|null $videoDownloadUrl
|
||||
*/
|
||||
public function __construct(
|
||||
string $guid,
|
||||
int $id,
|
||||
Room $room,
|
||||
string $title,
|
||||
string $subtitle,
|
||||
string $type,
|
||||
Carbon $date,
|
||||
string $start,
|
||||
string $duration,
|
||||
string $abstract,
|
||||
string $slug,
|
||||
string $track,
|
||||
?string $logo = null,
|
||||
array $persons = [],
|
||||
?string $language = null,
|
||||
?string $description = null,
|
||||
string $recording = '',
|
||||
array $links = [],
|
||||
array $attachments = [],
|
||||
?string $url = null,
|
||||
?string $videoDownloadUrl = null
|
||||
) {
|
||||
$this->guid = $guid;
|
||||
$this->id = $id;
|
||||
$this->room = $room;
|
||||
$this->title = $title;
|
||||
$this->subtitle = $subtitle;
|
||||
$this->type = $type;
|
||||
$this->date = $date;
|
||||
$this->start = $start;
|
||||
$this->duration = $duration;
|
||||
$this->abstract = $abstract;
|
||||
$this->slug = $slug;
|
||||
$this->track = $track;
|
||||
$this->logo = $logo;
|
||||
$this->persons = $persons;
|
||||
$this->language = $language;
|
||||
$this->description = $description;
|
||||
$this->recording = $recording;
|
||||
$this->links = $links;
|
||||
$this->attachments = $attachments;
|
||||
$this->url = $url;
|
||||
$this->videoDownloadUrl = $videoDownloadUrl;
|
||||
|
||||
$this->endDate = $this->date
|
||||
->copy()
|
||||
->addSeconds($this->getDurationSeconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getGuid(): string
|
||||
{
|
||||
return $this->guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Room
|
||||
*/
|
||||
public function getRoom(): Room
|
||||
{
|
||||
return $this->room;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSubtitle(): string
|
||||
{
|
||||
return $this->subtitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getDate(): Carbon
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getStart(): string
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDuration(): string
|
||||
{
|
||||
return $this->duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getDurationSeconds(): int
|
||||
{
|
||||
return $this->secondsFromTime($this->duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAbstract(): string
|
||||
{
|
||||
return $this->abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTrack(): string
|
||||
{
|
||||
return $this->track;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLogo(): ?string
|
||||
{
|
||||
return $this->logo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPersons(): array
|
||||
{
|
||||
return $this->persons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLanguage(): ?string
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRecording(): ?string
|
||||
{
|
||||
return $this->recording;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getLinks(): array
|
||||
{
|
||||
return $this->links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAttachments(): array
|
||||
{
|
||||
return $this->attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUrl(): ?string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getVideoDownloadUrl(): ?string
|
||||
{
|
||||
return $this->videoDownloadUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getEndDate(): Carbon
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Helpers\Schedule;
|
||||
|
||||
class Room
|
||||
{
|
||||
/** @var string required */
|
||||
protected $name;
|
||||
|
||||
/** @var Event[] */
|
||||
protected $event;
|
||||
|
||||
/**
|
||||
* Room constructor.
|
||||
*
|
||||
* @param string $name
|
||||
* @param Event[] $events
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
array $events = []
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->event = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Event[]
|
||||
*/
|
||||
public function getEvent(): array
|
||||
{
|
||||
return $this->event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Event[] $event
|
||||
*/
|
||||
public function setEvent(array $event): void
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Helpers\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Schedule
|
||||
{
|
||||
/** @var string */
|
||||
protected $version;
|
||||
|
||||
/** @var Conference */
|
||||
protected $conference;
|
||||
|
||||
/** @var Day[] */
|
||||
protected $day;
|
||||
|
||||
/**
|
||||
* @param string $version
|
||||
* @param Conference $conference
|
||||
* @param Day[] $days
|
||||
*/
|
||||
public function __construct(
|
||||
string $version,
|
||||
Conference $conference,
|
||||
array $days
|
||||
) {
|
||||
$this->version = $version;
|
||||
$this->conference = $conference;
|
||||
$this->day = $days;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion(): string
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Conference
|
||||
*/
|
||||
public function getConference(): Conference
|
||||
{
|
||||
return $this->conference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Day[]
|
||||
*/
|
||||
public function getDay(): array
|
||||
{
|
||||
return $this->day;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Room[]
|
||||
*/
|
||||
public function getRooms(): array
|
||||
{
|
||||
$rooms = [];
|
||||
foreach ($this->day as $day) {
|
||||
foreach ($day->getRoom() as $room) {
|
||||
$name = $room->getName();
|
||||
$rooms[$name] = $room;
|
||||
}
|
||||
}
|
||||
|
||||
return $rooms;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getStartDateTime(): ?Carbon
|
||||
{
|
||||
$start = null;
|
||||
foreach ($this->day as $day) {
|
||||
$time = $day->getStart();
|
||||
if ($time > $start && $start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$start = $time;
|
||||
}
|
||||
|
||||
return $start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getEndDateTime(): ?Carbon
|
||||
{
|
||||
$end = null;
|
||||
foreach ($this->day as $day) {
|
||||
$time = $day->getEnd();
|
||||
if ($time < $end && $end) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$end = $time;
|
||||
}
|
||||
|
||||
return $end;
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Helpers\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use SimpleXMLElement;
|
||||
|
||||
class XmlParser
|
||||
{
|
||||
/** @var SimpleXMLElement */
|
||||
protected $scheduleXML;
|
||||
|
||||
/** @var Schedule */
|
||||
protected $schedule;
|
||||
|
||||
/**
|
||||
* @param string $xml
|
||||
* @return bool
|
||||
*/
|
||||
public function load(string $xml): bool
|
||||
{
|
||||
$this->scheduleXML = simplexml_load_string($xml);
|
||||
|
||||
if (!$this->scheduleXML) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->parseXml();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the predefined XML content
|
||||
*/
|
||||
protected function parseXml(): void
|
||||
{
|
||||
$version = $this->getFirstXpathContent('version');
|
||||
$conference = new Conference(
|
||||
$this->getFirstXpathContent('conference/title'),
|
||||
$this->getFirstXpathContent('conference/acronym'),
|
||||
$this->getFirstXpathContent('conference/start'),
|
||||
$this->getFirstXpathContent('conference/end'),
|
||||
(int)$this->getFirstXpathContent('conference/days'),
|
||||
$this->getFirstXpathContent('conference/timeslot_duration'),
|
||||
$this->getFirstXpathContent('conference/base_url')
|
||||
);
|
||||
$days = [];
|
||||
|
||||
foreach ($this->scheduleXML->xpath('day') as $day) {
|
||||
$rooms = [];
|
||||
|
||||
foreach ($day->xpath('room') as $roomElement) {
|
||||
$room = new Room(
|
||||
(string)$roomElement->attributes()['name']
|
||||
);
|
||||
|
||||
$events = $this->parseEvents($roomElement->xpath('event'), $room);
|
||||
$room->setEvent($events);
|
||||
$rooms[] = $room;
|
||||
}
|
||||
|
||||
$days[] = new Day(
|
||||
(string)$day->attributes()['date'],
|
||||
new Carbon($day->attributes()['start']),
|
||||
new Carbon($day->attributes()['end']),
|
||||
(int)$day->attributes()['index'],
|
||||
$rooms
|
||||
);
|
||||
}
|
||||
|
||||
$this->schedule = new Schedule(
|
||||
$version,
|
||||
$conference,
|
||||
$days
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement[] $eventElements
|
||||
* @param Room $room
|
||||
* @return array
|
||||
*/
|
||||
protected function parseEvents(array $eventElements, Room $room): array
|
||||
{
|
||||
$events = [];
|
||||
|
||||
foreach ($eventElements as $event) {
|
||||
$persons = $this->getListFromSequence($event, 'persons', 'person', 'id');
|
||||
$links = $this->getListFromSequence($event, 'links', 'link', 'href');
|
||||
$attachments = $this->getListFromSequence($event, 'attachments', 'attachment', 'href');
|
||||
|
||||
$recording = '';
|
||||
$recordingElement = $event->xpath('recording')[0];
|
||||
if ($this->getFirstXpathContent('optout', $recordingElement) == 'false') {
|
||||
$recording = $this->getFirstXpathContent('license', $recordingElement);
|
||||
}
|
||||
|
||||
$events[] = new Event(
|
||||
(string)$event->attributes()['guid'],
|
||||
(int)$event->attributes()['id'],
|
||||
$room,
|
||||
$this->getFirstXpathContent('title', $event),
|
||||
$this->getFirstXpathContent('subtitle', $event),
|
||||
$this->getFirstXpathContent('type', $event),
|
||||
new Carbon($this->getFirstXpathContent('date', $event)),
|
||||
$this->getFirstXpathContent('start', $event),
|
||||
$this->getFirstXpathContent('duration', $event),
|
||||
$this->getFirstXpathContent('abstract', $event),
|
||||
$this->getFirstXpathContent('slug', $event),
|
||||
$this->getFirstXpathContent('track', $event),
|
||||
$this->getFirstXpathContent('logo', $event) ?: null,
|
||||
$persons,
|
||||
$this->getFirstXpathContent('language', $event) ?: null,
|
||||
$this->getFirstXpathContent('description', $event) ?: null,
|
||||
$recording,
|
||||
$links,
|
||||
$attachments,
|
||||
$this->getFirstXpathContent('url', $event) ?: null,
|
||||
$this->getFirstXpathContent('video_download_url', $event) ?: null
|
||||
);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param SimpleXMLElement|null $xml
|
||||
* @return string
|
||||
*/
|
||||
protected function getFirstXpathContent(string $path, ?SimpleXMLElement $xml = null): string
|
||||
{
|
||||
$element = ($xml ?: $this->scheduleXML)->xpath($path);
|
||||
|
||||
return $element ? (string)$element[0] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a list from a sequence of elements
|
||||
*
|
||||
* @param SimpleXMLElement $element
|
||||
* @param string $firstElement
|
||||
* @param string $secondElement
|
||||
* @param string $idAttribute
|
||||
* @return array
|
||||
*/
|
||||
protected function getListFromSequence(
|
||||
SimpleXMLElement $element,
|
||||
string $firstElement,
|
||||
string $secondElement,
|
||||
string $idAttribute
|
||||
): array {
|
||||
$items = [];
|
||||
|
||||
foreach ($element->xpath($firstElement)[0]->xpath($secondElement) as $item) {
|
||||
$items[(string)$item->attributes()[$idAttribute]] = (string)$item;
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Schedule
|
||||
*/
|
||||
public function getSchedule(): Schedule
|
||||
{
|
||||
return $this->schedule;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Http;
|
||||
|
||||
use Engelsystem\Container\ServiceProvider;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
|
||||
class GuzzleServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
$this->app->when(GuzzleClient::class)
|
||||
->needs('$config')
|
||||
->give(
|
||||
function () {
|
||||
return [
|
||||
// No exception on >= 400 responses
|
||||
'http_errors' => false,
|
||||
// Wait max n seconds for a response
|
||||
'timeout' => 2.0,
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\BaseModel;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $url
|
||||
*
|
||||
* @property-read QueryBuilder|Collection|ScheduleShift[] $scheduleShifts
|
||||
*
|
||||
* @method static QueryBuilder|Schedule[] whereId($value)
|
||||
* @method static QueryBuilder|Schedule[] whereUrl($value)
|
||||
*/
|
||||
class Schedule extends BaseModel
|
||||
{
|
||||
/** @var array Values that are mass assignable */
|
||||
protected $fillable = ['url'];
|
||||
|
||||
/**
|
||||
* @return HasMany
|
||||
*/
|
||||
public function scheduleShifts()
|
||||
{
|
||||
return $this->hasMany(ScheduleShift::class);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\BaseModel;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
|
||||
/**
|
||||
* @property int $shift_id
|
||||
* @property int $schedule_id
|
||||
* @property string $guid
|
||||
*
|
||||
* @property-read QueryBuilder|Schedule $schedule
|
||||
*
|
||||
* @method static QueryBuilder|ScheduleShift[] whereShiftId($value)
|
||||
* @method static QueryBuilder|ScheduleShift[] whereScheduleId($value)
|
||||
* @method static QueryBuilder|ScheduleShift[] whereGuid($value)
|
||||
*/
|
||||
class ScheduleShift extends BaseModel
|
||||
{
|
||||
/** @var string The primary key for the model */
|
||||
protected $primaryKey = 'shift_id';
|
||||
|
||||
/** @var string Required because it is not schedule_shifts */
|
||||
protected $table = 'schedule_shift';
|
||||
|
||||
/** @var array Values that are mass assignable */
|
||||
protected $fillable = ['shift_id', 'schedule_id', 'guid'];
|
||||
|
||||
/**
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function schedule()
|
||||
{
|
||||
return $this->belongsTo(Schedule::class);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<schedule>
|
||||
<version>Some version string</version>
|
||||
<conference>
|
||||
<title>Test Event</title>
|
||||
<acronym>Test1</acronym>
|
||||
<start>2042-01-01</start>
|
||||
<end>2042-01-01</end>
|
||||
<days>1</days>
|
||||
<timeslot_duration>00:15</timeslot_duration>
|
||||
<base_url>https://foo.bar/baz/schedule/</base_url>
|
||||
</conference>
|
||||
<day index='1' date='2042-01-01' start='2042-01-01T01:00:00+02:00' end='2042-01-01T22:59:00+02:00'>
|
||||
<room name='Rooming'>
|
||||
<event guid='e427cfa9-9ba1-4b14-a99f-bce83ffe5a1c' id='1337'>
|
||||
<date>2042-01-01T12:30:00+02:00</date>
|
||||
<title>Foo Bar Test</title>
|
||||
<subtitle>Some sub</subtitle>
|
||||
<start>12:30</start>
|
||||
<duration>00:30</duration>
|
||||
<room>Rooming</room>
|
||||
<slug>foo-bar-test</slug>
|
||||
<recording>
|
||||
<license>WTFPL</license>
|
||||
<optout>false</optout>
|
||||
</recording>
|
||||
<track>Testing</track>
|
||||
<type>Talk</type>
|
||||
<language>de</language>
|
||||
<abstract>Foo bar is da best</abstract>
|
||||
<description>Any describing stuff?</description>
|
||||
<url>https://foo.bar/baz/schedule/ipsum</url>
|
||||
<logo>https://lorem.ipsum/foo/bar.png</logo>
|
||||
<persons>
|
||||
<person id='1234'>Some Person</person>
|
||||
</persons>
|
||||
<links>
|
||||
<link href="https://foo.bar">Some Foo Bar</link>
|
||||
</links>
|
||||
<attachments>
|
||||
<attachment href="https://foo.bar/stuff.pdf">A PDF File</attachment>
|
||||
</attachments>
|
||||
</event>
|
||||
</room>
|
||||
</day>
|
||||
</schedule>
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers\Schedule;
|
||||
|
||||
use Engelsystem\Helpers\Schedule\CalculatesTime;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class CalculatesTimeTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\CalculatesTime::secondsFromTime
|
||||
*/
|
||||
public function testSecondsFromTime()
|
||||
{
|
||||
$calc = new class {
|
||||
use CalculatesTime;
|
||||
|
||||
/**
|
||||
* @param string $time
|
||||
* @return int
|
||||
*/
|
||||
public function calc(string $time): int
|
||||
{
|
||||
return $this->secondsFromTime($time);
|
||||
}
|
||||
};
|
||||
|
||||
$this->assertEquals(0, $calc->calc('0:00'));
|
||||
$this->assertEquals(60, $calc->calc('0:01'));
|
||||
$this->assertEquals(60 * 60, $calc->calc('01:00'));
|
||||
$this->assertEquals(60 * 60 * 10 + 60 * 11, $calc->calc('10:11'));
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers\Schedule;
|
||||
|
||||
use Engelsystem\Helpers\Schedule\Conference;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class ConferenceTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::__construct
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getTitle
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getAcronym
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getStart
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getEnd
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getDays
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getTimeslotDuration
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getTimeslotDurationSeconds
|
||||
* @covers \Engelsystem\Helpers\Schedule\Conference::getBaseUrl
|
||||
*/
|
||||
public function testCreate()
|
||||
{
|
||||
$conference = new Conference('Doing stuff', 'DS');
|
||||
$this->assertEquals('Doing stuff', $conference->getTitle());
|
||||
$this->assertEquals('DS', $conference->getAcronym());
|
||||
$this->assertNull($conference->getStart());
|
||||
$this->assertNull($conference->getEnd());
|
||||
$this->assertNull($conference->getDays());
|
||||
$this->assertNull($conference->getTimeslotDuration());
|
||||
$this->assertNull($conference->getTimeslotDurationSeconds());
|
||||
$this->assertNull($conference->getBaseUrl());
|
||||
|
||||
$conference = new Conference(
|
||||
'Doing stuff',
|
||||
'DS',
|
||||
'2042-01-01',
|
||||
'2042-01-10',
|
||||
10,
|
||||
'00:10',
|
||||
'https://foo.bar/schedule'
|
||||
);
|
||||
$this->assertEquals('2042-01-01', $conference->getStart());
|
||||
$this->assertEquals('2042-01-10', $conference->getEnd());
|
||||
$this->assertEquals(10, $conference->getDays());
|
||||
$this->assertEquals('00:10', $conference->getTimeslotDuration());
|
||||
$this->assertEquals(60 * 10, $conference->getTimeslotDurationSeconds());
|
||||
$this->assertEquals('https://foo.bar/schedule', $conference->getBaseUrl());
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Helpers\Schedule\Day;
|
||||
use Engelsystem\Helpers\Schedule\Room;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class DayTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Day::__construct
|
||||
* @covers \Engelsystem\Helpers\Schedule\Day::getDate
|
||||
* @covers \Engelsystem\Helpers\Schedule\Day::getStart
|
||||
* @covers \Engelsystem\Helpers\Schedule\Day::getEnd
|
||||
* @covers \Engelsystem\Helpers\Schedule\Day::getIndex
|
||||
* @covers \Engelsystem\Helpers\Schedule\Day::getRoom
|
||||
*/
|
||||
public function testCreate()
|
||||
{
|
||||
$day = new Day(
|
||||
'2000-01-01',
|
||||
new Carbon('2000-01-01T03:00:00+01:00'),
|
||||
new Carbon('2000-01-02T05:59:00+00:00'),
|
||||
1
|
||||
);
|
||||
$this->assertEquals('2000-01-01', $day->getDate());
|
||||
$this->assertEquals('2000-01-01T03:00:00+01:00', $day->getStart()->format(Carbon::RFC3339));
|
||||
$this->assertEquals('2000-01-02T05:59:00+00:00', $day->getEnd()->format(Carbon::RFC3339));
|
||||
$this->assertEquals(1, $day->getIndex());
|
||||
$this->assertEquals([], $day->getRoom());
|
||||
|
||||
$rooms = [
|
||||
new Room('Foo'),
|
||||
new Room('Bar'),
|
||||
];
|
||||
$day = new Day(
|
||||
'2001-01-01',
|
||||
new Carbon('2001-01-01T03:00:00+01:00'),
|
||||
new Carbon('2001-01-02T05:59:00+00:00'),
|
||||
1,
|
||||
$rooms
|
||||
);
|
||||
$this->assertEquals($rooms, $day->getRoom());
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Helpers\Schedule\Event;
|
||||
use Engelsystem\Helpers\Schedule\Room;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class EventTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::__construct
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getGuid
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getId
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getRoom
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getTitle
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getSubtitle
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getType
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDate
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getStart
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDuration
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDurationSeconds
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getAbstract
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getSlug
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getTrack
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getLogo
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getPersons
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getLanguage
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDescription
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getRecording
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getLinks
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getAttachments
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getUrl
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getVideoDownloadUrl
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getEndDate
|
||||
*/
|
||||
public function testCreate()
|
||||
{
|
||||
$room = new Room('Foo');
|
||||
$date = new Carbon('2020-12-28T19:30:00+00:00');
|
||||
$event = new Event(
|
||||
'0-1-2-3',
|
||||
1,
|
||||
$room,
|
||||
'Some stuff',
|
||||
'sub stuff',
|
||||
'Talk',
|
||||
$date,
|
||||
'19:30:00',
|
||||
'00:50',
|
||||
'Doing stuff is hard, plz try again',
|
||||
'1-some-stuff',
|
||||
'Security'
|
||||
);
|
||||
|
||||
$this->assertEquals('0-1-2-3', $event->getGuid());
|
||||
$this->assertEquals(1, $event->getId());
|
||||
$this->assertEquals($room, $event->getRoom());
|
||||
$this->assertEquals('Some stuff', $event->getTitle());
|
||||
$this->assertEquals('sub stuff', $event->getSubtitle());
|
||||
$this->assertEquals('Talk', $event->getType());
|
||||
$this->assertEquals($date, $event->getDate());
|
||||
$this->assertEquals('19:30:00', $event->getStart());
|
||||
$this->assertEquals('00:50', $event->getDuration());
|
||||
$this->assertEquals('Doing stuff is hard, plz try again', $event->getAbstract());
|
||||
$this->assertEquals('1-some-stuff', $event->getSlug());
|
||||
$this->assertEquals('Security', $event->getTrack());
|
||||
$this->assertNull($event->getLogo());
|
||||
$this->assertEquals([], $event->getPersons());
|
||||
$this->assertNull($event->getLanguage());
|
||||
$this->assertNull($event->getDescription());
|
||||
$this->assertEquals('', $event->getRecording());
|
||||
$this->assertEquals([], $event->getLinks());
|
||||
$this->assertEquals([], $event->getAttachments());
|
||||
$this->assertNull($event->getUrl());
|
||||
$this->assertNull($event->getVideoDownloadUrl());
|
||||
$this->assertEquals('2020-12-28T20:20:00+00:00', $event->getEndDate()->format(Carbon::RFC3339));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::__construct
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getGuid
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getId
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getRoom
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getTitle
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getSubtitle
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getType
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDate
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getStart
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDuration
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDurationSeconds
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getAbstract
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getSlug
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getTrack
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getLogo
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getPersons
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getLanguage
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getDescription
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getRecording
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getLinks
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getAttachments
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getUrl
|
||||
* @covers \Engelsystem\Helpers\Schedule\Event::getVideoDownloadUrl
|
||||
*/
|
||||
public function testCreateNotDefault()
|
||||
{
|
||||
$persons = [1337 => 'Some Person'];
|
||||
$links = ['https://foo.bar' => 'Foo Bar'];
|
||||
$attachments = ['/files/foo.pdf' => 'Suspicious PDF'];
|
||||
$event = new Event(
|
||||
'3-2-1-0',
|
||||
2,
|
||||
new Room('Bar'),
|
||||
'Lorem',
|
||||
'Ipsum',
|
||||
'Workshop',
|
||||
new Carbon('2021-01-01T00:00:00+00:00'),
|
||||
'00:00:00',
|
||||
'00:30',
|
||||
'Lorem ipsum dolor sit amet',
|
||||
'2-lorem',
|
||||
'DevOps',
|
||||
'/foo/bar.png',
|
||||
$persons,
|
||||
'de',
|
||||
'Foo bar is awesome! & That\'s why...',
|
||||
'CC BY SA',
|
||||
$links,
|
||||
$attachments,
|
||||
'https://foo.bar/2-lorem',
|
||||
'https://videos.orem.ipsum/2-lorem.mp4'
|
||||
);
|
||||
|
||||
$this->assertEquals('/foo/bar.png', $event->getLogo());
|
||||
$this->assertEquals($persons, $event->getPersons());
|
||||
$this->assertEquals('de', $event->getLanguage());
|
||||
$this->assertEquals('Foo bar is awesome! & That\'s why...', $event->getDescription());
|
||||
$this->assertEquals('CC BY SA', $event->getRecording());
|
||||
$this->assertEquals($links, $event->getLinks());
|
||||
$this->assertEquals($attachments, $event->getAttachments());
|
||||
$this->assertEquals('https://foo.bar/2-lorem', $event->getUrl());
|
||||
$this->assertEquals('https://videos.orem.ipsum/2-lorem.mp4', $event->getVideoDownloadUrl());
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers\Schedule;
|
||||
|
||||
use Engelsystem\Helpers\Schedule\Event;
|
||||
use Engelsystem\Helpers\Schedule\Room;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class RoomTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Room::__construct
|
||||
* @covers \Engelsystem\Helpers\Schedule\Room::getName
|
||||
* @covers \Engelsystem\Helpers\Schedule\Room::getEvent
|
||||
* @covers \Engelsystem\Helpers\Schedule\Room::setEvent
|
||||
*/
|
||||
public function testCreate()
|
||||
{
|
||||
$room = new Room('Test');
|
||||
$this->assertEquals('Test', $room->getName());
|
||||
$this->assertEquals([], $room->getEvent());
|
||||
|
||||
$events = [$this->createMock(Event::class), $this->createMock(Event::class)];
|
||||
$events2 = [$this->createMock(Event::class)];
|
||||
$room = new Room('Test2', $events);
|
||||
$this->assertEquals($events, $room->getEvent());
|
||||
|
||||
$room->setEvent($events2);
|
||||
$this->assertEquals($events2, $room->getEvent());
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Helpers\Schedule\Conference;
|
||||
use Engelsystem\Helpers\Schedule\Day;
|
||||
use Engelsystem\Helpers\Schedule\Room;
|
||||
use Engelsystem\Helpers\Schedule\Schedule;
|
||||
use Engelsystem\Test\Unit\HasDatabase;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class ScheduleTest extends TestCase
|
||||
{
|
||||
use HasDatabase;
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Schedule::__construct
|
||||
* @covers \Engelsystem\Helpers\Schedule\Schedule::getVersion
|
||||
* @covers \Engelsystem\Helpers\Schedule\Schedule::getConference
|
||||
* @covers \Engelsystem\Helpers\Schedule\Schedule::getDay
|
||||
*/
|
||||
public function testCreate()
|
||||
{
|
||||
$conference = new Conference('Foo Bar', 'FooB');
|
||||
$days = [$this->createMock(Day::class)];
|
||||
$schedule = new Schedule('Foo\'ing stuff 1.0', $conference, $days);
|
||||
|
||||
$this->assertEquals('Foo\'ing stuff 1.0', $schedule->getVersion());
|
||||
$this->assertEquals($conference, $schedule->getConference());
|
||||
$this->assertEquals($days, $schedule->getDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Schedule::getRooms
|
||||
*/
|
||||
public function testGetRooms()
|
||||
{
|
||||
$conference = new Conference('Test', 'T');
|
||||
$room1 = new Room('Test 1');
|
||||
$room2 = new Room('Test 2');
|
||||
$room3 = new Room('Test 3');
|
||||
$days = [
|
||||
new Day(
|
||||
'2042-01-01',
|
||||
new Carbon('2042-01-01T00:00:00+00:00'),
|
||||
new Carbon('2042-01-01T23:59:00+00:00'),
|
||||
1,
|
||||
[$room1, $room2]
|
||||
),
|
||||
new Day(
|
||||
'2042-01-02',
|
||||
new Carbon('2042-02-01T00:00:00+00:00'),
|
||||
new Carbon('2042-02-01T23:59:00+00:00'),
|
||||
2,
|
||||
[new Room('Test 2'), $room3]
|
||||
),
|
||||
];
|
||||
$schedule = new Schedule('Lorem 1.3.3.7', $conference, $days);
|
||||
|
||||
$this->assertEquals(['Test 1' => $room1, 'Test 2' => $room2, 'Test 3' => $room3], $schedule->getRooms());
|
||||
|
||||
$schedule = new Schedule('Lorem 1.3.3.0', $conference, []);
|
||||
$this->assertEquals([], $schedule->getRooms());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\Schedule::getStartDateTime
|
||||
* @covers \Engelsystem\Helpers\Schedule\Schedule::getEndDateTime
|
||||
*/
|
||||
public function testGetDateTimes()
|
||||
{
|
||||
$conference = new Conference('Some Conference', 'SC');
|
||||
$days = [
|
||||
new Day(
|
||||
'2042-01-02',
|
||||
new Carbon('2042-01-02T00:00:00+00:00'),
|
||||
new Carbon('2042-01-02T23:59:00+00:00'),
|
||||
2
|
||||
),
|
||||
new Day(
|
||||
'2042-01-01',
|
||||
new Carbon('2042-01-01T00:00:00+00:00'),
|
||||
new Carbon('2042-01-01T23:59:00+00:00'),
|
||||
1
|
||||
),
|
||||
new Day(
|
||||
'2042-01-04',
|
||||
new Carbon('2042-01-04T00:00:00+00:00'),
|
||||
new Carbon('2042-01-04T23:59:00+00:00'),
|
||||
3
|
||||
),
|
||||
];
|
||||
$schedule = new Schedule('Ipsum tester', $conference, $days);
|
||||
|
||||
$this->assertEquals('2042-01-01T00:00:00+00:00', $schedule->getStartDateTime()->format(Carbon::RFC3339));
|
||||
$this->assertEquals('2042-01-04T23:59:00+00:00', $schedule->getEndDateTime()->format(Carbon::RFC3339));
|
||||
|
||||
$schedule = new Schedule('Ipsum old', $conference, []);
|
||||
$this->assertNull($schedule->getStartDateTime());
|
||||
$this->assertNull($schedule->getEndDateTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare test
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->initDatabase();
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers\Schedule;
|
||||
|
||||
use Engelsystem\Helpers\Schedule\Day;
|
||||
use Engelsystem\Helpers\Schedule\Event;
|
||||
use Engelsystem\Helpers\Schedule\Room;
|
||||
use Engelsystem\Helpers\Schedule\XmlParser;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class XmlParserTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Schedule\XmlParser::load
|
||||
* @covers \Engelsystem\Helpers\Schedule\XmlParser::parseXml
|
||||
* @covers \Engelsystem\Helpers\Schedule\XmlParser::parseEvents
|
||||
* @covers \Engelsystem\Helpers\Schedule\XmlParser::getFirstXpathContent
|
||||
* @covers \Engelsystem\Helpers\Schedule\XmlParser::getListFromSequence
|
||||
* @covers \Engelsystem\Helpers\Schedule\XmlParser::getSchedule
|
||||
*/
|
||||
public function testLoad()
|
||||
{
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
$parser = new XmlParser();
|
||||
$this->assertFalse($parser->load('foo'));
|
||||
$this->assertTrue($parser->load(file_get_contents(__DIR__ . '/Assets/schedule.xml')));
|
||||
|
||||
$schedule = $parser->getSchedule();
|
||||
$this->assertEquals('Some version string', $schedule->getVersion());
|
||||
$this->assertEquals('Test Event', $schedule->getConference()->getTitle());
|
||||
|
||||
/** @var Room $room */
|
||||
$room = Arr::first($schedule->getRooms());
|
||||
$this->assertEquals('Rooming', $room->getName());
|
||||
|
||||
/** @var Day $day */
|
||||
$day = Arr::first($schedule->getDay());
|
||||
$this->assertEquals('2042-01-01', $day->getDate());
|
||||
$this->assertEquals(1, $day->getIndex());
|
||||
|
||||
/** @var Room $room */
|
||||
$room = Arr::first($day->getRoom());
|
||||
/** @var Event $event */
|
||||
$event = Arr::first($room->getEvent());
|
||||
|
||||
$this->assertEquals('Foo Bar Test', $event->getTitle());
|
||||
$this->assertEquals('WTFPL', $event->getRecording());
|
||||
$this->assertEquals('de', $event->getLanguage());
|
||||
$this->assertEquals('12:30', $event->getStart());
|
||||
$this->assertEquals([1234 => 'Some Person'], $event->getPersons());
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http;
|
||||
|
||||
use Engelsystem\Application;
|
||||
use Engelsystem\Http\GuzzleServiceProvider;
|
||||
use Engelsystem\Test\Unit\ServiceProviderTest;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
|
||||
class GuzzleServiceProviderTest extends ServiceProviderTest
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\GuzzleServiceProvider::register
|
||||
*/
|
||||
public function testRegister()
|
||||
{
|
||||
$app = new Application();
|
||||
|
||||
$serviceProvider = new GuzzleServiceProvider($app);
|
||||
$serviceProvider->register();
|
||||
|
||||
/** @var GuzzleClient $guzzle */
|
||||
$guzzle = $app->make(GuzzleClient::class);
|
||||
$config = $guzzle->getConfig();
|
||||
|
||||
$this->assertFalse($config['http_errors']);
|
||||
$this->assertArrayHasKey('timeout', $config);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\Shifts\Schedule;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Test\Unit\HasDatabase;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ScheduleShiftTest extends TestCase
|
||||
{
|
||||
use HasDatabase;
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\Shifts\ScheduleShift::schedule
|
||||
*/
|
||||
public function testScheduleShifts()
|
||||
{
|
||||
$schedule = new Schedule(['url' => 'https://lorem.ipsum/schedule.xml']);
|
||||
$schedule->save();
|
||||
|
||||
$scheduleShift = new ScheduleShift(['shift_id' => 1, 'guid' => 'a']);
|
||||
$scheduleShift->schedule()->associate($schedule);
|
||||
$scheduleShift->save();
|
||||
|
||||
/** @var ScheduleShift $scheduleShift */
|
||||
$scheduleShift = (new ScheduleShift())->find(1);
|
||||
$this->assertInstanceOf(BelongsTo::class, $scheduleShift->schedule());
|
||||
$this->assertEquals($schedule->id, $scheduleShift->schedule->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare test
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->initDatabase();
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\Shifts\Schedule;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Test\Unit\HasDatabase;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class ScheduleTest extends TestCase
|
||||
{
|
||||
use HasDatabase;
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\Shifts\Schedule::scheduleShifts
|
||||
*/
|
||||
public function testScheduleShifts()
|
||||
{
|
||||
$schedule = new Schedule(['url' => 'https://foo.bar/schedule.xml']);
|
||||
$schedule->save();
|
||||
|
||||
(new ScheduleShift(['shift_id' => 1, 'schedule_id' => $schedule->id, 'guid' => 'a']))->save();
|
||||
(new ScheduleShift(['shift_id' => 2, 'schedule_id' => $schedule->id, 'guid' => 'b']))->save();
|
||||
(new ScheduleShift(['shift_id' => 3, 'schedule_id' => $schedule->id, 'guid' => 'c']))->save();
|
||||
|
||||
$this->assertCount(3, $schedule->scheduleShifts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare test
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->initDatabase();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue