feat: add facebook posting

This commit is contained in:
2025-12-23 15:12:27 -08:00
parent 98aefb0b12
commit 0cef2f3429
6 changed files with 628 additions and 5 deletions
+81
View File
@@ -0,0 +1,81 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
interface FacebookErrorResponse {
error: {
code: number;
message: string;
type: string;
};
}
interface FacebookSuccessResponse {
id: string;
}
type FacebookResponse = FacebookErrorResponse | FacebookSuccessResponse;
/**
* Forwards an announcement to our Facebook Page.
* @param content - The main body of the announcement.
* @returns A message indicating the success or failure of the operation.
*/
export const announceOnFacebook = async(content: string): Promise<string> => {
if (
process.env.FACEBOOK_PAGE_TOKEN === undefined
|| process.env.FACEBOOK_PAGE_ID === undefined
) {
return "Facebook credentials are not set.";
}
if (content.trim().length === 0) {
return "No content to send to Facebook.";
}
const pageId = process.env.FACEBOOK_PAGE_ID;
const accessToken = process.env.FACEBOOK_PAGE_TOKEN;
try {
const response = await fetch(
`https://graph.facebook.com/v21.0/${pageId}/feed`,
{
body: new URLSearchParams({
// eslint-disable-next-line @typescript-eslint/naming-convention -- Facebook API requires snake_case.
access_token: accessToken,
message: content,
}),
headers: {
// eslint-disable-next-line @typescript-eslint/naming-convention -- HTTP header name.
"Content-Type": "application/x-www-form-urlencoded",
},
method: "POST",
},
);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Fetch does not accept generic.
const result = (await response.json()) as FacebookResponse;
if ("error" in result) {
const errorMessage = result.error.message === ""
? JSON.stringify(result.error)
: result.error.message;
return `Failed to send message to Facebook. ${errorMessage}`;
}
if ("id" in result) {
return `Successfully sent post to Facebook. Post ID: ${result.id}`;
}
return `Failed to send message to Facebook. Unexpected response: ${JSON.stringify(result)}`;
} catch (error: unknown) {
return `Failed to send message to Facebook. ${
error instanceof Error
? error.message
: String(error)
}`;
}
};
+10 -2
View File
@@ -8,6 +8,7 @@ import { blockedIps } from "../cache/blockedIps.js";
import { database } from "../db/database.js";
import { announceOnBluesky } from "../modules/announceOnBluesky.js";
import { announceOnDiscord } from "../modules/announceOnDiscord.js";
import { announceOnFacebook } from "../modules/announceOnFacebook.js";
import { announceOnReddit } from "../modules/announceOnReddit.js";
import { announceOnTwitter } from "../modules/announceOnTwitter.js";
import { generateAnnouncements } from "../modules/generateAnnouncements.js";
@@ -86,7 +87,13 @@ export const announcementRoutes: FastifyPluginAsync = async(server) => {
});
}
const { bluesky, discord, reddit, twitter } = announcement.response;
const {
bluesky,
discord,
facebook,
reddit,
twitter,
} = announcement.response;
const { title: discordTitle, content: discordContent } = discord;
const { title: redditTitle, content: redditContent } = reddit;
@@ -110,9 +117,10 @@ export const announcementRoutes: FastifyPluginAsync = async(server) => {
);
const blueskyPost = await announceOnBluesky(bluesky);
const twitterPost = await announceOnTwitter(twitter);
const facebookPost = await announceOnFacebook(facebook);
return await reply.status(201).send({
cost: announcement.cost,
message: `Announcement processed. Discord: ${discordPost}, Reddit: ${redditPost}, Bluesky: ${blueskyPost}, Twitter: ${twitterPost}`,
message: `Announcement processed. Discord: ${discordPost}, Reddit: ${redditPost}, Bluesky: ${blueskyPost}, Twitter: ${twitterPost}, Facebook: ${facebookPost}`,
rawPost: announcement.response,
});
},