Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Add Patient base model

Revision ID: 1cabfca3d8c8
Revises: 1a31ce608336
Create Date: 2025-03-02 16:54:50.053566

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes


# revision identifiers, used by Alembic.
revision = '1cabfca3d8c8'
down_revision = '1a31ce608336'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('patient',
sa.Column('full_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False),
sa.Column('description', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
sa.Column('email', sqlmodel.sql.sqltypes.AutoString(length=55), nullable=False),
sa.Column('phone_number', sqlmodel.sql.sqltypes.AutoString(length=20), nullable=False),
sa.Column('height', sa.Float(), nullable=False),
sa.Column('weight', sa.Float(), nullable=False),
sa.Column('gender', sa.Integer(), nullable=False),
sa.Column('birth_date', sa.TIMESTAMP(timezone=True), nullable=False),
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('owner_id', sa.Uuid(), nullable=False),
sa.Column('created_datetime', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
sa.ForeignKeyConstraint(['owner_id'], ['user.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('patient')
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Add menu_b class Menu base model

Revision ID: 32ba675b8ec6
Revises: 1cabfca3d8c8
Create Date: 2025-03-05 08:58:47.583292

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes


# revision identifiers, used by Alembic.
revision = '32ba675b8ec6'
down_revision = '1cabfca3d8c8'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('menu',
sa.Column('description', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
sa.Column('data', sa.JSON(), nullable=True),
sa.Column('current', sa.Boolean(), nullable=False),
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('title', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False),
sa.Column('created_datetime', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
sa.Column('owner_id', sa.Uuid(), nullable=False),
sa.ForeignKeyConstraint(['owner_id'], ['patient.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('menu')
# ### end Alembic commands ###
51 changes: 48 additions & 3 deletions backend/app/api/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from app.core import security
from app.core.config import settings
from app.core.db import engine
from app.models import TokenPayload, User
from app.models import TokenPayload, User, Patient, Menu

reusable_oauth2 = OAuth2PasswordBearer(
tokenUrl=f"{settings.API_V1_STR}/login/access-token"
Expand All @@ -25,8 +25,6 @@ def get_db() -> Generator[Session, None, None]:

SessionDep = Annotated[Session, Depends(get_db)]
TokenDep = Annotated[str, Depends(reusable_oauth2)]


def get_current_user(session: SessionDep, token: TokenDep) -> User:
try:
payload = jwt.decode(
Expand Down Expand Up @@ -55,3 +53,50 @@ def get_current_active_superuser(current_user: CurrentUser) -> User:
status_code=403, detail="The user doesn't have enough privileges"
)
return current_user



def get_current_patient(session: SessionDep, token: TokenDep) -> User:
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
)
token_data = TokenPayload(**payload)
except (InvalidTokenError, ValidationError):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Could not validate credentials",
)
user = session.get(User, token_data.sub)
if not user:
raise HTTPException(status_code=404, detail="User not found")
if not user.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
return user

CurrentPatient = Annotated[Menu, Depends(get_current_menu)]

def get_current_menu(session: SessionDep, token: TokenDep) -> Menu:
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
)
token_data = TokenPayload(**payload)
except (InvalidTokenError, ValidationError):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Could not validate credentials",
)
patient = session.get(Menu, token_data.sub)
if not patient:
raise HTTPException(status_code=404, detail="User not found")
if not patient.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
return patient


CurrentMenu = Annotated[Menu, Depends(get_current_menu)]




109 changes: 109 additions & 0 deletions backend/app/api/routes/patient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import uuid
from typing import Any

from fastapi import APIRouter, HTTPException
from sqlmodel import func, select

from app.api.deps import CurrentPatient, SessionDep
from app.models import Patient, PatientCreate, PatientPublic, PatientsPublic, PatientUpdate

router = APIRouter(prefix="/items", tags=["items"])


@router.get("/", response_model=PatientsPublic)
def read_items(
session: SessionDep, current_patient: CurrentPatient, skip: int = 0, limit: int = 100
) -> Any:
"""
Retrieve items.
"""

if current_patient.is_superuser:
count_statement = select(func.count()).select_from(Patient)
count = session.exec(count_statement).one()
statement = select(Patient).offset(skip).limit(limit)
patient = session.exec(statement).all()
else:
count_statement = (
select(func.count())
.select_from(patient)
.where(patient.owner_id == current_patient.id)
)
count = session.exec(count_statement).one()
statement = (
select(patient)
.where(patient.owner_id == current_patient.id)
.offset(skip)
.limit(limit)
)
items = session.exec(statement).all()

return ItemsPublic(data=items, count=count)


@router.get("/{id}", response_model=ItemPublic)
def read_item(session: SessionDep, current_user: CurrentUser, id: uuid.UUID) -> Any:
"""
Get item by ID.
"""
item = session.get(Item, id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
if not current_user.is_superuser and (item.owner_id != current_user.id):
raise HTTPException(status_code=400, detail="Not enough permissions")
return item


@router.post("/", response_model=ItemPublic)
def create_item(
*, session: SessionDep, current_user: CurrentUser, item_in: ItemCreate
) -> Any:
"""
Create new item.
"""
item = Item.model_validate(item_in, update={"owner_id": current_user.id})
session.add(item)
session.commit()
session.refresh(item)
return item


@router.put("/{id}", response_model=ItemPublic)
def update_item(
*,
session: SessionDep,
current_user: CurrentUser,
id: uuid.UUID,
item_in: ItemUpdate,
) -> Any:
"""
Update an item.
"""
item = session.get(Item, id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
if not current_user.is_superuser and (item.owner_id != current_user.id):
raise HTTPException(status_code=400, detail="Not enough permissions")
update_dict = item_in.model_dump(exclude_unset=True)
item.sqlmodel_update(update_dict)
session.add(item)
session.commit()
session.refresh(item)
return item


@router.delete("/{id}")
def delete_item(
session: SessionDep, current_user: CurrentUser, id: uuid.UUID
) -> Message:
"""
Delete an item.
"""
item = session.get(Item, id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
if not current_user.is_superuser and (item.owner_id != current_user.id):
raise HTTPException(status_code=400, detail="Not enough permissions")
session.delete(item)
session.commit()
return Message(message="Item deleted successfully")
66 changes: 65 additions & 1 deletion backend/app/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from sqlmodel import Session, select

from app.core.security import get_password_hash, verify_password
from app.models import Item, ItemCreate, User, UserCreate, UserUpdate
from app.models import Item, ItemCreate, User, UserCreate, UserUpdate, Patient, PatientCreate, MenuCreate, MenuUpdate, Menu


def create_user(*, session: Session, user_create: UserCreate) -> User:
Expand Down Expand Up @@ -52,3 +52,67 @@ def create_item(*, session: Session, item_in: ItemCreate, owner_id: uuid.UUID) -
session.commit()
session.refresh(db_item)
return db_item




def create_patient(*, session: Session,patient_in: PatientCreate, owner_id: uuid.UUID) -> Patient:
db_obj = Patient.model_validate(patient_in, update={"owner_id": owner_id})

session.add(db_obj)
session.commit()
session.refresh(db_obj)
return db_obj

def update_patient_password(*, session: Session,db_patient: Patient, user_in: UserUpdate) -> Any:
patient_data = user_in.model_dump(exclude_unset=True)
extra_data = {}
if "password" in patient_data:
password = patient_data["password"]
hashed_password = get_password_hash(password)
extra_data["hashed_password"] = hashed_password
db_patient.sqlmodel_update(patient_data, update=extra_data)
session.add(db_patient)
session.commit()
session.refresh(db_patient)
return db_patient




def update_patient_info(*, session: Session,db_patient: Patient, patient_in: UserUpdate) -> Any:
patient_data = patient_in.model_dump(exclude_unset=True)
extra_data = {}
if "password" in patient_data:
password = patient_data["password"]
hashed_password = get_password_hash(password)
extra_data["hashed_password"] = hashed_password
db_patient.sqlmodel_update(patient_data, update=extra_data)
session.add(db_patient)
session.commit()
session.refresh(db_patient)
return db_patient



def get_patient_by_email(*, session: Session, email: str) -> User | None:
statement = select(Patient).where(Patient.email == email)
session_patient = session.exec(statement).first()
return session_patient

def create_menu(*, session: Session,menu_create: MenuCreate) -> Menu:
db_obj = Menu.model_validate(
menu_create
)
session.add(db_obj)
session.commit()
session.refresh(db_obj)
return db_obj








Loading
Loading