diff --git a/backend/app/models.py b/backend/app/models.py index 324ff9a..99a5478 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -1,82 +1,132 @@ from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, ForeignKey, JSON from sqlalchemy.orm import relationship -from datetime import datetime +from datetime import datetime, timezone from .database import Base + class Source(Base): __tablename__ = "sources" - - id = Column(Integer, primary_key=True, index=True) + + id = Column(Integer, primary_key=True) name = Column(String, nullable=False) type = Column(String, nullable=False) # local, ssh, database - config = Column(JSON, default=dict) - created_at = Column(DateTime, default=datetime.utcnow) - updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + config = Column(JSON, default=lambda: {}) + created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) + updated_at = Column( + DateTime, + default=lambda: datetime.now(timezone.utc), + onupdate=lambda: datetime.now(timezone.utc), + ) + jobs = relationship("Job", back_populates="source", cascade="all, delete-orphan") + def __repr__(self): + return f"" + + class Job(Base): __tablename__ = "jobs" - - id = Column(Integer, primary_key=True, index=True) + + id = Column(Integer, primary_key=True) name = Column(String, nullable=False) - source_id = Column(Integer, ForeignKey("sources.id"), nullable=False) + source_id = Column(Integer, ForeignKey("sources.id"), nullable=False, index=True) strategy = Column(String, nullable=False, default="full") # full, incremental destination_path = Column(String, nullable=False) - exclude_patterns = Column(JSON, default=list) + exclude_patterns = Column(JSON, default=lambda: []) enabled = Column(Boolean, default=True) - created_at = Column(DateTime, default=datetime.utcnow) - updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - + created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) + updated_at = Column( + DateTime, + default=lambda: datetime.now(timezone.utc), + onupdate=lambda: datetime.now(timezone.utc), + ) + source = relationship("Source", back_populates="jobs") - schedule = relationship("Schedule", back_populates="job", uselist=False, cascade="all, delete-orphan") - executions = relationship("JobExecution", back_populates="job", cascade="all, delete-orphan") + schedule = relationship( + "Schedule", back_populates="job", uselist=False, cascade="all, delete-orphan" + ) + executions = relationship( + "JobExecution", back_populates="job", cascade="all, delete-orphan" + ) + + def __repr__(self): + return f"" + class Schedule(Base): __tablename__ = "schedules" - - id = Column(Integer, primary_key=True, index=True) - job_id = Column(Integer, ForeignKey("jobs.id"), unique=True, nullable=False) + + id = Column(Integer, primary_key=True) + job_id = Column( + Integer, ForeignKey("jobs.id"), unique=True, nullable=False, index=True + ) cron_expression = Column(String, nullable=False) enabled = Column(Boolean, default=True) - created_at = Column(DateTime, default=datetime.utcnow) - + created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) + job = relationship("Job", back_populates="schedule") + def __repr__(self): + return f"" + + class JobExecution(Base): __tablename__ = "job_executions" - - id = Column(Integer, primary_key=True, index=True) - job_id = Column(Integer, ForeignKey("jobs.id"), nullable=False) - status = Column(String, nullable=False, default="pending") # pending, running, success, failed, cancelled + + id = Column(Integer, primary_key=True) + job_id = Column(Integer, ForeignKey("jobs.id"), nullable=False, index=True) + status = Column( + String, nullable=False, default="pending" + ) # pending, running, success, failed, cancelled started_at = Column(DateTime, nullable=True) completed_at = Column(DateTime, nullable=True) bytes_processed = Column(Integer, default=0) bytes_backed_up = Column(Integer, default=0) error_message = Column(Text, nullable=True) triggered_by = Column(String, nullable=False) # manual, schedule - + job = relationship("Job", back_populates="executions") - backups = relationship("Backup", back_populates="execution", cascade="all, delete-orphan") + backups = relationship( + "Backup", back_populates="execution", cascade="all, delete-orphan" + ) + + def __repr__(self): + return f"" + class Backup(Base): __tablename__ = "backups" - - id = Column(Integer, primary_key=True, index=True) - execution_id = Column(Integer, ForeignKey("job_executions.id"), nullable=False) + + id = Column(Integer, primary_key=True) + execution_id = Column( + Integer, ForeignKey("job_executions.id"), nullable=False, index=True + ) storage_path = Column(String, nullable=False) size_bytes = Column(Integer, default=0) checksum = Column(String, nullable=True) type = Column(String, nullable=False) # full, incremental - parent_backup_id = Column(Integer, ForeignKey("backups.id"), nullable=True) - created_at = Column(DateTime, default=datetime.utcnow) - + parent_backup_id = Column( + Integer, ForeignKey("backups.id"), nullable=True, index=True + ) + created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) + execution = relationship("JobExecution", back_populates="backups") parent_backup = relationship("Backup", remote_side=[id]) + def __repr__(self): + return f"" + + class Setting(Base): __tablename__ = "settings" - + key = Column(String, primary_key=True) value = Column(Text, nullable=True) - updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) + updated_at = Column( + DateTime, + default=lambda: datetime.now(timezone.utc), + onupdate=lambda: datetime.now(timezone.utc), + ) + + def __repr__(self): + return f""