feat: LinkedIn editorial, accesos agencia estables y deshacer en historial
Integra estrategias LinkedIn en calendarios (backlog publicado vs pendiente), unifica roles/cookies de vista agencia y permite deshacer cambios de brandbook dejando constancia en el historial. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
132
scripts/ensure_ecp_tsp_drive.ts
Normal file
132
scripts/ensure_ecp_tsp_drive.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Create client Drive roots for ECP + TSP under 03-Clientes if missing,
|
||||
* link integrations + tenants.drive_folder_id, ensure Ads/RRSS creatives folders,
|
||||
* re-enrich brandbooks.
|
||||
*
|
||||
* npx tsx scripts/ensure_ecp_tsp_drive.ts
|
||||
*/
|
||||
import { config } from 'dotenv';
|
||||
import { resolve } from 'path';
|
||||
config({ path: resolve(process.cwd(), '.env.local') });
|
||||
|
||||
import { enrichTenantBrandbook } from '../src/lib/brandbook-enrich';
|
||||
import { ensureCreativesDriveFolders } from '../src/lib/creatives-drive';
|
||||
import {
|
||||
ensureChildFolder,
|
||||
findClientesRootFolder,
|
||||
listClientFoldersUnderClientes,
|
||||
} from '../src/lib/google-drive';
|
||||
|
||||
const url = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const key = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const h = {
|
||||
apikey: key,
|
||||
Authorization: `Bearer ${key}`,
|
||||
'Content-Type': 'application/json',
|
||||
Prefer: 'return=minimal',
|
||||
};
|
||||
|
||||
const TARGETS: { slug: string; folderName: string }[] = [
|
||||
{ slug: 'ecp', folderName: '50-ECP Escuela de Cuidadores' },
|
||||
{ slug: 'tsp', folderName: '51-TSP Talento Scholar Program' },
|
||||
];
|
||||
|
||||
async function main() {
|
||||
const listed = await listClientFoldersUnderClientes();
|
||||
const root = listed.clientesRoot || (await findClientesRootFolder());
|
||||
if (!root?.id) throw new Error('No se encontró carpeta Clientes en Drive');
|
||||
console.log('Clientes root', root.name, root.id);
|
||||
|
||||
const folders = listed.folders;
|
||||
|
||||
for (const t of TARGETS) {
|
||||
const tr = await fetch(
|
||||
`${url}/rest/v1/tenants?slug=eq.${t.slug}&select=id,slug,name`,
|
||||
{ headers: h }
|
||||
);
|
||||
const tenant = (await tr.json())[0] as
|
||||
| { id: string; slug: string; name: string }
|
||||
| undefined;
|
||||
if (!tenant) {
|
||||
console.log(`[skip] ${t.slug} no existe`);
|
||||
continue;
|
||||
}
|
||||
|
||||
let folder = folders.find((f) =>
|
||||
t.slug === 'ecp'
|
||||
? /ecp|cuidadores/i.test(f.name) && !/navidad/i.test(f.name)
|
||||
: /tsp|scholar/i.test(f.name)
|
||||
);
|
||||
|
||||
if (!folder) {
|
||||
const id = await ensureChildFolder(root.id, t.folderName);
|
||||
folder = { id, name: t.folderName };
|
||||
console.log(`[create] ${t.folderName} → ${id}`);
|
||||
} else {
|
||||
console.log(`[exist] ${folder.name} → ${folder.id}`);
|
||||
}
|
||||
|
||||
await fetch(
|
||||
`${url}/rest/v1/integrations?tenant_id=eq.${tenant.id}&provider=eq.google_drive`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
headers: h,
|
||||
body: JSON.stringify({
|
||||
status: 'connected',
|
||||
enabled: true,
|
||||
external_account_id: folder.id,
|
||||
label: folder.name,
|
||||
updated_at: new Date().toISOString(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Upsert if no google_drive row
|
||||
const check = await fetch(
|
||||
`${url}/rest/v1/integrations?tenant_id=eq.${tenant.id}&provider=eq.google_drive&select=id`,
|
||||
{ headers: h }
|
||||
);
|
||||
const rows = (await check.json()) as { id: string }[];
|
||||
if (!rows.length) {
|
||||
await fetch(`${url}/rest/v1/integrations`, {
|
||||
method: 'POST',
|
||||
headers: h,
|
||||
body: JSON.stringify({
|
||||
tenant_id: tenant.id,
|
||||
provider: 'google_drive',
|
||||
status: 'connected',
|
||||
enabled: true,
|
||||
external_account_id: folder.id,
|
||||
label: folder.name,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
await fetch(`${url}/rest/v1/tenants?id=eq.${tenant.id}`, {
|
||||
method: 'PATCH',
|
||||
headers: h,
|
||||
body: JSON.stringify({ drive_folder_id: folder.id }),
|
||||
});
|
||||
|
||||
const creatives = await ensureCreativesDriveFolders(tenant.id, t.slug);
|
||||
console.log(
|
||||
`[creatives] ${t.slug}`,
|
||||
creatives.ok ? 'Ads+RRSS ok' : creatives.warning
|
||||
);
|
||||
|
||||
const enrich = await enrichTenantBrandbook({
|
||||
tenantId: tenant.id,
|
||||
forceSeed: true,
|
||||
});
|
||||
console.log(
|
||||
`[enrich] ${t.slug} ok=${enrich.ok} score=${enrich.completenessAfter} warn=${enrich.warning || '-'}`
|
||||
);
|
||||
}
|
||||
|
||||
console.log('Done');
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user