From 3814d6d290dc70f6993e77fe3c27a718488f793e Mon Sep 17 00:00:00 2001 From: Aidan Kim Date: Tue, 29 Oct 2024 19:24:07 -0400 Subject: [PATCH] Created API routes for create, update, delete, get_all, and get_by_name. Deleted service methods for get by id. --- backend/api/resource.py | 21 +++++-- backend/api/service.py | 26 ++++---- backend/main.py | 1 - backend/services/exceptions.py | 2 + backend/services/resource.py | 105 +++++++++++---------------------- backend/services/service.py | 33 ++++------- 6 files changed, 78 insertions(+), 110 deletions(-) diff --git a/backend/api/resource.py b/backend/api/resource.py index 0b11539..97d25af 100644 --- a/backend/api/resource.py +++ b/backend/api/resource.py @@ -19,25 +19,38 @@ openapi_tags = { # TODO: Create custom exceptions @api.post("", response_model=Resource, tags=["Resource"]) def create( - subject: User, resource: Resource, resource_svc: ResourceService = Depends() + uuid: str, resource: Resource, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() ): + subject = user_svc.get_user_by_uuid(uuid) return resource_svc.create(subject, resource) @api.get("", response_model=List[Resource], tags=["Resource"]) -def get_all(subject: User, resource_svc: ResourceService = Depends()): +def get_all( + uuid: str, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() +): + subject = user_svc.get_user_by_uuid(uuid) return resource_svc.get_resource_by_user(subject) +@api.get("/{name}", response_model=Resource, tags=["Resource"]) +def get_by_name( + name:str, uuid:str, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() +): + subject = user_svc.get_user_by_uuid(uuid) + return resource_svc.get_resource_by_name(name, subject) + @api.put("", response_model=Resource, tags=["Resource"]) def update( - subject: User, resource: Resource, resource_svc: ResourceService = Depends() + uuid: str, resource: Resource, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() ): + subject = user_svc.get_user_by_uuid(uuid) return resource_svc.update(subject, resource) @api.delete("", response_model=None, tags=["Resource"]) def delete( - subject: User, resource: Resource, resource_svc: ResourceService = Depends() + uuid: str, resource: Resource, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends() ): + subject = user_svc.get_user_by_uuid(uuid) resource_svc.delete(subject, resource) diff --git a/backend/api/service.py b/backend/api/service.py index de73d13..bd3c4dc 100644 --- a/backend/api/service.py +++ b/backend/api/service.py @@ -19,32 +19,36 @@ openapi_tags = { # TODO: Create custom exceptions @api.post("", response_model=Service, tags=["Service"]) def create( - subject: User, - service: Service, - service_svc: ServiceService = Depends() + uuid: str, service: Service, user_svc: UserService = Depends(), service_svc: ServiceService = Depends() ): + subject = user_svc.get_user_by_uuid(uuid) return service_svc.create(subject, service) @api.get("", response_model=List[Service], tags=["Service"]) def get_all( - subject: User, - service_svc: ServiceService = Depends() + uuid: str, user_svc: UserService = Depends(), service_svc: ServiceService = Depends() ): + subject = user_svc.get_user_by_uuid(uuid) return service_svc.get_service_by_user(subject) +@api.get("/{name}", response_model=Service, tags=["Service"]) +def get_by_name( + name: str, uuid: str, user_svc: UserService = Depends(), service_svc: ServiceService = Depends() +): + subject = user_svc.get_user_by_uuid(uuid) + return service_svc.get_service_by_name(name, subject) + @api.put("", response_model=Service, tags=["Service"]) def update( - subject: User, - service: Service, - service_svc: ServiceService = Depends() + uuid: str, service: Service, user_svc: UserService = Depends(), service_svc: ServiceService = Depends() ): + subject = user_svc.get_user_by_uuid(uuid) return service_svc.update(subject, service) @api.delete("", response_model=None, tags=["Service"]) def delete( - subject: User, - service: Service, - service_svc: ServiceService = Depends() + uuid: str, service: Service, user_svc: UserService = Depends(), service_svc: ServiceService = Depends() ): + subject = user_svc.get_user_by_uuid(uuid) service_svc.delete(subject, service) diff --git a/backend/main.py b/backend/main.py index 5720633..12ecaad 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,7 +3,6 @@ from fastapi.responses import JSONResponse from fastapi.middleware.gzip import GZipMiddleware - from .api import user, health, service, resource, tag description = """ diff --git a/backend/services/exceptions.py b/backend/services/exceptions.py index 069bff1..daa4b9b 100644 --- a/backend/services/exceptions.py +++ b/backend/services/exceptions.py @@ -20,6 +20,8 @@ class UserPermissionException(Exception): class ServiceNotFoundException(Exception): """Exception for when the service being requested is not in the table.""" +class TagNotFoundException(Exception): + """Exception for when the tag being requested is not in the table.""" class ProgramNotAssignedException(Exception): """Exception for when the user does not have correct access for requested services.""" diff --git a/backend/services/resource.py b/backend/services/resource.py index 2ccbee9..3522003 100644 --- a/backend/services/resource.py +++ b/backend/services/resource.py @@ -1,12 +1,12 @@ from fastapi import Depends from ..database import db_session from sqlalchemy.orm import Session -from sqlalchemy import select +from sqlalchemy import and_, select from ..models.resource_model import Resource from ..entities.resource_entity import ResourceEntity from ..models.user_model import User, UserTypeEnum -from .exceptions import ResourceNotFoundException +from .exceptions import ProgramNotAssignedException, ResourceNotFoundException class ResourceService: @@ -24,11 +24,29 @@ class ResourceService: programs = subject.program resources = [] for program in programs: - entities = self._session.query(ResourceEntity).where(ResourceEntity.program == program).all() + entities = ( + self._session.query(ResourceEntity) + .where(ResourceEntity.program == program) + .all() + ) for entity in entities: resources.append(entity.to_model()) return [resource for resource in resources] + def get_resource_by_name(self, name: str, subject: User) -> Resource: + """Get a resource by name.""" + query = select(ResourceEntity).where( + and_( + ResourceEntity.name == name, ResourceEntity.program.in_(subject.program) + ) + ) + entity = self._session.scalars(query).one_or_none() + if entity is None: + raise ResourceNotFoundException( + f"Resource with name: {name} does not exist or program has not been assigned." + ) + return entity.to_model() + def create(self, subject: User, resource: Resource) -> Resource: """ Creates a resource based on the input object and adds it to the table if the user has the right permissions. @@ -40,47 +58,15 @@ class ResourceService: Returns: Resource: Object added to table """ - # Ask about what the requirements for making a resource are. - if resource.role != subject.role or resource.group != subject.group: - raise PermissionError( - "User does not have permission to add resources in this role or group." + if subject.role != UserTypeEnum.ADMIN: + raise ProgramNotAssignedException( + f"User is not {UserTypeEnum.ADMIN}, cannot update service" ) - resource_entity = ResourceEntity.from_model(resource) self._session.add(resource_entity) self._session.commit() - return resource_entity.to_model() - def get_by_id(self, user: User, id: int) -> Resource: - """ - Gets a resource based on the resource id that the user has access to - - Parameters: - user: a valid User model representing the currently logged in User - id: int, the id of the resource - - Returns: - Resource - - Raises: - ResourceNotFoundException: If no resource is found with id - """ - resource = ( - self._session.query(ResourceEntity) - .filter( - ResourceEntity.id == id, - ResourceEntity.role == user.role, - ResourceEntity.group == user.group, - ) - .one_or_none() - ) - - if resource is None: - raise ResourceNotFoundException(f"No resource found with id: {id}") - - return resource.to_model() - def update(self, subject: User, resource: Resource) -> Resource: """ Update the resource if the user has access @@ -95,25 +81,21 @@ class ResourceService: Raises: ResourceNotFoundException: If no resource is found with the corresponding ID """ - if resource.role != subject.role or resource.group != subject.group: - raise PermissionError( - "User does not have permission to update this resource." + if subject.role != UserTypeEnum.ADMIN: + raise ProgramNotAssignedException( + f"User is not {UserTypeEnum.ADMIN}, cannot update service" ) - query = select(ResourceEntity).where(ResourceEntity.id == resource.id) entity = self._session.scalars(query).one_or_none() - if entity is None: raise ResourceNotFoundException( f"No resource found with matching id: {resource.id}" ) - entity.name = resource.name entity.summary = resource.summary entity.link = resource.link entity.program = resource.program self._session.commit() - return entity.to_model() def delete(self, subject: User, resource: Resource) -> None: @@ -127,34 +109,15 @@ class ResourceService: Raises: ResourceNotFoundException: If no resource is found with the corresponding id """ + if subject.role != UserTypeEnum.ADMIN: + raise ProgramNotAssignedException( + f"User is not {UserTypeEnum.ADMIN}, cannot update service" + ) query = select(ResourceEntity).where(ResourceEntity.id == resource.id) entity = self._session.scalars(query).one_or_none() - if entity is None: - raise ResourceNotFoundException(f"No resource found with matching id: {resource.id}") - + raise ResourceNotFoundException( + f"No resource found with matching id: {resource.id}" + ) self._session.delete(entity) self._session.commit() - - def get_by_slug(self, user: User, search_string: str) -> list[Resource]: - """ - Get a list of resources given a search string that the user has access to - - Parameters: - user: a valid User model representing the currently logged in User - search_string: a string to search resources by - - Returns: - list[Resource]: list of resources relating to the string - - Raises: - ResourceNotFoundException if no resource is found with the corresponding slug - """ - query = select(ResourceEntity).where( - ResourceEntity.title.ilike(f"%{search_string}%"), - ResourceEntity.role == user.role, - ResourceEntity.group == user.group, - ) - entities = self._session.scalars(query).all() - - return [entity.to_model() for entity in entities] diff --git a/backend/services/service.py b/backend/services/service.py index edce109..e10309e 100644 --- a/backend/services/service.py +++ b/backend/services/service.py @@ -27,37 +27,24 @@ class ServiceService: return [service.to_model() for service in entities] else: programs = subject.program - resources = [] + services = [] for program in programs: entities = self._session.query(ServiceEntity).where(ServiceEntity.program == program).all() for entity in entities: - resources.append(entity.to_model()) - return [service for service in resources] + services.append(entity.to_model()) + return [service for service in services] - def get_service_by_program(self, program: ProgramTypeEnum) -> list[Service]: - """Service method getting services belonging to a particular program.""" - query = select(ServiceEntity).filter(ServiceEntity.program == program) - entities = self._session.scalars(query) - - return [entity.to_model() for entity in entities] - - def get_service_by_id(self, id: int) -> Service: + def get_service_by_name(self, name: str, subject: User) -> Service: """Service method getting services by id.""" - query = select(ServiceEntity).filter(ServiceEntity.id == id) + query = select(ServiceEntity).where( + and_( + ServiceEntity.name == name, ServiceEntity.program.in_(subject.program) + ) + ) entity = self._session.scalars(query).one_or_none() if entity is None: - raise ServiceNotFoundException(f"Service with id: {id} does not exist") - - return entity.to_model() - - def get_service_by_name(self, name: str) -> Service: - """Service method getting services by id.""" - query = select(ServiceEntity).filter(ServiceEntity.name == name) - entity = self._session.scalars(query).one_or_none() - - if entity is None: - raise ServiceNotFoundException(f"Service with name: {name} does not exist") + raise ServiceNotFoundException(f"Service with name: {name} does not exist or program has not been assigned") return entity.to_model()