feat: comments RBAC + notification on new comment

This commit is contained in:
Zhi
2026-02-24 04:22:42 +00:00
parent 26ee18a4a4
commit 622112c02f

View File

@@ -1,4 +1,4 @@
"""Comments router.""" """Comments router with RBAC and notifications."""
from typing import List from typing import List
from fastapi import APIRouter, Depends, HTTPException, status from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -6,16 +6,47 @@ from sqlalchemy.orm import Session
from app.core.config import get_db from app.core.config import get_db
from app.models import models from app.models import models
from app.schemas import schemas from app.schemas import schemas
from app.api.deps import get_current_user_or_apikey
from app.api.rbac import check_project_role
from app.models.notification import Notification as NotificationModel
router = APIRouter(tags=["Comments"]) router = APIRouter(tags=["Comments"])
def _notify_if_needed(db, issue_id, user_ids, ntype, title):
"""Helper to notify multiple users."""
issue = db.query(models.Issue).filter(models.Issue.id == issue_id).first()
if not issue:
return
for uid in set(user_ids):
if uid:
n = NotificationModel(user_id=uid, type=ntype, title=title, entity_type="issue", entity_id=issue_id)
db.add(n)
db.commit()
@router.post("/comments", response_model=schemas.CommentResponse, status_code=status.HTTP_201_CREATED) @router.post("/comments", response_model=schemas.CommentResponse, status_code=status.HTTP_201_CREATED)
def create_comment(comment: schemas.CommentCreate, db: Session = Depends(get_db)): def create_comment(comment: schemas.CommentCreate, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)):
# Get project_id from issue first
issue = db.query(models.Issue).filter(models.Issue.id == comment.issue_id).first()
if not issue:
raise HTTPException(status_code=404, detail="Issue not found")
check_project_role(db, current_user.id, issue.project_id, min_role="viewer")
db_comment = models.Comment(**comment.model_dump()) db_comment = models.Comment(**comment.model_dump())
db.add(db_comment) db.add(db_comment)
db.commit() db.commit()
db.refresh(db_comment) db.refresh(db_comment)
# Notify reporter and assignee (but not the commenter themselves)
notify_users = []
if issue.reporter_id != current_user.id:
notify_users.append(issue.reporter_id)
if issue.assignee_id and issue.assignee_id != current_user.id:
notify_users.append(issue.assignee_id)
if notify_users:
_notify_if_needed(db, issue.id, notify_users, "comment_added", f"New comment on: {issue.title[:50]}")
return db_comment return db_comment
@@ -37,10 +68,15 @@ def update_comment(comment_id: int, comment_update: schemas.CommentUpdate, db: S
@router.delete("/comments/{comment_id}", status_code=status.HTTP_204_NO_CONTENT) @router.delete("/comments/{comment_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_comment(comment_id: int, db: Session = Depends(get_db)): def delete_comment(comment_id: int, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)):
comment = db.query(models.Comment).filter(models.Comment.id == comment_id).first() comment = db.query(models.Comment).filter(models.Comment.id == comment_id).first()
if not comment: if not comment:
raise HTTPException(status_code=404, detail="Comment not found") raise HTTPException(status_code=404, detail="Comment not found")
# Get issue to check project role
issue = db.query(models.Issue).filter(models.Issue.id == comment.issue_id).first()
if not issue:
raise HTTPException(status_code=404, detail="Issue not found")
check_project_role(db, current_user.id, issue.project_id, min_role="dev")
db.delete(comment) db.delete(comment)
db.commit() db.commit()
return None return None