Reimplemented admin room pages
This commit is contained in:
parent
baca49c53b
commit
a464682b47
|
@ -157,6 +157,17 @@ $route->addGroup(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Rooms
|
||||||
|
$route->addGroup(
|
||||||
|
'/rooms',
|
||||||
|
function (RouteCollector $route): void {
|
||||||
|
$route->get('', 'Admin\\RoomsController@index');
|
||||||
|
$route->post('', 'Admin\\RoomsController@delete');
|
||||||
|
$route->get('/edit[/{room_id:\d+}]', 'Admin\\RoomsController@edit');
|
||||||
|
$route->post('/edit[/{room_id:\d+}]', 'Admin\\RoomsController@save');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// User
|
// User
|
||||||
$route->addGroup(
|
$route->addGroup(
|
||||||
'/user/{user_id:\d+}',
|
'/user/{user_id:\d+}',
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use Engelsystem\Helpers\Carbon;
|
use Engelsystem\Helpers\Carbon;
|
||||||
use Engelsystem\Models\AngelType;
|
use Engelsystem\Models\AngelType;
|
||||||
|
use Engelsystem\Models\Room;
|
||||||
use Engelsystem\Models\UserAngelType;
|
use Engelsystem\Models\UserAngelType;
|
||||||
use Engelsystem\ShiftsFilter;
|
use Engelsystem\ShiftsFilter;
|
||||||
use Engelsystem\ShiftsFilterRenderer;
|
use Engelsystem\ShiftsFilterRenderer;
|
||||||
|
@ -239,9 +240,13 @@ function angeltype_controller_shiftsFilterDays(AngelType $angeltype)
|
||||||
function angeltype_controller_shiftsFilter(AngelType $angeltype, $days)
|
function angeltype_controller_shiftsFilter(AngelType $angeltype, $days)
|
||||||
{
|
{
|
||||||
$request = request();
|
$request = request();
|
||||||
|
$roomIds = Room::query()
|
||||||
|
->select('id')
|
||||||
|
->pluck('id')
|
||||||
|
->toArray();
|
||||||
$shiftsFilter = new ShiftsFilter(
|
$shiftsFilter = new ShiftsFilter(
|
||||||
auth()->can('user_shifts_admin'),
|
auth()->can('user_shifts_admin'),
|
||||||
Room_ids(),
|
$roomIds,
|
||||||
[$angeltype->id]
|
[$angeltype->id]
|
||||||
);
|
);
|
||||||
$selected_day = date('Y-m-d');
|
$selected_day = date('Y-m-d');
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use Engelsystem\Models\AngelType;
|
use Engelsystem\Models\AngelType;
|
||||||
use Engelsystem\Models\News;
|
use Engelsystem\Models\News;
|
||||||
|
use Engelsystem\Models\Room;
|
||||||
use Engelsystem\Models\Shifts\Shift;
|
use Engelsystem\Models\Shifts\Shift;
|
||||||
use Engelsystem\ShiftsFilter;
|
use Engelsystem\ShiftsFilter;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ function public_dashboard_controller()
|
||||||
}
|
}
|
||||||
|
|
||||||
$angelTypes = collect(unrestricted_angeltypes());
|
$angelTypes = collect(unrestricted_angeltypes());
|
||||||
$rooms = $requestRooms ?: Rooms()->pluck('id')->toArray();
|
$rooms = $requestRooms ?: Room::orderBy('name')->get()->pluck('id')->toArray();
|
||||||
$angelTypes = $requestAngelTypes ?: $angelTypes->pluck('id')->toArray();
|
$angelTypes = $requestAngelTypes ?: $angelTypes->pluck('id')->toArray();
|
||||||
$filterValues = [
|
$filterValues = [
|
||||||
'userShiftsAdmin' => false,
|
'userShiftsAdmin' => false,
|
||||||
|
|
|
@ -73,8 +73,8 @@ function rooms_controller(): array
|
||||||
|
|
||||||
return match ($action) {
|
return match ($action) {
|
||||||
'view' => room_controller(),
|
'view' => room_controller(),
|
||||||
'list' => throw_redirect(page_link_to('admin_rooms')),
|
'list' => throw_redirect(page_link_to('admin/rooms')),
|
||||||
default => throw_redirect(page_link_to('admin_rooms')),
|
default => throw_redirect(page_link_to('admin/rooms')),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ function shift_edit_controller()
|
||||||
}
|
}
|
||||||
|
|
||||||
$rooms = [];
|
$rooms = [];
|
||||||
foreach (Rooms() as $room) {
|
foreach (Room::orderBy('name')->get() as $room) {
|
||||||
$rooms[$room->id] = $room->name;
|
$rooms[$room->id] = $room->name;
|
||||||
}
|
}
|
||||||
$angeltypes = AngelType::all()->pluck('name', 'id')->toArray();
|
$angeltypes = AngelType::all()->pluck('name', 'id')->toArray();
|
||||||
|
|
|
@ -12,7 +12,6 @@ $includeFiles = [
|
||||||
__DIR__ . '/../includes/sys_template.php',
|
__DIR__ . '/../includes/sys_template.php',
|
||||||
|
|
||||||
__DIR__ . '/../includes/model/NeededAngelTypes_model.php',
|
__DIR__ . '/../includes/model/NeededAngelTypes_model.php',
|
||||||
__DIR__ . '/../includes/model/Room_model.php',
|
|
||||||
__DIR__ . '/../includes/model/ShiftEntry_model.php',
|
__DIR__ . '/../includes/model/ShiftEntry_model.php',
|
||||||
__DIR__ . '/../includes/model/Shifts_model.php',
|
__DIR__ . '/../includes/model/Shifts_model.php',
|
||||||
__DIR__ . '/../includes/model/ShiftsFilter.php',
|
__DIR__ . '/../includes/model/ShiftsFilter.php',
|
||||||
|
@ -61,7 +60,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_rooms.php',
|
|
||||||
__DIR__ . '/../includes/pages/admin_shifts.php',
|
__DIR__ . '/../includes/pages/admin_shifts.php',
|
||||||
__DIR__ . '/../includes/pages/admin_user.php',
|
__DIR__ . '/../includes/pages/admin_user.php',
|
||||||
__DIR__ . '/../includes/pages/guest_login.php',
|
__DIR__ . '/../includes/pages/guest_login.php',
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Engelsystem\Models\Room;
|
|
||||||
use Engelsystem\ValidationResult;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate a name for a room.
|
|
||||||
*
|
|
||||||
* @param string $name The new name
|
|
||||||
* @param int $room_id The room id
|
|
||||||
* @return ValidationResult
|
|
||||||
*/
|
|
||||||
function Room_validate_name(string $name, int $room_id)
|
|
||||||
{
|
|
||||||
$valid = true;
|
|
||||||
if (empty($name)) {
|
|
||||||
$valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$roomCount = Room::query()
|
|
||||||
->where('name', $name)
|
|
||||||
->where('id', '!=', $room_id)
|
|
||||||
->count();
|
|
||||||
if ($roomCount) {
|
|
||||||
$valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ValidationResult($valid, $name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a list of rooms.
|
|
||||||
*
|
|
||||||
* @return Room[]|Collection
|
|
||||||
*/
|
|
||||||
function Rooms()
|
|
||||||
{
|
|
||||||
return Room::orderBy('name')->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns Room id array
|
|
||||||
*
|
|
||||||
* @return int[]
|
|
||||||
*/
|
|
||||||
function Room_ids()
|
|
||||||
{
|
|
||||||
return Room::query()
|
|
||||||
->select('id')
|
|
||||||
->pluck('id')
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a room
|
|
||||||
*
|
|
||||||
* @param Room $room
|
|
||||||
*/
|
|
||||||
function Room_delete(Room $room)
|
|
||||||
{
|
|
||||||
$room->delete();
|
|
||||||
engelsystem_log('Room deleted: ' . $room->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new room
|
|
||||||
*
|
|
||||||
* @param string $name Name of the room
|
|
||||||
* @param string|null $map_url URL to a map tha can be displayed in an iframe
|
|
||||||
* @param string|null $description
|
|
||||||
*
|
|
||||||
* @return null|int
|
|
||||||
*/
|
|
||||||
function Room_create(string $name, string $map_url = null, string $description = null, string $dect = null)
|
|
||||||
{
|
|
||||||
$room = new Room();
|
|
||||||
$room->name = $name;
|
|
||||||
$room->description = $description;
|
|
||||||
$room->map_url = $map_url;
|
|
||||||
$room->dect = $dect;
|
|
||||||
$room->save();
|
|
||||||
|
|
||||||
engelsystem_log(
|
|
||||||
'Room created: ' . $name
|
|
||||||
. ', dect: ' . $dect
|
|
||||||
. ', map_url: ' . $map_url
|
|
||||||
. ', description: ' . $description
|
|
||||||
);
|
|
||||||
|
|
||||||
return $room->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a room
|
|
||||||
*
|
|
||||||
* @param int $room_id The rooms id
|
|
||||||
* @param string $name Name of the room
|
|
||||||
* @param string|null $map_url URL to a map tha can be displayed in an iframe
|
|
||||||
* @param string|null $description Markdown description
|
|
||||||
*/
|
|
||||||
function Room_update(
|
|
||||||
int $room_id,
|
|
||||||
string $name,
|
|
||||||
string $map_url = null,
|
|
||||||
string $description = null,
|
|
||||||
string $dect = null
|
|
||||||
) {
|
|
||||||
$room = Room::find($room_id);
|
|
||||||
$room->name = $name;
|
|
||||||
$room->description = $description ?: null;
|
|
||||||
$room->map_url = $map_url ?: null;
|
|
||||||
$room->dect = $dect ?: null;
|
|
||||||
$room->save();
|
|
||||||
|
|
||||||
engelsystem_log(
|
|
||||||
'Room updated: ' . $name .
|
|
||||||
', dect: ' . $dect .
|
|
||||||
', map_url: ' . $map_url .
|
|
||||||
', description: ' . $description
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,238 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Engelsystem\Models\AngelType;
|
|
||||||
use Engelsystem\Models\Room;
|
|
||||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
|
||||||
use Engelsystem\Models\User\User;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function admin_rooms_title()
|
|
||||||
{
|
|
||||||
return __('Rooms');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function admin_rooms()
|
|
||||||
{
|
|
||||||
$rooms_source = Rooms();
|
|
||||||
$rooms = [];
|
|
||||||
$request = request();
|
|
||||||
|
|
||||||
foreach ($rooms_source as $room) {
|
|
||||||
$rooms[] = [
|
|
||||||
'name' => Room_name_render($room),
|
|
||||||
'dect' => icon_bool($room->dect),
|
|
||||||
'map_url' => icon_bool($room->map_url),
|
|
||||||
'actions' => table_buttons([
|
|
||||||
button(
|
|
||||||
page_link_to('admin_rooms', ['show' => 'edit', 'id' => $room->id]),
|
|
||||||
icon('pencil') . __('edit'),
|
|
||||||
'btn-sm'
|
|
||||||
),
|
|
||||||
button(
|
|
||||||
page_link_to('admin_rooms', ['show' => 'delete', 'id' => $room->id]),
|
|
||||||
icon('trash') . __('delete'),
|
|
||||||
'btn-sm'
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$room = null;
|
|
||||||
if ($request->has('show')) {
|
|
||||||
$msg = '';
|
|
||||||
$name = '';
|
|
||||||
$map_url = null;
|
|
||||||
$description = null;
|
|
||||||
$dect = null;
|
|
||||||
$room_id = 0;
|
|
||||||
|
|
||||||
$angeltypes_source = AngelType::all();
|
|
||||||
$angeltypes = [];
|
|
||||||
$angeltypes_count = [];
|
|
||||||
foreach ($angeltypes_source as $angeltype) {
|
|
||||||
$angeltypes[$angeltype->id] = $angeltype->name;
|
|
||||||
$angeltypes_count[$angeltype->id] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (test_request_int('id')) {
|
|
||||||
$room = Room::find($request->input('id'));
|
|
||||||
if (!$room) {
|
|
||||||
throw_redirect(page_link_to('admin_rooms'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$room_id = $room->id;
|
|
||||||
$name = $room->name;
|
|
||||||
$map_url = $room->map_url;
|
|
||||||
$description = $room->description;
|
|
||||||
$dect = $room->dect;
|
|
||||||
|
|
||||||
$angeltypes_count = NeededAngelType::whereRoomId($room_id)
|
|
||||||
->pluck('count', 'angel_type_id')
|
|
||||||
->toArray() + $angeltypes_count;
|
|
||||||
}
|
|
||||||
if ($request->input('show') == 'edit') {
|
|
||||||
if ($request->hasPostData('submit')) {
|
|
||||||
$valid = true;
|
|
||||||
|
|
||||||
if ($request->has('name') && strlen(strip_request_tags('name')) > 0) {
|
|
||||||
$result = Room_validate_name(strip_request_tags('name'), $room_id);
|
|
||||||
if (!$result->isValid()) {
|
|
||||||
$valid = false;
|
|
||||||
$msg .= error(__('This name is already in use.'), true);
|
|
||||||
} else {
|
|
||||||
$name = $result->getValue();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$valid = false;
|
|
||||||
$msg .= error(__('Please enter a name.'), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->has('map_url')) {
|
|
||||||
$map_url = strip_request_item('map_url');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->has('description')) {
|
|
||||||
$description = strip_request_item_nl('description');
|
|
||||||
}
|
|
||||||
if ($request->has('dect')) {
|
|
||||||
$dect = strip_request_item_nl('dect');
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($angeltypes as $angeltype_id => $angeltype) {
|
|
||||||
$angeltypes_count[$angeltype_id] = 0;
|
|
||||||
$queryKey = 'angeltype_count_' . $angeltype_id;
|
|
||||||
if (!$request->has($queryKey)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preg_match('/^\d{1,4}$/', $request->input($queryKey))) {
|
|
||||||
$angeltypes_count[$angeltype_id] = $request->input($queryKey);
|
|
||||||
} else {
|
|
||||||
$valid = false;
|
|
||||||
$msg .= error(sprintf(
|
|
||||||
__('Please enter needed angels for type %s.'),
|
|
||||||
$angeltype
|
|
||||||
), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($valid) {
|
|
||||||
if (empty($room_id)) {
|
|
||||||
$room_id = Room_create($name, $map_url, $description, $dect);
|
|
||||||
} else {
|
|
||||||
Room_update($room_id, $name, $map_url, $description, $dect);
|
|
||||||
}
|
|
||||||
|
|
||||||
NeededAngelType::whereRoomId($room_id)->delete();
|
|
||||||
$needed_angeltype_info = [];
|
|
||||||
foreach ($angeltypes_count as $angeltype_id => $angeltype_count) {
|
|
||||||
$angeltype = AngelType::find($angeltype_id);
|
|
||||||
if (!empty($angeltype) && $angeltype_count > 0) {
|
|
||||||
$neededAngelType = new NeededAngelType();
|
|
||||||
$neededAngelType->room_id = $room_id;
|
|
||||||
$neededAngelType->angelType()->associate($angeltype);
|
|
||||||
$neededAngelType->count = $angeltype_count;
|
|
||||||
$neededAngelType->save();
|
|
||||||
|
|
||||||
$needed_angeltype_info[] = $angeltype->name . ': ' . $angeltype_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
engelsystem_log(
|
|
||||||
'Set needed angeltypes of room ' . $name
|
|
||||||
. ' to: ' . join(', ', $needed_angeltype_info)
|
|
||||||
);
|
|
||||||
success(__('Room saved.'));
|
|
||||||
throw_redirect(page_link_to('admin_rooms'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$angeltypes_count_form = [];
|
|
||||||
foreach ($angeltypes as $angeltype_id => $angeltypeName) {
|
|
||||||
$angeltypes_count_form[] = div('col-lg-4 col-md-6 col-xs-6', [
|
|
||||||
form_spinner('angeltype_count_' . $angeltype_id, $angeltypeName, $angeltypes_count[$angeltype_id]),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return page_with_title(admin_rooms_title(), [
|
|
||||||
buttons([
|
|
||||||
button(page_link_to('admin_rooms'), __('back'), 'back'),
|
|
||||||
]),
|
|
||||||
$msg,
|
|
||||||
form([
|
|
||||||
div('row', [
|
|
||||||
div('col-md-6', [
|
|
||||||
form_text('name', __('Name'), $name, false, 35),
|
|
||||||
form_text('dect', __('DECT'), $dect),
|
|
||||||
form_text('map_url', __('Map URL'), $map_url),
|
|
||||||
form_info('', __('The map url is used to display an iframe on the room page.')),
|
|
||||||
form_textarea('description', __('Description'), $description),
|
|
||||||
form_info('', __('Please use markdown for the description.')),
|
|
||||||
]),
|
|
||||||
div('col-md-6', [
|
|
||||||
div('row', [
|
|
||||||
div('col-md-12', [
|
|
||||||
form_info(__('Needed angels:')),
|
|
||||||
]),
|
|
||||||
join($angeltypes_count_form),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
form_submit('submit', __('Save')),
|
|
||||||
]),
|
|
||||||
], true);
|
|
||||||
} elseif ($request->input('show') == 'delete') {
|
|
||||||
if ($request->hasPostData('ack')) {
|
|
||||||
$room = Room::find($room_id);
|
|
||||||
$shifts = $room->shifts;
|
|
||||||
foreach ($shifts as $shift) {
|
|
||||||
$shift = Shift($shift);
|
|
||||||
foreach ($shift->shiftEntries as $entry) {
|
|
||||||
event('shift.entry.deleting', [
|
|
||||||
'user' => User::find($entry['user_id']),
|
|
||||||
'start' => $shift->start,
|
|
||||||
'end' => $shift->end,
|
|
||||||
'name' => $shift->shiftType->name,
|
|
||||||
'title' => $shift->title,
|
|
||||||
'type' => $entry->angelType->name,
|
|
||||||
'room' => $room,
|
|
||||||
'freeloaded' => (bool) $entry['freeloaded'],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Room_delete($room);
|
|
||||||
|
|
||||||
success(sprintf(__('Room %s deleted.'), $name));
|
|
||||||
throw_redirect(page_link_to('admin_rooms'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return page_with_title(admin_rooms_title(), [
|
|
||||||
buttons([
|
|
||||||
button(page_link_to('admin_rooms'), __('back'), 'back'),
|
|
||||||
]),
|
|
||||||
sprintf(__('Do you want to delete room %s?'), $name),
|
|
||||||
form([
|
|
||||||
form_submit('ack', __('Delete'), 'delete btn-danger'),
|
|
||||||
], page_link_to('admin_rooms', ['show' => 'delete', 'id' => $room_id])),
|
|
||||||
], true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return page_with_title(admin_rooms_title(), [
|
|
||||||
buttons([
|
|
||||||
button(page_link_to('admin_rooms', ['show' => 'edit']), __('add')),
|
|
||||||
]),
|
|
||||||
msg(),
|
|
||||||
table([
|
|
||||||
'name' => __('Name'),
|
|
||||||
'dect' => __('DECT'),
|
|
||||||
'map_url' => __('Map'),
|
|
||||||
'actions' => '',
|
|
||||||
], $rooms),
|
|
||||||
], true);
|
|
||||||
}
|
|
|
@ -43,11 +43,8 @@ function admin_shifts()
|
||||||
$shift_over_midnight = true;
|
$shift_over_midnight = true;
|
||||||
|
|
||||||
// Locations laden
|
// Locations laden
|
||||||
$rooms = Rooms();
|
$rooms = Room::orderBy('name')->get();
|
||||||
$room_array = [];
|
$room_array = $rooms->pluck('name', 'id')->toArray();
|
||||||
foreach ($rooms as $room) {
|
|
||||||
$room_array[$room->id] = $room->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load angeltypes
|
// Load angeltypes
|
||||||
/** @var AngelType[] $types */
|
/** @var AngelType[] $types */
|
||||||
|
|
|
@ -115,7 +115,7 @@ function update_ShiftsFilter(ShiftsFilter $shiftsFilter, $user_shifts_admin, $da
|
||||||
*/
|
*/
|
||||||
function load_rooms()
|
function load_rooms()
|
||||||
{
|
{
|
||||||
$rooms = Rooms();
|
$rooms = Room::orderBy('name')->get();
|
||||||
if ($rooms->isEmpty()) {
|
if ($rooms->isEmpty()) {
|
||||||
error(__('The administration has not configured any rooms yet.'));
|
error(__('The administration has not configured any rooms yet.'));
|
||||||
throw_redirect(page_link_to('/'));
|
throw_redirect(page_link_to('/'));
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Engelsystem\Models\Question;
|
use Engelsystem\Models\Question;
|
||||||
|
use Engelsystem\Models\Room;
|
||||||
use Engelsystem\UserHintsRenderer;
|
use Engelsystem\UserHintsRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,7 +91,7 @@ function make_navigation()
|
||||||
'admin/questions' => ['Answer questions', 'question.edit'],
|
'admin/questions' => ['Answer questions', 'question.edit'],
|
||||||
'shifttypes' => 'Shifttypes',
|
'shifttypes' => 'Shifttypes',
|
||||||
'admin_shifts' => 'Create shifts',
|
'admin_shifts' => 'Create shifts',
|
||||||
'admin_rooms' => 'Rooms',
|
'admin/rooms' => ['room.rooms', 'admin_rooms'],
|
||||||
'admin_groups' => 'Grouprights',
|
'admin_groups' => 'Grouprights',
|
||||||
'admin/schedule' => ['schedule.import', 'schedule.import'],
|
'admin/schedule' => ['schedule.import', 'schedule.import'],
|
||||||
'admin/logs' => ['log.log', 'admin_log'],
|
'admin/logs' => ['log.log', 'admin_log'],
|
||||||
|
@ -152,10 +153,10 @@ function make_room_navigation($menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of all rooms
|
// Get a list of all rooms
|
||||||
$rooms = Rooms();
|
$rooms = Room::orderBy('name')->get();
|
||||||
$room_menu = [];
|
$room_menu = [];
|
||||||
if (auth()->can('admin_rooms')) {
|
if (auth()->can('admin_rooms')) {
|
||||||
$room_menu[] = toolbar_dropdown_item(page_link_to('admin_rooms'), __('Manage rooms'), false, 'list');
|
$room_menu[] = toolbar_dropdown_item(page_link_to('admin/rooms'), __('Manage rooms'), false, 'list');
|
||||||
}
|
}
|
||||||
if (count($room_menu) > 0) {
|
if (count($room_menu) > 0) {
|
||||||
$room_menu[] = toolbar_dropdown_item_divider();
|
$room_menu[] = toolbar_dropdown_item_divider();
|
||||||
|
|
|
@ -61,15 +61,10 @@ function Room_view(Room $room, ShiftsFilterRenderer $shiftsFilterRenderer, Shift
|
||||||
$assignNotice,
|
$assignNotice,
|
||||||
auth()->can('admin_rooms') ? buttons([
|
auth()->can('admin_rooms') ? buttons([
|
||||||
button(
|
button(
|
||||||
page_link_to('admin_rooms', ['show' => 'edit', 'id' => $room->id]),
|
page_link_to('admin/rooms/edit/' . $room->id),
|
||||||
icon('pencil') . __('edit'),
|
icon('pencil') . __('edit'),
|
||||||
'btn'
|
'btn'
|
||||||
),
|
),
|
||||||
button(
|
|
||||||
page_link_to('admin_rooms', ['show' => 'delete', 'id' => $room->id]),
|
|
||||||
icon('trash') . __('delete'),
|
|
||||||
'btn'
|
|
||||||
),
|
|
||||||
]) : '',
|
]) : '',
|
||||||
$dect,
|
$dect,
|
||||||
$description,
|
$description,
|
||||||
|
|
|
@ -254,6 +254,13 @@ ready(() => {
|
||||||
document.querySelectorAll('[data-bs-toggle="popover"]').forEach((element) => new bootstrap.Popover(element));
|
document.querySelectorAll('[data-bs-toggle="popover"]').forEach((element) => new bootstrap.Popover(element));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init Bootstrap Tooltips
|
||||||
|
*/
|
||||||
|
ready(() => {
|
||||||
|
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach((element) => new bootstrap.Tooltip(element));
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show oauth buttons on welcome title click
|
* Show oauth buttons on welcome title click
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -46,6 +46,7 @@ $form-label-font-weight: $font-weight-bold;
|
||||||
@import '~bootstrap/scss/list-group';
|
@import '~bootstrap/scss/list-group';
|
||||||
@import '~bootstrap/scss/close';
|
@import '~bootstrap/scss/close';
|
||||||
@import '~bootstrap/scss/popover';
|
@import '~bootstrap/scss/popover';
|
||||||
|
@import '~bootstrap/scss/tooltip';
|
||||||
|
|
||||||
@import '~bootstrap/scss/helpers';
|
@import '~bootstrap/scss/helpers';
|
||||||
|
|
||||||
|
|
|
@ -209,3 +209,12 @@ msgstr "Arbeitseinsatz erfolgreich bearbeitet."
|
||||||
|
|
||||||
msgid "worklog.delete.success"
|
msgid "worklog.delete.success"
|
||||||
msgstr "Arbeitseinsatz erfolgreich gelöscht."
|
msgstr "Arbeitseinsatz erfolgreich gelöscht."
|
||||||
|
|
||||||
|
msgid "room.edit.success"
|
||||||
|
msgstr "Raum erfolgreich bearbeitet."
|
||||||
|
|
||||||
|
msgid "room.delete.success"
|
||||||
|
msgstr "Raum erfolgreich gelöscht."
|
||||||
|
|
||||||
|
msgid "validation.name.exists"
|
||||||
|
msgstr "Der Name wird bereits verwendet."
|
||||||
|
|
|
@ -2812,6 +2812,12 @@ msgstr "Aktualisiert"
|
||||||
msgid "form.cancel"
|
msgid "form.cancel"
|
||||||
msgstr "Abbrechen"
|
msgstr "Abbrechen"
|
||||||
|
|
||||||
|
msgid "form.markdown"
|
||||||
|
msgstr "Du kannst hier Markdown verwenden"
|
||||||
|
|
||||||
|
msgid "form.required"
|
||||||
|
msgstr "Pflichtfeld"
|
||||||
|
|
||||||
msgid "schedule.import"
|
msgid "schedule.import"
|
||||||
msgstr "Programm importieren"
|
msgstr "Programm importieren"
|
||||||
|
|
||||||
|
@ -3189,3 +3195,30 @@ msgstr "E-Mail"
|
||||||
|
|
||||||
msgid "registration.register"
|
msgid "registration.register"
|
||||||
msgstr "Registrieren"
|
msgstr "Registrieren"
|
||||||
|
|
||||||
|
msgid "room.rooms"
|
||||||
|
msgstr "Räume"
|
||||||
|
|
||||||
|
msgid "room.name"
|
||||||
|
msgstr "Name"
|
||||||
|
|
||||||
|
msgid "room.dect"
|
||||||
|
msgstr "DECT"
|
||||||
|
|
||||||
|
msgid "room.map_url"
|
||||||
|
msgstr "Karte"
|
||||||
|
|
||||||
|
msgid "room.description"
|
||||||
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
|
msgid "room.required_angels"
|
||||||
|
msgstr "Benötigte Engel"
|
||||||
|
|
||||||
|
msgid "room.map_url.info"
|
||||||
|
msgstr "Die Karte wird auf der Raum-Seite als iframe eingebettet."
|
||||||
|
|
||||||
|
msgid "room.create.title"
|
||||||
|
msgstr "Raum erstellen"
|
||||||
|
|
||||||
|
msgid "room.edit.title"
|
||||||
|
msgstr "Raum bearbeiten"
|
||||||
|
|
|
@ -208,3 +208,12 @@ msgstr "Work log successfully updated."
|
||||||
|
|
||||||
msgid "worklog.delete.success"
|
msgid "worklog.delete.success"
|
||||||
msgstr "Work log successfully deleted."
|
msgstr "Work log successfully deleted."
|
||||||
|
|
||||||
|
msgid "room.edit.success"
|
||||||
|
msgstr "Room edited successfully."
|
||||||
|
|
||||||
|
msgid "room.delete.success"
|
||||||
|
msgstr "Room successfully deleted."
|
||||||
|
|
||||||
|
msgid "validation.name.exists"
|
||||||
|
msgstr "The name is already used."
|
||||||
|
|
|
@ -79,6 +79,12 @@ msgstr "Updated"
|
||||||
msgid "form.cancel"
|
msgid "form.cancel"
|
||||||
msgstr "Cancel"
|
msgstr "Cancel"
|
||||||
|
|
||||||
|
msgid "form.required"
|
||||||
|
msgstr "Required"
|
||||||
|
|
||||||
|
msgid "form.markdown"
|
||||||
|
msgstr "You can use Markdown here"
|
||||||
|
|
||||||
msgid "schedule.import"
|
msgid "schedule.import"
|
||||||
msgstr "Import schedule"
|
msgstr "Import schedule"
|
||||||
|
|
||||||
|
@ -452,3 +458,30 @@ msgstr "E-Mail"
|
||||||
|
|
||||||
msgid "registration.register"
|
msgid "registration.register"
|
||||||
msgstr "Register"
|
msgstr "Register"
|
||||||
|
|
||||||
|
msgid "room.rooms"
|
||||||
|
msgstr "Rooms"
|
||||||
|
|
||||||
|
msgid "room.name"
|
||||||
|
msgstr "Name"
|
||||||
|
|
||||||
|
msgid "room.dect"
|
||||||
|
msgstr "DECT"
|
||||||
|
|
||||||
|
msgid "room.map_url"
|
||||||
|
msgstr "Map"
|
||||||
|
|
||||||
|
msgid "room.description"
|
||||||
|
msgstr "Description"
|
||||||
|
|
||||||
|
msgid "room.required_angels"
|
||||||
|
msgstr "Required angels"
|
||||||
|
|
||||||
|
msgid "room.map_url.info"
|
||||||
|
msgstr "The map will be embedded on the room page as an iframe."
|
||||||
|
|
||||||
|
msgid "room.create.title"
|
||||||
|
msgstr "Create room"
|
||||||
|
|
||||||
|
msgid "room.edit.title"
|
||||||
|
msgstr "Edit room"
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
{% extends 'admin/rooms/index.twig' %}
|
||||||
|
{% import 'macros/base.twig' as m %}
|
||||||
|
{% import 'macros/form.twig' as f %}
|
||||||
|
|
||||||
|
{% block title %}{{ room ? __('room.edit.title') : __('room.create.title') }}{% endblock %}
|
||||||
|
|
||||||
|
{% block row_content %}
|
||||||
|
<form method="post">
|
||||||
|
{{ csrf() }}
|
||||||
|
{{ f.hidden('id', room ? room.id : '') }}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
{{ f.input(
|
||||||
|
'name',
|
||||||
|
__('room.name'),
|
||||||
|
null,
|
||||||
|
{'required': true, 'entry_required_icon': true, 'value': f.formData('room', room ? room.name : '')}
|
||||||
|
) }}
|
||||||
|
|
||||||
|
{{ f.input('dect', __('room.dect'), null, {'value': f.formData('dect', room ? room.dect : '')}) }}
|
||||||
|
{{ f.input(
|
||||||
|
'map_url',
|
||||||
|
__('room.map_url'),
|
||||||
|
'url',
|
||||||
|
{'value': f.formData('map_url', room ? room.map_url : ''), 'info': __('room.map_url.info')}
|
||||||
|
) }}
|
||||||
|
|
||||||
|
{{ f.textarea(
|
||||||
|
'description',
|
||||||
|
__('room.description'),
|
||||||
|
{'value': f.formData('description', room ? room.description : ''), 'rows': 5, 'info': __('form.markdown')}
|
||||||
|
) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<h4>{{ __('room.required_angels') }}</h4>
|
||||||
|
{% for types in angel_types.chunk(3) %}
|
||||||
|
<div class="row">
|
||||||
|
{% for angel_type in types %}
|
||||||
|
{% set needed = needed_angel_types ? needed_angel_types.where('angel_type_id', angel_type.id).first() : null %}
|
||||||
|
{% set name = 'angel_type_' ~ angel_type.id %}
|
||||||
|
<div class="col-md-4">
|
||||||
|
{{ f.number(
|
||||||
|
name,
|
||||||
|
angel_type.name,
|
||||||
|
{'value': f.formData(name, needed ? needed.count : 0), 'min': 0, 'step': 1}
|
||||||
|
) }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="btn-group">
|
||||||
|
{{ f.submit(__('form.save'), {'icon_left': 'save'}) }}
|
||||||
|
{% if room %}
|
||||||
|
{{ f.submit(__('form.delete'), {'name': 'delete', 'btn_type': 'danger', 'icon_left': 'trash'}) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,71 @@
|
||||||
|
{% extends 'layouts/app.twig' %}
|
||||||
|
{% import 'macros/base.twig' as m %}
|
||||||
|
{% import 'macros/form.twig' as f %}
|
||||||
|
|
||||||
|
{% block title %}{{ __('room.rooms') }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<h1>
|
||||||
|
{{ block('title') }}
|
||||||
|
|
||||||
|
{% if is_index|default(false) %}
|
||||||
|
{{ m.button(m.icon('plus-lg'), url('/admin/rooms/edit'), 'secondary') }}
|
||||||
|
{% endif %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{% include 'layouts/parts/messages.twig' %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
{% block row_content %}
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('room.name') }}</th>
|
||||||
|
<th>{{ __('room.dect') }}</th>
|
||||||
|
<th>{{ __('room.map_url') }}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for room in rooms %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ m.icon('pin-map-fill') }}
|
||||||
|
<a href="{{ url('/rooms', {'action': 'view', 'room_id': room.id}) }}">
|
||||||
|
{{ room.name }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>{{ m.iconBool(room.dect) }}</td>
|
||||||
|
|
||||||
|
<td>{{ m.iconBool(room.map_url) }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="d-flex ms-auto">
|
||||||
|
|
||||||
|
{{ m.button(m.icon('pencil'), url('admin/rooms/edit/' ~ room.id), null, 'sm', __('form.edit')) }}
|
||||||
|
|
||||||
|
<form method="post" class="ps-1">
|
||||||
|
{{ csrf() }}
|
||||||
|
{{ f.hidden('id', room.id) }}
|
||||||
|
{{ f.button(m.icon('trash'), {'title': __('form.delete'), 'name': 'delete', 'type': 'submit', 'btn_type': 'danger', 'size': 'sm'}) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -6,6 +6,12 @@
|
||||||
<span class="bi bi-{{ icon }} {% if color %} text-{{ color }} {% endif %}"></span>
|
<span class="bi bi-{{ icon }} {% if color %} text-{{ color }} {% endif %}"></span>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro iconBool(value) %}
|
||||||
|
<span class="text-{% if value %}success{% else %}danger{% endif %}">
|
||||||
|
{{ _self.icon(value ? 'check-lg' : 'x-lg') }}
|
||||||
|
</span>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro alert(message, type, raw) %}
|
{% macro alert(message, type, raw) %}
|
||||||
<div class="alert alert-{{ type|default('info') }}" role="alert">
|
<div class="alert alert-{{ type|default('info') }}" role="alert">
|
||||||
{%- if raw|default(false) -%}
|
{%- if raw|default(false) -%}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
{% macro entry_required() %}
|
{% macro entry_required() %}
|
||||||
<span class="bi bi-exclamation-triangle text-info"></span>
|
<span class="text-info" title="{{ __('form.required') }}">*</span>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro info(text) %}
|
||||||
|
<span class="bi bi-info-circle-fill text-info" data-bs-toggle="tooltip" title="{{ text | e('html_attr') }}"></span>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro input(name, label, type, opt) %}
|
{% macro input(name, label, type, opt) %}
|
||||||
|
@ -10,6 +14,9 @@
|
||||||
{% if opt.entry_required_icon|default(false) %}
|
{% if opt.entry_required_icon|default(false) %}
|
||||||
{{ _self.entry_required() }}
|
{{ _self.entry_required() }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if opt.info is defined %}
|
||||||
|
{{ _self.info(opt.info) }}
|
||||||
|
{% endif %}
|
||||||
</label>
|
</label>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
<input
|
<input
|
||||||
|
@ -35,10 +42,58 @@
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro number(name, label, opt) %}
|
||||||
|
<div class="mb-3">
|
||||||
|
{% if label -%}
|
||||||
|
<label class="form-label" for="{{ name }}">{{ label }}</label>
|
||||||
|
{% if opt.entry_required_icon|default(false) %}
|
||||||
|
{{ _self.entry_required() }}
|
||||||
|
{% endif %}
|
||||||
|
{% if opt.info is defined %}
|
||||||
|
{{ _self.info(opt.info) }}
|
||||||
|
{% endif %}
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<input
|
||||||
|
type="number" class="form-control"
|
||||||
|
id="{{ name }}" name="{{ name }}"
|
||||||
|
value="{{ opt.value|default('')|escape('html_attr') }}"
|
||||||
|
{%- if opt.min is defined %} min="{{ opt.min }}"{% endif %}
|
||||||
|
{%- if opt.max is defined %} max="{{ opt.max }}"{% endif %}
|
||||||
|
{%- if opt.step is defined %} step="{{ opt.step }}"{% endif %}
|
||||||
|
{%- if opt.required|default(false) %}
|
||||||
|
required
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if opt.disabled|default(false) %}
|
||||||
|
disabled
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if opt.readonly|default(false) %}
|
||||||
|
readonly
|
||||||
|
{%- endif -%}
|
||||||
|
>
|
||||||
|
|
||||||
|
<button class="btn btn-secondary spinner-down" type="button" data-input-id="{{ name }}">
|
||||||
|
<span class="bi bi-dash-lg"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn btn-secondary spinner-up" type="button" data-input-id="{{ name }}">
|
||||||
|
<span class="bi bi-plus-lg"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro textarea(name, label, opt) %}
|
{% macro textarea(name, label, opt) %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
{% if label -%}
|
{% if label -%}
|
||||||
<label class="form-label" for="{{ name }}">{{ label }}</label>
|
<label class="form-label" for="{{ name }}">{{ label }}</label>
|
||||||
|
{% if opt.entry_required_icon|default(false) %}
|
||||||
|
{{ _self.entry_required() }}
|
||||||
|
{% endif %}
|
||||||
|
{% if opt.info is defined %}
|
||||||
|
{{ _self.info(opt.info) }}
|
||||||
|
{% endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
<textarea class="form-control" id="{{ name }}" name="{{ name }}"
|
<textarea class="form-control" id="{{ name }}" name="{{ name }}"
|
||||||
{%- if opt.required|default(false) %}
|
{%- if opt.required|default(false) %}
|
||||||
|
@ -59,6 +114,9 @@
|
||||||
{% if opt.entry_required_icon|default(false) %}
|
{% if opt.entry_required_icon|default(false) %}
|
||||||
{{ _self.entry_required() }}
|
{{ _self.entry_required() }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if opt.info is defined %}
|
||||||
|
{{ _self.info(opt.info) }}
|
||||||
|
{% endif %}
|
||||||
</label>
|
</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<select id="{{ name }}" name="{{ name }}"
|
<select id="{{ name }}" name="{{ name }}"
|
||||||
|
@ -74,18 +132,22 @@
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro checkbox(name, label, checked, value, disabled, raw_label) %}
|
{% macro checkbox(name, label, checked, value, disabled, raw_label, opt) %}
|
||||||
<div class="form-check mb-3">
|
<div class="form-check mb-3">
|
||||||
<input class="form-check-input" type="checkbox" id="{{ name }}" name="{{ name }}" value="{{ value|default('1') }}"
|
<input class="form-check-input" type="checkbox" id="{{ name }}" name="{{ name }}"
|
||||||
|
value="{{ value|default('1') }}"
|
||||||
{%- if checked|default(false) %} checked{% endif %}
|
{%- if checked|default(false) %} checked{% endif %}
|
||||||
{%- if disabled|default(false) %} disabled{% endif %}
|
{%- if disabled|default(false) %} disabled{% endif %}
|
||||||
/>
|
>
|
||||||
<label class="form-check-label" for="{{ name }}">
|
<label class="form-check-label" for="{{ name }}">
|
||||||
{%- if raw_label|default(false) -%}
|
{%- if raw_label|default(false) -%}
|
||||||
{{ label|raw }}
|
{{ label|raw }}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{{ label }}
|
{{ label }}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
{% if opt.info is defined %}
|
||||||
|
{{ _self.info(opt.info) }}
|
||||||
|
{% endif %}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
@ -103,7 +165,9 @@
|
||||||
{%- if opt.title is defined %} title="{{ opt.title }}"{% endif %}
|
{%- if opt.title is defined %} title="{{ opt.title }}"{% endif %}
|
||||||
{%- if opt.value is defined or opt.name is defined %} value="{{ opt.value|default('1') }}"{% endif -%}
|
{%- if opt.value is defined or opt.name is defined %} value="{{ opt.value|default('1') }}"{% endif -%}
|
||||||
>
|
>
|
||||||
|
{%- if opt.icon_left is defined %}<span class="bi bi-{{ opt.icon_left }}"></span>{% endif %}
|
||||||
{{ label }}
|
{{ label }}
|
||||||
|
{%- if opt.icon_right is defined %}<span class="bi bi-{{ opt.icon_right }}"></span>{% endif %}
|
||||||
</button>
|
</button>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
@ -113,10 +177,15 @@
|
||||||
|
|
||||||
{% macro switch(name, label, checked, opt) %}
|
{% macro switch(name, label, checked, opt) %}
|
||||||
<div class="form-check form-switch mb-3">
|
<div class="form-check form-switch mb-3">
|
||||||
<input class="form-check-input" type="checkbox" id="{{ name }}" name="{{ name }}" value="{{ opt.value|default('1') }}"
|
<input class="form-check-input" type="checkbox" id="{{ name }}" name="{{ name }}"
|
||||||
|
value="{{ opt.value|default('1') }}"
|
||||||
{%- if checked|default(false) %} checked{% endif %}
|
{%- if checked|default(false) %} checked{% endif %}
|
||||||
{%- if opt.disabled|default(false) %} disabled{% endif %}
|
{%- if opt.disabled|default(false) %} disabled{% endif %}
|
||||||
>
|
>
|
||||||
<label class="form-check-label" for="{{ name }}">{{ label }}</label>
|
<label class="form-check-label" for="{{ name }}">{{ label }}</label>
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro formData(name, default) -%}
|
||||||
|
{{ session_pop('form-data-' ~ name, default) }}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
|
@ -359,6 +359,10 @@
|
||||||
<h4><code>icon(icon_name)</code></h4>
|
<h4><code>icon(icon_name)</code></h4>
|
||||||
<p>{{ m.icon('star') }}</p>
|
<p>{{ m.icon('star') }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h4><code>iconBool(true)</code></h4>
|
||||||
|
<p>{{ m.iconBool(true) }} {{ m.iconBool(false) }}</p>
|
||||||
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<h4><code>alert(message, type)</code></h4>
|
<h4><code>alert(message, type)</code></h4>
|
||||||
<p>{{ m.alert('Test content', 'info') }}</p>
|
<p>{{ m.alert('Test content', 'info') }}</p>
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Controllers\Admin;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\BaseController;
|
||||||
|
use Engelsystem\Controllers\HasUserNotifications;
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Redirector;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use Engelsystem\Models\AngelType;
|
||||||
|
use Engelsystem\Models\Room;
|
||||||
|
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class RoomsController extends BaseController
|
||||||
|
{
|
||||||
|
use HasUserNotifications;
|
||||||
|
|
||||||
|
/** @var array<string> */
|
||||||
|
protected array $permissions = [
|
||||||
|
'admin_rooms',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected LoggerInterface $log,
|
||||||
|
protected Room $room,
|
||||||
|
protected Redirector $redirect,
|
||||||
|
protected Response $response
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): Response
|
||||||
|
{
|
||||||
|
$rooms = $this->room
|
||||||
|
->orderBy('name')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return $this->response->withView(
|
||||||
|
'admin/rooms/index',
|
||||||
|
['rooms' => $rooms, 'is_index' => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Request $request): Response
|
||||||
|
{
|
||||||
|
$roomId = (int) $request->getAttribute('room_id');
|
||||||
|
|
||||||
|
$room = $this->room->find($roomId);
|
||||||
|
|
||||||
|
return $this->showEdit($room);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(Request $request): Response
|
||||||
|
{
|
||||||
|
$roomId = (int) $request->getAttribute('room_id');
|
||||||
|
|
||||||
|
/** @var Room $room */
|
||||||
|
$room = $this->room->findOrNew($roomId);
|
||||||
|
/** @var Collection|AngelType[] $angelTypes */
|
||||||
|
$angelTypes = AngelType::all();
|
||||||
|
$validation = [];
|
||||||
|
foreach ($angelTypes as $angelType) {
|
||||||
|
$validation['angel_type_' . $angelType->id] = 'optional|int';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->request->has('delete')) {
|
||||||
|
return $this->delete($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->validate(
|
||||||
|
$request,
|
||||||
|
[
|
||||||
|
'name' => 'required',
|
||||||
|
'description' => 'required|optional',
|
||||||
|
'dect' => 'required|optional',
|
||||||
|
'map_url' => 'optional|url',
|
||||||
|
] + $validation
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Room::whereName($data['name'])->where('id', '!=', $room->id)->exists()) {
|
||||||
|
throw new ValidationException((new Validator())->addErrors(['name' => ['validation.name.exists']]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$room->name = $data['name'];
|
||||||
|
$room->description = $data['description'];
|
||||||
|
$room->dect = $data['dect'];
|
||||||
|
$room->map_url = $data['map_url'];
|
||||||
|
|
||||||
|
$room->save();
|
||||||
|
$room->neededAngelTypes()->getQuery()->delete();
|
||||||
|
$angelsInfo = '';
|
||||||
|
|
||||||
|
foreach ($angelTypes as $angelType) {
|
||||||
|
$count = $data['angel_type_' . $angelType->id];
|
||||||
|
if (!$count) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$neededAngelType = new NeededAngelType();
|
||||||
|
|
||||||
|
$neededAngelType->room()->associate($room);
|
||||||
|
$neededAngelType->angelType()->associate($angelType);
|
||||||
|
|
||||||
|
$neededAngelType->count = $data['angel_type_' . $angelType->id];
|
||||||
|
|
||||||
|
$neededAngelType->save();
|
||||||
|
|
||||||
|
$angelsInfo .= sprintf(', %s: %s', $angelType->name, $count);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->log->info(
|
||||||
|
'Updated room "{name}": {description} {dect} {map_url} {angels}',
|
||||||
|
[
|
||||||
|
'name' => $room->name,
|
||||||
|
'description' => $room->description,
|
||||||
|
'dect' => $room->dect,
|
||||||
|
'map_url' => $room->map_url,
|
||||||
|
'angels' => $angelsInfo,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->addNotification('room.edit.success');
|
||||||
|
|
||||||
|
return $this->redirect->to('/admin/rooms');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Request $request): Response
|
||||||
|
{
|
||||||
|
$data = $this->validate($request, [
|
||||||
|
'id' => 'required|int',
|
||||||
|
'delete' => 'checked',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$room = $this->room->findOrFail($data['id']);
|
||||||
|
|
||||||
|
$shifts = $room->shifts;
|
||||||
|
foreach ($shifts as $shift) {
|
||||||
|
foreach ($shift->shiftEntries as $entry) {
|
||||||
|
event('shift.entry.deleting', [
|
||||||
|
'user' => $entry->user,
|
||||||
|
'start' => $shift->start,
|
||||||
|
'end' => $shift->end,
|
||||||
|
'name' => $shift->shiftType->name,
|
||||||
|
'title' => $shift->title,
|
||||||
|
'type' => $entry->angelType->name,
|
||||||
|
'room' => $room,
|
||||||
|
'freeloaded' => $entry->freeloaded,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$room->delete();
|
||||||
|
|
||||||
|
$this->log->info('Deleted room {room}', ['room' => $room->name]);
|
||||||
|
$this->addNotification('room.delete.success');
|
||||||
|
|
||||||
|
return $this->redirect->to('/admin/rooms');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function showEdit(?Room $room): Response
|
||||||
|
{
|
||||||
|
$angeltypes = AngelType::all()
|
||||||
|
->sortBy('name');
|
||||||
|
|
||||||
|
return $this->response->withView(
|
||||||
|
'admin/rooms/edit',
|
||||||
|
['room' => $room, 'angel_types' => $angeltypes, 'needed_angel_types' => $room?->neededAngelTypes]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -167,7 +167,9 @@ class Response extends SymfonyResponse implements ResponseInterface
|
||||||
throw new InvalidArgumentException('Session not defined');
|
throw new InvalidArgumentException('Session not defined');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->session->set('form-data', $input);
|
foreach ($input as $name => $value) {
|
||||||
|
$this->session->set('form-data-' . $name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,4 +103,11 @@ class Validator
|
||||||
{
|
{
|
||||||
return $this->errors;
|
return $this->errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addErrors(array $errors): self
|
||||||
|
{
|
||||||
|
$this->errors = array_merge($this->errors, $errors);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,10 +128,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
$title = admin_free_title();
|
$title = admin_free_title();
|
||||||
$content = admin_free();
|
$content = admin_free();
|
||||||
return [$title, $content];
|
return [$title, $content];
|
||||||
case 'admin_rooms':
|
|
||||||
$title = admin_rooms_title();
|
|
||||||
$content = admin_rooms();
|
|
||||||
return [$title, $content];
|
|
||||||
case 'admin_groups':
|
case 'admin_groups':
|
||||||
$title = admin_groups_title();
|
$title = admin_groups_title();
|
||||||
$content = admin_groups();
|
$content = admin_groups();
|
||||||
|
|
|
@ -22,6 +22,18 @@ class Session extends TwigExtension
|
||||||
return [
|
return [
|
||||||
new TwigFunction('session_get', [$this->session, 'get']),
|
new TwigFunction('session_get', [$this->session, 'get']),
|
||||||
new TwigFunction('session_set', [$this->session, 'set']),
|
new TwigFunction('session_set', [$this->session, 'set']),
|
||||||
|
new TwigFunction('session_pop', [$this, 'sessionPop']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the requested attribute and removes it from the session
|
||||||
|
*/
|
||||||
|
public function sessionPop(string $name, mixed $default = null): mixed
|
||||||
|
{
|
||||||
|
$value = $this->session->get($name, $default);
|
||||||
|
$this->session->remove($name);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Controllers\Admin;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\Admin\RoomsController;
|
||||||
|
use Engelsystem\Events\EventDispatcher;
|
||||||
|
use Engelsystem\Helpers\Carbon;
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Redirector;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use Engelsystem\Models\AngelType;
|
||||||
|
use Engelsystem\Models\Room;
|
||||||
|
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||||
|
use Engelsystem\Models\Shifts\Shift;
|
||||||
|
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||||
|
use Engelsystem\Models\User\User;
|
||||||
|
use Engelsystem\Test\Unit\Controllers\ControllerTest;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
|
||||||
|
class RoomsControllerTest extends ControllerTest
|
||||||
|
{
|
||||||
|
protected Redirector|MockObject $redirect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::__construct
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::index
|
||||||
|
*/
|
||||||
|
public function testIndex(): void
|
||||||
|
{
|
||||||
|
/** @var RoomsController $controller */
|
||||||
|
$controller = $this->app->make(RoomsController::class);
|
||||||
|
Room::factory(5)->create();
|
||||||
|
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('withView')
|
||||||
|
->willReturnCallback(function (string $view, array $data) {
|
||||||
|
$this->assertEquals('admin/rooms/index', $view);
|
||||||
|
$this->assertTrue($data['is_index'] ?? false);
|
||||||
|
$this->assertCount(5, $data['rooms'] ?? []);
|
||||||
|
return $this->response;
|
||||||
|
});
|
||||||
|
|
||||||
|
$controller->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::edit
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::showEdit
|
||||||
|
*/
|
||||||
|
public function testEdit(): void
|
||||||
|
{
|
||||||
|
/** @var RoomsController $controller */
|
||||||
|
$controller = $this->app->make(RoomsController::class);
|
||||||
|
/** @var Room $room */
|
||||||
|
$room = Room::factory()->create();
|
||||||
|
$angelTypes = AngelType::factory(3)->create();
|
||||||
|
(new NeededAngelType(['room_id' => $room->id, 'angel_type_id' => $angelTypes[0]->id, 'count' => 3]))->save();
|
||||||
|
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('withView')
|
||||||
|
->willReturnCallback(function (string $view, array $data) use ($room) {
|
||||||
|
$this->assertEquals('admin/rooms/edit', $view);
|
||||||
|
$this->assertEquals($room->id, $data['room']?->id);
|
||||||
|
$this->assertCount(3, $data['angel_types'] ?? []);
|
||||||
|
$this->assertCount(1, $data['needed_angel_types'] ?? []);
|
||||||
|
return $this->response;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->request = $this->request->withAttribute('room_id', 1);
|
||||||
|
|
||||||
|
$controller->edit($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::edit
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::showEdit
|
||||||
|
*/
|
||||||
|
public function testEditNew(): void
|
||||||
|
{
|
||||||
|
/** @var RoomsController $controller */
|
||||||
|
$controller = $this->app->make(RoomsController::class);
|
||||||
|
AngelType::factory(3)->create();
|
||||||
|
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('withView')
|
||||||
|
->willReturnCallback(function (string $view, array $data) {
|
||||||
|
$this->assertEquals('admin/rooms/edit', $view);
|
||||||
|
$this->assertEmpty($data['room'] ?? []);
|
||||||
|
$this->assertCount(3, $data['angel_types'] ?? []);
|
||||||
|
$this->assertEmpty($data['needed_angel_types'] ?? []);
|
||||||
|
return $this->response;
|
||||||
|
});
|
||||||
|
|
||||||
|
$controller->edit($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::save
|
||||||
|
*/
|
||||||
|
public function testSave(): void
|
||||||
|
{
|
||||||
|
/** @var RoomsController $controller */
|
||||||
|
$controller = $this->app->make(RoomsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
AngelType::factory(3)->create();
|
||||||
|
|
||||||
|
$this->setExpects($this->redirect, 'to', ['/admin/rooms']);
|
||||||
|
|
||||||
|
$this->request = $this->request->withParsedBody([
|
||||||
|
'name' => 'Testroom',
|
||||||
|
'description' => 'Something',
|
||||||
|
'dect' => 'DECTNR',
|
||||||
|
'map_url' => 'https://osm.url/#map=h/x/y',
|
||||||
|
'angel_type_1' => '0',
|
||||||
|
'angel_type_2' => '3',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$controller->save($this->request);
|
||||||
|
|
||||||
|
$this->assertTrue($this->log->hasInfoThatContains('Updated room'));
|
||||||
|
$this->assertHasNotification('room.edit.success');
|
||||||
|
$this->assertCount(1, Room::whereName('Testroom')->get());
|
||||||
|
|
||||||
|
$neededAngelType = NeededAngelType::whereRoomId(1)
|
||||||
|
->where('angel_type_id', 2)
|
||||||
|
->where('count', 3)
|
||||||
|
->get();
|
||||||
|
$this->assertCount(1, $neededAngelType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::save
|
||||||
|
*/
|
||||||
|
public function testSaveUniqueName(): void
|
||||||
|
{
|
||||||
|
/** @var RoomsController $controller */
|
||||||
|
$controller = $this->app->make(RoomsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
Room::factory()->create(['name' => 'Testroom']);
|
||||||
|
|
||||||
|
$this->request = $this->request->withParsedBody([
|
||||||
|
'name' => 'Testroom',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->expectException(ValidationException::class);
|
||||||
|
$controller->save($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::save
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::delete
|
||||||
|
*/
|
||||||
|
public function testSaveDelete(): void
|
||||||
|
{
|
||||||
|
/** @var RoomsController $controller */
|
||||||
|
$controller = $this->app->make(RoomsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
/** @var Room $room */
|
||||||
|
$room = Room::factory()->create();
|
||||||
|
|
||||||
|
$this->request = $this->request->withParsedBody([
|
||||||
|
'id' => '1',
|
||||||
|
'delete' => '1',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$controller->save($this->request);
|
||||||
|
$this->assertEmpty(Room::find($room->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\RoomsController::delete
|
||||||
|
*/
|
||||||
|
public function testDelete(): void
|
||||||
|
{
|
||||||
|
/** @var EventDispatcher|MockObject $dispatcher */
|
||||||
|
$dispatcher = $this->createMock(EventDispatcher::class);
|
||||||
|
$this->app->instance('events.dispatcher', $dispatcher);
|
||||||
|
/** @var RoomsController $controller */
|
||||||
|
$controller = $this->app->make(RoomsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
/** @var Room $room */
|
||||||
|
$room = Room::factory()->create();
|
||||||
|
/** @var Shift $shift */
|
||||||
|
$shift = Shift::factory()->create(['room_id' => $room->id, 'start' => Carbon::create()->subHour()]);
|
||||||
|
/** @var User $user */
|
||||||
|
$user = User::factory()->create(['name' => 'foo', 'email' => 'lorem@ipsum']);
|
||||||
|
/** @var ShiftEntry $shiftEntry */
|
||||||
|
ShiftEntry::factory()->create(['shift_id' => $shift->id, 'user_id' => $user->id]);
|
||||||
|
|
||||||
|
$this->setExpects($this->redirect, 'to', ['/admin/rooms'], $this->response);
|
||||||
|
|
||||||
|
$dispatcher->expects($this->once())
|
||||||
|
->method('dispatch')
|
||||||
|
->willReturnCallback(function (string $event, array $data) use ($room, $user) {
|
||||||
|
$this->assertEquals('shift.entry.deleting', $event);
|
||||||
|
$this->assertEquals($room->id, $data['room']->id);
|
||||||
|
$this->assertEquals($user->id, $data['user']->id);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->request = $this->request->withParsedBody(['id' => 1, 'delete' => '1']);
|
||||||
|
|
||||||
|
$controller->delete($this->request);
|
||||||
|
|
||||||
|
$this->assertNull(Room::find($room->id));
|
||||||
|
$this->assertTrue($this->log->hasInfoThatContains('Deleted room'));
|
||||||
|
$this->assertHasNotification('room.delete.success');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->redirect = $this->createMock(Redirector::class);
|
||||||
|
$this->app->instance(Redirector::class, $this->redirect);
|
||||||
|
}
|
||||||
|
}
|
|
@ -159,10 +159,10 @@ class ResponseTest extends TestCase
|
||||||
$response = new Response('', 200, [], null, $session);
|
$response = new Response('', 200, [], null, $session);
|
||||||
|
|
||||||
$response->withInput(['some' => 'value']);
|
$response->withInput(['some' => 'value']);
|
||||||
$this->assertEquals(['some' => 'value'], $session->get('form-data'));
|
$this->assertEquals('value', $session->get('form-data-some'));
|
||||||
|
|
||||||
$response->withInput(['lorem' => 'ipsum']);
|
$response->withInput(['lorem' => 'ipsum']);
|
||||||
$this->assertEquals(['lorem' => 'ipsum'], $session->get('form-data'));
|
$this->assertEquals('ipsum', $session->get('form-data-lorem'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -171,4 +171,19 @@ class ValidatorTest extends TestCase
|
||||||
['foo' => 'optional|int']
|
['foo' => 'optional|int']
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validator::addErrors
|
||||||
|
*/
|
||||||
|
public function testAddErrors(): void
|
||||||
|
{
|
||||||
|
$val = new Validator();
|
||||||
|
$val->addErrors(['bar' => ['Lorem']]);
|
||||||
|
$val->addErrors(['foo' => ['Foo value is definitely wrong!']]);
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'bar' => ['Lorem'],
|
||||||
|
'foo' => ['Foo value is definitely wrong!'],
|
||||||
|
], $val->getErrors());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,9 +220,7 @@ class ErrorHandlerTest extends TestCase
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'form-data' => [
|
'form-data-foo' => 'bar',
|
||||||
'foo' => 'bar',
|
|
||||||
],
|
|
||||||
], $session->all());
|
], $session->all());
|
||||||
|
|
||||||
$request = $request->withAddedHeader('referer', '/foo/batz');
|
$request = $request->withAddedHeader('referer', '/foo/batz');
|
||||||
|
|
|
@ -5,8 +5,8 @@ declare(strict_types=1);
|
||||||
namespace Engelsystem\Test\Unit\Renderer\Twig\Extensions;
|
namespace Engelsystem\Test\Unit\Renderer\Twig\Extensions;
|
||||||
|
|
||||||
use Engelsystem\Renderer\Twig\Extensions\Session;
|
use Engelsystem\Renderer\Twig\Extensions\Session;
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Session as SymfonySession;
|
use Symfony\Component\HttpFoundation\Session\Session as SymfonySession;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||||
|
|
||||||
class SessionTest extends ExtensionTest
|
class SessionTest extends ExtensionTest
|
||||||
{
|
{
|
||||||
|
@ -16,13 +16,31 @@ class SessionTest extends ExtensionTest
|
||||||
*/
|
*/
|
||||||
public function testGetGlobals(): void
|
public function testGetGlobals(): void
|
||||||
{
|
{
|
||||||
/** @var SymfonySession|MockObject $session */
|
$session = new SymfonySession(new MockArraySessionStorage());
|
||||||
$session = $this->createMock(SymfonySession::class);
|
|
||||||
|
|
||||||
$extension = new Session($session);
|
$extension = new Session($session);
|
||||||
$functions = $extension->getFunctions();
|
$functions = $extension->getFunctions();
|
||||||
|
|
||||||
$this->assertExtensionExists('session_get', [$session, 'get'], $functions);
|
$this->assertExtensionExists('session_get', [$session, 'get'], $functions);
|
||||||
$this->assertExtensionExists('session_set', [$session, 'set'], $functions);
|
$this->assertExtensionExists('session_set', [$session, 'set'], $functions);
|
||||||
|
$this->assertExtensionExists('session_pop', [$extension, 'sessionPop'], $functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Renderer\Twig\Extensions\Session::sessionPop
|
||||||
|
*/
|
||||||
|
public function testSessionPop(): void
|
||||||
|
{
|
||||||
|
$session = new SymfonySession(new MockArraySessionStorage());
|
||||||
|
$session->set('test', 'value');
|
||||||
|
|
||||||
|
$extension = new Session($session);
|
||||||
|
|
||||||
|
$result = $extension->sessionPop('test');
|
||||||
|
$this->assertEquals('value', $result);
|
||||||
|
$this->assertFalse($session->has('test'));
|
||||||
|
|
||||||
|
$result = $extension->sessionPop('foo', 'default value');
|
||||||
|
$this->assertEquals('default value', $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue