refactor: all task mutations require auth — actor from JWT/token, no ?actor= or ?slug= params
Some checks failed
Deploy Tracker / deploy (push) Failing after 1s

This commit is contained in:
markov 2026-02-24 13:32:29 +01:00
parent 2f0c4d1636
commit 904c105174

View File

@ -11,6 +11,7 @@ from sqlalchemy.orm import selectinload, joinedload
from tracker.database import get_db
from tracker.models import Task, Step, Project, Member, Message, Chat
from tracker.api.auth import get_current_member
router = APIRouter(tags=["tasks"])
@ -231,6 +232,7 @@ async def get_task(task_id: str, db: AsyncSession = Depends(get_db)):
async def create_task(
project_slug: str = Query(...),
req: TaskCreate = ...,
current_member: Member = Depends(get_current_member),
db: AsyncSession = Depends(get_db),
):
# Find project
@ -298,14 +300,14 @@ async def create_task(
async def update_task(
task_id: str,
req: TaskUpdate,
actor: Optional[str] = Query(None, description="Who made the change"),
current_member: Member = Depends(get_current_member),
db: AsyncSession = Depends(get_db),
):
task = await _get_task(task_id, db)
slug = task.project.slug if task.project else ""
prefix = slug[:2].upper() if slug else "XX"
key = f"{prefix}-{task.number}"
who = f"@{actor}" if actor else "Кто-то"
who = f"@{current_member.slug}"
old_status = task.status
old_assignee = task.assignee_slug
@ -338,7 +340,7 @@ async def update_task(
chat_text=f"{key}: {old_status}{req.status}",
task_text=f"{who} изменил статус: {old_status}{req.status} ({now_str})",
project_slug=slug,
actor_slug=actor or "system",
actor_slug=current_member.slug,
)
if req.assignee_slug is not None and req.assignee_slug != old_assignee:
if req.assignee_slug:
@ -347,7 +349,7 @@ async def update_task(
chat_text=f"{key}: назначена на @{req.assignee_slug}",
task_text=f"{who} назначил задачу на @{req.assignee_slug} ({now_str})",
project_slug=slug,
actor_slug=actor or "system",
actor_slug=current_member.slug,
)
else:
await _system_message(
@ -355,7 +357,7 @@ async def update_task(
chat_text=f"{key}: исполнитель снят",
task_text=f"{who} снял исполнителя @{old_assignee} ({now_str})",
project_slug=slug,
actor_slug=actor or "system",
actor_slug=current_member.slug,
)
await db.commit()
@ -375,7 +377,7 @@ async def update_task(
@router.delete("/tasks/{task_id}")
async def delete_task(task_id: str, db: AsyncSession = Depends(get_db)):
async def delete_task(task_id: str, current_member: Member = Depends(get_current_member), db: AsyncSession = Depends(get_db)):
task = await _get_task(task_id, db)
project_id = str(task.project_id)
task_data = {"id": str(task.id), "project_id": project_id}
@ -387,8 +389,9 @@ async def delete_task(task_id: str, db: AsyncSession = Depends(get_db)):
@router.post("/tasks/{task_id}/take", response_model=TaskOut)
async def take_task(task_id: str, slug: str = Query(...), db: AsyncSession = Depends(get_db)):
async def take_task(task_id: str, current_member: Member = Depends(get_current_member), db: AsyncSession = Depends(get_db)):
"""Atomically take a task — only if unassigned and in backlog/todo."""
slug = current_member.slug
task = await _get_task(task_id, db)
if task.assignee_slug:
raise HTTPException(409, f"Task already assigned to {task.assignee_slug}")
@ -431,7 +434,7 @@ async def take_task(task_id: str, slug: str = Query(...), db: AsyncSession = Dep
@router.post("/tasks/{task_id}/reject")
async def reject_task(task_id: str, req: RejectRequest, db: AsyncSession = Depends(get_db)):
async def reject_task(task_id: str, req: RejectRequest, current_member: Member = Depends(get_current_member), db: AsyncSession = Depends(get_db)):
"""Reject a task with reason — unassign and return to todo."""
task = await _get_task(task_id, db)
old_assignee = task.assignee_slug
@ -456,7 +459,7 @@ async def reject_task(task_id: str, req: RejectRequest, db: AsyncSession = Depen
@router.post("/tasks/{task_id}/assign", response_model=TaskOut)
async def assign_task(task_id: str, req: AssignRequest, db: AsyncSession = Depends(get_db)):
async def assign_task(task_id: str, req: AssignRequest, current_member: Member = Depends(get_current_member), db: AsyncSession = Depends(get_db)):
"""Assign task to a member."""
# Verify assignee exists
result = await db.execute(select(Member).where(Member.slug == req.assignee_slug))
@ -495,7 +498,8 @@ async def assign_task(task_id: str, req: AssignRequest, db: AsyncSession = Depen
@router.post("/tasks/{task_id}/watch")
async def watch_task(task_id: str, slug: str = Query(...), db: AsyncSession = Depends(get_db)):
async def watch_task(task_id: str, current_member: Member = Depends(get_current_member), db: AsyncSession = Depends(get_db)):
slug = current_member.slug
task = await _get_task(task_id, db)
if slug not in (task.watchers or []):
task.watchers = (task.watchers or []) + [slug]
@ -504,7 +508,8 @@ async def watch_task(task_id: str, slug: str = Query(...), db: AsyncSession = De
@router.delete("/tasks/{task_id}/watch")
async def unwatch_task(task_id: str, slug: str = Query(...), db: AsyncSession = Depends(get_db)):
async def unwatch_task(task_id: str, current_member: Member = Depends(get_current_member), db: AsyncSession = Depends(get_db)):
slug = current_member.slug
task = await _get_task(task_id, db)
task.watchers = [w for w in (task.watchers or []) if w != slug]
await db.commit()