From ddd551adb4303983ee3d9a561442d7a1ae8d67b1 Mon Sep 17 00:00:00 2001 From: Andrei Duvakin Date: Tue, 18 Feb 2025 11:59:46 +0500 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20=D1=81?= =?UTF-8?q?=D0=BB=D0=BE=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=82=D0=B0=D0=B1?= =?UTF-8?q?=D0=BB=D0=B8=D1=86=D1=8B=20=D0=BB=D0=B8=D0=BD=D0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/application/lens_types_repository.py | 42 +++++++ api/app/application/lenses_repository.py | 5 + api/app/controllers/auth_router.py | 9 +- api/app/controllers/lenses_router.py | 69 +++++++++++ api/app/controllers/patients_router.py | 37 ++++-- ...ソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_3.py | 32 +++++ ...7a_ミエミセミアミーミイミクミサ_ムひーミアミサミクムムダム\ムミセミエミオムミカミーミスミクミオミシ_ミスミーミアミセムミー.py | 44 +++++++ ...ソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_1.py | 32 +++++ ...ソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_2.py | 42 +++++++ api/app/domain/entities/__init__.py | 3 - api/app/domain/entities/lens.py | 18 +++ api/app/domain/models/__init__.py | 3 +- api/app/domain/models/lens.py | 4 +- .../models/{lenses_types.py => lens_types.py} | 4 +- api/app/domain/models/set_contents.py | 23 ++++ api/app/domain/models/sets.py | 1 + api/app/infrastructure/auth_service.py | 3 +- api/app/infrastructure/dependencies.py | 11 +- api/app/infrastructure/lenses_service.py | 109 ++++++++++++++++++ api/app/infrastructure/patients_service.py | 5 +- 20 files changed, 464 insertions(+), 32 deletions(-) create mode 100644 api/app/application/lens_types_repository.py create mode 100644 api/app/controllers/lenses_router.py create mode 100644 api/app/database/migrations/versions/70eb3c307702_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_3.py create mode 100644 api/app/database/migrations/versions/7d74a745da7a_ミエミセミアミーミイミクミサ_ムひーミアミサミクムムダム\ムミセミエミオムミカミーミスミクミオミシ_ミスミーミアミセムミー.py create mode 100644 api/app/database/migrations/versions/7f50bd3f0523_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_1.py create mode 100644 api/app/database/migrations/versions/ee12ffac87d7_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_2.py create mode 100644 api/app/domain/entities/lens.py rename api/app/domain/models/{lenses_types.py => lens_types.py} (84%) create mode 100644 api/app/domain/models/set_contents.py create mode 100644 api/app/infrastructure/lenses_service.py diff --git a/api/app/application/lens_types_repository.py b/api/app/application/lens_types_repository.py new file mode 100644 index 0000000..e05715b --- /dev/null +++ b/api/app/application/lens_types_repository.py @@ -0,0 +1,42 @@ +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession + +from app.domain.models import LensType + + +class LensTypesRepository: + def __init__(self, db: AsyncSession): + self.db = db + + async def get_all(self): + stmt = select(LensType) + result = await self.db.execute(stmt) + return result.scalars().all() + + async def get_by_id(self, lens_type_id: int): + stmt = select(LensType).filter(LensType.id == lens_type_id) + result = await self.db.execute(stmt) + return result.scalars().first() + + async def create(self, lens_type: LensType): + self.db.add(lens_type) + await self.db.commit() + await self.db.refresh(lens_type) + return lens_type + + async def update(self, lens_type: LensType): + await self.db.merge(lens_type) + await self.db.commit() + return lens_type + + async def delete(self, lens_type_id: int): + stmt = select(LensType).filter(LensType.id == lens_type_id) + result = await self.db.execute(stmt) + lens_type = result.scalars().first() + + if lens_type: + await self.db.delete(lens_type) + await self.db.commit() + return lens_type + + return None \ No newline at end of file diff --git a/api/app/application/lenses_repository.py b/api/app/application/lenses_repository.py index fac8dca..1fe8b21 100644 --- a/api/app/application/lenses_repository.py +++ b/api/app/application/lenses_repository.py @@ -13,6 +13,11 @@ class LensesRepository: result = await self.db.execute(stmt) return result.scalars().all() + async def get_by_id(self, lens_id: int): + stmt = select(Lens).filter(Lens.id == lens_id) + result = await self.db.execute(stmt) + return result.scalars().first() + async def create(self, lens: Lens): self.db.add(lens) await self.db.commit() diff --git a/api/app/controllers/auth_router.py b/api/app/controllers/auth_router.py index 19c7e98..c4c2644 100644 --- a/api/app/controllers/auth_router.py +++ b/api/app/controllers/auth_router.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, HTTPException, Response +from fastapi import APIRouter, Depends, Response from sqlalchemy.ext.asyncio import AsyncSession from app.database.session import get_db @@ -22,15 +22,8 @@ async def auth_user( db: AsyncSession = Depends(get_db) ): auth_service = AuthService(db) - token = await auth_service.authenticate_user(user_data.login, user_data.password) - if token is None: - raise HTTPException( - status_code=401, - detail="Incorrect username or password" - ) - response.set_cookie( key="users_access_token", value=token["access_token"], diff --git a/api/app/controllers/lenses_router.py b/api/app/controllers/lenses_router.py new file mode 100644 index 0000000..5a26b67 --- /dev/null +++ b/api/app/controllers/lenses_router.py @@ -0,0 +1,69 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.ext.asyncio import AsyncSession + +from app.database.session import get_db +from app.domain.entities.lens import LensEntity +from app.infrastructure.dependencies import get_current_user +from app.infrastructure.lenses_service import LensesService + +router = APIRouter() + + +@router.get( + "/lenses/", + response_model=list[LensEntity], + summary="Get all lenses", + description="Returns a list of all lenses", +) +async def get_all_lenses( + db: AsyncSession = Depends(get_db), + user=Depends(get_current_user), +): + lenses_service = LensesService(db) + return await lenses_service.get_all_lenses() + + +@router.post( + "/lenses/", + response_model=LensEntity, + summary="Create lens", + description="Creates a new lens", +) +async def create_lens( + lens: LensEntity, + db: AsyncSession = Depends(get_db), + user=Depends(get_current_user), +): + lenses_service = LensesService(db) + return await lenses_service.create_lens(lens) + + +@router.put( + "/lenses/{lens_id}/", + response_model=LensEntity, + summary="Update lens", + description="Updates an existing lens", +) +async def update_lens( + lens_id: int, + lens: LensEntity, + db: AsyncSession = Depends(get_db), + user=Depends(get_current_user), +): + lenses_service = LensesService(db) + return await lenses_service.update_lens(lens_id, lens) + + +@router.delete( + "/lenses/{lens_id}/", + response_model=bool, + summary="Delete lens", + description="Deletes an existing lens", +) +async def delete_lens( + lens_id: int, + db: AsyncSession = Depends(get_db), + user=Depends(get_current_user), +): + lenses_service = LensesService(db) + return await lenses_service.delete_lens(lens_id) diff --git a/api/app/controllers/patients_router.py b/api/app/controllers/patients_router.py index 5345adc..161a597 100644 --- a/api/app/controllers/patients_router.py +++ b/api/app/controllers/patients_router.py @@ -9,40 +9,61 @@ from app.infrastructure.patients_service import PatientsService router = APIRouter() -@router.get("/patients/") +@router.get( + "/patients/", + response_model=list[PatientEntity], + summary="Get all patients", + description="Returns a list of all patients", +) async def get_all_patients( db: AsyncSession = Depends(get_db), - user=Depends(get_current_user) + user=Depends(get_current_user), ): patients_service = PatientsService(db) return await patients_service.get_all_patients() -@router.post("/patients/") +@router.post( + "/patients/", + response_model=PatientEntity, + summary="Create a new patient", + description="Creates a new patient", +) async def create_patient( patient: PatientEntity, db: AsyncSession = Depends(get_db), - user=Depends(get_current_user) + user=Depends(get_current_user), ): patients_service = PatientsService(db) return await patients_service.create_patient(patient) -@router.put("/patients/{patient_id}/") +@router.put( + "/patients/{patient_id}/", + response_model=PatientEntity, + summary="Update a patient", + description="Updates a patient", +) async def update_patient( patient_id: int, patient: PatientEntity, db: AsyncSession = Depends(get_db), - user=Depends(get_current_user) + user=Depends(get_current_user), ): patients_service = PatientsService(db) return await patients_service.update_patient(patient_id, patient) -@router.delete("/patients/{patient_id}/", response_model=bool) + +@router.delete( + "/patients/{patient_id}/", + response_model=bool, + summary="Delete a patient", + description="Deletes a patient", +) async def delete_patient( patient_id: int, db: AsyncSession = Depends(get_db), - user=Depends(get_current_user) + user=Depends(get_current_user), ): patient_service = PatientsService(db) return await patient_service.delete_patient(patient_id) diff --git a/api/app/database/migrations/versions/70eb3c307702_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_3.py b/api/app/database/migrations/versions/70eb3c307702_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_3.py new file mode 100644 index 0000000..35bbc2d --- /dev/null +++ b/api/app/database/migrations/versions/70eb3c307702_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_3.py @@ -0,0 +1,32 @@ +"""ミ渙オムミオミクミシミオミスミセミイミーミサ ムひーミアミサミクムム ム ムひクミソミーミシミク ミサミクミスミキ - ミィミーミウ 3 + +Revision ID: 70eb3c307702 +Revises: ee12ffac87d7 +Create Date: 2025-02-18 11:41:53.344762 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '70eb3c307702' +down_revision: Union[str, None] = 'ee12ffac87d7' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('lens', sa.Column('type_id', sa.Integer(), nullable=False)) + op.create_foreign_key(None, 'lens', 'lens_types', ['type_id'], ['id']) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'lens', type_='foreignkey') + op.drop_column('lens', 'type_id') + # ### end Alembic commands ### diff --git a/api/app/database/migrations/versions/7d74a745da7a_ミエミセミアミーミイミクミサ_ムひーミアミサミクムムダム\ムミセミエミオムミカミーミスミクミオミシ_ミスミーミアミセムミー.py b/api/app/database/migrations/versions/7d74a745da7a_ミエミセミアミーミイミクミサ_ムひーミアミサミクムムダム\ムミセミエミオムミカミーミスミクミオミシ_ミスミーミアミセムミー.py new file mode 100644 index 0000000..602182c --- /dev/null +++ b/api/app/database/migrations/versions/7d74a745da7a_ミエミセミアミーミイミクミサ_ムひーミアミサミクムムダム\ムミセミエミオムミカミーミスミクミオミシ_ミスミーミアミセムミー.py @@ -0,0 +1,44 @@ +"""ミ頒セミアミーミイミクミサ ムひーミアミサミクムム ム ムミセミエミオムミカミーミスミクミオミシ ミスミーミアミセムミー + +Revision ID: 7d74a745da7a +Revises: c0997c6bf2f1 +Create Date: 2025-02-18 11:28:51.401555 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '7d74a745da7a' +down_revision: Union[str, None] = 'c0997c6bf2f1' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('set_contents', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('tor', sa.Integer(), nullable=False), + sa.Column('trial', sa.Integer(), nullable=False), + sa.Column('esa', sa.Integer(), nullable=False), + sa.Column('fvc', sa.Integer(), nullable=False), + sa.Column('preset_refraction', sa.Integer(), nullable=False), + sa.Column('diameter', sa.Integer(), nullable=False), + sa.Column('periphery_toricity', sa.Integer(), nullable=False), + sa.Column('side', sa.Integer(), nullable=False), + sa.Column('count', sa.Integer(), nullable=False), + sa.Column('set_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['set_id'], ['sets.id'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('set_contents') + # ### end Alembic commands ### diff --git a/api/app/database/migrations/versions/7f50bd3f0523_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_1.py b/api/app/database/migrations/versions/7f50bd3f0523_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_1.py new file mode 100644 index 0000000..69b056a --- /dev/null +++ b/api/app/database/migrations/versions/7f50bd3f0523_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_1.py @@ -0,0 +1,32 @@ +"""ミ渙オムミオミクミシミオミスミセミイミーミサ ムひーミアミサミクムム ム ムひクミソミーミシミク ミサミクミスミキ - ミィミーミウ 1 + +Revision ID: 7f50bd3f0523 +Revises: 7d74a745da7a +Create Date: 2025-02-18 11:41:03.926914 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '7f50bd3f0523' +down_revision: Union[str, None] = '7d74a745da7a' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('lens_type_id_fkey', 'lens', type_='foreignkey') + op.drop_column('lens', 'type_id') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('lens', sa.Column('type_id', sa.INTEGER(), autoincrement=False, nullable=False)) + op.create_foreign_key('lens_type_id_fkey', 'lens', 'lenses_types', ['type_id'], ['id']) + # ### end Alembic commands ### diff --git a/api/app/database/migrations/versions/ee12ffac87d7_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_2.py b/api/app/database/migrations/versions/ee12ffac87d7_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_2.py new file mode 100644 index 0000000..824dce9 --- /dev/null +++ b/api/app/database/migrations/versions/ee12ffac87d7_ミソミオムミオミクミシミオミスミセミイミーミサ_ムひーミアミサミクムムダム\ムひクミソミーミシミク_ミサミクミスミキ_ム威ーミウ_2.py @@ -0,0 +1,42 @@ +"""ミ渙オムミオミクミシミオミスミセミイミーミサ ムひーミアミサミクムム ム ムひクミソミーミシミク ミサミクミスミキ - ミィミーミウ 2 + +Revision ID: ee12ffac87d7 +Revises: 7f50bd3f0523 +Create Date: 2025-02-18 11:41:15.961296 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'ee12ffac87d7' +down_revision: Union[str, None] = '7f50bd3f0523' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('lens_types', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('title', sa.VARCHAR(length=150), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('title') + ) + op.drop_table('lenses_types') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('lenses_types', + sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column('title', sa.VARCHAR(length=150), autoincrement=False, nullable=False), + sa.PrimaryKeyConstraint('id', name='lenses_types_pkey'), + sa.UniqueConstraint('title', name='lenses_types_title_key') + ) + op.drop_table('lens_types') + # ### end Alembic commands ### diff --git a/api/app/domain/entities/__init__.py b/api/app/domain/entities/__init__.py index 7c2377a..e69de29 100644 --- a/api/app/domain/entities/__init__.py +++ b/api/app/domain/entities/__init__.py @@ -1,3 +0,0 @@ -from sqlalchemy.ext.declarative import declarative_base - -Base = declarative_base() \ No newline at end of file diff --git a/api/app/domain/entities/lens.py b/api/app/domain/entities/lens.py new file mode 100644 index 0000000..778dadd --- /dev/null +++ b/api/app/domain/entities/lens.py @@ -0,0 +1,18 @@ +from typing import Optional + +from pydantic import BaseModel + + +class LensEntity(BaseModel): + id: Optional[int] = None + tor: float + trial: float + esa: float + fvc: float + preset_refraction: float + diameter: float + periphery_toricity: float + side: str + issued: bool + + type_id: int diff --git a/api/app/domain/models/__init__.py b/api/app/domain/models/__init__.py index 5771f05..33337d0 100644 --- a/api/app/domain/models/__init__.py +++ b/api/app/domain/models/__init__.py @@ -5,7 +5,7 @@ Base = declarative_base() from app.domain.models.appointment_files import AppointmentFile from app.domain.models.appointments import Appointment from app.domain.models.appointment_types import AppointmentType -from app.domain.models.lenses_types import LensesType +from app.domain.models.lens_types import LensType from app.domain.models.lens_issues import LensIssue from app.domain.models.lens import Lens from app.domain.models.mailing_delivery_methods import MailingDeliveryMethod @@ -14,6 +14,7 @@ from app.domain.models.mailing import Mailing from app.domain.models.patients import Patient from app.domain.models.recipients import Recipient from app.domain.models.roles import Role +from app.domain.models.set_contents import SetContent from app.domain.models.set_lens import SetLens from app.domain.models.sets import Set from app.domain.models.users import User diff --git a/api/app/domain/models/lens.py b/api/app/domain/models/lens.py index 4f62ad0..d6a40cb 100644 --- a/api/app/domain/models/lens.py +++ b/api/app/domain/models/lens.py @@ -24,9 +24,9 @@ class Lens(Base): side = Column(Enum(SideEnum), nullable=False) issued = Column(Boolean, nullable=False, default=False) - type_id = Column(Integer, ForeignKey('lenses_types.id'), nullable=False) + type_id = Column(Integer, ForeignKey('lens_types.id'), nullable=False) - type = relationship('LensesType', back_populates='lenses') + type = relationship('LensType', back_populates='lenses') set = relationship('SetLens', back_populates='lens') lens_issues = relationship('LensIssue', back_populates='lens') diff --git a/api/app/domain/models/lenses_types.py b/api/app/domain/models/lens_types.py similarity index 84% rename from api/app/domain/models/lenses_types.py rename to api/app/domain/models/lens_types.py index 0bd15b5..b581183 100644 --- a/api/app/domain/models/lenses_types.py +++ b/api/app/domain/models/lens_types.py @@ -4,8 +4,8 @@ from sqlalchemy.orm import relationship from app.domain.models import Base -class LensesType(Base): - __tablename__ = 'lenses_types' +class LensType(Base): + __tablename__ = 'lens_types' id = Column(Integer, primary_key=True, autoincrement=True) title = Column(VARCHAR(150), nullable=False, unique=True) diff --git a/api/app/domain/models/set_contents.py b/api/app/domain/models/set_contents.py new file mode 100644 index 0000000..e4b6483 --- /dev/null +++ b/api/app/domain/models/set_contents.py @@ -0,0 +1,23 @@ +from sqlalchemy import Column, Integer, ForeignKey +from sqlalchemy.orm import relationship + +from app.domain.models import Base + + +class SetContent(Base): + __tablename__ = 'set_contents' + + id = Column(Integer, primary_key=True, autoincrement=True) + tor = Column(Integer, nullable=False) + trial = Column(Integer, nullable=False) + esa = Column(Integer, nullable=False) + fvc = Column(Integer, nullable=False) + preset_refraction = Column(Integer, nullable=False) + diameter = Column(Integer, nullable=False) + periphery_toricity = Column(Integer, nullable=False) + side = Column(Integer, nullable=False) + count = Column(Integer, nullable=False) + + set_id = Column(Integer, ForeignKey('sets.id'), nullable=False) + + set = relationship('Set', back_populates='contents') diff --git a/api/app/domain/models/sets.py b/api/app/domain/models/sets.py index b554ba9..939e5da 100644 --- a/api/app/domain/models/sets.py +++ b/api/app/domain/models/sets.py @@ -11,4 +11,5 @@ class Set(Base): title = Column(VARCHAR(150), nullable=False, unique=True) count = Column(Integer, nullable=False) + contents = relationship('SetContent', back_populates='set') lens = relationship('SetLens', back_populates='set') diff --git a/api/app/infrastructure/auth_service.py b/api/app/infrastructure/auth_service.py index 3aee7bd..d43afac 100644 --- a/api/app/infrastructure/auth_service.py +++ b/api/app/infrastructure/auth_service.py @@ -4,6 +4,7 @@ from typing import Optional import jwt from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession +from starlette import status from app.application.users_repository import UsersRepository from app.settings import get_auth_data @@ -22,7 +23,7 @@ class AuthService: "user_id": user.id } - raise HTTPException(status_code=403, detail="Invalid login or password") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invalid login or password") @staticmethod def create_access_token(data: dict) -> str: diff --git a/api/app/infrastructure/dependencies.py b/api/app/infrastructure/dependencies.py index 1d97970..15d0259 100644 --- a/api/app/infrastructure/dependencies.py +++ b/api/app/infrastructure/dependencies.py @@ -2,6 +2,7 @@ from fastapi import Depends, HTTPException, Security from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials import jwt from sqlalchemy.ext.asyncio import AsyncSession +from starlette import status from app.database.session import get_db from app.domain.models.users import User @@ -20,23 +21,23 @@ async def get_current_user( try: payload = jwt.decode(credentials.credentials, auth_data["secret_key"], algorithms=[auth_data["algorithm"]]) except jwt.ExpiredSignatureError: - raise HTTPException(status_code=401, detail="Token has expired") + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token has expired") except jwt.InvalidTokenError: - raise HTTPException(status_code=401, detail="Invalid token") + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token") user_id = payload.get("user_id") if user_id is None: - raise HTTPException(status_code=401, detail="Invalid token") + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token") user = await UsersRepository(db).get_by_id_with_role(user_id) if user is None: - raise HTTPException(status_code=401, detail="User not found") + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found") return user def require_admin(user: User = Depends(get_current_user)): if user.role.title != "ミ籍エミシミクミスミクムムびミームひセム": - raise HTTPException(status_code=403, detail="Access denied") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") return user diff --git a/api/app/infrastructure/lenses_service.py b/api/app/infrastructure/lenses_service.py new file mode 100644 index 0000000..cc27318 --- /dev/null +++ b/api/app/infrastructure/lenses_service.py @@ -0,0 +1,109 @@ +from typing import Optional + +from fastapi import HTTPException +from sqlalchemy.ext.asyncio import AsyncSession +from starlette import status + +from app.application.lens_types_repository import LensTypesRepository +from app.application.lenses_repository import LensesRepository +from app.domain.entities.lens import LensEntity +from app.domain.models import Lens + + +class LensesService: + def __init__(self, db: AsyncSession): + self.lenses_repository = LensesRepository(db) + self.lens_types_repository = LensTypesRepository(db) + + async def get_all_lenses(self) -> list[LensEntity]: + lenses = await self.lenses_repository.get_all() + return [ + LensEntity( + id=lens.id, + tor=lens.tor, + trial=lens.trial, + esa=lens.esa, + fvc=lens.fvs, + preset_refraction=lens.preset_refraction, + diameter=lens.diameter, + periphery_toricity=lens.periphery_toricity, + side=lens.side, + issued=lens.issued, + type_id=lens.type_id, + ) + for lens in lenses + ] + + async def create_lens(self, lens: LensEntity) -> LensEntity: + lens_type = self.lens_types_repository.get_by_id(lens.type_id) + + if not lens_type: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail='The lens type with this ID was not found' + ) + + lens_model = Lens( + tor=lens.tor, + trial=lens.trial, + esa=lens.esa, + fvc=lens.fvc, + preset_refraction=lens.preset_refraction, + diameter=lens.diameter, + periphery_toricity=lens.periphery_toricity, + side=lens.side, + type_id=lens.type_id, + ) + await self.lenses_repository.create(lens_model) + return LensEntity( + id=lens_model.id, + tor=lens_model.tor, + trial=lens_model.trial, + esa=lens_model.esa, + fvc=lens_model.fvs, + preset_refraction=lens_model.preset_refraction, + diameter=lens_model.diameter, + periphery_toricity=lens_model.periphery_toricity, + side=lens_model.side, + issued=lens_model.issued, + type_id=lens_model.type_id, + ) + + async def update_lens(self, lens_id: int, lens: LensEntity) -> LensEntity: + lens_model = await self.lenses_repository.get_by_id(lens_id) + + if lens_model: + lens_model.tor = lens.tor + lens_model.trial = lens.trial + lens_model.esa = lens.esa + lens_model.fvc = lens.fvc + lens_model.preset_refraction = lens.preset_refraction + lens_model.diameter = lens.diameter + lens_model.periphery_toricity = lens.periphery_toricity + lens_model.side = lens.side + lens_model.issued = lens.issued + lens_model.type_id = lens.type_id + await self.lenses_repository.update(lens_model) + return LensEntity( + id=lens_model.id, + tor=lens_model.tor, + trial=lens_model.trial, + esa=lens_model.esa, + fvc=lens_model.fvs, + preset_refraction=lens_model.preset_refraction, + diameter=lens_model.diameter, + periphery_toricity=lens_model.periphery_toricity, + side=lens_model.side, + issued=lens_model.issued, + type_id=lens_model.type_id, + ) + + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Lens not found") + + async def delete_lens(self, lens_id: int) -> Optional[bool]: + result = await self.lenses_repository.delete(lens_id) is not None + + if not result: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Lens not found") + + return result diff --git a/api/app/infrastructure/patients_service.py b/api/app/infrastructure/patients_service.py index 9ea8964..846711c 100644 --- a/api/app/infrastructure/patients_service.py +++ b/api/app/infrastructure/patients_service.py @@ -2,6 +2,7 @@ from typing import Optional from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession +from starlette import status from app.application.patients_repository import PatientsRepository from app.domain.entities.patient import PatientEntity @@ -82,12 +83,12 @@ class PatientsService: correction=patient_model.correction, ) - raise HTTPException(status_code=404, detail="Patient not found") + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Patient not found") async def delete_patient(self, patient_id: int) -> Optional[bool]: result = await self.patient_repository.delete(patient_id) is not None if not result: - raise HTTPException(status_code=404, detail="Patient not found") + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Patient not found") return result