206 lines
7.9 KiB
Python
206 lines
7.9 KiB
Python
"""生物由来照会 APIRoute"""
|
|
import datetime
|
|
from typing import Optional, Union
|
|
|
|
import pandas as pd
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from fastapi.encoders import jsonable_encoder
|
|
from fastapi.responses import JSONResponse
|
|
from starlette import status
|
|
|
|
from src.depends.auth import verify_session
|
|
from src.depends.services import get_service
|
|
from src.logging.get_logger import get_logger
|
|
from src.model.internal.session import UserSession
|
|
from src.model.request.bio import BioModel
|
|
from src.model.request.bio_download import BioDownloadModel
|
|
from src.model.view.bio_disp_model import BioDisplayModel
|
|
from src.services.batch_status_service import BatchStatusService
|
|
from src.services.bio_view_service import BioViewService
|
|
from src.services.session_service import set_session
|
|
from src.system_var import constants, environment
|
|
|
|
logger = get_logger('生物由来参照')
|
|
|
|
router = APIRouter()
|
|
|
|
#########################
|
|
# APIs #
|
|
#########################
|
|
|
|
|
|
@router.post('/search')
|
|
def search_bio_data(
|
|
bio_form: Optional[BioModel] = Depends(BioModel.as_form),
|
|
bio_service: BioViewService = Depends(get_service(BioViewService)),
|
|
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService)),
|
|
session: Union[UserSession, None] = Depends(verify_session)
|
|
):
|
|
if session is None:
|
|
return JSONResponse(content={'status': 'session_expired'}, status_code=status.HTTP_401_UNAUTHORIZED)
|
|
# バッチ処理中の場合、機能を利用させない
|
|
if batch_status_service.is_batch_processing():
|
|
return JSONResponse(content={'status': 'batch_processing'}, status_code=status.HTTP_403_FORBIDDEN)
|
|
|
|
# 生物由来データと件数を取得
|
|
trn_result_data_bio_lot_data = bio_service.search_bio_data(bio_form)
|
|
trn_result_data_bio_lot_count = bio_service.count_bio_data(bio_form, session)
|
|
|
|
# レスポンスデータを加工
|
|
# 日付型のデータのエンコードエラーを解消するための措置
|
|
def custom_encode(obj):
|
|
encoded_obj = obj.model_dump()
|
|
for key, value in encoded_obj.items():
|
|
if type(value) == datetime.datetime:
|
|
encoded_obj[key] = value.strftime("%Y-%m-%d %H:%M:%S") if obj is not None else ''
|
|
if type(value) == datetime.date:
|
|
encoded_obj[key] = value.strftime("%Y-%m-%d") if obj is not None else ''
|
|
return encoded_obj
|
|
|
|
data = jsonable_encoder(
|
|
trn_result_data_bio_lot_data,
|
|
custom_encoder={
|
|
BioDisplayModel: custom_encode
|
|
}
|
|
)
|
|
|
|
# セッション書き換え
|
|
session.update(
|
|
actions=[
|
|
UserSession.last_access_time.set(UserSession.new_last_access_time()),
|
|
UserSession.record_expiration_time.set(UserSession.new_record_expiration_time()),
|
|
# 検索結果をキャッシュする
|
|
UserSession.bio_search_condition.set(bio_form.model_dump()),
|
|
UserSession.bio_search_count.set(trn_result_data_bio_lot_count),
|
|
]
|
|
)
|
|
set_session(session)
|
|
json_response = JSONResponse(content={
|
|
'data': data,
|
|
'count': trn_result_data_bio_lot_count
|
|
})
|
|
|
|
# クッキーも書き換え
|
|
json_response.set_cookie(
|
|
key='session',
|
|
value=session.session_key,
|
|
secure=True,
|
|
httponly=True
|
|
)
|
|
return json_response
|
|
|
|
|
|
@router.post('/download')
|
|
async def download_bio_data(
|
|
search_param: BioModel = Depends(BioModel.as_body),
|
|
download_param: BioDownloadModel = Depends(BioDownloadModel.as_body),
|
|
bio_service: BioViewService = Depends(get_service(BioViewService)),
|
|
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService)),
|
|
session: Union[UserSession, None] = Depends(verify_session)
|
|
):
|
|
# 通常のビューとはルーティングの扱いを変えるために、個別のルーターで登録する
|
|
logger.info('生物由来データダウンロード開始')
|
|
logger.info(f'ユーザーID: {download_param.user_id}')
|
|
logger.info(f'拡張子: {download_param.ext}')
|
|
# ファイル名に使用するタイムスタンプを初期化しておく
|
|
current_timestamp = datetime.datetime.now()
|
|
# 出力ファイル名
|
|
download_file_name = f'Result_{download_param.user_id}_{current_timestamp:%Y%m%d%H%M%S%f}.{download_param.ext}'
|
|
if session is None:
|
|
return {'status': 'session_expired'}
|
|
# バッチ処理中の場合、機能を利用させない
|
|
if batch_status_service.is_batch_processing():
|
|
return {'status': 'batch_processing'}
|
|
# 生物由来データを検索
|
|
# 検索に使用したクエリも取得
|
|
search_result_df, query = _search_download_bio_data(bio_service, search_param, download_param)
|
|
# アクセスログを記録
|
|
bio_service.write_access_log(query, search_param, download_param.user_id, current_timestamp, download_file_name)
|
|
|
|
if search_result_df.size < 1:
|
|
# 検索結果が0件の場合、download_urlを返さない
|
|
logger.info('検索結果が0件です')
|
|
return {'status': 'ok', 'download_url': None}
|
|
|
|
# ファイルを書き出し(Excel or CSV)
|
|
local_file_path = await _write_bio_data_to_file(bio_service, download_param, search_result_df, download_file_name)
|
|
|
|
logger.info('ファイル書き出し完了')
|
|
|
|
# ローカルファイルからS3にアップロードし、ダウンロード用URLを取得する
|
|
try:
|
|
bio_service.upload_bio_data_file(local_file_path)
|
|
download_file_url = bio_service.generate_download_file_url(
|
|
local_file_path, download_param.user_id, download_param.ext)
|
|
except Exception as e:
|
|
logger.exception(f'S3 アクセスエラー{e}')
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail={'error': 'aws_error', 'message': e.args}
|
|
)
|
|
|
|
# セッション書き換え
|
|
session.update(
|
|
actions=[
|
|
UserSession.last_access_time.set(UserSession.new_last_access_time()),
|
|
UserSession.record_expiration_time.set(UserSession.new_record_expiration_time()),
|
|
]
|
|
)
|
|
set_session(session)
|
|
|
|
# クッキーも書き換え
|
|
json_response = JSONResponse(content={
|
|
'status': 'ok',
|
|
'download_url': download_file_url
|
|
})
|
|
|
|
json_response.set_cookie(
|
|
key='session',
|
|
value=session.session_key,
|
|
secure=True,
|
|
httponly=True
|
|
)
|
|
return json_response
|
|
|
|
|
|
def _search_download_bio_data(
|
|
bio_service: BioViewService,
|
|
search_param: BioModel,
|
|
download_param: BioDownloadModel
|
|
) -> pd.DataFrame:
|
|
try:
|
|
# 生物由来データを検索
|
|
# Excelの場合、出力件数を絞る
|
|
if download_param.ext == 'xlsx':
|
|
search_result_df, query = bio_service.search_download_bio_data(
|
|
search_param, limitation=environment.BIO_EXCEL_RESULT_MAX_COUNT)
|
|
elif download_param.ext == 'csv':
|
|
search_result_df, query = bio_service.search_download_bio_data(search_param)
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail={'error': 'db_error', 'message': e.args}
|
|
)
|
|
|
|
return search_result_df, query
|
|
|
|
|
|
async def _write_bio_data_to_file(
|
|
bio_service: BioViewService,
|
|
download_param: BioDownloadModel,
|
|
df: pd.DataFrame,
|
|
download_file_name: str
|
|
) -> str:
|
|
# 種別によって出力を変える
|
|
local_file_path = ''
|
|
if download_param.ext == 'xlsx':
|
|
logger.info('今回はExcelファイルに出力する')
|
|
local_file_path = await bio_service.write_excel_file(
|
|
df, download_param.user_id, download_file_name=download_file_name)
|
|
elif download_param.ext == 'csv':
|
|
logger.info('今回はCSVファイルに出力する')
|
|
local_file_path = await bio_service.write_csv_file(
|
|
df, download_param.user_id, header=constants.BIO_CSV_HEADER, download_file_name=download_file_name)
|
|
|
|
return local_file_path
|