feat(comments): add reply threading + UI
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
"""add reply_to_comment_id to task_comments
|
||||
|
||||
Revision ID: 9d3d9b9c1a23
|
||||
Revises: 157587037601
|
||||
Create Date: 2026-02-02 08:15:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "9d3d9b9c1a23"
|
||||
down_revision = "157587037601"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("task_comments", sa.Column("reply_to_comment_id", sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(
|
||||
"fk_task_comments_reply_to_comment_id",
|
||||
"task_comments",
|
||||
"task_comments",
|
||||
["reply_to_comment_id"],
|
||||
["id"],
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_constraint("fk_task_comments_reply_to_comment_id", "task_comments", type_="foreignkey")
|
||||
op.drop_column("task_comments", "reply_to_comment_id")
|
||||
@@ -89,6 +89,12 @@ def create_task_comment(payload: TaskCommentCreate, session: Session = Depends(g
|
||||
if payload.author_employee_id is None:
|
||||
payload = TaskCommentCreate(**{**payload.model_dump(), "author_employee_id": actor_employee_id})
|
||||
c = TaskComment(**payload.model_dump())
|
||||
|
||||
# Validate reply target (must exist + belong to same task)
|
||||
if c.reply_to_comment_id is not None:
|
||||
parent = session.get(TaskComment, c.reply_to_comment_id)
|
||||
if parent is None or parent.task_id != c.task_id:
|
||||
raise HTTPException(status_code=400, detail="Invalid reply_to_comment_id")
|
||||
session.add(c)
|
||||
session.commit()
|
||||
session.refresh(c)
|
||||
|
||||
@@ -30,5 +30,9 @@ class TaskComment(SQLModel, table=True):
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
task_id: int = Field(foreign_key="tasks.id", index=True)
|
||||
author_employee_id: int | None = Field(default=None, foreign_key="employees.id")
|
||||
|
||||
# Optional reply threading
|
||||
reply_to_comment_id: int | None = Field(default=None, foreign_key="task_comments.id")
|
||||
|
||||
body: str
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
@@ -24,4 +24,5 @@ class TaskUpdate(SQLModel):
|
||||
class TaskCommentCreate(SQLModel):
|
||||
task_id: int
|
||||
author_employee_id: int | None = None
|
||||
reply_to_comment_id: int | None = None
|
||||
body: str
|
||||
|
||||
Reference in New Issue
Block a user