From 673eb78dd06a14b4cf812b0b754c3175c0b0cfff Mon Sep 17 00:00:00 2001 From: Christian Beutel <> Date: Sun, 8 Dec 2024 21:30:55 +0100 Subject: [PATCH] adds public lists --- db/migrations/1733689501_updated_lists.go | 60 ++++++++ web/src/lib/components/confirm_modal.svelte | 5 +- web/src/lib/components/list/list_card.svelte | 8 + web/src/lib/components/list/list_panel.svelte | 20 ++- web/src/lib/i18n/locales/de.json | 2 + web/src/lib/i18n/locales/en.json | 2 + web/src/lib/i18n/locales/fr.json | 2 + web/src/lib/i18n/locales/hu.json | 2 + web/src/lib/i18n/locales/it.json | 2 + web/src/lib/i18n/locales/nl.json | 2 + web/src/lib/i18n/locales/pl.json | 2 + web/src/lib/i18n/locales/pt.json | 2 + web/src/lib/i18n/locales/zh.json | 2 + web/src/lib/models/list.ts | 4 +- web/src/routes/lists/edit/[id]/+page.svelte | 144 +++++++++++------- 15 files changed, 200 insertions(+), 59 deletions(-) create mode 100644 db/migrations/1733689501_updated_lists.go diff --git a/db/migrations/1733689501_updated_lists.go b/db/migrations/1733689501_updated_lists.go new file mode 100644 index 00000000..310d7e17 --- /dev/null +++ b/db/migrations/1733689501_updated_lists.go @@ -0,0 +1,60 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models/schema" + "github.com/pocketbase/pocketbase/tools/types" +) + +func init() { + m.Register(func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("r6gu2ajyidy1x69") + if err != nil { + return err + } + + collection.ListRule = types.Pointer("author = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)") + + collection.ViewRule = types.Pointer("author = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)") + + // add + new_public := &schema.SchemaField{} + if err := json.Unmarshal([]byte(`{ + "system": false, + "id": "rolk3q3j", + "name": "public", + "type": "bool", + "required": false, + "presentable": false, + "unique": false, + "options": {} + }`), new_public); err != nil { + return err + } + collection.Schema.AddField(new_public) + + return dao.SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("r6gu2ajyidy1x69") + if err != nil { + return err + } + + collection.ListRule = types.Pointer("author = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)") + + collection.ViewRule = types.Pointer("author = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)") + + // remove + collection.Schema.RemoveField("rolk3q3j") + + return dao.SaveCollection(collection) + }) +} diff --git a/web/src/lib/components/confirm_modal.svelte b/web/src/lib/components/confirm_modal.svelte index b876da7d..9fe0514c 100644 --- a/web/src/lib/components/confirm_modal.svelte +++ b/web/src/lib/components/confirm_modal.svelte @@ -9,6 +9,7 @@ export let title: string = $_('confirm-deletion'); export let text: string; export let action: string = "delete"; + export let id: string = "confirm-modal"; const dispatch = createEventDispatcher(); @@ -18,13 +19,13 @@ } - +

{text}

