style: format適用

This commit is contained in:
shimoda.m@nds-tyo.co.jp 2023-05-12 13:39:14 +09:00
parent 311e76346c
commit 65acc3ce09
38 changed files with 163 additions and 130 deletions

View File

@ -7,9 +7,9 @@ from src.system_var import environment
class CognitoClient(AWSAPIClient):
def __init__(self) -> None:
self.__client = boto3.client('cognito-idp')
def login_by_user_password_flow(self, username: str, password: str, secret_hash: str):
auth_response = self.__client.admin_initiate_auth(
UserPoolId=environment.COGNITO_USER_POOL_ID,
ClientId=environment.COGNITO_CLIENT_ID,
@ -21,5 +21,5 @@ class CognitoClient(AWSAPIClient):
},
)
authentication_result = auth_response['AuthenticationResult']
return authentication_result['IdToken'], authentication_result['RefreshToken'],

View File

@ -7,16 +7,16 @@ from src.aws.aws_api_client import AWSAPIClient
class S3Client(AWSAPIClient):
__s3_client = boto3.client('s3')
def upload_file(self, local_file_path: str, bucket_name: str, file_key: str):
self.__s3_client.upload_file(
local_file_path,
Bucket=bucket_name,
Key=file_key
)
local_file_path,
Bucket=bucket_name,
Key=file_key
)
def generate_presigned_url(self, bucket_name: str, file_key: str, download_filename: str=''):
# presigned_urlを生成
def generate_presigned_url(self, bucket_name: str, file_key: str, download_filename: str = ''):
# presigned_urlを生成
presigned_url = self.__s3_client.generate_presigned_url(
'get_object',
Params={
@ -28,5 +28,5 @@ class S3Client(AWSAPIClient):
# 有効期限20分
ExpiresIn=1200
)
return presigned_url

View File

@ -1,7 +1,6 @@
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.exceptions import HTTPException
from starlette import status
from src.depends.services import get_service
@ -21,11 +20,13 @@ router.route_class = AuthenticatedRoute
#########################
# Views #
#########################
@router.get('/BioSearchList')
def bio_view(
request: Request,
batch_status_service:BatchStatusService=Depends(get_service(BatchStatusService)),
bio_service: BioViewService=Depends(get_service(BioViewService))
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService)),
bio_service: BioViewService = Depends(get_service(BioViewService))
):
session: UserSession = request.session
# バッチ処理中の場合、機能を利用させない
@ -50,12 +51,13 @@ def bio_view(
)
return templates_response
@router.post('/BioSearchList')
def search_bio(
request: Request,
bio_form: Optional[BioModel] = Depends(BioModel.as_form),
bio_service: BioViewService=Depends(get_service(BioViewService)),
batch_status_service:BatchStatusService=Depends(get_service(BatchStatusService))
bio_service: BioViewService = Depends(get_service(BioViewService)),
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
# error_log(date("Y/m/d H:i:s") . " [INFO] UserId:" . $UserId . "\r\n", 3, "$execLog");
session: UserSession = request.session

View File

@ -3,7 +3,6 @@ from datetime import datetime
from typing import Union
from fastapi import APIRouter, Depends, HTTPException
from fastapi.exceptions import HTTPException
from fastapi.responses import JSONResponse
from starlette import status
@ -23,14 +22,16 @@ router = APIRouter()
#########################
# APIs #
#########################
@router.post('/download')
async def download_bio_data(
search_param: BioModel=Depends(BioModel.as_body),
download_param: BioDownloadModel=Depends(BioDownloadModel.as_body),
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)
):
session: Union[UserSession, None] = Depends(verify_session)
):
# 通常のビューとはルーティングの扱いを変えるために、個別のルーターで登録する
# error_log(date("Y/m/d H:i:s") . " [INFO] getBioData start" . "\r\n", 3, "$execLog");
# 改修後のパラメータを打ち出すようにする
@ -68,14 +69,18 @@ async def download_bio_data(
# 値を変換
# データ種別の正式名を設定
extract_df.loc[:, 'slip_org_kbn'] = extract_df['slip_org_kbn'].apply(lambda key: constants.SLIP_ORG_KBN_FULL_NAME.get(key))
extract_df.loc[:, 'slip_org_kbn'] = extract_df['slip_org_kbn'].apply(
lambda key: constants.SLIP_ORG_KBN_FULL_NAME.get(key))
# データ区分の区分の日本語名を設定
extract_df.loc[:, 'data_kbn'] = extract_df['data_kbn'].apply(lambda key: constants.DATA_KBN_JP_NAME.get(key))
# ロット番号エラーフラグの日本語名を設定
extract_df.loc[:, 'lot_no_err_flg'] = extract_df['lot_no_err_flg'].apply(lambda key: constants.LOT_NO_ERR_FLG_JP_NAME.get(key))
# 訂正前伝票管理番号がセットされているときのみ修正日時、修正者、エラー詳細種別をセット
extract_df.loc[:, 'ins_dt'] = extract_df['bef_slip_mgt_no'].apply(lambda bef_slip_mgt_no:extract_df['ins_dt'] if bef_slip_mgt_no is not None else '')
extract_df.loc[:, 'ins_usr'] = extract_df['bef_slip_mgt_no'].apply(lambda bef_slip_mgt_no:extract_df['ins_usr'] if bef_slip_mgt_no is not None else '')
extract_df.loc[:, 'lot_no_err_flg'] = extract_df['lot_no_err_flg'].apply(
lambda key: constants.LOT_NO_ERR_FLG_JP_NAME.get(key))
# 訂正前伝票管理番号がセットされているときのみ修正日時、修正者、エラー詳細種別をセット
extract_df.loc[:, 'ins_dt'] = extract_df['bef_slip_mgt_no'].apply(
lambda bef_slip_mgt_no: extract_df['ins_dt'] if bef_slip_mgt_no is not None else '')
extract_df.loc[:, 'ins_usr'] = extract_df['bef_slip_mgt_no'].apply(
lambda bef_slip_mgt_no: extract_df['ins_usr'] if bef_slip_mgt_no is not None else '')
# 種別によって出力を変える
local_file_path = ''
@ -84,12 +89,14 @@ async def download_bio_data(
local_file_path = bio_service.write_excel_file(extract_df, download_param.user_id, timestamp=now)
elif download_param.kind == 'csv':
# error_log(date("Y/m/d H:i:s") . " [INFO] 今回はCSVファイルに出力する" . "\r\n", 3, "$execLog");
local_file_path = bio_service.write_csv_file(extract_df, download_param.user_id, header=constants.BIO_CSV_HEADER, timestamp=now)
local_file_path = bio_service.write_csv_file(
extract_df, download_param.user_id, header=constants.BIO_CSV_HEADER, timestamp=now)
# ローカルファイルから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.kind)
download_file_url = bio_service.generate_download_file_url(
local_file_path, download_param.user_id, download_param.kind)
except Exception as e:
print('S3 access error', e.args)
raise HTTPException(

View File

@ -5,6 +5,8 @@ router = APIRouter()
#########################
# Views #
#########################
@router.get('/')
def healthcheck():
return {'status': 'OK'}

View File

@ -1,4 +1,3 @@
import os.path as path
import secrets
import urllib.parse as parse
from typing import Union
@ -25,6 +24,8 @@ router.route_class = AfterSetCookieSessionRoute
#########################
# Views #
#########################
@router.get('/userlogin')
def login_user_redirect_view():
auth_query_string = parse.urlencode(
@ -39,6 +40,7 @@ def login_user_redirect_view():
return RedirectResponse(url=authorize_endpoint_url, status_code=status.HTTP_303_SEE_OTHER)
@router.get('/maintlogin')
def login_maintenance_view(request: Request):
mainte_login = MainteLoginViewModel()
@ -53,20 +55,22 @@ def login_maintenance_view(request: Request):
#########################
# APIs #
#########################
@router.post('/maintlogin')
def login(
response: Response,
request: LoginModel = Depends(LoginModel.as_form),
login_service: LoginService = Depends(get_service(LoginService))
):
response: Response,
request: LoginModel = Depends(LoginModel.as_form),
login_service: LoginService = Depends(get_service(LoginService))
):
try:
jwt_token = login_service.login(request.username, request.password)
except NotAuthorizeException as e:
print(e)
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR)
except JWTTokenVerifyException as e:
except JWTTokenVerifyException:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_SESSION_EXPIRED)
verified_token = jwt_token.verify_token()
# 普通の認証だと、`cognito:username`に入る。
user_id = verified_token.user_id
@ -92,7 +96,7 @@ def login(
user_flg=user_record.mntuser_flg
)
session_key = set_session(session_model)
response = RedirectResponse(
url='/menu',
status_code=status.HTTP_303_SEE_OTHER,
@ -103,9 +107,9 @@ def login(
@router.get('/authorize')
def sso_authorize(
code:Union[str, None]=Depends(code_security),
login_service: LoginService=Depends(get_service(LoginService))
) -> Response:
code: Union[str, None] = Depends(code_security),
login_service: LoginService = Depends(get_service(LoginService))
) -> Response:
if not code:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_NOT_LOGIN)
@ -114,7 +118,7 @@ def sso_authorize(
try:
# トークン検証
verified_token = jwt_token.verify_token()
except JWTTokenVerifyException as e:
except JWTTokenVerifyException:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_SESSION_EXPIRED)
# トークンからユーザーIDを取得

View File

@ -14,12 +14,14 @@ router = APIRouter()
#########################
# Views #
#########################
@router.get('/', response_class=HTMLResponse)
def logout_view(
request: Request,
reason: Optional[str] = None,
session: Union[UserSession, None]=Depends(verify_session)
):
request: Request,
reason: Optional[str] = None,
session: Union[UserSession, None] = Depends(verify_session)
):
redirect_to = '/login/userlogin'
link_text = 'MeDaCA機能メニューへ'
if session is not None and session.user_flg == '1':

