Add project staffing endpoints and project detail Kanban UI
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -5,7 +5,7 @@ from sqlmodel import Session, select
|
||||
|
||||
from app.api.utils import log_activity
|
||||
from app.db.session import get_session
|
||||
from app.models.projects import Project
|
||||
from app.models.projects import Project, ProjectMember
|
||||
from app.schemas.projects import ProjectCreate, ProjectUpdate
|
||||
|
||||
router = APIRouter(prefix="/projects", tags=["projects"])
|
||||
@@ -43,3 +43,47 @@ def update_project(project_id: int, payload: ProjectUpdate, session: Session = D
|
||||
log_activity(session, actor_employee_id=None, entity_type="project", entity_id=proj.id, verb="updated", payload=data)
|
||||
session.commit()
|
||||
return proj
|
||||
|
||||
|
||||
@router.get("/{project_id}/members", response_model=list[ProjectMember])
|
||||
def list_project_members(project_id: int, session: Session = Depends(get_session)):
|
||||
return session.exec(
|
||||
select(ProjectMember).where(ProjectMember.project_id == project_id).order_by(ProjectMember.id.asc())
|
||||
).all()
|
||||
|
||||
|
||||
@router.post("/{project_id}/members", response_model=ProjectMember)
|
||||
def add_project_member(project_id: int, payload: ProjectMember, session: Session = Depends(get_session)):
|
||||
member = ProjectMember(project_id=project_id, employee_id=payload.employee_id, role=payload.role)
|
||||
session.add(member)
|
||||
session.commit()
|
||||
session.refresh(member)
|
||||
log_activity(
|
||||
session,
|
||||
actor_employee_id=None,
|
||||
entity_type="project_member",
|
||||
entity_id=member.id,
|
||||
verb="added",
|
||||
payload={"project_id": project_id, "employee_id": member.employee_id},
|
||||
)
|
||||
session.commit()
|
||||
return member
|
||||
|
||||
|
||||
@router.delete("/{project_id}/members/{member_id}")
|
||||
def remove_project_member(project_id: int, member_id: int, session: Session = Depends(get_session)):
|
||||
member = session.get(ProjectMember, member_id)
|
||||
if not member or member.project_id != project_id:
|
||||
raise HTTPException(status_code=404, detail="Project member not found")
|
||||
session.delete(member)
|
||||
session.commit()
|
||||
log_activity(
|
||||
session,
|
||||
actor_employee_id=None,
|
||||
entity_type="project_member",
|
||||
entity_id=member_id,
|
||||
verb="removed",
|
||||
payload={"project_id": project_id},
|
||||
)
|
||||
session.commit()
|
||||
return {"ok": True}
|
||||
|
||||
@@ -12,6 +12,8 @@ from app.schemas.work import TaskCommentCreate, TaskCreate, TaskUpdate
|
||||
|
||||
router = APIRouter(tags=["work"])
|
||||
|
||||
ALLOWED_STATUSES = {"backlog", "ready", "in_progress", "review", "done", "blocked"}
|
||||
|
||||
|
||||
@router.get("/tasks", response_model=list[Task])
|
||||
def list_tasks(project_id: int | None = None, session: Session = Depends(get_session)):
|
||||
@@ -24,11 +26,20 @@ def list_tasks(project_id: int | None = None, session: Session = Depends(get_ses
|
||||
@router.post("/tasks", response_model=Task)
|
||||
def create_task(payload: TaskCreate, session: Session = Depends(get_session)):
|
||||
task = Task(**payload.model_dump())
|
||||
if task.status not in ALLOWED_STATUSES:
|
||||
raise HTTPException(status_code=400, detail="Invalid status")
|
||||
task.updated_at = datetime.utcnow()
|
||||
session.add(task)
|
||||
session.commit()
|
||||
session.refresh(task)
|
||||
log_activity(session, actor_employee_id=task.created_by_employee_id, entity_type="task", entity_id=task.id, verb="created", payload={"project_id": task.project_id, "title": task.title})
|
||||
log_activity(
|
||||
session,
|
||||
actor_employee_id=task.created_by_employee_id,
|
||||
entity_type="task",
|
||||
entity_id=task.id,
|
||||
verb="created",
|
||||
payload={"project_id": task.project_id, "title": task.title},
|
||||
)
|
||||
session.commit()
|
||||
return task
|
||||
|
||||
@@ -40,6 +51,8 @@ def update_task(task_id: int, payload: TaskUpdate, session: Session = Depends(ge
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
|
||||
data = payload.model_dump(exclude_unset=True)
|
||||
if "status" in data and data["status"] not in ALLOWED_STATUSES:
|
||||
raise HTTPException(status_code=400, detail="Invalid status")
|
||||
for k, v in data.items():
|
||||
setattr(task, k, v)
|
||||
task.updated_at = datetime.utcnow()
|
||||
|
||||
Reference in New Issue
Block a user