Skip to content
Merged
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 app/admin/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from app.auth import validate_jwt

router = APIRouter(
prefix="/api",
prefix="/admin",
tags=["Admin"],
)

Expand Down
39 changes: 23 additions & 16 deletions app/applicants/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sqlalchemy import Column, Date, Integer, String
from sqlalchemy import Column, Date, DateTime, Integer, String, Text, func
from sqlalchemy.orm import relationship

from app.db import Base
Expand All @@ -8,20 +8,27 @@ class DBApplicant(Base):
__tablename__ = "applicants"

id = Column(Integer, primary_key=True, index=True)
first_name = Column(String, nullable=False)
last_name = Column(String, nullable=False)
middle_name = Column(String, nullable=True)
gender = Column(String, nullable=False)
first_name = Column(String(50), index=True, nullable=False)
last_name = Column(String(50), index=True, nullable=False)
middle_name = Column(String(50), nullable=True)
gender = Column(String(20), nullable=False)
date_of_birth = Column(Date, nullable=False)
ssn = Column(String, nullable=False, unique=True)
email = Column(String, nullable=True)
home_phone = Column(String, nullable=True)
mobile_phone = Column(String, nullable=True)
address = Column(String, nullable=True)
city = Column(String, nullable=True)
state = Column(String, nullable=True)
zip = Column(String, nullable=True)
country = Column(String, nullable=False)
created_at = Column(Date, nullable=False)
updated_at = Column(Date, nullable=False)
ssn = Column(String(11), nullable=False, unique=True)
email = Column(String(254), nullable=True)
home_phone = Column(String(20), nullable=True)
mobile_phone = Column(String(20), nullable=True)
address = Column(Text, nullable=True)
city = Column(String(100), nullable=True)
state = Column(String(50), nullable=True)
zip = Column(String(10), nullable=True)
country = Column(String(100), nullable=False)
created_at = Column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)
updated_at = Column(
DateTime(timezone=True),
server_default=func.now(),
onupdate=func.now(),
nullable=False,
)
case = relationship("DBCase", back_populates="applicant")
47 changes: 25 additions & 22 deletions app/applicants/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
from starlette import status

import app.applicants.services as service
from app.applicants.schemas import Applicant, ApplicantBase, ApplicantPayload
from app.applicants.schemas import (
ApplicantCreate,
ApplicantListResponse,
ApplicantResponse,
ApplicantUpdate,
)
from app.db import get_db

router = APIRouter(
prefix="/api",
prefix="/applicants",
tags=["Applicants"],
responses={404: {"description": "Endpoint not found"}},
)
Expand All @@ -18,36 +23,34 @@
db_session = Annotated[Session, Depends(get_db)]


@router.get(
"/applicants", status_code=status.HTTP_200_OK, response_model=ApplicantPayload
)
@router.get("/", status_code=status.HTTP_200_OK, response_model=ApplicantListResponse)
async def get_applicants(db: db_session, page_number: int = 0, page_size: int = 100):
return service.get_items(db, page_number, page_size)


@router.get(
"/applicants/{id}", status_code=status.HTTP_200_OK, response_model=Applicant
)
async def get_applicant(id: int, db: db_session):
return service.get_item(db, id)
@router.post("/", status_code=status.HTTP_201_CREATED, response_model=ApplicantResponse)
async def create_applicant(applicant: ApplicantCreate, db: db_session):
db_applicant = service.create_item(db, applicant)
return db_applicant


