Add per-calendar reminders_enabled flag (server)
New boolean column on every calendar type (CalDAV, local, Google, Home Assistant, iCal subscription), default ON so existing data is unchanged. Lets a calendar be shown without generating reminders/notifications. - models.py: reminders_enabled on the five calendar models - main.py _migrate(): ALTER TABLE ADD COLUMN for each table - caldav/google/homeassistant/local/ical routers: expose the flag in the calendar serialization and accept it in the calendar/subscription update endpoints Clients map event -> (source, calendar_id) -> reminders_enabled to skip scheduling notifications for disabled calendars. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -201,6 +201,15 @@ def _migrate():
|
|||||||
logging.info("Migration: added color to group_members")
|
logging.info("Migration: added color to group_members")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# Per-calendar reminder toggle (default ON = unchanged behaviour for existing data).
|
||||||
|
for tbl in ("calendars", "local_calendars", "google_calendars",
|
||||||
|
"homeassistant_calendars", "ical_subscriptions"):
|
||||||
|
try:
|
||||||
|
conn.execute(text(f"ALTER TABLE {tbl} ADD COLUMN reminders_enabled BOOLEAN DEFAULT 1"))
|
||||||
|
conn.commit()
|
||||||
|
logging.info("Migration: added reminders_enabled to %s", tbl)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
_migrate()
|
_migrate()
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ class Calendar(Base):
|
|||||||
color = Column(String(7), nullable=True)
|
color = Column(String(7), nullable=True)
|
||||||
enabled = Column(Boolean, default=True)
|
enabled = Column(Boolean, default=True)
|
||||||
sidebar_hidden = Column(Boolean, default=False)
|
sidebar_hidden = Column(Boolean, default=False)
|
||||||
|
# Whether events of this calendar generate reminders/notifications on clients.
|
||||||
|
reminders_enabled = Column(Boolean, default=True, nullable=False)
|
||||||
|
|
||||||
account = relationship("CalDAVAccount", back_populates="calendars")
|
account = relationship("CalDAVAccount", back_populates="calendars")
|
||||||
|
|
||||||
@@ -116,6 +118,8 @@ class LocalCalendar(Base):
|
|||||||
name = Column(String(100), nullable=False)
|
name = Column(String(100), nullable=False)
|
||||||
color = Column(String(7), default="#34a853")
|
color = Column(String(7), default="#34a853")
|
||||||
enabled = Column(Boolean, default=True)
|
enabled = Column(Boolean, default=True)
|
||||||
|
# Whether events of this calendar generate reminders/notifications on clients.
|
||||||
|
reminders_enabled = Column(Boolean, default=True, nullable=False)
|
||||||
|
|
||||||
user = relationship("User", back_populates="local_calendars")
|
user = relationship("User", back_populates="local_calendars")
|
||||||
events = relationship("LocalEvent", back_populates="calendar", cascade="all, delete-orphan")
|
events = relationship("LocalEvent", back_populates="calendar", cascade="all, delete-orphan")
|
||||||
@@ -158,6 +162,8 @@ class ICalSubscription(Base):
|
|||||||
url = Column(String(1000), nullable=False)
|
url = Column(String(1000), nullable=False)
|
||||||
color = Column(String(7), default="#46bdc6")
|
color = Column(String(7), default="#46bdc6")
|
||||||
enabled = Column(Boolean, default=True)
|
enabled = Column(Boolean, default=True)
|
||||||
|
# Whether events of this subscription generate reminders/notifications on clients.
|
||||||
|
reminders_enabled = Column(Boolean, default=True, nullable=False)
|
||||||
refresh_minutes = Column(Integer, default=60)
|
refresh_minutes = Column(Integer, default=60)
|
||||||
last_fetched = Column(DateTime, nullable=True)
|
last_fetched = Column(DateTime, nullable=True)
|
||||||
cached_ics = Column(Text, nullable=True)
|
cached_ics = Column(Text, nullable=True)
|
||||||
@@ -210,6 +216,8 @@ class GoogleCalendar(Base):
|
|||||||
color = Column(String(7), nullable=True)
|
color = Column(String(7), nullable=True)
|
||||||
enabled = Column(Boolean, default=True)
|
enabled = Column(Boolean, default=True)
|
||||||
sidebar_hidden = Column(Boolean, default=False)
|
sidebar_hidden = Column(Boolean, default=False)
|
||||||
|
# Whether events of this calendar generate reminders/notifications on clients.
|
||||||
|
reminders_enabled = Column(Boolean, default=True, nullable=False)
|
||||||
|
|
||||||
account = relationship("GoogleAccount", back_populates="calendars")
|
account = relationship("GoogleAccount", back_populates="calendars")
|
||||||
|
|
||||||
@@ -243,6 +251,8 @@ class HomeAssistantCalendar(Base):
|
|||||||
color = Column(String(7), nullable=True)
|
color = Column(String(7), nullable=True)
|
||||||
enabled = Column(Boolean, default=True)
|
enabled = Column(Boolean, default=True)
|
||||||
sidebar_hidden = Column(Boolean, default=False)
|
sidebar_hidden = Column(Boolean, default=False)
|
||||||
|
# Whether events of this calendar generate reminders/notifications on clients.
|
||||||
|
reminders_enabled = Column(Boolean, default=True, nullable=False)
|
||||||
|
|
||||||
account = relationship("HomeAssistantAccount", back_populates="calendars")
|
account = relationship("HomeAssistantAccount", back_populates="calendars")
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class CalendarUpdate(BaseModel):
|
|||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
sidebar_hidden: Optional[bool] = None
|
sidebar_hidden: Optional[bool] = None
|
||||||
|
reminders_enabled: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
class EventCreate(BaseModel):
|
class EventCreate(BaseModel):
|
||||||
@@ -84,6 +85,7 @@ def _account_dict(a: models.CalDAVAccount) -> dict:
|
|||||||
"enabled": c.enabled,
|
"enabled": c.enabled,
|
||||||
"cal_id": c.cal_id,
|
"cal_id": c.cal_id,
|
||||||
"sidebar_hidden": bool(c.sidebar_hidden),
|
"sidebar_hidden": bool(c.sidebar_hidden),
|
||||||
|
"reminders_enabled": bool(c.reminders_enabled),
|
||||||
}
|
}
|
||||||
for c in a.calendars
|
for c in a.calendars
|
||||||
],
|
],
|
||||||
@@ -270,6 +272,8 @@ def update_calendar(
|
|||||||
calendar.name = data.name
|
calendar.name = data.name
|
||||||
if data.sidebar_hidden is not None:
|
if data.sidebar_hidden is not None:
|
||||||
calendar.sidebar_hidden = data.sidebar_hidden
|
calendar.sidebar_hidden = data.sidebar_hidden
|
||||||
|
if data.reminders_enabled is not None:
|
||||||
|
calendar.reminders_enabled = data.reminders_enabled
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ def _account_dict(a: models.GoogleAccount) -> dict:
|
|||||||
"color": c.color or "#4285f4",
|
"color": c.color or "#4285f4",
|
||||||
"enabled": c.enabled,
|
"enabled": c.enabled,
|
||||||
"sidebar_hidden": bool(c.sidebar_hidden),
|
"sidebar_hidden": bool(c.sidebar_hidden),
|
||||||
|
"reminders_enabled": bool(c.reminders_enabled),
|
||||||
}
|
}
|
||||||
for c in a.calendars
|
for c in a.calendars
|
||||||
if not _is_system_calendar(c.cal_id)
|
if not _is_system_calendar(c.cal_id)
|
||||||
@@ -344,6 +345,7 @@ class GoogleCalendarUpdate(BaseModel):
|
|||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
sidebar_hidden: Optional[bool] = None
|
sidebar_hidden: Optional[bool] = None
|
||||||
|
reminders_enabled: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
@router.put("/calendars/{calendar_id}")
|
@router.put("/calendars/{calendar_id}")
|
||||||
@@ -372,6 +374,8 @@ def update_calendar(
|
|||||||
gcal.name = data.name
|
gcal.name = data.name
|
||||||
if data.sidebar_hidden is not None:
|
if data.sidebar_hidden is not None:
|
||||||
gcal.sidebar_hidden = data.sidebar_hidden
|
gcal.sidebar_hidden = data.sidebar_hidden
|
||||||
|
if data.reminders_enabled is not None:
|
||||||
|
gcal.reminders_enabled = data.reminders_enabled
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
@@ -349,6 +349,7 @@ def _account_dict(a: models.HomeAssistantAccount) -> dict:
|
|||||||
"color": c.color or HA_DEFAULT_COLOR,
|
"color": c.color or HA_DEFAULT_COLOR,
|
||||||
"enabled": c.enabled,
|
"enabled": c.enabled,
|
||||||
"sidebar_hidden": bool(c.sidebar_hidden),
|
"sidebar_hidden": bool(c.sidebar_hidden),
|
||||||
|
"reminders_enabled": bool(c.reminders_enabled),
|
||||||
}
|
}
|
||||||
for c in a.calendars
|
for c in a.calendars
|
||||||
],
|
],
|
||||||
@@ -375,6 +376,7 @@ class HACalendarUpdate(BaseModel):
|
|||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
sidebar_hidden: Optional[bool] = None
|
sidebar_hidden: Optional[bool] = None
|
||||||
|
reminders_enabled: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
# ── Endpoints ─────────────────────────────────────────────
|
# ── Endpoints ─────────────────────────────────────────────
|
||||||
@@ -623,6 +625,8 @@ def update_calendar(
|
|||||||
cal.name = data.name
|
cal.name = data.name
|
||||||
if data.sidebar_hidden is not None:
|
if data.sidebar_hidden is not None:
|
||||||
cal.sidebar_hidden = data.sidebar_hidden
|
cal.sidebar_hidden = data.sidebar_hidden
|
||||||
|
if data.reminders_enabled is not None:
|
||||||
|
cal.reminders_enabled = data.reminders_enabled
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class SubscriptionUpdate(BaseModel):
|
|||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
enabled: Optional[bool] = None
|
enabled: Optional[bool] = None
|
||||||
refresh_minutes: Optional[int] = None
|
refresh_minutes: Optional[int] = None
|
||||||
|
reminders_enabled: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
def _sub_dict(sub: models.ICalSubscription) -> dict:
|
def _sub_dict(sub: models.ICalSubscription) -> dict:
|
||||||
@@ -38,6 +39,7 @@ def _sub_dict(sub: models.ICalSubscription) -> dict:
|
|||||||
"url": sub.url,
|
"url": sub.url,
|
||||||
"color": sub.color,
|
"color": sub.color,
|
||||||
"enabled": sub.enabled,
|
"enabled": sub.enabled,
|
||||||
|
"reminders_enabled": bool(sub.reminders_enabled),
|
||||||
"refresh_minutes": sub.refresh_minutes,
|
"refresh_minutes": sub.refresh_minutes,
|
||||||
"last_fetched": sub.last_fetched.isoformat() if sub.last_fetched else None,
|
"last_fetched": sub.last_fetched.isoformat() if sub.last_fetched else None,
|
||||||
}
|
}
|
||||||
@@ -215,6 +217,8 @@ def update_subscription(
|
|||||||
sub.enabled = data.enabled
|
sub.enabled = data.enabled
|
||||||
if data.refresh_minutes is not None:
|
if data.refresh_minutes is not None:
|
||||||
sub.refresh_minutes = data.refresh_minutes
|
sub.refresh_minutes = data.refresh_minutes
|
||||||
|
if data.reminders_enabled is not None:
|
||||||
|
sub.reminders_enabled = data.reminders_enabled
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class CalendarUpdate(BaseModel):
|
|||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
enabled: Optional[bool] = None
|
enabled: Optional[bool] = None
|
||||||
|
reminders_enabled: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
class EventCreate(BaseModel):
|
class EventCreate(BaseModel):
|
||||||
@@ -72,6 +73,7 @@ def _cal_dict(cal: models.LocalCalendar, *, owned: bool = True,
|
|||||||
"name": cal.name,
|
"name": cal.name,
|
||||||
"color": cal.color,
|
"color": cal.color,
|
||||||
"enabled": cal.enabled,
|
"enabled": cal.enabled,
|
||||||
|
"reminders_enabled": bool(cal.reminders_enabled),
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"owned": owned,
|
"owned": owned,
|
||||||
}
|
}
|
||||||
@@ -199,6 +201,8 @@ def update_calendar(
|
|||||||
cal.color = data.color
|
cal.color = data.color
|
||||||
if data.enabled is not None:
|
if data.enabled is not None:
|
||||||
cal.enabled = data.enabled
|
cal.enabled = data.enabled
|
||||||
|
if data.reminders_enabled is not None:
|
||||||
|
cal.reminders_enabled = data.reminders_enabled
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user