fix(monitoring): lista negra estricta e ignorado permanente de grupos ajenos, eliminacion de productos no calzado y proteccion en webhook
This commit is contained in:
parent
02bac37af0
commit
31130bfbb5
@ -82,7 +82,20 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isGroupIgnored = (jid: string, name?: string): boolean => {
|
||||||
|
if (!jid) return false;
|
||||||
|
if (jid === '120363400148850031@g.us' || jid === '120363420942364759@g.us') return true;
|
||||||
|
if (name && /black diamonds|team emporio|emporio/i.test(name)) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const handleToggleSelectJid = (jid: string) => {
|
const handleToggleSelectJid = (jid: string) => {
|
||||||
|
const grp = liveGroups.find((g) => g.jid === jid);
|
||||||
|
if (grp && isGroupIgnored(grp.jid, grp.name)) {
|
||||||
|
setToast(`⛔ El grupo "${grp.name}" está excluido permanentemente y no puede seleccionarse.`);
|
||||||
|
setTimeout(() => setToast(null), 4000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setSelectedJids((prev) => {
|
setSelectedJids((prev) => {
|
||||||
const next = new Set(prev);
|
const next = new Set(prev);
|
||||||
if (next.has(jid)) next.delete(jid);
|
if (next.has(jid)) next.delete(jid);
|
||||||
@ -94,7 +107,11 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
const handleSelectAllFiltered = (filtered: MonitoredWhatsAppGroup[]) => {
|
const handleSelectAllFiltered = (filtered: MonitoredWhatsAppGroup[]) => {
|
||||||
setSelectedJids((prev) => {
|
setSelectedJids((prev) => {
|
||||||
const next = new Set(prev);
|
const next = new Set(prev);
|
||||||
filtered.forEach((g) => next.add(g.jid));
|
filtered.forEach((g) => {
|
||||||
|
if (!isGroupIgnored(g.jid, g.name)) {
|
||||||
|
next.add(g.jid);
|
||||||
|
}
|
||||||
|
});
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -108,9 +125,10 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
try {
|
try {
|
||||||
const updatedGroups: MonitoredWhatsAppGroup[] = liveGroups.map((lg) => ({
|
const updatedGroups: MonitoredWhatsAppGroup[] = liveGroups.map((lg) => ({
|
||||||
...lg,
|
...lg,
|
||||||
isMonitored: selectedJids.has(lg.jid),
|
isMonitored: !isGroupIgnored(lg.jid, lg.name) && selectedJids.has(lg.jid),
|
||||||
autoPublish: true,
|
autoPublish: !isGroupIgnored(lg.jid, lg.name),
|
||||||
profitMarginOverride: 35,
|
profitMarginOverride: 35,
|
||||||
|
notes: isGroupIgnored(lg.jid, lg.name) ? 'IGNORADO EXPLICITAMENTE' : lg.notes,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const res = await fetch('/api/whatsapp-groups', {
|
const res = await fetch('/api/whatsapp-groups', {
|
||||||
@ -134,6 +152,12 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleToggleGroup = async (group: MonitoredWhatsAppGroup) => {
|
const handleToggleGroup = async (group: MonitoredWhatsAppGroup) => {
|
||||||
|
if (isGroupIgnored(group.jid, group.name)) {
|
||||||
|
setToast(`⛔ El grupo "${group.name}" está en la lista de exclusión (ignorado permanente) y no puede ser monitoreado.`);
|
||||||
|
setTimeout(() => setToast(null), 4500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const nextState = !group.isMonitored;
|
const nextState = !group.isMonitored;
|
||||||
const updatedList = groups.map((g) =>
|
const updatedList = groups.map((g) =>
|
||||||
g.jid === group.jid || g.id === group.id ? { ...g, isMonitored: nextState } : g
|
g.jid === group.jid || g.id === group.id ? { ...g, isMonitored: nextState } : g
|
||||||
@ -329,12 +353,15 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
) : (
|
) : (
|
||||||
filteredGroups.map((group) => {
|
filteredGroups.map((group) => {
|
||||||
const isMonitored = group.isMonitored;
|
const isMonitored = group.isMonitored;
|
||||||
|
const isIgnored = isGroupIgnored(group.jid, group.name);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={group.id || group.jid}
|
key={group.id || group.jid}
|
||||||
className={`p-5 rounded-3xl border transition-all space-y-4 ${
|
className={`p-5 rounded-3xl border transition-all space-y-4 ${
|
||||||
isMonitored
|
isIgnored
|
||||||
|
? 'bg-neutral-950/80 border-rose-900/40 opacity-70'
|
||||||
|
: isMonitored
|
||||||
? 'bg-gradient-to-br from-neutral-900 to-neutral-900/90 border-purple-500/40 shadow-lg shadow-purple-950/20 ring-1 ring-purple-500/20'
|
? 'bg-gradient-to-br from-neutral-900 to-neutral-900/90 border-purple-500/40 shadow-lg shadow-purple-950/20 ring-1 ring-purple-500/20'
|
||||||
: 'bg-neutral-900/60 border-neutral-800 hover:border-neutral-700 opacity-80'
|
: 'bg-neutral-900/60 border-neutral-800 hover:border-neutral-700 opacity-80'
|
||||||
}`}
|
}`}
|
||||||
@ -342,15 +369,20 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<span
|
<span
|
||||||
className={`w-2.5 h-2.5 rounded-full shrink-0 ${
|
className={`w-2.5 h-2.5 rounded-full shrink-0 ${
|
||||||
isMonitored ? 'bg-purple-400 animate-pulse' : 'bg-neutral-600'
|
isIgnored ? 'bg-rose-500' : isMonitored ? 'bg-purple-400 animate-pulse' : 'bg-neutral-600'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<h3 className="font-black text-white text-sm leading-snug line-clamp-1">
|
<h3 className="font-black text-white text-sm leading-snug line-clamp-1">
|
||||||
{group.name}
|
{group.name}
|
||||||
</h3>
|
</h3>
|
||||||
|
{isIgnored && (
|
||||||
|
<span className="bg-rose-500/20 text-rose-300 border border-rose-500/30 text-[9px] font-black px-2 py-0.5 rounded-full uppercase tracking-wider">
|
||||||
|
⛔ Ignorado
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[11px] font-mono text-neutral-400 pl-4 mt-0.5 truncate">
|
<p className="text-[11px] font-mono text-neutral-400 pl-4 mt-0.5 truncate">
|
||||||
{group.jid}
|
{group.jid}
|
||||||
@ -360,13 +392,21 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
{/* Toggle Switch */}
|
{/* Toggle Switch */}
|
||||||
<button
|
<button
|
||||||
onClick={() => handleToggleGroup(group)}
|
onClick={() => handleToggleGroup(group)}
|
||||||
className={`shrink-0 text-xs font-bold px-3 py-1.5 rounded-xl border flex items-center gap-1.5 transition-all cursor-pointer ${
|
disabled={isIgnored}
|
||||||
isMonitored
|
className={`shrink-0 text-xs font-bold px-3 py-1.5 rounded-xl border flex items-center gap-1.5 transition-all ${
|
||||||
? 'bg-purple-600 text-white border-purple-400 shadow-md font-black'
|
isIgnored
|
||||||
: 'bg-neutral-800 text-neutral-400 border-neutral-700 hover:text-white'
|
? 'bg-rose-950/40 text-rose-400 border-rose-900/50 cursor-not-allowed'
|
||||||
|
: isMonitored
|
||||||
|
? 'bg-purple-600 text-white border-purple-400 shadow-md font-black cursor-pointer'
|
||||||
|
: 'bg-neutral-800 text-neutral-400 border-neutral-700 hover:text-white cursor-pointer'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isMonitored ? (
|
{isIgnored ? (
|
||||||
|
<>
|
||||||
|
<XCircle className="w-3.5 h-3.5" />
|
||||||
|
<span>Bloqueado</span>
|
||||||
|
</>
|
||||||
|
) : isMonitored ? (
|
||||||
<>
|
<>
|
||||||
<CheckCircle2 className="w-3.5 h-3.5 fill-white text-purple-600" />
|
<CheckCircle2 className="w-3.5 h-3.5 fill-white text-purple-600" />
|
||||||
<span>Monitoreando</span>
|
<span>Monitoreando</span>
|
||||||
@ -500,22 +540,27 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
filteredPickerGroups.map((group) => {
|
filteredPickerGroups.map((group) => {
|
||||||
const isSelected = selectedJids.has(group.jid);
|
const isIgnored = isGroupIgnored(group.jid, group.name);
|
||||||
|
const isSelected = !isIgnored && selectedJids.has(group.jid);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={group.jid}
|
key={group.jid}
|
||||||
onClick={() => handleToggleSelectJid(group.jid)}
|
onClick={() => !isIgnored && handleToggleSelectJid(group.jid)}
|
||||||
className={`p-3.5 rounded-2xl border transition-all cursor-pointer flex items-center justify-between gap-3 ${
|
className={`p-3.5 rounded-2xl border transition-all flex items-center justify-between gap-3 ${
|
||||||
isSelected
|
isIgnored
|
||||||
? 'bg-purple-950/30 border-purple-500/50 shadow-md ring-1 ring-purple-500/20'
|
? 'bg-neutral-950/60 border-rose-950/60 opacity-60 cursor-not-allowed'
|
||||||
: 'bg-neutral-950 border-neutral-800 hover:border-neutral-700'
|
: isSelected
|
||||||
|
? 'bg-purple-950/30 border-purple-500/50 shadow-md ring-1 ring-purple-500/20 cursor-pointer'
|
||||||
|
: 'bg-neutral-950 border-neutral-800 hover:border-neutral-700 cursor-pointer'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-3 flex-1 min-w-0">
|
<div className="flex items-center space-x-3 flex-1 min-w-0">
|
||||||
<div
|
<div
|
||||||
className={`w-5 h-5 rounded-lg border flex items-center justify-center shrink-0 transition-all ${
|
className={`w-5 h-5 rounded-lg border flex items-center justify-center shrink-0 transition-all ${
|
||||||
isSelected
|
isIgnored
|
||||||
|
? 'bg-neutral-900 border-neutral-800 text-neutral-600'
|
||||||
|
: isSelected
|
||||||
? 'bg-purple-600 border-purple-400 text-white'
|
? 'bg-purple-600 border-purple-400 text-white'
|
||||||
: 'border-neutral-700 bg-neutral-900'
|
: 'border-neutral-700 bg-neutral-900'
|
||||||
}`}
|
}`}
|
||||||
@ -524,8 +569,13 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h4 className="font-bold text-white text-xs truncate">
|
<h4 className="font-bold text-white text-xs truncate flex items-center gap-1.5">
|
||||||
{group.name}
|
<span>{group.name}</span>
|
||||||
|
{isIgnored && (
|
||||||
|
<span className="bg-rose-500/20 text-rose-300 border border-rose-500/30 text-[9px] font-black px-1.5 py-0.2 rounded-full uppercase">
|
||||||
|
⛔ Ignorado
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</h4>
|
</h4>
|
||||||
<p className="text-[10px] font-mono text-neutral-400 truncate">
|
<p className="text-[10px] font-mono text-neutral-400 truncate">
|
||||||
{group.jid}
|
{group.jid}
|
||||||
@ -534,7 +584,11 @@ export default function AdminWhatsAppGroupsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="shrink-0 flex items-center gap-2">
|
<div className="shrink-0 flex items-center gap-2">
|
||||||
{isSelected ? (
|
{isIgnored ? (
|
||||||
|
<span className="bg-rose-950/40 text-rose-400 border border-rose-900/50 text-[10px] font-bold px-2 py-0.5 rounded-full">
|
||||||
|
Bloqueado
|
||||||
|
</span>
|
||||||
|
) : isSelected ? (
|
||||||
<span className="bg-emerald-500/20 text-emerald-300 border border-emerald-500/30 text-[10px] font-black px-2 py-0.5 rounded-full uppercase">
|
<span className="bg-emerald-500/20 text-emerald-300 border border-emerald-500/30 text-[10px] font-black px-2 py-0.5 rounded-full uppercase">
|
||||||
Monitorear
|
Monitorear
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { dataService } from '@/lib/data-service';
|
import { dataService, isGroupIgnoredOrBlacklisted } from '@/lib/data-service';
|
||||||
import { parseSupplierMessage, detectCategory } from '@/lib/gemini-parser';
|
import { parseSupplierMessage, detectCategory } from '@/lib/gemini-parser';
|
||||||
import { sanitizePublicationTitle } from '@/lib/sanitizer';
|
import { sanitizePublicationTitle } from '@/lib/sanitizer';
|
||||||
import { generateAttractiveProductCopy } from '@/lib/attractive-copy';
|
import { generateAttractiveProductCopy } from '@/lib/attractive-copy';
|
||||||
@ -14,6 +14,7 @@ import {
|
|||||||
} from '@/lib/evolution-api';
|
} from '@/lib/evolution-api';
|
||||||
import {
|
import {
|
||||||
getMonitoredGroupsFromAppwrite,
|
getMonitoredGroupsFromAppwrite,
|
||||||
|
saveMonitoredGroupToAppwrite,
|
||||||
saveProductToAppwrite,
|
saveProductToAppwrite,
|
||||||
saveSupplierPostToAppwrite,
|
saveSupplierPostToAppwrite,
|
||||||
updateSupplierPostStatusInAppwrite,
|
updateSupplierPostStatusInAppwrite,
|
||||||
@ -238,7 +239,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// CASO B: GRUPOS MAYORISTAS DE PROVEEDORES (Publicación Automática Incondicional)
|
// CASO B: GRUPOS MAYORISTAS DE PROVEEDORES (Monitoreo Estricto por Lista Blanca)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Resolver el nombre del grupo de forma precisa usando Evolution API si no viene en el payload
|
// Resolver el nombre del grupo de forma precisa usando Evolution API si no viene en el payload
|
||||||
let groupSubject = data.groupInfo?.subject || data.chatName || '';
|
let groupSubject = data.groupInfo?.subject || data.chatName || '';
|
||||||
@ -255,6 +256,17 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0. LISTA NEGRA PERMANENTE DE GRUPOS IGNORADOS (Blacklist incondicional)
|
||||||
|
if (isGroupIgnoredOrBlacklisted(remoteJid, groupSubject)) {
|
||||||
|
console.log(`[DripZone Webhook] Grupo IGNORADO por lista negra: "${groupSubject}" (${remoteJid})`);
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
ignored: 'Grupo en lista negra comercial permanente (no monitorear ni publicar)',
|
||||||
|
chat: groupSubject,
|
||||||
|
remoteJid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 1. FILTRAR EXCLUSIVAMENTE GRUPOS DE PRENSA Y GOBIERNO (Reenviar a portal de noticias Almeira)
|
// 1. FILTRAR EXCLUSIVAMENTE GRUPOS DE PRENSA Y GOBIERNO (Reenviar a portal de noticias Almeira)
|
||||||
const isNonProductNews = /gob cauca|gobernacion|alcaldia|prensa|medios|noticias|comunicaciones|sedes asociadas|notificaciones almeira|inelpac|meliextra|almeira producciones|publicaciones almeira|quilichao en medios/i.test(
|
const isNonProductNews = /gob cauca|gobernacion|alcaldia|prensa|medios|noticias|comunicaciones|sedes asociadas|notificaciones almeira|inelpac|meliextra|almeira producciones|publicaciones almeira|quilichao en medios/i.test(
|
||||||
groupSubject
|
groupSubject
|
||||||
@ -292,25 +304,68 @@ export async function POST(request: Request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-registrar grupo como monitoreado y activo si no existía previamente
|
// 1.2 FILTRAR CONTENIDO DE EVENTOS, CONFERENCIAS, REUNIONES VIRTUALES O SPAM
|
||||||
try {
|
const isSpamOrAnnouncement = /conferencia|webinar|zoom\.us|pantalla de zoom|podcast|mañanas millonarias|liderazgo|liderea|orador|taller virtual|evento online|conversaciones m[aá]s dinero|estrategia que funciona|elevax10n|smoothie|strawberry flavored|smartwatch|reloj inteligente|forex|cripto|trading|hoy 🚨|empezamos en \d+ minutos|llamada 911/i.test(
|
||||||
const currentGroups = dataService.getMonitoredGroups();
|
`${messageContent} ${groupSubject}`
|
||||||
const existingGrp = currentGroups.find((g) => g.jid === remoteJid);
|
);
|
||||||
|
if (isSpamOrAnnouncement) {
|
||||||
|
console.log(`[DripZone Webhook] Mensaje descartado por ser anuncio/evento/no calzado: "${messageContent.slice(0, 60)}"`);
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
ignored: 'Mensaje es un anuncio, evento o contenido no calzado',
|
||||||
|
chat: groupSubject,
|
||||||
|
remoteJid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.3 VERIFICAR QUE EL GRUPO ESTÉ EXPRESAMENTE MONITOREADO Y ACTIVO
|
||||||
|
let currentGroups = dataService.getMonitoredGroups();
|
||||||
|
let existingGrp = currentGroups.find(
|
||||||
|
(g) => g.jid === remoteJid || g.name.toLowerCase().replace(/\s+/g, ' ').trim() === groupSubject.toLowerCase().replace(/\s+/g, ' ').trim()
|
||||||
|
);
|
||||||
|
|
||||||
if (!existingGrp) {
|
if (!existingGrp) {
|
||||||
dataService.saveMonitoredGroups([
|
try {
|
||||||
...currentGroups,
|
const appwriteGroups = await getMonitoredGroupsFromAppwrite();
|
||||||
{
|
existingGrp = appwriteGroups.find((g) => g.jid === remoteJid);
|
||||||
|
if (existingGrp) {
|
||||||
|
dataService.saveMonitoredGroups([...currentGroups, existingGrp]);
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si el grupo nunca se ha configurado, registrarlo como INACTIVO (pendiente de aprobación en panel)
|
||||||
|
if (!existingGrp) {
|
||||||
|
const newGroupDoc = {
|
||||||
id: `grp-${remoteJid.replace(/\D/g, '').slice(-8)}`,
|
id: `grp-${remoteJid.replace(/\D/g, '').slice(-8)}`,
|
||||||
jid: remoteJid,
|
jid: remoteJid,
|
||||||
name: groupSubject,
|
name: groupSubject,
|
||||||
isMonitored: true,
|
isMonitored: false,
|
||||||
autoPublish: true,
|
autoPublish: false,
|
||||||
notes: 'Auto-registrado desde Webhook activo de WhatsApp',
|
notes: 'Detectado en webhook (inactivo por defecto)',
|
||||||
supplierName: groupSubject,
|
supplierName: groupSubject,
|
||||||
},
|
};
|
||||||
]);
|
dataService.saveMonitoredGroups([...currentGroups, newGroupDoc]);
|
||||||
|
saveMonitoredGroupToAppwrite(newGroupDoc).catch(() => {});
|
||||||
|
console.log(`[DripZone Webhook] Nuevo grupo detectado pero REGISTRADO COMO INACTIVO: "${groupSubject}" (${remoteJid})`);
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
ignored: 'Grupo nuevo no monitoreado (registrado inactivo en panel admin)',
|
||||||
|
chat: groupSubject,
|
||||||
|
remoteJid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si el grupo está desactivado o tiene auto-publicación apagada
|
||||||
|
if (!existingGrp.isMonitored || existingGrp.autoPublish === false) {
|
||||||
|
console.log(`[DripZone Webhook] Mensaje descartado: grupo no monitoreado o autoPublish apagado: "${groupSubject}" (${remoteJid})`);
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
ignored: 'Grupo no monitoreado o auto-publicación apagada',
|
||||||
|
chat: groupSubject,
|
||||||
|
remoteJid,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
// 2. VERIFICACIÓN DE DUPLICADOS
|
// 2. VERIFICACIÓN DE DUPLICADOS
|
||||||
if (isDuplicateMessage(whatsappMessageId, messageContent)) {
|
if (isDuplicateMessage(whatsappMessageId, messageContent)) {
|
||||||
@ -397,6 +452,17 @@ export async function POST(request: Request) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validación de coherencia y descarte de spam
|
||||||
|
const invalidTitleCheck = /hoy 🚨|conferencia|evento|zoom|podcast|mañanas millonarias|liderea|sin producto|elevax10n|smoothie|no especificado/i;
|
||||||
|
if (invalidTitleCheck.test(extracted.name || '') || invalidTitleCheck.test(messageContent)) {
|
||||||
|
console.log(`[DripZone Webhook] Publicación cancelada por contenido no comercial/calzado: "${extracted.name}"`);
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
ignored: 'Contenido descartado por no ser calzado o producto legítimo',
|
||||||
|
name: extracted.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Categorización segura
|
// Categorización segura
|
||||||
if (!extracted.category || extracted.category === 'Calzado / Sneakers' || extracted.category === 'Sneakers / Colección') {
|
if (!extracted.category || extracted.category === 'Calzado / Sneakers' || extracted.category === 'Sneakers / Colección') {
|
||||||
extracted.category = detectCategory(`${extracted.name || ''} ${messageContent}`).category;
|
extracted.category = detectCategory(`${extracted.name || ''} ${messageContent}`).category;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { dataService } from '@/lib/data-service';
|
import { dataService, isGroupIgnoredOrBlacklisted } from '@/lib/data-service';
|
||||||
import { MonitoredWhatsAppGroup } from '@/types';
|
import { MonitoredWhatsAppGroup } from '@/types';
|
||||||
import {
|
import {
|
||||||
getMonitoredGroupsFromAppwrite,
|
getMonitoredGroupsFromAppwrite,
|
||||||
@ -22,7 +22,7 @@ export async function GET(request: Request) {
|
|||||||
const appwriteGroups = await getMonitoredGroupsFromAppwrite();
|
const appwriteGroups = await getMonitoredGroupsFromAppwrite();
|
||||||
if (appwriteGroups.length > 0) {
|
if (appwriteGroups.length > 0) {
|
||||||
dataService.saveMonitoredGroups(appwriteGroups);
|
dataService.saveMonitoredGroups(appwriteGroups);
|
||||||
localGroups = appwriteGroups;
|
localGroups = dataService.getMonitoredGroups();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Error leyendo grupos desde Appwrite:', err);
|
console.warn('Error leyendo grupos desde Appwrite:', err);
|
||||||
@ -36,8 +36,30 @@ export async function GET(request: Request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consultar grupos en vivo desde Evolution API usando findChats (base de datos local rápida sin rate-limits)
|
// Consultar grupos en vivo desde Evolution API usando findChats y fetchAllGroups
|
||||||
try {
|
try {
|
||||||
|
let liveGroups: any[] = [];
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${EVOLUTION_API_URL}/group/fetchAllGroups/${EVOLUTION_INSTANCE_NAME}?getParticipants=false`,
|
||||||
|
{
|
||||||
|
headers: { apikey: EVOLUTION_API_KEY },
|
||||||
|
signal: AbortSignal.timeout(8000),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.ok) {
|
||||||
|
const all = await response.json();
|
||||||
|
if (Array.isArray(all) && all.length > 0) {
|
||||||
|
liveGroups = all.map((g: any) => ({
|
||||||
|
remoteJid: g.id || g.jid,
|
||||||
|
name: g.subject || g.name || 'Grupo WhatsApp',
|
||||||
|
size: g.size,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
if (liveGroups.length === 0) {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${EVOLUTION_API_URL}/chat/findChats/${EVOLUTION_INSTANCE_NAME}`,
|
`${EVOLUTION_API_URL}/chat/findChats/${EVOLUTION_INSTANCE_NAME}`,
|
||||||
{
|
{
|
||||||
@ -49,11 +71,11 @@ export async function GET(request: Request) {
|
|||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const allChats = await response.json();
|
const allChats = await response.json();
|
||||||
const liveGroups = (Array.isArray(allChats) ? allChats : []).filter(
|
liveGroups = (Array.isArray(allChats) ? allChats : []).filter(
|
||||||
(c: any) => (c.remoteJid && c.remoteJid.includes('@g.us')) || (c.id && c.id.includes('@g.us'))
|
(c: any) => (c.remoteJid && c.remoteJid.includes('@g.us')) || (c.id && c.id.includes('@g.us'))
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (liveGroups.length > 0) {
|
if (liveGroups.length > 0) {
|
||||||
const merged: MonitoredWhatsAppGroup[] = await Promise.all(
|
const merged: MonitoredWhatsAppGroup[] = await Promise.all(
|
||||||
@ -61,49 +83,34 @@ export async function GET(request: Request) {
|
|||||||
const jid = lg.remoteJid || lg.id || lg.jid;
|
const jid = lg.remoteJid || lg.id || lg.jid;
|
||||||
const name = lg.name || lg.pushName || lg.subject || 'Grupo WhatsApp';
|
const name = lg.name || lg.pushName || lg.subject || 'Grupo WhatsApp';
|
||||||
let isStillMember = true;
|
let isStillMember = true;
|
||||||
let participants = undefined;
|
let participants = lg.size || undefined;
|
||||||
|
|
||||||
try {
|
const isBlacklisted = isGroupIgnoredOrBlacklisted(jid, name);
|
||||||
const infoRes = await fetch(
|
const existing = localGroups.find(
|
||||||
`${EVOLUTION_API_URL}/group/findGroupInfos/${EVOLUTION_INSTANCE_NAME}?groupJid=${jid}`,
|
(g) => g.jid === jid || g.name.toLowerCase().replace(/\s+/g, ' ').trim() === name.toLowerCase().replace(/\s+/g, ' ').trim()
|
||||||
{
|
|
||||||
headers: { apikey: EVOLUTION_API_KEY },
|
|
||||||
signal: AbortSignal.timeout(3500),
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
if (infoRes.status === 404 || infoRes.status === 401 || infoRes.status === 403) {
|
|
||||||
isStillMember = false;
|
|
||||||
} else if (infoRes.ok) {
|
|
||||||
const infoData = await infoRes.json();
|
|
||||||
if (Array.isArray(infoData.participants)) {
|
|
||||||
participants = infoData.participants.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Si falla por timeout, mantener estado previo
|
|
||||||
}
|
|
||||||
|
|
||||||
const existing = localGroups.find((g) => g.jid === jid || g.name.toLowerCase() === name.toLowerCase());
|
// Pre-marcar SOLO proveedores exclusivos verificados de calzado si no había configuración previa
|
||||||
|
const isKnownSupplierGroup = !isBlacklisted && /exclusive cc|jovic store/i.test(name);
|
||||||
// Pre-marcar como monitoreados grupos reconocidos de proveedores si no había configuración previa
|
const isMonitored = isBlacklisted ? false : (existing
|
||||||
const isKnownSupplierGroup = /exclusive|emporio|jovic|diamonds|mayorista|calzado|sneakers|zapatillas/i.test(name);
|
|
||||||
const isMonitored = existing
|
|
||||||
? (existing.isMonitored && isStillMember)
|
? (existing.isMonitored && isStillMember)
|
||||||
: (isKnownSupplierGroup && isStillMember);
|
: (isKnownSupplierGroup && isStillMember));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: existing?.id || `grp-${jid.replace(/\D/g, '').slice(-6)}`,
|
id: existing?.id || `grp-${jid.replace(/\D/g, '').slice(-8)}`,
|
||||||
jid,
|
jid,
|
||||||
name,
|
name,
|
||||||
isMonitored: isStillMember ? isMonitored : false,
|
isMonitored: isBlacklisted ? false : (isStillMember ? isMonitored : false),
|
||||||
isStillMember,
|
isStillMember,
|
||||||
hasLeft: !isStillMember,
|
hasLeft: !isStillMember,
|
||||||
supplierId: existing?.supplierId,
|
supplierId: existing?.supplierId,
|
||||||
supplierName: existing?.supplierName || name,
|
supplierName: existing?.supplierName || name,
|
||||||
profitMarginOverride: existing?.profitMarginOverride || 35,
|
profitMarginOverride: existing?.profitMarginOverride || 35,
|
||||||
autoPublish: existing?.autoPublish ?? true,
|
autoPublish: isBlacklisted ? false : (existing?.autoPublish ?? true),
|
||||||
participantsCount: participants ?? lg.unreadCount,
|
participantsCount: participants ?? lg.unreadCount,
|
||||||
notes: isStillMember ? (existing?.notes || '') : 'Saliste de este grupo en WhatsApp',
|
notes: isBlacklisted
|
||||||
|
? 'IGNORADO EXPLICITAMENTE'
|
||||||
|
: isStillMember ? (existing?.notes || '') : 'Saliste de este grupo en WhatsApp',
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -145,7 +152,8 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
if (body.action === 'toggle' || body.action === 'deactivate-group') {
|
if (body.action === 'toggle' || body.action === 'deactivate-group') {
|
||||||
const { idOrJid, isMonitored } = body;
|
const { idOrJid, isMonitored } = body;
|
||||||
const targetState = isMonitored !== undefined ? isMonitored : false;
|
const isBlacklisted = isGroupIgnoredOrBlacklisted(idOrJid);
|
||||||
|
const targetState = isBlacklisted ? false : (isMonitored !== undefined ? isMonitored : false);
|
||||||
const updated = dataService.toggleGroupMonitoring(idOrJid, targetState);
|
const updated = dataService.toggleGroupMonitoring(idOrJid, targetState);
|
||||||
toggleMonitoredGroupInAppwrite(idOrJid, targetState).catch((e) =>
|
toggleMonitoredGroupInAppwrite(idOrJid, targetState).catch((e) =>
|
||||||
console.warn('Error sincronizando toggle con Appwrite:', e)
|
console.warn('Error sincronizando toggle con Appwrite:', e)
|
||||||
@ -154,8 +162,14 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(body.groups)) {
|
if (Array.isArray(body.groups)) {
|
||||||
const saved = dataService.saveMonitoredGroups(body.groups);
|
const sanitized = body.groups.map((g: any) => {
|
||||||
Promise.all(body.groups.map((g: any) => saveMonitoredGroupToAppwrite(g))).catch((e) =>
|
if (isGroupIgnoredOrBlacklisted(g.jid, g.name)) {
|
||||||
|
return { ...g, isMonitored: false, autoPublish: false, notes: 'IGNORADO EXPLICITAMENTE' };
|
||||||
|
}
|
||||||
|
return g;
|
||||||
|
});
|
||||||
|
const saved = dataService.saveMonitoredGroups(sanitized);
|
||||||
|
Promise.all(sanitized.map((g: any) => saveMonitoredGroupToAppwrite(g))).catch((e) =>
|
||||||
console.warn('Error sincronizando grupos con Appwrite:', e)
|
console.warn('Error sincronizando grupos con Appwrite:', e)
|
||||||
);
|
);
|
||||||
return NextResponse.json({ success: true, groups: saved });
|
return NextResponse.json({ success: true, groups: saved });
|
||||||
|
|||||||
@ -227,6 +227,19 @@ export const INITIAL_USERS: User[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const BLACKLISTED_WHATSAPP_GROUPS: string[] = [
|
||||||
|
'120363400148850031@g.us', // SOMOS BLACK DIAMONDS 💎💎💎
|
||||||
|
'120363420942364759@g.us', // 💎TEAM EMPORIO💎🔥👑❤️🔥🤯
|
||||||
|
];
|
||||||
|
|
||||||
|
export function isGroupIgnoredOrBlacklisted(jid: string, name?: string): boolean {
|
||||||
|
if (!jid) return false;
|
||||||
|
const cleanJid = jid.trim();
|
||||||
|
if (BLACKLISTED_WHATSAPP_GROUPS.includes(cleanJid)) return true;
|
||||||
|
if (name && /black diamonds|team emporio|emporio/i.test(name)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [];
|
export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [];
|
||||||
|
|
||||||
function getFsModule() {
|
function getFsModule() {
|
||||||
@ -1092,21 +1105,48 @@ class DataService {
|
|||||||
return user || null;
|
return user || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private monitoredGroups: MonitoredWhatsAppGroup[] = [...INITIAL_MONITORED_GROUPS];
|
private monitoredGroups: MonitoredWhatsAppGroup[] = loadPersistedData<MonitoredWhatsAppGroup[]>(
|
||||||
|
'persisted_monitored_groups.json',
|
||||||
|
[...INITIAL_MONITORED_GROUPS]
|
||||||
|
);
|
||||||
|
|
||||||
getMonitoredGroups(): MonitoredWhatsAppGroup[] {
|
getMonitoredGroups(): MonitoredWhatsAppGroup[] {
|
||||||
return this.monitoredGroups;
|
if (!this.monitoredGroups || this.monitoredGroups.length === 0) {
|
||||||
|
this.monitoredGroups = loadPersistedData<MonitoredWhatsAppGroup[]>(
|
||||||
|
'persisted_monitored_groups.json',
|
||||||
|
[...INITIAL_MONITORED_GROUPS]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.monitoredGroups.map((g) => {
|
||||||
|
if (isGroupIgnoredOrBlacklisted(g.jid, g.name)) {
|
||||||
|
return { ...g, isMonitored: false, autoPublish: false, notes: 'IGNORADO EXPLICITAMENTE' };
|
||||||
|
}
|
||||||
|
return g;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
saveMonitoredGroups(groups: MonitoredWhatsAppGroup[]): MonitoredWhatsAppGroup[] {
|
saveMonitoredGroups(groups: MonitoredWhatsAppGroup[]): MonitoredWhatsAppGroup[] {
|
||||||
this.monitoredGroups = groups;
|
this.monitoredGroups = groups.map((g) => {
|
||||||
|
if (isGroupIgnoredOrBlacklisted(g.jid, g.name)) {
|
||||||
|
return { ...g, isMonitored: false, autoPublish: false, notes: 'IGNORADO EXPLICITAMENTE' };
|
||||||
|
}
|
||||||
|
return g;
|
||||||
|
});
|
||||||
|
savePersistedData('persisted_monitored_groups.json', this.monitoredGroups);
|
||||||
return this.monitoredGroups;
|
return this.monitoredGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleGroupMonitoring(idOrJid: string, isMonitored: boolean): MonitoredWhatsAppGroup | null {
|
toggleGroupMonitoring(idOrJid: string, isMonitored: boolean): MonitoredWhatsAppGroup | null {
|
||||||
const grp = this.monitoredGroups.find((g) => g.id === idOrJid || g.jid === idOrJid);
|
const grp = this.monitoredGroups.find((g) => g.id === idOrJid || g.jid === idOrJid);
|
||||||
if (grp) {
|
if (grp) {
|
||||||
|
if (isGroupIgnoredOrBlacklisted(grp.jid, grp.name)) {
|
||||||
|
grp.isMonitored = false;
|
||||||
|
grp.autoPublish = false;
|
||||||
|
grp.notes = 'IGNORADO EXPLICITAMENTE';
|
||||||
|
} else {
|
||||||
grp.isMonitored = isMonitored;
|
grp.isMonitored = isMonitored;
|
||||||
|
}
|
||||||
|
savePersistedData('persisted_monitored_groups.json', this.monitoredGroups);
|
||||||
return grp;
|
return grp;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
MessageTemplate,
|
MessageTemplate,
|
||||||
CustomProductRequest,
|
CustomProductRequest,
|
||||||
} from '@/types';
|
} from '@/types';
|
||||||
import { INITIAL_CITIES, INITIAL_PAYMENT_METHODS, INITIAL_SUPPLIERS } from './data-service';
|
import { INITIAL_CITIES, INITIAL_PAYMENT_METHODS, INITIAL_SUPPLIERS, isGroupIgnoredOrBlacklisted } from './data-service';
|
||||||
import { DEFAULT_MESSAGE_TEMPLATES } from './templates-service';
|
import { DEFAULT_MESSAGE_TEMPLATES } from './templates-service';
|
||||||
import { sanitizePublicationTitle, sanitizePublicationText } from './sanitizer';
|
import { sanitizePublicationTitle, sanitizePublicationText } from './sanitizer';
|
||||||
|
|
||||||
@ -717,15 +717,18 @@ export async function getMonitoredGroupsFromAppwrite(): Promise<MonitoredWhatsAp
|
|||||||
Query.limit(100),
|
Query.limit(100),
|
||||||
]);
|
]);
|
||||||
if (res.documents && res.documents.length > 0) {
|
if (res.documents && res.documents.length > 0) {
|
||||||
return res.documents.map((d: any) => ({
|
return res.documents.map((d: any) => {
|
||||||
|
const isBlacklisted = isGroupIgnoredOrBlacklisted(d.jid, d.name);
|
||||||
|
return {
|
||||||
id: d.$id,
|
id: d.$id,
|
||||||
jid: d.jid || '',
|
jid: d.jid || '',
|
||||||
name: d.name || '',
|
name: d.name || '',
|
||||||
isMonitored: Boolean(d.isMonitored),
|
isMonitored: isBlacklisted ? false : Boolean(d.isMonitored),
|
||||||
autoPublish: d.autoPublish !== false,
|
autoPublish: isBlacklisted ? false : d.autoPublish !== false,
|
||||||
notes: d.notes || '',
|
notes: isBlacklisted ? 'IGNORADO EXPLICITAMENTE' : d.notes || '',
|
||||||
supplierName: d.name || '',
|
supplierName: d.name || '',
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@ -737,13 +740,14 @@ export async function getMonitoredGroupsFromAppwrite(): Promise<MonitoredWhatsAp
|
|||||||
export async function saveMonitoredGroupToAppwrite(
|
export async function saveMonitoredGroupToAppwrite(
|
||||||
group: Partial<MonitoredWhatsAppGroup>
|
group: Partial<MonitoredWhatsAppGroup>
|
||||||
): Promise<MonitoredWhatsAppGroup> {
|
): Promise<MonitoredWhatsAppGroup> {
|
||||||
|
const isBlacklisted = isGroupIgnoredOrBlacklisted(group.jid || '', group.name);
|
||||||
const docId = group.id || `grp-${(group.jid || '').replace(/\D/g, '').slice(-8)}` || `grp-${Date.now()}`;
|
const docId = group.id || `grp-${(group.jid || '').replace(/\D/g, '').slice(-8)}` || `grp-${Date.now()}`;
|
||||||
const payload = {
|
const payload = {
|
||||||
jid: group.jid || '',
|
jid: group.jid || '',
|
||||||
name: group.name || '',
|
name: group.name || '',
|
||||||
isMonitored: Boolean(group.isMonitored),
|
isMonitored: isBlacklisted ? false : Boolean(group.isMonitored),
|
||||||
autoPublish: group.autoPublish !== false,
|
autoPublish: isBlacklisted ? false : group.autoPublish !== false,
|
||||||
notes: group.notes || '',
|
notes: isBlacklisted ? 'IGNORADO EXPLICITAMENTE' : group.notes || '',
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -780,12 +784,24 @@ export async function toggleMonitoredGroupInAppwrite(
|
|||||||
isMonitored: boolean
|
isMonitored: boolean
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const groups = await getMonitoredGroupsFromAppwrite();
|
const isBlacklisted = isGroupIgnoredOrBlacklisted(idOrJid);
|
||||||
const found = groups.find((g) => g.id === idOrJid || g.jid === idOrJid);
|
const finalState = isBlacklisted ? false : isMonitored;
|
||||||
if (found) {
|
|
||||||
await serverDatabases.updateDocument(DB_ID, 'monitored_groups', found.id, {
|
const res = await serverDatabases.listDocuments(DB_ID, 'monitored_groups', [Query.limit(100)]);
|
||||||
isMonitored,
|
const matchingDocs = res.documents.filter(
|
||||||
});
|
(d: any) => d.$id === idOrJid || d.jid === idOrJid || d.name === idOrJid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (matchingDocs.length > 0) {
|
||||||
|
await Promise.all(
|
||||||
|
matchingDocs.map((doc: any) =>
|
||||||
|
serverDatabases.updateDocument(DB_ID, 'monitored_groups', doc.$id, {
|
||||||
|
isMonitored: finalState,
|
||||||
|
autoPublish: finalState,
|
||||||
|
notes: isBlacklisted ? 'IGNORADO EXPLICITAMENTE' : doc.notes,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
114
scripts/clean_unwanted_supplier_products.js
Normal file
114
scripts/clean_unwanted_supplier_products.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
const sdk = require('node-appwrite');
|
||||||
|
const client = new sdk.Client()
|
||||||
|
.setEndpoint('https://appwrite.almeira.com.co/v1')
|
||||||
|
.setProject('69b84df5003bd8957c5c')
|
||||||
|
.setKey('standard_cce3cdb866ea6433888d40cedd24dc45987372308fdc3dd0697de08648c0e5c7e04b02c3bcee271403fd656b00a5820f04c08b51631284a6e8a3582d8aed2aa33234f3c29cc777e9b162eb54810b789251b0d006a9a3b081ebc2da53b9baa94614b124b3508ad849fd9a4187cc6094f506d4b57f409b69d9562a74df594f3ec3');
|
||||||
|
const dbs = new sdk.Databases(client);
|
||||||
|
|
||||||
|
const DB_ID = 'sneakers_multistore_db';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log('=== [1] ELIMINANDO PRODUCTOS BASURA DE LOS GRUPOS IGNORADOS ===');
|
||||||
|
let offset = 0;
|
||||||
|
const limit = 100;
|
||||||
|
const toDelete = [];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const res = await dbs.listDocuments(DB_ID, 'products', [
|
||||||
|
sdk.Query.limit(limit),
|
||||||
|
sdk.Query.offset(offset)
|
||||||
|
]);
|
||||||
|
if (!res.documents || res.documents.length === 0) break;
|
||||||
|
|
||||||
|
for (const doc of res.documents) {
|
||||||
|
const sup = (doc.supplierName || '').toLowerCase();
|
||||||
|
const name = (doc.name || '').toLowerCase();
|
||||||
|
const raw = JSON.stringify(doc).toLowerCase();
|
||||||
|
|
||||||
|
if (
|
||||||
|
sup.includes('emporio') ||
|
||||||
|
sup.includes('black diamonds') ||
|
||||||
|
raw.includes('120363400148850031') ||
|
||||||
|
raw.includes('120363420942364759') ||
|
||||||
|
name.includes('hoy 🚨') ||
|
||||||
|
name.includes('liderea con')
|
||||||
|
) {
|
||||||
|
// Asegurar que no borramos productos legítimos de Jovic o CC Mío
|
||||||
|
if (sup.includes('jovic') || sup.includes('cc mío') || sup.includes('exclusive')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toDelete.push({ id: doc['$id'], name: doc.name, supplier: doc.supplierName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += limit;
|
||||||
|
if (offset >= res.total) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Encontrados ${toDelete.length} productos para eliminar:`);
|
||||||
|
for (const p of toDelete) {
|
||||||
|
try {
|
||||||
|
await dbs.deleteDocument(DB_ID, 'products', p.id);
|
||||||
|
console.log(` ✓ Eliminado producto: ${p.id} - ${p.name} (${p.supplier})`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ✗ Error eliminando ${p.id}:`, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n=== [2] SANITIZANDO COLECCIÓN MONITORED_GROUPS EN APPWRITE ===');
|
||||||
|
const groupsRes = await dbs.listDocuments(DB_ID, 'monitored_groups', [sdk.Query.limit(100)]);
|
||||||
|
console.log(`Total grupos en Appwrite: ${groupsRes.total}`);
|
||||||
|
|
||||||
|
const blacklistedJids = [
|
||||||
|
'120363400148850031@g.us', // SOMOS BLACK DIAMONDS
|
||||||
|
'120363420942364759@g.us', // TEAM EMPORIO
|
||||||
|
];
|
||||||
|
|
||||||
|
// Agrupar por JID para eliminar duplicados
|
||||||
|
const groupsByJid = new Map();
|
||||||
|
for (const doc of groupsRes.documents) {
|
||||||
|
const jid = doc.jid;
|
||||||
|
if (!groupsByJid.has(jid)) {
|
||||||
|
groupsByJid.set(jid, []);
|
||||||
|
}
|
||||||
|
groupsByJid.get(jid).push(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [jid, docs] of groupsByJid.entries()) {
|
||||||
|
const isBlacklisted = blacklistedJids.includes(jid) ||
|
||||||
|
docs.some(d => /black diamonds|team emporio|emporio/i.test(d.name || ''));
|
||||||
|
|
||||||
|
// Mantener 1 documento canónico y eliminar duplicados
|
||||||
|
const canonicalDoc = docs[0];
|
||||||
|
const duplicates = docs.slice(1);
|
||||||
|
|
||||||
|
for (const dup of duplicates) {
|
||||||
|
try {
|
||||||
|
await dbs.deleteDocument(DB_ID, 'monitored_groups', dup['$id']);
|
||||||
|
console.log(` ✓ Eliminado documento duplicado: ${dup['$id']} (${jid})`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ✗ Error eliminando duplicado ${dup['$id']}:`, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlacklisted) {
|
||||||
|
try {
|
||||||
|
await dbs.updateDocument(DB_ID, 'monitored_groups', canonicalDoc['$id'], {
|
||||||
|
isMonitored: 0,
|
||||||
|
autoPublish: 0,
|
||||||
|
notes: 'IGNORADO EXPLICITAMENTE - NO PUBLICAR NI MONITOREAR',
|
||||||
|
});
|
||||||
|
console.log(` 🛑 Grupo marcado como IGNORADO permanentemente: ${canonicalDoc.name} (${jid})`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(` ✗ Error actualizando grupo ${canonicalDoc['$id']}:`, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n=== [3] VERIFICACIÓN FINAL DE GRUPOS EN APPWRITE ===');
|
||||||
|
const finalRes = await dbs.listDocuments(DB_ID, 'monitored_groups', [sdk.Query.limit(100)]);
|
||||||
|
finalRes.documents.forEach((d) => {
|
||||||
|
console.log(`ID: ${d['$id']} | JID: ${d.jid} | isMonitored: ${d.isMonitored} | Name: ${d.name}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error);
|
||||||
45
scripts/find_all_unwanted_products.js
Normal file
45
scripts/find_all_unwanted_products.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const sdk = require('node-appwrite');
|
||||||
|
const client = new sdk.Client()
|
||||||
|
.setEndpoint('https://appwrite.almeira.com.co/v1')
|
||||||
|
.setProject('69b84df5003bd8957c5c')
|
||||||
|
.setKey('standard_cce3cdb866ea6433888d40cedd24dc45987372308fdc3dd0697de08648c0e5c7e04b02c3bcee271403fd656b00a5820f04c08b51631284a6e8a3582d8aed2aa33234f3c29cc777e9b162eb54810b789251b0d006a9a3b081ebc2da53b9baa94614b124b3508ad849fd9a4187cc6094f506d4b57f409b69d9562a74df594f3ec3');
|
||||||
|
const dbs = new sdk.Databases(client);
|
||||||
|
|
||||||
|
async function inspectAll() {
|
||||||
|
let offset = 0;
|
||||||
|
const limit = 100;
|
||||||
|
const toDelete = [];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const res = await dbs.listDocuments('sneakers_multistore_db', 'products', [
|
||||||
|
sdk.Query.limit(limit),
|
||||||
|
sdk.Query.offset(offset)
|
||||||
|
]);
|
||||||
|
if (!res.documents || res.documents.length === 0) break;
|
||||||
|
|
||||||
|
for (const doc of res.documents) {
|
||||||
|
const sup = (doc.supplierName || '').toLowerCase();
|
||||||
|
const name = (doc.name || '').toLowerCase();
|
||||||
|
const raw = JSON.stringify(doc).toLowerCase();
|
||||||
|
|
||||||
|
if (
|
||||||
|
sup.includes('emporio') ||
|
||||||
|
sup.includes('black diamonds') ||
|
||||||
|
raw.includes('120363400148850031') ||
|
||||||
|
raw.includes('120363420942364759') ||
|
||||||
|
name.includes('hoy 🚨') ||
|
||||||
|
name.includes('liderea con')
|
||||||
|
) {
|
||||||
|
toDelete.push({ id: doc.$id, name: doc.name, supplier: doc.supplierName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += limit;
|
||||||
|
if (offset >= res.total) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Encontrados ${toDelete.length} productos publicados de estos grupos:`);
|
||||||
|
toDelete.forEach(p => console.log(` - ID: ${p.id} | Nombre: ${p.name} | Proveedor: ${p.supplier}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
inspectAll().catch(console.error);
|
||||||
24
scripts/inspect_target_products.js
Normal file
24
scripts/inspect_target_products.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const sdk = require('node-appwrite');
|
||||||
|
const client = new sdk.Client()
|
||||||
|
.setEndpoint('https://appwrite.almeira.com.co/v1')
|
||||||
|
.setProject('69b84df5003bd8957c5c')
|
||||||
|
.setKey('standard_cce3cdb866ea6433888d40cedd24dc45987372308fdc3dd0697de08648c0e5c7e04b02c3bcee271403fd656b00a5820f04c08b51631284a6e8a3582d8aed2aa33234f3c29cc777e9b162eb54810b789251b0d006a9a3b081ebc2da53b9baa94614b124b3508ad849fd9a4187cc6094f506d4b57f409b69d9562a74df594f3ec3');
|
||||||
|
const dbs = new sdk.Databases(client);
|
||||||
|
|
||||||
|
async function inspect() {
|
||||||
|
const ids = ['snk-1789056531032-5ut8', 'snk-1789057093753-lz2a', 'snk-1789058687729-e6zk'];
|
||||||
|
for (const id of ids) {
|
||||||
|
try {
|
||||||
|
const doc = await dbs.getDocument('sneakers_multistore_db', 'products', id);
|
||||||
|
console.log('--- PRODUCT:', doc['$id']);
|
||||||
|
console.log('Name:', doc.name);
|
||||||
|
console.log('Description:', (doc.description || '').slice(0, 150));
|
||||||
|
console.log('SupplierPostId:', doc.supplierPostId);
|
||||||
|
console.log('SupplierName:', doc.supplierName);
|
||||||
|
console.log('IsActive:', doc.isActive);
|
||||||
|
} catch(e) {
|
||||||
|
console.log('Error', id, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inspect().catch(console.error);
|
||||||
@ -20,9 +20,9 @@ const GROUPS_TO_SEED = [
|
|||||||
{
|
{
|
||||||
jid: '120363420942364759@g.us',
|
jid: '120363420942364759@g.us',
|
||||||
name: '💎TEAM EMPORIO💎🔥👑❤️🔥🤯',
|
name: '💎TEAM EMPORIO💎🔥👑❤️🔥🤯',
|
||||||
isMonitored: true,
|
isMonitored: false,
|
||||||
autoPublish: true,
|
autoPublish: false,
|
||||||
notes: 'Proveedor Mayorista Team Emporio Sneakers',
|
notes: 'IGNORADO EXPLICITAMENTE - NO PUBLICAR NI MONITOREAR',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jid: '120363027254133375@g.us',
|
jid: '120363027254133375@g.us',
|
||||||
@ -34,9 +34,9 @@ const GROUPS_TO_SEED = [
|
|||||||
{
|
{
|
||||||
jid: '120363400148850031@g.us',
|
jid: '120363400148850031@g.us',
|
||||||
name: 'SOMOS BLACK DIAMONDS 💎💎💎',
|
name: 'SOMOS BLACK DIAMONDS 💎💎💎',
|
||||||
isMonitored: true,
|
isMonitored: false,
|
||||||
autoPublish: true,
|
autoPublish: false,
|
||||||
notes: 'Proveedor Mayorista Black Diamonds Sneakers',
|
notes: 'IGNORADO EXPLICITAMENTE - NO PUBLICAR NI MONITOREAR',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jid: '120363317242539420@g.us',
|
jid: '120363317242539420@g.us',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user