From e85338761d2ec9688a53ae7423c42dfc81d1783a Mon Sep 17 00:00:00 2001 From: Stefan Hacker Date: Sun, 12 Apr 2026 13:14:45 +0200 Subject: [PATCH] feat: Persoenliche Farbe fuer freigegebene Kalender CalendarShare bekommt color-Spalte. Im Kalender-Menue kann jeder Benutzer eine eigene Anzeigefarbe fuer einen mit ihm geteilten Kalender setzen, ohne dass sich dadurch die Farbe beim Eigentuemer oder anderen Share-Empfaengern aendert. * Owner: Farbe aendert den Kalender direkt (wie bisher). * Share-Empfaenger: Farbe landet in CalendarShare.color und wird nur fuer ihn ausgeliefert (list_calendars injiziert sie in 'color', Owner-Farbe bleibt in 'owner_color' als Referenz). Neuer Endpoint: PUT /calendars//my-color. UI-Hinweis: "Nur fuer deine Ansicht - behaelt seine Farbe". Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/app/api/calendar.py | 32 +++++++++++++++++++++++++++++ backend/app/models/calendar.py | 1 + frontend/src/views/CalendarView.vue | 28 +++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/backend/app/api/calendar.py b/backend/app/api/calendar.py index 903ab15..6e9d355 100644 --- a/backend/app/api/calendar.py +++ b/backend/app/api/calendar.py @@ -100,6 +100,11 @@ def list_calendars(): calendar_id=c.id, shared_with_id=user.id ).first() d['permission'] = share.permission if share else 'read' + # Per-user color override: the owner's color is kept in 'owner_color' + # so the UI can show both, and 'color' reflects what this user picked. + d['owner_color'] = c.color + if share and share.color: + d['color'] = share.color d['owner_name'] = c.owner.username result.append(d) @@ -146,6 +151,33 @@ def update_calendar(cal_id): return jsonify(cal.to_dict()), 200 +@api_bp.route('/calendars//my-color', methods=['PUT']) +@token_required +def set_my_calendar_color(cal_id): + """Personal display color for a shared calendar. Doesn't affect the + owner's calendar color or any other user's view.""" + user = request.current_user + cal = db.session.get(Calendar, cal_id) + if not cal: + return jsonify({'error': 'Nicht gefunden'}), 404 + + color = (request.get_json() or {}).get('color', '').strip() + + if cal.owner_id == user.id: + # Owner -> update the calendar itself + if color: + cal.color = color + db.session.commit() + return jsonify({'color': cal.color}), 200 + + share = CalendarShare.query.filter_by(calendar_id=cal_id, shared_with_id=user.id).first() + if not share: + return jsonify({'error': 'Kein Zugriff'}), 403 + share.color = color or None + db.session.commit() + return jsonify({'color': share.color or cal.color}), 200 + + @api_bp.route('/calendars/', methods=['DELETE']) @token_required def delete_calendar(cal_id): diff --git a/backend/app/models/calendar.py b/backend/app/models/calendar.py index fefb946..7aa7ea8 100644 --- a/backend/app/models/calendar.py +++ b/backend/app/models/calendar.py @@ -82,6 +82,7 @@ class CalendarShare(db.Model): calendar_id = db.Column(db.Integer, db.ForeignKey('calendars.id'), nullable=False, index=True) shared_with_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True) permission = db.Column(db.String(20), nullable=False, default='read') # 'read' or 'readwrite' + color = db.Column(db.String(7), nullable=True) # Persoenliche Anzeige-Farbe shared_with = db.relationship('User', backref='shared_calendars') diff --git a/frontend/src/views/CalendarView.vue b/frontend/src/views/CalendarView.vue index 3983db9..8613fb0 100644 --- a/frontend/src/views/CalendarView.vue +++ b/frontend/src/views/CalendarView.vue @@ -146,6 +146,19 @@

{{ selectedCal.name }}

+
+ +
+ + + Nur fuer deine Ansicht - {{ selectedCal.owner_name }} behaelt seine Farbe + +
+
+