Schedule Import: Moved file, initial cleanup, updated schedules

This commit is contained in:
Igor Scheller 2023-07-30 18:23:01 +02:00 committed by xuwhite
parent aef53a306b
commit 790a04dc14
6 changed files with 115 additions and 152 deletions

View File

@ -187,11 +187,11 @@ $route->addGroup(
$route->addGroup(
'/schedule',
function (RouteCollector $route): void {
$route->get('', 'Admin\\Schedule\\ImportSchedule@index');
$route->get('/edit[/{schedule_id:\d+}]', 'Admin\\Schedule\\ImportSchedule@edit');
$route->post('/edit[/{schedule_id:\d+}]', 'Admin\\Schedule\\ImportSchedule@save');
$route->get('/load/{schedule_id:\d+}', 'Admin\\Schedule\\ImportSchedule@loadSchedule');
$route->post('/import/{schedule_id:\d+}', 'Admin\\Schedule\\ImportSchedule@importSchedule');
$route->get('', 'Admin\\ScheduleController@index');
$route->get('/edit[/{schedule_id:\d+}]', 'Admin\\ScheduleController@edit');
$route->post('/edit[/{schedule_id:\d+}]', 'Admin\\ScheduleController@save');
$route->get('/load/{schedule_id:\d+}', 'Admin\\ScheduleController@loadSchedule');
$route->post('/import/{schedule_id:\d+}', 'Admin\\ScheduleController@importSchedule');
}
);

View File

@ -59,8 +59,6 @@ $includeFiles = [
__DIR__ . '/../includes/pages/admin_user.php',
__DIR__ . '/../includes/pages/user_myshifts.php',
__DIR__ . '/../includes/pages/user_shifts.php',
__DIR__ . '/../includes/pages/schedule/ImportSchedule.php',
];
foreach ($includeFiles as $file) {

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Engelsystem\Controllers\Admin\Schedule;
namespace Engelsystem\Controllers\Admin;
use Engelsystem\Controllers\NotificationType;
use Engelsystem\Helpers\Carbon;
@ -17,7 +17,7 @@ use Engelsystem\Helpers\Uuid;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
use Engelsystem\Models\Location;
use Engelsystem\Models\Shifts\Schedule as ScheduleUrl;
use Engelsystem\Models\Shifts\Schedule as ScheduleModel;
use Engelsystem\Models\Shifts\ScheduleShift;
use Engelsystem\Models\Shifts\Shift;
use Engelsystem\Models\Shifts\ShiftType;
@ -25,56 +25,28 @@ use Engelsystem\Models\User\User;
use ErrorException;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Connection as DatabaseConnection;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Collection as DatabaseCollection;
use Illuminate\Support\Collection;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class ImportSchedule extends BaseController
class ScheduleController extends BaseController
{
use HasUserNotifications;
/** @var DatabaseConnection */
protected $db;
/** @var LoggerInterface */
protected $log;
protected array $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;
protected string $url = '/admin/schedule';
public function __construct(
Response $response,
SessionInterface $session,
GuzzleClient $guzzle,
XmlParser $parser,
DatabaseConnection $db,
LoggerInterface $log
protected Response $response,
protected GuzzleClient $guzzle,
protected XmlParser $parser,
protected DatabaseConnection $db,
protected LoggerInterface $log
) {
$this->guzzle = $guzzle;
$this->parser = $parser;
$this->response = $response;
$this->session = $session;
$this->db = $db;
$this->log = $log;
}
public function index(): Response
@ -83,7 +55,7 @@ class ImportSchedule extends BaseController
'admin/schedule/index.twig',
[
'is_index' => true,
'schedules' => ScheduleUrl::all(),
'schedules' => ScheduleModel::all(),
]
);
}
@ -91,7 +63,7 @@ class ImportSchedule extends BaseController
public function edit(Request $request): Response
{
$scheduleId = $request->getAttribute('schedule_id'); // optional
$schedule = ScheduleUrl::find($scheduleId);
$schedule = ScheduleModel::find($scheduleId);
return $this->response->withView(
'admin/schedule/edit.twig',
@ -103,12 +75,15 @@ class ImportSchedule extends BaseController
);
}
/**
* @throws ErrorException
*/
public function save(Request $request): Response
{
$scheduleId = $request->getAttribute('schedule_id'); // optional
/** @var ScheduleUrl $schedule */
$schedule = ScheduleUrl::findOrNew($scheduleId);
/** @var ScheduleModel $schedule */
$schedule = ScheduleModel::findOrNew($scheduleId);
if ($request->request->has('delete')) {
return $this->delete($schedule);
@ -173,7 +148,7 @@ class ImportSchedule extends BaseController
return redirect('/admin/schedule/load/' . $schedule->id);
}
protected function delete(ScheduleUrl $schedule): Response
protected function delete(ScheduleModel $schedule): Response
{
foreach ($schedule->scheduleShifts as $scheduleShift) {
// Only guid is needed here
@ -196,6 +171,7 @@ class ImportSchedule extends BaseController
}
$schedule->delete();
$this->log->info('Schedule {name} deleted', ['name' => $schedule->name]);
$this->addNotification('schedule.delete.success');
return redirect('/admin/schedule');
}
@ -209,7 +185,7 @@ class ImportSchedule extends BaseController
* @var Event[] $deleteEvents
* @var Room[] $newRooms
* @var int $shiftType
* @var ScheduleUrl $scheduleUrl
* @var ScheduleModel $scheduleModel
* @var Schedule $schedule
* @var int $minutesBefore
* @var int $minutesAfter
@ -220,7 +196,7 @@ class ImportSchedule extends BaseController
$deleteEvents,
$newRooms,
,
$scheduleUrl,
$scheduleModel,
$schedule
) = $this->getScheduleData($request);
} catch (ErrorException $e) {
@ -231,7 +207,7 @@ class ImportSchedule extends BaseController
return $this->response->withView(
'admin/schedule/load.twig',
[
'schedule_id' => $scheduleUrl->id,
'schedule_id' => $scheduleModel->id,
'schedule' => $schedule,
'locations' => [
'add' => $newRooms,
@ -254,7 +230,7 @@ class ImportSchedule extends BaseController
* @var Event[] $deleteEvents
* @var Room[] $newRooms
* @var int $shiftType
* @var ScheduleUrl $scheduleUrl
* @var ScheduleModel $schedule
*/
list(
$newEvents,
@ -262,14 +238,14 @@ class ImportSchedule extends BaseController
$deleteEvents,
$newRooms,
$shiftType,
$scheduleUrl
$schedule
) = $this->getScheduleData($request);
} catch (ErrorException $e) {
$this->addNotification($e->getMessage(), NotificationType::ERROR);
return back();
}
$this->log('Started schedule "{name}" import', ['name' => $scheduleUrl->name]);
$this->log->info('Started schedule "{name}" import', ['name' => $schedule->name]);
foreach ($newRooms as $room) {
$this->createLocation($room);
@ -283,7 +259,7 @@ class ImportSchedule extends BaseController
$locations
->where('name', $event->getRoom()->getName())
->first(),
$scheduleUrl
$schedule
);
}
@ -294,16 +270,16 @@ class ImportSchedule extends BaseController
$locations
->where('name', $event->getRoom()->getName())
->first(),
$scheduleUrl
$schedule
);
}
foreach ($deleteEvents as $event) {
$this->deleteEvent($event, $scheduleUrl);
$this->deleteEvent($event, $schedule);
}
$scheduleUrl->touch();
$this->log('Ended schedule "{name}" import', ['name' => $scheduleUrl->name]);
$schedule->touch();
$this->log->info('Ended schedule "{name}" import', ['name' => $schedule->name]);
$this->addNotification('schedule.import.success');
return redirect($this->url, 303);
@ -315,7 +291,7 @@ class ImportSchedule extends BaseController
$location->name = $room->getName();
$location->save();
$this->log('Created schedule location "{location}"', ['location' => $room->getName()]);
$this->log->info('Created schedule location "{location}"', ['location' => $room->getName()]);
}
protected function fireDeleteShiftEntryEvents(Event $event, ScheduleUrl $schedule): void
@ -349,7 +325,7 @@ class ImportSchedule extends BaseController
}
}
protected function createEvent(Event $event, int $shiftTypeId, Location $location, ScheduleUrl $scheduleUrl): void
protected function createEvent(Event $event, int $shiftTypeId, Location $location, ScheduleModel $scheduleUrl): void
{
$user = auth()->user();
$eventTimeZone = Carbon::now()->timezone;
@ -370,7 +346,7 @@ class ImportSchedule extends BaseController
$scheduleShift->shift()->associate($shift);
$scheduleShift->save();
$this->log(
$this->log->info(
'Created schedule shift "{shift}" in "{location}" ({from} {to}, {guid})',
[
'shift' => $shift->title,
@ -402,7 +378,7 @@ class ImportSchedule extends BaseController
$this->fireUpdateShiftUpdateEvent($oldShift, $shift);
$this->log(
$this->log->info(
'Updated schedule shift "{shift}" in "{location}" ({from} {to}, {guid})',
[
'shift' => $shift->title,
@ -424,7 +400,7 @@ class ImportSchedule extends BaseController
$this->fireDeleteShiftEntryEvents($event, $schedule);
$this->log(
$this->log->info(
'Deleted schedule shift "{shift}" in {location} ({from} {to}, {guid})',
[
'shift' => $shift->title,
@ -445,20 +421,19 @@ class ImportSchedule extends BaseController
}
/**
* @param Request $request
* @return Event[]|Room[]|Location[]
* @throws ErrorException
*/
protected function getScheduleData(Request $request)
protected function getScheduleData(Request $request): array
{
$scheduleId = (int) $request->getAttribute('schedule_id');
/** @var ScheduleUrl $scheduleUrl */
$scheduleUrl = ScheduleUrl::findOrFail($scheduleId);
/** @var ScheduleModel $scheduleUrl */
$scheduleUrl = ScheduleModel::findOrFail($scheduleId);
try {
$scheduleResponse = $this->guzzle->get($scheduleUrl->url);
} catch (ConnectException $e) {
} catch (ConnectException | GuzzleException) {
throw new ErrorException('schedule.import.request-error');
}
@ -503,16 +478,11 @@ class ImportSchedule extends BaseController
}
/**
* @param Schedule $schedule
* @param ScheduleUrl $scheduleUrl
* @param int $shiftType
* @param int $minutesBefore
* @param int $minutesAfter
* @return Event[]
*/
protected function shiftsDiff(
Schedule $schedule,
ScheduleUrl $scheduleUrl,
ScheduleModel $scheduleUrl,
int $shiftType,
int $minutesBefore,
int $minutesAfter
@ -554,6 +524,7 @@ class ImportSchedule extends BaseController
$guid = $scheduleShift->guid;
$shift = $scheduleShift->shift;
$event = $scheduleEvents[$guid];
/** @var Location $location */
$location = $locations->where('name', $event->getRoom()->getName())->first();
if (
@ -607,17 +578,17 @@ class ImportSchedule extends BaseController
/**
* @return Location[]|Collection
*/
protected function getAllLocations(): Collection
protected function getAllLocations(): Collection | array
{
return Location::all();
}
/**
* @param ScheduleUrl $scheduleUrl
* @param string[] $events
* @return QueryBuilder[]|DatabaseCollection|Collection|ScheduleShift[]
*
* @return Collection|ScheduleShift[]
*/
protected function getScheduleShiftsByGuid(ScheduleUrl $scheduleUrl, array $events)
protected function getScheduleShiftsByGuid(ScheduleModel $scheduleUrl, array $events): Collection | array
{
return ScheduleShift::with('shift.location')
->whereIn('guid', $events)
@ -626,24 +597,14 @@ class ImportSchedule extends BaseController
}
/**
* @param ScheduleUrl $scheduleUrl
* @param string[] $events
* @return QueryBuilder[]|DatabaseCollection|Collection|ScheduleShift[]
* @return Collection|ScheduleShift[]
*/
protected function getScheduleShiftsWhereNotGuid(ScheduleUrl $scheduleUrl, array $events)
protected function getScheduleShiftsWhereNotGuid(ScheduleModel $scheduleUrl, array $events): Collection | array
{
return ScheduleShift::with('shift.location')
->whereNotIn('guid', $events)
->where('schedule_id', $scheduleUrl->id)
->get();
}
/**
* @param string $message
* @param array $context
*/
protected function log(string $message, array $context = []): void
{
$this->log->info($message, $context);
}
}

View File

@ -1,12 +1,12 @@
<?xml version='1.0' encoding='utf-8' ?>
<schedule
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/voc/voctosched/master/schema/basic.xsd"
xsi:noNamespaceSchemaLocation="https://c3voc.de/schedule/schema.xsd"
>
<version>dolor</version>
<conference>
<title>Basic Test Event</title>
<acronym>Test2</acronym>
<acronym>test-2</acronym>
<start>2042-01-03</start>
<end>2042-01-03</end>
<days>1</days>
@ -21,7 +21,7 @@
<start>14:15</start>
<duration>00:45</duration>
<room>Some Room</room>
<slug>lorem/ipsum</slug>
<slug>lorem-42-ipsum</slug>
<recording>
<license>WTFPL</license>
<optout>true</optout>

View File

@ -1,20 +1,22 @@
<?xml version='1.0' encoding='utf-8' ?>
<schedule
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/voc/voctosched/master/schema/extended.xsd"
xsi:noNamespaceSchemaLocation="https://c3voc.de/schedule/schema.xsd"
>
<generator name="Engelsystem" version="1.2.3"/>
<version>Some version string</version>
<conference>
<title>Test Event</title>
<acronym>Test3</acronym>
<start>2042-01-01</start>
<end>2042-01-01</end>
<acronym>test-3</acronym>
<start>2042-01-01T01:00:00+02:00</start>
<end>2042-01-01T22:59:00+02:00</end>
<days>1</days>
<timeslot_duration>00:15</timeslot_duration>
<base_url>https://foo.bar/baz/schedule/</base_url>
<time_zone_name>Europe/Berlin</time_zone_name>
</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'>
<room name='Rooming' guid="bf5f1132-82bd-4da2-bbe0-1abbf8daf4ab">
<event guid='e427cfa9-9ba1-4b14-a99f-bce83ffe5a1c' id='1337'>
<date>2042-01-01T12:30:00+02:00</date>
<title>Foo Bar Test</title>
@ -22,10 +24,12 @@
<start>12:30</start>
<duration>00:30</duration>
<room>Rooming</room>
<slug>foo-bar-test</slug>
<slug>some-3-test</slug>
<recording>
<license>WTFPL</license>
<optout>false</optout>
<url>https://recorder.test/some-3-test/recorded</url>
<link>https://recorder.test/some-3-test</link>
</recording>
<video_download_url>https://foo.bar/baz/schedule/ipsum/recording.mp4</video_download_url>
<track>Testing</track>

View File

@ -2,7 +2,7 @@
<version>0.0.1</version>
<conference>
<title>Some Test Event</title>
<acronym>Test1</acronym>
<acronym>test-1</acronym>
</conference>
<day index='1' date='2042-01-02' start='2042-01-02T00:00:00+00:00' end='2042-01-02T22:59:00+00:00'>
<room name='Random Room'>
@ -13,7 +13,7 @@
<start>13:30</start>
<duration>00:30</duration>
<room>Rooming</room>
<slug>minimum-setup-test</slug>
<slug>minimum-1-setup</slug>
<track>Testing</track>
<type>Talk</type>
<abstract>A minimal description</abstract>