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>
50 lines
1.5 KiB
TypeScript
50 lines
1.5 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
||
import prisma from '@/lib/prisma'
|
||
import { gmailScannerService } from '@/lib/integrations/gmail-scanner.service'
|
||
|
||
export const dynamic = 'force-dynamic'
|
||
|
||
function authorize(request: NextRequest): boolean {
|
||
const cronSecret = process.env.CRON_SECRET
|
||
if (!cronSecret) return false
|
||
const authHeader = request.headers.get('authorization')
|
||
const bearer = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : null
|
||
return bearer === cronSecret
|
||
}
|
||
|
||
/** POST /api/cron/gmail — scan Gmail for connected users (1×/jour en prod via entrypoint) */
|
||
export async function POST(request: NextRequest) {
|
||
if (!authorize(request)) {
|
||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||
}
|
||
|
||
const users = await prisma.userAISettings.findMany({
|
||
select: { userId: true, integrationTokens: true },
|
||
take: 200,
|
||
})
|
||
|
||
const connected = users.filter(u => {
|
||
if (!u.integrationTokens) return false
|
||
try {
|
||
const meta = typeof u.integrationTokens === 'string'
|
||
? JSON.parse(u.integrationTokens)
|
||
: u.integrationTokens
|
||
return !!(meta?.gmailAccessToken && meta?.gmailRefreshToken)
|
||
} catch {
|
||
return false
|
||
}
|
||
})
|
||
|
||
let totalCreated = 0
|
||
for (const row of connected) {
|
||
try {
|
||
const { created } = await gmailScannerService.scanUser(row.userId)
|
||
totalCreated += created
|
||
} catch (err) {
|
||
console.error('[CronGmail]', row.userId, err)
|
||
}
|
||
}
|
||
|
||
return NextResponse.json({ success: true, users: connected.length, notesCreated: totalCreated })
|
||
}
|