Kalenderupdate

* Komplette Verwaltung von Kalender Rechte von internen und externen Mitarbeiteren
This commit is contained in:
Daniel Spitzer
2025-10-05 17:36:42 +02:00
parent c389477e05
commit 363dbd5436
5 changed files with 743 additions and 60 deletions

View File

@@ -15,7 +15,15 @@
</ol>
</div>
<h4 class="page-title"><?= ($calendars->id) ? "Kalender Verwaltung bearbeiten" : "Neuer Kalender Verwaltung" ?></h4>
<h4 class="page-title">
<?php if ($calendars->id && $calendars->user_id): ?>
Kalender Verwaltung bearbeiten
<?php elseif ($calendars->id && !$calendars->user_id): ?>
Benutzer bearbeiten
<?php else: ?>
Neuen Kalender Benutzer anlegen
<?php endif; ?>
</h4>
</div>
</div>
</div>
@@ -35,15 +43,31 @@
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="user_id">Name *</label>
<div class="col-lg-3">
<select disabled="disabled" required="required" id="user_id" name="user_id"
class="select2 form-control">
<option value=""></option>
<?php foreach ($users as $user): ?>
<option value="<?= $user->id ?>" <?= ($calendars->user_id == $user->id) ? "selected='selected'" : "" ?>><?= $user->name ?></option>
<?php endforeach; ?>
</select>
<?php if ($calendars->user_id): ?>
<input type="text" value="<?= $calendars->user->name ?>" class="form-control" disabled/>
<?php else: ?>
<input type="text" id="calendar_firstname" name="calendar_firstname"
value="<?= $calendars->calendar_firstname ?>"
placeholder="Vorname" class="form-control mb-2" required/>
<input type="text" id="calendar_lastname" name="calendar_lastname"
value="<?= $calendars->calendar_lastname ?>"
placeholder="Nachname" class="form-control" required/>
<?php endif; ?>
</div>
</div>
<?php if (!$calendars->id || !$calendars->user_id): ?>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="calendar_email">E-Mail (optional)</label>
<div class="col-lg-3">
<input type="email" id="calendar_email" name="calendar_email"
value="<?= $calendars->calendar_email ?>" class="form-control"
placeholder="wird automatisch aus Name generiert"/>
<small class="form-text text-muted">
Automatisch: vorname.nachname@xinon.extern
</small>
</div>
</div>
<?php endif; ?>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="go_calendar_id">GO Kalender ID</label>
<div class="col-lg-3">
@@ -76,7 +100,108 @@
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="calendar_admin">Kalender Admin</label>
<div class="col-lg-3">
<div class="custom-control custom-switch mt-1">
<input type="checkbox" <?= ($calendars->calendar_admin==1) ? 'checked="checked"' : '' ?> class="custom-control-input" value="1"
id="calendar_admin" name="calendar_admin">
<label class="custom-control-label no-user-select" for="calendar_admin"></label>
</div>
<small class="form-text text-muted">
Bekommt automatisch "all"-Rechte auf alle neuen Benutzer
</small>
</div>
</div>
<?php if ($calendars->id): ?>
<div class="form-group row">
<label class="col-lg-2 col-form-label">Kalenderrechte</label>
<div class="col-lg-8">
<div class="card">
<div class="card-body">
<table class="table table-sm table-hover">
<thead>
<tr>
<th>Kalender</th>
<th width="120" class="text-center">Keine</th>
<th width="120" class="text-center">Lesen</th>
<th width="120" class="text-center">Alle Rechte</th>
</tr>
</thead>
<tbody>
<?php
$currentRights = json_decode($calendars->rights, true) ?: [];
$allCalendars = CalendarModel::getAll();
$sortedCalendars = [];
foreach ($allCalendars as $cal) {
if ($cal->id == $calendars->id || !$cal->go_calendar_id) continue;
$name = $cal->user_id ? $cal->user->name : $cal->calendar_name;
$sortedCalendars[] = [
'cal' => $cal,
'name' => $name
];
}
usort($sortedCalendars, function($a, $b) {
return strcasecmp($a['name'], $b['name']);
});
foreach ($sortedCalendars as $item):
$cal = $item['cal'];
$calendarName = $item['name'];
$currentRight = isset($currentRights[$cal->go_calendar_id]) ? $currentRights[$cal->go_calendar_id] : 'none';
?>
<tr>
<td>
<strong><?= htmlspecialchars($calendarName) ?></strong>
<?php if ($cal->user_id): ?>
<span class="badge badge-success badge-sm ml-1">Mitarbeiter</span>
<?php else: ?>
<span class="badge badge-info badge-sm ml-1">Extern</span>
<?php endif; ?>
</td>
<td class="text-center">
<div class="custom-control custom-radio">
<input type="radio"
class="custom-control-input"
id="right_<?= $cal->go_calendar_id ?>_none"
name="rights[<?= $cal->go_calendar_id ?>]"
value="none"
<?= ($currentRight == 'none') ? 'checked' : '' ?>>
<label class="custom-control-label" for="right_<?= $cal->go_calendar_id ?>_none"></label>
</div>
</td>
<td class="text-center">
<div class="custom-control custom-radio">
<input type="radio"
class="custom-control-input"
id="right_<?= $cal->go_calendar_id ?>_read"
name="rights[<?= $cal->go_calendar_id ?>]"
value="read"
<?= ($currentRight == 'read') ? 'checked' : '' ?>>
<label class="custom-control-label" for="right_<?= $cal->go_calendar_id ?>_read"></label>
</div>
</td>
<td class="text-center">
<div class="custom-control custom-radio">
<input type="radio"
class="custom-control-input"
id="right_<?= $cal->go_calendar_id ?>_all"
name="rights[<?= $cal->go_calendar_id ?>]"
value="all"
<?= ($currentRight == 'all') ? 'checked' : '' ?>>
<label class="custom-control-label" for="right_<?= $cal->go_calendar_id ?>_all"></label>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
<div class="form-group row">
@@ -100,8 +225,7 @@
?>
<script type="text/javascript">
$(".select2").select2({placeholder: ""});
// disable mousewheel on a input number field when in focus
localStorage.setItem('calendarActiveTab', '#user-tab');
$('form').on('focus', 'input[type=number]', function (e) {
$(this).on('wheel.disableScroll', function (e) {
e.preventDefault()

View File

@@ -1,7 +1,6 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<!-- start page title -->
<div class="row">
<div class="col-12">
<div class="page-title-box">
@@ -16,8 +15,6 @@
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
@@ -103,6 +100,13 @@
role="tabpanel"
aria-labelledby="profile-tab"
>
<div class="row">
<div class="col-12">
<a class="btn btn-primary mb-2 float-right"
href="<?= self::getUrl("Calendar", "add") ?>"><i
class="fas fa-plus"></i> Neuen Benutzer anlegen</a>
</div>
</div>
<table id="datatable" class="table table-striped table-hover table-sm" style="width:100%">
<thead>
<tr>
@@ -113,6 +117,7 @@
<th class="text-center">Webhook</th>
<th class="text-center">Webhook Timeout</th>
<th class="text-center">Aktiv</th>
<th class="text-center">Admin</th>
<th class="edit-width" style="width: 50px !important;text-decoration: underline"></th>
</tr>
<tr id="filterrow">
@@ -124,37 +129,141 @@
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($calendars as $calendar):
// ÄNDERUNG: Rechte zusammenfassen mit korrektem Array-Zugriff
$calenadarRights = json_decode($calendar->rights, true);
$rights = "";
foreach ($calenadarRights as $key => $value) {
if ($key != $calendar->go_calendar_id) {
$rights .= $calendars[$key]->user->name . " : " . $value . "<br>";
$rightsTooltip = "";
$readCount = 0;
$allCount = 0;
if (is_array($calenadarRights)) {
foreach ($calenadarRights as $key => $value) {
if ($key != $calendar->go_calendar_id) {
// Zähle read und all
if ($value == 'read') {
$readCount++;
} elseif ($value == 'all') {
$allCount++;
}
// Baue Tooltip-Text - nutze calendarsById für Zugriff
$calName = "Unbekannt";
if (isset($calendarsById[$key])) { // Sucht nach go_calendar_id = $key
if ($calendarsById[$key]->user_id && ($calendarsById[$key]->user->name)) {
$calName = $calendarsById[$key]->user->name;
} elseif ($calendarsById[$key]->calendar_name) {
$calName = $calendarsById[$key]->calendar_name;
}
}
$rightsTooltip .= $calName . ": " . $value . "&#10;";
}
}
}
// Kompakte Anzeige: "X read, Y all"
$rightsSummary = "";
if ($readCount > 0) {
$rightsSummary .= $readCount . " read";
}
if ($allCount > 0) {
if ($rightsSummary) $rightsSummary .= ", ";
$rightsSummary .= $allCount . " all";
}
if (!$rightsSummary) {
$rightsSummary = "keine";
}
?>
<tr>
<td><?= $calendar->user->name ?></td>
<td>
<?= $calendar->user_id ? $calendar->user->name : $calendar->calendar_name ?>
<?php if ($calendar->user_id): ?>
<span class="badge badge-success badge-sm ml-1">Mitarbeiter</span>
<?php else: ?>
<span class="badge badge-info badge-sm ml-1">Extern</span>
<?php endif; ?>
</td>
<td class="text-center"><?= $calendar->go_calendar_id ?></td>
<td class="text-nowrap"><?= $calendar->microsoft_id ?></td>
<td><?= $rights ?></td>
<td class="text-center">
<?php
// Erstelle HTML für Popover-Inhalt
$popoverContent = '<div class="p-2">';
if ($readCount > 0 || $allCount > 0) {
$popoverContent .= '<table class="table table-sm table-borderless mb-0" style="font-size: 0.85rem;">';
$popoverContent .= '<thead><tr><th>Kalender</th><th class="text-center">Recht</th></tr></thead><tbody>';
// Sortiere nach Namen für bessere Übersicht
$sortedRights = [];
foreach ($calenadarRights as $key => $value) {
if ($key != $calendar->go_calendar_id) {
$calName = "Unbekannt";
if (isset($calendarsById[$key])) {
if ($calendarsById[$key]->user_id && ($calendarsById[$key]->user) && ($calendarsById[$key]->user->name)) {
$calName = $calendarsById[$key]->user->name;
} elseif (isset($calendarsById[$key]->calendar_name)) {
$calName = $calendarsById[$key]->calendar_name;
}
}
$sortedRights[$calName] = $value;
}
}
ksort($sortedRights);
foreach ($sortedRights as $name => $right) {
$badgeClass = ($right == 'all') ? 'badge-success' : 'badge-info';
$badgeText = ($right == 'all') ? 'Alle Rechte' : 'Lesen';
$popoverContent .= '<tr>';
$popoverContent .= '<td class="pt-1 pb-0 text-left">' . htmlspecialchars($name) . '</td>';
$popoverContent .= '<td class="text-center pt-1 pb-0"><span class="badge ' . $badgeClass . ' badge-sm">' . $badgeText . '</span></td>';
$popoverContent .= '</tr>';
}
$popoverContent .= '</tbody></table>';
} else {
$popoverContent .= '<em class="text-muted">Keine Rechte vergeben</em>';
}
$popoverContent .= '</div>';
$popoverContentEscaped = htmlspecialchars($popoverContent, ENT_QUOTES, 'UTF-8');
?>
<span class="badge badge-primary calendar-rights-badge"
style="cursor: help; position: relative;">
<i class="fas fa-shield-alt mr-1"></i><?= $rightsSummary ?>
<div class="rights-tooltip" style="display: none; position: absolute; z-index: 10000; background: white; border: 1px solid #ccc; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); min-width: 300px; max-width: 400px; left: auto; right: 100%; top: 50%; transform: translateY(-50%); margin-right: 10px; padding: 0;">
<div style="background: #f8f9fa; border-bottom: 1px solid #dee2e6; padding: 8px 12px; border-radius: 6px 6px 0 0;">
<strong style="font-size: 0.9rem; color: #212523">Kalenderrechte</strong>
</div>
<?= $popoverContent ?>
</div>
</span>
</td>
<td class="text-nowrap"><?= $calendar->subscription_id ?></td>
<td class="text-center"><?= ($calendar->expirationDateTime) ? date("d.m.Y H:i", $calendar->expirationDateTime) : '' ?></td>
<td class="text-center"><?= ($calendar->active == 1) ? '<i class="fa-regular fa-circle-check mr-1"></i>' : '<i class="fa-regular fa-circle-xmark mr-1"></i>' ?></td>
<td class="text-center">
<?php if ($calendar->calendar_admin == 1): ?>
<span class="badge badge-danger" title="Bekommt automatisch 'all'-Rechte auf neue Benutzer">
<i class="fas fa-user-shield mr-1"></i>Admin
</span>
<?php endif; ?>
</td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("Calendar", "edit", ["id" => $calendar->id]) ?>"><i
class="far fa-edit" title="Bearbeiten"></i></a>
<a href="<?= self::getUrl("Calendar", "delete", ["id" => $calendar->id]) ?>"
onclick="if(!confirm('Kalender Verwaltung wirklich löschen?')) return false;"
class="text-danger"
title="Löschen"><i class="fas fa-trash"></i></a>
<?php if (!$calendar->user_id): ?>
<a href="<?= self::getUrl("Calendar", "delete", ["id" => $calendar->id]) ?>"
onclick="if(!confirm('Kalender Benutzer wirklich löschen?')) return false;" class="text-danger"
title="Löschen"><i class="fas fa-trash"></i></a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php
endforeach; ?>
</tbody>
</table>
</div>
@@ -251,6 +360,17 @@
$('#filterrow2 select').val('');
table2.search('').columns().search('').draw();
});
$('.calendar-rights-badge').each(function() {
var content = $(this).attr('data-popover-content');
$(this).popover({
container: 'body',
html: true,
trigger: 'hover focus',
placement: 'left',
title: 'Kalenderrechte',
content: content
});
});
},
"dom": cstmdom
@@ -278,13 +398,8 @@
if (state2) {
table2.columns().eq(0).each(function (colIdx) {
var colSearch = state2.columns[colIdx].search;
if (colSearch.search) {
$('#filterrow2').find("[data-index='" + colIdx + "']").val(colSearch.search);
}
});
@@ -295,7 +410,7 @@
if (target === '#user-tab' && !tableInitialized) {
// Initialisierung der DataTable
var hidesearch = [6, 7];
var hidesearch = [6, 7, 8];
if (typeof hidesearch === "undefined") {
var hidesearch;
hidesearch = [100];
@@ -380,6 +495,17 @@
$('#filterrow select').val('');
table.search('').columns().search('').draw();
});
$('.calendar-rights-badge').each(function() {
var content = $(this).attr('data-popover-content');
$(this).popover({
container: 'body',
html: true,
trigger: 'hover focus',
placement: 'left',
title: 'Kalenderrechte',
content: content
});
});
},
"dom": cstmdom
@@ -421,10 +547,63 @@
}
tableInitialized = true;
} else if (target === '#table' && tableInitialized) {
// Neuberechnung der Spalten, falls die Tabelle bereits initialisiert ist
table.columns.adjust().responsive.recalc();
}
});
$(document).ready(function() {
var tooltipTimer;
$(document).on('mouseenter', '.calendar-rights-badge', function() {
var $tooltip = $(this).find('.rights-tooltip');
clearTimeout(tooltipTimer);
// Verstecke alle anderen Tooltips
$('.rights-tooltip').not($tooltip).stop(true, true).fadeOut(150);
// Zeige diesen Tooltip
$tooltip.stop(true, true).fadeIn(250);
});
$(document).on('mouseleave', '.calendar-rights-badge', function() {
var $tooltip = $(this).find('.rights-tooltip');
// Verzögertes Ausblenden
tooltipTimer = setTimeout(function() {
$tooltip.stop(true, true).fadeOut(200);
}, 100);
});
// Verhindere dass Tooltip verschwindet wenn man drüber hovert
$(document).on('mouseenter', '.rights-tooltip', function() {
clearTimeout(tooltipTimer);
$(this).stop(true, true).show();
});
$(document).on('mouseleave', '.rights-tooltip', function() {
var $this = $(this);
tooltipTimer = setTimeout(function() {
$this.stop(true, true).fadeOut(200);
}, 100);
});
$('[data-toggle="popover"]').popover({
container: 'body',
html: true,
trigger: 'hover focus',
placement: 'left'
});
var activeTab = localStorage.getItem('calendarActiveTab');
if (activeTab) {
$('.nav-tabs a[href="' + activeTab + '"]').tab('show');
}
// Tab-Wechsel speichern
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var activeTab = $(e.target).attr('href');
localStorage.setItem('calendarActiveTab', activeTab);
});
});
</script>
<!--script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/datatables-std.js?<?= date('U') ?>"></script-->

