Compare commits

...

2 Commits

Author SHA1 Message Date
IluaAir
9346aae5ef add delete task, update dep 2025-08-16 11:52:53 +03:00
IluaAir
464689bd29 add user with tasks and endpoint 2025-08-15 16:20:56 +03:00
8 changed files with 73 additions and 25 deletions

View File

@@ -8,6 +8,7 @@ from src.api.dependacies.db_dep import sessionDep
from src.core.auth_manager import AuthManager from src.core.auth_manager import AuthManager
from src.core.settings import settings from src.core.settings import settings
from src.schemas.auth import TokenData from src.schemas.auth import TokenData
from src.services.tasks import TaskService
from src.services.users import UserService from src.services.users import UserService
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.api.v1_login_url}/login") oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.api.v1_login_url}/login")
@@ -51,14 +52,35 @@ async def get_admin_user(db: sessionDep, current_user: ActiveUser):
AdminUser = Annotated[TokenData, Depends(get_admin_user)] AdminUser = Annotated[TokenData, Depends(get_admin_user)]
async def user_or_admin( async def user_or_admin(db: sessionDep, current_user: ActiveUser, owner_id: int):
db: sessionDep, current_user: ActiveUser, id: Annotated[int, Path()] if current_user.id == owner_id:
):
if current_user.id == id:
return current_user return current_user
else: else:
admin = await get_admin_user(db, current_user) admin = await get_admin_user(db, current_user)
return admin return admin
CurrentOrAdmin = Annotated[TokenData, Depends(user_or_admin)] async def CurrentOrAdminOwner(
db: sessionDep, current_user: ActiveUser, id: Annotated[int, Path()]
):
authorized_user = await user_or_admin(db, current_user, id)
if not authorized_user:
raise HTTPException(status_code=403, detail="Not authorized")
return authorized_user
async def CurrentOrAdminTask(
db: sessionDep,
id: Annotated[int, Path()],
current_user: ActiveUser,
):
task = await TaskService(db).get_task(id)
if not task:
raise HTTPException(status_code=404, detail="Task not found")
return await CurrentOrAdminOwner(db, current_user, task.user_id)
OwnerDep = Annotated[TokenData, Depends(CurrentOrAdminOwner)]
TaskOwnerDep = Annotated[TokenData, Depends(CurrentOrAdminTask)]

View File

