mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-19 02:00:15 -04:00
Implemented API routes for getting all, creating, updating, and deleting resources, services, and tags.
This commit is contained in:
parent
a43fb7429a
commit
4c3d49004a
|
@ -1,4 +1,6 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
|
||||
from backend.models.user_model import User
|
||||
from ..services import ResourceService, UserService
|
||||
from ..models.resource_model import Resource
|
||||
|
||||
|
@ -15,12 +17,27 @@ openapi_tags = {
|
|||
# TODO: Add security using HTTP Bearer Tokens
|
||||
# TODO: Enable authorization by passing user uuid to API
|
||||
# TODO: Create custom exceptions
|
||||
@api.get("", response_model=List[Resource], tags=["Resource"])
|
||||
def get_all(
|
||||
user_id: str,
|
||||
resource_svc: ResourceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
@api.post("", response_model=Resource, tags=["Resource"])
|
||||
def create(
|
||||
subject: User, resource: Resource, resource_svc: ResourceService = Depends()
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
return resource_svc.create(subject, resource)
|
||||
|
||||
|
||||
@api.get("", response_model=List[Resource], tags=["Resource"])
|
||||
def get_all(subject: User, resource_svc: ResourceService = Depends()):
|
||||
return resource_svc.get_resource_by_user(subject)
|
||||
|
||||
|
||||
@api.put("", response_model=Resource, tags=["Resource"])
|
||||
def update(
|
||||
subject: User, resource: Resource, resource_svc: ResourceService = Depends()
|
||||
):
|
||||
return resource_svc.update(subject, resource)
|
||||
|
||||
|
||||
@api.delete("", response_model=None, tags=["Resource"])
|
||||
def delete(
|
||||
subject: User, resource: Resource, resource_svc: ResourceService = Depends()
|
||||
):
|
||||
resource_svc.delete(subject, resource)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
|
||||
from backend.models.user_model import User
|
||||
from ..services import ServiceService, UserService
|
||||
from ..models.service_model import Service
|
||||
|
||||
|
@ -15,12 +17,34 @@ openapi_tags = {
|
|||
# TODO: Add security using HTTP Bearer Tokens
|
||||
# TODO: Enable authorization by passing user uuid to API
|
||||
# TODO: Create custom exceptions
|
||||
@api.post("", response_model=Service, tags=["Service"])
|
||||
def create(
|
||||
subject: User,
|
||||
service: Service,
|
||||
service_svc: ServiceService = Depends()
|
||||
):
|
||||
return service_svc.create(subject, service)
|
||||
|
||||
|
||||
@api.get("", response_model=List[Service], tags=["Service"])
|
||||
def get_all(
|
||||
user_id: str,
|
||||
service_svc: ServiceService = Depends(),
|
||||
user_svc: UserService = Depends(),
|
||||
subject: User,
|
||||
service_svc: ServiceService = Depends()
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(user_id)
|
||||
|
||||
return service_svc.get_service_by_user(subject)
|
||||
|
||||
@api.put("", response_model=Service, tags=["Service"])
|
||||
def update(
|
||||
subject: User,
|
||||
service: Service,
|
||||
service_svc: ServiceService = Depends()
|
||||
):
|
||||
return service_svc.update(subject, service)
|
||||
|
||||
@api.delete("", response_model=None, tags=["Service"])
|
||||
def delete(
|
||||
subject: User,
|
||||
service: Service,
|
||||
service_svc: ServiceService = Depends()
|
||||
):
|
||||
service_svc.delete(subject, service)
|
||||
|
|
51
backend/api/tag.py
Normal file
51
backend/api/tag.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
|
||||
from backend.models.tag_model import Tag
|
||||
from backend.models.user_model import User
|
||||
from backend.services.tag import TagService
|
||||
from ..services import ResourceService, UserService
|
||||
from ..models.resource_model import Resource
|
||||
|
||||
from typing import List
|
||||
|
||||
api = APIRouter(prefix="/api/tag")
|
||||
|
||||
openapi_tags = {
|
||||
"name": "Tag",
|
||||
"description": "Tag CRUD operations.",
|
||||
}
|
||||
|
||||
|
||||
# TODO: Add security using HTTP Bearer Tokens
|
||||
# TODO: Enable authorization by passing user uuid to API
|
||||
# TODO: Create custom exceptions
|
||||
@api.post("", response_model=Tag, tags=["Tag"])
|
||||
def create(
|
||||
subject: User,
|
||||
tag: Tag,
|
||||
tag_service: TagService
|
||||
):
|
||||
return tag_service.create(subject, tag)
|
||||
|
||||
@api.get("", response_model=List[Tag], tags=["Tag"])
|
||||
def get_all(
|
||||
subject: User,
|
||||
tag_svc: TagService
|
||||
):
|
||||
return tag_svc.get_all()
|
||||
|
||||
@api.put("", response_model=Tag, tags=["Tag"])
|
||||
def delete(
|
||||
subject: User,
|
||||
tag: Tag,
|
||||
tag_svc: TagService
|
||||
):
|
||||
return tag_svc.delete(subject, tag)
|
||||
|
||||
@api.delete("", response_model=None, tags=["Tag"])
|
||||
def delete(
|
||||
subject: User,
|
||||
tag: Tag,
|
||||
tag_svc: TagService
|
||||
):
|
||||
tag_svc.delete(subject, tag)
|
|
@ -1,7 +1,7 @@
|
|||
""" Defines the table for storing resources """
|
||||
|
||||
# Import our mapped SQL types from SQLAlchemy
|
||||
from sqlalchemy import Integer, String, DateTime, Enum
|
||||
from sqlalchemy import ForeignKey, Integer, String, DateTime, Enum
|
||||
|
||||
# Import mapping capabilities from the SQLAlchemy ORM
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
@ -31,9 +31,7 @@ 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"
|
||||
)
|
||||
tags: Mapped[list["ResourceTagEntity"]] = relationship(back_populates="resource")
|
||||
|
||||
@classmethod
|
||||
def from_model(cls, model: Resource) -> Self:
|
||||
|
|
|
@ -23,12 +23,10 @@ class ResourceTagEntity(EntityBase):
|
|||
|
||||
# set fields or 'columns' for the user table
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
resourceId: Mapped[int] = mapped_column(ForeignKey("resource.id"))
|
||||
tagId: Mapped[int] = mapped_column(ForeignKey("tag.id"))
|
||||
|
||||
# relationships
|
||||
resource: Mapped["ResourceEntity"] = relationship(back_populates="resourceTags")
|
||||
tag: Mapped["TagEntity"] = relationship(back_populates="resourceTags")
|
||||
resource_id: Mapped[int] = mapped_column(ForeignKey("resource.id"), primary_key=True)
|
||||
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id", primary_key=True))
|
||||
resource: Mapped["ResourceEntity"] = mapped_column(backpopulates="tags")
|
||||
tag: Mapped["TagEntity"] = mapped_column(backpopulates="resource_tags")
|
||||
|
||||
# @classmethod
|
||||
# def from_model (cls, model: resource_tag_model) -> Self:
|
||||
|
|
|
@ -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,32 @@ 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(
|
||||
tags: 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)
|
||||
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)
|
||||
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,
|
||||
)
|
||||
|
|
|
@ -17,9 +17,7 @@ class ServiceTagEntity(EntityBase):
|
|||
|
||||
# set fields or 'columns' for the user table
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
serviceId: Mapped[int] = mapped_column(ForeignKey("service.id"))
|
||||
tagId: Mapped[int] = mapped_column(ForeignKey("tag.id"))
|
||||
|
||||
# relationships
|
||||
service: Mapped["ServiceEntity"] = relationship(back_populates="serviceTags")
|
||||
tag: Mapped["TagEntity"] = relationship(back_populates="serviceTags")
|
||||
resource_id: Mapped[int] = mapped_column(ForeignKey("service.id"), primary_key=True)
|
||||
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id", primary_key=True))
|
||||
service: Mapped["ServiceEntity"] = mapped_column(backpopulates="tags")
|
||||
tag: Mapped["TagEntity"] = mapped_column(backpopulates="service_tags")
|
||||
|
|
|
@ -16,21 +16,20 @@ 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")
|
||||
|
||||
|
||||
resource_tags: Mapped[list["ResourceTagEntity"]] = relationship(
|
||||
back_populates="tag"
|
||||
)
|
||||
service_tags: Mapped[list["ServiceTagEntity"]] = relationship(back_populates="tag")
|
||||
|
||||
@classmethod
|
||||
def from_model(cls, model: Tag) -> Self:
|
||||
|
@ -46,6 +45,7 @@ class TagEntity(EntityBase):
|
|||
return cls(
|
||||
id=model.id,
|
||||
content=model.id,
|
||||
created_at=model.created_at
|
||||
)
|
||||
|
||||
def to_model(self) -> Tag:
|
||||
|
@ -59,7 +59,5 @@ class TagEntity(EntityBase):
|
|||
return Tag(
|
||||
id=self.id,
|
||||
content=self.content,
|
||||
created_at=self.created_at
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,25 +14,22 @@ class ResourceService:
|
|||
def __init__(self, session: Session = Depends(db_session)):
|
||||
self._session = session
|
||||
|
||||
def get_resource_by_user(self, subject: User):
|
||||
def get_resource_by_user(self, subject: User) -> list[Resource]:
|
||||
"""Resource method getting all of the resources that a user has access to based on role"""
|
||||
if subject.role != UserTypeEnum.VOLUNTEER:
|
||||
query = select(ResourceEntity)
|
||||
entities = self._session.scalars(query).all()
|
||||
|
||||
return [resource.to_model() for resource in entities]
|
||||
else:
|
||||
programs = subject.program
|
||||
resources = []
|
||||
for program in programs:
|
||||
query = select(ResourceEntity).filter(ResourceEntity.program == program)
|
||||
entities = self._session.scalars(query).all()
|
||||
entities = self._session.query(ResourceEntity).where(ResourceEntity.program == program).all()
|
||||
for entity in entities:
|
||||
resources.append(entity)
|
||||
resources.append(entity.to_model())
|
||||
return [resource for resource in resources]
|
||||
|
||||
return [resource.to_model() for resource in resources]
|
||||
|
||||
def create(self, user: User, resource: Resource) -> Resource:
|
||||
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.
|
||||
|
||||
|
@ -43,7 +40,8 @@ class ResourceService:
|
|||
Returns:
|
||||
Resource: Object added to table
|
||||
"""
|
||||
if resource.role != user.role or resource.group != user.group:
|
||||
# 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."
|
||||
)
|
||||
|
@ -83,7 +81,7 @@ class ResourceService:
|
|||
|
||||
return resource.to_model()
|
||||
|
||||
def update(self, user: User, resource: ResourceEntity) -> Resource:
|
||||
def update(self, subject: User, resource: Resource) -> Resource:
|
||||
"""
|
||||
Update the resource if the user has access
|
||||
|
||||
|
@ -97,24 +95,28 @@ class ResourceService:
|
|||
Raises:
|
||||
ResourceNotFoundException: If no resource is found with the corresponding ID
|
||||
"""
|
||||
if resource.role != user.role or resource.group != user.group:
|
||||
if resource.role != subject.role or resource.group != subject.group:
|
||||
raise PermissionError(
|
||||
"User does not have permission to update this resource."
|
||||
)
|
||||
|
||||
obj = self._session.get(ResourceEntity, resource.id) if resource.id else None
|
||||
query = select(ResourceEntity).where(ResourceEntity.id == resource.id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
|
||||
if obj is None:
|
||||
if entity is None:
|
||||
raise ResourceNotFoundException(
|
||||
f"No resource found with matching id: {resource.id}"
|
||||
)
|
||||
|
||||
obj.update_from_model(resource) # Assuming an update method exists
|
||||
entity.name = resource.name
|
||||
entity.summary = resource.summary
|
||||
entity.link = resource.link
|
||||
entity.program = resource.program
|
||||
self._session.commit()
|
||||
|
||||
return obj.to_model()
|
||||
return entity.to_model()
|
||||
|
||||
def delete(self, user: User, id: int) -> None:
|
||||
def delete(self, subject: User, resource: Resource) -> None:
|
||||
"""
|
||||
Delete resource based on id that the user has access to
|
||||
|
||||
|
@ -125,20 +127,13 @@ class ResourceService:
|
|||
Raises:
|
||||
ResourceNotFoundException: If no resource is found with the corresponding id
|
||||
"""
|
||||
resource = (
|
||||
self._session.query(ResourceEntity)
|
||||
.filter(
|
||||
ResourceEntity.id == id,
|
||||
ResourceEntity.role == user.role,
|
||||
ResourceEntity.group == user.group,
|
||||
)
|
||||
.one_or_none()
|
||||
)
|
||||
query = select(ResourceEntity).where(ResourceEntity.id == resource.id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
|
||||
if resource is None:
|
||||
raise ResourceNotFoundException(f"No resource found with matching id: {id}")
|
||||
if entity is None:
|
||||
raise ResourceNotFoundException(f"No resource found with matching id: {resource.id}")
|
||||
|
||||
self._session.delete(resource)
|
||||
self._session.delete(entity)
|
||||
self._session.commit()
|
||||
|
||||
def get_by_slug(self, user: User, search_string: str) -> list[Resource]:
|
||||
|
|
|
@ -19,6 +19,21 @@ class ServiceService:
|
|||
def __init__(self, session: Session = Depends(db_session)):
|
||||
self._session = session
|
||||
|
||||
def get_service_by_user(self, subject: User) -> list[Service]:
|
||||
"""Resource method getting all of the resources that a user has access to based on role"""
|
||||
if subject.role != UserTypeEnum.VOLUNTEER:
|
||||
query = select(ServiceEntity)
|
||||
entities = self._session.scalars(query).all()
|
||||
return [service.to_model() for service in entities]
|
||||
else:
|
||||
programs = subject.program
|
||||
resources = []
|
||||
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]
|
||||
|
||||
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)
|
||||
|
@ -46,36 +61,6 @@ class ServiceService:
|
|||
|
||||
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"""
|
||||
if subject.role != UserTypeEnum.VOLUNTEER:
|
||||
query = select(ServiceEntity)
|
||||
entities = self._session.scalars(query).all()
|
||||
|
||||
return [service.to_model() for service in entities]
|
||||
else:
|
||||
programs = subject.program
|
||||
services = []
|
||||
for program in programs:
|
||||
query = select(ServiceEntity).filter(ServiceEntity.program == program)
|
||||
entities = self._session.scalars(query).all()
|
||||
for entity in entities:
|
||||
services.append(entity)
|
||||
|
||||
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.VOLUNTEER:
|
||||
raise ProgramNotAssignedException(
|
||||
f"User is not {UserTypeEnum.ADMIN} or {UserTypeEnum.VOLUNTEER}, 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:
|
||||
|
@ -95,33 +80,35 @@ class ServiceService:
|
|||
f"User is not {UserTypeEnum.ADMIN}, cannot update service"
|
||||
)
|
||||
|
||||
service_entity = self._session.get(ServiceEntity, service.id)
|
||||
query = select(ServiceEntity).where(ServiceEntity.id == service.id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
|
||||
if service_entity is None:
|
||||
if 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
|
||||
|
||||
entity.name = service.name
|
||||
entity.status = service.status
|
||||
entity.summary = service.summary
|
||||
entity.requirements = service.requirements
|
||||
entity.program = service.program
|
||||
self._session.commit()
|
||||
|
||||
return service_entity.to_model()
|
||||
return 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:
|
||||
query = select(ServiceEntity).where(ServiceEntity.id == service.id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
|
||||
if entity is None:
|
||||
raise ServiceNotFoundException(
|
||||
"The service you are searching for does not exist."
|
||||
)
|
||||
|
||||
self._session.delete(service_entity)
|
||||
self._session.delete(entity)
|
||||
self._session.commit()
|
||||
|
|
|
@ -1,20 +1,52 @@
|
|||
from fastapi import Depends
|
||||
|
||||
from backend.models.enum_for_models import UserTypeEnum
|
||||
from backend.models.user_model import User
|
||||
from backend.services.exceptions import TagNotFoundException
|
||||
from ..database import db_session
|
||||
from sqlalchemy.orm import Session
|
||||
from ..models.tag_model import Tag
|
||||
from ..entities.tag_entity import TagEntity
|
||||
from sqlalchemy import select
|
||||
|
||||
|
||||
# Add in checks for user permission?
|
||||
class TagService:
|
||||
|
||||
def __init__(self, session: Session = Depends(db_session)):
|
||||
self._session = session
|
||||
|
||||
def all(self) -> list[Tag]:
|
||||
def get_all(self) -> list[Tag]:
|
||||
"""Returns a list of all Tags"""
|
||||
|
||||
query = select(TagEntity)
|
||||
entities = self._session.scalars(query).all()
|
||||
|
||||
return [entity.to_model() for entity in entities]
|
||||
|
||||
def create(self, subject: User, tag: Tag) -> Tag:
|
||||
entity = TagEntity.from_model(tag)
|
||||
self._session.add(entity)
|
||||
self._session.commit()
|
||||
return entity.to_model()
|
||||
|
||||
def update(self, subject: User, tag: Tag) -> Tag:
|
||||
query = select(TagEntity).where(TagEntity.id == tag.id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
|
||||
if entity is None:
|
||||
raise TagNotFoundException(f"Tag with id {tag.id} does not exist")
|
||||
|
||||
entity.content = tag.content
|
||||
self._session.commit()
|
||||
return entity.to_model()
|
||||
|
||||
|
||||
def delete(self, subject: User, tag: Tag) -> None:
|
||||
query = select(TagEntity).where(TagEntity.id == tag.id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
|
||||
if entity is None:
|
||||
raise TagNotFoundException(f"Tag with id {tag.id} does not exist")
|
||||
|
||||
self._session.delete(entity)
|
||||
self._session.commit()
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user