import { queryOne, execute } from '../../utils/db' import { requireAuth } from '../../utils/session' /** * 구글 그룹 메시지 조회 * GET /api/google-group/messages * * Gmail API로 그룹 이메일 조회 * * Query params: * - groupEmail: 그룹 이메일 주소 (예: dev-team@company.com) * - maxResults: 최대 결과 수 (기본 20) * - after: 이 날짜 이후 메시지 (YYYY-MM-DD) */ export default defineEventHandler(async (event) => { const session = await requireAuth(event) const query = getQuery(event) const groupEmail = query.groupEmail as string const maxResults = parseInt(query.maxResults as string) || 20 const after = query.after as string if (!groupEmail) { throw createError({ statusCode: 400, message: '그룹 이메일이 필요합니다.' }) } // 사용자의 Google 토큰 조회 const employee = await queryOne(` SELECT google_access_token, google_refresh_token, google_token_expires_at FROM wr_employee_info WHERE employee_id = $1 `, [session.employeeId]) if (!employee?.google_access_token) { throw createError({ statusCode: 401, message: 'Google 계정이 연결되지 않았습니다.' }) } let accessToken = employee.google_access_token // 토큰 만료 확인 및 갱신 if (employee.google_token_expires_at && new Date(employee.google_token_expires_at) < new Date()) { accessToken = await refreshGoogleToken(session.employeeId, employee.google_refresh_token) } try { // Gmail API로 그룹 메일 검색 let searchQuery = `list:${groupEmail}` if (after) { searchQuery += ` after:${after}` } const listResponse = await $fetch('https://gmail.googleapis.com/gmail/v1/users/me/messages', { headers: { 'Authorization': `Bearer ${accessToken}` }, query: { q: searchQuery, maxResults: maxResults } }) if (!listResponse.messages || listResponse.messages.length === 0) { return { messages: [], total: 0 } } // 각 메시지의 상세 정보 조회 const messages = await Promise.all( listResponse.messages.slice(0, maxResults).map(async (msg: any) => { const detail = await $fetch(`https://gmail.googleapis.com/gmail/v1/users/me/messages/${msg.id}`, { headers: { 'Authorization': `Bearer ${accessToken}` }, query: { format: 'metadata', metadataHeaders: ['Subject', 'From', 'Date', 'To'] } }) const headers = detail.payload?.headers || [] const getHeader = (name: string) => headers.find((h: any) => h.name === name)?.value || '' return { id: msg.id, threadId: msg.threadId, subject: getHeader('Subject'), from: getHeader('From'), to: getHeader('To'), date: getHeader('Date'), snippet: detail.snippet } }) ) return { messages, total: listResponse.resultSizeEstimate || messages.length } } catch (e: any) { console.error('Gmail API error:', e) if (e.status === 403) { throw createError({ statusCode: 403, message: 'Gmail 접근 권한이 없습니다. Google 로그인 시 권한을 허용해주세요.' }) } throw createError({ statusCode: 500, message: '그룹 메시지를 가져오는데 실패했습니다.' }) } }) /** * Google 토큰 갱신 */ async function refreshGoogleToken(employeeId: number, refreshToken: string): Promise { const config = useRuntimeConfig() const response = await $fetch('https://oauth2.googleapis.com/token', { method: 'POST', body: new URLSearchParams({ client_id: config.googleClientId, client_secret: config.googleClientSecret, refresh_token: refreshToken, grant_type: 'refresh_token' }).toString(), headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) if (response.access_token) { await execute(` UPDATE wr_employee_info SET google_access_token = $1, google_token_expires_at = NOW() + INTERVAL '${response.expires_in} seconds' WHERE employee_id = $2 `, [response.access_token, employeeId]) return response.access_token } throw new Error('토큰 갱신 실패') }