@@ -3,7 +3,8 @@ from typing import Annotated
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from src.api.dependacies.db_dep import sessionDep from src.api.dependacies.db_dep import sessionDep
from src.api.dependacies.user_dep import ActiveUser from src.api.dependacies.user_dep import ActiveUser, CurrentOrAdminTask, TaskOwnerDep
from src.schemas.auth import TokenData
from src.schemas.tasks import TaskADDRequest from src.schemas.tasks import TaskADDRequest
from src.services.tasks import TaskService from src.services.tasks import TaskService
from src.services.users import UserService from src.services.users import UserService
@@ -17,8 +18,8 @@ async def get_tasks(session: sessionDep, user: ActiveUser):
return result return result
@router.get("/{task_id}") @router.get("/{id}")
async def get_task_id(task_id: int): ... async def get_task_id(id: int): ...
@router.post("/") @router.post("/")
@@ -33,13 +34,10 @@ async def post_task(
return result return result
@router.put("/{task_id}") @router.delete("/{id}")
async def put_task(task_id: int): ... async def delete_task(
session: sessionDep,
id: int,
@router.patch("/{task_id}") _: TaskOwnerDep,
async def patch_task(task_id: int): ... ):
await TaskService(session).delete_task(id)
@router.delete("/{task_id}")
async def delete_task(task_id: int): ...

View File

@@ -1,7 +1,11 @@
from fastapi import APIRouter, Body from fastapi import APIRouter, Body
from src.api.dependacies.db_dep import sessionDep from src.api.dependacies.db_dep import sessionDep
from src.api.dependacies.user_dep import ActiveUser, AdminUser, CurrentOrAdmin from src.api.dependacies.user_dep import (
ActiveUser,
AdminUser,
OwnerDep,
)
from src.core.settings import settings from src.core.settings import settings
from src.schemas.users import UserUpdate from src.schemas.users import UserUpdate
from src.services.users import UserService from src.services.users import UserService
@@ -21,14 +25,17 @@ async def get_all_users(session: sessionDep, _: AdminUser):
@router.get("/{id}") @router.get("/{id}")
async def get_user_by_id(session: sessionDep, id: int, _: CurrentOrAdmin): async def get_user_by_id(session: sessionDep, id: int, _: OwnerDep):
user = await UserService(session).get_user_by_filter_or_raise(id=id) user = await UserService(session).get_user_by_filter_or_raise(id=id)
return user return user
@router.patch("/{id}") @router.patch("/{id}")
async def patch_user( async def patch_user(
session: sessionDep, id: int, _: CurrentOrAdmin, user_update: UserUpdate = Body() session: sessionDep,
id: int,
_: OwnerDep,
user_update: UserUpdate = Body(),
): ):
updated_user = await UserService(session).update_user( updated_user = await UserService(session).update_user(
id=id, update_data=user_update id=id, update_data=user_update

View File

@@ -26,7 +26,7 @@ class UsersRepo(BaseRepo):
.where(self.model.id == user_id) .where(self.model.id == user_id)
.options( .options(
selectinload(self.model.tasks).load_only( selectinload(self.model.tasks).load_only(
TasksORM.id, TasksORM.title, TasksORM.due_date TasksORM.id, TasksORM.title, TasksORM.due_date, TasksORM.priority
) )
) )
) )

View File

@@ -4,11 +4,19 @@ from typing import Literal
from pydantic import BaseModel, ConfigDict from pydantic import BaseModel, ConfigDict
class TaskADDRequest(BaseModel): class TaskShort(BaseModel):
title: str title: str
description: str | None = None
due_date: date | None = None due_date: date | None = None
priority: Literal["low", "medium", "high", "critical"] = "medium" priority: Literal["low", "medium", "high", "critical"] = "medium"
model_config = ConfigDict(from_attributes=True)
class TaskWithId(TaskShort):
id: int
class TaskADDRequest(TaskShort):
description: str | None = None
class Task(TaskADDRequest): class Task(TaskADDRequest):

View File

@@ -2,6 +2,7 @@ from typing import Annotated
from pydantic import BaseModel, BeforeValidator, ConfigDict, EmailStr from pydantic import BaseModel, BeforeValidator, ConfigDict, EmailStr
from src.schemas.tasks import TaskWithId
from src.schemas.validators import ensure_password from src.schemas.validators import ensure_password
@@ -25,6 +26,10 @@ class UserWithHashedPass(User):
hashed_password: str hashed_password: str
class UserWithTasks(User):
tasks: list[TaskWithId]
class UserRequest(BaseModel): class UserRequest(BaseModel):
username: str username: str
password: str password: str

View File

@@ -17,3 +17,10 @@ class TaskService(BaseService):
created_task_orm = await self.session.task.create_one(data_to_insert) created_task_orm = await self.session.task.create_one(data_to_insert)
await self.session.commit() await self.session.commit()
return Task.model_validate(created_task_orm) return Task.model_validate(created_task_orm)
async def get_task(self, task_id: int):
return await self.session.task.get_one_or_none(id=task_id)
async def delete_task(self, task_id: int):
await self.session.task.delete_one(id=task_id)
await self.session.commit()

View File

@@ -1,6 +1,6 @@
from fastapi import HTTPException from fastapi import HTTPException
from src.schemas.users import User, UserUpdate from src.schemas.users import User, UserUpdate, UserWithTasks
from src.services.base import BaseService from src.services.base import BaseService
@@ -43,3 +43,4 @@ class UserService(BaseService):
user = await self.session.user.get_one_with_load(user_id) user = await self.session.user.get_one_with_load(user_id)
if user is None: if user is None:
raise HTTPException(status_code=404, detail="User not found.") raise HTTPException(status_code=404, detail="User not found.")
return UserWithTasks.model_validate(user)