diff --git a/.env.example b/.env.example index a509dc6..98dfb05 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ DB_HOST=localhost DB_PORT=5432 DB_USERNAME=postgres DB_PASSWORD=your-db-password +GHOST_API_KEY=your-ghost-api-key AUTH_CLIENT_ID=your-authentik-client-id AUTH_CLIENT_SECRET=your-authentik-client-secret AUTH_ISSUER=https://authentik-domain/application/o/app-name/ diff --git a/src/lib/db.ts b/src/lib/db.ts index 1d67bd0..0ccaa54 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -34,42 +34,6 @@ sequelize.define("Announcements", { } }); -sequelize.define("Posts", { - title: { - type: DataTypes.STRING, - allowNull: false - }, - content: { - type: DataTypes.TEXT, - allowNull: false - }, - tags: { - type: DataTypes.ARRAY(DataTypes.STRING), - allowNull: false - }, - author: { - type: DataTypes.STRING, - allowNull: false - }, - created: { - type: DataTypes.BIGINT, - allowNull: false - }, - updated: { - type: DataTypes.BIGINT, - allowNull: true, - defaultValue: null - }, - words: { - type: DataTypes.INTEGER, - allowNull: false - }, - readingTime: { - type: DataTypes.INTEGER, - allowNull: false - } -}); - try { await sequelize.authenticate(); await sequelize.sync(); diff --git a/src/lib/ghost.ts b/src/lib/ghost.ts new file mode 100644 index 0000000..3309dfd --- /dev/null +++ b/src/lib/ghost.ts @@ -0,0 +1,9 @@ +import { env } from "$env/dynamic/private"; + +const fetchApi = async (action: string, additional?: string) => { + const data = await fetch("https://blog.projectsegfau.lt/ghost/api/content/" + action + "/?key=" + env.GHOST_API_KEY + "&include=authors,tags&limit=all&formats=html,plaintext" + (additional ? additional : "")); + + return data.json(); +}; + +export default fetchApi; \ No newline at end of file diff --git a/src/routes/admin/+page.svelte b/src/routes/admin/+page.svelte index ae31b65..1ebd53e 100644 --- a/src/routes/admin/+page.svelte +++ b/src/routes/admin/+page.svelte @@ -2,5 +2,4 @@
Announcements - Blog
\ No newline at end of file diff --git a/src/routes/admin/blog/+page.server.ts b/src/routes/admin/blog/+page.server.ts deleted file mode 100644 index 70cb8de..0000000 --- a/src/routes/admin/blog/+page.server.ts +++ /dev/null @@ -1,143 +0,0 @@ -import type { Actions, PageServerLoad } from "./$types"; -import db from "$lib/db"; -import Joi from "joi"; -import { fail } from "@sveltejs/kit"; -  -export const load = ( async () => { - const Posts = db.model("Posts"); - - return { - postTitles: await Posts.findAll({ attributes: ["title"] }).then((docs) => { - const titles = docs.map((doc) => doc.get("title")); - return titles; - }) - } -}) satisfies PageServerLoad; - -export const actions: Actions = { - add: async ({ request }) => { - const formData = await request.formData(); - - const AddPostTypeSchema = Joi.object({ - title: Joi.string().required(), - content: Joi.string().required(), - tags: Joi.string().optional().allow(""), - author: Joi.string().required() - }); - - if (AddPostTypeSchema.validate(Object.fromEntries(formData.entries())).error) { - return fail(400, { addError: true, addMessage: String(AddPostTypeSchema.validate(Object.fromEntries(formData.entries())).error) }); - } else { - const Posts = db.model("Posts"); - - //@ts-ignore - const words = formData.get("content")!.trim().split(/\s+/).length; - - //@ts-ignore - const tags = formData.get("tags") ? formData.get("tags").split(" ") : []; - - const now = Math.floor(Date.now() / 1000); - - const data = { - title: formData.get("title"), - content: formData.get("content"), - tags: tags, - author: formData.get("author"), - created: now, - words: words, - readingTime: Math.ceil(words / 225) - }; - - if (await Posts.findOne({ where: { title: data.title } })) { - return fail(409, { addError: true, addMessage: "A post with that title already exists." }); - } else { - await Posts.create(data); - - return { addSuccess: true, addMessage: "Your post has been posted." }; - } - } - }, - delete: async ({ request }) => { - const Posts = db.model("Posts"); - - const formData = await request.formData(); - - const deleteFromDb = await Posts.destroy({ where: { title: formData.get("title") } }); - - if (!deleteFromDb) { - return fail(404, { deleteError: true, deleteMessage: "A post with that title does not exist." }); - } else { - return { deleteSuccess: true, deleteMessage: "Your post has been deleted." }; - } - }, - edit: async ({ request }) => { - const EditPostTypeSchema = Joi.object({ - title: Joi.string().required(), - newTitle: Joi.string().optional().allow(""), - content: Joi.string().optional().allow(""), - tags: Joi.string().optional().allow(""), - area: Joi.string().required().allow("title", "content", "tags") - }); - - const formData = await request.formData(); - - if (EditPostTypeSchema.validate(Object.fromEntries(formData.entries())).error) { - return fail(400, { editError: true, editMessage: String(EditPostTypeSchema.validate(Object.fromEntries(formData.entries())).error) }); - } else { - if (formData.get("area") === "title") { - const Posts = db.model("Posts"); - - const updateOnDb = await Posts.update( - { title: formData.get("newTitle") }, - { where: { title: formData.get("title") } } - ); - - if (updateOnDb[0] === 0) { - return fail(404, { editError: true, editMessage: "A post with that title does not exist." }); - } else { - return { editSuccess: true, editMessage: "Your post has been edited." }; - } - } else if (formData.get("area") === "content") { - const Posts = db.model("Posts"); - - //@ts-ignore - const words = formData.get("content")!.trim().split(/\s+/).length; - - const now = Math.floor(Date.now() / 1000); - - const updateonDb = await Posts.update( - { - content: formData.get("content"), - words: words, - readingTime: Math.ceil(words / 225), - updated: now - }, - { where: { title: formData.get("title") } } - ); - - if (updateonDb[0] === 0) { - return fail(404, { editError: true, editMessage: "A post with that title does not exist." }); - } else { - return { editSuccess: true, editMessage: "Your post has been edited." }; - } - } else if (formData.get("area") === "tags") { - const Posts = db.model("Posts"); - - //@ts-ignore - const tags = formData.get("tags") ? formData.get("tags").split(" ") : []; - - const updateOnDb = await Posts.update( - { tags: tags - }, - { where: { title: formData.get("title") } } - ); - - if (updateOnDb[0] === 0) { - return fail(404, { editError: true, editMessage: "A post with that title does not exist." }); - } else { - return { editSuccess: true, editMessage: "Your post has been edited." }; - } - } - } - } -} \ No newline at end of file diff --git a/src/routes/admin/blog/+page.svelte b/src/routes/admin/blog/+page.svelte deleted file mode 100644 index 1cd2e7d..0000000 --- a/src/routes/admin/blog/+page.svelte +++ /dev/null @@ -1,81 +0,0 @@ - - -

Add post

- -
- - - - - {#if form?.addSuccess} - {form.addMessage} - {/if} - - {#if form?.addError} - {form.addMessage} - {/if} - -
- -

Delete post

- -
- - {#if form?.deleteSuccess} - {form.deleteMessage} - {/if} - - {#if form?.deleteError} - {form.deleteMessage} - {/if} - -
- -

Edit post

- -
- - - - - - {#if form?.editSuccess} - {form.editMessage} - {/if} - - {#if form?.editError} - {form.editMessage} - {/if} - -
\ No newline at end of file diff --git a/src/routes/blog/+page.server.ts b/src/routes/blog/+page.server.ts index 405e68f..e00bfcb 100644 --- a/src/routes/blog/+page.server.ts +++ b/src/routes/blog/+page.server.ts @@ -1,20 +1,10 @@ import type { PageServerLoad } from "./$types"; -import db from "$lib/db"; +import fetchApi from "$lib/ghost"; -export const load: PageServerLoad = async () => { - const Posts = db.model("Posts"); +export const load = (async () => { + const data = await fetchApi("posts"); - const posts = await Posts.findAll().then((docs) => { - return docs.map((doc) => doc.get()); - }); - - if (posts.length === 0 || posts[0] === undefined) { - return { - posts: [] - } - } else { - return { - posts: posts.sort((a, b) => b["created"] - a["created"]) - } - } -}; + return { + posts: data.posts + }; +}) satisfies PageServerLoad; diff --git a/src/routes/blog/+page.svelte b/src/routes/blog/+page.svelte index 71e986a..5a46f80 100644 --- a/src/routes/blog/+page.svelte +++ b/src/routes/blog/+page.svelte @@ -43,19 +43,21 @@
{#each post.tags as tag} - {tag} + {tag.name} {/each}
{/if} -
{post.author} + {#each post.authors as author} +
{author.name} + {/each}
{dayjs - .unix(post.created) + (post.published_at) .format("ddd, DD MMM YYYY HH:mm")} -
{post.words} words -
{post.readingTime} minute read +
{post.plaintext.trim().split(/\s+/).length} words +
{post.reading_time} minute read
- {post.content.split(" ").slice(0, 20).join(" ") + "..."} - Read more... + {post.plaintext.split(" ").slice(0, 20).join(" ") + "..."} + Read more...
{/each}
\ No newline at end of file diff --git a/src/routes/blog/[title]/+page.server.ts b/src/routes/blog/[title]/+page.server.ts index 4b5f7ee..4d8c9fa 100644 --- a/src/routes/blog/[title]/+page.server.ts +++ b/src/routes/blog/[title]/+page.server.ts @@ -1,27 +1,10 @@ import type { PageServerLoad } from "./$types"; -import db from "$lib/db"; -import { compile } from "mdsvex"; +import fetchApi from "$lib/ghost"; -export const load: PageServerLoad = async ({ params }) => { - const Posts = db.model("Posts"); +export const load = (async ({ params }) => { + const data = await fetchApi("posts/slug/" + params.title); - const data = await Posts.findAll({ - where: { - title: params.title - } - }).then((docs) => { - return docs.map((doc) => doc.get()); - }); - - if (data.length === 0 || data[0] === undefined) { - return { - post: {}, - content: {} - } - } else { - return { - post: data[0], - content: compile(data[0].content).then((res) => res?.code) - } - } -}; + return { + post: data.posts[0] + }; +}) satisfies PageServerLoad; diff --git a/src/routes/blog/[title]/+page.svelte b/src/routes/blog/[title]/+page.svelte index f9406e7..7c36c99 100644 --- a/src/routes/blog/[title]/+page.svelte +++ b/src/routes/blog/[title]/+page.svelte @@ -11,16 +11,18 @@
{#each data.post.tags as tag} - {tag} + {tag.name} {/each}
{/if} -
{data.post.author} + {#each data.post.authors as author} +
{author.name} + {/each}
{dayjs - .unix(data.post.created) + (data.post.published_at) .format("ddd, DD MMM YYYY HH:mm")} -
{data.post.words} words -
{data.post.readingTime} minute read +
{data.post.plaintext.trim().split(/\s+/).length} words +
{data.post.reading_time} minute read
- {@html data.content} + {@html data.post.html}
\ No newline at end of file diff --git a/src/routes/blog/authors/+page.server.ts b/src/routes/blog/authors/+page.server.ts index 21f31ba..7a8ddbc 100644 --- a/src/routes/blog/authors/+page.server.ts +++ b/src/routes/blog/authors/+page.server.ts @@ -1,23 +1,11 @@ import type { PageServerLoad } from "./$types"; -import db from "$lib/db"; +import fetchApi from "$lib/ghost"; -export const load: PageServerLoad = async ({ params }) => { - const Posts = db.model("Posts"); +export const load: PageServerLoad = async () => { + const data = await fetchApi("authors"); - const data = await Posts.findAll({ - attributes: ["author"] - }) - - if (data.length === 0 || data[0] === undefined) { - return { - authors: [] - } - } else { - const authors = data.map((post) => post["author"]); - const uniqueAuthors = [...new Set(authors)]; - - return { - authors: uniqueAuthors - } - } + return { + authors: data.authors + }; }; + diff --git a/src/routes/blog/authors/+page.svelte b/src/routes/blog/authors/+page.svelte index 4001b80..2e8eed2 100644 --- a/src/routes/blog/authors/+page.svelte +++ b/src/routes/blog/authors/+page.svelte @@ -7,6 +7,6 @@
{#each data.authors as author} - {author} + {author.name} {/each}
\ No newline at end of file diff --git a/src/routes/blog/authors/[author]/+page.server.ts b/src/routes/blog/authors/[author]/+page.server.ts index 6937ffb..101e1be 100644 --- a/src/routes/blog/authors/[author]/+page.server.ts +++ b/src/routes/blog/authors/[author]/+page.server.ts @@ -1,26 +1,12 @@ import type { PageServerLoad } from "./$types"; -import db from "$lib/db"; +import fetchApi from "$lib/ghost"; export const load: PageServerLoad = async ({ params }) => { - const Posts = db.model("Posts"); + const data = await fetchApi("posts", "&filter=author:" + params.author); - const data = await Posts.findAll({ - where: { - author: params.author - } - }).then((docs) => { - return docs.map((doc) => doc.get()); - }); + return { + posts: data.posts, + authorName: params.author + }; +}; - if (data.length === 0 || data[0] === undefined) { - return { - posts: [], - authorName: params.author - } - } else { - return { - posts: data, - authorName: params.author - } - } -}; \ No newline at end of file diff --git a/src/routes/blog/authors/[author]/+page.svelte b/src/routes/blog/authors/[author]/+page.svelte index 183ee3e..b3b83c9 100644 --- a/src/routes/blog/authors/[author]/+page.svelte +++ b/src/routes/blog/authors/[author]/+page.svelte @@ -15,19 +15,21 @@
{#each post.tags as tag} - {tag} + {tag.name} {/each}
{/if} -
{post.author} + {#each post.authors as author} +
{author.name} + {/each}
{dayjs - .unix(post.created) + (post.published_at) .format("ddd, DD MMM YYYY HH:mm")} -
{post.words} words -
{post.readingTime} minute read +
{post.plaintext.trim().split(/\s+/).length} words +
{post.reading_time} minute read
- {post.content.split(" ").slice(0, 20).join(" ") + "..."} - Read more... + {post.plaintext.split(" ").slice(0, 20).join(" ") + "..."} + Read more...
{/each}
\ No newline at end of file diff --git a/src/routes/blog/tags/+page.server.ts b/src/routes/blog/tags/+page.server.ts index 4542281..6b486c6 100644 --- a/src/routes/blog/tags/+page.server.ts +++ b/src/routes/blog/tags/+page.server.ts @@ -1,20 +1,10 @@ import type { PageServerLoad } from "./$types"; -import db from "$lib/db"; +import fetchApi from "$lib/ghost"; export const load: PageServerLoad = async () => { - const Posts = db.model("Posts"); + const data = await fetchApi("tags"); - const data = await Posts.findAll({ attributes: ["tags"] }) - - if (data.length === 0 || data[0] === undefined) { - return { - tags: [] - } - } else { - const tags = data.map((post) => post["tags"]).flat(); - const uniqueTags = [...new Set(tags)]; - return { - tags: uniqueTags - } + return { + tags: data.tags } }; diff --git a/src/routes/blog/tags/+page.svelte b/src/routes/blog/tags/+page.svelte index 022dd62..d9e0655 100644 --- a/src/routes/blog/tags/+page.svelte +++ b/src/routes/blog/tags/+page.svelte @@ -7,6 +7,6 @@
{#each data.tags as tag} - {tag} + {tag.name} {/each}
\ No newline at end of file diff --git a/src/routes/blog/tags/[tag]/+page.server.ts b/src/routes/blog/tags/[tag]/+page.server.ts index e006ad8..2c7820a 100644 --- a/src/routes/blog/tags/[tag]/+page.server.ts +++ b/src/routes/blog/tags/[tag]/+page.server.ts @@ -1,29 +1,11 @@ import type { PageServerLoad } from "./$types"; -import db from "$lib/db"; -import { Op } from "sequelize"; +import fetchApi from "$lib/ghost"; export const load: PageServerLoad = async ({ params }) => { - const Posts = db.model("Posts"); + const data = await fetchApi("posts", "&filter=tags:" + params.tag); - const data = await Posts.findAll({ - where: { - tags: { - [Op.contains]: [params.tag] - } - } - }).then((docs) => { - return docs.map((doc) => doc.get()); - }); - - if (data.length === 0 || data[0] === undefined) { - return { - posts: [], - tagName: params.tag - } - } else { - return { - posts: data, - tagName: params.tag - } + return { + posts: data.posts, + tagName: params.tag } }; \ No newline at end of file diff --git a/src/routes/blog/tags/[tag]/+page.svelte b/src/routes/blog/tags/[tag]/+page.svelte index 4b970ba..3938ff7 100644 --- a/src/routes/blog/tags/[tag]/+page.svelte +++ b/src/routes/blog/tags/[tag]/+page.svelte @@ -15,19 +15,21 @@
{#each post.tags as tag} - {tag} + {tag.name} {/each}
{/if} -
{post.author} + {#each post.authors as author} +
{author.name} + {/each}
{dayjs - .unix(post.created) + (post.published_at) .format("ddd, DD MMM YYYY HH:mm")} -
{post.words} words -
{post.readingTime} minute read +
{post.plaintext.trim().split(/\s+/).length} words +
{post.reading_time} minute read
- {post.content.split(" ").slice(0, 20).join(" ") + "..."} - Read more... + {post.plaintext.split(" ").slice(0, 20).join(" ") + "..."} + Read more...
{/each}
\ No newline at end of file