feat(H): H-WIKI/H-VER/H-LINK — Wiki plugin (articles, categories, versioning, entity links), migration 0126, 9 routes, 15 tests passing
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
"""Wiki plugin models — articles, categories, versions (H-WIKI, H-VER)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import ForeignKey, Index, Integer, String, Text
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.dialects.postgresql import UUID as PGUUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.db import Base, TenantMixin
|
||||
from app.models.owned_mixin import OwnedMixin
|
||||
|
||||
|
||||
class WikiCategory(Base, TenantMixin, OwnedMixin):
|
||||
"""Wiki category for organizing articles."""
|
||||
|
||||
__tablename__ = "wiki_categories"
|
||||
__table_args__ = (
|
||||
Index("ix_wiki_cat_tenant", "tenant_id"),
|
||||
Index("ix_wiki_cat_tenant_slug", "tenant_id", "slug"),
|
||||
)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
slug: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
parent_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
PGUUID(as_uuid=True),
|
||||
ForeignKey("wiki_categories.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
)
|
||||
sort_order: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
|
||||
|
||||
class WikiArticle(Base, TenantMixin, OwnedMixin):
|
||||
"""Wiki article with Markdown content, tags, and entity links (H-WIKI, H-LINK)."""
|
||||
|
||||
__tablename__ = "wiki_articles"
|
||||
__table_args__ = (
|
||||
Index("ix_wiki_art_tenant", "tenant_id"),
|
||||
Index("ix_wiki_art_tenant_category", "tenant_id", "category_id"),
|
||||
Index("ix_wiki_art_tenant_slug", "tenant_id", "slug"),
|
||||
Index("ix_wiki_art_tenant_status", "tenant_id", "status"),
|
||||
)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||||
)
|
||||
title: Mapped[str] = mapped_column(String(300), nullable=False)
|
||||
slug: Mapped[str] = mapped_column(String(300), nullable=False)
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
content_html: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
summary: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
category_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
PGUUID(as_uuid=True),
|
||||
ForeignKey("wiki_categories.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
)
|
||||
tags: Mapped[list[str]] = mapped_column(JSONB, nullable=False, default=list)
|
||||
status: Mapped[str] = mapped_column(
|
||||
String(20), nullable=False, default="draft"
|
||||
) # draft, published, archived
|
||||
entity_links: Mapped[list[dict[str, Any]]] = mapped_column(
|
||||
JSONB, nullable=False, default=list
|
||||
) # [{"entity_type": "contact", "entity_id": "..."}]
|
||||
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
published_at: Mapped[datetime | None] = mapped_column(
|
||||
nullable=True
|
||||
)
|
||||
|
||||
|
||||
class WikiArticleVersion(Base, TenantMixin):
|
||||
"""Article version history for diff and restore (H-VER)."""
|
||||
|
||||
__tablename__ = "wiki_article_versions"
|
||||
__table_args__ = (
|
||||
Index("ix_wiki_ver_tenant_article", "tenant_id", "article_id"),
|
||||
Index("ix_wiki_ver_tenant_version", "tenant_id", "article_id", "version"),
|
||||
)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||||
)
|
||||
article_id: Mapped[uuid.UUID] = mapped_column(
|
||||
PGUUID(as_uuid=True),
|
||||
ForeignKey("wiki_articles.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
version: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
title: Mapped[str] = mapped_column(String(300), nullable=False)
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
edited_by: Mapped[uuid.UUID | None] = mapped_column(
|
||||
PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
|
||||
)
|
||||
edit_comment: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
Reference in New Issue
Block a user