From 134b238dea1c4386e016efb598cca369aaa52981 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Wed, 29 Apr 2026 18:21:56 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20CalDAV-Update=20DTSTART-Fehler=20und=20H?= =?UTF-8?q?A-Events=20read-only=20-=20caldav=5Fclient:=20del+add=20statt?= =?UTF-8?q?=20direkter=20Zuweisung=20bei=20VEVENT-Properties=20=20=20(behe?= =?UTF-8?q?bt=20"DTSTART=20MUST=20appear=20exactly=20once"=20Validierungsf?= =?UTF-8?q?ehler)=20-=20HA-Events=20als=20read-only=20behandeln=20(kein=20?= =?UTF-8?q?Bearbeiten/L=C3=B6schen=20im=20Popup)=20-=20[object=20Object]?= =?UTF-8?q?=20Toast=20behoben:=20HA-Events=20fallen=20nicht=20mehr=20in=20?= =?UTF-8?q?CalDAV-Pfad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/caldav_client.py | 34 +++++++++++++++++++++++----------- frontend/js/calendar.js | 14 ++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/backend/caldav_client.py b/backend/caldav_client.py index d7a8db2..dc43b9e 100644 --- a/backend/caldav_client.py +++ b/backend/caldav_client.py @@ -237,31 +237,43 @@ def update_event( continue if "title" in data or "summary" in data: - component["SUMMARY"] = data.get("title", data.get("summary", "")) + if "SUMMARY" in component: + del component["SUMMARY"] + component.add("summary", data.get("title", data.get("summary", ""))) if "start" in data: + if "DTSTART" in component: + del component["DTSTART"] if data.get("allDay"): - component["DTSTART"] = date.fromisoformat(data["start"][:10]) + component.add("dtstart", date.fromisoformat(data["start"][:10])) else: - component["DTSTART"] = _parse_dt(data["start"]) + component.add("dtstart", _parse_dt(data["start"])) if "end" in data: + if "DTEND" in component: + del component["DTEND"] if data.get("allDay"): - component["DTEND"] = date.fromisoformat(data["end"][:10]) + component.add("dtend", date.fromisoformat(data["end"][:10])) else: - component["DTEND"] = _parse_dt(data["end"]) + component.add("dtend", _parse_dt(data["end"])) if "location" in data: - component["LOCATION"] = data["location"] + if "LOCATION" in component: + del component["LOCATION"] + component.add("location", data["location"]) if "description" in data: - component["DESCRIPTION"] = data["description"] + if "DESCRIPTION" in component: + del component["DESCRIPTION"] + component.add("description", data["description"]) if "color" in data: - component["X-CALENDARR-COLOR"] = data["color"] + if "X-CALENDARR-COLOR" in component: + del component["X-CALENDARR-COLOR"] + component.add("x-calendarr-color", data["color"]) if "rrule" in data: - if data["rrule"]: - component["RRULE"] = _parse_rrule_str(data["rrule"]) - elif "RRULE" in component: + if "RRULE" in component: del component["RRULE"] + if data["rrule"]: + component.add("rrule", _parse_rrule_str(data["rrule"])) if "exdate" in data and data["exdate"]: # Parse YYYYMMDD string into a proper EXDATE diff --git a/frontend/js/calendar.js b/frontend/js/calendar.js index a1e49f7..b2f8caf 100644 --- a/frontend/js/calendar.js +++ b/frontend/js/calendar.js @@ -994,8 +994,8 @@ function showEventPopup(ev, anchor) { popup.style.left = Math.max(8, left) + 'px'; popup.style.top = Math.max(8, top) + 'px'; - // Hide edit/delete for read-only iCal subscription events - const isReadOnly = (ev.source === 'ical'); + // Hide edit/delete for read-only sources (iCal subscriptions, Home Assistant) + const isReadOnly = (ev.source === 'ical' || ev.source === 'homeassistant'); document.getElementById('popup-edit').style.display = isReadOnly ? 'none' : ''; document.getElementById('popup-delete').style.display = isReadOnly ? 'none' : ''; @@ -1134,7 +1134,7 @@ function openNewEventModal(date) { } function openEditEventModal(ev) { - if (ev.source === 'ical') { showToast(t('event_readonly'), true); return; } + if (ev.source === 'ical' || ev.source === 'homeassistant') { showToast(t('event_readonly'), true); return; } state.editingEvent = ev; state.selectedEventColor = ev.color || ''; @@ -1426,11 +1426,9 @@ function bindEventModal() { await api.put(`/local/events/${encodeURIComponent(ev.id)}`, { title, start, end, allDay, location: loc, description: desc, color: color || null, rrule: rrule || '' } ); - } else if (ev.source === 'ical') { - const subId = ev.calendar_id.replace('ical-', ''); - await api.put(`/ical/events/${subId}/${encodeURIComponent(ev.id)}`, - { title, start, end, allDay, location: loc, description: desc, color: color || null } - ); + } else if (ev.source === 'ical' || ev.source === 'homeassistant') { + showToast(t('event_readonly'), true); + return; } else { await api.put( `/caldav/events/${encodeURIComponent(ev.id)}?event_url=${encodeURIComponent(ev.url)}&calendar_id=${ev.calendar_id}`,