From e0cc5989cc9d4d78bd65b1f70671ed73206179b2 Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Mon, 10 Aug 2026 21:00:54 +0200 Subject: [PATCH] change event --- Internal/db/schema.sql | 21 + Internal/de/PROJECT_CONTEXT.md | 11 +- Internal/de/PROJECT_STRUCTURE.md | 5 +- Internal/de/README.md | 5 +- Internal/en/PROJECT_CONTEXT.md | 11 +- Internal/en/PROJECT_STRUCTURE.md | 5 +- Internal/en/README.md | 5 +- README.md | 8 +- partials/landing/account/community-admin.php | 75 +++- partials/landing/account/dashboard.php | 97 ++++- partials/structure/nav.php | 2 + src/App/AccountPages.php | 57 ++- src/App/ListingCatalog.php | 422 ++++++++++++++++++- 13 files changed, 648 insertions(+), 76 deletions(-) diff --git a/Internal/db/schema.sql b/Internal/db/schema.sql index 624ce8a..606b033 100755 --- a/Internal/db/schema.sql +++ b/Internal/db/schema.sql @@ -258,6 +258,27 @@ CREATE TABLE listing_benefits ( INDEX idx_listing_benefits_listing (listing_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE listing_moderation_requests ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + listing_id BIGINT UNSIGNED NOT NULL, + request_type ENUM('create','update','delete') NOT NULL, + request_status ENUM('open','approved','rejected') NOT NULL DEFAULT 'open', + requested_by BIGINT UNSIGNED NOT NULL, + reviewed_by BIGINT UNSIGNED NULL, + request_reason TEXT NULL, + review_note TEXT NULL, + payload_json LONGTEXT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + reviewed_at DATETIME NULL, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT fk_listing_moderation_listing FOREIGN KEY (listing_id) REFERENCES listings(id) ON DELETE CASCADE, + CONSTRAINT fk_listing_moderation_requested_by FOREIGN KEY (requested_by) REFERENCES users(id) ON DELETE CASCADE, + CONSTRAINT fk_listing_moderation_reviewed_by FOREIGN KEY (reviewed_by) REFERENCES users(id) ON DELETE SET NULL, + INDEX idx_listing_moderation_status (request_status), + INDEX idx_listing_moderation_type (request_type), + INDEX idx_listing_moderation_user (requested_by) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + -- Community / Forum CREATE TABLE forum_categories ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, diff --git a/Internal/de/PROJECT_CONTEXT.md b/Internal/de/PROJECT_CONTEXT.md index d3b1c60..31c64c8 100644 --- a/Internal/de/PROJECT_CONTEXT.md +++ b/Internal/de/PROJECT_CONTEXT.md @@ -16,16 +16,21 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l - Seiten-Admins erhalten eine eigene System-Sektion für globale Betriebs- und Diensteschalter. ## Konto / Mitgliederbereich -- Profil-Menü aktuell: `Profil`, `Kinder`, `Events`, `Ausflugsziele`, `Community`, `Einstellungen`, `Abmelden` +- Profil-Menü aktuell: `Profil`, `Kinder`, `Events`, `Orte & Veranstaltungen`, `Community`, `Einstellungen`, `Abmelden` - Kinder können angelegt, bearbeitet und gelöscht werden. - Wenn ein Geburtsdatum gesetzt ist, wird das Alter automatisch berechnet und später bei Bedarf aktualisiert. - Die Konto-E-Mail wird app-seitig verschlüsselt gespeichert und über einen separaten HMAC-Lookup-Hash adressiert. - Profiladresse kann per Suche oder Browser-Standort übernommen werden. - Der Bereich `Events` ist wieder auf echte eigene Events und Event-Teilnahmen begrenzt. - Der Bereich `Events` bietet zusätzlich einen manuellen ICS-Export und einen persönlichen abonnierbaren Kalender-Feed für alle eigenen Events und Event-Teilnahmen. -- Der Bereich `Events` ist im UI in `Meine Events`, `Synchronisation` und `Abgelaufene Events` getrennt, damit aktive Events, Kalender-Themen und Vergangenes sauber getrennt bleiben. +- Der Bereich `Events` ist im UI in `Meine Events`, `Kalendersynchronisation` und `Abgelaufene Events` getrennt, damit aktive Events, Kalender-Themen und Vergangenes sauber getrennt bleiben. - In `Meine Events` sitzt der Button `Neues Event anlegen` direkt in der Box `Eigene Events`; die bisherige Teilnahme-Box heißt jetzt `Angemeldete Events` und enthält zusätzlich einen direkten Link zur `Event Suche`. -- Orte und Veranstaltungen als Ausflugsziele sind vorerst in einen separaten Mitgliederbereichspunkt `Ausflugsziele` verschoben. +- Orte und Veranstaltungen sind vorerst in einen separaten Mitgliederbereichspunkt `Orte & Veranstaltungen` verschoben. +- In `Orte & Veranstaltungen` können Nutzer dauerhafte Orte und zeitlich begrenzte Veranstaltungen neu anlegen. +- Neue Orte und Veranstaltungen bleiben bis zur Freigabe im Status `wartet auf Freigabe` und werden erst danach systemweit veröffentlicht. +- Änderungs- und Löschwünsche für veröffentlichte Orte und Veranstaltungen laufen immer über eine begründete Moderationsanfrage. +- Vorschläge für neue Orte und Veranstaltungen dürfen schon vor der Freigabe als Ortsvorschlag für Events genutzt werden, solange sie noch offen geprüft werden. +- Dubletten bei Orten und Veranstaltungen sollen serverseitig mindestens über Namen und Adresse abgefangen werden. - Die Eingabe im Bereich `Events` soll so einfach wie möglich bleiben und zeigt deshalb nur die für echte Termine relevanten Felder. - Kategorien werden im Mitgliederbereich per Sucheingabe mit bestehenden Vorschlägen und automatischer Neuanlage gepflegt. - Eigene Events unterstützen Kategorie, optionales Bild, Ja/Nein-Angabe `Mit Kindern`, optionale Platzzahl und direkte Karten-/Adress-Synchronisierung. diff --git a/Internal/de/PROJECT_STRUCTURE.md b/Internal/de/PROJECT_STRUCTURE.md index e65c71c..eeb0db3 100644 --- a/Internal/de/PROJECT_STRUCTURE.md +++ b/Internal/de/PROJECT_STRUCTURE.md @@ -21,8 +21,9 @@ Stand: 2026-08-10 - System-Einstellungen: `src/App/SystemSettings.php` - neue Listing-/Ort-Basis: `src/App/ListingCatalog.php` - Kalender-Export und abonnierbarer Feed: `src/App/CalendarSync.php` plus `public/page/calendar/export.php` und `public/page/calendar/feed.php` -- UI für getrennte Bereiche `Events` und `Ausflugsziele` im Mitgliederbereich: `partials/landing/account/dashboard.php` -- Preis-, Bild- und Ortseingabe für Ausflugsziele sowie reduzierte Event-Maske: `partials/landing/account/dashboard.php` plus Speicherung in `src/App/ListingCatalog.php` +- UI für getrennte Bereiche `Events` und `Orte & Veranstaltungen` im Mitgliederbereich: `partials/landing/account/dashboard.php` +- Preis-, Bild- und Ortseingabe für Orte und Veranstaltungen sowie reduzierte Event-Maske: `partials/landing/account/dashboard.php` plus Speicherung in `src/App/ListingCatalog.php` +- Freigaben sowie Änderungs- und Löschanfragen für Orte und Veranstaltungen: `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php`, `partials/landing/account/community-admin.php` - Legacy-Eigen-Events wurden erweitert in `src/App/AccountPages.php` und `Internal/db/schema.sql` um Kategorie- und Bildfelder - Kategorien-Prüfung und Zusammenführung für Seiten-Admins liegen ebenfalls in `partials/landing/account/dashboard.php` mit Logik in `src/App/ListingCatalog.php` diff --git a/Internal/de/README.md b/Internal/de/README.md index 9186b1e..4dfeed4 100644 --- a/Internal/de/README.md +++ b/Internal/de/README.md @@ -16,7 +16,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf lokale - Community-Admin-Bereich für Bewerbungen, Meldungen, Rollen und Migration - standortbasierte Sortierung für die neuesten Events - Mitgliederbereich mit linker Bereichsnavigation -- Profil-Menü mit `Profil`, `Kinder`, `Events`, `Ausflugsziele`, `Community`, `Einstellungen` +- Profil-Menü mit `Profil`, `Kinder`, `Events`, `Orte & Veranstaltungen`, `Community`, `Einstellungen` - Konto-E-Mails sowie sensible Profilfelder werden app-seitig verschlüsselt gespeichert - Kinder können angelegt, bearbeitet und gelöscht werden - Profiladresse mit verschlüsselter Straße/Hausnummer, Adresssuche, Browser-Übernahme und Validierung @@ -24,7 +24,8 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf lokale - neue Datenbasis für ein späteres Termin-, Ort- und Veranstaltungssystem angelegt - Mitgliederbereich `Events` ist wieder auf echte eigene Events und Event-Teilnahmen fokussiert - Eigene Events haben jetzt Kategorie, optionales Bild, klare Kinderangabe, optionale Platzzahl und eine direktere Karten-/Adress-Synchronisierung -- Orte und sonstige Veranstaltungen wurden vorerst in einen separaten Bereich `Ausflugsziele` verschoben +- Orte und sonstige Veranstaltungen wurden vorerst in einen separaten Bereich `Orte & Veranstaltungen` verschoben +- Neue Orte und Veranstaltungen müssen vor Veröffentlichung erst durch einen Admin freigegeben werden; Änderungs- und Löschwünsche laufen ebenfalls nur als begründete Anfrage - Die Eingabemasken sind jetzt progressiv aufgebaut: erst Pflichtangaben, optionale Daten in einklappbaren Bereichen - Kategorien laufen jetzt über eine Sucheingabe mit bestehenden Vorschlägen; neue Kategorien werden automatisch angelegt und können im Systembereich von Seiten-Admins zusammengeführt werden - Im Bereich `Events` gibt es jetzt zusätzlich einen ICS-Download und einen persönlichen abonnierbaren Kalender-Feed für alle eigenen Events und Event-Teilnahmen diff --git a/Internal/en/PROJECT_CONTEXT.md b/Internal/en/PROJECT_CONTEXT.md index ae6e3f3..44d61b3 100644 --- a/Internal/en/PROJECT_CONTEXT.md +++ b/Internal/en/PROJECT_CONTEXT.md @@ -16,16 +16,21 @@ Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events - Site admins get a dedicated system section for global operating and service flags. ## Account / Member Area -- Profile menu currently contains `Profile`, `Children`, `Events`, `Outings`, `Community`, `Settings`, `Logout`. +- Profile menu currently contains `Profile`, `Children`, `Events`, `Places & Events`, `Community`, `Settings`, `Logout`. - Children can be created, edited, and deleted. - If a birth date is set, age is calculated automatically and updated later when needed. - Account email is encrypted application-side and addressed through a separate HMAC lookup hash. - Profile address can be completed via address search or browser-based location import. - The `Events` area is limited again to real own events and event participations. - The `Events` area now also provides a manual ICS export and a personal subscribable calendar feed for all own events and event participations. -- The `Events` area is now separated in the UI into `My Events`, `Synchronization`, and `Expired Events` so that active events, calendar tasks, and past items stay clearly separated. +- The `Events` area is now separated in the UI into `My Events`, `Calendar Sync`, and `Expired Events` so that active events, calendar tasks, and past items stay clearly separated. - Inside `My Events`, the `Create New Event` button now lives directly in the `Own Events` box; the previous participation box is now labeled `Registered Events` and also includes a direct link to `Event Search`. -- Places and event-like outing targets were moved for now into a separate member-area section `Outings`. +- Places and event-like entries were moved for now into a separate member-area section `Places & Events`. +- Inside `Places & Events`, users can create permanent places and time-limited event-style entries. +- New places and event-style entries stay in a pending state until an admin approves them for publication. +- Change and deletion wishes for published places and event-style entries always run through a reasoned moderation request. +- Pending new places and event-style entries can already be used as location suggestions for events while they are still under review. +- Duplicate submissions for places and event-style entries should be blocked server-side at least by name and address. - The `Events` input flow should stay as simple as possible and therefore only shows fields relevant for real scheduled events. - Categories in the member area are handled via a search input with existing suggestions and automatic creation when needed. - Own events support category, optional image, a clear `with children` yes/no field, optional capacity, and direct map/address synchronization. diff --git a/Internal/en/PROJECT_STRUCTURE.md b/Internal/en/PROJECT_STRUCTURE.md index 617ff1f..97fae36 100644 --- a/Internal/en/PROJECT_STRUCTURE.md +++ b/Internal/en/PROJECT_STRUCTURE.md @@ -21,8 +21,9 @@ Updated: 2026-08-10 - system settings: `src/App/SystemSettings.php` - new listing/place base: `src/App/ListingCatalog.php` - calendar export and subscribable feed: `src/App/CalendarSync.php` plus `public/page/calendar/export.php` and `public/page/calendar/feed.php` -- separated `Events` and `Outings` UI in member area: `partials/landing/account/dashboard.php` -- pricing, image upload, and place/address input for outings plus a reduced own-event form: `partials/landing/account/dashboard.php` with persistence in `src/App/ListingCatalog.php` +- separated `Events` and `Places & Events` UI in member area: `partials/landing/account/dashboard.php` +- pricing, image upload, and place/address input for places and event-style entries plus a reduced own-event form: `partials/landing/account/dashboard.php` with persistence in `src/App/ListingCatalog.php` +- approvals as well as change and deletion requests for places and event-style entries: `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php`, `partials/landing/account/community-admin.php` - legacy own events were extended in `src/App/AccountPages.php` and `Internal/db/schema.sql` with category and image fields ## Documentation Rule diff --git a/Internal/en/README.md b/Internal/en/README.md index d7ecb8f..1cbcb81 100644 --- a/Internal/en/README.md +++ b/Internal/en/README.md @@ -16,7 +16,7 @@ Papa-Kind-Treff is a PHP-based platform for fathers focused on local events, app - community admin area for applications, reports, roles, and migrations - location-based ordering for the newest events - member area with left-side section navigation -- profile menu with `Profile`, `Children`, `Events`, `Outings`, `Community`, `Settings` +- profile menu with `Profile`, `Children`, `Events`, `Places & Events`, `Community`, `Settings` - account emails and sensitive profile fields are stored encrypted application-side - children can be created, edited, and deleted - profile address supports encrypted street/house number, address search, browser import, and validation @@ -24,7 +24,8 @@ Papa-Kind-Treff is a PHP-based platform for fathers focused on local events, app - new data foundation prepared for a broader event, place, and listing system - member area `Events` is now limited again to real own events and event participations - own events now include category, optional image, explicit child suitability, optional capacity, and more direct map/address synchronization -- places and other events were moved for now into a separate member-area section `Outings` +- places and other event-style entries were moved for now into a separate member-area section `Places & Events` +- new places and event-style entries must be approved by an admin before publication; change and deletion wishes also run as reasoned requests - the member-area entry forms now follow a progressive approach: required fields first, optional data inside collapsible sections - categories now use a search input with existing suggestions; new categories are created automatically and can be merged by site admins in the system area - the `Events` area now also includes an ICS download and a personal subscribable calendar feed for all own events and event participations diff --git a/README.md b/README.md index 4dd8f95..6e1d469 100644 --- a/README.md +++ b/README.md @@ -36,16 +36,18 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf: - Primärbegriff im Produkt: `Events` - `Termine` und `Treffen` ergänzend in SEO- und Erklärungstexten - Hauptnavigation aktuell: `Home`, `Event Suche`, `Community` -- Profil-Menü aktuell: `Profil`, `Kinder`, `Events`, `Ausflugsziele`, `Community`, `Einstellungen`, `Abmelden` +- Profil-Menü aktuell: `Profil`, `Kinder`, `Events`, `Orte & Veranstaltungen`, `Community`, `Einstellungen`, `Abmelden` - neue interne Grundstruktur: `listing_places`, `listings`, `listing_occurrences`, `listing_prices`, `listing_benefits` - Seiten-Admins haben zusätzlich eine System-Sektion für globale Wartungs- und Diensteschalter - Im Mitgliederbereich ist `Events` jetzt wieder auf echte eigene Events und Event-Teilnahmen beschränkt -- Orte und sonstige Veranstaltungen laufen jetzt separat unter `Ausflugsziele` +- Orte und sonstige Veranstaltungen laufen jetzt separat unter `Orte & Veranstaltungen` +- Neue Orte und Veranstaltungen müssen vor Veröffentlichung erst durch einen Admin freigegeben werden; Änderungs- und Löschwünsche laufen ebenfalls als begründete Anfrage - Eigene Events unterstützen aktuell Kategorie, Bild-Upload, klare Kinderangabe, optionale Platzzahl und direkte Karten-/Adress-Synchronisierung - Die Eingabe im Mitgliederbereich ist jetzt bewusst vereinfacht: zuerst nur Pflichtangaben, optionale Angaben in einklappbaren Bereichen - Kategorien werden jetzt über eine Sucheingabe mit bestehenden Vorschlägen gepflegt; neue Kategorien werden automatisch angelegt und sind für Seiten-Admins im Systembereich zusammenführbar - Im Mitgliederbereich `Events` gibt es jetzt zusätzlich einen ICS-Download und einen persönlichen abonnierbaren Kalender-Feed für alle eigenen Events und Event-Teilnahmen -- Der Bereich `Events` ist im Mitgliederbereich jetzt zusätzlich in die Tabs `Meine Events`, `Synchronisation` und `Abgelaufene Events` gegliedert +- Der Bereich `Events` ist im Mitgliederbereich jetzt zusätzlich in die Tabs `Meine Events`, `Kalendersynchronisation` und `Abgelaufene Events` gegliedert +- Vorschläge für neue Orte und Veranstaltungen werden schon vor der Freigabe als mögliche Ortsauswahl für Events berücksichtigt, solange sie nicht abgelehnt oder archiviert wurden - Für später vorgemerkt: direkte Kalender-Anbindung großer Anbieter wie Google und Microsoft/Outlook per OAuth, zusätzlich zum bestehenden ICS-Feed - Interne Projektdateien und das Datenbankschema liegen nicht mehr im Root, sondern unter `Internal/` diff --git a/partials/landing/account/community-admin.php b/partials/landing/account/community-admin.php index 07e18e6..7c30868 100644 --- a/partials/landing/account/community-admin.php +++ b/partials/landing/account/community-admin.php @@ -12,6 +12,7 @@ if (!$userId) { $communityCfg = require __DIR__ . '/../../../config/community.php'; $access = $pdo ? new \App\CommunityAccess($pdo, $communityCfg) : null; $migration = $pdo ? new \App\CommunityMigration($pdo) : null; +$listingCatalog = $pdo ? new \App\ListingCatalog($pdo) : null; if (!$access || !$access->canModerateForum((int)$userId)) { http_response_code(403); @@ -23,11 +24,18 @@ $error = ''; $info = ''; $canManageApplications = $access->canManageApplications((int)$userId) && $access->supportsApplications(); $canManageRoles = $access->canManageRoles((int)$userId); +$canReviewListings = $listingCatalog !== null && !$access->hasRole((int)$userId, 'owner'); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = (string)($_POST['action'] ?? ''); try { - if ($action === 'application_decide') { + if ($action === 'listing_request_decide') { + if (!$canReviewListings || !$listingCatalog) { + throw new \RuntimeException('Keine Berechtigung für Listing-Freigaben.'); + } + $listingCatalog->decideModerationRequest((int)$userId, (int)($_POST['request_id'] ?? 0), (string)($_POST['decision'] ?? ''), (string)($_POST['review_note'] ?? '')); + $info = 'Listing-Anfrage wurde bearbeitet.'; + } elseif ($action === 'application_decide') { $access->decideApplication((int)$userId, (int)($_POST['application_id'] ?? 0), (string)($_POST['decision'] ?? ''), (string)($_POST['decision_reason'] ?? '')); $info = 'Bewerbung wurde bearbeitet.'; } elseif ($action === 'report_resolve') { @@ -51,6 +59,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } +$listingRequests = $canReviewListings && $listingCatalog ? $listingCatalog->listOpenModerationRequests() : []; $applications = $canManageApplications ? $access->listApplications('open') : []; $reports = $access->supportsReports() ? $access->listOpenReports() : []; $roleAssignments = $canManageRoles ? $access->listRoleAssignments() : []; @@ -84,6 +93,70 @@ $migrationStatus = ($migration && $canManageApplications) ? $migration->status()
+ +
+
+
+

Offene Orts- und Veranstaltungsanfragen

+

Neue Einträge sowie Änderungs- und Löschwünsche prüfen.

+
+
+
+ + 'Neu', + 'update' => 'Änderung', + 'delete' => 'Löschung', + default => 'Anfrage', + }; + ?> +
+
+ · +

Typ: · Von · am

+ +

Begründung:

+ +

+ +

+ +
+ Vorgeschlagener Titel:
+ Vorgeschlagene Adresse: +
+ +
+
+ + + +
+ + +
+
+
+ + +
Keine offenen Orts- oder Veranstaltungsanfragen.
+ +
+
+ +
diff --git a/partials/landing/account/dashboard.php b/partials/landing/account/dashboard.php index 746f658..591dbc7 100755 --- a/partials/landing/account/dashboard.php +++ b/partials/landing/account/dashboard.php @@ -18,8 +18,8 @@ if ($editingEvent && !empty($editEvent['starts_at'])) { $startVal = date('Y-m-d', strtotime((string)$editListing['starts_at'])); } $withChildrenValue = $editingEvent ? (((int)($editEvent['allow_kids'] ?? 1)) === 1 ? 'yes' : 'no') : (($editingListing && $currentEntryKind === 'editorial_event' && !empty($editListing['supports_registration'])) ? 'yes' : 'yes'); -$eventTitle = $editingEvent ? 'Event bearbeiten' : ($editingListing ? ($currentEntryKind === 'place' ? 'Ort bearbeiten' : 'Veranstaltung bearbeiten') : ((($section ?? 'events') === 'places') ? 'Ausflugsziel anlegen' : 'Neues Event anlegen')); -$submitLabel = $editingEvent ? 'Event speichern' : ($editingListing ? ($currentEntryKind === 'place' ? 'Ort speichern' : 'Veranstaltung speichern') : ((($section ?? 'events') === 'places') ? 'Ausflugsziel anlegen' : 'Event anlegen')); +$eventTitle = $editingEvent ? 'Event bearbeiten' : ($editingListing ? ($currentEntryKind === 'place' ? 'Änderung für Ort anfragen' : 'Änderung für Veranstaltung anfragen') : ((($section ?? 'events') === 'places') ? 'Ort oder Veranstaltung anlegen' : 'Neues Event anlegen')); +$submitLabel = $editingEvent ? 'Event speichern' : ($editingListing ? 'Änderungsanfrage senden' : ((($section ?? 'events') === 'places') ? 'Eintrag zur Freigabe einreichen' : 'Event anlegen')); $titleValue = $editingEvent ? (string)($editEvent['title'] ?? '') : (string)($editListing['title'] ?? ''); $teaserValue = $editingEvent ? (string)($editEvent['teaser_public'] ?? '') : (string)($editListing['teaser_public'] ?? ''); $descriptionValue = $editingEvent ? (string)($editEvent['description'] ?? '') : (string)($editListing['description'] ?? ''); @@ -87,7 +87,7 @@ $sectionLinks = [ 'profile' => 'Profil', 'children' => 'Kinder', 'events' => 'Events', - 'places' => 'Ausflugsziele', + 'places' => 'Orte & Veranstaltungen', 'community' => 'Community', 'settings' => 'Einstellungen', ]; @@ -279,7 +279,7 @@ if (!empty($canManageSystemSettings)) {