Started project managment endpoints

This commit is contained in:
Marta Borgia Leiva 2026-02-02 13:39:22 +01:00
parent f9631cfe87
commit 407b22eaf5
4 changed files with 243 additions and 141 deletions

View file

@ -38,4 +38,4 @@ class Task(Base):
description = Column(String)
status = Column(String, default="pending")
project_id = Column(Integer, ForeignKey("projects.id"))
project = relationship("Project", back_populates="tasks")
project_user = relationship("Project", back_populates="tasks")

View file

@ -7,7 +7,6 @@ from datetime import datetime, timedelta, timezone
import models
import schemas.users as user_schemas
import routers.users as user_router
from pyargon2 import hash

View file

@ -23,11 +23,13 @@ def get_me(request: Request, db: db_dependency):
payload = jwt.decode(token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM])
user_id: str = str(payload.get("sub"))
if user_id is None:
request.cookies.clear() ## removing invalid auth cookie
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not logged in"
)
except JWTError:
request.cookies.clear() ## removing invalid auth cookie
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials"
@ -35,6 +37,7 @@ def get_me(request: Request, db: db_dependency):
db_user = db.query(models.User).filter(models.User.id == int(user_id)).first()
if db_user is None:
request.cookies.clear() ## removing invalid auth cookie
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User not found"
@ -42,7 +45,7 @@ def get_me(request: Request, db: db_dependency):
return db_user
@router.post("/logout")
@router.get("/logout", tags=["me", "auth"])
def logout(request: Request,response: Response):
"""Logout by clearing the JWT cookie"""
@ -96,5 +99,4 @@ def delete_me(request: Request, db: db_dependency):
## Logout user by clearing cookie
request.cookies.clear()
return {"message": "User deleted successfully"}

View file

