Skip to content

Commit 57dcbb5

Browse files
authored
feat(content): update PHP2Shell cover to Excalidraw style and support PUT updates in syndication (#787)
1 parent 5840d41 commit 57dcbb5

4 files changed

Lines changed: 82 additions & 33 deletions

File tree

‎apps/sanity/functions/syndicate-content/index.ts‎

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export const handler = documentEventHandler<ContentDocument>(
176176
}
177177

178178
const mainImageUrl =
179-
urlForImage(data.coverImage)?.width(1000).height(420).url() || "";
179+
urlForImage(data.coverImage)?.width(1280).url() || "";
180180

181181
const youtubeEmbed = data.youtube
182182
? `{% youtube ${data.youtube.replace("live", "embed")} %}\n\n`
@@ -209,6 +209,9 @@ export const handler = documentEventHandler<ContentDocument>(
209209
existingSyndication?.externalId ||
210210
(data.devto ? data.devto.split("https://dev.to/").at(-1) : null);
211211

212+
let targetDevtoUrl = "https://dev.to/api/articles";
213+
let devtoMethod = "POST";
214+
212215
if (existingDevtoId && !existingDevtoId.startsWith("simulated-")) {
213216
// Retrieve existing article ID from Dev.to to perform a PUT update
214217
const getArticleRes = await fetch(
@@ -223,39 +226,42 @@ export const handler = documentEventHandler<ContentDocument>(
223226

224227
if (getArticleRes.ok) {
225228
const articleData = (await getArticleRes.json()) as any;
226-
res = await fetch(`https://dev.to/api/articles/${articleData.id}`, {
227-
method: "PUT",
228-
headers: {
229-
"api-key": apiKey,
230-
"Content-Type": "application/json",
231-
},
232-
body: JSON.stringify(devtoArticlePayload),
233-
});
234-
} else {
235-
// If lookup failed, create as new article
236-
res = await fetch("https://dev.to/api/articles", {
237-
method: "POST",
229+
if (articleData?.id) {
230+
targetDevtoUrl = `https://dev.to/api/articles/${articleData.id}`;
231+
devtoMethod = "PUT";
232+
}
233+
}
234+
}
235+
236+
res = await fetch(targetDevtoUrl, {
237+
method: devtoMethod,
238+
headers: {
239+
"api-key": apiKey,
240+
"Content-Type": "application/json",
241+
},
242+
body: JSON.stringify(devtoArticlePayload),
243+
});
244+
245+
let errText = "";
246+
if (!res.ok) {
247+
errText = await res.text();
248+
if (errText.toLowerCase().includes("organization")) {
249+
delete devtoArticlePayload.article.organization_id;
250+
res = await fetch(targetDevtoUrl, {
251+
method: devtoMethod,
238252
headers: {
239253
"api-key": apiKey,
240254
"Content-Type": "application/json",
241255
},
242256
body: JSON.stringify(devtoArticlePayload),
243257
});
258+
if (!res.ok) {
259+
errText = await res.text();
260+
}
244261
}
245-
} else {
246-
// Create new article
247-
res = await fetch("https://dev.to/api/articles", {
248-
method: "POST",
249-
headers: {
250-
"api-key": apiKey,
251-
"Content-Type": "application/json",
252-
},
253-
body: JSON.stringify(devtoArticlePayload),
254-
});
255262
}
256263

257264
if (!res.ok) {
258-
const errText = await res.text();
259265
throw new Error(`Dev.to API error (${res.status}): ${errText}`);
260266
}
261267

‎scripts/assets/php2shell-cover.jpg‎

-183 KB
Loading

‎scripts/publish-php2shell-post.mjs‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export async function publishPhp2ShellPost() {
9090
console.log(`Uploading PHP2Shell cover and meme images to Sanity (${dataset})...`);
9191
const coverAssetId = await uploadImage(
9292
path.join(__dirname, "assets/php2shell-cover.jpg"),
93-
"php2shell-cover.jpg"
93+
"php2shell-excalidraw-cover.jpg"
9494
);
9595
const memeAssetId = await uploadImage(
9696
path.join(__dirname, "assets/php2shell-meme.jpg"),
@@ -444,7 +444,21 @@ sudo systemctl restart php8.4-fpm apache2`
444444
};
445445

446446
const mutations = [
447-
{ createOrReplace: postDoc },
447+
{ createIfNotExists: postDoc },
448+
{
449+
patch: {
450+
id: postDoc._id,
451+
set: {
452+
title: postDoc.title,
453+
slug: postDoc.slug,
454+
date: postDoc.date,
455+
excerpt: postDoc.excerpt,
456+
author: postDoc.author,
457+
coverImage: postDoc.coverImage,
458+
content: postDoc.content,
459+
},
460+
},
461+
},
448462
{ patch: { id: "LzgcvqoNSwz5R8loykZyIB", set: { excerpt: "Learn how to customize your Slack workspace theme using SlackThemes.net and contribute custom color themes on GitHub." } } },
449463
{ patch: { id: "ZKdo3vLUqcb4sYreiCMc5A", set: { excerpt: "Learn how to inspect and debug Angular 9 components directly inside the Chrome DevTools console using the new ng global object." } } },
450464
{ patch: { id: "ZKdo3vLUqcb4sYreiCPNnI", set: { excerpt: "Join Alex Patterson and Brittney Postma with special guests Zach DeRose, Facundo Giuliani, Swyx, Jason Lengstorf, and Scott Tolinski for a year-end Holiday AMA." } } },

‎scripts/run-syndicate-post.mjs‎

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ async function run() {
8484
const devtoTags = ["webdev", "javascript", "beginners"];
8585
if (doc._type === "podcast") devtoTags.push("podcast");
8686

87-
const mainImageUrl = urlForImage(doc.coverImage)?.width(1000).height(420).url() || "";
87+
const mainImageUrl = urlForImage(doc.coverImage)?.width(1280).url() || "";
8888
const youtubeEmbed = doc.youtube ? `{% youtube ${doc.youtube.replace("live", "embed")} %}\n\n` : "";
8989

9090
const devtoArticlePayload = {
@@ -105,10 +105,39 @@ async function run() {
105105
}
106106

107107
try {
108+
const existingSyndication = await client.getDocument(syndicationDocId).catch(() => null);
109+
let existingArticleId =
110+
existingSyndication?.externalId && !String(existingSyndication.externalId).startsWith("simulated-")
111+
? String(existingSyndication.externalId)
112+
: null;
113+
114+
if (!existingArticleId && doc.devto) {
115+
const pathSlug = doc.devto.split("https://dev.to/").at(-1);
116+
if (pathSlug) {
117+
const lookupRes = await fetch(`https://dev.to/api/articles/${pathSlug}`, {
118+
headers: {
119+
"api-key": devtoApiKey,
120+
"Content-Type": "application/json",
121+
},
122+
});
123+
if (lookupRes.ok) {
124+
const lookupJson = await lookupRes.json();
125+
if (lookupJson?.id) {
126+
existingArticleId = String(lookupJson.id);
127+
}
128+
}
129+
}
130+
}
131+
132+
const method = existingArticleId ? "PUT" : "POST";
133+
const targetUrl = existingArticleId
134+
? `https://dev.to/api/articles/${existingArticleId}`
135+
: "https://dev.to/api/articles";
136+
108137
// First attempt with organization_id: 1009
109-
console.log("Sending POST to Dev.to API with organization_id: 1009...");
110-
let res = await fetch("https://dev.to/api/articles", {
111-
method: "POST",
138+
console.log(`Sending ${method} to ${targetUrl} with organization_id: 1009...`);
139+
let res = await fetch(targetUrl, {
140+
method,
112141
headers: {
113142
"api-key": devtoApiKey,
114143
"Content-Type": "application/json",
@@ -124,8 +153,8 @@ async function run() {
124153
if (!res.ok && resText.toLowerCase().includes("organization")) {
125154
console.warn("Dev.to rejected organization_id 1009. Retrying under personal account without organization_id...");
126155
delete devtoArticlePayload.article.organization_id;
127-
res = await fetch("https://dev.to/api/articles", {
128-
method: "POST",
156+
res = await fetch(targetUrl, {
157+
method,
129158
headers: {
130159
"api-key": devtoApiKey,
131160
"Content-Type": "application/json",
@@ -181,7 +210,7 @@ async function run() {
181210
{ name: "Beginner Developers", slug: "beginners" },
182211
];
183212

184-
const hashnodeCoverImageUrl = urlForImage(doc.coverImage)?.width(1600).height(840).url() || "";
213+
const hashnodeCoverImageUrl = urlForImage(doc.coverImage)?.width(1600).url() || "";
185214
const youtubeEmbed = doc.youtube ? `%[${doc.youtube.replace("live", "embed")}]\n\n` : "";
186215

187216
const articleInput = {

0 commit comments

Comments
 (0)