mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-09 22:00:18 -04:00
Compare commits
5 Commits
68f07b8c53
...
e3dbe59fb9
Author | SHA1 | Date | |
---|---|---|---|
|
e3dbe59fb9 | ||
|
b3db1144ca | ||
|
8532f8c4c1 | ||
|
e26201b810 | ||
|
21167f7a6b |
|
@ -24,3 +24,58 @@ def get_all(
|
|||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
|
||||
return resource_svc.get_resource_by_user(subject)
|
||||
|
||||
|
||||
@api.get("/{id}", response_model=Resource, tags=["Resource"])
|
||||
def get_by_id(
|
||||
user_id: str,
|
||||
id: int,
|
||||
resource_svc: ResourceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
resource = resource_svc.get_resource_by_id(id)
|
||||
return resource
|
||||
|
||||
|
||||
@api.post("/", response_model=Resource, tags=["Resource"])
|
||||
def create_service(
|
||||
user_id: str,
|
||||
resource: Resource,
|
||||
resource_svc: ResourceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
new_resource = resource_svc.create(subject, resource)
|
||||
return new_resource
|
||||
|
||||
|
||||
@api.put("/{resource_id}", response_model=Resource, tags=["Resource"])
|
||||
def update_service(
|
||||
resource_id: int,
|
||||
user_id: str,
|
||||
resource: Resource,
|
||||
resource_svc: ResourceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
resource.id = resource_id
|
||||
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
updated_resource = resource_svc.update(subject, resource)
|
||||
return updated_resource
|
||||
|
||||
|
||||
@api.delete("/{resource_id}", response_model=Resource, tags=["Resource"])
|
||||
def delete_service_tag_by_id(
|
||||
resource_id: int,
|
||||
tag_id: int,
|
||||
user_id: str,
|
||||
resource_svc: ResourceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
resource = resource_svc.get_resource_by_id(resource_id)
|
||||
tag = resource_svc._tag_service.get_tag_by_id(tag_id)
|
||||
|
||||
resource_svc.remove_tag(subject, resource, tag)
|
||||
return resource_svc.get_resource_by_id(resource_id)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
from ..services import ServiceService, UserService
|
||||
from ..models.service_model import Service
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from ..services import ServiceService, UserService, TagService
|
||||
from ..models import Service, Tag
|
||||
|
||||
from typing import List
|
||||
|
||||
|
@ -24,3 +24,58 @@ def get_all(
|
|||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
|
||||
return service_svc.get_service_by_user(subject)
|
||||
|
||||
|
||||
@api.get("/{id}", response_model=Service, tags=["Service"])
|
||||
def get_by_id(
|
||||
user_id: str,
|
||||
id: int,
|
||||
service_svc: ServiceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
service = service_svc.get_service_by_id(id)
|
||||
return service
|
||||
|
||||
|
||||
@api.post("/", response_model=Service, tags=["Service"])
|
||||
def create_service(
|
||||
user_id: str,
|
||||
service: Service,
|
||||
service_svc: ServiceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
new_service = service_svc.create(subject, service)
|
||||
return new_service
|
||||
|
||||
|
||||
@api.put("/{service_id}", response_model=Service, tags=["Service"])
|
||||
def update_service(
|
||||
service_id: int,
|
||||
user_id: str,
|
||||
service: Service,
|
||||
service_svc: ServiceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
service.id = service_id
|
||||
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
updated_service = service_svc.update(subject, service)
|
||||
return updated_service
|
||||
|
||||
|
||||
@api.delete("/{service_id}", response_model=Service, tags=["Service"])
|
||||
def delete_service_tag_by_id(
|
||||
service_id: int,
|
||||
tag_id: int,
|
||||
user_id: str,
|
||||
service_svc: ServiceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
service = service_svc.get_service_by_id(service_id)
|
||||
tag = service_svc._tag_service.get_tag_by_id(tag_id)
|
||||
|
||||
service_svc.remove_tag(subject, service, tag)
|
||||
return service_svc.get_service_by_id(service_id)
|
||||
|
|
|
@ -31,8 +31,8 @@ class ResourceEntity(EntityBase):
|
|||
link: Mapped[str] = mapped_column(String, nullable=False)
|
||||
program: Mapped[Program_Enum] = mapped_column(Enum(Program_Enum), nullable=False)
|
||||
# relationships
|
||||
resourceTags: Mapped[list["ResourceTagEntity"]] = relationship(
|
||||
back_populates="resource", cascade="all,delete"
|
||||
resource_tags: Mapped[list["ResourceTagEntity"]] = relationship(
|
||||
back_populates="resource", cascade="all,delete-orphan"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -64,4 +64,5 @@ class ResourceEntity(EntityBase):
|
|||
summary=self.summary,
|
||||
link=self.link,
|
||||
program=self.program,
|
||||
tags=[tag_entity.tag.to_model() for tag_entity in self.resource_tags],
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
""" Defines the table for resource tags """
|
||||
|
||||
# Import our mapped SQL types from SQLAlchemy
|
||||
from importlib.resources import Resource
|
||||
from sqlalchemy import ForeignKey, Integer, String, DateTime
|
||||
|
||||
# Import mapping capabilities from the SQLAlchemy ORM
|
||||
|
@ -15,6 +16,8 @@ from datetime import datetime
|
|||
# Import self for to model
|
||||
from typing import Self
|
||||
|
||||
from ..models import ResourceTag
|
||||
|
||||
|
||||
class ResourceTagEntity(EntityBase):
|
||||
|
||||
|
@ -27,20 +30,20 @@ class ResourceTagEntity(EntityBase):
|
|||
tagId: Mapped[int] = mapped_column(ForeignKey("tag.id"))
|
||||
|
||||
# relationships
|
||||
resource: Mapped["ResourceEntity"] = relationship(back_populates="resourceTags")
|
||||
tag: Mapped["TagEntity"] = relationship(back_populates="resourceTags")
|
||||
resource: Mapped["ResourceEntity"] = relationship(back_populates="resource_tags")
|
||||
tag: Mapped["TagEntity"] = relationship(back_populates="resource")
|
||||
|
||||
# @classmethod
|
||||
# def from_model (cls, model: resource_tag_model) -> Self:
|
||||
# return cls (
|
||||
# id = model.id,
|
||||
# resourceId = model.resourceId,
|
||||
# tagId = model.tagId,
|
||||
# )
|
||||
def to_model(self) -> ResourceTag:
|
||||
return ResourceTag(
|
||||
id=self.id,
|
||||
resourceId=self.resourceId,
|
||||
tagId=self.tagId,
|
||||
)
|
||||
|
||||
# def to_model (self) -> resource_tag_model:
|
||||
# return user_model(
|
||||
# id = self.id,
|
||||
# resourceId = self.resourceId,
|
||||
# tagId = self.tagId,
|
||||
# )
|
||||
@classmethod
|
||||
def from_model(cls, model: "ResourceTag") -> Self:
|
||||
return cls(
|
||||
id=model.id,
|
||||
resourceId=model.resourceId,
|
||||
tagId=model.tagId,
|
||||
)
|
||||
|
|
|
@ -20,6 +20,7 @@ from backend.models.service_model import Service
|
|||
from typing import Self
|
||||
from backend.models.enum_for_models import ProgramTypeEnum
|
||||
|
||||
|
||||
class ServiceEntity(EntityBase):
|
||||
|
||||
# set table name
|
||||
|
@ -32,16 +33,33 @@ class ServiceEntity(EntityBase):
|
|||
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[ProgramTypeEnum] = mapped_column(Enum(ProgramTypeEnum), nullable=False)
|
||||
program: Mapped[ProgramTypeEnum] = mapped_column(
|
||||
Enum(ProgramTypeEnum), nullable=False
|
||||
)
|
||||
|
||||
# relationships
|
||||
serviceTags: Mapped[list["ServiceTagEntity"]] = relationship(
|
||||
back_populates="service", cascade="all,delete"
|
||||
service_tags: Mapped[list["ServiceTagEntity"]] = relationship(
|
||||
back_populates="service", cascade="all,delete-orphan"
|
||||
)
|
||||
|
||||
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)
|
||||
return Service(
|
||||
id=self.id,
|
||||
name=self.name,
|
||||
status=self.status,
|
||||
summary=self.summary,
|
||||
requirements=self.requirements,
|
||||
program=self.program,
|
||||
tags=[tag.tag.to_model() for tag in self.service_tags],
|
||||
)
|
||||
|
||||
@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)
|
||||
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,
|
||||
)
|
||||
|
|
|
@ -9,6 +9,10 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|||
# Import the EntityBase that we are extending
|
||||
from .entity_base import EntityBase
|
||||
|
||||
from typing import Self
|
||||
|
||||
from ..models.service_tag_model import ServiceTag
|
||||
|
||||
|
||||
class ServiceTagEntity(EntityBase):
|
||||
|
||||
|
@ -21,5 +25,16 @@ class ServiceTagEntity(EntityBase):
|
|||
tagId: Mapped[int] = mapped_column(ForeignKey("tag.id"))
|
||||
|
||||
# relationships
|
||||
service: Mapped["ServiceEntity"] = relationship(back_populates="serviceTags")
|
||||
tag: Mapped["TagEntity"] = relationship(back_populates="serviceTags")
|
||||
service: Mapped["ServiceEntity"] = relationship(back_populates="service_tags")
|
||||
tag: Mapped["TagEntity"] = relationship(back_populates="service")
|
||||
|
||||
def to_model(self) -> ServiceTag:
|
||||
return ServiceTag(id=self.id, serviceId=self.serviceId, tagId=self.tagId)
|
||||
|
||||
@classmethod
|
||||
def from_model(cls, model: "ServiceTag") -> Self:
|
||||
return cls(
|
||||
id=model.id,
|
||||
serviceId=model.serviceId,
|
||||
tagId=model.tagId,
|
||||
)
|
||||
|
|
|
@ -16,22 +16,25 @@ from ..models.tag_model import Tag
|
|||
|
||||
from typing import Self
|
||||
|
||||
|
||||
class TagEntity(EntityBase):
|
||||
|
||||
#set table name
|
||||
# set table name
|
||||
__tablename__ = "tag"
|
||||
|
||||
#set fields
|
||||
# set fields
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
content: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
|
||||
#relationships
|
||||
resourceTags: Mapped[list["ResourceTagEntity"]] = relationship(back_populates="tag", cascade="all,delete")
|
||||
serviceTags: Mapped[list["ServiceTagEntity"]] = relationship(back_populates="tag", cascade="all,delete")
|
||||
# relationships
|
||||
resource: Mapped[list["ResourceTagEntity"]] = relationship(
|
||||
back_populates="tag", cascade="all,delete", overlaps="tag"
|
||||
)
|
||||
service: Mapped[list["ServiceTagEntity"]] = relationship(
|
||||
back_populates="tag", cascade="all,delete", overlaps="tag"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_model(cls, model: Tag) -> Self:
|
||||
"""
|
||||
|
@ -42,10 +45,10 @@ class TagEntity(EntityBase):
|
|||
Returns:
|
||||
self: The entity
|
||||
"""
|
||||
|
||||
|
||||
return cls(
|
||||
id=model.id,
|
||||
content=model.id,
|
||||
content=model.content,
|
||||
)
|
||||
|
||||
def to_model(self) -> Tag:
|
||||
|
@ -56,10 +59,4 @@ class TagEntity(EntityBase):
|
|||
User: A User model for API usage
|
||||
"""
|
||||
|
||||
return Tag(
|
||||
id=self.id,
|
||||
content=self.content,
|
||||
)
|
||||
|
||||
|
||||
|
||||
return Tag(id=self.id, content=self.content, created_at=self.created_at)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
from .user_model import User
|
||||
from .resource_model import Resource
|
||||
from .service_model import Service
|
||||
from .tag_model import Tag
|
||||
from .enum_for_models import ProgramTypeEnum, UserTypeEnum
|
||||
from .resource_tag_model import ResourceTag
|
||||
from .service_tag_model import ServiceTag
|
|
@ -4,6 +4,7 @@ from typing import List
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from .enum_for_models import ProgramTypeEnum
|
||||
from .tag_model import Tag
|
||||
|
||||
|
||||
class Resource(BaseModel):
|
||||
|
@ -13,3 +14,4 @@ class Resource(BaseModel):
|
|||
link: str = Field(..., max_length=150, description="link to the resource")
|
||||
program: ProgramTypeEnum
|
||||
created_at: Optional[datetime]
|
||||
tags: List[Tag] = []
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
from pydantic import BaseModel, Field
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from .tag_model import Tag
|
||||
from .resource_model import Resource
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ResourceTag(Resource, BaseModel):
|
||||
class ResourceTag(BaseModel):
|
||||
id: int | None = None
|
||||
resourceid: int | None = None
|
||||
tagid: List[Tag]
|
||||
tagId: int
|
||||
resourceId: int
|
||||
|
|
|
@ -4,6 +4,7 @@ from typing import List
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from .enum_for_models import ProgramTypeEnum
|
||||
from .tag_model import Tag
|
||||
|
||||
|
||||
class Service(BaseModel):
|
||||
|
@ -14,3 +15,4 @@ class Service(BaseModel):
|
|||
summary: str
|
||||
requirements: List[str]
|
||||
program: ProgramTypeEnum
|
||||
tags: List[Tag] = []
|
||||
|
|
|
@ -4,16 +4,12 @@ from typing import List
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from .enum_for_models import ProgramTypeEnum
|
||||
from .enum_for_models import UserTypeEnum
|
||||
from .service_model import Service
|
||||
|
||||
from .tag_model import Tag
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ServiceTag(Service, BaseModel):
|
||||
class ServiceTag(BaseModel):
|
||||
id: int | None = None
|
||||
serviceid: int | None = None
|
||||
tagId: List[Tag]
|
||||
serviceId: int | None = None
|
||||
tagId: int
|
||||
|
|
|
@ -6,7 +6,12 @@ from ..database import engine, _engine_str
|
|||
from ..env import getenv
|
||||
from .. import entities
|
||||
|
||||
from ..test.services import user_test_data, service_test_data, resource_test_data
|
||||
from ..test.services import (
|
||||
user_test_data,
|
||||
service_test_data,
|
||||
resource_test_data,
|
||||
tag_test_data,
|
||||
)
|
||||
|
||||
database = getenv("POSTGRES_DATABASE")
|
||||
|
||||
|
@ -23,5 +28,6 @@ entities.EntityBase.metadata.create_all(engine)
|
|||
with Session(engine) as session:
|
||||
user_test_data.insert_test_data(session)
|
||||
service_test_data.insert_test_data(session)
|
||||
tag_test_data.insert_test_data(session)
|
||||
resource_test_data.insert_test_data(session)
|
||||
session.commit()
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from fastapi import Depends
|
||||
|
||||
from backend.services.tag import TagService
|
||||
from ..database import db_session
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import select
|
||||
|
@ -6,13 +8,18 @@ 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:
|
||||
|
||||
def __init__(self, session: Session = Depends(db_session)):
|
||||
def __init__(
|
||||
self,
|
||||
session: Session = Depends(db_session),
|
||||
tag_service: TagService = Depends(),
|
||||
):
|
||||
self._session = session
|
||||
self._tag_service = tag_service
|
||||
|
||||
def get_resource_by_user(self, subject: User):
|
||||
"""Resource method getting all of the resources that a user has access to based on role"""
|
||||
|
@ -43,15 +50,22 @@ class ResourceService:
|
|||
Returns:
|
||||
Resource: Object added to table
|
||||
"""
|
||||
if resource.role != user.role or resource.group != user.group:
|
||||
raise PermissionError(
|
||||
"User does not have permission to add resources in this role or group."
|
||||
if user.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(
|
||||
f"User is not {UserTypeEnum.ADMIN}, cannot update resource"
|
||||
)
|
||||
|
||||
resource_entity = ResourceEntity.from_model(resource)
|
||||
self._session.add(resource_entity)
|
||||
self._session.commit()
|
||||
self._session.flush()
|
||||
|
||||
for tag in resource.tags:
|
||||
tag_entity = self._tag_service.get_or_create_tag(tag.content)
|
||||
self._tag_service.add_tag_resource(
|
||||
user, tag_entity, ResourceEntity.to_model(resource_entity)
|
||||
)
|
||||
|
||||
self._session.commit()
|
||||
return resource_entity.to_model()
|
||||
|
||||
def get_by_id(self, user: User, id: int) -> Resource:
|
||||
|
@ -72,8 +86,7 @@ class ResourceService:
|
|||
self._session.query(ResourceEntity)
|
||||
.filter(
|
||||
ResourceEntity.id == id,
|
||||
ResourceEntity.role == user.role,
|
||||
ResourceEntity.group == user.group,
|
||||
ResourceEntity.program.in_(user.program),
|
||||
)
|
||||
.one_or_none()
|
||||
)
|
||||
|
@ -97,22 +110,38 @@ class ResourceService:
|
|||
Raises:
|
||||
ResourceNotFoundException: If no resource is found with the corresponding ID
|
||||
"""
|
||||
if resource.role != user.role or resource.group != user.group:
|
||||
raise PermissionError(
|
||||
"User does not have permission to update this resource."
|
||||
if user.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(
|
||||
f"User is not {UserTypeEnum.ADMIN}, cannot update service"
|
||||
)
|
||||
|
||||
obj = self._session.get(ResourceEntity, resource.id) if resource.id else None
|
||||
resource_entity = (
|
||||
self._session.query(ResourceEntity)
|
||||
.filter(ResourceEntity.id == resource.id)
|
||||
.one_or_none()
|
||||
)
|
||||
|
||||
if obj is None:
|
||||
self._tag_service.delete_all_tags_service(resource)
|
||||
|
||||
if resource_entity is None:
|
||||
raise ResourceNotFoundException(
|
||||
f"No resource found with matching id: {resource.id}"
|
||||
"The resource you are searching for does not exist."
|
||||
)
|
||||
|
||||
obj.update_from_model(resource) # Assuming an update method exists
|
||||
self._session.commit()
|
||||
resource_entity.name = resource.name
|
||||
resource_entity.status = resource.status
|
||||
resource_entity.summary = resource.summary
|
||||
resource_entity.requirements = resource.requirements
|
||||
resource_entity.program = resource.program
|
||||
|
||||
return obj.to_model()
|
||||
for tag in resource.tags:
|
||||
tag_entity = self._tag_service.get_or_create_tag(tag.content)
|
||||
self._tag_service.add_tag_service(
|
||||
user, tag_entity, ResourceEntity.to_model(resource_entity)
|
||||
)
|
||||
|
||||
self._session.commit()
|
||||
return resource_entity.to_model()
|
||||
|
||||
def delete(self, user: User, id: int) -> None:
|
||||
"""
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
from typing import List
|
||||
from fastapi import Depends
|
||||
|
||||
from backend.entities.service_tag_entity import ServiceTagEntity
|
||||
from backend.entities.tag_entity import TagEntity
|
||||
|
||||
from ..database import db_session
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import func, select, and_, func, or_, exists, or_
|
||||
|
@ -12,12 +16,19 @@ from backend.services.exceptions import (
|
|||
ServiceNotFoundException,
|
||||
ProgramNotAssignedException,
|
||||
)
|
||||
from . import TagService
|
||||
from ..models import Tag
|
||||
|
||||
|
||||
class ServiceService:
|
||||
|
||||
def __init__(self, session: Session = Depends(db_session)):
|
||||
def __init__(
|
||||
self,
|
||||
session: Session = Depends(db_session),
|
||||
tag_service: TagService = Depends(),
|
||||
):
|
||||
self._session = session
|
||||
self._tag_service = tag_service
|
||||
|
||||
def get_service_by_program(self, program: ProgramTypeEnum) -> list[Service]:
|
||||
"""Service method getting services belonging to a particular program."""
|
||||
|
@ -33,8 +44,8 @@ class ServiceService:
|
|||
|
||||
if entity is None:
|
||||
raise ServiceNotFoundException(f"Service with id: {id} does not exist")
|
||||
|
||||
return entity.to_model()
|
||||
service = entity.to_model()
|
||||
return service
|
||||
|
||||
def get_service_by_name(self, name: str) -> Service:
|
||||
"""Service method getting services by id."""
|
||||
|
@ -44,7 +55,9 @@ class ServiceService:
|
|||
if entity is None:
|
||||
raise ServiceNotFoundException(f"Service with name: {name} does not exist")
|
||||
|
||||
return entity.to_model()
|
||||
service = entity.to_model()
|
||||
# service.tags.extend(TagService.get_tags_for_service(TagService, service))
|
||||
return service
|
||||
|
||||
def get_service_by_user(self, subject: User):
|
||||
"""Service method getting all of the services that a user has access to based on role"""
|
||||
|
@ -73,8 +86,8 @@ class ServiceService:
|
|||
|
||||
query = select(ServiceEntity)
|
||||
entities = self._session.scalars(query).all()
|
||||
|
||||
return [service.to_model() for service in entities]
|
||||
services = [service.to_model() for service in entities]
|
||||
return services
|
||||
|
||||
def create(self, subject: User, service: Service) -> Service:
|
||||
"""Creates/adds a service to the table."""
|
||||
|
@ -85,6 +98,14 @@ class ServiceService:
|
|||
|
||||
service_entity = ServiceEntity.from_model(service)
|
||||
self._session.add(service_entity)
|
||||
self._session.flush()
|
||||
|
||||
for tag in service.tags:
|
||||
tag_entity = self._tag_service.get_or_create_tag(tag.content)
|
||||
self._tag_service.add_tag_service(
|
||||
subject, tag_entity, ServiceEntity.to_model(service_entity)
|
||||
)
|
||||
|
||||
self._session.commit()
|
||||
return service_entity.to_model()
|
||||
|
||||
|
@ -95,7 +116,13 @@ class ServiceService:
|
|||
f"User is not {UserTypeEnum.ADMIN}, cannot update service"
|
||||
)
|
||||
|
||||
service_entity = self._session.get(ServiceEntity, service.id)
|
||||
service_entity = (
|
||||
self._session.query(ServiceEntity)
|
||||
.filter(ServiceEntity.id == service.id)
|
||||
.one_or_none()
|
||||
)
|
||||
|
||||
self._tag_service.delete_all_tags_service(service)
|
||||
|
||||
if service_entity is None:
|
||||
raise ServiceNotFoundException(
|
||||
|
@ -108,20 +135,49 @@ class ServiceService:
|
|||
service_entity.requirements = service.requirements
|
||||
service_entity.program = service.program
|
||||
|
||||
self._session.commit()
|
||||
for tag in service.tags:
|
||||
tag_entity = self._tag_service.get_or_create_tag(tag.content)
|
||||
self._tag_service.add_tag_service(
|
||||
subject, tag_entity, ServiceEntity.to_model(service_entity)
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
service_entity = (
|
||||
self._session.query(ServiceEntity)
|
||||
.filter(ServiceEntity.id == service.id)
|
||||
.one_or_none()
|
||||
)
|
||||
if service_entity is None:
|
||||
raise ServiceNotFoundException(
|
||||
"The service you are searching for does not exist."
|
||||
)
|
||||
|
||||
self._tag_service.delete_all_tags_service(service_entity.to_model())
|
||||
self._session.delete(service_entity)
|
||||
self._session.commit()
|
||||
|
||||
def add_tag(self, subject: User, service: Service, tag: Tag):
|
||||
service = self.get_service_by_id(service.id)
|
||||
tag = self._tag_service.get_tag_by_id(tag.id)
|
||||
self._tag_service.add_tag_service(subject, service.id, tag.id)
|
||||
|
||||
def remove_tag(self, subject: User, service: Service, tag: Tag) -> None:
|
||||
service_tag = (
|
||||
self._session.query(ServiceTagEntity)
|
||||
.filter(
|
||||
ServiceTagEntity.serviceId == service.id,
|
||||
ServiceTagEntity.tagId == tag.id,
|
||||
)
|
||||
.one_or_none()
|
||||
)
|
||||
if service_tag is None:
|
||||
raise Exception(
|
||||
f"No tag with id {tag.id} found for service with id {service.id}."
|
||||
)
|
||||
self._session.delete(service_tag)
|
||||
self._session.commit()
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
from fastapi import Depends
|
||||
|
||||
from backend.models.enum_for_models import UserTypeEnum
|
||||
from ..database import db_session
|
||||
from sqlalchemy.orm import Session
|
||||
from ..models.tag_model import Tag
|
||||
from ..entities.tag_entity import TagEntity
|
||||
from ..entities.resource_tag_entity import ResourceTagEntity
|
||||
from ..entities.service_tag_entity import ServiceTagEntity
|
||||
from .exceptions import ResourceNotFoundException
|
||||
from ..models.user_model import User
|
||||
from ..models.resource_model import Resource
|
||||
from ..models.service_model import Service
|
||||
from sqlalchemy import select
|
||||
from ..entities import TagEntity, ResourceTagEntity, ServiceTagEntity
|
||||
from ..models import User, Resource, Service, Tag, ResourceTag, ServiceTag
|
||||
from .exceptions import ProgramNotAssignedException, ResourceNotFoundException
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class TagService:
|
||||
|
@ -20,39 +18,33 @@ class TagService:
|
|||
def all(self) -> list[Tag]:
|
||||
"""Returns a list of all Tags"""
|
||||
|
||||
query = select(TagEntity)
|
||||
query = select(TagEntity)
|
||||
entities = self._session.scalars(query).all()
|
||||
|
||||
return [entity.to_model() for entity in entities]
|
||||
|
||||
def get_tag_by_id(self, id:int) -> Tag:
|
||||
|
||||
def get_tag_by_id(self, id: int) -> Tag:
|
||||
"""Returns tag based on it's id."""
|
||||
|
||||
tag = self._session.query(TagEntity).filter(TagEntity.id == id).one_or_none()
|
||||
return tag.to_model()
|
||||
return tag
|
||||
|
||||
def create(self, user: User, tag: Tag) -> Tag:
|
||||
def create(self, tag: Tag) -> Tag:
|
||||
"""Creates a tag in the database with id and content."""
|
||||
|
||||
# Add user permission check here if needed
|
||||
|
||||
tag_entity = TagEntity.from_model(tag)
|
||||
self._session.add(tag_entity)
|
||||
self._session.commit
|
||||
self._session.commit()
|
||||
|
||||
return tag_entity.to_model()
|
||||
|
||||
def delete(self, user: User, id:int) -> None:
|
||||
def delete(self, id: int) -> None:
|
||||
"""Method to delete a tag from the database, along with all connections."""
|
||||
|
||||
tag = (
|
||||
self._session.query(TagEntity)
|
||||
.filter(
|
||||
TagEntity.id == id
|
||||
)
|
||||
.one_or_none()
|
||||
)
|
||||
|
||||
tag = self._session.query(TagEntity).filter(TagEntity.id == id).one_or_none()
|
||||
|
||||
if tag is None:
|
||||
raise ResourceNotFoundException(f"No tag found with matching id: {id}")
|
||||
|
||||
|
@ -60,20 +52,16 @@ class TagService:
|
|||
|
||||
resource_tags = (
|
||||
self._session.query(ResourceTagEntity)
|
||||
.filter(
|
||||
ResourceTagEntity.tagId == id
|
||||
)
|
||||
.filter(ResourceTagEntity.tagId == id)
|
||||
.all()
|
||||
)
|
||||
|
||||
for tag in resource_tags:
|
||||
self._session.delete(tag)
|
||||
|
||||
|
||||
service_tags = (
|
||||
self._session.query(ServiceTagEntity)
|
||||
.filter(
|
||||
ServiceTagEntity.tagId == id
|
||||
)
|
||||
.filter(ServiceTagEntity.tagId == id)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
@ -81,42 +69,147 @@ class TagService:
|
|||
self._session.delete(tag)
|
||||
|
||||
self._session.commit()
|
||||
|
||||
def get_tags_for_resource(self, user: User, resource: Resource) -> list[Tag]:
|
||||
|
||||
def get_tags_for_resource(self, resource: Resource) -> list[Tag]:
|
||||
"""Get tags based on a resource."""
|
||||
tags: list[Tag]
|
||||
tags: list[Tag] = []
|
||||
resource_tags = (
|
||||
self._session.query(ResourceTagEntity)
|
||||
.filter(
|
||||
ResourceTagEntity.tagId == resource.id
|
||||
)
|
||||
.filter(ResourceTagEntity.tagId == resource.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
if resource_tags is None:
|
||||
raise ResourceNotFoundException(f"No tags found for resource with id: {resource.id}")
|
||||
raise ResourceNotFoundException(
|
||||
f"No tags found for resource with id: {resource.id}"
|
||||
)
|
||||
|
||||
for tag in resource_tags:
|
||||
tags.append(self.get_tag_by_id(tag.id))
|
||||
|
||||
|
||||
return tags
|
||||
|
||||
def get_tags_for_service(self, user: User, service: Service) -> list[Tag]:
|
||||
|
||||
def get_tags_for_service(self, service: Service) -> list[Tag]:
|
||||
"""Get tags based on a resource."""
|
||||
tags: list[Tag]
|
||||
tags: list[Tag] = []
|
||||
service_tags = (
|
||||
self._session.query(ServiceTagEntity)
|
||||
.filter(
|
||||
ServiceTagEntity.tagId == service.id
|
||||
)
|
||||
.filter(ServiceTagEntity.serviceId == service.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
if service_tags is None:
|
||||
raise ResourceNotFoundException(f"No tags found for service with id: {service.id}")
|
||||
raise ResourceNotFoundException(
|
||||
f"No tags found for service with id: {service.id}"
|
||||
)
|
||||
|
||||
for tag in service_tags:
|
||||
tags.append(self.get_tag_by_id(tag.id))
|
||||
|
||||
|
||||
return tags
|
||||
|
||||
def add_tag_resource(self, user: User, tag: Tag, resource: Resource) -> None:
|
||||
"""Adds a tag to a resource"""
|
||||
if user.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(
|
||||
f"User is not {UserTypeEnum.ADMIN}, cannot update resource tags"
|
||||
)
|
||||
|
||||
existing_tag = (
|
||||
self._session.query(ResourceTagEntity)
|
||||
.filter(
|
||||
ResourceTagEntity.tagId == tag.id,
|
||||
ResourceTagEntity.resourceId == resource.id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if existing_tag:
|
||||
raise Exception(
|
||||
f"Tag with id {tag.id} already exists for resource with id {resource.id}."
|
||||
)
|
||||
|
||||
resource_tag_entity = ResourceTagEntity.from_model(
|
||||
ResourceTag(tagId=tag.id, resourceId=resource.id)
|
||||
)
|
||||
|
||||
try:
|
||||
self._session.add(resource_tag_entity)
|
||||
self._session.commit()
|
||||
except Exception as e:
|
||||
self._session.rollback() # Rollback in case of error
|
||||
raise Exception("Failed to add tag to resource") from e
|
||||
|
||||
def add_tag_service(self, user: User, tag: Tag, service: Service) -> None:
|
||||
"""Adds a tag to a service"""
|
||||
|
||||
existing_tag = (
|
||||
self._session.query(ServiceTagEntity)
|
||||
.filter(
|
||||
ServiceTagEntity.tagId == tag.id,
|
||||
ServiceTagEntity.serviceId == service.id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if existing_tag:
|
||||
raise Exception(
|
||||
f"Tag with id {tag.id} already exists for service with id {service.id}."
|
||||
)
|
||||
|
||||
service_tag_entity = ServiceTagEntity.from_model(
|
||||
ServiceTag(tagId=tag.id, serviceId=service.id)
|
||||
)
|
||||
|
||||
try:
|
||||
self._session.add(service_tag_entity)
|
||||
self._session.commit()
|
||||
except Exception as e:
|
||||
self._session.rollback() # Rollback in case of error
|
||||
raise Exception("Failed to add tag to service") from e
|
||||
|
||||
def delete_all_tags_service(self, service: Service) -> None:
|
||||
"""Deletes all service tags for a service"""
|
||||
|
||||
service_tags = self._session.query(ServiceTagEntity).filter(
|
||||
ServiceTagEntity.serviceId == service.id
|
||||
)
|
||||
|
||||
if service_tags.count() == 0:
|
||||
raise ResourceNotFoundException
|
||||
|
||||
service_tags.delete(synchronize_session=False)
|
||||
self._session.commit()
|
||||
|
||||
def delete_all_tags_resource(self, resource: Resource) -> None:
|
||||
"""Deletes all resource tags for a resource"""
|
||||
|
||||
resource_tags = self._session.query(ResourceTagEntity).filter(
|
||||
ResourceTagEntity.resourceId == resource.id
|
||||
)
|
||||
|
||||
if resource_tags.count() == 0:
|
||||
raise ResourceNotFoundException
|
||||
|
||||
resource_tags.delete(synchronize_session=False)
|
||||
self._session.commit()
|
||||
|
||||
def get_or_create_tag(self, content: str) -> Tag:
|
||||
existing_tag = (
|
||||
self._session.query(TagEntity)
|
||||
.filter(TagEntity.content == content)
|
||||
.one_or_none()
|
||||
)
|
||||
|
||||
if existing_tag:
|
||||
return existing_tag.to_model()
|
||||
|
||||
try:
|
||||
tag = Tag(content=content)
|
||||
tag_entity = TagEntity.from_model(tag)
|
||||
self._session.add(tag_entity)
|
||||
self._session.commit()
|
||||
return tag_entity.to_model()
|
||||
except Exception as e:
|
||||
self._session.rollback()
|
||||
raise Exception(f"Failed to create tag with content: {tag.content}") from e
|
||||
|
|
|
@ -4,7 +4,12 @@ import pytest
|
|||
from sqlalchemy import Engine, create_engine, text
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.exc import OperationalError
|
||||
from .services import user_test_data, tag_test_data, service_test_data
|
||||
from .services import (
|
||||
user_test_data,
|
||||
tag_test_data,
|
||||
service_test_data,
|
||||
resource_test_data,
|
||||
)
|
||||
|
||||
from ..database import _engine_str
|
||||
from ..env import getenv
|
||||
|
@ -57,5 +62,6 @@ def setup_insert_data_fixture(session: Session):
|
|||
user_test_data.insert_fake_data(session)
|
||||
tag_test_data.insert_fake_data(session)
|
||||
service_test_data.insert_fake_data(session)
|
||||
resource_test_data.insert_fake_data(session)
|
||||
session.commit()
|
||||
yield
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
import pytest
|
||||
from unittest.mock import create_autospec
|
||||
from sqlalchemy.orm import Session
|
||||
from ...services import UserService
|
||||
from ...services import TagService
|
||||
from ...services import ServiceService
|
||||
|
||||
|
||||
from ...services import UserService, TagService, ServiceService, ResourceService
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
@ -15,12 +11,20 @@ def user_svc(session: Session):
|
|||
"""This fixture is used to test the UserService class"""
|
||||
return UserService(session)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
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)
|
||||
return ServiceService(session)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def resource_svc(session: Session):
|
||||
"""This fixutre is used to test the ResourceService class"""
|
||||
return ResourceService(session)
|
||||
|
|
10
backend/test/services/resource_test.py
Normal file
10
backend/test/services/resource_test.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from backend.services import ResourceService, TagService
|
||||
from .user_test_data import admin
|
||||
from .fixtures import resource_svc, tag_svc
|
||||
|
||||
|
||||
def test_temp(resource_svc: ResourceService, tag_svc: TagService):
|
||||
resources = resource_svc.get_resource_by_user(admin)
|
||||
tags = tag_svc.all()
|
||||
print(tags)
|
||||
print(resources)
|
|
@ -3,7 +3,8 @@ from sqlalchemy.orm import Session
|
|||
|
||||
from ...entities import ServiceEntity
|
||||
from ...models.enum_for_models import ProgramTypeEnum
|
||||
from ...models.service_model import Service
|
||||
from ...models import Service, Tag
|
||||
from .tag_test_data import tags
|
||||
|
||||
service1 = Service(
|
||||
id=1,
|
||||
|
@ -95,6 +96,7 @@ service_1 = Service(
|
|||
summary="24/7 support for individuals in crisis",
|
||||
requirements=["Anonymous", "Confidential"],
|
||||
program=ProgramTypeEnum.DOMESTIC,
|
||||
tags=[tags[0], tags[1]],
|
||||
)
|
||||
|
||||
service_2 = Service(
|
||||
|
|
|
@ -2,13 +2,55 @@
|
|||
|
||||
# PyTest
|
||||
import pytest
|
||||
from ...services.tag import TagService
|
||||
from .fixtures import tag_svc
|
||||
from .tag_test_data import tag1, tag2, tag3
|
||||
from . import tag_test_data
|
||||
from ...services import TagService, ResourceService, ServiceService
|
||||
from .fixtures import tag_svc, resource_svc, service_svc
|
||||
from .tag_test_data import tag_to_create, tag_to_create_no_id, tags
|
||||
from .user_test_data import admin
|
||||
|
||||
|
||||
def test_get_all(tag_svc: TagService):
|
||||
"""Test that all tags can be retrieved."""
|
||||
tags = tag_svc.all()
|
||||
assert len(tags) == 3
|
||||
all_tags = tag_svc.all()
|
||||
assert len(all_tags) == len(tags)
|
||||
|
||||
|
||||
def test_create_tag(tag_svc: TagService):
|
||||
"""Test creation of tag"""
|
||||
created_tag = tag_svc.create(admin, tag_to_create)
|
||||
|
||||
assert created_tag.content == tag_to_create.content
|
||||
assert len(tag_svc.all()) == len(tags) + 1
|
||||
|
||||
|
||||
def test_create_tag_no_id(tag_svc: TagService):
|
||||
"""Test creation of tag"""
|
||||
created_tag = tag_svc.create(admin, tag_to_create_no_id)
|
||||
queried_tag = tag_svc.get_tag_by_id(4)
|
||||
|
||||
assert created_tag.content == tag_to_create_no_id.content
|
||||
assert len(tag_svc.all()) == len(tags) + 1
|
||||
assert queried_tag.content == created_tag.content
|
||||
|
||||
|
||||
def test_resource_tag_creation(tag_svc: TagService, resource_svc: ResourceService):
|
||||
"""Test creation and attachment of resource tag"""
|
||||
|
||||
resource = resource_svc.get_resource_by_user(admin)[0]
|
||||
tag_svc.add_tag_resource(admin, tags[0], resource)
|
||||
updated_resource = resource_svc.get_by_id(admin, resource.id)
|
||||
|
||||
assert len(resource.tags) == 0
|
||||
assert len(updated_resource.tags) == 1
|
||||
assert resource.id == updated_resource.id
|
||||
|
||||
|
||||
def test_service_tag_creation(tag_svc: TagService, service_svc: ServiceService):
|
||||
"""Test creation and attachment of service tag"""
|
||||
|
||||
service = service_svc.get_service_by_user(admin)[0]
|
||||
tag_svc.add_tag_service(admin, tags[0], service)
|
||||
updated_service = service_svc.get_service_by_id(service.id)
|
||||
|
||||
assert len(service.tags) == 0
|
||||
assert len(updated_service.tags) == 1
|
||||
assert service.id == updated_service.id
|
||||
|
|
|
@ -11,7 +11,9 @@ tag2 = Tag(id=2, content="Tag 2", created_at=datetime.now())
|
|||
|
||||
tag3 = Tag(id=3, content="Tag 3", created_at=datetime.now())
|
||||
|
||||
tagToCreate = Tag(id=4, content="Tag 4", created_at=datetime.now())
|
||||
tag_to_create = Tag(id=4, content="Tag 4", created_at=datetime.now())
|
||||
|
||||
tag_to_create_no_id = Tag(content="Tag 5", created_at=datetime.now())
|
||||
|
||||
tags = [tag1, tag2, tag3]
|
||||
|
||||
|
@ -61,6 +63,25 @@ def insert_fake_data(session: Session):
|
|||
session.commit()
|
||||
|
||||
|
||||
def insert_test_data(session: Session):
|
||||
"""Inserts test organization data into the test session."""
|
||||
|
||||
global tags
|
||||
|
||||
# Create entities for test organization data
|
||||
entities = []
|
||||
for tag in tags:
|
||||
entity = TagEntity.from_model(tag)
|
||||
session.add(entity)
|
||||
entities.append(entity)
|
||||
|
||||
# Reset table IDs to prevent ID conflicts
|
||||
reset_table_id_seq(session, TagEntity, TagEntity.id, len(tags) + 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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user