@ -1,11 +1,15 @@
from fastapi import APIRouter, HTTPException, Depends
from fastapi import APIRouter, HTTPException, Depends, Request
from typing import List, Annotated
from httpx import request
from jose import JWTError, jwt
from routers import auth
from database import db_dependency
import schemas.tasks as tasks
import schemas.projects as projects
import schemas.users as users
import schemas.tasks as tasks_schemas
import schemas.projects as projects_schemas
import schemas.users as users_schemas
router = APIRouter(prefix="/projects", tags=["projects"])
@ -13,169 +17,266 @@ router = APIRouter(prefix="/projects", tags=["projects"])
## GET endpoints
##
@router.get("/", response_model=List[projects_schemas.ProjectBase], tags=["projects", "me"])
def get_projects(db: db_dependency, request: Request):
"""Get a user's projects"""
## User retrieval from JWT token in cookies
get_token = request.cookies.get("access_token")
if not get_token:
raise HTTPException(
status_code=401,
detail="Not logged in"
)
try:
payload = jwt.decode(get_token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM])
user_id: str = str(payload.get("sub"))
if user_id is None:
request.cookies.clear() ## User in cookies not found, clear cookies
raise HTTPException(
status_code=401,
detail="Not logged in"
)
except JWTError:
request.cookies.clear() ## Probably an invalid token, clear cookies
raise HTTPException(
status_code=401,
detail="Could not validate credentials"
)
## fetching projects for the user
projects: projects_schemas.ProjectBase | None = db.query(projects_schemas.ProjectBase).filter(getattr(projects_schemas.ProjectBase, "users.id") == int(user_id)).first()
if projects is None:
return []
return projects
@router.get("/{project_id}", response_model=projects_schemas.ProjectBase)
def get_project(project_id: int, request:Request, db: db_dependency):
"""Get a project by ID"""
@router.get("/{project_id}", response_model=projects.ProjectBase)
def read_project(project_id: int, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
get_token = request.cookies.get("access_token")
if not get_token:
raise HTTPException(
status_code=401,
detail="Not logged in"
)
try:
payload = jwt.decode(get_token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM])
user_id: str = str(payload.get("sub"))
if user_id is None:
request.cookies.clear() ## User in cookies not found, clear cookies
raise HTTPException(
status_code=401,
detail="Not logged in"
)
except JWTError:
request.cookies.clear() ## Probably an invalid token, clear cookies
raise HTTPException(
status_code=401,
detail="Could not validate credentials"
)
user = db.query(users_schemas.UserBase).filter(getattr(users_schemas.UserBase, "id") == user_id).first()
db_project = db.query(projects_schemas.ProjectBase).filter(getattr(projects_schemas.ProjectBase, "id") == project_id).first()
if db_project is None:
raise HTTPException(status_code=404, detail="Project not found")
if user not in db_project.users:
raise HTTPException(status_code=403, detail="Not authorized to access this project")
return db_project
"""Get tasks from a specified project"""
@router.get("/{project_id}/tasks", response_model=List[tasks.TaskBase], tags=["tasks"])
def read_tasks_from_project(project_id: int, db: db_dependency):
db_tasks = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id).all()
return db_tasks
"""Get a specific task from a specified project"""
@router.get("/{project_id}/tasks/{task_id}", response_model=tasks.TaskBase, tags=["tasks"])
def read_task_from_project(project_id: int, task_id: int, db: db_dependency):
db_task = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id, tasks.models.Task.id == task_id).first()
if db_task is None:
raise HTTPException(status_code=404, detail="Task not found in the specified project")
return db_task
@router.get("/{project_id}/users", response_model=List[users_schemas.UserBase], tags=["users", "projects"])
def get_project_users(project_id: int, request:Request, db: db_dependency):
"""Get users from a specified project"""
@router.get("/{project_id}/users", response_model=List[users.UserBase], tags=["users"])
def read_users_from_project(project_id: int, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
get_token = request.cookies.get("access_token")
if not get_token:
raise HTTPException(
status_code=401,
detail="Not logged in"
)
try:
payload = jwt.decode(get_token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM])
user_id: str = str(payload.get("sub"))
if user_id is None:
request.cookies.clear() ## User in cookies not found, clear cookies
raise HTTPException(
status_code=401,
detail="Not logged in"
)
except JWTError:
request.cookies.clear() ## Probably an invalid token, clear cookies
raise HTTPException(
status_code=401,
detail="Could not validate credentials"
)
user = db.query(users_schemas.UserBase).filter(getattr(users_schemas.UserBase, "id") == user_id).first()
db_project = db.query(projects_schemas.ProjectBase).filter(getattr(projects_schemas.ProjectBase, "id") == project_id).first()
if db_project is None:
raise HTTPException(status_code=404, detail="Project not found")
if user not in db_project.users:
raise HTTPException(status_code=403, detail="Not authorized to access this project's users")
return db_project.users
# """Get tasks from a specified project"""
# @router.get("/{project_id}/tasks", response_model=List[tasks_schemas.TaskBase], tags=["tasks"])
# def read_tasks_from_project(project_id: int, db: db_dependency):
# db_tasks = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id).all()
# return db_tasks
##
## POST endpoints
##
# """Get a specific task from a specified project"""
# @router.get("/{project_id}/tasks/{task_id}", response_model=tasks_schemas.TaskBase, tags=["tasks"])
# def read_task_from_project(project_id: int, task_id: int, db: db_dependency):
# db_task = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id, tasks.models.Task.id == task_id).first()
# if db_task is None:
# raise HTTPException(status_code=404, detail="Task not found in the specified project")
# return db_task
"""Create a new project"""
# """Get users from a specified project"""
@router.post("/", response_model=projects.ProjectCreate)
def create_project(project: projects.ProjectCreate, db: db_dependency):
db_project = projects.models.Project(
name=project.name,
description=project.description
)
db.add(db_project)
db.commit()
db.refresh(db_project)
return db_project
# @router.get("/{project_id}/users", response_model=List[users_schemas.UserBase], tags=["users"])
# def read_users_from_project(project_id: int, db: db_dependency):
# db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
# if db_project is None:
# raise HTTPException(status_code=404, detail="Project not found")
# return db_project.users
"""Create a new task in a specified project"""
@router.post("/{project_id}/tasks", response_model=tasks.TaskBase, tags=["tasks"])
def create_task_in_project(project_id: int, task: tasks.TaskBase, db: db_dependency):
db_task = tasks.models.Task(
title=task.title,
description=task.description,
status=task.status,
project_id=project_id
)
db.add(db_task)
db.commit()
db.refresh(db_task)
return db_task
# ##
# ## POST endpoints
# ##
"""Add users to a specified project using their IDs"""
# """Create a new project"""
@router.post("/{project_id}/users", response_model=projects.ProjectAddUsers, tags=["users"])
def add_users_to_project(project_id: int, user_data: projects.ProjectAddUsers, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
if db_project is None:
raise HTTPException(status_code=404, detail="Project not found")
for user_id in user_data.user_ids:
db_user = db.query(users.models.User).filter(users.models.User.id == user_id).first()
if db_user:
db_project.users.append(db_user)
db.commit()
db.refresh(db_project)
return db_project
# @router.post("/", response_model=projects.ProjectCreate)
# def create_project(project: projects.ProjectCreate, db: db_dependency):
# db_project = projects(
# name=project.name,
# description=project.description
# )
# db.add(db_project)
# db.commit()
# db.refresh(db_project)
# return db_project
##
## PUT endpoints
##
# """Create a new task in a specified project"""
# @router.post("/{project_id}/tasks", response_model=tasks.TaskBase, tags=["tasks"])
# def create_task_in_project(project_id: int, task: tasks.TaskBase, db: db_dependency):
# db_task = tasks.models.Task(
# title=task.title,
# description=task.description,
# status=task.status,
# project_id=project_id
# )
# db.add(db_task)
# db.commit()
# db.refresh(db_task)
# return db_task
"""Update a project by ID"""
# """Add users to a specified project using their IDs"""
@router.put("/{project_id}", response_model=projects.ProjectUpdate)
def update_project(project_id: int, project: projects.ProjectUpdate, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
if db_project is None:
raise HTTPException(status_code=404, detail="Project not found")
if project.name is not None:
db_project.name = project.name
if project.description is not None:
db_project.description = project.description
db.commit()
db.refresh(db_project)
return db_project
# @router.post("/{project_id}/users", response_model=projects.ProjectAddUsers, tags=["users"])
# def add_users_to_project(project_id: int, user_data: projects.ProjectAddUsers, db: db_dependency):
# db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
# if db_project is None:
# raise HTTPException(status_code=404, detail="Project not found")
# for user_id in user_data.user_ids:
# db_user = db.query(users.models.User).filter(users.models.User.id == user_id).first()
# if db_user:
# db_project.users.append(db_user)
# db.commit()
# db.refresh(db_project)
# return db_project
"""Update a task in a specified project"""
@router.put("/{project_id}/tasks/{task_id}", response_model=tasks.TaskUpdate, tags=["tasks"])
def update_task_in_project(project_id: int, task_id: int, task: tasks.TaskUpdate, db: db_dependency):
db_task = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id, tasks.models.Task.id == task_id).first()
if db_task is None:
raise HTTPException(status_code=404, detail="Task not found in the specified project")
if task.title is not None:
db_task.title = task.title
if task.description is not None:
db_task.description = task.description
if task.status is not None:
db_task.status = task.status
db.commit()
db.refresh(db_task)
return db_task
##
## DELETE endpoints
##
"""Delete a project by ID"""
@router.delete("/{project_id}")
def delete_project(project_id: int, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
if db_project is None:
raise HTTPException(status_code=404, detail="Project not found")
db.delete(db_project)
db.commit()
return {"detail": "Project deleted successfully"}
# ##
# ## PUT endpoints
# ##
"""Delete a task from a specified project"""
# """Update a project by ID"""
@router.delete("/{project_id}/tasks/{task_id}" , tags=["tasks"])
def delete_task_from_project(project_id: int, task_id: int, db: db_dependency):
db_task = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id, tasks.models.Task.id == task_id).first()
if db_task is None:
raise HTTPException(status_code=404, detail="Task not found in the specified project")
db.delete(db_task)
db.commit()
return {"detail": "Task deleted successfully"}
# @router.put("/{project_id}", response_model=projects.ProjectUpdate)
# def update_project(project_id: int, project: projects.ProjectUpdate, db: db_dependency):
# db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
# if db_project is None:
# raise HTTPException(status_code=404, detail="Project not found")
# if project.name is not None:
# db_project.name = project.name
# if project.description is not None:
# db_project.description = project.description
# db.commit()
# db.refresh(db_project)
# return db_project
"""Remove users from a specified project using their IDs"""
# """Update a task in a specified project"""
@router.delete("/{project_id}/users/{user_id}", tags=["users"])
def remove_user_from_project(project_id: int, user_id: int, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
if db_project is None:
raise HTTPException(status_code=404, detail="Project not found")
db_user = db.query(users.models.User).filter(users.models.User.id == user_id).first()
if db_user is None or db_user not in db_project.users:
raise HTTPException(status_code=404, detail="User not found in the specified project")
db_project.users.remove(db_user)
db.commit()
db.refresh(db_project)
return {"detail": "User removed from project successfully"}
# @router.put("/{project_id}/tasks/{task_id}", response_model=tasks.TaskUpdate, tags=["tasks"])
# def update_task_in_project(project_id: int, task_id: int, task: tasks.TaskUpdate, db: db_dependency):
# db_task = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id, tasks.models.Task.id == task_id).first()
# if db_task is None:
# raise HTTPException(status_code=404, detail="Task not found in the specified project")
# if task.title is not None:
# db_task.title = task.title
# if task.description is not None:
# db_task.description = task.description
# if task.status is not None:
# db_task.status = task.status
# db.commit()
# db.refresh(db_task)
# return db_task
# ##
# ## DELETE endpoints
# ##
# """Delete a project by ID"""
# @router.delete("/{project_id}")
# def delete_project(project_id: int, db: db_dependency):
# db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
# if db_project is None:
# raise HTTPException(status_code=404, detail="Project not found")
# db.delete(db_project)
# db.commit()
# return {"detail": "Project deleted successfully"}
# """Delete a task from a specified project"""
# @router.delete("/{project_id}/tasks/{task_id}" , tags=["tasks"])
# def delete_task_from_project(project_id: int, task_id: int, db: db_dependency):
# db_task = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id, tasks.models.Task.id == task_id).first()
# if db_task is None:
# raise HTTPException(status_code=404, detail="Task not found in the specified project")
# db.delete(db_task)
# db.commit()
# return {"detail": "Task deleted successfully"}
# """Remove users from a specified project using their IDs"""
# @router.delete("/{project_id}/users/{user_id}", tags=["users"])
# def remove_user_from_project(project_id: int, user_id: int, db: db_dependency):
# db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
# if db_project is None:
# raise HTTPException(status_code=404, detail="Project not found")
# db_user = db.query(users.models.User).filter(users.models.User.id == user_id).first()
# if db_user is None or db_user not in db_project.users:
# raise HTTPException(status_code=404, detail="User not found in the specified project")
# db_project.users.remove(db_user)
# db.commit()
# db.refresh(db_project)
# return {"detail": "User removed from project successfully"}