View File

@ -16,11 +16,13 @@ router.route_class = AuthenticatedRoute
#########################
# Views #
#########################
@router.get('/', response_class=HTMLResponse)
def menu_view(
request: Request,
batch_status_service:BatchStatusService=Depends(get_service(BatchStatusService))
):
request: Request,
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
session: UserSession = request.session
# 日付マスターからバッチ情報を取得する
hdke_tbl_record = batch_status_service.hdke_table_record

View File

@ -18,4 +18,4 @@ def create_stop_app_handler(app: FastAPI) -> Callable:
def stop_app() -> None:
close_db(app)
return stop_app
return stop_app

View File

@ -16,13 +16,14 @@ class SQLCondition:
self.column = column
self.operator = operator
self.param = param
self.literal=literal
self.literal = literal
def apply(self):
# literalがFalseならプレースホルダー。Trueだったならは固定値。
param = f':{self.param}' if self.literal is False else self.param
return f' {self.column} {self.operator} {param}'
# 定数
EQ = '='
NE = '<>'
@ -32,4 +33,4 @@ GE = '>='
LE = '<='
LIKE = 'LIKE'
IS = 'IS'
IS_NOT = 'IS NOT'
IS_NOT = 'IS NOT'

View File

@ -17,26 +17,28 @@ code_security = APIKeyQuery(name='code', auto_error=False)
def get_current_session(session_key=Depends(cookie_security)):
if session_key is None:
return None
session = get_session(session_key)
# sessionが存在しない場合はNoneが返る
return session
def check_session_expired(session:Union[UserSession, None]=Depends(get_current_session)):
def check_session_expired(session: Union[UserSession, None] = Depends(get_current_session)):
"""セッションの最後にアクセスした時間が、セッション有効期限切れであるかどうかをチェックする"""
if session is None:
return None
last_access_time = session.last_access_time
session_expired_period = datetime.datetime.fromtimestamp(last_access_time) + datetime.timedelta(minutes=environment.SESSION_EXPIRE_MINUTE)
session_expired_period = datetime.datetime.fromtimestamp(
last_access_time) + datetime.timedelta(minutes=environment.SESSION_EXPIRE_MINUTE)
if session_expired_period < datetime.datetime.now():
return None
return session
def verify_session(session:Union[UserSession, None]=Depends(check_session_expired)):
def verify_session(session: Union[UserSession, None] = Depends(check_session_expired)):
if session is None:
return None
jwt_token = JWTToken(session.id_token, session.refresh_token)

