Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ RUN mkdir -p /etc/apt/keyrings \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install nodejs -y \
&& npm install -g npm@latest \
&& npm install -g npm@10.8.2 \
&& rm -rf /var/lib/apt/lists/*

# Use a non-root user per https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ NEXT_PUBLIC_HOST=http://localhost:3000
Open a new terminal and run this script in sequence to setup the dependencies and database

```
chmod +x ./start.sh
./start.sh
```

Expand Down
29 changes: 22 additions & 7 deletions backend/api/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,53 @@
# TODO: Create custom exceptions
@api.post("", response_model=Resource, tags=["Resource"])
def create(
uuid: str, resource: Resource, user_svc: UserService = Depends(), 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(
uuid: str, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends()
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()
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(
uuid: str, resource: Resource, user_svc: UserService = Depends(), 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"])
@api.delete("", response_model=dict, tags=["Resource"])
def delete(
uuid: str, resource: Resource, user_svc: UserService = Depends(), resource_svc: ResourceService = Depends()
uuid: str,
id: int,
user_svc: UserService = Depends(),
resource_svc: ResourceService = Depends(),
):
subject = user_svc.get_user_by_uuid(uuid)
resource_svc.delete(subject, resource)
return resource_svc.delete(subject, id)
31 changes: 24 additions & 7 deletions backend/api/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,53 @@
# TODO: Create custom exceptions
@api.post("", response_model=Service, tags=["Service"])
def create(
uuid: str, service: Service, user_svc: UserService = Depends(), 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(
uuid: str, user_svc: UserService = Depends(), 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()
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(
uuid: str, service: Service, user_svc: UserService = Depends(), 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"])

@api.delete("", response_model=dict, tags=["Service"])
def delete(
uuid: str, service: Service, user_svc: UserService = Depends(), service_svc: ServiceService = Depends()
uuid: str,
id: int,
user_svc: UserService = Depends(),
service_svc: ServiceService = Depends(),
):
subject = user_svc.get_user_by_uuid(uuid)
service_svc.delete(subject, service)
return service_svc.delete(subject, id)
41 changes: 35 additions & 6 deletions backend/api/user.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, HTTPException
from ..services import UserService
from ..models.user_model import User, UserTypeEnum

Expand All @@ -16,15 +16,44 @@
# TODO: Enable authorization by passing user uuid to API
# TODO: Create custom exceptions
@api.get("/all", response_model=List[User], tags=["Users"])
def get_all(user_id: str, user_svc: UserService = Depends()):
subject = user_svc.get_user_by_uuid(user_id)
def get_all(uuid: str, user_svc: UserService = Depends()):
subject = user_svc.get_user_by_uuid(uuid)

if subject.role != UserTypeEnum.ADMIN:
raise Exception(f"Insufficient permissions for user {subject.uuid}")

return user_svc.all()


@api.get("/{user_id}", response_model=User, tags=["Users"])
def get_by_uuid(user_id: str, user_svc: UserService = Depends()):
return user_svc.get_user_by_uuid(user_id)
@api.get("/{uuid}", response_model=User, tags=["Users"])
def get_by_uuid(uuid: str, user_svc: UserService = Depends()):
return user_svc.get_user_by_uuid(uuid)


@api.post("/", response_model=User, tags=["Users"])
def create_user(uuid: str, user: User, user_svc: UserService = Depends()):
subject = user_svc.get_user_by_uuid(uuid)
if subject.role != UserTypeEnum.ADMIN:
raise Exception(f"Insufficient permissions for user {subject.uuid}")

return user_svc.create(user)


@api.put("/", response_model=User, tags=["Users"])
def update_user(uuid: str, user: User, user_svc: UserService = Depends()):
subject = user_svc.get_user_by_uuid(uuid)
if subject.role != UserTypeEnum.ADMIN:
raise Exception(f"Insufficient permissions for user {subject.uuid}")

return user_svc.update(user)


@api.delete("/", response_model=dict, tags=["Users"])
def delete_user(uuid: str, id: int, user_svc: UserService = Depends()):
subject = user_svc.get_user_by_uuid(uuid)

try:
user_svc.delete_by_id(id, subject)
return {"message": "User deleted successfully"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
4 changes: 2 additions & 2 deletions backend/entities/user_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ class UserEntity(EntityBase):
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))
experience: Mapped[int] = mapped_column(Integer, nullable=True)
group: Mapped[str] = mapped_column(String(50), nullable=True)
uuid: Mapped[str] = mapped_column(String, nullable=True)

@classmethod
Expand Down
8 changes: 4 additions & 4 deletions backend/models/user_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class User(BaseModel):
id: int | None = None
username: str = Field(..., description="The username of the user")
email: str = Field(..., description="The e-mail of the user")
experience: int = Field(..., description="Years of Experience of the User")
group: str
program: List[ProgramTypeEnum]
role: UserTypeEnum
experience: int | None = Field(None, description="Years of Experience of the User")
group: str | None = Field(None, description="The group of the user")
program: List[ProgramTypeEnum] | None = None
role: UserTypeEnum | None = None
created_at: Optional[datetime] = datetime.now()
uuid: str | None = None
21 changes: 11 additions & 10 deletions backend/services/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self, session: Session = Depends(db_session)):
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)
query = select(ResourceEntity).order_by(ResourceEntity.id)
entities = self._session.scalars(query).all()
return [resource.to_model() for resource in entities]
else:
Expand Down Expand Up @@ -86,14 +86,14 @@ def update(self, subject: User, resource: Resource) -> Resource:
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
entity.name = resource.name if resource.name else entity.name
entity.summary = resource.summary if resource.summary else entity.summary
entity.link = resource.link if resource.link else entity.link
entity.program = resource.program if resource.program else entity.program
self._session.commit()
return entity.to_model()

def delete(self, subject: User, resource: Resource) -> None:
def delete(self, subject: User, id: int) -> None:
"""
Delete resource based on id that the user has access to
Parameters:
Expand All @@ -106,15 +106,16 @@ def delete(self, subject: User, resource: Resource) -> None:
raise ProgramNotAssignedException(
f"User is not {UserTypeEnum.ADMIN}, cannot update service"
)
query = select(ResourceEntity).where(ResourceEntity.id == resource.id)

query = select(ResourceEntity).where(ResourceEntity.id == 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: {id}")
self._session.delete(entity)
self._session.commit()

return {"message": "Resource deleted successfully"}

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
Expand Down
38 changes: 23 additions & 15 deletions backend/services/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,33 @@ def __init__(self, session: Session = Depends(db_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)
query = select(ServiceEntity).order_by(ServiceEntity.id)
entities = self._session.scalars(query).all()
return [service.to_model() for service in entities]
else:
programs = subject.program
services = []
for program in programs:
entities = self._session.query(ServiceEntity).where(ServiceEntity.program == program).all()
entities = (
self._session.query(ServiceEntity)
.where(ServiceEntity.program == program)
.all()
)
for entity in entities:
services.append(entity.to_model())
return [service for service in services]

def get_service_by_name(self, name: str, subject: User) -> Service:
"""Service method getting services by id."""
query = select(ServiceEntity).where(
and_(
ServiceEntity.name == name, ServiceEntity.program.in_(subject.program)
)
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 name: {name} does not exist or program has not been assigned")
raise ServiceNotFoundException(
f"Service with name: {name} does not exist or program has not been assigned"
)

return entity.to_model()

Expand All @@ -66,7 +70,7 @@ def update(self, subject: User, service: Service) -> Service:
raise ProgramNotAssignedException(
f"User is not {UserTypeEnum.ADMIN}, cannot update service"
)

query = select(ServiceEntity).where(ServiceEntity.id == service.id)
entity = self._session.scalars(query).one_or_none()

Expand All @@ -75,21 +79,23 @@ def update(self, subject: User, service: Service) -> Service:
"The service you are searching for does not exist."
)

entity.name = service.name
entity.status = service.status
entity.summary = service.summary
entity.requirements = service.requirements
entity.program = service.program
entity.name = service.name if service.name else entity.name
entity.status = service.status if service.status else entity.status
entity.summary = service.summary if service.summary else entity.summary
entity.requirements = (
service.requirements if service.requirements else entity.requirements
)
entity.program = service.program if service.program else entity.program
self._session.commit()

return entity.to_model()

def delete(self, subject: User, service: Service) -> None:
def delete(self, subject: User, id: int) -> None:
"""Deletes a service from the table."""
if subject.role != UserTypeEnum.ADMIN:
raise ProgramNotAssignedException(f"User is not {UserTypeEnum.ADMIN}")
query = select(ServiceEntity).where(ServiceEntity.id == service.id)

query = select(ServiceEntity).where(ServiceEntity.id == id)
entity = self._session.scalars(query).one_or_none()

if entity is None:
Expand All @@ -99,3 +105,5 @@ def delete(self, subject: User, service: Service) -> None:

self._session.delete(entity)
self._session.commit()

return {"message": "Service deleted successfully"}
Loading