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) description = Column(String)
status = Column(String, default="pending") status = Column(String, default="pending")
project_id = Column(Integer, ForeignKey("projects.id")) 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 models
import schemas.users as user_schemas import schemas.users as user_schemas
import routers.users as user_router
from pyargon2 import hash 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]) payload = jwt.decode(token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM])
user_id: str = str(payload.get("sub")) user_id: str = str(payload.get("sub"))
if user_id is None: if user_id is None:
request.cookies.clear() ## removing invalid auth cookie
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not logged in" detail="Not logged in"
) )
except JWTError: except JWTError:
request.cookies.clear() ## removing invalid auth cookie
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials" 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() db_user = db.query(models.User).filter(models.User.id == int(user_id)).first()
if db_user is None: if db_user is None:
request.cookies.clear() ## removing invalid auth cookie
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="User not found" detail="User not found"
@ -42,7 +45,7 @@ def get_me(request: Request, db: db_dependency):
return db_user return db_user
@router.post("/logout") @router.get("/logout", tags=["me", "auth"])
def logout(request: Request,response: Response): def logout(request: Request,response: Response):
"""Logout by clearing the JWT cookie""" """Logout by clearing the JWT cookie"""
@ -96,5 +99,4 @@ def delete_me(request: Request, db: db_dependency):
## Logout user by clearing cookie ## Logout user by clearing cookie
request.cookies.clear() request.cookies.clear()
return {"message": "User deleted successfully"} 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 typing import List, Annotated
from httpx import request
from jose import JWTError, jwt
from routers import auth
from database import db_dependency from database import db_dependency
import schemas.tasks as tasks import schemas.tasks as tasks_schemas
import schemas.projects as projects import schemas.projects as projects_schemas
import schemas.users as users import schemas.users as users_schemas
router = APIRouter(prefix="/projects", tags=["projects"]) router = APIRouter(prefix="/projects", tags=["projects"])
@ -13,169 +17,266 @@ router = APIRouter(prefix="/projects", tags=["projects"])
## GET endpoints ## 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""" """Get a project by ID"""
@router.get("/{project_id}", response_model=projects.ProjectBase) get_token = request.cookies.get("access_token")
def read_project(project_id: int, db: db_dependency): if not get_token:
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first() 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: if db_project is None:
raise HTTPException(status_code=404, detail="Project not found") 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 return db_project
"""Get tasks from a specified project""" @router.get("/{project_id}/users", response_model=List[users_schemas.UserBase], tags=["users", "projects"])
@router.get("/{project_id}/tasks", response_model=List[tasks.TaskBase], tags=["tasks"]) def get_project_users(project_id: int, request:Request, db: db_dependency):
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
"""Get users from a specified project""" """Get users from a specified project"""
@router.get("/{project_id}/users", response_model=List[users.UserBase], tags=["users"]) get_token = request.cookies.get("access_token")
def read_users_from_project(project_id: int, db: db_dependency): if not get_token:
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first() 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: if db_project is None:
raise HTTPException(status_code=404, detail="Project not found") 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 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
## # """Get a specific task from a specified project"""
## POST endpoints # @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) # @router.get("/{project_id}/users", response_model=List[users_schemas.UserBase], tags=["users"])
def create_project(project: projects.ProjectCreate, db: db_dependency): # def read_users_from_project(project_id: int, db: db_dependency):
db_project = projects.models.Project( # db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
name=project.name, # if db_project is None:
description=project.description # raise HTTPException(status_code=404, detail="Project not found")
) # return db_project.users
db.add(db_project)
db.commit()
db.refresh(db_project)
return db_project
"""Create a new task in a specified project""" # ##
# ## POST endpoints
@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
"""Add users to a specified project using their IDs""" # """Create a new project"""
@router.post("/{project_id}/users", response_model=projects.ProjectAddUsers, tags=["users"]) # @router.post("/", response_model=projects.ProjectCreate)
def add_users_to_project(project_id: int, user_data: projects.ProjectAddUsers, db: db_dependency): # def create_project(project: projects.ProjectCreate, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first() # db_project = projects(
if db_project is None: # name=project.name,
raise HTTPException(status_code=404, detail="Project not found") # description=project.description
for user_id in user_data.user_ids: # )
db_user = db.query(users.models.User).filter(users.models.User.id == user_id).first() # db.add(db_project)
if db_user: # db.commit()
db_project.users.append(db_user) # db.refresh(db_project)
db.commit() # return db_project
db.refresh(db_project)
return db_project
## # """Create a new task in a specified project"""
## PUT endpoints
## # @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) # @router.post("/{project_id}/users", response_model=projects.ProjectAddUsers, tags=["users"])
def update_project(project_id: int, project: projects.ProjectUpdate, db: db_dependency): # 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() # db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
if db_project is None: # if db_project is None:
raise HTTPException(status_code=404, detail="Project not found") # raise HTTPException(status_code=404, detail="Project not found")
if project.name is not None: # for user_id in user_data.user_ids:
db_project.name = project.name # db_user = db.query(users.models.User).filter(users.models.User.id == user_id).first()
if project.description is not None: # if db_user:
db_project.description = project.description # db_project.users.append(db_user)
db.commit() # db.commit()
db.refresh(db_project) # db.refresh(db_project)
return db_project # return db_project
"""Update a task in a specified project""" # ##
# ## PUT endpoints
@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""" # """Update a project by ID"""
@router.delete("/{project_id}/tasks/{task_id}" , tags=["tasks"]) # @router.put("/{project_id}", response_model=projects.ProjectUpdate)
def delete_task_from_project(project_id: int, task_id: int, db: db_dependency): # def update_project(project_id: int, project: projects.ProjectUpdate, 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() # db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first()
if db_task is None: # if db_project is None:
raise HTTPException(status_code=404, detail="Task not found in the specified project") # raise HTTPException(status_code=404, detail="Project not found")
db.delete(db_task) # if project.name is not None:
db.commit() # db_project.name = project.name
return {"detail": "Task deleted successfully"} # 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"]) # @router.put("/{project_id}/tasks/{task_id}", response_model=tasks.TaskUpdate, tags=["tasks"])
def remove_user_from_project(project_id: int, user_id: int, db: db_dependency): # def update_task_in_project(project_id: int, task_id: int, task: tasks.TaskUpdate, db: db_dependency):
db_project = db.query(projects.models.Project).filter(projects.models.Project.id == project_id).first() # db_task = db.query(tasks.models.Task).filter(tasks.models.Task.project_id == project_id, tasks.models.Task.id == task_id).first()
if db_project is None: # if db_task is None:
raise HTTPException(status_code=404, detail="Project not found") # raise HTTPException(status_code=404, detail="Task not found in the specified project")
db_user = db.query(users.models.User).filter(users.models.User.id == user_id).first() # if task.title is not None:
if db_user is None or db_user not in db_project.users: # db_task.title = task.title
raise HTTPException(status_code=404, detail="User not found in the specified project") # if task.description is not None:
db_project.users.remove(db_user) # db_task.description = task.description
db.commit() # if task.status is not None:
db.refresh(db_project) # db_task.status = task.status
return {"detail": "User removed from project successfully"} # 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"}