Rename Postgres tables for better recognition and add additional routes in web app

This commit is contained in:
Thilo Hohlt
2024-07-31 10:29:46 +02:00
parent a7f2fdebf5
commit d21e00a0c3
13 changed files with 601 additions and 243 deletions

View File

@@ -0,0 +1,107 @@
export const load = async ({ fetch, cookies, url }) => {
const searchQuery = url.searchParams.get("website_search_query");
const sortBy = url.searchParams.get("website_sort");
const params = new URLSearchParams();
const baseFetchUrl = "http://localhost:3000/website";
if (searchQuery) {
params.append("website_title", `ilike.*${searchQuery}*`);
}
switch (sortBy) {
case "creation-time":
params.append("order", "created_at.desc");
break;
case "last-modified":
params.append("order", "last_modified_at.desc");
break;
case "title-a-to-z":
params.append("order", "title.asc");
break;
case "title-z-to-a":
params.append("order", "title.desc");
break;
}
const constructedFetchUrl = `${baseFetchUrl}?${params.toString()}`;
const websiteData = await fetch(constructedFetchUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${cookies.get("session_token")}`
}
});
const websites = await websiteData.json();
return {
websites
};
};
export const actions = {
createWebsite: async ({ request, fetch, cookies }) => {
const data = await request.formData();
const res = await fetch("http://localhost:3000/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"),
title: data.get("title")
})
});
if (!res.ok) {
const response = await res.json();
return { createWebsite: { success: false, message: response.message } };
}
return { createWebsite: { success: true, operation: "created" } };
},
updateWebsite: async ({ request, cookies, fetch }) => {
const data = await request.formData();
const res = await fetch(`http://localhost:3000/website?id=eq.${data.get("id")}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${cookies.get("session_token")}`
},
body: JSON.stringify({
title: data.get("title")
})
});
if (!res.ok) {
const response = await res.json();
return { updateWebsite: { success: false, message: response.message } };
}
return { updateWebsite: { success: true, operation: "updated" } };
},
deleteWebsite: async ({ request, cookies, fetch }) => {
const data = await request.formData();
const res = await fetch(`http://localhost:3000/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 { deleteWebsite: { success: false, message: response.message } };
}
return { deleteWebsite: { success: true, operation: "deleted" } };
}
};

View File

@@ -0,0 +1,103 @@
<script lang="ts">
import { enhance } from "$app/forms";
import DateTime from "$lib/components/DateTime.svelte";
const { form, data } = $props();
</script>
<section>
<h2>Create website</h2>
<form method="POST" action="?/createWebsite" use:enhance>
{#if form?.createWebsite?.success}
<p>Successfully created website</p>
{/if}
{#if form?.createWebsite?.success === false}
<p>{form.createWebsite.message}</p>
{/if}
<label>
Type
<select name="content-type">
<option value="Blog">Blog</option>
<option value="Docs">Docs</option>
</select>
</label>
<label>
Title
<input type="text" name="title" />
</label>
<button type="submit">Submit</button>
</form>
</section>
<section>
<h2>Your websites</h2>
{#if form?.deleteWebsite?.success}
<p>Successfully deleted website</p>
{/if}
{#if form?.deleteWebsite?.success === false}
<p>{form.deleteWebsite.message}</p>
{/if}
{#each data.websites as { id, content_type, title, created_at }}
<article>
<h3>
<a href="/website/{id}">{title}</a>
</h3>
<p>
<strong>Type:</strong>
{content_type}
</p>
<p>
<strong>Created at:</strong>
<DateTime date={created_at} />
</p>
<details>
<summary>Update</summary>
<form
method="POST"
action="?/updateWebsite"
use:enhance={() => {
return async ({ update }) => {
await update({ reset: false });
};
}}
>
{#if form?.updateWebsite?.success}
<p>Successfully updated website</p>
{/if}
{#if form?.updateWebsite?.success === false}
<p>{form.updateWebsite.message}</p>
{/if}
<input type="hidden" name="id" value={id} />
<label>
Title
<input type="text" name="title" value={title} />
</label>
<button type="submit">Submit</button>
</form>
</details>
<details>
<summary>Delete</summary>
<!-- TODO: Needs to be password protected -->
<form method="POST" action="?/deleteWebsite" use:enhance>
<input type="hidden" name="id" value={id} />
<button type="submit">Delete</button>
</form>
</details>
</article>
{/each}
</section>
<section>
<h2>Shared with you</h2>
</section>

View File

@@ -0,0 +1,36 @@
export const load = async ({ locals }) => {
return {
user: locals.user
};
};
export const actions = {
logout: async ({ cookies }) => {
cookies.delete("session_token", { path: "/" });
return { logout: { success: true } };
},
deleteAccount: async ({ request, fetch, cookies }) => {
const data = await request.formData();
const res = await fetch("http://localhost:3000/rpc/delete_account", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${cookies.get("session_token")}`
},
body: JSON.stringify({
password: data.get("password")
})
});
const response = await res.json();
if (!res.ok) {
return { deleteAccount: { success: false, message: response.message } };
}
cookies.delete("session_token", { path: "/" });
return { deleteAccount: { success: true } };
}
};

View File