View File

@ -14,4 +14,4 @@ def get_database(request: Request) -> Database:
def get_repository(Repo_type: Type[BaseRepository]) -> Callable:
def get_repo(db: Database = Depends(get_database)) -> Type[BaseRepository]:
return Repo_type(db)
return get_repo
return get_repo

View File

@ -1,7 +1,6 @@
from typing import Callable, Type
from fastapi import Depends
from starlette.requests import Request
from src.db.database import Database
from src.depends.database import get_database
@ -9,8 +8,8 @@ from src.services.base_service import BaseService
def get_service(Service_type: Type[BaseService]) -> Callable:
def get_service(db: Database=Depends(get_database)) -> Type[BaseService]:
def get_service(db: Database = Depends(get_database)) -> Type[BaseService]:
repositories = {key: repository(db) for key, repository in Service_type.REPOSITORIES.items()}
clients = {key: client() for key, client in Service_type.CLIENTS.items()}
return Service_type(repositories=repositories, clients=clients)
return get_service
return get_service

View File

@ -7,18 +7,22 @@ class MeDaCaException(Exception):
"""Webアプリの共通例外"""
pass
class NotAuthorizeException(MeDaCaException):
"""認証失敗の例外"""
pass
class JWTTokenVerifyException(MeDaCaException):
"""トークン検証失敗の例外"""
pass
class DBException(MeDaCaException):
"""DB関連の例外"""
pass
class UnexpectedException(MeDaCaException):
"""予期しない例外"""

