rsocials-online/src/app/api/campaigns/[id]/sync/route.ts

127 lines
3.5 KiB
TypeScript

import { NextResponse } from "next/server";
import { getCampaign, saveCampaign } from "@/lib/campaign-storage";
import { computeTimeline } from "@/lib/campaign-timeline";
import {
getIntegrations,
schedulePost,
findIntegrationForPlatform,
} from "@/lib/postiz-client";
import type { PostSyncState, Platform, PostNode } from "@/lib/types/campaign";
export async function POST(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const campaign = await getCampaign(id);
if (!campaign) {
return NextResponse.json({ error: "Not found" }, { status: 404 });
}
if (!campaign.postiz?.instance || !campaign.postiz?.apiKey) {
return NextResponse.json(
{ error: "Postiz not configured for this campaign" },
{ status: 400 }
);
}
const { instance, apiKey } = campaign.postiz;
// Fetch available integrations from Postiz
let integrations;
try {
integrations = await getIntegrations(instance, apiKey);
} catch (err) {
return NextResponse.json(
{
error: `Failed to connect to Postiz: ${err instanceof Error ? err.message : "Unknown error"}`,
},
{ status: 502 }
);
}
// Compute timeline entries from graph
const timeline = computeTimeline(campaign);
const results: {
nodeId: string;
platform: string;
status: string;
error?: string;
}[] = [];
// Build a node-id map for quick lookup
const nodeMap = new Map(campaign.nodes.map((n) => [n.id, n]));
for (const entry of timeline) {
const node = nodeMap.get(entry.nodeId);
if (!node || node.type !== "post") continue;
const postNode = node as PostNode;
// Initialize sync state if needed
if (!postNode.data.postizSync) {
postNode.data.postizSync = {} as Record<Platform, PostSyncState>;
}
const platform = entry.platform;
const integration = findIntegrationForPlatform(integrations, platform);
if (!integration) {
postNode.data.postizSync[platform] = {
status: "failed",
error: `No ${platform} integration found in Postiz`,
};
results.push({
nodeId: entry.nodeId,
platform,
status: "failed",
error: `No ${platform} integration found`,
});
continue;
}
try {
const postizType =
platform === "twitter" ? "x" : platform;
const response = await schedulePost(instance, apiKey, {
content: entry.content,
type: postizType,
date: entry.scheduledAt.toISOString(),
integration: integration.id,
});
postNode.data.postizSync[platform] = {
postizPostId: response.id,
scheduledAt: entry.scheduledAt.toISOString(),
syncedAt: new Date().toISOString(),
integrationId: integration.id,
status: "synced",
};
results.push({ nodeId: entry.nodeId, platform, status: "synced" });
} catch (err) {
postNode.data.postizSync[platform] = {
status: "failed",
error: err instanceof Error ? err.message : "Unknown error",
};
results.push({
nodeId: entry.nodeId,
platform,
status: "failed",
error: err instanceof Error ? err.message : "Unknown error",
});
}
}
// Save updated campaign with sync state
await saveCampaign(campaign);
const synced = results.filter((r) => r.status === "synced").length;
const failed = results.filter((r) => r.status === "failed").length;
return NextResponse.json({
synced,
failed,
total: results.length,
results,
});
}