-
{list.name} + {#if list.public} + + + + {/if} {#if listIsShared} {/if} diff --git a/web/src/lib/components/list/list_panel.svelte b/web/src/lib/components/list/list_panel.svelte index f9b6b904..4c0691b2 100644 --- a/web/src/lib/components/list/list_panel.svelte +++ b/web/src/lib/components/list/list_panel.svelte @@ -72,14 +72,26 @@
- {#if listIsShared} + {#if (list.public || listIsShared) && $currentUser}
- + {#if list.public} + + + + {/if} + {#if listIsShared} + + {/if}
{/if} - {#if dropdownItems.length}
t.id!); this.description = params?.description; diff --git a/web/src/routes/lists/edit/[id]/+page.svelte b/web/src/routes/lists/edit/[id]/+page.svelte index f18e79a6..8447403a 100644 --- a/web/src/routes/lists/edit/[id]/+page.svelte +++ b/web/src/routes/lists/edit/[id]/+page.svelte @@ -20,13 +20,15 @@ trail_share_create, trail_share_index, } from "$lib/stores/trail_share_store.js"; - import { trails_show } from "$lib/stores/trail_store"; + import { trails_show, trails_update } from "$lib/stores/trail_store"; import { getFileURL } from "$lib/util/file_util.js"; import { formatDistance, formatElevation, formatTimeHHMM, } from "$lib/util/format_util"; + import Toggle from "$lib/components/base/toggle.svelte"; + import { currentUser } from "$lib/stores/user_store.js"; export let data; @@ -42,46 +44,62 @@ let newShares: TrailShare[] = []; let openConfirmModal: () => void; + let openPublishConfirmModal: () => void; const { form, errors, handleChange, handleSubmit } = createForm({ initialValues: data.list!, validationSchema: listSchema, onSubmit: async (submittedList) => { - const avatarFile = ( - document.getElementById("avatar") as HTMLInputElement - ).files![0]; - loading = true; - try { - if ($form.id) { - await lists_update($form, avatarFile); - await findNewTrailShares(); - if (!newShares.length) { - show_toast({ - type: "success", - icon: "check", - text: $_("list-saved-successfully"), - }); - } - } else { - await lists_create($form, avatarFile); - show_toast({ - type: "success", - icon: "check", - text: $_("list-saved-successfully"), - }); - } - } catch (e) { - show_toast({ - type: "error", - icon: "close", - text: $_("error-saving-list"), - }); - } finally { - loading = false; + if (await checkPrerequisites()) { + await saveList(); } }, }); + async function checkPrerequisites() { + if ( + (data.list?.public === false && $form.public === true) || + ($form.public === true && + data.list?.expand?.trails?.length !== + $form.expand?.trails?.length) + ) { + openPublishConfirmModal(); + return false; + } else if (await findNewTrailShares()) { + openConfirmModal(); + return false; + } + + return true; + } + + async function saveList() { + const avatarFile = ( + document.getElementById("avatar") as HTMLInputElement + ).files![0]; + loading = true; + try { + if ($form.id) { + await lists_update($form, avatarFile); + } else { + await lists_create($form, avatarFile); + } + show_toast({ + type: "success", + icon: "check", + text: $_("list-saved-successfully"), + }); + } catch (e) { + show_toast({ + type: "error", + icon: "close", + text: $_("error-saving-list"), + }); + } finally { + loading = false; + } + } + function openAvatarBrowser() { document.getElementById("avatar")!.click(); } @@ -98,22 +116,21 @@ } async function search(q: string) { - const r = await fetch("/api/v1/search/multi", { + const r = await fetch("/api/v1/search/trails", { method: "POST", body: JSON.stringify({ - queries: [ - { - indexUid: "trails", - q: q, - limit: 3, - }, - ], + q, + options: { + filter: `author = ${$currentUser?.id} OR public = true`, + sort: ["name:desc"], + limit: 3, + }, }), }); const response = await r.json(); - searchDropdownItems = response.results[0].hits + searchDropdownItems = response.hits .filter((h: List) => !$form.trails?.includes(h.id!)) .map((t: Record) => ({ text: t.name, @@ -149,7 +166,10 @@ user: userId, }); for (const trail of $form.expand?.trails ?? []) { - if (trail.author == userId) { + if ( + trail.author == userId || + trail.author != $currentUser?.id + ) { continue; } const trailShare = existingTrailShares.find( @@ -160,10 +180,7 @@ } } } - - if (newShares.length) { - openConfirmModal(); - } + return newShares.length > 0; } async function updateTrailShares() { @@ -171,11 +188,16 @@ await trail_share_create(newShare); } newShares = []; - show_toast({ - type: "success", - icon: "check", - text: $_("list-saved-successfully"), - }); + } + + async function publishTrails() { + for (const trail of $form.expand?.trails ?? []) { + if (trail.author !== $currentUser?.id) { + continue; + } + const updatedTrail: Trail = { ...trail, public: true }; + await trails_update(trail, updatedTrail); + } } function moveTrail(trail: Trail, index: number, direction: 1 | -1) { @@ -261,6 +283,8 @@ error={$errors.description} on:change={handleChange} > +

{$_("trail", { values: { n: 2 } })}

@@ -379,11 +403,27 @@ { + await updateTrailShares(); + await saveList(); + }} +> + + { + await publishTrails(); + await saveList(); + }} >