View File

@ -1,4 +1,3 @@
from datetime import datetime
from typing import Optional
from src.model.db.base_db_model import BaseDBModel

View File

@ -28,9 +28,9 @@ class UserMasterModel(BaseDBModel):
def is_enable_user(self):
return self.enabled_flg == 'Y'
def is_maintenance_user(self):
return self.mntuser_flg == '1'
def is_groupware_user(self):
return self.mntuser_flg == '0'

View File

@ -15,11 +15,11 @@ class JWTToken:
refresh_token: str
verified_jwt: Optional[dict]
def __init__(self, id_token: str, refresh_token: str, verified_jwt: dict=None) -> None:
def __init__(self, id_token: str, refresh_token: str, verified_jwt: dict = None) -> None:
self.id_token = id_token
self.refresh_token = refresh_token
self.verified_jwt = verified_jwt
@property
def verified_token(self):
if self.verified_jwt is None:
@ -29,7 +29,7 @@ class JWTToken:
@property
def user_id(self):
verified_token = self.verified_token
user_id: str = None
identities: dict = verified_token.get('identities')
if identities is not None:
@ -63,7 +63,7 @@ class JWTToken:
'code': code,
'redirect_uri': environment.COGNITO_REDIRECT_URI
}
message = bytes(f'{environment.COGNITO_CLIENT_ID}:{environment.COGNITO_CLIENT_SECRET}', 'utf8')
auth_header_value = base64.b64encode(message).decode()
request_headers = {
@ -76,7 +76,7 @@ class JWTToken:
raise JWTTokenVerifyException(res.text)
token_response = json.loads(res.text)
return cls(id_token=token_response['id_token'], refresh_token=token_response['refresh_token'])
@classmethod
@ -99,7 +99,7 @@ class JWTToken:
'refresh_token': refresh_token,
'redirect_uri': environment.COGNITO_REDIRECT_URI
}
message = bytes(f'{environment.COGNITO_CLIENT_ID}:{environment.COGNITO_CLIENT_SECRET}', 'utf8')
auth_header_value = base64.b64encode(message).decode()
request_headers = {
@ -117,13 +117,13 @@ class JWTToken:
def verify_token(self):
if self.id_token is None:
raise Exception('アクセストークンがない')
issuer = f'https://cognito-idp.{environment.AWS_REGION}.amazonaws.com/{environment.COGNITO_USER_POOL_ID}'
jwks_url = f'{issuer}/.well-known/jwks.json'
jwks_client = jwt.PyJWKClient(jwks_url)
signing_key = jwks_client.get_signing_key_from_jwt(self.id_token)
try:
verified_jwt = jwt.decode(
self.id_token,

View File

@ -27,7 +27,7 @@ class UserSession(DynamoDBTableModel):
@classmethod
def new_last_access_time(cls):
return datetime.datetime.now().timestamp()
@classmethod
def new_record_expiration_time(cls, expire=environment.SESSION_EXPIRE_MINUTE):
last_access_time = datetime.datetime.fromtimestamp(cls.new_last_access_time())
@ -35,8 +35,8 @@ class UserSession(DynamoDBTableModel):
@classmethod
def new(
cls, user_id, id_token, refresh_token, csrf_token, doc_flg, inst_flg, bio_flg, master_mainte_flg, user_flg
):
cls, user_id, id_token, refresh_token, csrf_token, doc_flg, inst_flg, bio_flg, master_mainte_flg, user_flg
):
return cls(
session_key=str(uuid.uuid4()),
user_id=user_id,
@ -47,7 +47,7 @@ class UserSession(DynamoDBTableModel):
inst_flg=inst_flg,
bio_flg=bio_flg,
master_mainte_flg=master_mainte_flg,
user_flg=user_flg,
user_flg=user_flg,
last_access_time=cls.new_last_access_time(),
record_expiration_time=cls.new_record_expiration_time()
)

View File

@ -50,7 +50,7 @@ class BioModel(BaseModel):
ctrl_rev_hsdnymd_srk_to,
ikoFlg
)
@classmethod
def as_body(
cls,
@ -79,7 +79,6 @@ class BioModel(BaseModel):
ctrl_rev_hsdnymd_srk_to,
ikoFlg
)
def __convert_request_param(
cls,
@ -134,4 +133,4 @@ class BioModel(BaseModel):
rev_hsdnymd_srk_from=rev_hsdnymd_srk_from,
rev_hsdnymd_srk_to=rev_hsdnymd_srk_to,
ikoFlg=ikoFlg
)
)

