style: format適用
This commit is contained in:
parent
311e76346c
commit
65acc3ce09
@ -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'],
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -5,6 +5,8 @@ router = APIRouter()
|
||||
#########################
|
||||
# Views #
|
||||
#########################
|
||||
|
||||
|
||||
@router.get('/')
|
||||
def healthcheck():
|
||||
return {'status': 'OK'}
|
||||
|
||||
@ -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を取得
|
||||
|
||||
@ -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':
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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):
|
||||
"""予期しない例外"""
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from src.model.db.base_db_model import BaseDBModel
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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()
|
||||
)
|
||||
|
||||
@ -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
|
||||
)
|
||||
)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -5,7 +5,7 @@ from pydantic import BaseModel
|
||||
class LoginModel(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
|
||||
|
||||
@classmethod
|
||||
def as_form(
|
||||
cls,
|
||||
|
||||
@ -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 = ""
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
"""
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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('日付テーブルのレコードが存在しません')
|
||||
|
||||
|
||||
@ -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)}'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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'])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user