Briefing granulaire, pistes rapides puis enrichissement async, layout persisté v5, suggestions agents, intégration Gmail et navigation sidebar alignée sur /home. Co-authored-by: Cursor <cursoragent@cursor.com>
39 lines
1.4 KiB
TypeScript
39 lines
1.4 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { getGoogleOAuthCredentials, readIntegrationMeta, writeIntegrationMeta } from '@/lib/integrations/google-integration-tokens'
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const url = new URL(req.url)
|
|
const code = url.searchParams.get('code')
|
|
const userId = url.searchParams.get('state')
|
|
const error = url.searchParams.get('error')
|
|
|
|
if (error || !code || !userId) {
|
|
return NextResponse.redirect(`${url.origin}/settings/integrations?error=gmail_auth_failed`)
|
|
}
|
|
|
|
const { clientId, clientSecret } = getGoogleOAuthCredentials()
|
|
const tokenRes = await fetch('https://oauth2.googleapis.com/token', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: new URLSearchParams({
|
|
client_id: clientId,
|
|
client_secret: clientSecret,
|
|
code,
|
|
redirect_uri: `${url.origin}/api/integrations/gmail/callback`,
|
|
grant_type: 'authorization_code',
|
|
}),
|
|
})
|
|
|
|
const tokenData = await tokenRes.json()
|
|
if (!tokenData.access_token) {
|
|
return NextResponse.redirect(`${url.origin}/settings/integrations?error=gmail_token_failed`)
|
|
}
|
|
|
|
const meta = await readIntegrationMeta(userId)
|
|
meta.gmailAccessToken = tokenData.access_token
|
|
if (tokenData.refresh_token) meta.gmailRefreshToken = tokenData.refresh_token
|
|
await writeIntegrationMeta(userId, meta)
|
|
|
|
return NextResponse.redirect(`${url.origin}/settings/integrations?connected=gmail`)
|
|
}
|