diff --git a/db/main.go b/db/main.go index d5d1281d..e5801e26 100644 --- a/db/main.go +++ b/db/main.go @@ -120,7 +120,7 @@ func setupEventHandlers(app *pocketbase.PocketBase, client meilisearch.ServiceMa app.OnRecordUpdate("integrations").BindFunc(updateIntegrationHandler()) app.OnRecordAfterUpdateSuccess("integrations").BindFunc(createUpdateIntegrationSuccessHandler()) - app.OnRecordsListRequest("feed").BindFunc(listFeedHandler()) + app.OnRecordsListRequest("feed", "profile_feed").BindFunc(listFeedHandler()) app.OnRecordCreateRequest().BindFunc(sanitizeHTML()) app.OnRecordUpdateRequest().BindFunc(sanitizeHTML()) @@ -905,19 +905,35 @@ func listFeedHandler() func(e *core.RecordsListRequestEvent) error { for _, r := range e.Records { var item *core.Record var err error - switch r.GetString("type") { + + typ := r.GetString("type") + typ = strings.Trim(typ, "\"") + + itemId := r.GetString("item") + itemId = strings.Trim(itemId, "\"") + + switch typ { case string(util.TrailFeed): - item, err = e.App.FindRecordById("trails", r.GetString("item")) + item, err = e.App.FindRecordById("trails", itemId) case string(util.ListFeed): - item, err = e.App.FindRecordById("lists", r.GetString("item")) + item, err = e.App.FindRecordById("lists", itemId) case string(util.SummitLogFeed): - item, err = e.App.FindRecordById("summit_logs", r.GetString("item")) + item, err = e.App.FindRecordById("summit_logs", itemId) } if err != nil { continue } + if item == nil { + continue + } + + errs := e.App.ExpandRecord(item, []string{"author"}, nil) + if len(errs) > 0 { + return fmt.Errorf("failed to expand: %v", errs) + } + r.MergeExpand(map[string]any{"item": item}) } return e.Next() diff --git a/db/migrations/1752321031_created_profile_feed.go b/db/migrations/1752321031_created_profile_feed.go new file mode 100644 index 00000000..0dfa5fc6 --- /dev/null +++ b/db/migrations/1752321031_created_profile_feed.go @@ -0,0 +1,106 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(app core.App) error { + jsonData := `{ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3208210256", + "max": 0, + "min": 0, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "hidden": false, + "id": "json1148540665", + "maxSize": 1, + "name": "actor", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json3182418120", + "maxSize": 1, + "name": "author", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json521872670", + "maxSize": 1, + "name": "item", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json2363381545", + "maxSize": 1, + "name": "type", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json2990389176", + "maxSize": 1, + "name": "created", + "presentable": false, + "required": false, + "system": false, + "type": "json" + } + ], + "id": "pbc_1973704172", + "indexes": [], + "listRule": "", + "name": "profile_feed", + "system": false, + "type": "view", + "updateRule": null, + "viewQuery": "SELECT\n (ROW_NUMBER() OVER ()) as id,\n actor,\n author,\n item,\n type,\n created\nFROM\n (\n SELECT\n author as actor,\n author,\n id as item,\n \"list\" as type,\n created\n FROM\n lists\n UNION\n SELECT\n author as actor,\n author,\n id as item,\n \"trail\" as type,\n created\n FROM trails\n )\nORDER BY created desc;", + "viewRule": null + }` + + collection := &core.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { + return err + } + + return app.Save(collection) + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_1973704172") + if err != nil { + return err + } + + return app.Delete(collection) + }) +} diff --git a/db/migrations/1752324952_updated_profile_feed.go b/db/migrations/1752324952_updated_profile_feed.go new file mode 100644 index 00000000..96d7ffeb --- /dev/null +++ b/db/migrations/1752324952_updated_profile_feed.go @@ -0,0 +1,57 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_1973704172") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "viewQuery": "SELECT\n (ROW_NUMBER() OVER ()) as id,\n actor,\n item,\n type,\n created\nFROM\n (\n SELECT\n author as actor,\n id as item,\n 'list' as type,\n created\n FROM\n lists\n UNION\n SELECT\n author as actor,\n id as item,\n 'trail' as type,\n created\n FROM trails\n )\nORDER BY created desc;" + }`), &collection); err != nil { + return err + } + + // remove field + collection.Fields.RemoveById("json3182418120") + + return app.Save(collection) + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_1973704172") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "viewQuery": "SELECT\n (ROW_NUMBER() OVER ()) as id,\n actor,\n author,\n item,\n type,\n created\nFROM\n (\n SELECT\n author as actor,\n author,\n id as item,\n \"list\" as type,\n created\n FROM\n lists\n UNION\n SELECT\n author as actor,\n author,\n id as item,\n \"trail\" as type,\n created\n FROM trails\n )\nORDER BY created desc;" + }`), &collection); err != nil { + return err + } + + // add field + if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{ + "hidden": false, + "id": "json3182418120", + "maxSize": 1, + "name": "author", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }`)); err != nil { + return err + } + + return app.Save(collection) + }) +} diff --git a/db/migrations/1752324970_updated_feed.go b/db/migrations/1752324970_updated_feed.go new file mode 100644 index 00000000..63dc7de0 --- /dev/null +++ b/db/migrations/1752324970_updated_feed.go @@ -0,0 +1,44 @@ +package migrations + +import ( + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_72164123") + if err != nil { + return err + } + + // remove field + collection.Fields.RemoveById("relation3182418120") + + return app.Save(collection) + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_72164123") + if err != nil { + return err + } + + // add field + if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{ + "cascadeDelete": true, + "collectionId": "pbc_1295301207", + "hidden": false, + "id": "relation3182418120", + "maxSelect": 1, + "minSelect": 0, + "name": "author", + "presentable": false, + "required": true, + "system": false, + "type": "relation" + }`)); err != nil { + return err + } + + return app.Save(collection) + }) +} diff --git a/db/migrations/1752330359_deleted_timeline.go b/db/migrations/1752330359_deleted_timeline.go new file mode 100644 index 00000000..1c19b6a8 --- /dev/null +++ b/db/migrations/1752330359_deleted_timeline.go @@ -0,0 +1,216 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_468398817") + if err != nil { + return err + } + + return app.Delete(collection) + }, func(app core.App) error { + jsonData := `{ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3208210256", + "max": 0, + "min": 0, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "hidden": false, + "id": "json2310347867", + "maxSize": 1, + "name": "trail_id", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json3184124860", + "maxSize": 1, + "name": "trail_author_username", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json2887874732", + "maxSize": 1, + "name": "trail_author_domain", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json113557190", + "maxSize": 1, + "name": "trail_iri", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json2862495610", + "maxSize": 1, + "name": "date", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json1579384326", + "maxSize": 1, + "name": "name", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json1843675174", + "maxSize": 1, + "name": "description", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json3275261007", + "maxSize": 1, + "name": "gpx", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json3182418120", + "maxSize": 1, + "name": "author", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json142008537", + "maxSize": 1, + "name": "photos", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json479369857", + "maxSize": 1, + "name": "distance", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json2254405824", + "maxSize": 1, + "name": "duration", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json3015100073", + "maxSize": 1, + "name": "elevation_gain", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json3171089056", + "maxSize": 1, + "name": "elevation_loss", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json2990389176", + "maxSize": 1, + "name": "created", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "json2363381545", + "maxSize": 1, + "name": "type", + "presentable": false, + "required": false, + "system": false, + "type": "json" + } + ], + "id": "pbc_468398817", + "indexes": [], + "listRule": "@collection.trails.id ?= trail_id && @collection.trails.public ?= true", + "name": "timeline", + "system": false, + "type": "view", + "updateRule": null, + "viewQuery": "SELECT\n id,\n trail_id,\n trail_author_username,\n trail_author_domain,\n trail_iri,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.id,\n summit_logs.trail as trail_id,\n tapa.preferred_username as trail_author_username,\n tapa.domain as trail_author_domain,\n trails.iri as trail_iri,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n sapa.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors sapa ON sapa.id = summit_logs.author\n JOIN activitypub_actors tapa ON tapa.id = trails.author\n UNION\n SELECT\n trails.id,\n trails.id as trail_id,\n activitypub_actors.preferred_username as trail_author_username,\n activitypub_actors.domain as trail_author_domain,\n trails.iri as trail_iri,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n", + "viewRule": "@collection.trails.id ?= trail_id && @collection.trails.public ?= true" + }` + + collection := &core.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { + return err + } + + return app.Save(collection) + }) +} diff --git a/db/migrations/1752330401_updated_profile_feed.go b/db/migrations/1752330401_updated_profile_feed.go new file mode 100644 index 00000000..bbc0d21c --- /dev/null +++ b/db/migrations/1752330401_updated_profile_feed.go @@ -0,0 +1,40 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_1973704172") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "listRule": "actor.user.settings_via_user.privacy.account != 'private' || actor.user = @request.auth.id" + }`), &collection); err != nil { + return err + } + + return app.Save(collection) + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_1973704172") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "listRule": "" + }`), &collection); err != nil { + return err + } + + return app.Save(collection) + }) +} diff --git a/web/src/lib/components/base/dropdown.svelte b/web/src/lib/components/base/dropdown.svelte index 8670271b..b424bcf3 100644 --- a/web/src/lib/components/base/dropdown.svelte +++ b/web/src/lib/components/base/dropdown.svelte @@ -21,16 +21,16 @@ let isOpen = $state(false); - let dropdownElement: HTMLUListElement; + let dropdownElement: HTMLUListElement | undefined = $state(); let dropdownToggleElement: HTMLDivElement; - export async function toggleMenu(e: MouseEvent) { + export async function toggleMenu(e: MouseEvent) { e.stopPropagation(); e.preventDefault(); isOpen = !isOpen; - if (isOpen) { + if (isOpen && dropdownElement) { await tick(); const toggleRect = dropdownToggleElement.getBoundingClientRect(); @@ -81,7 +81,8 @@ isOpen = false; } - function handleItemClick(e: Event, item: { text: string; value: any }) { + function handleItemClick(e: MouseEvent, item: { text: string; value: any }) { + e.preventDefault(); e.stopPropagation(); onchange?.(item); closeMenu(); @@ -129,7 +130,7 @@