Added Schedule parsing and replaced old Fahrplan importer
Resolves #553 (Change Frab Import from xCal to XML) Resolves #538 (Feature Request: Multi Frab Import)
This commit is contained in:
parent
377b390c97
commit
42721e9572
|
@ -65,7 +65,7 @@ The following instructions explain how to get, build and run the latest engelsys
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration and Setup
|
### Configuration and Setup
|
||||||
* The webserver must have write access to the ```import``` and ```storage``` directories and read access for all other directories
|
* The webserver must have write access to the ```storage``` directory and read access for all other directories
|
||||||
* The webserver must point to the ```public``` directory.
|
* The webserver must point to the ```public``` directory.
|
||||||
* The webserver must read the ```.htaccess``` file and ```mod_rewrite``` must be enabled
|
* The webserver must read the ```.htaccess``` file and ```mod_rewrite``` must be enabled
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"doctrine/dbal": "^2.9",
|
"doctrine/dbal": "^2.9",
|
||||||
"erusev/parsedown": "^1.7",
|
"erusev/parsedown": "^1.7",
|
||||||
"gettext/gettext": "^4.6",
|
"gettext/gettext": "^4.6",
|
||||||
|
"guzzlehttp/guzzle": "^6.3",
|
||||||
"illuminate/container": "5.8.*",
|
"illuminate/container": "5.8.*",
|
||||||
"illuminate/database": "5.8.*",
|
"illuminate/database": "5.8.*",
|
||||||
"illuminate/support": "5.8.*",
|
"illuminate/support": "5.8.*",
|
||||||
|
|
|
@ -31,6 +31,7 @@ return [
|
||||||
// Additional services
|
// Additional services
|
||||||
\Engelsystem\Helpers\VersionServiceProvider::class,
|
\Engelsystem\Helpers\VersionServiceProvider::class,
|
||||||
\Engelsystem\Mail\MailerServiceProvider::class,
|
\Engelsystem\Mail\MailerServiceProvider::class,
|
||||||
|
\Engelsystem\Http\GuzzleServiceProvider::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
// Application middleware
|
// Application middleware
|
||||||
|
|
|
@ -25,3 +25,19 @@ $route->get('/stats', 'Metrics\\Controller@stats');
|
||||||
|
|
||||||
// API
|
// API
|
||||||
$route->get('/api[/{resource:.+}]', 'ApiController@index');
|
$route->get('/api[/{resource:.+}]', 'ApiController@index');
|
||||||
|
|
||||||
|
// Administration
|
||||||
|
$route->addGroup(
|
||||||
|
'/admin',
|
||||||
|
function (RouteCollector $route) {
|
||||||
|
// Schedule
|
||||||
|
$route->addGroup(
|
||||||
|
'/schedule',
|
||||||
|
function (RouteCollector $route) {
|
||||||
|
$route->get('', 'Admin\\Schedule\\ImportSchedule@index');
|
||||||
|
$route->post('/load', 'Admin\\Schedule\\ImportSchedule@loadSchedule');
|
||||||
|
$route->post('/import', 'Admin\\Schedule\\ImportSchedule@importSchedule');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ namespace Engelsystem\Migrations;
|
||||||
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Illuminate\Database\Schema\ColumnDefinition;
|
use Illuminate\Database\Schema\ColumnDefinition;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
trait Reference
|
trait Reference
|
||||||
{
|
{
|
||||||
|
@ -11,20 +12,25 @@ trait Reference
|
||||||
* @param Blueprint $table
|
* @param Blueprint $table
|
||||||
* @param bool $setPrimary
|
* @param bool $setPrimary
|
||||||
*/
|
*/
|
||||||
protected function referencesUser(Blueprint $table, $setPrimary = false)
|
protected function referencesUser(Blueprint $table, bool $setPrimary = false)
|
||||||
{
|
{
|
||||||
$this->references($table, 'users', 'user_id', $setPrimary);
|
$this->references($table, 'users', null, $setPrimary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Blueprint $table
|
* @param Blueprint $table
|
||||||
* @param string $targetTable
|
* @param string $targetTable
|
||||||
* @param string $fromColumn
|
* @param string|null $fromColumn
|
||||||
* @param bool $setPrimary
|
* @param bool $setPrimary
|
||||||
* @return ColumnDefinition
|
* @return ColumnDefinition
|
||||||
*/
|
*/
|
||||||
protected function references(Blueprint $table, $targetTable, $fromColumn, $setPrimary = false): ColumnDefinition
|
protected function references(
|
||||||
{
|
Blueprint $table,
|
||||||
|
string $targetTable,
|
||||||
|
?string $fromColumn = null,
|
||||||
|
bool $setPrimary = false
|
||||||
|
): ColumnDefinition {
|
||||||
|
$fromColumn = $fromColumn ?? Str::singular($targetTable) . '_id';
|
||||||
$col = $table->unsignedInteger($fromColumn);
|
$col = $table->unsignedInteger($fromColumn);
|
||||||
|
|
||||||
if ($setPrimary) {
|
if ($setPrimary) {
|
||||||
|
|
|
@ -15,7 +15,6 @@ COPY .babelrc .browserslistrc composer.json LICENSE package.json README.md webpa
|
||||||
COPY bin/ /app/bin
|
COPY bin/ /app/bin
|
||||||
COPY config/ /app/config
|
COPY config/ /app/config
|
||||||
COPY db/ /app/db
|
COPY db/ /app/db
|
||||||
RUN mkdir /app/import/
|
|
||||||
COPY includes/ /app/includes
|
COPY includes/ /app/includes
|
||||||
COPY public/ /app/public
|
COPY public/ /app/public
|
||||||
COPY resources/views /app/resources/views
|
COPY resources/views /app/resources/views
|
||||||
|
@ -35,7 +34,7 @@ WORKDIR /var/www
|
||||||
RUN apk add --no-cache icu-dev && \
|
RUN apk add --no-cache icu-dev && \
|
||||||
docker-php-ext-install intl pdo_mysql
|
docker-php-ext-install intl pdo_mysql
|
||||||
COPY --from=data /app/ /var/www
|
COPY --from=data /app/ /var/www
|
||||||
RUN chown -R www-data:www-data /var/www/import/ /var/www/storage/ && \
|
RUN chown -R www-data:www-data /var/www/storage/ && \
|
||||||
rm -r /var/www/html
|
rm -r /var/www/html
|
||||||
|
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
|
|
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
|
@ -69,7 +69,6 @@ $includeFiles = [
|
||||||
__DIR__ . '/../includes/pages/admin_arrive.php',
|
__DIR__ . '/../includes/pages/admin_arrive.php',
|
||||||
__DIR__ . '/../includes/pages/admin_free.php',
|
__DIR__ . '/../includes/pages/admin_free.php',
|
||||||
__DIR__ . '/../includes/pages/admin_groups.php',
|
__DIR__ . '/../includes/pages/admin_groups.php',
|
||||||
__DIR__ . '/../includes/pages/admin_import.php',
|
|
||||||
__DIR__ . '/../includes/pages/admin_log.php',
|
__DIR__ . '/../includes/pages/admin_log.php',
|
||||||
__DIR__ . '/../includes/pages/admin_questions.php',
|
__DIR__ . '/../includes/pages/admin_questions.php',
|
||||||
__DIR__ . '/../includes/pages/admin_rooms.php',
|
__DIR__ . '/../includes/pages/admin_rooms.php',
|
||||||
|
@ -82,6 +81,8 @@ $includeFiles = [
|
||||||
__DIR__ . '/../includes/pages/user_questions.php',
|
__DIR__ . '/../includes/pages/user_questions.php',
|
||||||
__DIR__ . '/../includes/pages/user_settings.php',
|
__DIR__ . '/../includes/pages/user_settings.php',
|
||||||
__DIR__ . '/../includes/pages/user_shifts.php',
|
__DIR__ . '/../includes/pages/user_shifts.php',
|
||||||
|
|
||||||
|
__DIR__ . '/../includes/pages/schedule/ImportSchedule.php',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($includeFiles as $file) {
|
foreach ($includeFiles as $file) {
|
||||||
|
|
|
@ -61,36 +61,21 @@ function Room_delete($room_id)
|
||||||
engelsystem_log('Room deleted: ' . $room['Name']);
|
engelsystem_log('Room deleted: ' . $room['Name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a room by its name
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*/
|
|
||||||
function Room_delete_by_name($name)
|
|
||||||
{
|
|
||||||
DB::delete('DELETE FROM `Room` WHERE `Name` = ?', [
|
|
||||||
$name
|
|
||||||
]);
|
|
||||||
engelsystem_log('Room deleted: ' . $name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new room
|
* Create a new room
|
||||||
*
|
*
|
||||||
* @param string $name Name of the room
|
* @param string $name Name of the room
|
||||||
* @param boolean $from_frab Is this a frab imported room?
|
|
||||||
* @param string $map_url URL to a map tha can be displayed in an iframe
|
* @param string $map_url URL to a map tha can be displayed in an iframe
|
||||||
* @param string description Markdown description
|
* @param string description Markdown description
|
||||||
* @return false|int
|
* @return false|int
|
||||||
*/
|
*/
|
||||||
function Room_create($name, $from_frab, $map_url, $description)
|
function Room_create($name, $map_url, $description)
|
||||||
{
|
{
|
||||||
DB::insert('
|
DB::insert('
|
||||||
INSERT INTO `Room` (`Name`, `from_frab`, `map_url`, `description`)
|
INSERT INTO `Room` (`Name`, `map_url`, `description`)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?)
|
||||||
', [
|
', [
|
||||||
$name,
|
$name,
|
||||||
(int)$from_frab,
|
|
||||||
$map_url,
|
$map_url,
|
||||||
$description
|
$description
|
||||||
]);
|
]);
|
||||||
|
@ -98,7 +83,6 @@ function Room_create($name, $from_frab, $map_url, $description)
|
||||||
|
|
||||||
engelsystem_log(
|
engelsystem_log(
|
||||||
'Room created: ' . $name
|
'Room created: ' . $name
|
||||||
. ', frab import: ' . ($from_frab ? 'Yes' : '')
|
|
||||||
. ', map_url: ' . $map_url
|
. ', map_url: ' . $map_url
|
||||||
. ', description: ' . $description
|
. ', description: ' . $description
|
||||||
);
|
);
|
||||||
|
@ -107,28 +91,25 @@ function Room_create($name, $from_frab, $map_url, $description)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update a room
|
* Update a room
|
||||||
*
|
*
|
||||||
* @param int $room_id The rooms id
|
* @param int $room_id The rooms id
|
||||||
* @param string $name Name of the room
|
* @param string $name Name of the room
|
||||||
* @param boolean $from_frab Is this a frab imported room?
|
|
||||||
* @param string $map_url URL to a map tha can be displayed in an iframe
|
* @param string $map_url URL to a map tha can be displayed in an iframe
|
||||||
* @param string $description Markdown description
|
* @param string $description Markdown description
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
function Room_update($room_id, $name, $from_frab, $map_url, $description)
|
function Room_update($room_id, $name, $map_url, $description)
|
||||||
{
|
{
|
||||||
$result = DB::update('
|
$result = DB::update('
|
||||||
UPDATE `Room`
|
UPDATE `Room`
|
||||||
SET
|
SET
|
||||||
`Name`=?,
|
`Name`=?,
|
||||||
`from_frab`=?,
|
|
||||||
`map_url`=?,
|
`map_url`=?,
|
||||||
`description`=?
|
`description`=?
|
||||||
WHERE `RID`=?
|
WHERE `RID`=?
|
||||||
LIMIT 1', [
|
LIMIT 1', [
|
||||||
$name,
|
$name,
|
||||||
(int)$from_frab,
|
|
||||||
$map_url,
|
$map_url,
|
||||||
$description,
|
$description,
|
||||||
$room_id
|
$room_id
|
||||||
|
@ -136,7 +117,6 @@ function Room_update($room_id, $name, $from_frab, $map_url, $description)
|
||||||
|
|
||||||
engelsystem_log(
|
engelsystem_log(
|
||||||
'Room updated: ' . $name .
|
'Room updated: ' . $name .
|
||||||
', frab import: ' . ($from_frab ? 'Yes' : '') .
|
|
||||||
', map_url: ' . $map_url .
|
', map_url: ' . $map_url .
|
||||||
', description: ' . $description
|
', description: ' . $description
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,17 +14,19 @@ function Shifts_by_angeltype($angeltype)
|
||||||
return DB::select('
|
return DB::select('
|
||||||
SELECT DISTINCT `Shifts`.* FROM `Shifts`
|
SELECT DISTINCT `Shifts`.* FROM `Shifts`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id` = `Shifts`.`SID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id` = `Shifts`.`SID`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `NeededAngelTypes`.`angel_type_id` = ?
|
WHERE `NeededAngelTypes`.`angel_type_id` = ?
|
||||||
AND `NeededAngelTypes`.`count` > 0
|
AND `NeededAngelTypes`.`count` > 0
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION
|
UNION
|
||||||
|
|
||||||
SELECT DISTINCT `Shifts`.* FROM `Shifts`
|
SELECT DISTINCT `Shifts`.* FROM `Shifts`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id` = `Shifts`.`RID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id` = `Shifts`.`RID`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `NeededAngelTypes`.`angel_type_id` = ?
|
WHERE `NeededAngelTypes`.`angel_type_id` = ?
|
||||||
AND `NeededAngelTypes`.`count` > 0
|
AND `NeededAngelTypes`.`count` > 0
|
||||||
AND NOT `Shifts`.`PSID` IS NULL
|
AND NOT s.shift_id IS NULL
|
||||||
', [$angeltype['id'], $angeltype['id']]);
|
', [$angeltype['id'], $angeltype['id']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,19 +43,21 @@ function Shifts_free($start, $end)
|
||||||
SELECT * FROM (
|
SELECT * FROM (
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE (`end` > ? AND `start` < ?)
|
WHERE (`end` > ? AND `start` < ?)
|
||||||
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`)
|
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`)
|
||||||
> (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`Shifts`.`SID` AND `freeloaded`=0)
|
> (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`Shifts`.`SID` AND `freeloaded`=0)
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION
|
UNION
|
||||||
|
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE (`end` > ? AND `start` < ?)
|
WHERE (`end` > ? AND `start` < ?)
|
||||||
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`room_id`=`Shifts`.`RID`)
|
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`room_id`=`Shifts`.`RID`)
|
||||||
> (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`Shifts`.`SID` AND `freeloaded`=0)
|
> (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`Shifts`.`SID` AND `freeloaded`=0)
|
||||||
AND NOT `Shifts`.`PSID` IS NULL
|
AND NOT s.shift_id IS NULL
|
||||||
) AS `tmp`
|
) AS `tmp`
|
||||||
ORDER BY `tmp`.`start`
|
ORDER BY `tmp`.`start`
|
||||||
", [
|
", [
|
||||||
|
@ -69,16 +73,6 @@ function Shifts_free($start, $end)
|
||||||
return $free_shifts;
|
return $free_shifts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all shifts with a PSID (from frab import)
|
|
||||||
*
|
|
||||||
* @return array[]
|
|
||||||
*/
|
|
||||||
function Shifts_from_frab()
|
|
||||||
{
|
|
||||||
return DB::select('SELECT * FROM `Shifts` WHERE `PSID` IS NOT NULL ORDER BY `start`');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|int $room
|
* @param array|int $room
|
||||||
* @return array[]
|
* @return array[]
|
||||||
|
@ -103,11 +97,12 @@ function Shifts_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
||||||
JOIN `Room` USING (`RID`)
|
JOIN `Room` USING (`RID`)
|
||||||
JOIN `ShiftTypes` ON `ShiftTypes`.`id` = `Shifts`.`shifttype_id`
|
JOIN `ShiftTypes` ON `ShiftTypes`.`id` = `Shifts`.`shifttype_id`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id` = `Shifts`.`SID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id` = `Shifts`.`SID`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||||
AND `start` BETWEEN ? AND ?
|
AND `start` BETWEEN ? AND ?
|
||||||
AND `NeededAngelTypes`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
AND `NeededAngelTypes`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
||||||
AND `NeededAngelTypes`.`count` > 0
|
AND `NeededAngelTypes`.`count` > 0
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION
|
UNION
|
||||||
|
|
||||||
|
@ -116,11 +111,12 @@ function Shifts_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
||||||
JOIN `Room` USING (`RID`)
|
JOIN `Room` USING (`RID`)
|
||||||
JOIN `ShiftTypes` ON `ShiftTypes`.`id` = `Shifts`.`shifttype_id`
|
JOIN `ShiftTypes` ON `ShiftTypes`.`id` = `Shifts`.`shifttype_id`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id`=`Shifts`.`RID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id`=`Shifts`.`RID`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||||
AND `start` BETWEEN ? AND ?
|
AND `start` BETWEEN ? AND ?
|
||||||
AND `NeededAngelTypes`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
AND `NeededAngelTypes`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
||||||
AND `NeededAngelTypes`.`count` > 0
|
AND `NeededAngelTypes`.`count` > 0
|
||||||
AND NOT `Shifts`.`PSID` IS NULL) AS tmp_shifts
|
AND NOT s.shift_id IS NULL) AS tmp_shifts
|
||||||
|
|
||||||
ORDER BY `room_name`, `start`';
|
ORDER BY `room_name`, `start`';
|
||||||
|
|
||||||
|
@ -152,9 +148,10 @@ function NeededAngeltypes_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`
|
||||||
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||||
AND `start` BETWEEN ? AND ?
|
AND `start` BETWEEN ? AND ?
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION
|
UNION
|
||||||
|
|
||||||
|
@ -168,9 +165,10 @@ function NeededAngeltypes_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id`=`Shifts`.`RID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id`=`Shifts`.`RID`
|
||||||
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
WHERE `Shifts`.`RID` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||||
AND `start` BETWEEN ? AND ?
|
AND `start` BETWEEN ? AND ?
|
||||||
AND NOT `Shifts`.`PSID` IS NULL';
|
AND NOT s.shift_id IS NULL';
|
||||||
|
|
||||||
return DB::select(
|
return DB::select(
|
||||||
$sql,
|
$sql,
|
||||||
|
@ -201,9 +199,10 @@ function NeededAngeltype_by_Shift_and_Angeltype($shift, $angeltype)
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`
|
||||||
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `Shifts`.`SID`=?
|
WHERE `Shifts`.`SID`=?
|
||||||
AND `AngelTypes`.`id`=?
|
AND `AngelTypes`.`id`=?
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION
|
UNION
|
||||||
|
|
||||||
|
@ -217,9 +216,10 @@ function NeededAngeltype_by_Shift_and_Angeltype($shift, $angeltype)
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id`=`Shifts`.`RID`
|
JOIN `NeededAngelTypes` ON `NeededAngelTypes`.`room_id`=`Shifts`.`RID`
|
||||||
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
JOIN `AngelTypes` ON `AngelTypes`.`id`= `NeededAngelTypes`.`angel_type_id`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `Shifts`.`SID`=?
|
WHERE `Shifts`.`SID`=?
|
||||||
AND `AngelTypes`.`id`=?
|
AND `AngelTypes`.`id`=?
|
||||||
AND NOT `Shifts`.`PSID` IS NULL
|
AND NOT s.shift_id IS NULL
|
||||||
',
|
',
|
||||||
[
|
[
|
||||||
$shift['SID'],
|
$shift['SID'],
|
||||||
|
@ -494,16 +494,6 @@ function Shift_signup_allowed(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a shift by its external id.
|
|
||||||
*
|
|
||||||
* @param int $shift_psid
|
|
||||||
*/
|
|
||||||
function Shift_delete_by_psid($shift_psid)
|
|
||||||
{
|
|
||||||
DB::delete('DELETE FROM `Shifts` WHERE `PSID`=?', [$shift_psid]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a shift.
|
* Delete a shift.
|
||||||
*
|
*
|
||||||
|
@ -535,7 +525,6 @@ function Shift_update($shift)
|
||||||
`RID` = ?,
|
`RID` = ?,
|
||||||
`title` = ?,
|
`title` = ?,
|
||||||
`URL` = ?,
|
`URL` = ?,
|
||||||
`PSID` = ?,
|
|
||||||
`edited_by_user_id` = ?,
|
`edited_by_user_id` = ?,
|
||||||
`edited_at_timestamp` = ?
|
`edited_at_timestamp` = ?
|
||||||
WHERE `SID` = ?
|
WHERE `SID` = ?
|
||||||
|
@ -547,7 +536,6 @@ function Shift_update($shift)
|
||||||
$shift['RID'],
|
$shift['RID'],
|
||||||
$shift['title'],
|
$shift['title'],
|
||||||
$shift['URL'],
|
$shift['URL'],
|
||||||
$shift['PSID'],
|
|
||||||
$user->id,
|
$user->id,
|
||||||
time(),
|
time(),
|
||||||
$shift['SID']
|
$shift['SID']
|
||||||
|
@ -555,25 +543,6 @@ function Shift_update($shift)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a shift by its external id.
|
|
||||||
*
|
|
||||||
* @param array $shift
|
|
||||||
* @return int
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
function Shift_update_by_psid($shift)
|
|
||||||
{
|
|
||||||
$shift_source = DB::selectOne('SELECT `SID` FROM `Shifts` WHERE `PSID`=?', [$shift['PSID']]);
|
|
||||||
|
|
||||||
if (empty($shift_source)) {
|
|
||||||
throw new Exception('Shift not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$shift['SID'] = $shift_source['SID'];
|
|
||||||
return Shift_update($shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new shift.
|
* Create a new shift.
|
||||||
*
|
*
|
||||||
|
@ -590,12 +559,11 @@ function Shift_create($shift)
|
||||||
`RID`,
|
`RID`,
|
||||||
`title`,
|
`title`,
|
||||||
`URL`,
|
`URL`,
|
||||||
`PSID`,
|
|
||||||
`created_by_user_id`,
|
`created_by_user_id`,
|
||||||
`edited_at_timestamp`,
|
`edited_at_timestamp`,
|
||||||
`created_at_timestamp`
|
`created_at_timestamp`
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
',
|
',
|
||||||
[
|
[
|
||||||
$shift['shifttype_id'],
|
$shift['shifttype_id'],
|
||||||
|
@ -604,7 +572,6 @@ function Shift_create($shift)
|
||||||
$shift['RID'],
|
$shift['RID'],
|
||||||
$shift['title'],
|
$shift['title'],
|
||||||
$shift['URL'],
|
$shift['URL'],
|
||||||
$shift['PSID'],
|
|
||||||
auth()->user()->id,
|
auth()->user()->id,
|
||||||
time(),
|
time(),
|
||||||
time(),
|
time(),
|
||||||
|
|
|
@ -39,8 +39,9 @@ function stats_hours_to_work()
|
||||||
(SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`)
|
(SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`shift_id`=`Shifts`.`SID`)
|
||||||
* (`Shifts`.`end` - `Shifts`.`start`)/3600 AS `count`
|
* (`Shifts`.`end` - `Shifts`.`start`)/3600 AS `count`
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `end` >= ?
|
WHERE `end` >= ?
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION ALL
|
UNION ALL
|
||||||
|
|
||||||
|
@ -48,8 +49,9 @@ function stats_hours_to_work()
|
||||||
(SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`room_id`=`Shifts`.`RID`)
|
(SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`room_id`=`Shifts`.`RID`)
|
||||||
* (`Shifts`.`end` - `Shifts`.`start`)/3600 AS `count`
|
* (`Shifts`.`end` - `Shifts`.`start`)/3600 AS `count`
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `end` >= ?
|
WHERE `end` >= ?
|
||||||
AND NOT `Shifts`.`PSID` IS NULL
|
AND NOT s.shift_id IS NULL
|
||||||
) AS `tmp`
|
) AS `tmp`
|
||||||
", [
|
", [
|
||||||
time(),
|
time(),
|
||||||
|
@ -90,8 +92,9 @@ function stats_angels_needed_three_hours()
|
||||||
)
|
)
|
||||||
AS `count`
|
AS `count`
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `end` > ? AND `start` < ?
|
WHERE `end` > ? AND `start` < ?
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION ALL
|
UNION ALL
|
||||||
|
|
||||||
|
@ -113,8 +116,9 @@ function stats_angels_needed_three_hours()
|
||||||
)
|
)
|
||||||
AS `count`
|
AS `count`
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `end` > ? AND `start` < ?
|
WHERE `end` > ? AND `start` < ?
|
||||||
AND NOT `Shifts`.`PSID` IS NULL
|
AND NOT s.shift_id IS NULL
|
||||||
) AS `tmp`", [
|
) AS `tmp`", [
|
||||||
$now,
|
$now,
|
||||||
$in3hours,
|
$in3hours,
|
||||||
|
@ -163,8 +167,9 @@ function stats_angels_needed_for_nightshifts()
|
||||||
)
|
)
|
||||||
AS `count`
|
AS `count`
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `end` > ? AND `start` < ?
|
WHERE `end` > ? AND `start` < ?
|
||||||
AND `Shifts`.`PSID` IS NULL
|
AND s.shift_id IS NULL
|
||||||
|
|
||||||
UNION ALL
|
UNION ALL
|
||||||
|
|
||||||
|
@ -186,8 +191,9 @@ function stats_angels_needed_for_nightshifts()
|
||||||
)
|
)
|
||||||
AS `count`
|
AS `count`
|
||||||
FROM `Shifts`
|
FROM `Shifts`
|
||||||
|
LEFT JOIN schedule_shift AS s on Shifts.SID = s.shift_id
|
||||||
WHERE `end` > ? AND `start` < ?
|
WHERE `end` > ? AND `start` < ?
|
||||||
AND NOT `Shifts`.`PSID` IS NULL
|
AND NOT s.shift_id IS NULL
|
||||||
) AS `tmp`", [
|
) AS `tmp`", [
|
||||||
$night_start,
|
$night_start,
|
||||||
$night_end,
|
$night_end,
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -19,7 +19,6 @@ function admin_rooms()
|
||||||
foreach ($rooms_source as $room) {
|
foreach ($rooms_source as $room) {
|
||||||
$rooms[] = [
|
$rooms[] = [
|
||||||
'name' => Room_name_render($room),
|
'name' => Room_name_render($room),
|
||||||
'from_frab' => glyph_bool($room['from_frab']),
|
|
||||||
'map_url' => glyph_bool(!empty($room['map_url'])),
|
'map_url' => glyph_bool(!empty($room['map_url'])),
|
||||||
'actions' => table_buttons([
|
'actions' => table_buttons([
|
||||||
button(
|
button(
|
||||||
|
@ -40,7 +39,6 @@ function admin_rooms()
|
||||||
if ($request->has('show')) {
|
if ($request->has('show')) {
|
||||||
$msg = '';
|
$msg = '';
|
||||||
$name = '';
|
$name = '';
|
||||||
$from_frab = false;
|
|
||||||
$map_url = null;
|
$map_url = null;
|
||||||
$description = null;
|
$description = null;
|
||||||
$room_id = 0;
|
$room_id = 0;
|
||||||
|
@ -61,7 +59,6 @@ function admin_rooms()
|
||||||
|
|
||||||
$room_id = $request->input('id');
|
$room_id = $request->input('id');
|
||||||
$name = $room['Name'];
|
$name = $room['Name'];
|
||||||
$from_frab = $room['from_frab'];
|
|
||||||
$map_url = $room['map_url'];
|
$map_url = $room['map_url'];
|
||||||
$description = $room['description'];
|
$description = $room['description'];
|
||||||
|
|
||||||
|
@ -88,8 +85,6 @@ function admin_rooms()
|
||||||
$msg .= error(__('Please enter a name.'), true);
|
$msg .= error(__('Please enter a name.'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$from_frab = $request->has('from_frab');
|
|
||||||
|
|
||||||
if ($request->has('map_url')) {
|
if ($request->has('map_url')) {
|
||||||
$map_url = strip_request_item('map_url');
|
$map_url = strip_request_item('map_url');
|
||||||
}
|
}
|
||||||
|
@ -118,9 +113,9 @@ function admin_rooms()
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
if (empty($room_id)) {
|
if (empty($room_id)) {
|
||||||
$room_id = Room_create($name, $from_frab, $map_url, $description);
|
$room_id = Room_create($name, $map_url, $description);
|
||||||
} else {
|
} else {
|
||||||
Room_update($room_id, $name, $from_frab, $map_url, $description);
|
Room_update($room_id, $name, $map_url, $description);
|
||||||
}
|
}
|
||||||
|
|
||||||
NeededAngelTypes_delete_by_room($room_id);
|
NeededAngelTypes_delete_by_room($room_id);
|
||||||
|
@ -159,7 +154,6 @@ function admin_rooms()
|
||||||
div('row', [
|
div('row', [
|
||||||
div('col-md-6', [
|
div('col-md-6', [
|
||||||
form_text('name', __('Name'), $name, false, 35),
|
form_text('name', __('Name'), $name, false, 35),
|
||||||
form_checkbox('from_frab', __('Frab import'), $from_frab),
|
|
||||||
form_text('map_url', __('Map URL'), $map_url),
|
form_text('map_url', __('Map URL'), $map_url),
|
||||||
form_info('', __('The map url is used to display an iframe on the room page.')),
|
form_info('', __('The map url is used to display an iframe on the room page.')),
|
||||||
form_textarea('description', __('Description'), $description),
|
form_textarea('description', __('Description'), $description),
|
||||||
|
@ -212,7 +206,6 @@ function admin_rooms()
|
||||||
msg(),
|
msg(),
|
||||||
table([
|
table([
|
||||||
'name' => __('Name'),
|
'name' => __('Name'),
|
||||||
'from_frab' => __('Frab import'),
|
|
||||||
'map_url' => __('Map'),
|
'map_url' => __('Map'),
|
||||||
'actions' => ''
|
'actions' => ''
|
||||||
], $rooms)
|
], $rooms)
|
||||||
|
|
|
@ -350,7 +350,6 @@ function admin_shifts()
|
||||||
|
|
||||||
foreach ($session->get('admin_shifts_shifts', []) as $shift) {
|
foreach ($session->get('admin_shifts_shifts', []) as $shift) {
|
||||||
$shift['URL'] = null;
|
$shift['URL'] = null;
|
||||||
$shift['PSID'] = null;
|
|
||||||
$shift_id = Shift_create($shift);
|
$shift_id = Shift_create($shift);
|
||||||
|
|
||||||
engelsystem_log(
|
engelsystem_log(
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,30 +108,38 @@ function make_navigation()
|
||||||
|
|
||||||
$admin_menu = [];
|
$admin_menu = [];
|
||||||
$admin_pages = [
|
$admin_pages = [
|
||||||
'admin_arrive' => __('Arrived angels'),
|
'admin_arrive' => 'Arrived angels',
|
||||||
'admin_active' => __('Active angels'),
|
'admin_active' => 'Active angels',
|
||||||
'admin_user' => __('All Angels'),
|
'admin_user' => 'All Angels',
|
||||||
'admin_free' => __('Free angels'),
|
'admin_free' => 'Free angels',
|
||||||
'admin_questions' => __('Answer questions'),
|
'admin_questions' => 'Answer questions',
|
||||||
'shifttypes' => __('Shifttypes'),
|
'shifttypes' => 'Shifttypes',
|
||||||
'admin_shifts' => __('Create shifts'),
|
'admin_shifts' => 'Create shifts',
|
||||||
'admin_rooms' => __('Rooms'),
|
'admin_rooms' => 'Rooms',
|
||||||
'admin_groups' => __('Grouprights'),
|
'admin_groups' => 'Grouprights',
|
||||||
'admin_import' => __('Frab import'),
|
'admin/schedule' => ['schedule.import', 'schedule.import'],
|
||||||
'admin_log' => __('Log'),
|
'admin_log' => 'Log',
|
||||||
'admin_event_config' => __('Event config'),
|
'admin_event_config' => 'Event config',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (config('autoarrive')) {
|
if (config('autoarrive')) {
|
||||||
unset($admin_pages['admin_arrive']);
|
unset($admin_pages['admin_arrive']);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($admin_pages as $menu_page => $title) {
|
foreach ($admin_pages as $menu_page => $options) {
|
||||||
if (auth()->can($menu_page)) {
|
$options = (array)$options;
|
||||||
|
$permissions = $menu_page;
|
||||||
|
$title = $options[0];
|
||||||
|
|
||||||
|
if (isset($options[1])) {
|
||||||
|
$permissions = $options[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth()->can($permissions)) {
|
||||||
$admin_menu[] = toolbar_item_link(
|
$admin_menu[] = toolbar_item_link(
|
||||||
page_link_to($menu_page),
|
page_link_to($menu_page),
|
||||||
'',
|
'',
|
||||||
$title,
|
__($title),
|
||||||
$menu_page == $page
|
$menu_page == $page
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,42 +409,6 @@ function table_buttons($buttons = [])
|
||||||
return '<div class="btn-group">' . join(' ', $buttons) . '</div>';
|
return '<div class="btn-group">' . join(' ', $buttons) . '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $str
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function shorten($str, $length = 50)
|
|
||||||
{
|
|
||||||
if (strlen($str) < $length) {
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
return '<span title="' . htmlentities($str, ENT_COMPAT, 'UTF-8') . '">'
|
|
||||||
. substr($str, 0, $length - 3)
|
|
||||||
. '...</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array[] $array
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function table_body($array)
|
|
||||||
{
|
|
||||||
$html = '';
|
|
||||||
foreach ($array as $line) {
|
|
||||||
$html .= '<tr>';
|
|
||||||
if (is_array($line)) {
|
|
||||||
foreach ($line as $td) {
|
|
||||||
$html .= '<td>' . $td . '</td>';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$html .= '<td>' . $line . '</td>';
|
|
||||||
}
|
|
||||||
$html .= '</tr>';
|
|
||||||
}
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $msg
|
* @param string $msg
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
|
|
@ -34,3 +34,36 @@ msgstr "Deine Passwörter stimmen nicht überein."
|
||||||
|
|
||||||
msgid "validation.password_confirmation.required"
|
msgid "validation.password_confirmation.required"
|
||||||
msgstr "Du musst dein Passwort bestätigen."
|
msgstr "Du musst dein Passwort bestätigen."
|
||||||
|
|
||||||
|
msgid "schedule.import"
|
||||||
|
msgstr "Programm importieren"
|
||||||
|
|
||||||
|
msgid "schedule.import.request-error"
|
||||||
|
msgstr "Das Programm konnte nicht abgerufen werden."
|
||||||
|
|
||||||
|
msgid "schedule.import.read-error"
|
||||||
|
msgstr "Das Programm konnte nicht gelesen werden."
|
||||||
|
|
||||||
|
msgid "schedule.import.invalid-shift-type"
|
||||||
|
msgstr "Der Schichttyp konnte nicht gefunden werden."
|
||||||
|
|
||||||
|
msgid "schedule.import.success"
|
||||||
|
msgstr "Das Programm wurde erfolgreich importiert."
|
||||||
|
|
||||||
|
msgid "validation.schedule-url.required"
|
||||||
|
msgstr "Bitte gib eine Programm URL an."
|
||||||
|
|
||||||
|
msgid "validation.schedule-url.url"
|
||||||
|
msgstr "Die Programm URL muss eine URL sein."
|
||||||
|
|
||||||
|
msgid "validation.shift-type.required"
|
||||||
|
msgstr "Der Schichttyp ist erforderlich."
|
||||||
|
|
||||||
|
msgid "validation.shift-type.int"
|
||||||
|
msgstr "Der Schichttyp muss eine Zahl sein."
|
||||||
|
|
||||||
|
msgid "validation.minutes-before.int"
|
||||||
|
msgstr "Die Minuten vor dem Talk müssen eine Zahl sein."
|
||||||
|
|
||||||
|
msgid "validation.minutes-after.int"
|
||||||
|
msgstr "Die Minuten nach dem Talk müssen eine Zahl sein."
|
||||||
|
|
|
@ -2806,3 +2806,60 @@ msgstr ""
|
||||||
|
|
||||||
#~ msgid "auth.no-nickname"
|
#~ msgid "auth.no-nickname"
|
||||||
#~ msgstr "Gib bitte einen Nick an."
|
#~ msgstr "Gib bitte einen Nick an."
|
||||||
|
|
||||||
|
msgid "form.load_schedule"
|
||||||
|
msgstr "Programm laden"
|
||||||
|
|
||||||
|
msgid "form.import"
|
||||||
|
msgstr "Importieren"
|
||||||
|
|
||||||
|
msgid "schedule.import.title"
|
||||||
|
msgstr "Programm importieren"
|
||||||
|
|
||||||
|
msgid "schedule.import.text"
|
||||||
|
msgstr "Dieser Import erstellt Räume and erstellt, aktualisiert und löscht Schichten anhand des schedule.xml exportes."
|
||||||
|
|
||||||
|
msgid "schedule.import.load.title"
|
||||||
|
msgstr "Programm importieren: Vorschau"
|
||||||
|
|
||||||
|
msgid "schedule.import.load.info"
|
||||||
|
msgstr "Importiere \"%s\" (Version \"%s\")"
|
||||||
|
|
||||||
|
msgid "schedule.url"
|
||||||
|
msgstr "Programm URL (schedule.xml)"
|
||||||
|
|
||||||
|
msgid "schedule.shift-type"
|
||||||
|
msgstr "Schichttyp"
|
||||||
|
|
||||||
|
msgid "schedule.minutes-before"
|
||||||
|
msgstr "Minuten vor Talk beginn hinzufügen"
|
||||||
|
|
||||||
|
msgid "schedule.minutes-after"
|
||||||
|
msgstr "Minuten nach Talk ende hinzufügen"
|
||||||
|
|
||||||
|
msgid "schedule.import.rooms.add"
|
||||||
|
msgstr "Neue Räume"
|
||||||
|
|
||||||
|
msgid "schedule.import.shifts.add"
|
||||||
|
msgstr "Neue Schichten"
|
||||||
|
|
||||||
|
msgid "schedule.import.shifts.update"
|
||||||
|
msgstr "Zu aktualisierende Schichten"
|
||||||
|
|
||||||
|
msgid "schedule.import.shifts.delete"
|
||||||
|
msgstr "Zu löschende Schichten"
|
||||||
|
|
||||||
|
msgid "schedule.import.rooms.name"
|
||||||
|
msgstr "Name"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.dates"
|
||||||
|
msgstr "Zeit"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.type"
|
||||||
|
msgstr "Typ"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.title"
|
||||||
|
msgstr "Titel"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.room"
|
||||||
|
msgstr "Raum"
|
||||||
|
|
|
@ -32,3 +32,36 @@ msgstr "Your passwords are not equal."
|
||||||
|
|
||||||
msgid "validation.password_confirmation.required"
|
msgid "validation.password_confirmation.required"
|
||||||
msgstr "You have to confirm your password."
|
msgstr "You have to confirm your password."
|
||||||
|
|
||||||
|
msgid "schedule.import"
|
||||||
|
msgstr "Import schedule"
|
||||||
|
|
||||||
|
msgid "schedule.import.request-error"
|
||||||
|
msgstr "The schedule could not be requested."
|
||||||
|
|
||||||
|
msgid "schedule.import.read-error"
|
||||||
|
msgstr "Unable to parse schedule."
|
||||||
|
|
||||||
|
msgid "schedule.import.invalid-shift-type"
|
||||||
|
msgstr "The shift type can't not be found."
|
||||||
|
|
||||||
|
msgid "schedule.import.success"
|
||||||
|
msgstr "Schedule import successful."
|
||||||
|
|
||||||
|
msgid "validation.schedule-url.required"
|
||||||
|
msgstr "The schedule URL is required."
|
||||||
|
|
||||||
|
msgid "validation.schedule-url.url"
|
||||||
|
msgstr "The schedule URL needs to be of type URL."
|
||||||
|
|
||||||
|
msgid "validation.shift-type.required"
|
||||||
|
msgstr "The shift type is required."
|
||||||
|
|
||||||
|
msgid "validation.shift-type.int"
|
||||||
|
msgstr "The shift type has to ba a number."
|
||||||
|
|
||||||
|
msgid "validation.minutes-before.int"
|
||||||
|
msgstr "The minutes before the talk have to be an integer."
|
||||||
|
|
||||||
|
msgid "validation.minutes-after.int"
|
||||||
|
msgstr "The minutes after the talk have to be an integer."
|
||||||
|
|
|
@ -45,3 +45,63 @@ msgstr ""
|
||||||
"Please have a look at the "
|
"Please have a look at the "
|
||||||
"[contributors list on GitHub](https://github.com/engelsystem/engelsystem/graphs/contributors)"
|
"[contributors list on GitHub](https://github.com/engelsystem/engelsystem/graphs/contributors)"
|
||||||
" for a complete list."
|
" for a complete list."
|
||||||
|
|
||||||
|
msgid "form.load_schedule"
|
||||||
|
msgstr "Load schedule"
|
||||||
|
|
||||||
|
msgid "form.import"
|
||||||
|
msgstr "Import"
|
||||||
|
|
||||||
|
msgid "schedule.import.title"
|
||||||
|
msgstr "Import schedule"
|
||||||
|
|
||||||
|
msgid "schedule.import.text"
|
||||||
|
msgstr "This import creates rooms and creates, updates and deletes shifts according to the schedule.xml export."
|
||||||
|
|
||||||
|
msgid "schedule.import.load.title"
|
||||||
|
msgstr "Import schedule: Preview"
|
||||||
|
|
||||||
|
msgid "schedule.import.load.info"
|
||||||
|
msgstr "Import \"%s\" (version \"%s\")"
|
||||||
|
|
||||||
|
msgid "schedule.url"
|
||||||
|
msgstr "Schedule URL (schedule.xml)"
|
||||||
|
|
||||||
|
msgid "schedule.shift-type"
|
||||||
|
msgstr "Shift type"
|
||||||
|
|
||||||
|
msgid "schedule.minutes-before"
|
||||||
|
msgstr "Add minutes before talk begins"
|
||||||
|
|
||||||
|
msgid "schedule.minutes-after"
|
||||||
|
msgstr "Add minutes after talk ends"
|
||||||
|
|
||||||
|
msgid "schedule.import.request_error"
|
||||||
|
msgstr "Unable to load schedule."
|
||||||
|
|
||||||
|
msgid "schedule.import.rooms.add"
|
||||||
|
msgstr "Rooms to create"
|
||||||
|
|
||||||
|
msgid "schedule.import.shifts.add"
|
||||||
|
msgstr "Shifts to create"
|
||||||
|
|
||||||
|
msgid "schedule.import.shifts.update"
|
||||||
|
msgstr "Shifts to update"
|
||||||
|
|
||||||
|
msgid "schedule.import.shifts.delete"
|
||||||
|
msgstr "Shifts to delete"
|
||||||
|
|
||||||
|
msgid "schedule.import.rooms.name"
|
||||||
|
msgstr "Name"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.dates"
|
||||||
|
msgstr "Times"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.type"
|
||||||
|
msgstr "Type"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.title"
|
||||||
|
msgstr "Title"
|
||||||
|
|
||||||
|
msgid "schedule.import.shift.room"
|
||||||
|
msgstr "Room"
|
||||||
|
|
|
@ -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 %}
|
|
@ -13,6 +13,19 @@
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro select(name, data, label, selected) %}
|
||||||
|
<div class="form-group">
|
||||||
|
{% if label -%}
|
||||||
|
<label for="{{ name }}">{{ label }}</label>
|
||||||
|
{% endif %}
|
||||||
|
<select id="{{ name }}" name="{{ name }}" class="form-control">
|
||||||
|
{% for value,decription in data -%}
|
||||||
|
<option value="{{ value }}" {% if name == selected %} selected{% endif %}>{{ decription }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro hidden(name, value) %}
|
{% macro hidden(name, value) %}
|
||||||
<input type="hidden" id="{{ name }}" name="{{ name }}" value="{{ value }}">
|
<input type="hidden" id="{{ name }}" name="{{ name }}" value="{{ value }}">
|
||||||
{%- endmacro %}
|
{%- 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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -205,10 +205,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
$title = admin_groups_title();
|
$title = admin_groups_title();
|
||||||
$content = admin_groups();
|
$content = admin_groups();
|
||||||
return [$title, $content];
|
return [$title, $content];
|
||||||
case 'admin_import':
|
|
||||||
$title = admin_import_title();
|
|
||||||
$content = admin_import();
|
|
||||||
return [$title, $content];
|
|
||||||
case 'admin_shifts':
|
case 'admin_shifts':
|
||||||
$title = admin_shifts_title();
|
$title = admin_shifts_title();
|
||||||
$content = admin_shifts();
|
$content = admin_shifts();
|
||||||
|
@ -239,9 +235,15 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
return response($content, (int)$page);
|
return response($content, (int)$page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response(view('layouts/app', [
|
return response(
|
||||||
|
view(
|
||||||
|
'layouts/app',
|
||||||
|
[
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'content' => msg() . $content,
|
'content' => msg() . $content,
|
||||||
]), 200);
|
]
|
||||||
|
),
|
||||||
|
200
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ class RoomModelTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function createRoom()
|
public function createRoom()
|
||||||
{
|
{
|
||||||
$this->room_id = Room_create('test', false, null, null);
|
$this->room_id = Room_create('test', null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,14 +36,17 @@ trait HasDatabase
|
||||||
$this->database
|
$this->database
|
||||||
->getConnection()
|
->getConnection()
|
||||||
->table('migrations')
|
->table('migrations')
|
||||||
->insert([
|
->insert(
|
||||||
|
[
|
||||||
['migration' => '2018_01_01_000001_import_install_sql'],
|
['migration' => '2018_01_01_000001_import_install_sql'],
|
||||||
['migration' => '2018_01_01_000002_import_update_sql'],
|
['migration' => '2018_01_01_000002_import_update_sql'],
|
||||||
['migration' => '2018_01_01_000003_fix_old_tables'],
|
['migration' => '2018_01_01_000003_fix_old_tables'],
|
||||||
['migration' => '2018_01_01_000004_cleanup_group_privileges'],
|
['migration' => '2018_01_01_000004_cleanup_group_privileges'],
|
||||||
['migration' => '2018_01_01_000005_add_angel_supporter_permissions'],
|
['migration' => '2018_01_01_000005_add_angel_supporter_permissions'],
|
||||||
['migration' => '2018_12_27_000000_fix_missing_arrival_dates'],
|
['migration' => '2018_12_27_000000_fix_missing_arrival_dates'],
|
||||||
]);
|
['migration' => '2019_09_07_000000_migrate_admin_schedule_permissions'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
$migration->run(__DIR__ . '/../../db/migrations');
|
$migration->run(__DIR__ . '/../../db/migrations');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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