Coverage for src / idx_api / models / brokerage_content_source.py: 100%
19 statements
« prev ^ index » next coverage.py v7.13.1, created at 2025-12-28 11:09 -0700
« prev ^ index » next coverage.py v7.13.1, created at 2025-12-28 11:09 -0700
1"""BrokerageContentSource model - git repository configuration for brokerage blog content."""
3from datetime import datetime
4from typing import TYPE_CHECKING, Optional
6from sqlalchemy import Boolean, DateTime, ForeignKey, String, Text
7from sqlalchemy.orm import Mapped, mapped_column, relationship
9from idx_api.models.base import Base, TimestampMixin
11if TYPE_CHECKING:
12 from idx_api.models.brokerage import Brokerage
15class BrokerageContentSource(Base, TimestampMixin):
16 """
17 Git repository configuration for brokerage blog content.
19 Each brokerage can have one content repository containing MDX blog posts.
20 The content is synced at build time and rendered via Astro content collections.
21 """
23 __tablename__ = "brokerage_content_sources"
25 id: Mapped[int] = mapped_column(primary_key=True)
26 brokerage_id: Mapped[int] = mapped_column(
27 ForeignKey("brokerages.id", ondelete="CASCADE"),
28 nullable=False,
29 unique=True, # One content source per brokerage
30 index=True,
31 )
33 # Git repository URL (supports HTTPS and SSH)
34 # e.g., "https://github.com/elevateidaho/blog-content.git"
35 git_url: Mapped[str] = mapped_column(String(500), nullable=False)
37 # Branch to pull from (default: main)
38 git_branch: Mapped[str] = mapped_column(String(100), nullable=False, default="main", server_default="main")
40 # Optional: path within repo where content lives (default: root)
41 # e.g., "content" if posts are in content/posts/
42 content_path: Mapped[Optional[str]] = mapped_column(String(200))
44 # Authentication method: "none", "token", "ssh_key", "deploy_key"
45 auth_method: Mapped[str] = mapped_column(String(50), nullable=False, default="none", server_default="none")
47 # Encrypted credentials (stored securely, decrypted at build time)
48 # For tokens: the token itself (should be encrypted in production)
49 # For SSH: reference to secret in vault/env
50 auth_credential: Mapped[Optional[str]] = mapped_column(String(500))
52 # Whether content sync is enabled
53 enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, server_default="1")
55 # Last successful sync timestamp
56 last_synced_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
58 # Last sync commit SHA (40 character git hash)
59 last_sync_commit: Mapped[Optional[str]] = mapped_column(String(40))
61 # Last sync error message (if any)
62 last_sync_error: Mapped[Optional[str]] = mapped_column(Text)
64 # Relationships
65 brokerage: Mapped["Brokerage"] = relationship(back_populates="content_source")
67 def __repr__(self) -> str:
68 return f"<BrokerageContentSource(id={self.id}, brokerage_id={self.brokerage_id}, git_url='{self.git_url}')>"