From ce8b0238ce293a1ab7f64fe5d73fef9d11b36251 Mon Sep 17 00:00:00 2001 From: Miwory Date: Tue, 14 Apr 2026 14:54:40 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=80=D0=BE=D1=83=D1=82=D0=B5=D1=80=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D0=BA=D0=B0=D1=87=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- src/apps/download/__init__.py | 0 src/apps/download/v1/__init__.py | 0 src/apps/download/v1/router.py | 33 +++++++++++++++++++++++++++++ src/apps/users/v1/router.py | 36 ++++++++++++++++++++++++-------- src/apps/users/v1/schema.py | 4 ++++ src/core/routers/v1.py | 2 ++ 7 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 src/apps/download/__init__.py create mode 100644 src/apps/download/v1/__init__.py create mode 100644 src/apps/download/v1/router.py diff --git a/pyproject.toml b/pyproject.toml index df05cba..4e65e16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "HospitalAssistantBackend" -version = "1.4.1" +version = "1.5.0" description = "Backend for Hospital Assistant" readme = "README.md" requires-python = ">=3.13,<3.14" diff --git a/src/apps/download/__init__.py b/src/apps/download/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/download/v1/__init__.py b/src/apps/download/v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/download/v1/router.py b/src/apps/download/v1/router.py new file mode 100644 index 0000000..34fddb6 --- /dev/null +++ b/src/apps/download/v1/router.py @@ -0,0 +1,33 @@ +from logging import getLogger + +from fastapi import APIRouter, Response +from orjson import loads + +from shared import exceptions as e +from shared.redis import client as cache + +logger = getLogger(__name__) +router = APIRouter( + prefix='/download', + tags=[ + 'Download', + ], +) + + +@router.get('/{token}') +async def download_file(token: str): + file_data = await cache.get(f'download:{token}') + + if file_data is None: + raise e.NotFoundException + + data = loads(file_data) + + return Response( + content=data['data'], + media_type=data['content_type'], + headers={ + 'Content-Disposition': f'attachment; filename="{data["filename"]}"' + }, + ) diff --git a/src/apps/users/v1/router.py b/src/apps/users/v1/router.py index d352beb..3a1823d 100644 --- a/src/apps/users/v1/router.py +++ b/src/apps/users/v1/router.py @@ -5,7 +5,7 @@ from logging import getLogger from secrets import token_urlsafe from typing import Annotated -from fastapi import APIRouter, Body, Depends, Response, UploadFile, status +from fastapi import APIRouter, Body, Depends, UploadFile, status from orjson import loads from apps.remd.dependencies import convert_aemd_to_pdf, get_parsable_ids @@ -119,12 +119,21 @@ async def get_vaccs_report_download( file_bytes = base64.b64decode(file.content) filename = f'vaccs_report_{resultId or user.vita_id}.doc' - return Response( - content=file_bytes, - media_type='application/msword', - headers={'Content-Disposition': f'attachment; filename="{filename}"'}, + temp_link_token = token_urlsafe(32) + await cache.set( + f'download:{temp_link_token}', + dumps( + { + 'filename': filename, + 'content_type': 'application/msword', + 'data': file_bytes, + } + ), + ex=600, ) + return s.DownloadFile(link=temp_link_token) + @router.get('/getMedExamDict') async def get_med_exam_dict(user: Annotated[User, Depends(login)]): @@ -296,12 +305,21 @@ async def get_aemd_file_download( pdf_bytes = await convert_aemd_to_pdf(decoded, docKind) filename = f'{emdrId}.pdf' - return Response( - content=pdf_bytes, - media_type='application/pdf', - headers={'Content-Disposition': f'attachment; filename="{filename}"'}, + temp_link_token = token_urlsafe(32) + await cache.set( + f'download:{temp_link_token}', + dumps( + { + 'filename': filename, + 'content_type': 'application/pdf', + 'data': pdf_bytes, + } + ), + ex=600, ) + return s.DownloadFile(link=temp_link_token) + @router.post('/measurement', status_code=status.HTTP_202_ACCEPTED) async def measurement( diff --git a/src/apps/users/v1/schema.py b/src/apps/users/v1/schema.py index 46bd37c..8737b4e 100644 --- a/src/apps/users/v1/schema.py +++ b/src/apps/users/v1/schema.py @@ -33,3 +33,7 @@ class Notifications(TypedDict): class Complaints(BaseModel): complaints: str + + +class DownloadFile(BaseModel): + link: str diff --git a/src/core/routers/v1.py b/src/core/routers/v1.py index 0ab150b..c4fed24 100644 --- a/src/core/routers/v1.py +++ b/src/core/routers/v1.py @@ -1,6 +1,7 @@ from fastapi import APIRouter, HTTPException from apps.default.v1.router import router as default_router +from apps.download.v1.router import router as download_router from apps.esia.v1.router import router as esia_router from apps.remd.v1.router import router as remd_router from apps.tmk.v1.router import router as tmk_router @@ -17,6 +18,7 @@ router.include_router(users_router) router.include_router(remd_router) router.include_router(vitacore_router) router.include_router(tmk_router) +router.include_router(download_router) openapi_schema = get_openapi_schema(router) swagger_ui_html = get_swagger_html(router)