View File

@ -1,5 +1,3 @@
from typing import Optional
from fastapi import Body
from pydantic import BaseModel
@ -7,7 +5,7 @@ from pydantic import BaseModel
class BioDownloadModel(BaseModel):
user_id: str
kind: str
@classmethod
def as_body(
cls,

View File

@ -5,7 +5,7 @@ from pydantic import BaseModel
class LoginModel(BaseModel):
username: str
password: str
@classmethod
def as_form(
cls,

View File

@ -7,12 +7,12 @@ from src.util.sanitize import sanitize
class BisDisplayModel(BioSalesViewModel):
def __init__(self, param: BioSalesViewModel) -> None:
super().__init__(**param.dict())
# 区分・フラグの正式名称を設定
self.slip_org_kbn = constants.SLIP_ORG_KBN_FULL_NAME.get(self.slip_org_kbn)
self.data_kbn = constants.DATA_KBN_JP_NAME.get(self.data_kbn)
self.lot_no_err_flg = constants.LOT_NO_ERR_FLG_JP_NAME.get(self.lot_no_err_flg)
# 訂正前伝票管理番号がセットされているときのみ修正日時、修正者、エラー詳細種別をセット
if (self.bef_slip_mgt_no is None):
self.ins_dt = ""

View File

@ -20,7 +20,7 @@ class BioViewModel(BaseModel):
phm_models: list[PharmacyProductMasterModel]
bio_data: Optional[list[BisDisplayModel]] = []
form_data: Optional[BioModel]
def display_wholesaler_names(self):
display_names = [
f'{whs_model.rec_whs_cd}-{whs_model.rec_whs_sub_cd}:{whs_model.nm}'
@ -41,7 +41,7 @@ class BioViewModel(BaseModel):
def display_data_kbn(self):
return OrderedDict(
{
'' : '',
'': '',
'0': '正常',
'1': 'ロットエラー',
'3': 'ロット不明',
@ -59,14 +59,16 @@ class BioViewModel(BaseModel):
if not self.is_form_submitted():
return ''
form_wholesaler_full_name = f'{self.form_data.wholesaler_code}-{self.form_data.wholesaler_sub_code}:{self.form_data.wholesaler_name}'
form_wholesaler_full_name = \
f'{self.form_data.wholesaler_code}-{self.form_data.wholesaler_sub_code}:{self.form_data.wholesaler_name}'
return self._selected_value(form_wholesaler_full_name, selected_wholesaler)
def is_selected_org_kbn(self, selected_org_kbn):
if not self.is_form_submitted():
return ''
return self._selected_value(self.form_data.org_kbn, selected_org_kbn)
def is_input_rec_ymd_from(self):
if not self.is_form_submitted():
return ''
@ -84,17 +86,17 @@ class BioViewModel(BaseModel):
return ''
return self.form_data.rec_lot_num or ''
def is_selected_data_kbn(self, selected_data_kbn):
if not self.is_form_submitted():
return ''
return self._selected_value(self.form_data.data_kbn, selected_data_kbn)
def is_selected_maker_cd(self, selected_maker_cd):
if not self.is_form_submitted():
return ''
return self._selected_value(self.form_data.maker_cd, selected_maker_cd)
def is_input_rev_hsdnymd_srk_from(self):
@ -108,13 +110,13 @@ class BioViewModel(BaseModel):
return ''
return self._format_date_string(self.form_data.rev_hsdnymd_srk_to)
def is_checked_iko_flg(self):
if not self.is_form_submitted():
return ''
return 'checked' if self.form_data.ikoFlg else ''
def disabled_button(self):
return 'disabled' if self.is_data_empty() or self.is_data_overflow_max_length() else ''
@ -123,7 +125,7 @@ class BioViewModel(BaseModel):
def is_data_empty(self):
return len(self.bio_data) == 0
def is_data_overflow_max_length(self):
return len(self.bio_data) >= environment.BIO_SEARCH_RESULT_MAX_COUNT

View File

@ -7,4 +7,4 @@ class LogoutViewModel(BaseModel):
subtitle: str = 'MeDaCA Logout'
redirect_to: Optional[str]
reason: Optional[str]
link_text:Optional[str]
link_text: Optional[str]

View File

@ -7,9 +7,9 @@ class UserViewModel(BaseModel):
bio_flg: str # AUTH_FLG1
doc_flg: str # AUTH_FLG2
inst_flg: str # AUTH_FLG3
master_mainte_flg: str # AUTH_FLG4
master_mainte_flg: str # AUTH_FLG4
user_flg: Optional[str] # MNTUSER_FLG
def has_ult_doctor_permission(self):
return self.doc_flg == '1'
@ -21,6 +21,6 @@ class UserViewModel(BaseModel):
def has_master_maintenance_permission(self):
return self.master_mainte_flg == '1'
def is_maintenance_user(self):
return self.user_flg == '1'

View File

@ -8,8 +8,9 @@ from src.model.db.base_db_model import BaseDBModel
class BaseRepository(metaclass=ABCMeta):
_database: Database
def __init__(self, db: Database) -> None:
self._database = db
@ -29,10 +30,9 @@ class BaseRepository(metaclass=ABCMeta):
"""DBの取得結果をデータフレームにして返す"""
pass
def _to_data_frame(self, query, parameter: BaseDBModel):
"""DBの取得結果をデータフレームに変換する"""
params = params=parameter.dict()
params = params = parameter.dict()
sql_query = pd.read_sql(
text(query),

View File

@ -55,7 +55,6 @@ class BioSalesViewRepository(BaseRepository):
finally:
self._database.disconnect()
def fetch_as_data_frame(self, parameter: BioModel):
try:
self._database.connect()
@ -95,7 +94,7 @@ class BioSalesViewRepository(BaseRepository):
if is_not_empty(parameter.rec_lot_num):
rec_lot_num = parameter.rec_lot_num
# あいまい検索文字列('%')が含まれる場合は'LIKE'、でなければ'='で検索
rec_lot_num_comparator = condition.LIKE if rec_lot_num in '%' else condition.EQ
rec_lot_num_comparator = condition.LIKE if rec_lot_num in '%' else condition.EQ
where_clauses.append(SQLCondition('rec_lot_num', rec_lot_num_comparator, 'rec_lot_num'))
# データ区分
if is_not_empty(parameter.data_kbn):
@ -112,7 +111,7 @@ class BioSalesViewRepository(BaseRepository):
# 移行フラグ
# チェックが入っていない場合、移行対象(IKO_FLG = '*')を省く
if parameter.ikoFlg is None:
where_clauses.append(SQLCondition('iko_flg', condition.IS, 'NULL', literal=True))
where_clauses.append(SQLCondition('iko_flg', condition.IS, 'NULL', literal=True))
# 固定条件
# Viewで返されるロット番号9件をNull以外で抽出
where_clauses.append(SQLCondition('LENGTH(TRIM(rec_lot_num))', condition.GT, '0', literal=True))

View File

@ -1,5 +1,4 @@
from src.model.db.hdke_tbl import HdkeTblModel
from src.model.request.bio import BioModel
from src.repositories.base_repository import BaseRepository

View File

@ -3,15 +3,15 @@ from src.repositories.base_repository import BaseRepository
class PharmacyProductMasterRepository(BaseRepository):
FETCH_SQL = """\
SELECT
SELECT
CONCAT(IFNULL(mkr_cd, ''), ' ', IFNULL(mkr_inf_1, '')) AS mkr_cd_nm
FROM
src05.phm_prd_mst_v t1
INNER JOIN
INNER JOIN
(
SELECT
SELECT
prd_cd,MAX(sub_no) AS sno
FROM
src05.phm_prd_mst_v

View File

@ -1,5 +1,4 @@
from src.model.db.user_master import UserMasterModel
from src.model.request.bio import BioModel
from src.repositories.base_repository import BaseRepository
@ -27,4 +26,4 @@ class UserMasterRepository(BaseRepository):
print(f"[ERROR] DB Error : Exception={e.args}")
raise e
finally:
self._database.disconnect()
self._database.disconnect()

View File

@ -3,7 +3,7 @@ from src.repositories.base_repository import BaseRepository
class WholesalerMasterRepository(BaseRepository):
FETCH_SQL = """\
SELECT DISTINCT
b.rec_whs_cd,
@ -17,7 +17,7 @@ class WholesalerMasterRepository(BaseRepository):
FROM src05.whs_mst_v
WHERE (SELECT STR_TO_DATE(syor_date, '%Y%m%d') FROM src05.hdke_tbl) BETWEEN start_date AND end_date
) v2
ON b.v_whs_cd = v2.v_whs_cd
ON b.v_whs_cd = v2.v_whs_cd
AND v2.rec_sts_kbn <> '9'
ORDER BY b.rec_whs_cd, b.rec_whs_sub_cd , b.whs_nm DESC
"""

View File

@ -13,12 +13,14 @@ from src.system_var import constants, environment
logger = logging.getLogger('uvicorn')
class MeDaCaRoute(APIRoute):
"""アプリケーションのカスタムルーター
Args:
APIRoute (APIRoute): FastAPIの標準APIRoute
"""
def get_route_handler(self) -> Callable:
"""前後処理を付加するルートハンドラーを返す
@ -60,6 +62,7 @@ class MeDaCaRoute(APIRoute):
Request: 加工後のRequestインスタンス
"""
return request
async def post_process_route(self, request: Request, response: Response) -> Response:
"""ルートハンドラーの事後処理
@ -71,6 +74,7 @@ class MeDaCaRoute(APIRoute):
"""
return response
class BeforeCheckSessionRoute(MeDaCaRoute):
"""事前処理として、セッションチェックを行うルートハンドラー
@ -86,12 +90,14 @@ class BeforeCheckSessionRoute(MeDaCaRoute):
verified_session = verify_session(checked_session)
# セッションが有効でない場合、エラーにする
if verified_session is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_SESSION_EXPIRED)
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail=constants.LOGOUT_REASON_SESSION_EXPIRED)
scope = request.scope
scope['session'] = verified_session
session_request = Request(receive=request.receive, scope=scope)
return session_request
class AfterSetCookieSessionRoute(MeDaCaRoute):
"""事後処理として、セッションキーをcookieに設定するカスタムルートハンドラー
@ -110,16 +116,18 @@ class AfterSetCookieSessionRoute(MeDaCaRoute):
response.set_cookie(
key='session',
value=session_key,
max_age=environment.SESSION_EXPIRE_MINUTE * 60, # cookieの有効期限は秒数指定なので、60秒をかける
max_age=environment.SESSION_EXPIRE_MINUTE * 60, # cookieの有効期限は秒数指定なので、60秒をかける
secure=True,
httponly=True
)
return response
class AuthenticatedRoute(BeforeCheckSessionRoute, AfterSetCookieSessionRoute):
async def pre_process_route(self, request: Request):
request = await super().pre_process_route(request)
return request
async def post_process_route(self, request: Request, response: Response):
response = await super().post_process_route(request, response)
return response

View File

@ -9,5 +9,6 @@ class BaseService(metaclass=ABCMeta):
REPOSITORIES: dict[str, BaseRepository] = {}
# 各サービスが依存するAWS APIクライアントクラスのマップ
CLIENTS: dict[str, AWSAPIClient] = {}
def __init__(self, repositories: dict[str, BaseRepository], clients: dict[str, AWSAPIClient]) -> None:
pass

View File

@ -13,6 +13,7 @@ class BatchStatusService(BaseService):
}
hdke_table_repository: HdkeTblRepository
__hdke_table_record: list[HdkeTblModel] = []
def __init__(self, repositories: dict[str, BaseRepository], clients: dict[str, AWSAPIClient]) -> None:
super().__init__(repositories, clients)
self.hdke_table_repository = repositories['hdke_table_repository']
@ -38,4 +39,3 @@ class BatchStatusService(BaseService):
# 日付マスタのレコードがない場合は例外とする
if len(self.__hdke_table_record) == 0:
raise DBException('日付テーブルのレコードが存在しません')

View File

@ -26,15 +26,16 @@ class BioViewService(BaseService):
'phm_repository': PharmacyProductMasterRepository,
'bio_sales_repository': BioSalesViewRepository
}
CLIENTS = {
's3_client': S3Client
}
whs_repository: WholesalerMasterRepository
phm_repository: PharmacyProductMasterRepository
bio_sales_repository: BioSalesViewRepository
s3_client: S3Client
def __init__(self, repositories: dict[str, BaseRepository], clients: dict[str, AWSAPIClient]) -> None:
super().__init__(repositories, clients)
self.whs_repository = repositories['whs_repository']
@ -45,7 +46,7 @@ class BioViewService(BaseService):
def prepare_bio_view(
self,
session: UserSession
) ->BioViewModel:
) -> BioViewModel:
# 卸リストを取得
wholesalers = self.whs_repository.fetch_all()
# 製品リストを取得
@ -72,7 +73,8 @@ class BioViewService(BaseService):
def write_excel_file(self, data_frame: pd.DataFrame, user_id: str, timestamp: datetime):
# Excelに書き込み
output_file_path = path.join(constants.BIO_TEMPORARY_FILE_DIR_PATH, f'Result_{user_id}_{timestamp:%Y%m%d%H%M%S%f}.xlsx')
output_file_path = path.join(constants.BIO_TEMPORARY_FILE_DIR_PATH,
f'Result_{user_id}_{timestamp:%Y%m%d%H%M%S%f}.xlsx')
# テンプレートファイルをコピーして出力ファイルの枠だけを作る
shutil.copyfile(
@ -87,12 +89,13 @@ class BioViewService(BaseService):
# DF内のヘッダと連番を書き込みたくない場合、`header`と`index`をFalseに指定する。
# `startrow`と`startcol`で、Excelの書き込み位置を決定する。省略した場合はA1セルから書く。
data_frame.to_excel(writer, header=False, index=False, startrow=1, startcol=0)
return output_file_path
def write_csv_file(self, data_frame: pd.DataFrame, user_id: str, header: list[str], timestamp: datetime):
# csvに書き込み
output_file_path = path.join(constants.BIO_TEMPORARY_FILE_DIR_PATH, f'Result_{user_id}_{timestamp:%Y%m%d%H%M%S%f}.csv')
output_file_path = path.join(constants.BIO_TEMPORARY_FILE_DIR_PATH,
f'Result_{user_id}_{timestamp:%Y%m%d%H%M%S%f}.csv')
# 横長のDataFrameとするため、ヘッダーの加工処理
header_data = {}
for df_column, header_column in zip(data_frame.columns, header):
@ -108,10 +111,10 @@ class BioViewService(BaseService):
def upload_bio_data_file(self, local_file_path: str) -> None:
bucket_name = environment.BIO_ACCESS_LOG_BUCKET
# TODO: フォルダを変える
file_key =f'bio/{path.basename(local_file_path)}'
file_key = f'bio/{path.basename(local_file_path)}'
self.s3_client.upload_file(local_file_path, bucket_name, file_key)
def generate_download_file_url(self, local_file_path:str, user_id: str, kind: str) -> str:
def generate_download_file_url(self, local_file_path: str, user_id: str, kind: str) -> str:
bucket_name = environment.BIO_ACCESS_LOG_BUCKET
# TODO: フォルダを変える
file_key = f'bio/{path.basename(local_file_path)}'

View File

@ -17,7 +17,7 @@ class LoginService(BaseService):
REPOSITORIES = {
'user_repository': UserMasterRepository
}
CLIENTS = {
'cognito_client': CognitoClient
}
@ -41,10 +41,10 @@ class LoginService(BaseService):
raise e
return JWTToken(id_token, refresh_token)
def login_with_security_code(self, code: str) -> JWTToken:
return JWTToken.request(code)
def logged_in_user(self, user_id):
user_record: UserMasterModel = self.user_repository.fetch_one({'user_id': user_id})
return user_record

View File

@ -6,6 +6,7 @@ def set_session(session: UserSession) -> str:
session.save()
return session.session_key
def get_session(key: str) -> UserSession:
try:
session = UserSession.get(hash_key=key, consistent_read=True)

View File

@ -19,4 +19,4 @@ DB_PASSWORD = os.environ['DB_PASSWORD']
DB_SCHEMA = os.environ['DB_SCHEMA']
BIO_SEARCH_RESULT_MAX_COUNT = int(os.environ['BIO_SEARCH_RESULT_MAX_COUNT'])
SESSION_EXPIRE_MINUTE=int(os.environ['SESSION_EXPIRE_MINUTE'])
SESSION_EXPIRE_MINUTE = int(os.environ['SESSION_EXPIRE_MINUTE'])