Skip to content

Commit

Permalink
Project and user favorites apis refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
prabinoid committed Sep 10, 2024
1 parent 5b5d5da commit 4cc786b
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 70 deletions.
16 changes: 12 additions & 4 deletions backend/api/annotations/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,30 @@
from backend.services.project_service import ProjectService
from backend.services.task_annotations_service import TaskAnnotationsService
from fastapi import APIRouter, Depends, Request
from backend.db import get_session
from starlette.authentication import requires
from loguru import logger
from backend.db import get_db
from databases import Database
from backend.services.users.authentication_service import login_required
from backend.models.dtos.user_dto import AuthUserDTO

router = APIRouter(
prefix="/projects",
tags=["projects"],
dependencies=[Depends(get_session)],
dependencies=[Depends(get_db)],
responses={404: {"description": "Not found"}},
)


# class AnnotationsRestAPI(Resource):
@router.get("/{project_id}/annotations/{annotation_type}/")
@router.get("/{project_id}/annotations/")
async def get(request: Request, project_id: int, annotation_type: str = None):
async def get(
request: Request,
project_id: int,
annotation_type: str = None,
user: AuthUserDTO = Depends(login_required),
db: Database = Depends(get_db),
):
"""
Get all task annotations for a project
---
Expand Down
61 changes: 30 additions & 31 deletions backend/api/projects/favorites.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
# from flask_restful import Resource

from backend.models.dtos.project_dto import ProjectFavoriteDTO
from backend.services.project_service import ProjectService

# from backend.services.users.authentication_service import token_auth
from fastapi import APIRouter, Depends, Request
from backend.db import get_session
from starlette.authentication import requires
from backend.db import get_db
from databases import Database
from backend.services.users.authentication_service import login_required
from backend.models.dtos.user_dto import AuthUserDTO

router = APIRouter(
prefix="/projects",
tags=["projects"],
dependencies=[Depends(get_session)],
dependencies=[Depends(get_db)],
responses={404: {"description": "Not found"}},
)


# class ProjectsFavoritesAPI(Resource):
# @token_auth.login_required
@router.get("/{project_id}/favorite/")
@requires("authenticated")
async def get(request: Request, project_id: int):
async def get(
request: Request,
project_id: int,
user: AuthUserDTO = Depends(login_required),
db: Database = Depends(get_db),
):
"""
Validate that project is favorited
---
Expand Down Expand Up @@ -51,17 +50,19 @@ async def get(request: Request, project_id: int):
description: Internal Server Error
"""
user_id = request.user.display_name if request.user else None
favorited = ProjectService.is_favorited(project_id, user_id)
favorited = await ProjectService.is_favorited(project_id, user_id, db)
if favorited is True:
return {"favorited": True}, 200
return {"favorited": True}
return {"favorited": False}

return {"favorited": False}, 200


# @token_auth.login_required
@router.post("/{project_id}/favorite/")
@requires("authenticated")
async def post(request: Request, project_id: int):
async def post(
request: Request,
project_id: int,
user: AuthUserDTO = Depends(login_required),
db: Database = Depends(get_db),
):
"""
Set a project as favorite
---
Expand Down Expand Up @@ -91,19 +92,18 @@ async def post(request: Request, project_id: int):
500:
description: Internal Server Error
"""
authenticated_user_id = request.user.display_name if request.user else None
favorite_dto = ProjectFavoriteDTO()
favorite_dto.project_id = project_id
favorite_dto.user_id = authenticated_user_id

ProjectService.favorite(project_id, authenticated_user_id)
return {"project_id": project_id}, 200
await ProjectService.favorite(project_id, user.id, db)
return {"project_id": project_id}


# @token_auth.login_required
@router.delete("/{project_id}/favorite/")
@requires("authenticated")
async def delete(request: Request, project_id: int):
async def delete(
request: Request,
project_id: int,
user: AuthUserDTO = Depends(login_required),
db: Database = Depends(get_db),
):
"""
Unsets a project as favorite
---
Expand Down Expand Up @@ -134,8 +134,7 @@ async def delete(request: Request, project_id: int):
description: Internal Server Error
"""
try:
ProjectService.unfavorite(project_id, request.user.display_name)
await ProjectService.unfavorite(project_id, user.id, db)
except ValueError as e:
return {"Error": str(e).split("-")[1], "SubCode": str(e).split("-")[0]}, 400

return {"project_id": project_id}, 200
return {"project_id": project_id}
13 changes: 7 additions & 6 deletions backend/api/users/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,12 @@ async def get(request: Request, session: AsyncSession = Depends(get_session)):
return users_dto.model_dump(by_alias=True), 200


# class UsersQueriesFavoritesAPI():
# @token_auth.login_required
@router.get("/queries/favorites/")
@requires("authenticated")
async def get(request: Request):
async def get(
request: Request,
user: AuthUserDTO = Depends(login_required),
db: Database = Depends(get_db),
):
"""
Get projects favorited by a user
---
Expand All @@ -165,8 +166,8 @@ async def get(request: Request):
500:
description: Internal Server Error
"""
favs_dto = UserService.get_projects_favorited(request.user.display_name)
return favs_dto.model_dump(by_alias=True), 200
favs_dto = await UserService.get_projects_favorited(user.id, db)
return favs_dto


# class UsersQueriesUsernameAPI():
Expand Down
3 changes: 3 additions & 0 deletions backend/models/dtos/project_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ def __init__(self, favorited_projects: List[ProjectDTO] = None, **kwargs):

favorited_projects: List[ProjectDTO] = Field(default=[], alias="favoritedProjects")

class Config:
populate_by_name = True


class ProjectSearchDTO(BaseModel):
"""Describes the criteria users use to filter active projects"""
Expand Down
70 changes: 55 additions & 15 deletions backend/models/postgis/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,24 +566,64 @@ async def exists(project_id: int, db: Database) -> bool:

return True

def is_favorited(self, user_id: int) -> bool:
user = session.get(User, user_id)
if user not in self.favorited:
return False
# def is_favorited(self, user_id: int) -> bool:
# user = session.get(User, user_id)
# if user not in self.favorited:
# return False

return True
# return True

def favorite(self, user_id: int):
user = session.get(User, user_id)
self.favorited.append(user)
session.commit()
@staticmethod
async def is_favorited(project_id: int, user_id: int, db: Database) -> bool:
query = """
SELECT 1
FROM project_favorites
WHERE user_id = :user_id
AND project_id = :project_id
LIMIT 1
"""

def unfavorite(self, user_id: int):
user = session.get(User, user_id)
if user not in self.favorited:
raise ValueError("NotFeatured- Project not been favorited by user")
self.favorited.remove(user)
session.commit()
result = await db.fetch_one(
query, values={"user_id": user_id, "project_id": project_id}
)
return result is not None

@staticmethod
async def favorite(project_id: int, user_id: int, db: Database):
check_query = """
SELECT 1 FROM project_favorites WHERE project_id = :project_id AND user_id = :user_id
"""
exists = await db.fetch_one(
check_query, {"project_id": project_id, "user_id": user_id}
)

if not exists:
insert_query = """
INSERT INTO project_favorites (project_id, user_id)
VALUES (:project_id, :user_id)
"""
await db.execute(
insert_query, {"project_id": project_id, "user_id": user_id}
)

@staticmethod
async def unfavorite(project_id: int, user_id: int, db: Database):
check_query = """
SELECT 1 FROM project_favorites
WHERE project_id = :project_id AND user_id = :user_id
"""
exists = await db.fetch_one(
check_query, {"project_id": project_id, "user_id": user_id}
)

if not exists:
raise ValueError("NotFeatured - Project has not been favorited by user")

delete_query = """
DELETE FROM project_favorites
WHERE project_id = :project_id AND user_id = :user_id
"""
await db.execute(delete_query, {"project_id": project_id, "user_id": user_id})

def set_as_featured(self):
if self.featured is True:
Expand Down
19 changes: 9 additions & 10 deletions backend/services/project_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,20 +628,19 @@ async def get_featured_projects(
return dto

@staticmethod
def is_favorited(project_id: int, user_id: int) -> bool:
project = ProjectService.get_project_by_id(project_id)

return project.is_favorited(user_id)
async def is_favorited(project_id: int, user_id: int, db: Database) -> bool:
await ProjectService.exists(project_id, db)
return await Project.is_favorited(project_id, user_id, db)

@staticmethod
def favorite(project_id: int, user_id: int):
project = ProjectService.get_project_by_id(project_id)
project.favorite(user_id)
async def favorite(project_id: int, user_id: int, db: Database):
await ProjectService.exists(project_id, db)
await Project.favorite(project_id, user_id, db)

@staticmethod
def unfavorite(project_id: int, user_id: int):
project = ProjectService.get_project_by_id(project_id)
project.unfavorite(user_id)
async def unfavorite(project_id: int, user_id: int, db: Database):
await ProjectService.exists(project_id, db)
await Project.unfavorite(project_id, user_id, db)

@staticmethod
def get_project_title(project_id: int, preferred_locale: str = "en") -> str:
Expand Down
19 changes: 15 additions & 4 deletions backend/services/users/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,24 @@ async def update_user(
return user

@staticmethod
def get_projects_favorited(user_id: int) -> ProjectFavoritesDTO:
user = UserService.get_user_by_id(user_id)
projects_dto = [f.as_dto_for_admin(f.id) for f in user.favorites]
async def get_projects_favorited(user_id: int, db: Database) -> ProjectFavoritesDTO:
# Query to get the project IDs favorited by the user
project_ids_query = """
SELECT project_id
FROM project_favorites
WHERE user_id = :user_id
"""
project_ids_rows = await db.fetch_all(project_ids_query, {"user_id": user_id})
if not project_ids_rows:
return ProjectFavoritesDTO(favorited_projects=[])

projects_dto = [
await Project.as_dto_for_admin(row["project_id"], db)
for row in project_ids_rows
]

fav_dto = ProjectFavoritesDTO()
fav_dto.favorited_projects = projects_dto

return fav_dto

@staticmethod
Expand Down

0 comments on commit 4cc786b

Please sign in to comment.