diff --git a/app/enums.py b/app/enums.py index f380d187..767ba04f 100644 --- a/app/enums.py +++ b/app/enums.py @@ -18,6 +18,10 @@ class LoginErrorEnum(str, Enum): INACTIVE_EMPLOYEE = "inactive_employee" REQUIRE_2FA = "require_2fa" +class AcceptTermsEnum(str, Enum): + SUCCESS = "success" + FAILURE = "failure" + class AccessErrorEnum(str, Enum): NOT_FOUND = "NOT_FOUND" diff --git a/app/models.py b/app/models.py index 0096d066..73a2eecd 100644 --- a/app/models.py +++ b/app/models.py @@ -41,6 +41,9 @@ class User(Model): is_2fa_required = fields.BooleanField(default=False) is_2fa_activated = fields.BooleanField(default=False) is_ergon_validation_required = fields.BooleanField(default=False) + # Terms of use + is_use_terms_accepted = fields.BooleanField(default=False) + use_terms_accepted_at = fields.DatetimeField(null=True) # Metadata is_active = fields.BooleanField(default=True) is_superuser = fields.BooleanField(default=False) diff --git a/app/routers/frontend.py b/app/routers/frontend.py index 97761d2c..70459a7e 100644 --- a/app/routers/frontend.py +++ b/app/routers/frontend.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- import asyncio +import datetime from typing import Annotated, List from fastapi import APIRouter, Depends, Request from fastapi_limiter.depends import RateLimiter +from fastapi.responses import JSONResponse from app.decorators import router_request from app.dependencies import assert_user_is_active, assert_cpf_is_valid @@ -13,6 +15,7 @@ Encounter, UserInfo, ) +from app.types.errors import AcceptTermsEnum from app.utils import read_bq, validate_user_access_to_patient_data from app.config import ( BIGQUERY_PROJECT, @@ -23,7 +26,8 @@ REQUEST_LIMIT_WINDOW_SIZE, ) from app.types.errors import ( - AccessErrorModel + AccessErrorModel, + TermAcceptanceErrorModel ) router = APIRouter(prefix="/frontend", tags=["Frontend Application"]) @@ -45,10 +49,46 @@ async def get_user_info( "role": user.role.job_title if user.role else None, "email": user.email, "username": user.username, + "is_use_terms_accepted": user.is_use_terms_accepted, "cpf": cpf, } +@router_request( + method="POST", + router=router, + path="/user/accept-terms/", + response_model=TermAcceptanceErrorModel, + responses={ + 500: {"model": TermAcceptanceErrorModel}, + }, +) +async def accept_use_terms( + user: Annotated[User, Depends(assert_user_is_active)], + request: Request, +) -> TermAcceptanceErrorModel: + + try: + user.is_use_terms_accepted = True + user.use_terms_accepted_at = datetime.datetime.now() + await user.save() + return JSONResponse( + status_code=200, + content={ + "message": "Success", + "type": AcceptTermsEnum.SUCCESS, + }, + ) + except Exception: + return JSONResponse( + status_code=500, + content={ + "message": "Patient not found", + "type": AcceptTermsEnum.FAILURE, + }, + ) + + @router_request( method="GET", router=router, diff --git a/app/types/errors.py b/app/types/errors.py index a8b76f08..069dfb3c 100644 --- a/app/types/errors.py +++ b/app/types/errors.py @@ -3,7 +3,8 @@ from app.enums import ( LoginErrorEnum, - AccessErrorEnum + AccessErrorEnum, + AcceptTermsEnum ) @@ -14,4 +15,9 @@ class AuthenticationErrorModel(BaseModel): class AccessErrorModel(BaseModel): message: str - type: AccessErrorEnum \ No newline at end of file + type: AccessErrorEnum + + +class TermAcceptanceErrorModel(BaseModel): + message: str + type: AcceptTermsEnum diff --git a/migrations/app/35_20241029140029_update.py b/migrations/app/35_20241029140029_update.py new file mode 100644 index 00000000..e131aab1 --- /dev/null +++ b/migrations/app/35_20241029140029_update.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +from tortoise import BaseDBAsyncClient + + +async def upgrade(db: BaseDBAsyncClient) -> str: + return """ + ALTER TABLE "user" ADD "use_terms_accepted_at" TIMESTAMPTZ; + ALTER TABLE "user" ADD "is_use_terms_accepted" BOOL NOT NULL DEFAULT False;""" + + +async def downgrade(db: BaseDBAsyncClient) -> str: + return """ + ALTER TABLE "user" DROP COLUMN "use_terms_accepted_at"; + ALTER TABLE "user" DROP COLUMN "is_use_terms_accepted";"""