mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-03 19:40:16 -04:00
updated the service methods and modified a few of the tests.
This commit is contained in:
parent
dfed92816d
commit
a107337737
12
backend/entities/sample_entity.py
Normal file
12
backend/entities/sample_entity.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from sqlalchemy import create_engine, Column, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from .entity_base import EntityBase
|
||||
|
||||
|
||||
class SampleEntity(EntityBase):
|
||||
__tablename__ = "persons"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String, nullable=False)
|
||||
age: Mapped[int] = mapped_column(Integer)
|
||||
email: Mapped[str] = mapped_column(String, unique=True, nullable=False)
|
|
@ -13,9 +13,12 @@ from .entity_base import EntityBase
|
|||
from datetime import datetime
|
||||
|
||||
# Import enums for Program
|
||||
from .program_enum import Program_Enum
|
||||
import enum
|
||||
from sqlalchemy import Enum
|
||||
|
||||
from backend.models.service_model import Service
|
||||
from typing import Self
|
||||
from backend.models.enum_for_models import ProgramTypeEnum
|
||||
|
||||
class ServiceEntity(EntityBase):
|
||||
|
||||
|
@ -26,11 +29,19 @@ class ServiceEntity(EntityBase):
|
|||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
name: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
summary: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
requirements: Mapped[list[str]] = mapped_column(ARRAY(String))
|
||||
program: Mapped[Program_Enum] = mapped_column(Enum(Program_Enum), nullable=False)
|
||||
program: Mapped[ProgramTypeEnum] = mapped_column(Enum(ProgramTypeEnum), nullable=False)
|
||||
|
||||
# relationships
|
||||
serviceTags: Mapped[list["ServiceTagEntity"]] = relationship(
|
||||
back_populates="service", cascade="all,delete"
|
||||
)
|
||||
|
||||
def to_model(self) -> Service:
|
||||
return Service(id=self.id, name=self.name, status=self.status, summary=self.summary, requirements=self.requirements, program=self.program)
|
||||
|
||||
@classmethod
|
||||
def from_model(cls, model:Service) -> Self:
|
||||
return cls(id=model.id, name=model.name, status=model.status, summary=model.summary, requirements=model.requirements, program=model.program)
|
|
@ -13,8 +13,7 @@ from .entity_base import EntityBase
|
|||
from datetime import datetime
|
||||
|
||||
# Import enums for Role and Program
|
||||
from .program_enum import Program_Enum
|
||||
from .user_enum import Role_Enum
|
||||
from backend.models.enum_for_models import UserTypeEnum, ProgramTypeEnum
|
||||
|
||||
# Import models for User methods
|
||||
from ..models.user_model import User
|
||||
|
@ -34,10 +33,10 @@ class UserEntity(EntityBase):
|
|||
username: Mapped[str] = mapped_column(
|
||||
String(32), nullable=False, default="", unique=True
|
||||
)
|
||||
role: Mapped[Role_Enum] = mapped_column(Enum(Role_Enum), nullable=False)
|
||||
role: Mapped[UserTypeEnum] = mapped_column(Enum(UserTypeEnum), nullable=False)
|
||||
email: Mapped[str] = mapped_column(String(50), nullable=False, unique=True)
|
||||
program: Mapped[list[Program_Enum]] = mapped_column(
|
||||
ARRAY(Enum(Program_Enum)), nullable=False
|
||||
program: Mapped[list[ProgramTypeEnum]] = mapped_column(
|
||||
ARRAY(Enum(ProgramTypeEnum)), nullable=False
|
||||
)
|
||||
experience: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
group: Mapped[str] = mapped_column(String(50))
|
||||
|
|
7
backend/services/exceptions.py
Normal file
7
backend/services/exceptions.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
class ServiceNotFoundException(Exception):
|
||||
"""Exception for when the service being requested is not in the table."""
|
||||
...
|
||||
|
||||
class ProgramNotAssignedException(Exception):
|
||||
"""Exception for when the user does not have correct access for requested services."""
|
||||
...
|
|
@ -1,9 +1,96 @@
|
|||
from fastapi import Depends
|
||||
|
||||
from ..database import db_session
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import func, select, and_, func, or_, exists, or_
|
||||
|
||||
from backend.models.service_model import Service
|
||||
from backend.models.user_model import User
|
||||
from backend.entities.service_entity import ServiceEntity
|
||||
from backend.models.enum_for_models import ProgramTypeEnum, UserTypeEnum
|
||||
from backend.services.exceptions import ServiceNotFoundException, ProgramNotAssignedException
|
||||
|
||||
class ServiceService:
|
||||
|
||||
def __init__(self, session: Session = Depends(db_session)):
|
||||
self._session = session
|
||||
|
||||
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:
|
||||
"""Service method getting services by id."""
|
||||
query = select(ServiceEntity).filter(ServiceEntity.id == id)
|
||||
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_user(self, subject: User):
|
||||
"""Service method getting all of the services that a user has access to based on role"""
|
||||
programs = subject.program
|
||||
services = []
|
||||
for program in programs:
|
||||
query = select(ServiceEntity).filter(ServiceEntity.program == program)
|
||||
entities = self._session.scalars(query)
|
||||
all.append(entities)
|
||||
return [service.to_model() for service in services]
|
||||
|
||||
|
||||
def get_all(self, subject: User) -> list[Service]:
|
||||
"""Service method retrieving all of the services in the table."""
|
||||
if subject.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(f"User is not {UserTypeEnum.ADMIN}, cannot get all")
|
||||
|
||||
query = select(ServiceEntity)
|
||||
entities = self._session.scalars(query).all()
|
||||
|
||||
return [service.to_model() for service in entities]
|
||||
|
||||
def create(self, subject: User, service: Service) -> Service:
|
||||
"""Creates/adds a service to the table."""
|
||||
if subject.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(f"User is not {UserTypeEnum.ADMIN}, cannot create service")
|
||||
|
||||
service_entity = ServiceEntity.from_model(service)
|
||||
self._session.add(service_entity)
|
||||
self._session.commit()
|
||||
return service_entity.to_model()
|
||||
|
||||
def update(self, subject: User, service: Service) -> Service:
|
||||
"""Updates a service if in the table."""
|
||||
if subject.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(f"User is not {UserTypeEnum.ADMIN}, cannot update service")
|
||||
|
||||
service_entity = self._session.get(ServiceEntity, service.id)
|
||||
|
||||
if service_entity is None:
|
||||
raise ServiceNotFoundException("The service you are searching for does not exist.")
|
||||
|
||||
service_entity.name = service.name
|
||||
service_entity.status = service.status
|
||||
service_entity.summary = service.summary
|
||||
service_entity.requirements = service.requirements
|
||||
service_entity.program = service.program
|
||||
|
||||
self._session.commit()
|
||||
|
||||
return service_entity.to_model()
|
||||
|
||||
def delete(self, subject: User, service: Service) -> None:
|
||||
"""Deletes a service from the table."""
|
||||
if subject.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(f"User is not {UserTypeEnum.ADMIN}")
|
||||
service_entity = self._session.get(ServiceEntity, service.id)
|
||||
|
||||
if service_entity is None:
|
||||
raise ServiceNotFoundException("The service you are searching for does not exist.")
|
||||
|
||||
self._session.delete(service_entity)
|
||||
self._session.commit()
|
|
@ -61,7 +61,8 @@ class UserService:
|
|||
|
||||
"""
|
||||
try:
|
||||
user = self.get_user_by_id(user.id)
|
||||
if (user.id != None):
|
||||
user = self.get_user_by_id(user.id)
|
||||
except:
|
||||
# if does not exist, create new object
|
||||
user_entity = UserEntity.from_model(user)
|
||||
|
|
|
@ -5,6 +5,7 @@ from unittest.mock import create_autospec
|
|||
from sqlalchemy.orm import Session
|
||||
from ...services import UserService
|
||||
from ...services import TagService
|
||||
from ...services import ServiceService
|
||||
|
||||
|
||||
|
||||
|
@ -18,3 +19,8 @@ def user_svc(session: Session):
|
|||
def tag_svc(session: Session):
|
||||
"""This fixture is used to test the TagService class"""
|
||||
return TagService(session)
|
||||
|
||||
@pytest.fixture()
|
||||
def service_svc(session: Session):
|
||||
"""This fixture is used to test the ServiceService class"""
|
||||
return ServiceService(session)
|
|
@ -0,0 +1,63 @@
|
|||
import pytest
|
||||
|
||||
from ...services import ServiceService
|
||||
from .fixtures import service_svc
|
||||
from ...models.enum_for_models import ProgramTypeEnum
|
||||
|
||||
from . import user_test_data
|
||||
from . import service_test_data
|
||||
from ...services.exceptions import ServiceNotFoundException, ProgramNotAssignedException
|
||||
|
||||
def test_get_all(service_svc: ServiceService):
|
||||
service = service_svc.get_all(user_test_data.admin)
|
||||
assert len(service) == len(service_test_data.services)
|
||||
|
||||
|
||||
def test_get_by_id(service_svc: ServiceService):
|
||||
if service_test_data.service_1.id != None:
|
||||
service = service_svc.get_service_by_id(service_test_data.service_1.id)
|
||||
assert service.id == service_test_data.service_1.id
|
||||
|
||||
|
||||
def test_get_by_name_not_found(service_svc: ServiceService):
|
||||
with pytest.raises(ServiceNotFoundException):
|
||||
service_svc.get_service_by_id(12)
|
||||
pytest.fail()
|
||||
|
||||
|
||||
def test_get_by_program(service_svc: ServiceService):
|
||||
services = service_svc.get_service_by_program(ProgramTypeEnum.COMMUNITY)
|
||||
for service in services:
|
||||
assert service.program == ProgramTypeEnum.COMMUNITY
|
||||
assert isinstance(service, Service)
|
||||
|
||||
|
||||
def test_create(service_svc: ServiceService):
|
||||
service = service_svc.create(user_test_data.admin, service_test_data.service_7)
|
||||
assert service.name == service_test_data.service_7.name
|
||||
assert isinstance(service, Service)
|
||||
|
||||
|
||||
def test_update(service_svc: ServiceService):
|
||||
service = service_svc.update(user_test_data.admin, service_test_data.service_6_edit)
|
||||
assert service.status == service_test_data.service_6_edit.status
|
||||
assert service.requirements == service_test_data.service_6_edit.requirements
|
||||
assert isinstance(service, Service)
|
||||
|
||||
|
||||
def test_update_not_found(service_svc: ServiceService):
|
||||
with pytest.raises(ServiceNotFoundException):
|
||||
service = service_svc.update(user_test_data.admin, service_test_data.new_service)
|
||||
pytest.fail()
|
||||
|
||||
|
||||
def test_delete(service_svc: ServiceService):
|
||||
service_svc.delete(user_test_data.admin, service_test_data.service_1)
|
||||
services = service_svc.get_all(user_test_data.admin)
|
||||
assert len(services) == len(service_test_data.services) - 1
|
||||
|
||||
|
||||
def test_delete_not_found(service_svc: ServiceService):
|
||||
with pytest.raises(ServiceNotFoundException):
|
||||
service_svc.delete(user_test_data.admin, service_test_data.service_7)
|
||||
pytest.fail()
|
143
backend/test/services/service_test_data.py
Normal file
143
backend/test/services/service_test_data.py
Normal file
|
@ -0,0 +1,143 @@
|
|||
import pytest
|
||||
from sqlalchemy.orm import Session
|
||||
from backend.entities.service_entity import ServiceEntity
|
||||
from backend.models.service_model import Service
|
||||
from backend.models.enum_for_models import ProgramTypeEnum
|
||||
|
||||
service_1 = Service(
|
||||
id = 1,
|
||||
name = "service 1",
|
||||
status= "open",
|
||||
summary= "presentation educating community on domestic violence",
|
||||
requirements= [""],
|
||||
program= ProgramTypeEnum.COMMUNITY
|
||||
)
|
||||
|
||||
service_2 = Service(
|
||||
id = 2,
|
||||
name = "service 2",
|
||||
status= "closed",
|
||||
summary= "service finding safe places to stay",
|
||||
requirements= [""],
|
||||
program= ProgramTypeEnum.DOMESTIC
|
||||
)
|
||||
|
||||
service_3 = Service(
|
||||
id = 3,
|
||||
name = "service 3",
|
||||
status= "open",
|
||||
summary= "",
|
||||
requirements= [""],
|
||||
program= ProgramTypeEnum.DOMESTIC
|
||||
)
|
||||
|
||||
service_4 = Service(
|
||||
id = 4,
|
||||
name = "service 4",
|
||||
status= "waitlist",
|
||||
summary= "community event",
|
||||
requirements= [""],
|
||||
program= ProgramTypeEnum.COMMUNITY
|
||||
)
|
||||
|
||||
service_5 = Service(
|
||||
id = 5,
|
||||
name = "service 5",
|
||||
status= "open",
|
||||
summary= "talk circle for victims of domestic violence",
|
||||
requirements= ["18+"],
|
||||
program= ProgramTypeEnum.COMMUNITY
|
||||
)
|
||||
|
||||
service_6 = Service(
|
||||
id = 6,
|
||||
name = "service 6",
|
||||
status= "waitlist",
|
||||
summary= "program offering economic assistance",
|
||||
requirements= [""],
|
||||
program= ProgramTypeEnum.ECONOMIC
|
||||
)
|
||||
|
||||
service_6_edit = Service(
|
||||
id = 6,
|
||||
name = "service 6",
|
||||
status= "open",
|
||||
summary= "program offering economic assistance",
|
||||
requirements= ["18+"],
|
||||
program= ProgramTypeEnum.ECONOMIC
|
||||
)
|
||||
|
||||
service_7 = Service(
|
||||
id = 7,
|
||||
name = "service 7",
|
||||
status= "waitlist",
|
||||
summary= "insert generic description",
|
||||
requirements= [""],
|
||||
program= ProgramTypeEnum.ECONOMIC
|
||||
)
|
||||
|
||||
new_service = Service(
|
||||
id = 8,
|
||||
name = "new service",
|
||||
status= "open",
|
||||
summary= "insert other generic description",
|
||||
requirements= [""],
|
||||
program= ProgramTypeEnum.DOMESTIC
|
||||
)
|
||||
|
||||
services = [service_1, service_2, service_3, service_4, service_5, service_6]
|
||||
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session, DeclarativeBase, InstrumentedAttribute
|
||||
|
||||
|
||||
def reset_table_id_seq(
|
||||
session: Session,
|
||||
entity: type[DeclarativeBase],
|
||||
entity_id_column: InstrumentedAttribute[int],
|
||||
next_id: int,
|
||||
) -> None:
|
||||
"""Reset the ID sequence of an entity table.
|
||||
|
||||
Args:
|
||||
session (Session) - A SQLAlchemy Session
|
||||
entity (DeclarativeBase) - The SQLAlchemy Entity table to target
|
||||
entity_id_column (MappedColumn) - The ID column (should be an int column)
|
||||
next_id (int) - Where the next inserted, autogenerated ID should begin
|
||||
|
||||
Returns:
|
||||
None"""
|
||||
table = entity.__table__
|
||||
id_column_name = entity_id_column.name
|
||||
sql = text(f"ALTER SEQUENCe {table}_{id_column_name}_seq RESTART WITH {next_id}")
|
||||
session.execute(sql)
|
||||
|
||||
|
||||
def insert_fake_data(session: Session):
|
||||
"""Inserts fake organization data into the test session."""
|
||||
|
||||
global services
|
||||
|
||||
# Create entities for test organization data
|
||||
entities = []
|
||||
for service in services:
|
||||
entity = ServiceEntity.from_model(service)
|
||||
session.add(entity)
|
||||
entities.append(entity)
|
||||
|
||||
# Reset table IDs to prevent ID conflicts
|
||||
reset_table_id_seq(session, ServiceEntity, ServiceEntity.id, len(services) + 1)
|
||||
|
||||
# Commit all changes
|
||||
session.commit()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def fake_data_fixture(session: Session):
|
||||
"""Insert fake data the session automatically when test is run.
|
||||
Note:
|
||||
This function runs automatically due to the fixture property `autouse=True`.
|
||||
"""
|
||||
insert_fake_data(session)
|
||||
session.commit()
|
||||
yield
|
|
@ -36,7 +36,8 @@ def test_get_all(user_svc: UserService):
|
|||
|
||||
def test_get_user_by_id(user_svc: UserService):
|
||||
"""Test getting a user by an id"""
|
||||
user = user_svc.get_user_by_id(volunteer.id)
|
||||
if volunteer.id != None:
|
||||
user = user_svc.get_user_by_id(volunteer.id)
|
||||
assert user is not None
|
||||
assert user.id is not None
|
||||
|
||||
|
|
|
@ -191,6 +191,6 @@ def fake_data_fixture(session: Session):
|
|||
Note:
|
||||
This function runs automatically due to the fixture property `autouse=True`.
|
||||
"""
|
||||
# insert_fake_data(session)
|
||||
insert_fake_data(session)
|
||||
session.commit()
|
||||
yield
|
||||
|
|
Loading…
Reference in New Issue
Block a user