@router.put(
"/applicants/{id}", status_code=status.HTTP_200_OK, response_model=Applicant
@router.get(
"/{applicant_id}", status_code=status.HTTP_200_OK, response_model=ApplicantResponse
)
async def update_applicant(id: int, applicant: ApplicantBase, db: db_session):
db_applicant = service.update_item(db, id, applicant)
return db_applicant
async def get_applicant(applicant_id: int, db: db_session):
return service.get_item(db, applicant_id)


@router.post(
"/applicants", status_code=status.HTTP_201_CREATED, response_model=Applicant
@router.put(
"/{applicant_id}", status_code=status.HTTP_200_OK, response_model=ApplicantResponse
)
async def create_applicant(applicant: ApplicantBase, db: db_session):
db_applicant = service.create_item(db, applicant)
async def update_applicant(
applicant_id: int, applicant: ApplicantUpdate, db: db_session
):
db_applicant = service.update_item(db, applicant_id, applicant)
return db_applicant


@router.delete("/applicants/{id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_applicant(id: int, db: db_session):
service.delete_item(db, id)
@router.delete("/{applicant_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_applicant(applicant_id: int, db: db_session):
service.delete_item(db, applicant_id)
43 changes: 32 additions & 11 deletions app/applicants/schemas.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,56 @@
from datetime import date, datetime

from pydantic import BaseModel, ConfigDict
from pydantic import BaseModel, ConfigDict, Field


# Pydantic Models
class ApplicantBase(BaseModel):
first_name: str
last_name: str
middle_name: str | None = None
gender: str
first_name: str = Field(..., min_length=1, max_length=50)
last_name: str = Field(..., min_length=1, max_length=50)
middle_name: str | None = Field(None, min_length=1, max_length=50)
gender: str = Field(..., min_length=1, max_length=20)
date_of_birth: date
ssn: str
ssn: str = Field(..., min_length=9, max_length=11)
email: str | None = Field(None, max_length=254)
home_phone: str | None = Field(None, max_length=20)
mobile_phone: str | None = Field(None, max_length=20)
address: str | None = Field(None, max_length=200)
city: str | None = Field(None, max_length=100)
state: str | None = Field(None, max_length=50)
zip: str | None = Field(None, max_length=10)
country: str = Field("USA", max_length=100)


class ApplicantCreate(ApplicantBase):
pass


class ApplicantUpdate(BaseModel):
first_name: str | None = None
last_name: str | None = None
middle_name: str | None = None
gender: str | None = None
date_of_birth: date | None = None
ssn: str | None = None
email: str | None = None
home_phone: str | None = None
mobile_phone: str | None = None
address: str | None = None
city: str | None = None
state: str | None = None
zip: str | None = None
country: str = "USA"
country: str | None = None


class Applicant(ApplicantBase):
class ApplicantResponse(ApplicantBase):
model_config = ConfigDict(from_attributes=True)
id: int | None = None
id: int
created_at: datetime
updated_at: datetime


class ApplicantPayload(BaseModel):
items: list[Applicant]
class ApplicantListResponse(BaseModel):
items: list[ApplicantResponse]
item_count: int = 0
page_count: int = 0
prev_page: int | None = None
Expand Down
52 changes: 20 additions & 32 deletions app/applicants/services.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from datetime import datetime

from fastapi import HTTPException
from sqlalchemy.orm import Session

from app.applicants.models import DBApplicant
from app.applicants.schemas import ApplicantBase
from app.applicants.schemas import ApplicantCreate, ApplicantUpdate
from app.utils import get_next_page, get_page_count, get_prev_page


Expand All @@ -21,42 +19,30 @@ def get_items(db: Session, page_number: int, page_size: int):
}


def create_item(db: Session, applicant: ApplicantCreate):
db_applicant = DBApplicant(**applicant.model_dump())
db.add(db_applicant)
db.commit()
db.refresh(db_applicant)

return db_applicant


def get_item(db: Session, applicant_id: int):
return db.query(DBApplicant).where(DBApplicant.id == applicant_id).first()


def update_item(db: Session, id: int, applicant: ApplicantBase):
def update_item(db: Session, id: int, applicant: ApplicantUpdate):
db_applicant = db.query(DBApplicant).filter(DBApplicant.id == id).first()
if db_applicant is None:
raise HTTPException(status_code=404, detail="Applicant not founds")

db_applicant.first_name = applicant.first_name
db_applicant.last_name = applicant.last_name
db_applicant.middle_name = applicant.middle_name
db_applicant.gender = applicant.gender
db_applicant.date_of_birth = applicant.date_of_birth
db_applicant.ssn = applicant.ssn
db_applicant.email = applicant.email
db_applicant.home_phone = applicant.home_phone
db_applicant.mobile_phone = applicant.mobile_phone
db_applicant.address = applicant.address
db_applicant.city = applicant.city
db_applicant.state = applicant.state
db_applicant.zip = applicant.zip
db_applicant.country = applicant.country
db_applicant.date_of_birth = applicant.date_of_birth
db_applicant.updated_at = datetime.now()
db.add(db_applicant)
db.commit()
db.refresh(db_applicant)

return db_applicant
raise HTTPException(status_code=404, detail="Applicant not found")

# Only update fields that are provided (not None)
update_data = applicant.model_dump(exclude_unset=True)
for field, value in update_data.items():
if value is not None:
setattr(db_applicant, field, value)

def create_item(db: Session, applicant: ApplicantBase):
db_applicant = DBApplicant(**applicant.model_dump())
db_applicant.created_at = datetime.now()
db_applicant.updated_at = datetime.now()
db.add(db_applicant)
db.commit()
db.refresh(db_applicant)
Expand All @@ -67,7 +53,9 @@ def create_item(db: Session, applicant: ApplicantBase):
def delete_item(db: Session, id: int):
db_applicant = db.query(DBApplicant).filter(DBApplicant.id == id).first()
if db_applicant is None:
raise HTTPException(status_code=404, detail="Applicant not founds")
raise HTTPException(status_code=404, detail="Applicant not found")

db.query(DBApplicant).filter(DBApplicant.id == id).delete()
db.commit()

return None
17 changes: 12 additions & 5 deletions app/cases/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sqlalchemy import Column, Date, ForeignKey, Integer, String
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, func
from sqlalchemy.orm import relationship

from app.db import Base
Expand All @@ -9,10 +9,17 @@ class DBCase(Base):
__tablename__ = "cases"

id = Column(Integer, primary_key=True, index=True)
status = Column(String, nullable=False)
assigned_to = Column(String, nullable=True)
created_at = Column(Date, nullable=False)
updated_at = Column(Date, nullable=False)
status = Column(String(50), nullable=False)
assigned_to = Column(String(255), nullable=True)
created_at = Column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)
updated_at = Column(
DateTime(timezone=True),
server_default=func.now(),
onupdate=func.now(),
nullable=False,
)
applicant_id = Column(
Integer, ForeignKey("applicants.id", ondelete="CASCADE"), nullable=False
)
Expand Down
42 changes: 24 additions & 18 deletions app/cases/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
from starlette import status

import app.cases.services as service
from app.cases.schemas import Case, CaseBase, CasePayload, CaseWithApplicant
from app.cases.schemas import (
CaseCreate,
CaseListResponse,
CaseResponse,
CaseUpdate,
CaseWithApplicant,
)
from app.db import get_db

router = APIRouter(
prefix="/api",
prefix="/cases",
tags=["Cases"],
responses={404: {"description": "Endpoint not found"}},
)
Expand All @@ -18,30 +24,30 @@
db_session = Annotated[Session, Depends(get_db)]


@router.get("/cases", status_code=status.HTTP_200_OK, response_model=CasePayload)
@router.get("/", status_code=status.HTTP_200_OK, response_model=CaseListResponse)
async def get_cases(db: db_session, page_number: int = 0, page_size: int = 100):
return service.get_items(db, page_number, page_size)


@router.get(
"/cases/{id}", status_code=status.HTTP_200_OK, response_model=CaseWithApplicant
)
async def get_case(id: int, db: db_session):
return service.get_item(db, id)
@router.post("/", status_code=status.HTTP_201_CREATED, response_model=CaseResponse)
async def create_case(case: CaseCreate, db: db_session):
db_case = service.create_item(db, case)
return db_case


@router.put("/cases/{id}", status_code=status.HTTP_200_OK, response_model=Case)
async def update_case(id: int, case: CaseBase, db: db_session):
db_case = service.update_item(db, id, case)
return db_case
@router.get(
"/{case_id}", status_code=status.HTTP_200_OK, response_model=CaseWithApplicant
)
async def get_case(case_id: int, db: db_session):
return service.get_item(db, case_id)


@router.post("/cases", status_code=status.HTTP_201_CREATED, response_model=Case)
async def create_case(case: CaseBase, db: db_session):
db_case = service.create_item(db, case)
@router.put("/{case_id}", status_code=status.HTTP_200_OK, response_model=CaseResponse)
async def update_case(case_id: int, case: CaseUpdate, db: db_session):
db_case = service.update_item(db, case_id, case)
return db_case


@router.delete("/cases/{id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_case(id: int, db: db_session):
service.delete_item(db, id)
@router.delete("/{case_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_case(case_id: int, db: db_session):
service.delete_item(db, case_id)
Loading