2024-09-20 15:56:07 +02:00
|
|
|
import { readFile, mkdir, writeFile, rename } from "node:fs/promises";
|
2024-08-04 16:15:09 +02:00
|
|
|
import { join } from "node:path";
|
2024-09-13 19:30:56 +02:00
|
|
|
import { type WebsiteOverview, slugify } from "$lib/utils";
|
2024-08-05 14:38:44 +02:00
|
|
|
import type { Actions, PageServerLoad } from "./$types";
|
2024-09-25 21:45:01 +02:00
|
|
|
import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils";
|
2024-08-17 19:29:10 +02:00
|
|
|
import { render } from "svelte/server";
|
|
|
|
|
import BlogIndex from "$lib/templates/blog/BlogIndex.svelte";
|
|
|
|
|
import BlogArticle from "$lib/templates/blog/BlogArticle.svelte";
|
2024-08-18 18:17:59 +02:00
|
|
|
import DocsIndex from "$lib/templates/docs/DocsIndex.svelte";
|
2024-08-27 16:39:29 +02:00
|
|
|
import DocsArticle from "$lib/templates/docs/DocsArticle.svelte";
|
2024-08-19 20:33:23 +02:00
|
|
|
import { dev } from "$app/environment";
|
2024-08-03 18:07:27 +02:00
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
export const load: PageServerLoad = async ({ params, fetch }) => {
|
|
|
|
|
const websiteOverview: WebsiteOverview = (
|
|
|
|
|
await apiRequest(
|
|
|
|
|
fetch,
|
|
|
|
|
`${API_BASE_PREFIX}/website?id=eq.${params.websiteId}&select=*,settings(*),header(*),home(*),footer(*),article(*,docs_category(*)),legal_information(*),domain_prefix(*)`,
|
|
|
|
|
"GET",
|
|
|
|
|
{
|
|
|
|
|
headers: {
|
|
|
|
|
Accept: "application/vnd.pgrst.object+json"
|
|
|
|
|
},
|
|
|
|
|
returnData: true
|
2024-08-14 19:33:41 +02:00
|
|
|
}
|
2024-09-25 21:45:01 +02:00
|
|
|
)
|
|
|
|
|
).data;
|
2024-08-04 16:15:09 +02:00
|
|
|
|
2024-08-07 19:13:39 +02:00
|
|
|
generateStaticFiles(websiteOverview);
|
2024-08-04 17:46:41 +02:00
|
|
|
|
2024-09-01 13:37:28 +02:00
|
|
|
const websitePreviewUrl = `${
|
|
|
|
|
dev
|
|
|
|
|
? "http://localhost:18000"
|
|
|
|
|
: process.env.ORIGIN
|
|
|
|
|
? process.env.ORIGIN
|
|
|
|
|
: "http://localhost:18000"
|
2024-09-07 18:22:58 +02:00
|
|
|
}/previews/${websiteOverview.id}/`;
|
2024-08-10 22:20:57 +02:00
|
|
|
|
2024-09-07 15:07:31 +02:00
|
|
|
const websiteProdUrl = dev
|
2024-09-20 15:56:07 +02:00
|
|
|
? `http://localhost:18000/${websiteOverview.domain_prefix?.prefix ?? websiteOverview.id}/`
|
2024-09-07 15:07:31 +02:00
|
|
|
: process.env.ORIGIN
|
2024-09-20 15:56:07 +02:00
|
|
|
? process.env.ORIGIN.replace(
|
|
|
|
|
"//",
|
|
|
|
|
`//${websiteOverview.domain_prefix?.prefix ?? websiteOverview.id}.`
|
|
|
|
|
)
|
|
|
|
|
: `http://localhost:18000/${websiteOverview.domain_prefix?.prefix ?? websiteOverview.id}/`;
|
2024-09-07 15:07:31 +02:00
|
|
|
|
2024-08-04 17:46:41 +02:00
|
|
|
return {
|
2024-08-10 22:20:57 +02:00
|
|
|
websiteOverview,
|
2024-08-20 19:17:05 +02:00
|
|
|
websitePreviewUrl,
|
2024-09-10 17:29:57 +02:00
|
|
|
websiteProdUrl
|
2024-08-04 17:46:41 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-05 14:38:44 +02:00
|
|
|
export const actions: Actions = {
|
2024-09-25 21:45:01 +02:00
|
|
|
publishWebsite: async ({ fetch, params }) => {
|
|
|
|
|
const websiteOverview: WebsiteOverview = (
|
|
|
|
|
await apiRequest(
|
|
|
|
|
fetch,
|
|
|
|
|
`${API_BASE_PREFIX}/website?id=eq.${params.websiteId}&select=*,settings(*),header(*),home(*),footer(*),article(*,docs_category(*)),legal_information(*),domain_prefix(*)`,
|
|
|
|
|
"GET",
|
|
|
|
|
{
|
|
|
|
|
headers: {
|
|
|
|
|
Accept: "application/vnd.pgrst.object+json"
|
|
|
|
|
},
|
|
|
|
|
returnData: true
|
2024-08-27 16:39:29 +02:00
|
|
|
}
|
2024-09-25 21:45:01 +02:00
|
|
|
)
|
|
|
|
|
).data;
|
2024-08-04 17:46:41 +02:00
|
|
|
|
2024-08-07 19:13:39 +02:00
|
|
|
generateStaticFiles(websiteOverview, false);
|
2024-08-10 22:20:57 +02:00
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
return await apiRequest(
|
|
|
|
|
fetch,
|
|
|
|
|
`${API_BASE_PREFIX}/website?id=eq.${params.websiteId}`,
|
|
|
|
|
"PATCH",
|
|
|
|
|
{
|
|
|
|
|
body: {
|
|
|
|
|
is_published: true
|
|
|
|
|
},
|
|
|
|
|
successMessage: "Successfully published website"
|
|
|
|
|
}
|
|
|
|
|
);
|
2024-09-20 15:56:07 +02:00
|
|
|
},
|
2024-09-25 21:45:01 +02:00
|
|
|
createUpdateCustomDomainPrefix: async ({ request, fetch, params }) => {
|
2024-09-20 15:56:07 +02:00
|
|
|
const data = await request.formData();
|
|
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
const oldDomainPrefix = (
|
|
|
|
|
await apiRequest(
|
|
|
|
|
fetch,
|
|
|
|
|
`${API_BASE_PREFIX}/domain_prefix?website_id=eq.${params.websiteId}`,
|
|
|
|
|
"GET",
|
|
|
|
|
{
|
|
|
|
|
headers: {
|
|
|
|
|
Accept: "application/vnd.pgrst.object+json"
|
|
|
|
|
},
|
|
|
|
|
returnData: true
|
2024-09-20 15:56:07 +02:00
|
|
|
}
|
2024-09-25 21:45:01 +02:00
|
|
|
)
|
|
|
|
|
).data;
|
2024-09-20 15:56:07 +02:00
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
const newDomainPrefix = await apiRequest(fetch, `${API_BASE_PREFIX}/domain_prefix`, "POST", {
|
2024-09-20 15:56:07 +02:00
|
|
|
headers: {
|
|
|
|
|
Prefer: "resolution=merge-duplicates",
|
|
|
|
|
Accept: "application/vnd.pgrst.object+json"
|
|
|
|
|
},
|
2024-09-25 21:45:01 +02:00
|
|
|
body: {
|
2024-09-20 15:56:07 +02:00
|
|
|
website_id: params.websiteId,
|
2024-09-25 22:05:39 +02:00
|
|
|
prefix: data.get("domain-prefix")
|
2024-09-25 21:45:01 +02:00
|
|
|
},
|
|
|
|
|
successMessage: "Successfully created/updated domain prefix"
|
2024-09-20 15:56:07 +02:00
|
|
|
});
|
|
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
if (!newDomainPrefix.success) {
|
|
|
|
|
return newDomainPrefix;
|
2024-09-20 15:56:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await rename(
|
|
|
|
|
join(
|
|
|
|
|
"/",
|
|
|
|
|
"var",
|
|
|
|
|
"www",
|
|
|
|
|
"archtika-websites",
|
2024-09-25 21:45:01 +02:00
|
|
|
oldDomainPrefix?.prefix ? oldDomainPrefix.prefix : params.websiteId
|
2024-09-20 15:56:07 +02:00
|
|
|
),
|
|
|
|
|
join("/", "var", "www", "archtika-websites", data.get("domain-prefix") as string)
|
|
|
|
|
);
|
|
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
return newDomainPrefix;
|
2024-09-20 15:56:07 +02:00
|
|
|
},
|
2024-09-25 21:45:01 +02:00
|
|
|
deleteCustomDomainPrefix: async ({ fetch, params }) => {
|
|
|
|
|
const customPrefix = await apiRequest(
|
|
|
|
|
fetch,
|
|
|
|
|
`${API_BASE_PREFIX}/domain_prefix?website_id=eq.${params.websiteId}`,
|
|
|
|
|
"DELETE",
|
|
|
|
|
{
|
|
|
|
|
headers: {
|
|
|
|
|
Prefer: "return=representation",
|
|
|
|
|
Accept: "application/vnd.pgrst.object+json"
|
|
|
|
|
},
|
|
|
|
|
successMessage: "Successfully deleted domain prefix",
|
|
|
|
|
returnData: true
|
2024-09-20 15:56:07 +02:00
|
|
|
}
|
2024-09-25 21:45:01 +02:00
|
|
|
);
|
2024-09-20 15:56:07 +02:00
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
if (!customPrefix.success) {
|
|
|
|
|
return customPrefix;
|
2024-09-20 15:56:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await rename(
|
2024-09-25 21:45:01 +02:00
|
|
|
join("/", "var", "www", "archtika-websites", customPrefix.data.prefix),
|
2024-09-20 15:56:07 +02:00
|
|
|
join("/", "var", "www", "archtika-websites", params.websiteId)
|
|
|
|
|
);
|
|
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
return customPrefix;
|
2024-08-04 17:46:41 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-20 15:56:07 +02:00
|
|
|
const generateStaticFiles = async (websiteData: WebsiteOverview, isPreview = true) => {
|
2024-09-10 17:29:57 +02:00
|
|
|
const fileContents = (head: string, body: string) => {
|
|
|
|
|
return `
|
2024-09-07 16:45:20 +02:00
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
${head}
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
${body}
|
|
|
|
|
</body>
|
|
|
|
|
</html>`;
|
2024-09-10 17:29:57 +02:00
|
|
|
};
|
|
|
|
|
|
2024-09-25 21:45:01 +02:00
|
|
|
console.log(websiteData);
|
|
|
|
|
|
2024-09-10 17:29:57 +02:00
|
|
|
const { head, body } = render(websiteData.content_type === "Blog" ? BlogIndex : DocsIndex, {
|
|
|
|
|
props: {
|
|
|
|
|
websiteOverview: websiteData,
|
|
|
|
|
apiUrl: API_BASE_PREFIX,
|
|
|
|
|
isLegalPage: false
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-08-04 17:46:41 +02:00
|
|
|
|
|
|
|
|
let uploadDir = "";
|
|
|
|
|
|
|
|
|
|
if (isPreview) {
|
2024-08-18 13:48:36 +02:00
|
|
|
uploadDir = join("/", "var", "www", "archtika-websites", "previews", websiteData.id);
|
2024-08-04 17:46:41 +02:00
|
|
|
} else {
|
2024-09-20 15:56:07 +02:00
|
|
|
uploadDir = join(
|
|
|
|
|
"/",
|
|
|
|
|
"var",
|
|
|
|
|
"www",
|
|
|
|
|
"archtika-websites",
|
|
|
|
|
websiteData.domain_prefix?.prefix ?? websiteData.id
|
|
|
|
|
);
|
2024-08-04 17:46:41 +02:00
|
|
|
}
|
2024-08-04 16:15:09 +02:00
|
|
|
|
|
|
|
|
await mkdir(uploadDir, { recursive: true });
|
2024-09-10 17:29:57 +02:00
|
|
|
await writeFile(join(uploadDir, "index.html"), fileContents(head, body));
|
2024-08-27 16:39:29 +02:00
|
|
|
await mkdir(join(uploadDir, "articles"), {
|
2024-08-18 18:17:59 +02:00
|
|
|
recursive: true
|
|
|
|
|
});
|
2024-08-04 16:15:09 +02:00
|
|
|
|
2024-09-10 17:29:57 +02:00
|
|
|
for (const article of websiteData.article ?? []) {
|
|
|
|
|
const { head, body } = render(websiteData.content_type === "Blog" ? BlogArticle : DocsArticle, {
|
|
|
|
|
props: {
|
|
|
|
|
websiteOverview: websiteData,
|
|
|
|
|
article,
|
|
|
|
|
apiUrl: API_BASE_PREFIX
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-08-03 18:07:27 +02:00
|
|
|
|
2024-09-10 17:29:57 +02:00
|
|
|
await writeFile(
|
2024-09-13 19:30:56 +02:00
|
|
|
join(uploadDir, "articles", `${slugify(article.title)}.html`),
|
2024-09-10 17:29:57 +02:00
|
|
|
fileContents(head, body)
|
|
|
|
|
);
|
2024-08-03 18:07:27 +02:00
|
|
|
}
|
2024-08-17 20:21:23 +02:00
|
|
|
|
2024-09-10 17:29:57 +02:00
|
|
|
if (websiteData.legal_information) {
|
|
|
|
|
const { head, body } = render(websiteData.content_type === "Blog" ? BlogIndex : DocsIndex, {
|
|
|
|
|
props: {
|
|
|
|
|
websiteOverview: websiteData,
|
|
|
|
|
apiUrl: API_BASE_PREFIX,
|
|
|
|
|
isLegalPage: true
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-09-08 16:42:32 +02:00
|
|
|
|
2024-09-10 17:29:57 +02:00
|
|
|
await writeFile(join(uploadDir, "legal-information.html"), fileContents(head, body));
|
2024-09-08 16:42:32 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-20 19:17:05 +02:00
|
|
|
const commonStyles = await readFile(`${process.cwd()}/template-styles/common-styles.css`, {
|
2024-08-17 20:21:23 +02:00
|
|
|
encoding: "utf-8"
|
|
|
|
|
});
|
2024-08-27 16:39:29 +02:00
|
|
|
const specificStyles = await readFile(
|
|
|
|
|
`${process.cwd()}/template-styles/${websiteData.content_type.toLowerCase()}-styles.css`,
|
|
|
|
|
{
|
|
|
|
|
encoding: "utf-8"
|
|
|
|
|
}
|
|
|
|
|
);
|
2024-08-25 16:31:12 +02:00
|
|
|
await writeFile(
|
|
|
|
|
join(uploadDir, "styles.css"),
|
|
|
|
|
commonStyles
|
|
|
|
|
.concat(specificStyles)
|
|
|
|
|
.replace(
|
|
|
|
|
/--color-accent:\s*(.*?);/,
|
2024-09-10 17:29:57 +02:00
|
|
|
`--color-accent: ${websiteData.settings.accent_color_dark_theme};`
|
2024-08-25 16:31:12 +02:00
|
|
|
)
|
|
|
|
|
.replace(
|
|
|
|
|
/@media\s*\(prefers-color-scheme:\s*dark\)\s*{[^}]*--color-accent:\s*(.*?);/,
|
|
|
|
|
(match) =>
|
|
|
|
|
match.replace(
|
|
|
|
|
/--color-accent:\s*(.*?);/,
|
2024-09-10 17:29:57 +02:00
|
|
|
`--color-accent: ${websiteData.settings.accent_color_light_theme};`
|
2024-08-25 16:31:12 +02:00
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
2024-08-03 18:07:27 +02:00
|
|
|
};
|