# 実消化&アルトマーク Webアプリケーション ## 概要 実消化&アルトマークのWebアプリケーション。 以下の機能を提供する - アルトマークデータ照会(施設・医師) - 生物由来データ照会 - マスターメンテナンス ## 環境情報 - Python 3.9 - MySQL 8.x - FastAPI - PythonのWebアプリケーションフレームワーク - VSCode ## 環境構築 - Pythonの構築 - Merck_NewDWH開発2021のWiki、[Python環境構築](https://nds-tyo.backlog.com/alias/wiki/1874930)を参照 - 「Pipenvの導入」までを行っておくこと - 構築完了後、プロジェクト配下で以下のコマンドを実行し、Pythonの仮想環境を作成する - `pipenv install --python --dev` - この手順で出力される仮想環境のパスは、後述するVSCodeの設定手順で使用するため、控えておく - MySQLの環境構築 - Windowsの場合、以下のリンクからダウンロードする - - Dockerを利用する場合、「newsdwh-tools」リポジトリのMySQL設定を使用すると便利 - 「crm-table-to-ddl」フォルダ内で以下のコマンドを実行すると - `docker-compose up -d` - Dockerの構築手順は、[Dockerのセットアップ手順](https://nds-tyo.backlog.com/alias/wiki/1754332)を参照のこと - データを投入する - 立ち上げたデータベースに「src05」スキーマを作成する - [ローカル開発用データ](https://ndstokyo.sharepoint.com/:f:/r/sites/merck-new-dwh-team/Shared%20Documents/03.NewDWH%E6%A7%8B%E7%AF%89%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA3/02.%E9%96%8B%E7%99%BA/90.%E9%96%8B%E7%99%BA%E5%85%B1%E6%9C%89/%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E9%96%8B%E7%99%BA%E7%94%A8%E3%83%87%E3%83%BC%E3%82%BF?csf=1&web=1&e=VVcRUs)をダウンロードし、mysqlコマンドを使用して復元する - `mysql -h <ホスト名> -P <ポート> -u <ユーザー名> -p src05 < src05_dump.sql` - 環境変数の設定 - 「.env.example」ファイルをコピーし、「.env」ファイルを作成する - 環境変数を設定する。設定内容はPRJメンバーより共有を受けてください - VSCodeの設定 - 「.vscode/recommended_settings.json」ファイルをコピーし、「settings.json」ファイルを作成する - 「python.defaultInterpreterPath」を、Pythonの構築手順で作成した仮想環境のパスに変更する ## 実行 - VSCode上で「F5」キーを押下すると、Webアプリケーションのサーバーが起動する - 「」にアクセスし、ログイン画面が表示されていれば成功 ## フォルダ構成 ```text . ├── Dockerfile -- Dockerイメージを作成するためのファイル ├── Pipfile -- Pythonモジュールの依存関係を管理するファイル ├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル ├── README.md -- 当ファイル └── src -- ソースコードの保管場所 ├── aws -- AWSリソース操作用のコード │   ├── aws_api_client.py │   ├── cognito.py │   └── s3.py ├── controller -- ルーティング層。基本的に1画面1つ │   ├── bio.py │   ├── bio_download.py │   ├── login.py │   ├── logout.py │   └── menu.py ├── core -- APサーバーのコア設定。 │   └── tasks.py -- 起動・終了時に実行するタスクを設定。 ├── data -- 生物由来照会のエクセルファイルテンプレート。 │   └── BioData_template.xlsx ├── db -- データベース関連処理。 │   ├── database.py -- データベース接続、クエリ発行の共通モジュール。 │   ├── sql_condition.py -- SQLの条件式を組み立てるためのモジュール │   └── tasks.py -- coreに渡すタスク。サーバー起動時にDBとの接続モジュールの初期化、終了時にインスタンス破棄を行っている。 ├── depends -- FastAPIの依存性注入(DI)使用するモジュールの置き場。Dependsで利用想定。 │   ├── auth.py -- セッション等の認証関連 │   ├── database.py -- リポジトリ層をコントローラーにDIするためのもの │   └── services.py -- サービス層をコントローラーにDIするためのもの ├── error -- エラー処理関連のモジュール置き場 │   ├── exception_handler.py -- FastAPI内部でエラー発生時のハンドリング │   └── exceptions.py -- カスタム例外クラス ├── main.py -- APサーバーのエントリーポイント。ここでルーターやハンドラーの登録を行う ├── middleware -- ミドルウェアの設定 │ └── middleware.py ├── model -- モデル層(MVCのM) │   ├── db -- リポジトリから返されるDBレコードのモデル │   │   ├── base_db_model.py │   │   ├── bio_sales_view.py │   │   ├── hdke_tbl.py │   │   ├── pharmacy_product_master.py │   │   ├── user_master.py │   │   └── wholesaler_master.py │   ├── jwt_token.py -- 認証用JWTトークンのモデル │   ├── request -- 画面からのリクエストを受け付けるモデル │   │   ├── bio.py │   │   ├── bio_download.py │   │   └── login.py │   ├── session.py -- セッションデータのモデル │   └── view -- ビューモデル。画面に対応したモデル。 │   ├── bio_disp_model.py │   ├── bio_view_model.py │   ├── logout_view_model.py │   ├── mainte_login_view_model.py │   ├── menu_view_model.py │   └── user_view_model.py ├── repositories -- リポジトリ層。DB操作モジュール置き場。 │   ├── base_repository.py │   ├── bio_sales_view_repository.py │   ├── hdke_tbl_repository.py │   ├── pharmacy_product_master_repository.py │   ├── user_master_repository.py │   └── wholesaler_master_repository.py ├── router -- コントローラー層の共通ルーティングの定義 │   └── session_router.py ├── services -- サービス層。ビジネスロジックはできる限りここに押し込む │   ├── base_service.py │   ├── batch_status_service.py │   ├── bio_view_service.py │   ├── login_service.py │   └── session_service.py ├── static -- 静的ファイルの配信ルートディレクトリ │   ├── css │   │   ├── bioStyle.css │   │   ├── datepicker.css │   │   ├── menuStyle.css │   │   └── pagenation.css │   ├── function │   │   └── businessLogicScript.js │   ├── img │   │   ├── icon_modal_confirm.png │   │   └── icon_modal_error.png │   ├── lib │   │   └── fixed_midashi.js │   ├── sample.css │   └── sample.js ├── system_var -- システム変数 │   ├── constants.py -- 定数 │   └── environment.py -- 環境変数 ├── templates -- ビューテンプレートエンジンの格納場所(Jinja2) │   ├── _header.html -- 共通ヘッダー │   ├── _modal.html -- モーダルの部品 │   ├── bioSearchList.html │   ├── logout.html │   ├── maintlogin.html │   ├── menu.html └── util -- ユーティリティ関数置き場 ├── sanitize.py -- モデルクラスのサニタイズを行うデコレータ └── string_util.py -- 文字列操作関連のユーティリティ ``` ## (参考)ファイルの追いかけ方 - APサーバーそのものは「src/main」にある。 - ルーター、例外処理ハンドラ、開始終了タスクの設定、静的ファイルディレクトリのマウントを行っている - URLパスに対する操作の実装は、「controller」フォルダを見る - `@router.xxx`の`xxx`の部分がHTTPメソッドに相当する。このデコレータが付与された関数が、HTTPメソッドを処理するパスオペレーション関数となる - パスオペレーション関数の引数には、リクエストで受け取るパラメータと、その関数内で使用できる依存関係を注入できる - Request型と、Response型の引数は、その名の通り。 - str型, int型などの引数を指定した場合、その引数はクエリストリングを意味する - Dependsで初期値が設定される引数は、Depends関数に渡した関数が処理されてから代入される - たとえば、`get_service`関数にサービスクラスの型を渡すと、get_service関数でサービスクラスのインスタンスを作成して返してくれる - サービスクラスはリポジトリクラスに依存しているので、自分でインスタンスを組み立てる手間が省ける - formやリクエストボディのJSONを受け取る場合、リクエスト用のモデルクラスに「as_form」や「as_body」などの関数を実装し、リクエストを受け取れるようにする - ビジネスロジックは基本的にサービスクラスに押し込む。コントローラーではそのサービスクラスをDependsで依存して利用すること - ビジネスロジックに相当するサービスクラスは「services」フォルダに格納する。共通実装は以下。 - REPOSITORIES定数に、依存するリポジトリクラスを辞書形式で指定する - CLIENTS定数に、依存するAWS APIクライアントクラスを辞書形式で指定する - `__init__`コンストラクタ内で、2つの定数に指定したキーに紐付いたインスタンスが渡ってくるため、インスタンス変数として登録する - あとは、ビジネスロジックにあたる関数を生やしていく - DBへのアクセスを行うリポジトリクラスは「repositories」フォルダに格納する。 - SQL文を用意し、`_db`インスタンス変数のメソッドを利用してクエリを実行する。 - 必要に応じて条件設定をする。条件設定には`SQLCondition`クラスを使用する。 - `BioSalesViewRepository`のやり方が参考になる - リポジトリクラスは、サービスクラスで利用するようにする(そのために、サービスクラス側に依存関係を書いている) - モデルクラスは、「models」フォルダに格納する - HTTPリクエスト用のモデルクラスは「request」フォルダへ - ビュー表示用のモデルクラス(View Model)は「view」フォルダへ - 画面への項目埋め込みや、非表示の制御を行うため、View Modelに値を詰めて、テンプレート側で操作するようにする - DBから取得したレコードのモデルクラスは「db」フォルダへ - 内部処理に利用するモデルクラスは「internal」フォルダへ - 「static」フォルダは、静的ファイルの置き場所 - CSS, JS、画像ファイルを置く。 - 画面の細かな制御は「BusinessLogicScript.js」で行っている。現行からちょこちょこ変える必要がある。 - CSSも、現行は画面ごとに分かれているが、一つのベーススタイルにまとめたい - 「templates」フォルダは、テンプレートエンジンを格納する - 各画面1つのテンプレートエンジンを用意する - 内部で使う変数は、コントローラーで「templates.TemplateResponse」」に詰めて渡す - テンプレート内でincludeする用途のテンプレートは先頭に「_」をつける - `_header.html`は、``タグ内に記載する部品。共通的に読み込むCSS等のファイルを指定する。 - PHPでは分岐などをベタ書きしているが、View Modelに宣言的な関数を用意して、可読性を向上させている。 - コントローラーの共通処理は、「router」フォルダ内のモジュールで実装している - コントローラーのrouter変数が、`router.route_class = AfterSetCookieSessionRoute`となっている場合、レスポンス時、クッキーにセッションキーを登録する動きをする - コントローラーのrouter変数が、`router.route_class = Authenticate`となっている場合、以下の動きをする - リクエスト到達時にセッションの有無をチェックする - レスポンス時、クッキーにセッションキーを登録する ## HTMLで読み込んでいるスクリプトのSRIハッシュ値を生成・設定する方法 ### サブリソース完全性 (Subresource Integrity, SRI) とは CDN などから取得したリソースが意図せず改ざんされていないかをブラウザーが検証するセキュリティ機能です。 SRI を利用する際には、取得したリソースのハッシュ値と一致すべきハッシュ値を指定します。 詳細: 実消化&アルトマークのWebアプリケーションでは、複数の外部スクリプトを読み込んで動作しているため、読み込むスクリプトを変更した場合は、 タグの属性値`integrity`に設定されているスクリプトのハッシュ値を更新する必要がある。 ### SRI ハッシュ値の生成方法(サーバー内のスクリプトについて) - サーバー内に保管されているスクリプトを更新した場合、Linux環境(WSL2でも可)で、以下のコマンドを実行し、ハッシュ値を生成する ```bash cat <更新したスクリプトファイル名> | openssl dgst -sha384 -binary | openssl base64 -A ``` 参考: ### SRI ハッシュ値の生成方法(外部サイトから読み込んでいるスクリプトについて) - 外部サイトから読み込んでいるスクリプトを更新した場合、下記のMDNオンラインツールでハッシュ値を生成する - [SRI Hash Generator](https://www.srihash.org/) ### SRI ハッシュ値の設定方法 - 更新したスクリプトを読み込んでいる箇所の`integrity`属性値を、生成したハッシュ値に置き換える - 以下は設定のサンプル ```bash ```