from __future__ import annotations from fastapi import APIRouter, Form, Request from fastapi.responses import RedirectResponse from app.core.db.common import CommonSessionLocal from app.core.security.csrf import get_or_create_csrf_token, validate_csrf from app.core.security.session_auth import get_current_user from app.core.templating import templates from app.modules.core.rbac.deps import get_user_permissions, get_user_roles from app.modules.work_detail.service import get_task_for_action, load_unified_engagement_detail, save_task_comment, save_task_status router = APIRouter(prefix="/work", tags=["unified-work-detail-ui"]) def _base_ctx(request: Request, db, user, **ctx): base = { "request": request, "current_user": user, "current_user_roles": get_user_roles(db, user.id), "current_user_permissions": get_user_permissions(db, user.id), "csrf_token": get_or_create_csrf_token(request), } base.update(ctx) return base def _fallback_for_user(db, user) -> str: roles = set(get_user_roles(db, user.id)) if "Client" in roles: return "/client/compliance" if "Consultant" in roles: return "/consultant/work" if "Partner" in roles: return "/partner/reviews" if roles.intersection({"Manager", "Branch Manager"}): return "/manager/work" return "/employee/work" @router.get("/engagements/{engagement_id}") def unified_engagement_detail(request: Request, engagement_id: int): db = CommonSessionLocal() try: user = get_current_user(request, db=db) if not user: return RedirectResponse(url="/login", status_code=303) detail = load_unified_engagement_detail(db, request=request, user=user, engagement_id=engagement_id) if not detail: return RedirectResponse(url=_fallback_for_user(db, user), status_code=303) return templates.TemplateResponse( "modules/work_detail/templates/work_detail/engagement_detail.html", _base_ctx(request, db, user, title="Work Details", **detail), ) finally: db.close() @router.post("/tasks/{task_id}/status") async def unified_task_status_update(request: Request, task_id: int, csrf_token: str = Form(...), status: str = Form(...), priority: str = Form("")): validate_csrf(request, csrf_token) db = CommonSessionLocal() try: user = get_current_user(request, db=db) if not user: return RedirectResponse(url="/login", status_code=303) task, access = get_task_for_action(db, user=user, task_id=task_id) if not task or not access: return RedirectResponse(url=_fallback_for_user(db, user), status_code=303) if not access.can_update_tasks: return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=not_allowed", status_code=303) save_task_status(db, task=task, status=status, priority=priority, user_id=user.id) db.commit() return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?updated=1", status_code=303) except Exception: db.rollback() raise finally: db.close() @router.post("/tasks/{task_id}/comment") async def unified_task_comment_add( request: Request, task_id: int, csrf_token: str = Form(...), comment_type: str = Form("internal_note"), visibility: str = Form("internal"), message: str = Form(""), ): validate_csrf(request, csrf_token) db = CommonSessionLocal() try: user = get_current_user(request, db=db) if not user: return RedirectResponse(url="/login", status_code=303) task, access = get_task_for_action(db, user=user, task_id=task_id) if not task or not access: return RedirectResponse(url=_fallback_for_user(db, user), status_code=303) if not access.can_comment: return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=comment_not_allowed", status_code=303) ok = save_task_comment(db, task=task, access=access, comment_type=comment_type, visibility=visibility, message=message, user_id=user.id) if ok: db.commit() return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?comment=sent", status_code=303) db.rollback() return RedirectResponse(url=f"/work/engagements/{task.subscription_id}?error=empty_comment", status_code=303) except Exception: db.rollback() raise finally: db.close()