From ac74871f2ba56ed185873b11fee2d71dabdd8247 Mon Sep 17 00:00:00 2001 From: Pedro Nascimento Date: Mon, 19 Aug 2024 16:43:54 -0300 Subject: [PATCH] split users into two classes: pipeline and frontend --- app/dependencies.py | 20 ++++++++++ app/enums.py | 5 +++ app/main.py | 3 +- app/models.py | 2 + app/routers/entities.py | 46 ---------------------- app/routers/entities_mrg.py | 18 +++++---- app/routers/entities_raw.py | 8 ++-- app/routers/entities_std.py | 10 ++--- app/routers/frontend.py | 14 ++++--- migrations/app/26_20240819161328_update.py | 12 ++++++ 10 files changed, 67 insertions(+), 71 deletions(-) delete mode 100644 app/routers/entities.py create mode 100644 migrations/app/26_20240819161328_update.py diff --git a/app/dependencies.py b/app/dependencies.py index 336396d..31fc5bc 100644 --- a/app/dependencies.py +++ b/app/dependencies.py @@ -46,3 +46,23 @@ async def get_current_active_user(current_user: Annotated[User, Depends(get_curr if not current_user.is_active: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Inactive user") return current_user + + +async def get_current_pipeline_user(current_user: Annotated[User, Depends(get_current_user)]): + if current_user.is_superuser: + return current_user + + if current_user.user_class.value in ["pipeline_user"]: + return current_user + else: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User don't have permition to access Pipeline Endpoints") + + +async def get_current_frontend_user(current_user: Annotated[User, Depends(get_current_user)]): + if current_user.is_superuser: + return current_user + + if current_user.user_class.value in ["frontend_user"]: + return current_user + else: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User don't have permition to access Front-end Endpoints") \ No newline at end of file diff --git a/app/enums.py b/app/enums.py index 3562743..1b247d6 100644 --- a/app/enums.py +++ b/app/enums.py @@ -2,6 +2,11 @@ from enum import Enum +class UserClassEnum(str, Enum): + WEBAPP_USER = "frontend_user" + PIPELINE_USER = "pipeline_user" + + class ConditionCodeTypeEnum(str, Enum): CID = "cid" CIAP = "ciap" diff --git a/app/main.py b/app/main.py index 6538ccb..adc432b 100644 --- a/app/main.py +++ b/app/main.py @@ -9,7 +9,7 @@ from app import config from app.db import TORTOISE_ORM -from app.routers import auth, entities_mrg, entities_raw, entities_std, entities, frontend +from app.routers import auth, entities_mrg, entities_raw, entities_std, frontend logger.remove() logger.add(sys.stdout, level=config.LOG_LEVEL) @@ -45,7 +45,6 @@ app.include_router(entities_raw.router) app.include_router(entities_std.router) app.include_router(entities_mrg.router) -app.include_router(entities.router) app.include_router(auth.router) app.include_router(frontend.router) diff --git a/app/models.py b/app/models.py index a20713f..56dd11f 100644 --- a/app/models.py +++ b/app/models.py @@ -10,6 +10,7 @@ CategoryEnum, ClinicalStatusEnum, SystemEnum, + UserClassEnum ) from app.validators import CPFValidator, PatientCodeValidator @@ -274,6 +275,7 @@ class User(Model): password = fields.CharField(max_length=255) is_active = fields.BooleanField(default=True) is_superuser = fields.BooleanField(default=False) + user_class = fields.CharEnumField(enum_type=UserClassEnum, null=True, default=UserClassEnum.PIPELINE_USER) data_source = fields.ForeignKeyField("app.DataSource", related_name="users", null=True) created_at = fields.DatetimeField(auto_now_add=True) updated_at = fields.DatetimeField(auto_now=True) diff --git a/app/routers/entities.py b/app/routers/entities.py deleted file mode 100644 index 658ea58..0000000 --- a/app/routers/entities.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -from typing import Annotated - -from fastapi import APIRouter, Depends -from tortoise.contrib.pydantic import pydantic_model_creator - -from app.dependencies import get_current_active_user -from app.types.pydantic_models import UserRegisterInputModel, UserRegisterOutputModel -from app.utils import password_hash -from app.models import ( - User, DataSource -) - -DataSourceInput = pydantic_model_creator(DataSource, name="DataSourceInput", exclude=("id",)) -DataSourceOutput = pydantic_model_creator(DataSource, name="DataSourceOutput") - - -router = APIRouter(prefix="/outros", tags=["Outras Entidades"]) - - -@router.post("/user", status_code=201) -async def create_user( - _ : Annotated[User, Depends(get_current_active_user)], - user : UserRegisterInputModel, -) -> UserRegisterOutputModel: - - user_data = user.dict() - datasource_data = user_data.pop('data_source') - - datasource_instance, _ = await DataSource.get_or_create( - system = datasource_data['system'], - cnes = datasource_data['cnes'], - description = datasource_data['description'] - ) - - user_data['password'] = password_hash(user_data['password']) - user_data['data_source'] = datasource_instance - - user_instance = await User.create(**user_data) - - output = { - **dict(user_instance), - 'data_source': dict(datasource_instance) - } - - return output diff --git a/app/routers/entities_mrg.py b/app/routers/entities_mrg.py index 140b359..929bbd0 100644 --- a/app/routers/entities_mrg.py +++ b/app/routers/entities_mrg.py @@ -7,7 +7,9 @@ from tortoise.contrib.pydantic import pydantic_model_creator from tortoise.exceptions import ValidationError -from app.dependencies import get_current_active_user +from app.dependencies import ( + get_current_pipeline_user +) from app.types.pydantic_models import ( CompletePatientModel, MergedPatient as PydanticMergedPatient, @@ -47,7 +49,7 @@ @router.put("/patient") async def create_or_update_patient( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], patients: List[PydanticMergedPatient], ) -> int: @@ -81,7 +83,7 @@ async def create_or_update_patient( @router.put("/patientaddress") async def create_or_update_patientaddress( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], patientaddress_list: List[PydanticMergedPatientAddress], ) -> int: # Get list of patient codes @@ -111,7 +113,7 @@ async def create_or_update_patientaddress( @router.put("/patienttelecom") async def create_or_update_patienttelecom( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], patienttelecom_list: List[PydanticMergedPatientTelecom], ) -> int: # Get list of patient codes @@ -140,7 +142,7 @@ async def create_or_update_patienttelecom( @router.put("/patientcns") async def create_or_update_patientcns( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], patientcns_list: List[PydanticMergedPatientCns], ) -> int: # Get list of patient codes @@ -169,7 +171,7 @@ async def create_or_update_patientcns( @router.get("/patient/{patient_cpf}") async def get_patient( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], patient_cpf: int, )-> list[CompletePatientModel]: @@ -225,7 +227,7 @@ async def get_patient( @router.put("/professionals") async def create_or_update_professionals( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], professionals: List[ProfessionalModel], ) -> int: @@ -328,7 +330,7 @@ async def create_or_update_professionals( @router.put("/teams") async def create_or_update_teams( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], teams: List[TeamModel], ) -> int: diff --git a/app/routers/entities_raw.py b/app/routers/entities_raw.py index d272dc2..102fa67 100644 --- a/app/routers/entities_raw.py +++ b/app/routers/entities_raw.py @@ -12,7 +12,7 @@ from tortoise.exceptions import ValidationError from app.types.pydantic_models import RawDataListModel, BulkInsertOutputModel, RawDataModel -from app.dependencies import get_current_active_user +from app.dependencies import get_current_pipeline_user from app.models import User, RawPatientRecord, RawPatientCondition, DataSource, RawEncounter from app.datalake.uploader import DatalakeUploader @@ -33,7 +33,7 @@ @router.get("/{entity_name}/{filter_type}") async def get_raw_data( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], entity_name: Literal["patientrecords", "patientconditions", "encounter"], filter_type: Literal["fromEventDatetime", "fromInsertionDatetime"], start_datetime: dt = dt.now() - td(hours=1), @@ -68,7 +68,7 @@ async def get_raw_data( @router.post("/{entity_name}", status_code=201) async def create_raw_data( entity_name: Literal["patientrecords", "patientconditions", "encounter"], - current_user: Annotated[User, Depends(get_current_active_user)], + current_user: Annotated[User, Depends(get_current_pipeline_user)], raw_data: RawDataListModel, upload_to_datalake: bool = True, ) -> BulkInsertOutputModel: @@ -145,7 +145,7 @@ async def create_raw_data( @router.post("/{entity_name}/setAsInvalid", status_code=200) async def set_as_invalid_flag_records( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], entity_name: Literal["patientrecords", "patientconditions", "encounter"], raw_record_id_list: list[str], ): diff --git a/app/routers/entities_std.py b/app/routers/entities_std.py index 80b6272..b2705ea 100644 --- a/app/routers/entities_std.py +++ b/app/routers/entities_std.py @@ -13,7 +13,7 @@ from tortoise.contrib.pydantic import pydantic_model_creator from tortoise.exceptions import ValidationError, DoesNotExist -from app.dependencies import get_current_active_user +from app.dependencies import get_current_pipeline_user from app.types.pydantic_models import ( PatientMergeableRecord, StandardizedPatientRecordModel, StandardizedPatientConditionModel, BulkInsertOutputModel, MergeableRecord, Page @@ -37,7 +37,7 @@ @router.get("/patientrecords/updated") async def get_patientrecords_of_updated_patients( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], start_datetime: datetime.datetime = datetime.datetime.now() - datetime.timedelta(hours=1), end_datetime: datetime.datetime = datetime.datetime.now(), @@ -100,7 +100,7 @@ async def get_patientrecords_of_updated_patients( @router.post("/patientrecords", status_code=201) async def create_standardized_patientrecords( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], records: list[StandardizedPatientRecordModel], ) -> BulkInsertOutputModel: @@ -164,7 +164,7 @@ async def create_standardized_patientrecords( @router.get("/patientconditions") async def get_standardized_patientconditions( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], patient_cpf: str, ) -> list[MergeableRecord[StandardizedPatientConditionModel]]: @@ -188,7 +188,7 @@ async def get_standardized_patientconditions( @router.post("/patientconditions", status_code=201) async def create_standardized_patientconditions( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_pipeline_user)], conditions: list[StandardizedPatientConditionModel], ) -> BulkInsertOutputModel: diff --git a/app/routers/frontend.py b/app/routers/frontend.py index e49b6f0..253af4e 100644 --- a/app/routers/frontend.py +++ b/app/routers/frontend.py @@ -5,7 +5,9 @@ from fastapi import APIRouter, Depends, HTTPException from basedosdados import read_sql -from app.dependencies import get_current_active_user +from app.dependencies import ( + get_current_frontend_user +) from app.models import User from app.types.frontend import ( PatientHeader, @@ -21,7 +23,7 @@ @router.get("/user") async def get_user_info( - user: Annotated[User, Depends(get_current_active_user)], + user: Annotated[User, Depends(get_current_frontend_user)], ) -> UserInfo: if user.cpf: cpf = user.cpf @@ -40,7 +42,7 @@ async def get_user_info( @router.get("/patient/header/{cpf}") async def get_patient_header( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_frontend_user)], cpf: str, ) -> PatientHeader: results_json = read_sql( @@ -122,7 +124,7 @@ async def get_patient_header( @router.get("/patient/summary/{cpf}") async def get_patient_summary( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_frontend_user)], cpf: str, ) -> PatientSummary: @@ -156,7 +158,7 @@ async def get_patient_summary( @router.get("/patient/filter_tags") async def get_filter_tags( - _: Annotated[User, Depends(get_current_active_user)] + _: Annotated[User, Depends(get_current_frontend_user)] ) -> List[str]: return [ "CF/CMS", @@ -172,7 +174,7 @@ async def get_filter_tags( @router.get("/patient/encounters/{cpf}") async def get_patient_encounters( - _: Annotated[User, Depends(get_current_active_user)], + _: Annotated[User, Depends(get_current_frontend_user)], cpf: str, ) -> List[Encounter]: diff --git a/migrations/app/26_20240819161328_update.py b/migrations/app/26_20240819161328_update.py new file mode 100644 index 0000000..044cf9c --- /dev/null +++ b/migrations/app/26_20240819161328_update.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +from tortoise import BaseDBAsyncClient + + +async def upgrade(db: BaseDBAsyncClient) -> str: + return """ + ALTER TABLE "user" ADD "user_class" VARCHAR(13) DEFAULT 'pipeline_user';""" + + +async def downgrade(db: BaseDBAsyncClient) -> str: + return """ + ALTER TABLE "user" DROP COLUMN "user_class";"""