Stop seeding Agua Miia’s October plan for every client and restrict the portal publish action to that tenant only. Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { createClient } from '@/lib/supabase/server';
|
|
import { resolveActiveTenant, restGet } from '@/lib/tenant-context';
|
|
import { isAgencyRole, serviceHeaders, supabaseUrl, userRole } from '@/lib/agency';
|
|
import octPlan from '@/data/rrss-octubre-2026.json';
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
/**
|
|
* POST — publish bundled RRSS month plan into documents for the active tenant.
|
|
* Agency only. Idempotent upsert by title + type.
|
|
*/
|
|
export async function POST() {
|
|
const supabase = await createClient();
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser();
|
|
if (!user) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
if (!isAgencyRole(userRole(user))) {
|
|
return NextResponse.json({ error: 'Solo agencia' }, { status: 403 });
|
|
}
|
|
|
|
const ctx = await resolveActiveTenant(user);
|
|
if (!ctx.tenantId || ctx.portfolioWide) {
|
|
return NextResponse.json(
|
|
{ error: 'Selecciona un cliente en Contexto' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const t = await restGet<{ slug?: string; name?: string }[]>(
|
|
`/rest/v1/tenants?id=eq.${encodeURIComponent(ctx.tenantId)}&select=slug,name`
|
|
);
|
|
const slug = t.data?.[0]?.slug || '';
|
|
if (slug !== 'agua-miia') {
|
|
return NextResponse.json(
|
|
{
|
|
error:
|
|
'Este botón solo carga el plan de octubre de Agua Miia en su propio portal. No publica en Instagram ni copia el calendario a otros clientes.',
|
|
},
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const headers = serviceHeaders();
|
|
if (!headers) {
|
|
return NextResponse.json({ error: 'no service role' }, { status: 500 });
|
|
}
|
|
|
|
const title = `RRSS ${octPlan.label}`;
|
|
const tid = encodeURIComponent(ctx.tenantId);
|
|
const existing = await restGet<Array<{ id: string }>>(
|
|
`/rest/v1/documents?tenant_id=eq.${tid}&type=eq.calendar&title=eq.${encodeURIComponent(title)}&select=id&limit=1`
|
|
);
|
|
|
|
const payload = {
|
|
tenant_id: ctx.tenantId,
|
|
type: 'calendar',
|
|
title,
|
|
content: octPlan,
|
|
};
|
|
|
|
let res: Response;
|
|
if (existing.data?.[0]?.id) {
|
|
res = await fetch(
|
|
`${supabaseUrl()}/rest/v1/documents?id=eq.${existing.data[0].id}`,
|
|
{
|
|
method: 'PATCH',
|
|
headers: { ...headers, 'Content-Type': 'application/json', Prefer: 'return=representation' },
|
|
body: JSON.stringify({ content: octPlan, title }),
|
|
}
|
|
);
|
|
} else {
|
|
res = await fetch(`${supabaseUrl()}/rest/v1/documents`, {
|
|
method: 'POST',
|
|
headers: { ...headers, 'Content-Type': 'application/json', Prefer: 'return=representation' },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
}
|
|
|
|
if (!res.ok) {
|
|
return NextResponse.json(
|
|
{ error: await res.text() },
|
|
{ status: 502 }
|
|
);
|
|
}
|
|
|
|
const row = await res.json();
|
|
return NextResponse.json({
|
|
ok: true,
|
|
tenant: ctx.label,
|
|
month: octPlan.month,
|
|
pieces: (octPlan.pieces || []).length,
|
|
document: Array.isArray(row) ? row[0] : row,
|
|
});
|
|
}
|