import json import logging import requests from datetime import datetime, timezone, timedelta from sqlalchemy.orm import Session from config import get_settings from models import Computer, Notification settings = get_settings() logger = logging.getLogger(__name__) def create_notification(db: Session, computer: Computer, ntype: str, title: str, message: str) -> Notification: n = Notification( computer_id=computer.id, type=ntype, title=title, message=message, ) db.add(n) db.commit() db.refresh(n) send_external_notifications(n, computer) return n def check_offline_computers(db: Session): """Mark online computers that missed the threshold as offline and create notifications.""" threshold = datetime.now(timezone.utc) - timedelta(minutes=settings.OFFLINE_THRESHOLD_MINUTES) stale = ( db.query(Computer) .filter(Computer.status == "online", Computer.last_seen < threshold) .all() ) for computer in stale: computer.status = "offline" db.add(computer) # avoid duplicate notifications for the same offline event existing = ( db.query(Notification) .filter( Notification.computer_id == computer.id, Notification.type == "offline", Notification.is_read == False, ) .first() ) if not existing: msg = ( f"ПК {computer.hostname} не присылал данные более " f"{settings.OFFLINE_THRESHOLD_MINUTES} минут. " f"Последний пользователь: {computer.current_user or '-'}, " f"IP: {computer.current_ip or '-'}" ) create_notification(db, computer, "offline", f"ПК {computer.hostname} офлайн", msg) db.commit() def send_external_notifications(notification: Notification, computer: Computer): if settings.NOTIFICATION_WEBHOOK_URL: try: requests.post( settings.NOTIFICATION_WEBHOOK_URL, json={ "type": notification.type, "title": notification.title, "message": notification.message, "hostname": computer.hostname, "user": computer.current_user, "ip": computer.current_ip, }, timeout=10, ) except Exception as e: logger.error("Webhook notification failed: %s", e) if settings.NOTIFICATION_TELEGRAM_BOT_TOKEN and settings.NOTIFICATION_TELEGRAM_CHAT_ID: try: text = f"*{notification.title}*\n\n{notification.message}" requests.post( f"https://api.telegram.org/bot{settings.NOTIFICATION_TELEGRAM_BOT_TOKEN}/sendMessage", json={ "chat_id": settings.NOTIFICATION_TELEGRAM_CHAT_ID, "text": text, "parse_mode": "Markdown", }, timeout=10, ) except Exception as e: logger.error("Telegram notification failed: %s", e) def mark_notification_read(db: Session, notification_id: int) -> bool: n = db.query(Notification).filter(Notification.id == notification_id).first() if not n: return False n.is_read = True n.read_at = datetime.now(timezone.utc) db.commit() return True def get_unread_count(db: Session) -> int: return db.query(Notification).filter(Notification.is_read == False).count()