# /// # models.py # 描述:数据库模型,使用 SQLAlchemy ORM # 作者:AI Generated # 创建日期:2026-04-05 # /// from sqlalchemy import create_engine, Column, String, Boolean, Integer, DateTime, Text from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from datetime import datetime import pytz Base = declarative_base() _asia_tz = pytz.timezone('Asia/Shanghai') def now_asia(): return datetime.now(_asia_tz) class Node(Base): __tablename__ = "nodes" node_id = Column(String(50), primary_key=True) name = Column(String(100), nullable=False) api_url = Column(String(255), nullable=False) api_key = Column(String(255), nullable=False) enabled = Column(Boolean, default=True) description = Column(Text, default="") group = Column(String(50), default="default", name="node_group") status = Column(String(20), default="inactive") wechat_status = Column(String(20), default="online") is_healthy = Column(Boolean, default=False) health_message = Column(String(255), default="") created_at = Column(DateTime, default=now_asia) updated_at = Column(DateTime, default=now_asia, onupdate=now_asia) def to_dict(self): return { "node_id": self.node_id, "name": self.name, "api_url": self.api_url, "api_key": self.api_key, "enabled": self.enabled, "description": self.description, "group": self.group, "status": self.status, "wechat_status": self.wechat_status, "is_healthy": self.is_healthy, "health_message": self.health_message, "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None } class WebhookUrl(Base): __tablename__ = "webhook_urls" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(100), nullable=False) url = Column(String(500), nullable=False) format = Column(String(20), default="bark") enabled = Column(Boolean, default=True) event_types = Column(Text, default="") created_at = Column(DateTime, default=now_asia) updated_at = Column(DateTime, default=now_asia, onupdate=now_asia) def to_dict(self): return { "id": self.id, "name": self.name, "url": self.url, "format": self.format, "enabled": self.enabled, "event_types": self.event_types.split(",") if self.event_types else [], "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None } class LogEntry(Base): __tablename__ = "logs" id = Column(Integer, primary_key=True, autoincrement=True) timestamp = Column(DateTime, default=now_asia) level = Column(String(20), nullable=False) source = Column(String(50), nullable=False) message = Column(Text, nullable=False) def to_dict(self): return { "id": self.id, "timestamp": self.timestamp.strftime("%Y-%m-%d %H:%M:%S") if self.timestamp else None, "level": self.level, "source": self.source, "message": self.message } class PluginConfig(Base): __tablename__ = "plugin_configs" id = Column(Integer, primary_key=True, autoincrement=True) plugin_name = Column(String(100), unique=True, nullable=False) config_json = Column(Text, default="{}") enabled = Column(Boolean, default=False) created_at = Column(DateTime, default=now_asia) updated_at = Column(DateTime, default=now_asia, onupdate=now_asia) def to_dict(self): import json return { "id": self.id, "plugin_name": self.plugin_name, "config": json.loads(self.config_json) if self.config_json else {}, "enabled": self.enabled, "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None } class DatabaseManager: def __init__(self, database_url: str): self.engine = create_engine(database_url, echo=False, pool_pre_ping=True) self.SessionLocal = sessionmaker(bind=self.engine) def create_tables(self): Base.metadata.create_all(self.engine) def get_session(self): return self.SessionLocal() def close(self): self.engine.dispose()