diff --git a/src/app/api/webhooks/whatsapp/route.ts b/src/app/api/webhooks/whatsapp/route.ts index 5a71a79..a60bd5a 100644 --- a/src/app/api/webhooks/whatsapp/route.ts +++ b/src/app/api/webhooks/whatsapp/route.ts @@ -48,7 +48,13 @@ export async function POST(req: Request) { // Ignorar mensajes generados por el bot para evitar bucle infinito, // pero permitir tests que el administrador envíe desde el mismo celular del bot. - if (fromMe && (rawText.includes('📰 *Publicación Procesada') || rawText.includes('✅ La publicación ha sido aprobada') || rawText.includes('❌ Error al publicar'))) { + if (fromMe && ( + rawText.includes('SOLICITUD DE APROBACIÓN') || + rawText.includes('Publicación Procesada') || + rawText.includes('PUBLICACIÓN APROBADA') || + rawText.includes('PUBLICACIÓN RECHAZADA') || + rawText.includes('Error al publicar') + )) { return NextResponse.json({ success: true, message: 'Ignored bot self-message loop' }, { status: 200 }); } @@ -72,7 +78,7 @@ export async function POST(req: Request) { console.log(`[WhatsApp Webhook] Chat autorizado detectado: "${filterResult.resolvedName}" (JID: ${remoteJid})`); - // Extraer texto del mensaje (ya guardado en rawText, lo mantenemos como text para retrocompatibilidad interna) + // Extraer texto del mensaje const text = rawText; const lowerText = text.trim().toLowerCase(); @@ -82,27 +88,71 @@ export async function POST(req: Request) { const { databases, storage } = await createAdminClient(); - // LOGIC 1: APROBAR PUBLICACIÓN - if (isReply && lowerText.includes('aprobar')) { - // Extraer ID de la referencia en el mensaje del bot - const refMatch = quotedText.match(/Ref:\s*([a-zA-Z0-9_-]+)/); - if (refMatch && refMatch[1]) { - const postId = refMatch[1]; + // LOGIC 1: RESPUESTA DE APROBACIÓN O RECHAZO + const isApprovalWord = lowerText.includes('aprobar') || lowerText.includes('publicar') || lowerText === 'si' || lowerText === 'sí' || lowerText === 'ok'; + const isRejectionWord = lowerText.includes('rechazar') || lowerText.includes('descartar') || lowerText.includes('cancelar') || lowerText === 'no'; + if (isApprovalWord || isRejectionWord) { + // Intentar extraer el ID de la referencia en el mensaje citado o en el texto + let postId: string | null = null; + const refMatch = quotedText.match(/Ref:\s*([a-zA-Z0-9_-]+)/) || rawText.match(/Ref:\s*([a-zA-Z0-9_-]+)/); + if (refMatch && refMatch[1]) { + postId = refMatch[1]; + } else { + // Fallback: buscar el borrador más reciente try { - // Actualizar Appwrite - await databases.updateDocument( + const drafts = await databases.listDocuments( APPWRITE_ALMEIRA_CONFIG.databaseId, APPWRITE_ALMEIRA_CONFIG.collections.posts, - postId, - { estado: 'publicado' } + [ + Query.equal('estado', 'borrador'), + Query.orderDesc('$createdAt'), + Query.limit(1) + ] ); + if (drafts.documents.length > 0) { + postId = drafts.documents[0].$id; + } + } catch (e) { + console.warn('No se pudo consultar el borrador más reciente:', e); + } + } - await sendWhatsAppMessage(remoteJid, `✅ La publicación ha sido aprobada y publicada exitosamente.\n(ID: ${postId})`); - return NextResponse.json({ success: true, message: 'Post aprobado' }, { status: 200 }); + if (postId) { + try { + if (isApprovalWord) { + const updatedPost = await databases.updateDocument( + APPWRITE_ALMEIRA_CONFIG.databaseId, + APPWRITE_ALMEIRA_CONFIG.collections.posts, + postId, + { estado: 'publicado' } + ); + + const approvalMsg = `✅ *¡PUBLICACIÓN APROBADA Y EN VIVO!*\n\n` + + `📌 *${updatedPost.titulo}*\n` + + `🌐 *Ver en el portal:* https://almeira.com.co/${updatedPost.slug}\n\n` + + `(ID: ${postId})`; + + await sendWhatsAppMessage(remoteJid, approvalMsg); + return NextResponse.json({ success: true, message: 'Post aprobado y publicado' }, { status: 200 }); + } else if (isRejectionWord) { + await databases.updateDocument( + APPWRITE_ALMEIRA_CONFIG.databaseId, + APPWRITE_ALMEIRA_CONFIG.collections.posts, + postId, + { estado: 'archivado' } + ); + + const rejectionMsg = `🚫 *PUBLICACIÓN RECHAZADA*\n\n` + + `El borrador ha sido descartado y no será publicado en Almeira Web.\n\n` + + `(ID: ${postId})`; + + await sendWhatsAppMessage(remoteJid, rejectionMsg); + return NextResponse.json({ success: true, message: 'Post rechazado y archivado' }, { status: 200 }); + } } catch (e: any) { - console.error("Error approving post:", e); - await sendWhatsAppMessage(remoteJid, `❌ Error al publicar: ${e.message}`); + console.error('Error al actualizar estado del post:', e); + await sendWhatsAppMessage(remoteJid, `❌ Error al procesar tu decisión: ${e.message}`); return NextResponse.json({ success: false, error: e.message }, { status: 500 }); } } @@ -244,22 +294,27 @@ export async function POST(req: Request) { } ); - // Notificar al grupo de WhatsApp pidiendo aprobación + // Notificar al grupo de WhatsApp pidiendo aprobación explícita let imageNotice = ''; if (candidateMediaList.length > 1) { const chosenNum = (parsed.selected_image_index ?? 0) + 1; - imageNotice = `*Imagen Destacada:* Foto #${chosenNum} de ${candidateMediaList.length} analizadas` + imageNotice = `🖼️ *Imagen Destacada:* Foto #${chosenNum} de ${candidateMediaList.length} analizadas` + (parsed.image_selection_reason ? ` (${parsed.image_selection_reason})\n` : '\n'); } else if (candidateMediaList.length === 1) { - imageNotice = `*Imagen Destacada:* 1 foto procesada (${isSquare ? 'Formato 640x640' : 'Formato 640x360'})\n`; + imageNotice = `🖼️ *Imagen Destacada:* 1 foto procesada (${isSquare ? 'Formato 640x640' : 'Formato 640x360'})\n`; } - const requestText = `📰 *Publicación Procesada (Pendiente de Aprobación)*\n\n` - + `*Título:* ${parsed.titulo}\n` - + `*Tipo:* ${parsed.tipo.toUpperCase()} (${isSquare ? 'Cuadrado 640x640' : 'Panorámico 640x360'})\n` + const requestText = `🔔 *SOLICITUD DE APROBACIÓN DE PUBLICACIÓN* 🔔\n` + + `_Almeira Web • Asistente Editorial con IA_\n\n` + + `📌 *Título:* ${parsed.titulo}\n` + + `📂 *Categoría:* ${parsed.tipo.toUpperCase()} (${isSquare ? 'Cuadrado 640x640' : 'Panorámico 640x360'})\n` + (imageNotice ? `${imageNotice}` : '') - + `*SEO:* ${parsed.seo_descripcion}\n\n` - + `Para aprobar esta publicación, responde a este mismo mensaje con la palabra "Aprobar".\n\n` + + `📝 *Resumen:* ${parsed.seo_descripcion}\n\n` + + `━━━━━━━━━━━━━━━━━━━━━━\n` + + `¿Autorizas la publicación en el portal?\n\n` + + `👉 Responde a este mensaje con:\n` + + `✅ *Aprobar* (para publicar en vivo en la web)\n` + + `❌ *Rechazar* (para descartar el borrador)\n\n` + `(Ref: ${newPost.$id})`; await sendWhatsAppMessage(remoteJid, requestText);