models.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. from datetime import datetime
  2. from typing import Optional
  3. from sqlalchemy import BigInteger, DateTime, Enum, ForeignKey, Integer, JSON, SmallInteger, String, Text, func
  4. from sqlalchemy.orm import Mapped, mapped_column, relationship
  5. from .database import Base
  6. class Admin(Base):
  7. __tablename__ = "tpc_admins"
  8. id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
  9. username: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
  10. password_hash: Mapped[str] = mapped_column(String(128), nullable=False)
  11. is_active: Mapped[bool] = mapped_column(default=True, nullable=False)
  12. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
  13. last_login_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
  14. class Developer(Base):
  15. __tablename__ = "tpc_developers"
  16. id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
  17. name: Mapped[str] = mapped_column(String(128), nullable=False)
  18. email: Mapped[Optional[str]] = mapped_column(String(255))
  19. website: Mapped[Optional[str]] = mapped_column(String(512))
  20. avatar_url: Mapped[Optional[str]] = mapped_column(String(512))
  21. verified: Mapped[bool] = mapped_column(default=False, nullable=False)
  22. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
  23. updated_at: Mapped[datetime] = mapped_column(
  24. DateTime, server_default=func.now(), onupdate=func.now(), nullable=False
  25. )
  26. apps: Mapped[list["App"]] = relationship(back_populates="developer")
  27. class Category(Base):
  28. __tablename__ = "tpc_categories"
  29. id: Mapped[int] = mapped_column(SmallInteger, primary_key=True, autoincrement=True)
  30. slug: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
  31. name: Mapped[str] = mapped_column(String(128), nullable=False)
  32. description: Mapped[Optional[str]] = mapped_column(String(255))
  33. icon: Mapped[Optional[str]] = mapped_column(String(64))
  34. sort_order: Mapped[int] = mapped_column(SmallInteger, default=0, nullable=False)
  35. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
  36. apps: Mapped[list["App"]] = relationship(secondary="tpc_app_category_map", back_populates="categories")
  37. class AppCategoryMap(Base):
  38. __tablename__ = "tpc_app_category_map"
  39. app_id: Mapped[int] = mapped_column(
  40. BigInteger, ForeignKey("tpc_apps.id", ondelete="CASCADE"), primary_key=True
  41. )
  42. category_id: Mapped[int] = mapped_column(
  43. SmallInteger, ForeignKey("tpc_categories.id", ondelete="CASCADE"), primary_key=True
  44. )
  45. class AppVersion(Base):
  46. __tablename__ = "tpc_app_versions"
  47. id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
  48. app_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("tpc_apps.id", ondelete="CASCADE"), nullable=False)
  49. version: Mapped[str] = mapped_column(String(64), nullable=False)
  50. storage_url: Mapped[Optional[str]] = mapped_column(String(512))
  51. checksum_sha256: Mapped[Optional[str]] = mapped_column(String(64))
  52. size_bytes: Mapped[Optional[int]] = mapped_column(BigInteger)
  53. manifest: Mapped[Optional[dict]] = mapped_column(JSON)
  54. release_notes: Mapped[Optional[str]] = mapped_column(Text)
  55. min_client_version: Mapped[Optional[str]] = mapped_column(String(32))
  56. status: Mapped[str] = mapped_column(
  57. Enum("draft", "published", "yanked", name="version_status"),
  58. default="draft",
  59. nullable=False,
  60. )
  61. published_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
  62. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
  63. app: Mapped["App"] = relationship(back_populates="versions", foreign_keys=[app_id])
  64. class App(Base):
  65. __tablename__ = "tpc_apps"
  66. id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
  67. app_uid: Mapped[str] = mapped_column(String(64), unique=True, nullable=False, index=True)
  68. name: Mapped[str] = mapped_column(String(255), nullable=False)
  69. type: Mapped[str] = mapped_column(
  70. Enum("system", "community", "external", name="app_type"), nullable=False, index=True
  71. )
  72. developer_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("tpc_developers.id", ondelete="SET NULL"))
  73. icon_url: Mapped[Optional[str]] = mapped_column(String(512))
  74. short_description: Mapped[Optional[str]] = mapped_column(String(255))
  75. description: Mapped[Optional[str]] = mapped_column(Text)
  76. homepage_url: Mapped[Optional[str]] = mapped_column(String(512))
  77. current_version_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("tpc_app_versions.id"))
  78. status: Mapped[str] = mapped_column(
  79. Enum("draft", "published", "deprecated", "suspended", name="app_status"),
  80. default="draft",
  81. nullable=False,
  82. index=True,
  83. )
  84. is_featured: Mapped[bool] = mapped_column(default=False, nullable=False, index=True)
  85. download_count: Mapped[int] = mapped_column(BigInteger, default=0, nullable=False)
  86. publish_time: Mapped[Optional[datetime]] = mapped_column(DateTime, index=True)
  87. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
  88. updated_at: Mapped[datetime] = mapped_column(
  89. DateTime, server_default=func.now(), onupdate=func.now(), nullable=False
  90. )
  91. developer: Mapped[Optional["Developer"]] = relationship(back_populates="apps")
  92. categories: Mapped[list["Category"]] = relationship(secondary="tpc_app_category_map", back_populates="apps")
  93. versions: Mapped[list["AppVersion"]] = relationship(
  94. back_populates="app",
  95. foreign_keys="AppVersion.app_id",
  96. order_by="AppVersion.published_at.desc()",
  97. )
  98. current_version: Mapped[Optional["AppVersion"]] = relationship(
  99. foreign_keys=[current_version_id], lazy="joined"
  100. )