From 52148e3896b45dbb25e148860a9d9d7c281a795e Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Thu, 2 Oct 2025 13:42:40 +0000 Subject: [PATCH] Add Facebook publishing functionality to schedule posts Integrate Facebook Graph API for publishing scheduled posts, including media. Update storage to handle post-media relationships and add new schema types. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/BuArSJC --- .replit | 4 ++++ server/services/scheduler.ts | 30 ++++++++++++++++++++++++++---- server/storage.ts | 7 +++++++ shared/schema.ts | 2 ++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/.replit b/.replit index ffeb98a..7852907 100644 --- a/.replit +++ b/.replit @@ -18,6 +18,10 @@ externalPort = 80 localPort = 5555 externalPort = 3002 +[[ports]] +localPort = 37219 +externalPort = 3003 + [[ports]] localPort = 40537 externalPort = 3000 diff --git a/server/services/scheduler.ts b/server/services/scheduler.ts index 14008f3..5254e89 100644 --- a/server/services/scheduler.ts +++ b/server/services/scheduler.ts @@ -1,5 +1,6 @@ import cron, { ScheduledTask } from "node-cron"; import { storage } from "../storage"; +import { facebookService } from "./facebook"; export class SchedulerService { private task: ScheduledTask | null = null; @@ -47,14 +48,35 @@ export class SchedulerService { throw new Error("Post or page not found"); } - // In a real implementation, this would call Facebook/Instagram Graph API - // For now, we'll simulate the publishing console.log(`Publishing post ${post.id} to ${page.platform} page ${page.pageName}`); + // Get media if post has media + const postMediaList = await storage.getPostMedia(post.id); + const media = postMediaList.length > 0 ? await storage.getMediaById(postMediaList[0].mediaId) : undefined; + + // Publish to Facebook/Instagram + let externalPostId: string; + + if (page.platform === 'facebook') { + externalPostId = await facebookService.publishPost(post, page, scheduledPost.postType, media || undefined); + } else if (page.platform === 'instagram') { + // Instagram publishing not yet implemented + console.warn(`Instagram publishing not yet implemented for post ${post.id}`); + await storage.updateScheduledPost(scheduledPost.id, { + error: 'Instagram publishing not yet implemented', + }); + await storage.updatePost(post.id, { + status: "failed", + }); + return; + } else { + throw new Error(`Unsupported platform: ${page.platform}`); + } + // Update the scheduled post as published await storage.updateScheduledPost(scheduledPost.id, { publishedAt: new Date(), - externalPostId: `simulated-${Date.now()}`, // In real app, this would be the ID from FB/IG + externalPostId, }); // Update post status @@ -62,7 +84,7 @@ export class SchedulerService { status: "published", }); - console.log(`Successfully published post ${post.id}`); + console.log(`Successfully published post ${post.id} with external ID: ${externalPostId}`); } } diff --git a/server/storage.ts b/server/storage.ts index 4f5a9b1..750a44c 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -3,6 +3,7 @@ import { socialPages, media, posts, + postMedia, scheduledPosts, aiGenerations, cloudinaryConfig, @@ -15,6 +16,7 @@ import { type InsertMedia, type Post, type InsertPost, + type PostMedia, type ScheduledPost, type InsertScheduledPost, type AiGeneration, @@ -48,6 +50,7 @@ export interface IStorage { getMediaById(id: string): Promise; createMedia(media: InsertMedia): Promise; deleteMedia(id: string): Promise; + getPostMedia(postId: string): Promise; // Posts getPosts(userId: string): Promise; @@ -152,6 +155,10 @@ export class DatabaseStorage implements IStorage { await db.delete(media).where(eq(media.id, id)); } + async getPostMedia(postId: string): Promise { + return await db.select().from(postMedia).where(eq(postMedia.postId, postId)); + } + // Posts async getPosts(userId: string): Promise { return await db.select().from(posts).where(eq(posts.userId, userId)).orderBy(desc(posts.createdAt)); diff --git a/shared/schema.ts b/shared/schema.ts index 144f27d..c50590b 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -254,3 +254,5 @@ export type InsertCloudinaryConfig = z.infer; + +export type PostMedia = typeof postMedia.$inferSelect;