mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-03 20:56:18 +02:00
POST /notifications/app-message delivers an app's message to every channel with the new "Messages from connected apps" switch on (off by default), through quiet hours, the digest and the log. API keys need the new "Send notifications" permission, and their owner notifications:update; plain text, http(s) links, 20 messages a minute per key. The electricity-price door and this one now share one scoped-key check. /queue?batch=<id> opens and highlights one batch order.
154 lines
8.0 KiB
Python
154 lines
8.0 KiB
Python
"""Notification provider and log models for push notifications."""
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, Text
|
|
from sqlalchemy.orm import relationship
|
|
|
|
from backend.app.core.database import Base
|
|
|
|
|
|
class NotificationDigestQueue(Base):
|
|
"""Model for queuing notifications to be sent in daily digest."""
|
|
|
|
__tablename__ = "notification_digest_queue"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
provider_id = Column(Integer, ForeignKey("notification_providers.id", ondelete="CASCADE"), nullable=False)
|
|
event_type = Column(String(50), nullable=False) # print_start, print_complete, etc.
|
|
title = Column(String(255), nullable=False)
|
|
message = Column(Text, nullable=False)
|
|
printer_id = Column(Integer, ForeignKey("printers.id", ondelete="SET NULL"), nullable=True)
|
|
printer_name = Column(String(100), nullable=True)
|
|
created_at = Column(DateTime, default=datetime.utcnow, index=True)
|
|
|
|
# Relationships
|
|
provider = relationship("NotificationProvider", back_populates="digest_queue")
|
|
|
|
|
|
class NotificationLog(Base):
|
|
"""Model for logging sent notifications."""
|
|
|
|
__tablename__ = "notification_logs"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
provider_id = Column(Integer, ForeignKey("notification_providers.id", ondelete="CASCADE"), nullable=False)
|
|
event_type = Column(String(50), nullable=False) # print_start, print_complete, etc.
|
|
title = Column(String(255), nullable=False)
|
|
message = Column(Text, nullable=False)
|
|
success = Column(Boolean, default=True)
|
|
error_message = Column(Text, nullable=True)
|
|
printer_id = Column(Integer, ForeignKey("printers.id", ondelete="SET NULL"), nullable=True)
|
|
printer_name = Column(String(100), nullable=True) # Store name in case printer is deleted
|
|
created_at = Column(DateTime, default=datetime.utcnow, index=True)
|
|
|
|
# Relationships
|
|
provider = relationship("NotificationProvider", back_populates="logs")
|
|
|
|
|
|
class NotificationProvider(Base):
|
|
"""Model for notification providers (WhatsApp, ntfy, Pushover, etc.)."""
|
|
|
|
__tablename__ = "notification_providers"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String(100), nullable=False) # User-defined name
|
|
provider_type = Column(String(50), nullable=False) # callmebot, ntfy, pushover, telegram, email
|
|
enabled = Column(Boolean, default=True)
|
|
|
|
# Provider-specific configuration stored as JSON string
|
|
config = Column(Text, nullable=False)
|
|
|
|
# Event triggers - print lifecycle
|
|
on_print_start = Column(Boolean, default=False)
|
|
on_print_complete = Column(Boolean, default=True)
|
|
on_print_failed = Column(Boolean, default=True)
|
|
on_print_stopped = Column(Boolean, default=True) # User cancelled/stopped print
|
|
on_print_progress = Column(Boolean, default=False) # 25%, 50%, 75% milestones
|
|
on_print_missing_spool_assignment = Column(Boolean, default=False) # Print started with unassigned required tray(s)
|
|
on_billing_charge_failed = Column(Boolean, default=True) # A completed/stopped print could not be charged
|
|
|
|
# Event triggers - printer status
|
|
on_printer_offline = Column(Boolean, default=False)
|
|
on_printer_error = Column(Boolean, default=False) # AMS issues, etc.
|
|
on_ai_failure_detection = Column(Boolean, default=False) # Obico spaghetti / failure detection (#1794)
|
|
on_filament_low = Column(Boolean, default=False)
|
|
on_maintenance_due = Column(Boolean, default=False) # Maintenance reminder
|
|
|
|
# Event triggers - AMS environmental alarms (regular AMS with 4 slots)
|
|
on_ams_humidity_high = Column(Boolean, default=False) # AMS humidity above threshold
|
|
on_ams_temperature_high = Column(Boolean, default=False) # AMS temperature above threshold
|
|
# Auto-drying gave up on a unit (#2770). Defaults True: it reports that
|
|
# Bambuddy has stopped acting, which nothing else in the UI would say.
|
|
on_ams_drying_suspended = Column(Boolean, default=True)
|
|
|
|
# Event triggers - AMS-HT environmental alarms (single slot heated AMS)
|
|
on_ams_ht_humidity_high = Column(Boolean, default=False) # AMS-HT humidity above threshold
|
|
on_ams_ht_temperature_high = Column(Boolean, default=False) # AMS-HT temperature above threshold
|
|
|
|
# Event triggers - Home Assistant sensors bound to a printer (#1148)
|
|
on_ha_sensor_alert = Column(Boolean, default=False) # Bound HA sensor entered its alert state
|
|
|
|
# Event triggers - Home Assistant sensors bound to a storage location (#2824)
|
|
# Its own column rather than reusing on_ha_sensor_alert above: that one can
|
|
# be scoped to a single printer, and a location alert has no printer to
|
|
# scope by, so sharing it would leak drybox alerts to a provider narrowed
|
|
# to one printer's sensors.
|
|
on_location_ha_sensor_alert = Column(Boolean, default=False)
|
|
|
|
# Event triggers - Build plate detection
|
|
on_plate_not_empty = Column(Boolean, default=True) # Objects detected on plate before print
|
|
# Off by default: fires after every print, alongside the print-complete alert (#2525)
|
|
on_plate_clear_required = Column(Boolean, default=False) # Print ended, queue gated until plate is confirmed clear
|
|
|
|
# Print asked for an outcome verdict (#1898). Defaults ON: it only ever
|
|
# fires for prints where the user opted in per-job, so the provider-level
|
|
# toggle exists to silence a channel, not to enable the feature.
|
|
on_print_confirm_request = Column(Boolean, default=True)
|
|
|
|
# Event triggers - Bed cooled after print
|
|
on_bed_cooled = Column(Boolean, default=False) # Bed cooled below threshold after print
|
|
on_first_layer_complete = Column(Boolean, default=False) # First layer finished printing
|
|
# Messages another application sends through Bambuddy (POST /notifications/app-message),
|
|
# e.g. Bambuddy Orders' "an order needs you". Off by default: nothing new arrives on upgrade.
|
|
on_app_message = Column(Boolean, default=False)
|
|
|
|
# Event triggers - Inventory stock alerts
|
|
on_stock_reorder_alert = Column(Boolean, default=False) # SKU hits reorder point
|
|
on_stock_break_alert = Column(Boolean, default=False) # Stock will run out before replenishment
|
|
|
|
# Event triggers - Print queue
|
|
on_queue_job_added = Column(Boolean, default=False) # Job added to queue
|
|
on_queue_job_assigned = Column(Boolean, default=False) # Model-based job assigned to printer
|
|
on_queue_job_started = Column(Boolean, default=False) # Queue job started printing
|
|
on_queue_job_waiting = Column(Boolean, default=True) # Job waiting for filament or printer
|
|
on_queue_job_skipped = Column(Boolean, default=True) # Job skipped (previous print failed)
|
|
on_queue_job_failed = Column(Boolean, default=True) # Job failed to start
|
|
on_queue_completed = Column(Boolean, default=False) # All pending jobs finished
|
|
|
|
# Quiet hours (do not disturb)
|
|
quiet_hours_enabled = Column(Boolean, default=False)
|
|
quiet_hours_start = Column(String(5), nullable=True) # HH:MM format, e.g., "22:00"
|
|
quiet_hours_end = Column(String(5), nullable=True) # HH:MM format, e.g., "07:00"
|
|
|
|
# Daily digest (batch notifications into a single daily summary)
|
|
daily_digest_enabled = Column(Boolean, default=False)
|
|
daily_digest_time = Column(String(5), nullable=True) # HH:MM format, e.g., "08:00"
|
|
|
|
# Optional: Link to specific printer (NULL = all printers)
|
|
printer_id = Column(Integer, ForeignKey("printers.id", ondelete="SET NULL"), nullable=True)
|
|
|
|
# Status tracking
|
|
last_success = Column(DateTime, nullable=True)
|
|
last_error = Column(Text, nullable=True)
|
|
last_error_at = Column(DateTime, nullable=True)
|
|
|
|
# Timestamps
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
# Relationships
|
|
printer = relationship("Printer", back_populates="notification_providers")
|
|
logs = relationship("NotificationLog", back_populates="provider", cascade="all, delete-orphan")
|
|
digest_queue = relationship("NotificationDigestQueue", back_populates="provider", cascade="all, delete-orphan")
|