Files
pvemanager/backend/app/models/notification.py
dilshod aa8c06116d Add in-app notifications for new panel version availability
- Add notify_update_available() method to NotificationService
- Add translations for update notifications (ru/en)
- Add 'update' type to default notification types
- Add check_for_panel_updates() background task (runs every 6 hours)
- Notifications include link to settings page for easy update access
- Prevent duplicate notifications for same version
2025-12-16 19:38:04 +05:00

86 lines
3.7 KiB
Python

"""
Notification models for SQLAlchemy
"""
from sqlalchemy import Column, Integer, String, Boolean, DateTime, Text, ForeignKey, JSON
from sqlalchemy.sql import func
from backend.app.db import Base
class Notification(Base):
"""Notification model"""
__tablename__ = "notifications"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
type = Column(String(50), nullable=False) # vm_status, resource_alert, system, etc
level = Column(String(20), nullable=False) # critical, warning, info, success
title = Column(String(255), nullable=False)
message = Column(Text)
data = Column(JSON) # Additional structured data
link = Column(String(500)) # Deep link to related resource
source = Column(String(50)) # proxmox, ipam, system, docker
source_id = Column(String(100)) # VM ID, Network ID, etc
read = Column(Boolean, default=False)
read_at = Column(DateTime(timezone=True))
created_at = Column(DateTime(timezone=True), server_default=func.now())
expires_at = Column(DateTime(timezone=True)) # Auto-delete old notifications
def to_dict(self):
"""Convert to dictionary"""
return {
"id": self.id,
"user_id": self.user_id,
"type": self.type,
"level": self.level,
"title": self.title,
"message": self.message,
"data": self.data,
"link": self.link,
"source": self.source,
"source_id": self.source_id,
"read": self.read,
"read_at": self.read_at.isoformat() if self.read_at else None,
"created_at": self.created_at.isoformat() if self.created_at else None,
"expires_at": self.expires_at.isoformat() if self.expires_at else None,
}
class NotificationPreference(Base):
"""User notification preferences"""
__tablename__ = "notification_preferences"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=True, nullable=False)
enabled = Column(Boolean, default=True)
email_enabled = Column(Boolean, default=False)
email_critical_only = Column(Boolean, default=True)
telegram_enabled = Column(Boolean, default=False)
telegram_chat_id = Column(String(100))
webhook_url = Column(String(500))
notification_levels = Column(JSON, default=["critical", "warning", "info", "success"])
notification_types = Column(JSON, default=["vm_status", "resource_alert", "system", "update"])
quiet_hours_start = Column(String(5)) # HH:MM format
quiet_hours_end = Column(String(5)) # HH:MM format
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
def to_dict(self):
"""Convert to dictionary"""
return {
"id": self.id,
"user_id": self.user_id,
"enabled": self.enabled,
"email_enabled": self.email_enabled,
"email_critical_only": self.email_critical_only,
"telegram_enabled": self.telegram_enabled,
"telegram_chat_id": self.telegram_chat_id,
"webhook_url": self.webhook_url,
"notification_levels": self.notification_levels,
"notification_types": self.notification_types,
"quiet_hours_start": self.quiet_hours_start,
"quiet_hours_end": self.quiet_hours_end,
"created_at": self.created_at.isoformat() if self.created_at else None,
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
}