From df7971aa0300ca09bb45e8c4c896bb9709c4d9ee Mon Sep 17 00:00:00 2001 From: Robert Goniszewski <43510122+goniszewski@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:54:29 +0100 Subject: [PATCH 1/3] chore: release v0.4.4 (#158) * chore: release v0.4.1-hotfix.3 * fix(data-migration): early return if no categories have parents (#128) Signed-off-by: Robert Goniszewski * Closes #130 (#131) Signed-off-by: Robert Goniszewski * fix(database): use dynamic path for SQLite database file Signed-off-by: Robert Goniszewski * docs(readme): use single README file for latest/preview version Signed-off-by: Robert Goniszewski * feat(ci): add manual deployment workflow and adjust tag conditions Signed-off-by: Robert Goniszewski * refactor(workflow): simplify manual-deploy GitHub Action Signed-off-by: Robert Goniszewski * fix(metadata): handle multiple image URLs in mainImageUrl field Signed-off-by: Robert Goniszewski * fix: auth error handling (#144) * refactor(api): migrate Swagger UI to external documentation and enhance health endpoint Signed-off-by: Robert Goniszewski * chore: release v0.4.3 * fix(docker): resolve issue with data directory permissions (#150) * Fix issue #153: creation/update of root categories (#157) * chore: release v0.4.3 (#149) * chore: release v0.4.1-hotfix.3 * fix(data-migration): early return if no categories have parents (#128) Signed-off-by: Robert Goniszewski * Closes #130 (#131) Signed-off-by: Robert Goniszewski * fix(database): use dynamic path for SQLite database file Signed-off-by: Robert Goniszewski * docs(readme): use single README file for latest/preview version Signed-off-by: Robert Goniszewski * feat(ci): add manual deployment workflow and adjust tag conditions Signed-off-by: Robert Goniszewski * refactor(workflow): simplify manual-deploy GitHub Action Signed-off-by: Robert Goniszewski * fix(metadata): handle multiple image URLs in mainImageUrl field Signed-off-by: Robert Goniszewski * fix: auth error handling (#144) * refactor(api): migrate Swagger UI to external documentation and enhance health endpoint Signed-off-by: Robert Goniszewski * chore: release v0.4.3 --------- Signed-off-by: Robert Goniszewski Co-authored-by: Prabhanjan * Fix creation/update of root categories --------- Signed-off-by: Robert Goniszewski Co-authored-by: Robert Goniszewski <43510122+goniszewski@users.noreply.github.com> Co-authored-by: Prabhanjan * Fix issue #145: bookmarks without images (#156) * chore: release v0.4.3 (#149) * chore: release v0.4.1-hotfix.3 * fix(data-migration): early return if no categories have parents (#128) Signed-off-by: Robert Goniszewski * Closes #130 (#131) Signed-off-by: Robert Goniszewski * fix(database): use dynamic path for SQLite database file Signed-off-by: Robert Goniszewski * docs(readme): use single README file for latest/preview version Signed-off-by: Robert Goniszewski * feat(ci): add manual deployment workflow and adjust tag conditions Signed-off-by: Robert Goniszewski * refactor(workflow): simplify manual-deploy GitHub Action Signed-off-by: Robert Goniszewski * fix(metadata): handle multiple image URLs in mainImageUrl field Signed-off-by: Robert Goniszewski * fix: auth error handling (#144) * refactor(api): migrate Swagger UI to external documentation and enhance health endpoint Signed-off-by: Robert Goniszewski * chore: release v0.4.3 --------- Signed-off-by: Robert Goniszewski Co-authored-by: Prabhanjan * Fix bookmark creation/update without image --------- Signed-off-by: Robert Goniszewski Co-authored-by: Robert Goniszewski <43510122+goniszewski@users.noreply.github.com> Co-authored-by: Prabhanjan * chore: release v0.4.4 --------- Signed-off-by: Robert Goniszewski Co-authored-by: Prabhanjan Co-authored-by: Guillaume Poussel --- Dockerfile | 6 ++-- docker-entrypoint.sh | 4 +++ package.json | 2 +- .../AddCategoryForm/AddCategoryForm.svelte | 13 ++++--- .../EditCategoryForm/EditCategoryForm.svelte | 13 ++++--- src/routes/+page.server.ts | 35 ++++++++++--------- 6 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 docker-entrypoint.sh diff --git a/Dockerfile b/Dockerfile index fde5713..2d8a771 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y python3 python3-pip wget build-essentia bun i -g svelte-kit@latest RUN adduser --disabled-password --gecos '' grimoire -RUN mkdir -p /app/data && chown -R grimoire:grimoire /app/data && chmod 755 /app/data +RUN mkdir -p /app/data && chown -R grimoire:grimoire /app/data && chmod 766 /app/data WORKDIR /app FROM base AS dependencies @@ -35,6 +35,7 @@ COPY --from=build /app/build ./build COPY --from=build /app/migrations ./migrations COPY --from=build /app/migrate.js ./migrate.js COPY --from=build /app/package.json ./package.json +COPY docker-entrypoint.sh / ENV NODE_ENV=production \ PUBLIC_ORIGIN=${PUBLIC_ORIGIN:-http://localhost:5173} \ ORIGIN=${PUBLIC_ORIGIN:-http://localhost:5173} \ @@ -43,8 +44,9 @@ ENV NODE_ENV=production \ PUBLIC_SIGNUP_DISABLED=${PUBLIC_SIGNUP_DISABLED:-false} \ BODY_SIZE_LIMIT=${BODY_SIZE_LIMIT:-5000000} +RUN chmod +x /docker-entrypoint.sh USER grimoire EXPOSE ${PORT} HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:$PORT/api/health || exit 1 -ENTRYPOINT ["sh", "-c", "bun --bun run run-migrations && bun ./build/index.js"] +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..32715d4 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh +chown -R grimoire:grimoire /app/data +chmod 755 /app/data +bun --bun run run-migrations && bun ./build/index.js diff --git a/package.json b/package.json index ac3c315..c3ef897 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grimoire", - "version": "0.4.3", + "version": "0.4.4", "description": "Bookmark manager for the wizards 🧙", "author": "Robert Goniszewski ", "main": "./build/index.js", diff --git a/src/lib/components/AddCategoryForm/AddCategoryForm.svelte b/src/lib/components/AddCategoryForm/AddCategoryForm.svelte index 25dcde8..ad878dd 100644 --- a/src/lib/components/AddCategoryForm/AddCategoryForm.svelte +++ b/src/lib/components/AddCategoryForm/AddCategoryForm.svelte @@ -28,9 +28,9 @@ let form: HTMLFormElement; export let closeModal: () => void; - const categoriesOptions = writable<{ value: string; label: string }[]>([ + const categoriesOptions = writable<{ value: string | null; label: string }[]>([ { - value: 'null', + value: null, label: 'No parent' } ]); @@ -38,7 +38,7 @@ $: { $categoriesOptions = [ { - value: 'null', + value: null, label: 'No parent' }, ...$page.data.categories @@ -46,7 +46,7 @@ return c.id !== $category.id; }) .map((c) => ({ - value: c.id, + value: c.id.toString(), label: c.name })) ]; @@ -224,13 +224,12 @@ name="parent" searchable placeholder="Select parent category..." - required - value={$category.parent?.id || $categoriesOptions[0].value} + value={$category.parent?.id?.toString() || $categoriesOptions[0].value} items={$categoriesOptions} class="this-select input input-bordered w-max" on:change={(event) => { // @ts-ignore-next-line - $category.parent = $page.data.categories.find((c) => c.id === event.detail.value); + $category.parent = $page.data.categories.find((c) => c.id.toString() === event.detail.value); }} /> diff --git a/src/lib/components/EditCategoryForm/EditCategoryForm.svelte b/src/lib/components/EditCategoryForm/EditCategoryForm.svelte index f7bd698..305fe13 100644 --- a/src/lib/components/EditCategoryForm/EditCategoryForm.svelte +++ b/src/lib/components/EditCategoryForm/EditCategoryForm.svelte @@ -16,9 +16,9 @@ let form: HTMLFormElement; export let closeModal: () => void; - const categoriesOptions = writable<{ value: number; label: string }[]>([ + const categoriesOptions = writable<{ value: string | null; label: string }[]>([ { - value: 0, + value: null, label: 'No parent' } ]); @@ -26,7 +26,7 @@ $: { $categoriesOptions = [ { - value: 0, + value: null, label: 'No parent' }, ...$page.data.categories @@ -34,7 +34,7 @@ return c.id !== $category.id; }) .map((c) => ({ - value: c.id, + value: c.id.toString(), label: c.name })) ]; @@ -214,13 +214,12 @@ name="parent" searchable placeholder="Select parent category..." - required - value={$category.parent?.id || $categoriesOptions[0].value} + value={$category.parent?.id?.toString() || $categoriesOptions[0].value} items={$categoriesOptions} class="this-select input input-bordered w-max" on:change={(event) => { // @ts-ignore-next-line - $category.parent = $page.data.categories.find((c) => c.id === event.detail.value); + $category.parent = $page.data.categories.find((c) => c.id.toString() === event.detail.value); }} /> diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index 3675110..540ae90 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -71,16 +71,15 @@ export const actions = { error: 'Failed to add bookmark' }; } - const { id: mainImageId } = await storage.storeImage( - mainImageUrl, - title, - ownerId, - bookmark.id - ); - const { id: iconId } = await storage.storeImage(iconUrl, title, ownerId, bookmark.id); + const mainImage = mainImageUrl + ? await storage.storeImage(mainImageUrl, title, ownerId, bookmark.id) + : undefined; + const icon = iconUrl + ? await storage.storeImage(iconUrl, title, ownerId, bookmark.id) + : undefined; const updatedBookmark = await updateBookmark(bookmark.id, ownerId, { - mainImageId, - iconId + ...(mainImage ? { mainImageId: mainImage.id } : {}), + ...(icon ? { iconId: icon.id } : {}) }); await upsertTagsForBookmark(bookmark.id, ownerId, tagNames); @@ -149,8 +148,10 @@ export const actions = { const tagNames = tags.map((tag: any) => tag.label); - const { id: mainImageId } = await storage.storeImage(mainImageUrl, title, ownerId, id); - const { id: iconId } = await storage.storeImage(iconUrl, title, ownerId, id); + const mainImage = mainImageUrl + ? await storage.storeImage(mainImageUrl, title, ownerId, id) + : undefined; + const icon = iconUrl ? await storage.storeImage(iconUrl, title, ownerId, id) : undefined; const bookmarkData = { author, @@ -169,8 +170,8 @@ export const actions = { title, url, read, - ...(mainImageId ? { mainImageId } : {}), - ...(iconId ? { iconId } : {}) + ...(mainImage ? { mainImageId: mainImage.id } : {}), + ...(icon ? { iconId: icon.id } : {}) }; const bookmark = await updateBookmark(id, ownerId, bookmarkData); @@ -290,7 +291,7 @@ export const actions = { const description = data.get('description') as string; const icon = data.get('icon') as string; const color = data.get('color') as string; - const parent = JSON.parse(data.get('parent') as string); + const parent = data.get('parent') ? JSON.parse(data.get('parent') as string) : null; const parentValue = parent?.value ? parent.value : parent; const archived = data.get('archived') === 'on' ? new Date() : null; const setPublic = data.get('public') === 'on' ? new Date() : null; @@ -301,7 +302,7 @@ export const actions = { description, icon, color, - parentId: parentValue === 'null' ? null : parentValue, + parentId: parentValue, archived, public: setPublic, ownerId, @@ -332,7 +333,7 @@ export const actions = { const description = data.get('description') as string; const icon = data.get('icon') as string; const color = data.get('color') as string; - const parent = JSON.parse(data.get('parent') as string); + const parent = data.get('parent') ? JSON.parse(data.get('parent') as string) : null; const parentValue = parent?.value ? parent.value : parent; const archived = data.get('archived') === 'on' ? new Date() : null; const setPublic = data.get('public') === 'on' ? new Date() : null; @@ -343,7 +344,7 @@ export const actions = { description, icon, color, - parentId: parentValue === 'null' ? null : parentValue, + parentId: parentValue, archived, public: setPublic }; From 6b98ad8390b3d5ffe11cb1fdf1ae5a32a5e4ac12 Mon Sep 17 00:00:00 2001 From: Robert Goniszewski Date: Tue, 17 Dec 2024 22:49:05 +0100 Subject: [PATCH 2/3] feat(docker): implement s6-overlay Signed-off-by: Robert Goniszewski --- Dockerfile | 40 +++++++++++++++++-- docker-compose.yml | 2 +- docker/etc/s6-overlay/s6-rc.d/grimoire/run | 9 +++++ docker/etc/s6-overlay/s6-rc.d/grimoire/type | 1 + .../s6-rc.d/user/contents.d/grimoire | 1 + 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 docker/etc/s6-overlay/s6-rc.d/grimoire/run create mode 100644 docker/etc/s6-overlay/s6-rc.d/grimoire/type create mode 100644 docker/etc/s6-overlay/s6-rc.d/user/contents.d/grimoire diff --git a/Dockerfile b/Dockerfile index 2d8a771..3b2da16 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,12 +3,43 @@ LABEL maintainer="Grimoire Developers " LABEL description="Bookmark manager for the wizards" LABEL org.opencontainers.image.source="https://github.com/goniszewski/grimoire" +RUN apt-get update && \ + apt-get install -y xz-utils && \ + rm -rf /var/lib/apt/lists/* && \ + mkdir -p /etc/s6-overlay/s6-rc.d/grimoire && \ + mkdir -p /etc/s6-overlay/s6-rc.d/user/contents.d + +RUN adduser --disabled-password --gecos '' --uid 1001 grimoire && \ + mkdir -p /app/data && \ + chown -R grimoire:grimoire /app/data && \ + chmod 766 /app/data + +ARG S6_OVERLAY_VERSION=3.1.6.2 +ARG TARGETARCH=x86_64 + +ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp +ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${TARGETARCH}.tar.xz /tmp +RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz && \ + tar -C / -Jxpf /tmp/s6-overlay-${TARGETARCH}.tar.xz && \ + rm /tmp/s6-overlay-noarch.tar.xz && \ + rm /tmp/s6-overlay-${TARGETARCH}.tar.xz + +COPY docker/etc/s6-overlay /etc/s6-overlay/ +RUN chown -R grimoire:grimoire /etc/s6-overlay && \ + chmod +x /etc/s6-overlay/s6-rc.d/grimoire/run + +ENV S6_KEEP_ENV=1 +ENV S6_SERVICES_GRACETIME=15000 +ENV S6_KILL_GRACETIME=10000 +ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 +ENV S6_SYNC_DISKS=1 +ENV S6_OVERLAY_USER=grimoire +ENV S6_OVERLAY_GROUP=grimoire + RUN apt-get update && apt-get install -y python3 python3-pip wget build-essential && \ rm -rf /var/lib/apt/lists/* && \ bun i -g svelte-kit@latest -RUN adduser --disabled-password --gecos '' grimoire -RUN mkdir -p /app/data && chown -R grimoire:grimoire /app/data && chmod 766 /app/data WORKDIR /app FROM base AS dependencies @@ -36,6 +67,9 @@ COPY --from=build /app/migrations ./migrations COPY --from=build /app/migrate.js ./migrate.js COPY --from=build /app/package.json ./package.json COPY docker-entrypoint.sh / +ENV S6_SERVICES_GRACETIME=15000 +ENV S6_KILL_GRACETIME=10000 +COPY docker/etc/ /etc/ ENV NODE_ENV=production \ PUBLIC_ORIGIN=${PUBLIC_ORIGIN:-http://localhost:5173} \ ORIGIN=${PUBLIC_ORIGIN:-http://localhost:5173} \ @@ -49,4 +83,4 @@ USER grimoire EXPOSE ${PORT} HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:$PORT/api/health || exit 1 -ENTRYPOINT ["/docker-entrypoint.sh"] +ENTRYPOINT ["/init"] diff --git a/docker-compose.yml b/docker-compose.yml index d6c7c31..e04b866 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: grimoire: - image: goniszewski/grimoire:latest + image: goniszewski/grimoire:test container_name: grimoire restart: unless-stopped environment: diff --git a/docker/etc/s6-overlay/s6-rc.d/grimoire/run b/docker/etc/s6-overlay/s6-rc.d/grimoire/run new file mode 100644 index 0000000..45d1335 --- /dev/null +++ b/docker/etc/s6-overlay/s6-rc.d/grimoire/run @@ -0,0 +1,9 @@ +#!/command/with-contenv bash + +cd /app + +# Run migrations first +/usr/local/bin/bun run run-migrations + +# Start the application +exec /usr/local/bin/bun ./build/index.js diff --git a/docker/etc/s6-overlay/s6-rc.d/grimoire/type b/docker/etc/s6-overlay/s6-rc.d/grimoire/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/docker/etc/s6-overlay/s6-rc.d/grimoire/type @@ -0,0 +1 @@ +longrun diff --git a/docker/etc/s6-overlay/s6-rc.d/user/contents.d/grimoire b/docker/etc/s6-overlay/s6-rc.d/user/contents.d/grimoire new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docker/etc/s6-overlay/s6-rc.d/user/contents.d/grimoire @@ -0,0 +1 @@ + From 2ffe6dc0263560d03e6f76f7bf92e416984c5adc Mon Sep 17 00:00:00 2001 From: Robert Goniszewski Date: Tue, 17 Dec 2024 22:53:36 +0100 Subject: [PATCH 3/3] fix(docker): use proper tag in compose Signed-off-by: Robert Goniszewski --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e04b866..d6c7c31 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: grimoire: - image: goniszewski/grimoire:test + image: goniszewski/grimoire:latest container_name: grimoire restart: unless-stopped environment: