100 lines
3.3 KiB
TypeScript
100 lines
3.3 KiB
TypeScript
export const dynamic = 'force-dynamic'
|
|
import { NextResponse } from 'next/server'
|
|
import { google } from 'googleapis'
|
|
import * as fs from 'fs'
|
|
import * as path from 'path'
|
|
|
|
function getAuth() {
|
|
// Service account JSON (inline or from file)
|
|
const saJson = process.env.GOOGLE_SA_JSON
|
|
if (saJson) {
|
|
const sa = JSON.parse(saJson)
|
|
return new google.auth.GoogleAuth({
|
|
credentials: sa,
|
|
scopes: ['https://www.googleapis.com/auth/calendar.readonly'],
|
|
})
|
|
}
|
|
// Fallback: file
|
|
const saPath = path.join(process.cwd(), 'google-sa.json')
|
|
if (fs.existsSync(saPath)) {
|
|
return new google.auth.GoogleAuth({
|
|
keyFile: saPath,
|
|
scopes: ['https://www.googleapis.com/auth/calendar.readonly'],
|
|
})
|
|
}
|
|
return null
|
|
}
|
|
|
|
export async function GET(req: Request) {
|
|
const { searchParams } = new URL(req.url)
|
|
const range = searchParams.get('range') || 'today'
|
|
|
|
const auth = getAuth()
|
|
if (!auth) {
|
|
return NextResponse.json({ events: [], error: 'not_configured' })
|
|
}
|
|
|
|
const daniilCalendarId = process.env.DANIIL_CALENDAR_ID || 'daniilklimov25@gmail.com'
|
|
const svetaCalendarId = process.env.SVETA_CALENDAR_ID || ''
|
|
|
|
const now = new Date()
|
|
let timeMin: string
|
|
let timeMax: string
|
|
|
|
if (range === 'today') {
|
|
timeMin = new Date(now.getFullYear(), now.getMonth(), now.getDate()).toISOString()
|
|
timeMax = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1).toISOString()
|
|
} else if (range === 'week') {
|
|
timeMin = new Date(now.getFullYear(), now.getMonth(), now.getDate()).toISOString()
|
|
timeMax = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 7).toISOString()
|
|
} else {
|
|
timeMin = new Date(now.getFullYear(), now.getMonth(), 1).toISOString()
|
|
timeMax = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59).toISOString()
|
|
}
|
|
|
|
const calendarClient = google.calendar({ version: 'v3', auth: auth as any })
|
|
|
|
const calendars = [
|
|
{ id: daniilCalendarId, owner: 'daniil', color: '#6366f1', name: 'Даниил' },
|
|
...(svetaCalendarId ? [{ id: svetaCalendarId, owner: 'sveta', color: '#ec4899', name: 'Света' }] : [])
|
|
]
|
|
|
|
const results = await Promise.allSettled(
|
|
calendars.map(cal =>
|
|
calendarClient.events.list({
|
|
calendarId: cal.id,
|
|
timeMin,
|
|
timeMax,
|
|
singleEvents: true,
|
|
orderBy: 'startTime',
|
|
maxResults: 100,
|
|
}).then(r => ({ ...cal, events: r.data.items || [] }))
|
|
)
|
|
)
|
|
|
|
const allEvents = results
|
|
.filter(r => r.status === 'fulfilled')
|
|
.flatMap(r => {
|
|
const val = (r as PromiseFulfilledResult<any>).value
|
|
return val.events.map((e: any) => ({
|
|
id: e.id,
|
|
title: e.summary || '(без названия)',
|
|
start: e.start?.dateTime || e.start?.date,
|
|
end: e.end?.dateTime || e.end?.date,
|
|
allDay: !e.start?.dateTime,
|
|
description: e.description || null,
|
|
location: e.location || null,
|
|
owner: val.owner,
|
|
ownerName: val.name,
|
|
color: val.color,
|
|
}))
|
|
})
|
|
.sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime())
|
|
|
|
const errors = results
|
|
.filter(r => r.status === 'rejected')
|
|
.map(r => (r as PromiseRejectedResult).reason?.message || 'unknown')
|
|
|
|
return NextResponse.json({ events: allEvents, errors: errors.length ? errors : undefined, fetchedAt: new Date().toISOString() })
|
|
}
|