View File

@@ -24,7 +24,18 @@ if (!is_array($Calendar_colors[$Calendar[0]->go_calendar_id])) {
$specialCalendars = array(999 => 'Abwesenheiten', 998 => 'Geburtstage', 997 => 'Feiertage');
$carCalendars = array();
foreach ($rights as $key => $right) :
$CalArray[$CalendarAll[$key]->user->name] = $key;
$calendarName = '';
if (isset($CalendarAll[$key])) {
if ($CalendarAll[$key]->user_id) {
$calendarName = $CalendarAll[$key]->user->name;
} elseif ($CalendarAll[$key]->calendar_name) {
$calendarName = $CalendarAll[$key]->calendar_name;
}
}
if ($calendarName) {
$CalArray[$calendarName] = $key;
}
endforeach;
//$CalArray['Anhänger Klein SO-421DH'] = 30;
//$CalArray['Einblasmaschine Bagela'] = 31;
@@ -209,14 +220,25 @@ endforeach;
value="<?= ($Calendar_colors[$calendar['calendar_id']]['txtcolor']) ? $Calendar_colors[$calendar['calendar_id']]['txtcolor'] : '#000000' ?>"
title="Textfarbe">
<label class="calendar-side-label" style="margin-top:2px;">
<?= ($CalendarAll[$calendar['calendar_id']]->user->name) ?: $specialCalendars[$calendar['calendar_id']] ?>
<?php
if (isset($CalendarAll[$calendar['calendar_id']])) {
if ($CalendarAll[$calendar['calendar_id']]->user_id) {
echo $CalendarAll[$calendar['calendar_id']]->user->name;
} elseif ($CalendarAll[$calendar['calendar_id']]->calendar_name) {
echo $CalendarAll[$calendar['calendar_id']]->calendar_name;
} else {
echo $specialCalendars[$calendar['calendar_id']] ?? 'Unbekannt';
}
} else {
echo $specialCalendars[$calendar['calendar_id']] ?? 'Unbekannt';
}
?>
</label>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endforeach;
// var_dump($Rights);
?>
</div>
<?php else : ?>
@@ -765,7 +787,8 @@ endforeach;
<div class="form-check" style="margin-top: 7px;">
<input style=" margin-top: 7px;" class="form-check-input eventmodal-checkbox" type="checkbox" value=""
<input style=" margin-top: 7px;" class="form-check-input eventmodal-checkbox"
type="checkbox" value=""
id="delete-old-entry"> <label class="form-check-label fw-medium checkbox-label"
for="delete-old-entry">
<span style="color:#a20909;font-size: 17px;">Alten eintrag löschen</span>