From bc5e494bbb7cc11dc69aed6f477d81b804f93f67 Mon Sep 17 00:00:00 2001 From: thiloho <123883702+thiloho@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:45:01 +0200 Subject: [PATCH] Create fetch utility function --- web-app/src/hooks.server.ts | 10 + web-app/src/lib/server/utils.ts | 45 ++++ web-app/src/lib/utils.ts | 2 +- .../routes/(anonymous)/login/+page.server.ts | 22 +- .../(anonymous)/register/+page.server.ts | 19 +- .../routes/(authenticated)/+page.server.ts | 135 ++++------ .../(authenticated)/account/+page.server.ts | 22 +- .../website/[websiteId]/+layout.server.ts | 37 ++- .../website/[websiteId]/+page.server.ts | 240 +++++++----------- .../[websiteId]/articles/+page.server.ts | 69 ++--- .../articles/[articleId]/+page.server.ts | 112 ++++---- .../[websiteId]/categories/+page.server.ts | 96 +++---- .../[websiteId]/collaborators/+page.server.ts | 116 ++++----- .../legal-information/+page.server.ts | 72 +++--- .../legal-information/+page.svelte | 6 +- .../website/[websiteId]/logs/+page.server.ts | 45 ++-- .../[websiteId]/publish/+page.server.ts | 165 ++++++------ web-app/src/routes/+layout.svelte | 4 + web-app/tests/collaborator.spec.ts | 4 +- web-app/tests/website.spec.ts | 4 +- 20 files changed, 525 insertions(+), 700 deletions(-) diff --git a/web-app/src/hooks.server.ts b/web-app/src/hooks.server.ts index 51a677c..992f487 100644 --- a/web-app/src/hooks.server.ts +++ b/web-app/src/hooks.server.ts @@ -30,3 +30,13 @@ export const handle = async ({ event, resolve }) => { return await resolve(event); }; + +export const handleFetch = async ({ event, request, fetch }) => { + const sessionToken = event.cookies.get("session_token"); + + if (sessionToken) { + request.headers.set("Authorization", `Bearer ${sessionToken}`); + } + + return fetch(request); +}; diff --git a/web-app/src/lib/server/utils.ts b/web-app/src/lib/server/utils.ts index 22d499a..134430c 100644 --- a/web-app/src/lib/server/utils.ts +++ b/web-app/src/lib/server/utils.ts @@ -9,3 +9,48 @@ export const REGISTRATION_IS_DISABLED = dev : process.env.REGISTRATION_IS_DISABLED ? JSON.parse(process.env.REGISTRATION_IS_DISABLED) : false; + +export const apiRequest = async ( + customFetch: typeof fetch, + url: string, + method: "HEAD" | "GET" | "POST" | "PATCH" | "DELETE", + options: { + headers?: Record; + body?: any; + successMessage?: string; + returnData?: boolean; + } = { + headers: {}, + body: undefined, + successMessage: "Operation was successful", + returnData: false + } +) => { + const headers = { + "Content-Type": "application/json", + ...options.headers + }; + + const response = await customFetch(url, { + method, + headers, + ...(!["HEAD", "GET", "DELETE"].includes(method) && { + body: options.body instanceof ArrayBuffer ? options.body : JSON.stringify(options.body) + }) + }); + + if (!response.ok) { + const errorData = await response.json(); + return { success: false, message: errorData.message }; + } + + if (options.returnData) { + return { + success: true, + message: options.successMessage, + data: method === "HEAD" ? response : await response.json() + }; + } + + return { success: true, message: options.successMessage }; +}; diff --git a/web-app/src/lib/utils.ts b/web-app/src/lib/utils.ts index a16e396..0af6b4c 100644 --- a/web-app/src/lib/utils.ts +++ b/web-app/src/lib/utils.ts @@ -177,7 +177,7 @@ export const handleImagePaste = async (event: ClipboardEvent, API_BASE_PREFIX: s const response = await request.json(); if (JSON.parse(response.data)[1]) { - const fileId = JSON.parse(response.data)[3]; + const fileId = JSON.parse(response.data)[4]; const fileUrl = `${API_BASE_PREFIX}/rpc/retrieve_file?id=${fileId}`; const target = event.target as HTMLTextAreaElement; diff --git a/web-app/src/routes/(anonymous)/login/+page.server.ts b/web-app/src/routes/(anonymous)/login/+page.server.ts index ce747c8..747b6a7 100644 --- a/web-app/src/routes/(anonymous)/login/+page.server.ts +++ b/web-app/src/routes/(anonymous)/login/+page.server.ts @@ -1,26 +1,24 @@ import type { Actions } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; export const actions: Actions = { default: async ({ request, cookies, fetch }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/rpc/login`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ + const response = await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/login`, "POST", { + body: { username: data.get("username"), pass: data.get("password") - }) + }, + returnData: true, + successMessage: "Successfully logged in, you can refresh the page" }); - const response = await res.json(); - - if (!res.ok) { - return { success: false, message: response.message }; + if (!response.success) { + return response; } - cookies.set("session_token", response.token, { path: "/" }); - return { success: true, message: "Successfully logged in" }; + cookies.set("session_token", response.data.token, { path: "/" }); + return response; } }; diff --git a/web-app/src/routes/(anonymous)/register/+page.server.ts b/web-app/src/routes/(anonymous)/register/+page.server.ts index 4fd0aef..5bef59b 100644 --- a/web-app/src/routes/(anonymous)/register/+page.server.ts +++ b/web-app/src/routes/(anonymous)/register/+page.server.ts @@ -1,5 +1,5 @@ import type { Actions, PageServerLoad } from "./$types"; -import { API_BASE_PREFIX, REGISTRATION_IS_DISABLED } from "$lib/server/utils"; +import { API_BASE_PREFIX, REGISTRATION_IS_DISABLED, apiRequest } from "$lib/server/utils"; export const load: PageServerLoad = async () => { return { @@ -11,21 +11,12 @@ export const actions: Actions = { default: async ({ request, fetch }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/rpc/register`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ + return await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/register`, "POST", { + body: { username: data.get("username"), pass: data.get("password") - }) + }, + successMessage: "Successfully registered, you can now login" }); - - const response = await res.json(); - - if (!res.ok) { - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully registered, you can now login" }; } }; diff --git a/web-app/src/routes/(authenticated)/+page.server.ts b/web-app/src/routes/(authenticated)/+page.server.ts index 4482e00..fe26335 100644 --- a/web-app/src/routes/(authenticated)/+page.server.ts +++ b/web-app/src/routes/(authenticated)/+page.server.ts @@ -1,10 +1,11 @@ import type { Actions, PageServerLoad } from "./$types"; +import { apiRequest } from "$lib/server/utils"; import { API_BASE_PREFIX } from "$lib/server/utils"; import { rm } from "node:fs/promises"; import { join } from "node:path"; -import type { Website, WebsiteInput } from "$lib/db-schema"; +import type { Website } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ fetch, cookies, url, locals }) => { +export const load: PageServerLoad = async ({ fetch, url, locals }) => { const searchQuery = url.searchParams.get("website_search_query"); const filterBy = url.searchParams.get("website_filter"); @@ -27,28 +28,22 @@ export const load: PageServerLoad = async ({ fetch, cookies, url, locals }) => { const constructedFetchUrl = `${baseFetchUrl}&${params.toString()}`; - const totalWebsitesData = await fetch(baseFetchUrl, { - method: "HEAD", + const totalWebsites = await apiRequest(fetch, baseFetchUrl, "HEAD", { headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, Prefer: "count=exact" - } + }, + returnData: true }); const totalWebsiteCount = Number( - totalWebsitesData.headers.get("content-range")?.split("/").at(-1) + totalWebsites.data.headers.get("content-range")?.split("/").at(-1) ); - const websiteData = await fetch(constructedFetchUrl, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } - }); - - const websites: Website[] = await websiteData.json(); + const websites: Website[] = ( + await apiRequest(fetch, constructedFetchUrl, "GET", { + returnData: true + }) + ).data; return { totalWebsiteCount, @@ -57,91 +52,63 @@ export const load: PageServerLoad = async ({ fetch, cookies, url, locals }) => { }; export const actions: Actions = { - createWebsite: async ({ request, fetch, cookies }) => { + createWebsite: async ({ request, fetch }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/rpc/create_website`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ - content_type: data.get("content-type") as string, - title: data.get("title") as string - } satisfies WebsiteInput) - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully created website" }; - }, - updateWebsite: async ({ request, cookies, fetch }) => { - const data = await request.formData(); - - const res = await fetch(`${API_BASE_PREFIX}/website?id=eq.${data.get("id")}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ + return await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/create_website`, "POST", { + body: { + content_type: data.get("content-type"), title: data.get("title") - }) + }, + successMessage: "Successfully created website" }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully updated website" }; }, - deleteWebsite: async ({ request, cookies, fetch }) => { + updateWebsite: async ({ request, fetch }) => { const data = await request.formData(); - const oldDomainPrefixData = await fetch( - `${API_BASE_PREFIX}/domain_prefix?website_id=eq.${data.get("id")}`, - { - method: "GET", + return await apiRequest(fetch, `${API_BASE_PREFIX}/website?id=eq.${data.get("id")}`, "PATCH", { + body: { + title: data.get("title") + }, + successMessage: "Successfully updated website" + }); + }, + deleteWebsite: async ({ request, fetch }) => { + const data = await request.formData(); + const id = data.get("id"); + + const oldDomainPrefix = ( + await apiRequest(fetch, `${API_BASE_PREFIX}/domain_prefix?website_id=eq.${id}`, "GET", { headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, Accept: "application/vnd.pgrst.object+json" - } + }, + returnData: true + }) + ).data; + + const deleteWebsite = await apiRequest( + fetch, + `${API_BASE_PREFIX}/website?id=eq.${id}`, + "DELETE", + { + successMessage: "Successfully deleted website" } ); - const oldDomainPrefix = await oldDomainPrefixData.json(); - const res = await fetch(`${API_BASE_PREFIX}/website?id=eq.${data.get("id")}`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; + if (!deleteWebsite.success) { + return deleteWebsite; } - await rm(join("/", "var", "www", "archtika-websites", "previews", data.get("id") as string), { + await rm(join("/", "var", "www", "archtika-websites", "previews", id as string), { recursive: true, force: true }); - await rm( - join("/", "var", "www", "archtika-websites", oldDomainPrefix.prefix ?? data.get("id")), - { - recursive: true, - force: true - } - ); + await rm(join("/", "var", "www", "archtika-websites", oldDomainPrefix?.prefix ?? id), { + recursive: true, + force: true + }); - return { success: true, message: "Successfully deleted website" }; + return deleteWebsite; } }; diff --git a/web-app/src/routes/(authenticated)/account/+page.server.ts b/web-app/src/routes/(authenticated)/account/+page.server.ts index 6306267..aa61f82 100644 --- a/web-app/src/routes/(authenticated)/account/+page.server.ts +++ b/web-app/src/routes/(authenticated)/account/+page.server.ts @@ -1,5 +1,5 @@ import type { Actions, PageServerLoad } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; export const load: PageServerLoad = async ({ locals }) => { return { @@ -16,24 +16,18 @@ export const actions: Actions = { deleteAccount: async ({ request, fetch, cookies }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/rpc/delete_account`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ + const response = await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/delete_account`, "POST", { + body: { pass: data.get("password") - }) + }, + successMessage: "Successfully deleted account" }); - const response = await res.json(); - - if (!res.ok) { - return { success: false, message: response.message }; + if (!response.success) { + return response; } cookies.delete("session_token", { path: "/" }); - return { success: true, message: "Successfully deleted account" }; + return response; } }; diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/+layout.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/+layout.server.ts index 560b904..9271b14 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/+layout.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/+layout.server.ts @@ -1,36 +1,35 @@ import type { LayoutServerLoad } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; import { error } from "@sveltejs/kit"; import type { Website, Home, User } from "$lib/db-schema"; -export const load: LayoutServerLoad = async ({ params, fetch, cookies }) => { - const websiteData = await fetch( +export const load: LayoutServerLoad = async ({ params, fetch }) => { + const websiteData = await apiRequest( + fetch, `${API_BASE_PREFIX}/website?id=eq.${params.websiteId}&select=*,user!user_id(username)`, + "GET", { - method: "GET", headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, Accept: "application/vnd.pgrst.object+json" - } + }, + returnData: true } ); - if (!websiteData.ok) { + const website: Website & { user: { username: User["username"] } } = websiteData.data; + + if (!websiteData.success) { throw error(404, "Website not found"); } - const homeData = await fetch(`${API_BASE_PREFIX}/home?website_id=eq.${params.websiteId}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" - } - }); - - const website: Website & { user: { username: User["username"] } } = await websiteData.json(); - const home: Home = await homeData.json(); + const home: Home = ( + await apiRequest(fetch, `${API_BASE_PREFIX}/home?website_id=eq.${params.websiteId}`, "GET", { + headers: { + Accept: "application/vnd.pgrst.object+json" + }, + returnData: true + }) + ).data; return { website, diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/+page.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/+page.server.ts index 8d61ee6..3a1baa7 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/+page.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/+page.server.ts @@ -1,41 +1,40 @@ import type { Actions, PageServerLoad } from "./$types"; import { API_BASE_PREFIX } from "$lib/server/utils"; +import { apiRequest } from "$lib/server/utils"; import type { Settings, Header, Footer } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ params, fetch, cookies }) => { - const globalSettingsData = await fetch( - `${API_BASE_PREFIX}/settings?website_id=eq.${params.websiteId}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" +export const load: PageServerLoad = async ({ params, fetch }) => { + const globalSettings: Settings = ( + await apiRequest( + fetch, + `${API_BASE_PREFIX}/settings?website_id=eq.${params.websiteId}`, + "GET", + { + headers: { + Accept: "application/vnd.pgrst.object+json" + }, + returnData: true } - } - ); + ) + ).data; - const headerData = await fetch(`${API_BASE_PREFIX}/header?website_id=eq.${params.websiteId}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" - } - }); + const header: Header = ( + await apiRequest(fetch, `${API_BASE_PREFIX}/header?website_id=eq.${params.websiteId}`, "GET", { + headers: { + Accept: "application/vnd.pgrst.object+json" + }, + returnData: true + }) + ).data; - const footerData = await fetch(`${API_BASE_PREFIX}/footer?website_id=eq.${params.websiteId}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" - } - }); - - const globalSettings: Settings = await globalSettingsData.json(); - const header: Header = await headerData.json(); - const footer: Footer = await footerData.json(); + const footer: Footer = ( + await apiRequest(fetch, `${API_BASE_PREFIX}/footer?website_id=eq.${params.websiteId}`, "GET", { + headers: { + Accept: "application/vnd.pgrst.object+json" + }, + returnData: true + }) + ).data; return { globalSettings, @@ -46,13 +45,12 @@ export const load: PageServerLoad = async ({ params, fetch, cookies }) => { }; export const actions: Actions = { - updateGlobal: async ({ request, fetch, cookies, params }) => { + updateGlobal: async ({ request, fetch, params }) => { const data = await request.formData(); const faviconFile = data.get("favicon") as File; const headers: Record = { "Content-Type": "application/octet-stream", - Authorization: `Bearer ${cookies.get("session_token")}`, Accept: "application/vnd.pgrst.object+json", "X-Website-Id": params.websiteId }; @@ -62,48 +60,36 @@ export const actions: Actions = { headers["X-Original-Filename"] = faviconFile.name; } - const uploadedImageData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, { - method: "POST", + const uploadedImage = await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/upload_file`, "POST", { headers, - body: faviconFile ? await faviconFile.arrayBuffer() : null + body: faviconFile ? await faviconFile.arrayBuffer() : null, + returnData: true }); - const uploadedImage = await uploadedImageData.json(); - - if (!uploadedImageData.ok && (faviconFile?.size ?? 0 > 0)) { - return { success: false, message: uploadedImage.message }; + if (!uploadedImage.success && (faviconFile?.size ?? 0 > 0)) { + return uploadedImage; } - const res = await fetch(`${API_BASE_PREFIX}/settings?website_id=eq.${params.websiteId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ - accent_color_light_theme: data.get("accent-color-light"), - accent_color_dark_theme: data.get("accent-color-dark"), - favicon_image: uploadedImage.file_id - }) - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { - success: true, - message: "Successfully updated global settings" - }; + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/settings?website_id=eq.${params.websiteId}`, + "PATCH", + { + body: { + accent_color_light_theme: data.get("accent-color-light"), + accent_color_dark_theme: data.get("accent-color-dark"), + favicon_image: uploadedImage.data?.file_id + }, + successMessage: "Successfully updated global settings" + } + ); }, - updateHeader: async ({ request, fetch, cookies, params }) => { + updateHeader: async ({ request, fetch, params }) => { const data = await request.formData(); const logoImage = data.get("logo-image") as File; const headers: Record = { "Content-Type": "application/octet-stream", - Authorization: `Bearer ${cookies.get("session_token")}`, Accept: "application/vnd.pgrst.object+json", "X-Website-Id": params.websiteId }; @@ -113,109 +99,75 @@ export const actions: Actions = { headers["X-Original-Filename"] = logoImage.name; } - const uploadedImageData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, { - method: "POST", + const uploadedImage = await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/upload_file`, "POST", { headers, - body: logoImage ? await logoImage.arrayBuffer() : null + body: logoImage ? await logoImage.arrayBuffer() : null, + returnData: true }); - const uploadedImage = await uploadedImageData.json(); - - if (!uploadedImageData.ok && (logoImage?.size ?? 0 > 0)) { + if (!uploadedImage.success && (logoImage?.size ?? 0 > 0)) { return { success: false, message: uploadedImage.message }; } - const res = await fetch(`${API_BASE_PREFIX}/header?website_id=eq.${params.websiteId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ - logo_type: data.get("logo-type"), - logo_text: data.get("logo-text"), - logo_image: uploadedImage.file_id - }) - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { - success: true, - message: "Successfully updated header" - }; + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/header?website_id=eq.${params.websiteId}`, + "PATCH", + { + body: { + logo_type: data.get("logo-type"), + logo_text: data.get("logo-text"), + logo_image: uploadedImage.data?.file_id + }, + successMessage: "Successfully updated header" + } + ); }, - updateHome: async ({ request, fetch, cookies, params }) => { + updateHome: async ({ request, fetch, params }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/home?website_id=eq.${params.websiteId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ - main_content: data.get("main-content") - }) - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully updated home" }; + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/home?website_id=eq.${params.websiteId}`, + "PATCH", + { + body: { + main_content: data.get("main-content") + }, + successMessage: "Successfully updated home" + } + ); }, - updateFooter: async ({ request, fetch, cookies, params }) => { + updateFooter: async ({ request, fetch, params }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/footer?website_id=eq.${params.websiteId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ - additional_text: data.get("additional-text") - }) - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { - success: true, - message: "Successfully updated footer" - }; + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/footer?website_id=eq.${params.websiteId}`, + "PATCH", + { + body: { + additional_text: data.get("additional-text") + }, + successMessage: "Successfully updated footer" + } + ); }, - pasteImage: async ({ request, fetch, cookies, params }) => { + pasteImage: async ({ request, fetch, params }) => { const data = await request.formData(); const file = data.get("file") as File; - const fileData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, { - method: "POST", + return await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/upload_file`, "POST", { headers: { "Content-Type": "application/octet-stream", - Authorization: `Bearer ${cookies.get("session_token")}`, Accept: "application/vnd.pgrst.object+json", "X-Website-Id": params.websiteId, "X-Mimetype": file.type, "X-Original-Filename": file.name }, - body: await file.arrayBuffer() + body: await file.arrayBuffer(), + successMessage: "Successfully uploaded image", + returnData: true }); - - const fileJSON = await fileData.json(); - - if (!fileData.ok) { - return { success: false, message: fileJSON.message }; - } - - return { success: true, message: "Successfully uploaded image", fileId: fileJSON.file_id }; } }; diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/articles/+page.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/articles/+page.server.ts index 7b37440..ac124fb 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/articles/+page.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/articles/+page.server.ts @@ -1,8 +1,9 @@ import type { Actions, PageServerLoad } from "./$types"; import { API_BASE_PREFIX } from "$lib/server/utils"; -import type { Article, ArticleInput, DocsCategory } from "$lib/db-schema"; +import { apiRequest } from "$lib/server/utils"; +import type { Article, DocsCategory } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ params, fetch, cookies, url, parent, locals }) => { +export const load: PageServerLoad = async ({ params, fetch, url, parent, locals }) => { const searchQuery = url.searchParams.get("article_search_query"); const filterBy = url.searchParams.get("article_filter"); @@ -34,28 +35,22 @@ export const load: PageServerLoad = async ({ params, fetch, cookies, url, parent const constructedFetchUrl = `${baseFetchUrl}&${parameters.toString()}`; - const totalArticlesData = await fetch(baseFetchUrl, { - method: "HEAD", + const totalArticles = await apiRequest(fetch, baseFetchUrl, "HEAD", { headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, Prefer: "count=exact" - } + }, + returnData: true }); const totalArticleCount = Number( - totalArticlesData.headers.get("content-range")?.split("/").at(-1) + totalArticles.data.headers.get("content-range")?.split("/").at(-1) ); - const articlesData = await fetch(constructedFetchUrl, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } - }); - - const articles: (Article & { docs_category: DocsCategory | null })[] = await articlesData.json(); + const articles: (Article & { docs_category: DocsCategory | null })[] = ( + await apiRequest(fetch, constructedFetchUrl, "GET", { + returnData: true + }) + ).data; return { totalArticleCount, @@ -66,44 +61,22 @@ export const load: PageServerLoad = async ({ params, fetch, cookies, url, parent }; export const actions: Actions = { - createArticle: async ({ request, fetch, cookies, params }) => { + createArticle: async ({ request, fetch, params }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/article`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ + return await apiRequest(fetch, `${API_BASE_PREFIX}/article`, "POST", { + body: { website_id: params.websiteId, - title: data.get("title") as string - } satisfies ArticleInput) + title: data.get("title") + }, + successMessage: "Successfully created article" }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully created article" }; }, - deleteArticle: async ({ request, fetch, cookies }) => { + deleteArticle: async ({ request, fetch }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/article?id=eq.${data.get("id")}`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } + return await apiRequest(fetch, `${API_BASE_PREFIX}/article?id=eq.${data.get("id")}`, "DELETE", { + successMessage: "Successfully deleted article" }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully deleted article" }; } }; diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/articles/[articleId]/+page.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/articles/[articleId]/+page.server.ts index eb2c0ea..83a1967 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/articles/[articleId]/+page.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/articles/[articleId]/+page.server.ts @@ -1,30 +1,28 @@ import type { Actions, PageServerLoad } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; import type { Article, DocsCategory } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ parent, params, cookies, fetch }) => { - const articleData = await fetch(`${API_BASE_PREFIX}/article?id=eq.${params.articleId}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" - } - }); - - const categoryData = await fetch( - `${API_BASE_PREFIX}/docs_category?website_id=eq.${params.websiteId}&order=category_weight.desc`, - { - method: "GET", +export const load: PageServerLoad = async ({ parent, params, fetch }) => { + const article: Article = ( + await apiRequest(fetch, `${API_BASE_PREFIX}/article?id=eq.${params.articleId}`, "GET", { headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } - } - ); + Accept: "application/vnd.pgrst.object+json" + }, + returnData: true + }) + ).data; + + const categories: DocsCategory[] = ( + await apiRequest( + fetch, + `${API_BASE_PREFIX}/docs_category?website_id=eq.${params.websiteId}&order=category_weight.desc`, + "GET", + { + returnData: true + } + ) + ).data; - const article: Article = await articleData.json(); - const categories: DocsCategory[] = await categoryData.json(); const { website } = await parent(); return { website, article, categories, API_BASE_PREFIX }; @@ -47,66 +45,50 @@ export const actions: Actions = { headers["X-Original-Filename"] = coverFile.name; } - const uploadedImageData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, { - method: "POST", + const uploadedImage = await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/upload_file`, "POST", { headers, - body: coverFile ? await coverFile.arrayBuffer() : null + body: coverFile ? await coverFile.arrayBuffer() : null, + returnData: true }); - const uploadedImage = await uploadedImageData.json(); - - if (!uploadedImageData.ok && (coverFile?.size ?? 0 > 0)) { + if (!uploadedImage.success && (coverFile?.size ?? 0 > 0)) { return { success: false, message: uploadedImage.message }; } - const res = await fetch(`${API_BASE_PREFIX}/article?id=eq.${params.articleId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ - title: data.get("title"), - meta_description: data.get("description"), - meta_author: data.get("author"), - cover_image: uploadedImage.file_id, - publication_date: data.get("publication-date"), - main_content: data.get("main-content"), - category: data.get("category"), - article_weight: data.get("article-weight") ? data.get("article-weight") : null - }) - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully updated article" }; + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/article?id=eq.${params.articleId}`, + "PATCH", + { + body: { + title: data.get("title"), + meta_description: data.get("description"), + meta_author: data.get("author"), + cover_image: uploadedImage.data?.file_id, + publication_date: data.get("publication-date"), + main_content: data.get("main-content"), + category: data.get("category"), + article_weight: data.get("article-weight") ? data.get("article-weight") : null + }, + successMessage: "Successfully updated article" + } + ); }, - pasteImage: async ({ request, fetch, cookies, params }) => { + pasteImage: async ({ request, fetch, params }) => { const data = await request.formData(); const file = data.get("file") as File; - const fileData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, { - method: "POST", + return await apiRequest(fetch, `${API_BASE_PREFIX}/rpc/upload_file`, "POST", { headers: { "Content-Type": "application/octet-stream", - Authorization: `Bearer ${cookies.get("session_token")}`, Accept: "application/vnd.pgrst.object+json", "X-Website-Id": params.websiteId, "X-Mimetype": file.type, "X-Original-Filename": file.name }, - body: await file.arrayBuffer() + body: await file.arrayBuffer(), + successMessage: "Successfully uploaded image", + returnData: true }); - - const fileJSON = await fileData.json(); - - if (!fileData.ok) { - return { success: false, message: fileJSON.message }; - } - - return { success: true, message: "Successfully uploaded image", fileId: fileJSON.file_id }; } }; diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/categories/+page.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/categories/+page.server.ts index 807dd05..0254e87 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/categories/+page.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/categories/+page.server.ts @@ -1,20 +1,19 @@ import type { Actions, PageServerLoad } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; -import type { DocsCategory, DocsCategoryInput } from "$lib/db-schema"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; +import type { DocsCategory } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ parent, params, cookies, fetch }) => { - const categoryData = await fetch( - `${API_BASE_PREFIX}/docs_category?website_id=eq.${params.websiteId}&order=category_weight.desc`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` +export const load: PageServerLoad = async ({ parent, params, fetch }) => { + const categories: DocsCategory[] = ( + await apiRequest( + fetch, + `${API_BASE_PREFIX}/docs_category?website_id=eq.${params.websiteId}&order=category_weight.desc`, + "GET", + { + returnData: true } - } - ); + ) + ).data; - const categories: DocsCategory[] = await categoryData.json(); const { website, home } = await parent(); return { @@ -25,73 +24,44 @@ export const load: PageServerLoad = async ({ parent, params, cookies, fetch }) = }; export const actions: Actions = { - createCategory: async ({ request, fetch, cookies, params }) => { + createCategory: async ({ request, fetch, params }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/docs_category`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ + return await apiRequest(fetch, `${API_BASE_PREFIX}/docs_category`, "POST", { + body: { website_id: params.websiteId, - category_name: data.get("category-name") as string, - category_weight: data.get("category-weight") as unknown as number - } satisfies DocsCategoryInput) + category_name: data.get("category-name"), + category_weight: data.get("category-weight") + }, + successMessage: "Successfully created category" }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully created category" }; }, - updateCategory: async ({ request, fetch, cookies, params }) => { + updateCategory: async ({ request, fetch }) => { const data = await request.formData(); - const res = await fetch( - `${API_BASE_PREFIX}/docs_category?website_id=eq.${params.websiteId}&id=eq.${data.get("category-id")}`, + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/docs_category?id=eq.${data.get("category-id")}`, + "PATCH", { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ + body: { category_name: data.get("category-name"), category_weight: data.get("category-weight") - }) + }, + successMessage: "Successfully updated category" } ); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully updated category" }; }, - deleteCategory: async ({ request, fetch, cookies, params }) => { + deleteCategory: async ({ request, fetch }) => { const data = await request.formData(); - const res = await fetch( - `${API_BASE_PREFIX}/docs_category?website_id=eq.${params.websiteId}&id=eq.${data.get("category-id")}`, + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/docs_category?id=eq.${data.get("category-id")}`, + "DELETE", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } + successMessage: "Successfully deleted category" } ); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully deleted category" }; } }; diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/collaborators/+page.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/collaborators/+page.server.ts index 89842a1..c574301 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/collaborators/+page.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/collaborators/+page.server.ts @@ -1,22 +1,20 @@ import type { Actions, PageServerLoad } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; -import type { Collab, CollabInput, User } from "$lib/db-schema"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; +import type { Collab, User } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ parent, params, fetch, cookies }) => { - const { website, home } = await parent(); - - const collabData = await fetch( - `${API_BASE_PREFIX}/collab?website_id=eq.${params.websiteId}&select=*,user!user_id(*)&order=last_modified_at.desc,added_at.desc`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` +export const load: PageServerLoad = async ({ parent, params, fetch }) => { + const collaborators: (Collab & { user: User })[] = ( + await apiRequest( + fetch, + `${API_BASE_PREFIX}/collab?website_id=eq.${params.websiteId}&select=*,user!user_id(*)&order=last_modified_at.desc,added_at.desc`, + "GET", + { + returnData: true } - } - ); + ) + ).data; - const collaborators: (Collab & { user: User })[] = await collabData.json(); + const { website, home } = await parent(); return { website, @@ -26,83 +24,57 @@ export const load: PageServerLoad = async ({ parent, params, fetch, cookies }) = }; export const actions: Actions = { - addCollaborator: async ({ request, fetch, cookies, params }) => { + addCollaborator: async ({ request, fetch, params }) => { const data = await request.formData(); - const userData = await fetch(`${API_BASE_PREFIX}/user?username=eq.${data.get("username")}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" - } - }); + const user: User = ( + await apiRequest( + fetch, + `${API_BASE_PREFIX}/user?username=eq.${data.get("username")}`, + "GET", + { + headers: { + Accept: "application/vnd.pgrst.object+json" + }, + returnData: true + } + ) + ).data; - const user: User = await userData.json(); - - const res = await fetch(`${API_BASE_PREFIX}/collab`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ + return await apiRequest(fetch, `${API_BASE_PREFIX}/collab`, "POST", { + body: { website_id: params.websiteId, user_id: user.id, - permission_level: data.get("permission-level") as unknown as number - } satisfies CollabInput) + permission_level: data.get("permission-level") + }, + successMessage: "Successfully added collaborator" }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully added collaborator" }; }, - updateCollaborator: async ({ request, fetch, cookies, params }) => { + updateCollaborator: async ({ request, fetch, params }) => { const data = await request.formData(); - const res = await fetch( + return await apiRequest( + fetch, `${API_BASE_PREFIX}/collab?website_id=eq.${params.websiteId}&user_id=eq.${data.get("user-id")}`, + "PATCH", { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ + body: { permission_level: data.get("permission-level") - }) + }, + successMessage: "Successfully updated collaborator" } ); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully updated collaborator" }; }, - removeCollaborator: async ({ request, fetch, cookies, params }) => { + removeCollaborator: async ({ request, fetch, params }) => { const data = await request.formData(); - const res = await fetch( + return await apiRequest( + fetch, `${API_BASE_PREFIX}/collab?website_id=eq.${params.websiteId}&user_id=eq.${data.get("user-id")}`, + "DELETE", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } + successMessage: "Successfully removed collaborator" } ); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully removed collaborator" }; } }; diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.server.ts index 86ac858..3b6507f 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.server.ts @@ -1,23 +1,24 @@ import type { Actions, PageServerLoad } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; import { rm } from "node:fs/promises"; import { join } from "node:path"; -import type { LegalInformation, LegalInformationInput } from "$lib/db-schema"; +import type { LegalInformation } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ parent, fetch, params, cookies }) => { - const legalInformationData = await fetch( - `${API_BASE_PREFIX}/legal_information?website_id=eq.${params.websiteId}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" +export const load: PageServerLoad = async ({ parent, fetch, params }) => { + const legalInformation: LegalInformation = ( + await apiRequest( + fetch, + `${API_BASE_PREFIX}/legal_information?website_id=eq.${params.websiteId}`, + "GET", + { + headers: { + Accept: "application/vnd.pgrst.object+json" + }, + returnData: true } - } - ); + ) + ).data; - const legalInformation: LegalInformation = await legalInformationData.json(); const { website } = await parent(); return { @@ -27,48 +28,33 @@ export const load: PageServerLoad = async ({ parent, fetch, params, cookies }) = }; export const actions: Actions = { - createUpdateLegalInformation: async ({ request, fetch, cookies, params }) => { + createUpdateLegalInformation: async ({ request, fetch, params }) => { const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/legal_information`, { - method: "POST", + return await apiRequest(fetch, `${API_BASE_PREFIX}/legal_information`, "POST", { headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, Prefer: "resolution=merge-duplicates", Accept: "application/vnd.pgrst.object+json" }, - body: JSON.stringify({ + body: { website_id: params.websiteId, - main_content: data.get("main-content") as string - } satisfies LegalInformationInput) + main_content: data.get("main-content") + }, + successMessage: "Successfully created/updated legal information" }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { - success: true, - message: `Successfully ${res.status === 201 ? "created" : "updated"} legal information` - }; }, - deleteLegalInformation: async ({ fetch, cookies, params }) => { - const res = await fetch( + deleteLegalInformation: async ({ fetch, params }) => { + const deleteLegalInformation = await apiRequest( + fetch, `${API_BASE_PREFIX}/legal_information?website_id=eq.${params.websiteId}`, + "DELETE", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } + successMessage: "Successfully deleted legal information" } ); - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; + if (!deleteLegalInformation.success) { + return deleteLegalInformation; } await rm( @@ -76,6 +62,6 @@ export const actions: Actions = { { force: true } ); - return { success: true, message: `Successfully deleted legal information` }; + return deleteLegalInformation; } }; diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.svelte b/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.svelte index a4eb040..38c8e7d 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.svelte +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/legal-information/+page.svelte @@ -8,7 +8,7 @@ const { data, form }: { data: PageServerData; form: ActionData } = $props(); - let previewContent = $state(data.legalInformation.main_content); + let previewContent = $state(data.legalInformation?.main_content); let mainContentTextarea: HTMLTextAreaElement; let textareaScrollTop = $state(0); @@ -82,14 +82,14 @@ bind:value={previewContent} bind:this={mainContentTextarea} onscroll={updateScrollPercentage} - required>{data.legalInformation.main_content ?? ""}{data.legalInformation?.main_content ?? ""} - {#if data.legalInformation.main_content} + {#if data.legalInformation?.main_content}
{ +export const load: PageServerLoad = async ({ parent, fetch, params, url }) => { const userFilter = url.searchParams.get("logs_filter_user"); const resourceFilter = url.searchParams.get("logs_filter_resource"); const operationFilter = url.searchParams.get("logs_filter_operation"); @@ -27,41 +27,30 @@ export const load: PageServerLoad = async ({ parent, fetch, params, cookies, url const constructedFetchUrl = `${baseFetchUrl}&${searchParams.toString()}&limit=50&offset=${resultOffset}`; - const changeLogData = await fetch(constructedFetchUrl, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } - }); + const changeLog: (ChangeLog & { user: { username: User["username"] } })[] = ( + await apiRequest(fetch, constructedFetchUrl, "GET", { returnData: true }) + ).data; - const resultChangeLogData = await fetch(constructedFetchUrl, { - method: "HEAD", + const resultChangeLogData = await apiRequest(fetch, constructedFetchUrl, "HEAD", { headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, Prefer: "count=exact" - } + }, + returnData: true }); const resultChangeLogCount = Number( - resultChangeLogData.headers.get("content-range")?.split("/").at(-1) + resultChangeLogData.data.headers.get("content-range")?.split("/").at(-1) ); - const collabData = await fetch( - `${API_BASE_PREFIX}/collab?website_id=eq.${params.websiteId}&select=*,user!user_id(*)&order=last_modified_at.desc,added_at.desc`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - } - } - ); + const collaborators: (Collab & { user: User })[] = ( + await apiRequest( + fetch, + `${API_BASE_PREFIX}/collab?website_id=eq.${params.websiteId}&select=*,user!user_id(*)&order=last_modified_at.desc,added_at.desc`, + "GET", + { returnData: true } + ) + ).data; - const changeLog: (ChangeLog & { user: { username: User["username"] } })[] = - await changeLogData.json(); - const collaborators: (Collab & { user: User })[] = await collabData.json(); const { website, home } = await parent(); return { diff --git a/web-app/src/routes/(authenticated)/website/[websiteId]/publish/+page.server.ts b/web-app/src/routes/(authenticated)/website/[websiteId]/publish/+page.server.ts index 08101b9..7542ef3 100644 --- a/web-app/src/routes/(authenticated)/website/[websiteId]/publish/+page.server.ts +++ b/web-app/src/routes/(authenticated)/website/[websiteId]/publish/+page.server.ts @@ -2,29 +2,28 @@ import { readFile, mkdir, writeFile, rename } from "node:fs/promises"; import { join } from "node:path"; import { type WebsiteOverview, slugify } from "$lib/utils"; import type { Actions, PageServerLoad } from "./$types"; -import { API_BASE_PREFIX } from "$lib/server/utils"; +import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils"; import { render } from "svelte/server"; import BlogIndex from "$lib/templates/blog/BlogIndex.svelte"; import BlogArticle from "$lib/templates/blog/BlogArticle.svelte"; import DocsIndex from "$lib/templates/docs/DocsIndex.svelte"; import DocsArticle from "$lib/templates/docs/DocsArticle.svelte"; import { dev } from "$app/environment"; -import type { DomainPrefixInput } from "$lib/db-schema"; -export const load: PageServerLoad = async ({ params, fetch, cookies }) => { - const websiteOverviewData = await fetch( - `${API_BASE_PREFIX}/website?id=eq.${params.websiteId}&select=*,settings(*),header(*),home(*),footer(*),article(*,docs_category(*)),legal_information(*),domain_prefix(*)`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" +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 } - } - ); - - const websiteOverview: WebsiteOverview = await websiteOverviewData.json(); + ) + ).data; generateStaticFiles(websiteOverview); @@ -53,73 +52,66 @@ export const load: PageServerLoad = async ({ params, fetch, cookies }) => { }; export const actions: Actions = { - publishWebsite: async ({ fetch, params, cookies }) => { - const websiteOverviewData = await fetch( - `${API_BASE_PREFIX}/website?id=eq.${params.websiteId}&select=*,settings(*),header(*),home(*),footer(*),article(*,docs_category(*)),legal_information(*),domain_prefix(*)`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" + 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 } - } - ); + ) + ).data; - const websiteOverview = await websiteOverviewData.json(); generateStaticFiles(websiteOverview, false); - const res = await fetch(`${API_BASE_PREFIX}/website?id=eq.${params.websiteId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}` - }, - body: JSON.stringify({ - is_published: true - }) - }); - - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; - } - - return { success: true, message: "Successfully published website" }; - }, - createUpdateCustomDomainPrefix: async ({ request, fetch, params, cookies }) => { - const data = await request.formData(); - - const oldDomainPrefixData = await fetch( - `${API_BASE_PREFIX}/domain_prefix?website_id=eq.${params.websiteId}`, + return await apiRequest( + fetch, + `${API_BASE_PREFIX}/website?id=eq.${params.websiteId}`, + "PATCH", { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Accept: "application/vnd.pgrst.object+json" - } + body: { + is_published: true + }, + successMessage: "Successfully published website" } ); - const oldDomainPrefix = await oldDomainPrefixData.json(); + }, + createUpdateCustomDomainPrefix: async ({ request, fetch, params }) => { + const data = await request.formData(); - const res = await fetch(`${API_BASE_PREFIX}/domain_prefix`, { - method: "POST", + 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 + } + ) + ).data; + + const newDomainPrefix = await apiRequest(fetch, `${API_BASE_PREFIX}/domain_prefix`, "POST", { headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, Prefer: "resolution=merge-duplicates", Accept: "application/vnd.pgrst.object+json" }, - body: JSON.stringify({ + body: { website_id: params.websiteId, prefix: data.get("domain-prefix") as string - } satisfies DomainPrefixInput) + }, + successMessage: "Successfully created/updated domain prefix" }); - if (!res.ok) { - const response = await res.json(); - return { success: false, message: response.message }; + if (!newDomainPrefix.success) { + return newDomainPrefix; } await rename( @@ -128,39 +120,38 @@ export const actions: Actions = { "var", "www", "archtika-websites", - res.status === 201 ? params.websiteId : oldDomainPrefix.prefix + oldDomainPrefix?.prefix ? oldDomainPrefix.prefix : params.websiteId ), join("/", "var", "www", "archtika-websites", data.get("domain-prefix") as string) ); - return { - success: true, - message: `Successfully ${res.status === 201 ? "created" : "updated"} domain prefix` - }; + return newDomainPrefix; }, - deleteCustomDomainPrefix: async ({ fetch, params, cookies }) => { - const res = await fetch(`${API_BASE_PREFIX}/domain_prefix?website_id=eq.${params.websiteId}`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${cookies.get("session_token")}`, - Prefer: "return=representation", - Accept: "application/vnd.pgrst.object+json" + 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 } - }); + ); - const response = await res.json(); - - if (!res.ok) { - return { success: false, message: response.message }; + if (!customPrefix.success) { + return customPrefix; } await rename( - join("/", "var", "www", "archtika-websites", response.prefix), + join("/", "var", "www", "archtika-websites", customPrefix.data.prefix), join("/", "var", "www", "archtika-websites", params.websiteId) ); - return { success: true, message: `Successfully deleted domain prefix` }; + return customPrefix; } }; @@ -178,6 +169,8 @@ const generateStaticFiles = async (websiteData: WebsiteOverview, isPreview = tru `; }; + console.log(websiteData); + const { head, body } = render(websiteData.content_type === "Blog" ? BlogIndex : DocsIndex, { props: { websiteOverview: websiteData, diff --git a/web-app/src/routes/+layout.svelte b/web-app/src/routes/+layout.svelte index 9bffbcf..43f6191 100644 --- a/web-app/src/routes/+layout.svelte +++ b/web-app/src/routes/+layout.svelte @@ -34,6 +34,10 @@ archtika | {routeName.replaceAll("/", " - ")} +