import { docs_v1, drive_v3, google, sheets_v4 } from "googleapis"; import fs from "fs"; import { CREDENTIALS_PATH, DEBUG, FOLDER_MIMETYPE, LOG_SHEET_HEADER_VALUES, SHEET_MIMETYPE } from "../../serverConfig"; import z from "zod"; const SCOPES = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file"] const MAX_RETRY = 3; export const LogRowDataSchema = z.object({ timestamp: z.string(), meetingDate: z.string(), title: z.string(), matchedCompanyName: z.string(), ownerName: z.string(), meetingUrl: z.string(), documentUrl: z.string(), hubspotUrl: z.string(), }); export type LogRowData = z.infer export const googleDriveController = { getAuth: async (): Promise => { try { const credentials = JSON.parse(process.env.SEARVICE_ACCOUNT_CREDENTIALS || "{}"); console.log(credentials) const auth = await new google.auth.GoogleAuth({ credentials: credentials, scopes: SCOPES, }); if (!auth) return null; return auth; } catch (error) { console.error("Error obtaining Google Auth:", error); return null; } }, getDriveClient: (auth: any): drive_v3.Drive => { // console.log("Google Drive client authenticated."); const drive = google.drive({ version: "v3", auth: auth }); return drive; }, getSheetsClient: (auth: any): sheets_v4.Sheets => { const sheets = google.sheets({ version: "v4", auth: auth }); return sheets; }, getDocsClient: (auth: any): docs_v1.Docs => { const docs = google.docs({ version: "v1", auth: auth }); return docs; }, uploadFile: async (driveClient: drive_v3.Drive, filePath: string, folderId: string, fileName: string): Promise => { try { console.log("Uploading file to Google Drive:", filePath); const response = await driveClient.files.create({ requestBody: { name: fileName, parents: [folderId], }, media: { mimeType: "application/zip", body: fs.createReadStream(filePath), }, }); console.log("File uploaded, Id:", response.data.id); fs.unlinkSync(filePath); return response.data.id; } catch (error) { console.error("Error uploading file:", error); fs.unlinkSync(filePath); return null; } }, getFolderId: async (driveClient: drive_v3.Drive, folderId: string, fileName: string): Promise => { try { const existsFolderId = await googleDriveController.searchFileIdByFileName(driveClient, folderId, fileName); if(existsFolderId) return existsFolderId; console.log('=== Create New Folder ===') const newFolderId = googleDriveController.createNewFile(driveClient, folderId, fileName, FOLDER_MIMETYPE); if(!newFolderId) return null; return newFolderId; } catch (error) { console.error('Error searching files:', error); return null; } }, searchFileIdByFileName: async (driveClient: drive_v3.Drive, folderId: string, fileName: string): Promise => { try { const params = googleDriveController.getSearchFileParamsByDebugMode(folderId); const res = await driveClient.files.list(params); console.log("Files:"); console.log(res.data.files); if(!res.data.files) return null; for(const file of res.data.files) { if(fileName === file.name) { if(!file.id) return null; return file.id; } } return null; } catch (error) { console.error('Error searching files:', error); return null; } }, getSearchFileParamsByDebugMode: (folderId: string): drive_v3.Params$Resource$Files$List => { if(DEBUG) { return { corpora: 'user', q: `'${folderId}' in parents`, pageSize: 10, fields: "files(id, name)", includeItemsFromAllDrives: true, includeTeamDriveItems: true, supportsAllDrives: true } } return { corpora: 'drive', driveId: process.env.GOOGLE_DRIVE_FOLDER_ID, q: `'${folderId}' in parents`, pageSize: 10, fields: "files(id, name)", includeItemsFromAllDrives: true, includeTeamDriveItems: true, supportsAllDrives: true } }, createNewFile: async (driveClient: drive_v3.Drive, folderId: string, fileName: string, mimeType: string): Promise => { try { const requestBody = { name: fileName, parents: [folderId], // 作成したフォルダのIDを指定 mimeType: mimeType, }; const file = await driveClient.files.create({ requestBody, // fields: 'id', }); console.log('File Id:', file.data); if (!file.data.id) return null; return file.data.id; } catch (error) { console.error('Error creating file:', error); return null; } }, // CAUTION deleteFile: async (driveClient: drive_v3.Drive, fileId: string) => { try { const body = { trashed: true } const response = await driveClient.files.update({ fileId: fileId, requestBody: body, }); console.log('File deleted:', response.data); } catch (error) { console.error('Error deleting file:', error); } }, addContentToDocs: async (docsClient: docs_v1.Docs, documentId: string, content: string): Promise => { try { const requestBody: docs_v1.Schema$BatchUpdateDocumentRequest = { requests: [ { insertText: { text: content, location: { index: 1, } } } ] }; const response = await docsClient.documents.batchUpdate({ documentId: documentId, requestBody: requestBody, }); console.log('Content added to document:', response.data); return true; } catch (error) { console.error('Error adding content to document:', error); return false; } }, getLogSheetId: async (driveClient: drive_v3.Drive, sheetsClient: sheets_v4.Sheets, folderId: string, fileName: string): Promise => { try { const existsSheetId = await googleDriveController.searchFileIdByFileName(driveClient, folderId, fileName); if(existsSheetId) return existsSheetId; console.log('=== Create New Sheet ===') const newSheetId = await googleDriveController.createNewFile(driveClient, folderId, fileName, SHEET_MIMETYPE); if(!newSheetId) return null; // await googleDriveController.insertRowToSheet(sheetsClient, newSheetId, ['※シート名変更厳禁']); await googleDriveController.insertRowToSheet(sheetsClient, newSheetId, LOG_SHEET_HEADER_VALUES); return newSheetId; } catch (error) { console.error('Error searching files:', error); return null; } }, insertRowToSheet: async (sheetsClient: sheets_v4.Sheets, sheetId: string, rowData: string[] ): Promise => { try { const body = { values: [rowData] } const params: sheets_v4.Params$Resource$Spreadsheets$Values$Append = { spreadsheetId: sheetId, range: 'Sheet1', valueInputOption: 'USER_ENTERED', insertDataOption: 'INSERT_ROWS', requestBody: body, } await sheetsClient.spreadsheets.values.append(params); return true; } catch (error) { console.log(error); return false; } }, };