@@ -0,0 +1,51 @@
<script lang="ts">
import { enhance } from "$app/forms";
const { data, form } = $props();
</script>
<section>
<h2>Overview</h2>
<p>
<strong>Username:</strong>
{data.user.username}
</p>
<p>
<strong>ID:</strong>
{data.user.id}
</p>
</section>
<section>
<h2>Logout</h2>
{#if form?.logout?.success}
<p>Successfully logged out</p>
{/if}
<form method="POST" action="?/logout" use:enhance>
<button type="submit">Logout</button>
</form>
</section>
<section>
<h2>Delete account</h2>
{#if form?.deleteAccount?.success}
<p>Account was deleted</p>
{/if}
{#if form?.deleteAccount?.success === false}
<p>{form.deleteAccount.message}</p>
{/if}
<form method="POST" action="?/deleteAccount" use:enhance>
<label>
Password
<input type="password" name="password" required />
</label>
<button type="submit">Delete account</button>
</form>
</section>

View File

@@ -1,5 +1,5 @@
export const load = async ({ params, fetch, cookies }) => {
const websiteData = await fetch(`http://localhost:3000/cms_content?id=eq.${params.websiteId}`, {
const websiteData = await fetch(`http://localhost:3000/content?id=eq.${params.websiteId}`, {
method: "GET",
headers: {
"Content-Type": "application/json",

View File

@@ -5,7 +5,7 @@ import { ALLOWED_MIME_TYPES } from "$lib/utils.js";
export const load = async ({ params, fetch, cookies, url }) => {
const globalSettingsData = await fetch(
`http://localhost:3000/cms_settings?content_id=eq.${params.websiteId}&select=*,cms_media(*)`,
`http://localhost:3000/settings?website_id=eq.${params.websiteId}&select=*,media(*)`,
{
method: "GET",
headers: {
@@ -17,7 +17,7 @@ export const load = async ({ params, fetch, cookies, url }) => {
);
const headerData = await fetch(
`http://localhost:3000/cms_header?content_id=eq.${params.websiteId}&select=*,cms_media(*)`,
`http://localhost:3000/header?website_id=eq.${params.websiteId}&select=*,media(*)`,
{
method: "GET",
headers: {
@@ -28,7 +28,7 @@ export const load = async ({ params, fetch, cookies, url }) => {
}
);
const homeData = await fetch(`http://localhost:3000/cms_home?content_id=eq.${params.websiteId}`, {
const homeData = await fetch(`http://localhost:3000/home?website_id=eq.${params.websiteId}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
@@ -37,24 +37,21 @@ export const load = async ({ params, fetch, cookies, url }) => {
}
});
const footerData = await fetch(
`http://localhost:3000/cms_footer?content_id=eq.${params.websiteId}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${cookies.get("session_token")}`,
Accept: "application/vnd.pgrst.object+json"
}
const footerData = await fetch(`http://localhost:3000/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 searchQuery = url.searchParams.get("article_search_query");
const sortBy = url.searchParams.get("article_sort");
const parameters = new URLSearchParams();
const baseFetchUrl = `http://localhost:3000/cms_article?content_id=eq.${params.websiteId}&select=*,cms_media(*)`;
const baseFetchUrl = `http://localhost:3000/article?website_id=eq.${params.websiteId}&select=*,media(*)`;
if (searchQuery) {
parameters.append("title", `ilike.*${searchQuery}*`);
@@ -117,21 +114,18 @@ export const actions = {
return favicon;
}
const res = await fetch(
`http://localhost:3000/cms_settings?content_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: favicon?.content
})
}
);
const res = await fetch(`http://localhost:3000/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: favicon?.content
})
});
if (!res.ok) {
const response = await res.json();
@@ -160,7 +154,7 @@ export const actions = {
return logo;
}
const res = await fetch(`http://localhost:3000/cms_header?content_id=eq.${params.websiteId}`, {
const res = await fetch(`http://localhost:3000/header?website_id=eq.${params.websiteId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
@@ -187,7 +181,7 @@ export const actions = {
updateHome: async ({ request, fetch, cookies, params }) => {
const data = await request.formData();
const res = await fetch(`http://localhost:3000/cms_home?content_id=eq.${params.websiteId}`, {
const res = await fetch(`http://localhost:3000/home?website_id=eq.${params.websiteId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
@@ -208,7 +202,7 @@ export const actions = {
updateFooter: async ({ request, fetch, cookies, params }) => {
const data = await request.formData();
const res = await fetch(`http://localhost:3000/cms_footer?content_id=eq.${params.websiteId}`, {
const res = await fetch(`http://localhost:3000/footer?website_id=eq.${params.websiteId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
@@ -233,14 +227,14 @@ export const actions = {
createArticle: async ({ request, fetch, cookies, params }) => {
const data = await request.formData();
const res = await fetch("http://localhost:3000/cms_article", {
const res = await fetch("http://localhost:3000/article", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${cookies.get("session_token")}`
},
body: JSON.stringify({
content_id: params.websiteId,
website_id: params.websiteId,
title: data.get("title")
})
});
@@ -268,7 +262,7 @@ export const actions = {
return cover;
}
const res = await fetch(`http://localhost:3000/cms_article?id=eq.${data.get("article-id")}`, {
const res = await fetch(`http://localhost:3000/article?id=eq.${data.get("article-id")}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
@@ -294,7 +288,7 @@ export const actions = {
deleteArticle: async ({ request, fetch, cookies }) => {
const data = await request.formData();
const res = await fetch(`http://localhost:3000/cms_article?id=eq.${data.get("article-id")}`, {
const res = await fetch(`http://localhost:3000/article?id=eq.${data.get("article-id")}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
@@ -348,7 +342,7 @@ const handleFileUpload = async (
const relativePath = relative(join(process.cwd(), "static"), filepath);
const res = await customFetch("http://localhost:3000/cms_media", {
const res = await customFetch("http://localhost:3000/media", {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -357,7 +351,7 @@ const handleFileUpload = async (
Accept: "application/vnd.pgrst.object+json"
},
body: JSON.stringify({
content_id: contentId,
website_id: contentId,
user_id: userId,
original_name: file.name,
file_system_path: relativePath