sales_tool/functions/append-log-to-sheet/source/main.py
2025-11-17 14:21:29 +09:00

267 lines
No EOL
10 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import functions_framework
from google.cloud import secretmanager
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import json
import os
from datetime import datetime, timezone, timedelta
sm_client = secretmanager.SecretManagerServiceClient()
SCOPES = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file"]
HEADER_VALUES = ["タイムスタンプ","商談日", "タイトル", "登録先企業","担当者", "ミーティングURL", "議事録URL", "HubSpot会社概要URL"]
@functions_framework.http
def handle_request(request):
# POSTリクエストの処理
if request.method != 'POST':
return ('', 405, {'Allow': 'POST', 'Content-Type': 'application/json'}) # メソッドがPOSTでない場合は405エラーを返す
"""Shows basic usage of the Drive Activity API.
Prints information about the last 10 events that occured the user's Drive.
"""
try:
request_json = request.get_json()
print(request_json)
title = request_json['title'] # 会議タイトル
document_id = request_json['document_id'] # 議事録ファイルのID
matched_company_id = request_json['matched_company_id'] # マッチした会社ID
matched_company_name = request_json['matched_company_name'] # マッチした会社名
host_name = request_json['host_name'] # ホストユーザー名
video_url = request_json['video_url'] # 会議履歴URL
starts_at = request_json['starts_at'] # 開始日時
log_folder_id = os.getenv("LOG_FOLDER_ID") # 共有ドライブID
meeting_folder_id = os.getenv("MEETING_FOLDER_ID") # ミーティングフォルダID
hubspot_company_url = os.getenv("HUBSPOT_COMPANY_URL") # HubSpotの会社情報URL
mode = os.getenv("MODE") # モードdevまたはprod
service_account_info = get_service_account_info()
# 認証
credentials = get_credentials(service_account_info)
# APIクライアントの構築
drive_service = build("drive", "v3", credentials=credentials)
sheet_service = build("sheets", "v4", credentials=credentials)
# 現在日時をJSTに変換
jst_now = datetime.now(timezone.utc).astimezone(timezone(timedelta(hours=9)))
# JSTの現在日時を文字列に変換
ym_str = jst_now.strftime("%Y%m")
y_str = jst_now.strftime("%Y")
# 年別のフォルダを検索
target_folder = get_directory_files_dev(drive_service, log_folder_id, y_str) if mode == "dev" else get_directory_files_prod(drive_service, meeting_folder_id, log_folder_id, y_str)
print("target_folder", target_folder)
year_folder_id = None
if not target_folder:
# フォルダが存在しない場合は新規作成
year_folder_id = create_new_folder(drive_service, log_folder_id, y_str)
else:
# フォルダが存在する場合はそのIDを使用
year_folder_id = target_folder[0]['id']
print("年別のフォルダID:", year_folder_id)
# スプレッドシートを検索
target_files = get_directory_files_dev(drive_service, year_folder_id, ym_str) if mode == "dev" else get_directory_files_prod(drive_service, meeting_folder_id, year_folder_id, ym_str)
print("スプレッドシート", target_files)
if not target_files:
print('not found')
# スプレッドシートを作成
spreadsheet_id = create_new_spreadsheet(drive_service, year_folder_id, ym_str)
print("スプレッドシートID:", spreadsheet_id)
# 注意事項追加
append_log_to_sheet(sheet_service, spreadsheet_id, ["※シート名変更厳禁"])
# ヘッダーを追加
append_log_to_sheet(sheet_service, spreadsheet_id, HEADER_VALUES)
else:
print('found')
# ファイルIDを取得
spreadsheet_id = target_files[0]['id']
documnet_url = f"https://docs.google.com/document/d/{document_id}/edit" if document_id else ""
hubspot_url = f"{hubspot_company_url}/{matched_company_id}" if matched_company_id else ""
# テストログを追加
row_data = [jst_now.strftime("%Y-%m-%d %H:%M:%S"),
convert_to_jst_ymd(starts_at),
title,
matched_company_name,
host_name,
video_url,
documnet_url,
hubspot_url
]
append_log_to_sheet(sheet_service, spreadsheet_id, row_data)
print("ログを追加しました:", row_data)
return (json.dumps({"status": "success"}, ensure_ascii=False), 200, {"Content-Type": "application/json"})
except HttpError as error:
# TODO(developer) - Handleerrors from drive activity API.
print(f"An error occurred: {error}")
#
# SecretManagerから秘密鍵を取得
#
def get_service_account_info():
key_path = os.getenv('KEY_PATH') + "/versions/1"
# 秘密鍵取得
response = sm_client.access_secret_version(name=key_path)
# 秘密鍵の値をデコード
secret_key = response.payload.data.decode("UTF-8")
return json.loads(secret_key)
# Google Drive認証
def get_credentials(service_account_info):
credentials = service_account.Credentials.from_service_account_info(
service_account_info,
scopes=SCOPES
)
return credentials
# 開発用マイドライブからのファイルを取得
def get_directory_files_dev(service,shared_folder_id, filename):
"""
対象のディレクトリ配下からファイル名で検索した結果を配列で返す
:param filename: ファイル名
:param directory_id: ディレクトリID
:param pages_max: 最大ページ探索数
:return: ファイルリスト
"""
items = []
page = 0
pages_max = 10 # 最大ページ数
while True:
page += 1
if page == pages_max:
break
results = service.files().list(
corpora="user",
includeItemsFromAllDrives=True,
includeTeamDriveItems=True,
q=f"'{shared_folder_id}' in parents and name = '{filename}' and trashed = false",
supportsAllDrives=True,
pageSize=10,
fields="nextPageToken, files(id, name)").execute()
items += results.get("files", [])
page_token = results.get('nextPageToken', None)
if page_token is None:
break
return items
# 本番用共有ドライブからのファイルを取得
def get_directory_files_prod(service,shared_folder_id,sub_folder_id,filename):
"""
対象のディレクトリ配下からファイル名で検索した結果を配列で返す
:param filename: ファイル名
:param directory_id: ディレクトリID
:param pages_max: 最大ページ探索数
:return: ファイルリスト
"""
items = []
page = 0
pages_max = 10 # 最大ページ数
while True:
page += 1
if page == pages_max:
break
results = service.files().list(
corpora="drive",
driveId=shared_folder_id,
includeItemsFromAllDrives=True,
includeTeamDriveItems=True,
q=f"'{sub_folder_id}' in parents and name = '{filename}' and trashed = false",
supportsAllDrives=True,
pageSize=10,
fields="nextPageToken, files(id, name, parents)").execute()
items += results.get("files", [])
page_token = results.get('nextPageToken', None)
if page_token is None:
break
return items
def create_new_folder(service, sub_folder_id, title):
"""
Google Drive APIを使用して新しいフォルダを作成する
:param service: Google Drive APIのサービスオブジェクト
:param title: フォルダのタイトル
:return: 作成したフォルダのID
"""
file_metadata = {
"name": title,
"parents": [sub_folder_id], # 共有ドライブのIDを指定
"mimeType": "application/vnd.google-apps.folder",
}
result = service.files().create(body=file_metadata, fields="id", supportsAllDrives=True).execute()
return result.get('id')
def create_new_spreadsheet(service,folder_id,title):
"""
Google Sheets APIを使用して新しいスプレッドシートを作成する
:param service: Google Sheets APIのサービスオブジェクト
:param title: スプレッドシートのタイトル
:return: 作成したスプレッドシートのID
"""
file_metadata = {
'name': title,
'parents': [folder_id], # 作成したフォルダのIDを指定
'mimeType': 'application/vnd.google-apps.spreadsheet',
}
result = (
service.files()
.create(body=file_metadata, fields="id", supportsAllDrives=True)
.execute()
)
return result.get("id")
def append_log_to_sheet(service, spreadsheet_id, row_data):
"""
Google Sheets APIを使用してスプレッドシートにログを追加する
:param service: Google Sheets APIのサービスオブジェクト
:param spreadsheet_id: スプレッドシートのID
:param row_data: 追加するログデータ(リスト形式)
"""
body = {
'values': [row_data]
}
# スプレッドシートにログを追加
result = service.spreadsheets().values().append(
spreadsheetId=spreadsheet_id,
range='Sheet1',
valueInputOption="USER_ENTERED",
insertDataOption='INSERT_ROWS',
body=body,
).execute()
print(f"{result.get('updates').get('updatedCells')} cells appended.")
def convert_to_jst_ymd(starts_at):
"""
開始日時をYYYY年MM月DD日形式に変換する
:param starts_at: 開始日時の文字列
:return: YYYY年MM月DD日形式の文字列
"""
# 開始日時をUTCからJSTに変換
dt = datetime.fromisoformat(starts_at.replace("Z", "+00:00")).astimezone(timezone(timedelta(hours=9)))
# YYYY年MM月DD日形式に変換
return dt.strftime("%Y年%m月%d")