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/<id>/my-color.
UI-Hinweis: "Nur fuer deine Ansicht - <Owner> behaelt seine Farbe".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker
2026-04-12 13:14:45 +02:00
parent 2170f4a7b1
commit e85338761d
3 changed files with 61 additions and 0 deletions
+32
View File
@@ -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/<int:cal_id>/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/<int:cal_id>', methods=['DELETE'])
@token_required
def delete_calendar(cal_id):