From 46df51eab720287f85921ebc023c788d84662627 Mon Sep 17 00:00:00 2001 From: maksim hodasevich <47758224+dogfrogfog@users.noreply.github.com> Date: Mon, 11 Nov 2024 07:46:40 +0100 Subject: [PATCH] update home story instead of creating a new one (#56) * update home story instead of creating a new one * remove console log --- apps/storyblok/CLI/sb.mjs | 7 +- apps/storyblok/CLI/services/storyblok.mjs | 125 +++++++++++++----- apps/storyblok/CLI/services/vercel.mjs | 6 +- .../storyblok/src/app/api/revalidate/route.ts | 20 +-- 4 files changed, 110 insertions(+), 48 deletions(-) diff --git a/apps/storyblok/CLI/sb.mjs b/apps/storyblok/CLI/sb.mjs index 8971c63..d6ae0d1 100644 --- a/apps/storyblok/CLI/sb.mjs +++ b/apps/storyblok/CLI/sb.mjs @@ -56,7 +56,7 @@ const main = async () => { // Log in to storyblok CLI spinner.start("Logging in to storyblok CLI ⏳"); - const stdio = "ignore"; + const stdio = process.env.DEBUG ? "inherit" : "ignore"; try { execSync("pnpm storyblok logout", { stdio, @@ -82,6 +82,7 @@ const main = async () => { // Create Vercel production and preview projects spinner.start("Creating Vercel production and preview projects ⏳"); + const whRevalidateSecret = crypto.randomUUID(); const { deploymentUrl: productionDeploymentUrl, projectName: productionProjectName, @@ -92,6 +93,7 @@ const main = async () => { isPreview: false, spaceId, previewToken, + whRevalidateSecret, }, }); @@ -105,6 +107,7 @@ const main = async () => { isPreview: true, spaceId, previewToken, + whRevalidateSecret, }, }); spinner.succeed( @@ -119,7 +122,7 @@ const main = async () => { }); await createStoryblokWebhook( spaceId, - `${productionDeploymentUrl}/api/revalidate`, + `${productionDeploymentUrl}/api/revalidate?secret=${whRevalidateSecret}`, ); spinner.succeed("Storyblok space successfully updated ✅"); diff --git a/apps/storyblok/CLI/services/storyblok.mjs b/apps/storyblok/CLI/services/storyblok.mjs index eac619d..3b401db 100644 --- a/apps/storyblok/CLI/services/storyblok.mjs +++ b/apps/storyblok/CLI/services/storyblok.mjs @@ -187,35 +187,6 @@ async function getSectionsFolder(spaceId) { return data.component_groups.find((folder) => folder.name === "sections"); } -async function createStory(spaceId, storyData) { - const envs = loadEnvVariables(); - const token = envs.SB_PERSONAL_ACCESS_TOKEN; - - const response = await fetch( - `https://mapi.storyblok.com/v1/spaces/${spaceId}/stories`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: token, - }, - body: JSON.stringify({ - story: storyData, - publish: 1, - }), - }, - ); - - if (!response.ok) { - console.log(response.status, response.statusText, await response.json()); - throw new Error(`❌ HTTP error! Status: ${response.status}`); - } - - const data = await response.json(); - - return data; -} - const globalComponentNames = ["header", "footer"]; export async function uploadBackupStories(spaceId) { // Get directory path relative to current file @@ -304,8 +275,12 @@ export async function uploadBackupStories(spaceId) { parent_id: newParentId, }; - // home page is created by default - if (story.slug !== "home") { + if (story.slug === "home") { + console.log("updated story data"); + + const homeStory = await getStoryBySlug(spaceId, "home"); + await updateStory(spaceId, homeStory.id, storyData); + } else { await createStory(spaceId, storyData); } } catch (error) { @@ -314,3 +289,91 @@ export async function uploadBackupStories(spaceId) { } } } + +export async function getStoryBySlug(spaceId, slug) { + const envs = loadEnvVariables(); + const token = envs.SB_PERSONAL_ACCESS_TOKEN; + + const searchParams = new URLSearchParams({ + version: "draft", + by_slugs: slug, // home, headers/default-header + }); + + const response = await fetch( + `https://mapi.storyblok.com/v1/spaces/${spaceId}/stories?${searchParams}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: token, + }, + }, + ); + + if (!response.ok) { + console.log(response.status, response.statusText, await response.json()); + throw new Error(`❌ HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + return data.stories[0] || null; +} + +async function createStory(spaceId, storyData) { + const envs = loadEnvVariables(); + const token = envs.SB_PERSONAL_ACCESS_TOKEN; + + const response = await fetch( + `https://mapi.storyblok.com/v1/spaces/${spaceId}/stories`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: token, + }, + body: JSON.stringify({ + story: storyData, + publish: 1, + }), + }, + ); + + if (!response.ok) { + console.log(response.status, response.statusText, await response.json()); + throw new Error(`❌ HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + + return data; +} + +export async function updateStory(spaceId, storyId, storyData) { + const envs = loadEnvVariables(); + const token = envs.SB_PERSONAL_ACCESS_TOKEN; + + const response = await fetch( + `https://mapi.storyblok.com/v1/spaces/${spaceId}/stories/${storyId}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: token, + }, + body: JSON.stringify({ + story: storyData, + publish: 1, + force_update: 1, + }), + }, + ); + + if (!response.ok) { + console.log(response.status, response.statusText, await response.json()); + throw new Error(`❌ HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + + return data; +} diff --git a/apps/storyblok/CLI/services/vercel.mjs b/apps/storyblok/CLI/services/vercel.mjs index 00ee885..2820bdc 100644 --- a/apps/storyblok/CLI/services/vercel.mjs +++ b/apps/storyblok/CLI/services/vercel.mjs @@ -58,7 +58,7 @@ export async function getVercelUserInfo() { } export async function createVercelProject({ projectName, sbParams }) { - const { isPreview, spaceId, previewToken } = sbParams; + const { isPreview, spaceId, previewToken, whRevalidateSecret } = sbParams; const envs = loadEnvVariables(); const repoName = envs.REPO_NAME; const vercelToken = envs.VERCEL_PERSONAL_AUTH_TOKEN; @@ -105,6 +105,10 @@ export async function createVercelProject({ projectName, sbParams }) { key: "SB_PREVIEW_TOKEN", value: previewToken, }, + { + key: "SB_WEBHOOK_REVALIDATE_SECRET", + value: whRevalidateSecret, + }, { key: "SB_SPACE_ID", value: spaceId + "", diff --git a/apps/storyblok/src/app/api/revalidate/route.ts b/apps/storyblok/src/app/api/revalidate/route.ts index f302f71..0e9d081 100644 --- a/apps/storyblok/src/app/api/revalidate/route.ts +++ b/apps/storyblok/src/app/api/revalidate/route.ts @@ -1,29 +1,21 @@ -import { createHmac } from "crypto"; import { revalidateTag } from "next/cache"; import { SB_CACHE_VERSION_TAG } from "@/constants/cacheTags"; -const webhookSecret = process.env.SB_WEBHOOK_REVALIDATE_SECRET || ""; - -function generateSignature(body: string) { - return createHmac("sha1", webhookSecret).update(body).digest("hex"); -} - export async function POST(request: Request) { const body = await request.json(); - const signature = request.headers.get("webhook-signature"); + const { searchParams } = new URL(request.url); + const secret = searchParams.get("secret"); - if (!body || !signature) { + if (!body || !secret) { return Response.json( - { error: "No body or signature provided" }, + { error: "No body or secret provided" }, { status: 400 }, ); } - const generatedSignature = generateSignature(JSON.stringify(body)); - - if (signature !== generatedSignature) { - return Response.json({ error: "Invalid signature" }, { status: 400 }); + if (secret !== process.env.SB_WEBHOOK_REVALIDATE_SECRET) { + return Response.json({ error: "No secret provided" }, { status: 400 }); } revalidateTag(SB_CACHE_VERSION_TAG);