Fix weekly recurrence crash: null fields in serialized rule
model_dump() includes None values for optional RecurrenceRule fields. When serialized to JSON, these become explicit nulls (e.g. "weekday": null). The recurrence service then does int(None) which raises TypeError. Fix: strip None values when serializing rule to JSON, and add defensive None handling in recurrence service for all rule.get() calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f66ffba0ef
commit
1a707ff179
@ -192,8 +192,9 @@ async def create_event(
|
|||||||
data["calendar_id"] = await _get_default_calendar_id(db)
|
data["calendar_id"] = await _get_default_calendar_id(db)
|
||||||
|
|
||||||
# Serialize RecurrenceRule object to JSON string for DB storage
|
# Serialize RecurrenceRule object to JSON string for DB storage
|
||||||
|
# Exclude None values so defaults in recurrence service work correctly
|
||||||
rule_obj = data.pop("recurrence_rule", None)
|
rule_obj = data.pop("recurrence_rule", None)
|
||||||
rule_json: Optional[str] = json.dumps(rule_obj) if rule_obj else None
|
rule_json: Optional[str] = json.dumps({k: v for k, v in rule_obj.items() if v is not None}) if rule_obj else None
|
||||||
|
|
||||||
if rule_json:
|
if rule_json:
|
||||||
# Parent template: is_recurring=True, no parent_event_id
|
# Parent template: is_recurring=True, no parent_event_id
|
||||||
@ -282,7 +283,7 @@ async def update_event(
|
|||||||
# Serialize RecurrenceRule → JSON string if present in update payload
|
# Serialize RecurrenceRule → JSON string if present in update payload
|
||||||
rule_obj = update_data.pop("recurrence_rule", None)
|
rule_obj = update_data.pop("recurrence_rule", None)
|
||||||
if rule_obj is not None:
|
if rule_obj is not None:
|
||||||
update_data["recurrence_rule"] = json.dumps(rule_obj) if rule_obj else None
|
update_data["recurrence_rule"] = json.dumps({k: v for k, v in rule_obj.items() if v is not None}) if rule_obj else None
|
||||||
|
|
||||||
start = update_data.get("start_datetime", event.start_datetime)
|
start = update_data.get("start_datetime", event.start_datetime)
|
||||||
end_dt = update_data.get("end_datetime", event.end_datetime)
|
end_dt = update_data.get("end_datetime", event.end_datetime)
|
||||||
|
|||||||
@ -85,7 +85,7 @@ def generate_occurrences(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if rule_type == "every_n_days":
|
if rule_type == "every_n_days":
|
||||||
interval: int = int(rule.get("interval", 1))
|
interval: int = int(rule.get("interval") or 1)
|
||||||
if interval < 1:
|
if interval < 1:
|
||||||
interval = 1
|
interval = 1
|
||||||
current = parent_start + timedelta(days=interval)
|
current = parent_start + timedelta(days=interval)
|
||||||
@ -94,7 +94,7 @@ def generate_occurrences(
|
|||||||
current += timedelta(days=interval)
|
current += timedelta(days=interval)
|
||||||
|
|
||||||
elif rule_type == "weekly":
|
elif rule_type == "weekly":
|
||||||
weekday: int = int(rule.get("weekday", parent_start.weekday()))
|
weekday: int = int(rule.get("weekday") if rule.get("weekday") is not None else parent_start.weekday())
|
||||||
# Start from the week after the parent
|
# Start from the week after the parent
|
||||||
days_ahead = (weekday - parent_start.weekday()) % 7
|
days_ahead = (weekday - parent_start.weekday()) % 7
|
||||||
if days_ahead == 0:
|
if days_ahead == 0:
|
||||||
@ -105,8 +105,8 @@ def generate_occurrences(
|
|||||||
current += timedelta(weeks=1)
|
current += timedelta(weeks=1)
|
||||||
|
|
||||||
elif rule_type == "monthly_nth_weekday":
|
elif rule_type == "monthly_nth_weekday":
|
||||||
week: int = int(rule.get("week", 1))
|
week: int = int(rule.get("week") or 1)
|
||||||
weekday = int(rule.get("weekday", parent_start.weekday()))
|
weekday = int(rule.get("weekday") if rule.get("weekday") is not None else parent_start.weekday())
|
||||||
# Advance month by month
|
# Advance month by month
|
||||||
year, month = parent_start.year, parent_start.month
|
year, month = parent_start.year, parent_start.month
|
||||||
# Move to the next month from the parent
|
# Move to the next month from the parent
|
||||||
@ -139,7 +139,7 @@ def generate_occurrences(
|
|||||||
break
|
break
|
||||||
|
|
||||||
elif rule_type == "monthly_date":
|
elif rule_type == "monthly_date":
|
||||||
day: int = int(rule.get("day", parent_start.day))
|
day: int = int(rule.get("day") or parent_start.day)
|
||||||
year, month = parent_start.year, parent_start.month
|
year, month = parent_start.year, parent_start.month
|
||||||
month += 1
|
month += 1
|
||||||
if month > 12:
|
if month > 12:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user