adds list search

This commit is contained in:
Christian Beutel
2025-01-26 17:28:38 +01:00
parent eda94f3003
commit f34fd7afed
20 changed files with 413 additions and 98 deletions

View File

@@ -61,9 +61,13 @@ func setupEventHandlers(app *pocketbase.PocketBase, client meilisearch.ServiceMa
app.OnRecordAfterCreateRequest("trail_share").Add(createTrailShareHandler(app, client))
app.OnRecordAfterDeleteRequest("trail_share").Add(deleteTrailShareHandler(client))
app.OnRecordAfterCreateRequest("list_share").Add(createListShareHandler(app))
app.OnRecordAfterCreateRequest("lists").Add(createListHandler(app, client))
app.OnRecordAfterUpdateRequest("lists").Add(updateListHandler(client))
app.OnRecordAfterDeleteRequest("lists").Add(deleteListHandler(client))
app.OnRecordAfterCreateRequest("list_share").Add(createListShareHandler(app, client))
app.OnRecordAfterDeleteRequest("list_share").Add(deleteListShareHandler(client))
app.OnRecordAfterCreateRequest("lists").Add(createListHandler(app))
app.OnRecordAfterCreateRequest("follows").Add(createFollowHandler(app))
app.OnRecordAfterCreateRequest("comments").Add(createCommentHandler(app))
@@ -77,7 +81,9 @@ func createUserHandler(app *pocketbase.PocketBase, client meilisearch.ServiceMan
userId := record.GetId()
searchRules := map[string]interface{}{
"cities500": map[string]string{},
"lists": map[string]string{
"filter": "public = true OR author = " + userId + " OR shares = " + userId,
},
"trails": map[string]string{
"filter": "public = true OR author = " + userId + " OR shares = " + userId,
},
@@ -156,7 +162,11 @@ func createTrailShareHandler(app *pocketbase.PocketBase, client meilisearch.Serv
for i, r := range shares {
userIds[i] = r.GetString("user")
}
util.UpdateTrailShares(trailId, userIds, client)
err = util.UpdateTrailShares(trailId, userIds, client)
if err != nil {
return err
}
if errs := app.Dao().ExpandRecord(e.Record, []string{"trail", "trail.author"}, nil); len(errs) > 0 {
return fmt.Errorf("failed to expand: %v", errs)
@@ -178,8 +188,66 @@ func createTrailShareHandler(app *pocketbase.PocketBase, client meilisearch.Serv
}
}
func createListShareHandler(app *pocketbase.PocketBase) func(e *core.RecordCreateEvent) error {
func deleteTrailShareHandler(client meilisearch.ServiceManager) func(e *core.RecordDeleteEvent) error {
return func(e *core.RecordDeleteEvent) error {
trailId := e.Record.GetString("trail")
return util.UpdateTrailShares(trailId, []string{}, client)
}
}
func createListHandler(app *pocketbase.PocketBase, client meilisearch.ServiceManager) func(e *core.RecordCreateEvent) error {
return func(e *core.RecordCreateEvent) error {
if err := util.IndexList(e.Record, client); err != nil {
return err
}
if !e.Record.GetBool("public") {
return nil
}
notification := util.Notification{
Type: util.ListCreate,
Metadata: map[string]string{
"id": e.Record.Id,
"list": e.Record.GetString("name"),
},
Seen: false,
Author: e.Record.GetString("author"),
}
return util.SendNotificationToFollowers(app, notification)
}
}
func updateListHandler(client meilisearch.ServiceManager) func(e *core.RecordUpdateEvent) error {
return func(e *core.RecordUpdateEvent) error {
return util.UpdateList(e.Record, client)
}
}
func deleteListHandler(client meilisearch.ServiceManager) func(e *core.RecordDeleteEvent) error {
return func(e *core.RecordDeleteEvent) error {
_, err := client.Index("lists").DeleteDocument(e.Record.Id)
return err
}
}
func createListShareHandler(app *pocketbase.PocketBase, client meilisearch.ServiceManager) func(e *core.RecordCreateEvent) error {
return func(e *core.RecordCreateEvent) error {
listId := e.Record.GetString("list")
shares, err := app.Dao().FindRecordsByExpr("list_share",
dbx.NewExp("list = {:listId}", dbx.Params{"listId": listId}),
)
if err != nil {
return err
}
userIds := make([]string, len(shares))
for i, r := range shares {
userIds[i] = r.GetString("user")
}
err = util.UpdateListShares(listId, userIds, client)
if err != nil {
return err
}
if errs := app.Dao().ExpandRecord(e.Record, []string{"list", "list.author"}, nil); len(errs) > 0 {
return fmt.Errorf("failed to expand: %v", errs)
}
@@ -200,28 +268,10 @@ func createListShareHandler(app *pocketbase.PocketBase) func(e *core.RecordCreat
}
}
func deleteTrailShareHandler(client meilisearch.ServiceManager) func(e *core.RecordDeleteEvent) error {
func deleteListShareHandler(client meilisearch.ServiceManager) func(e *core.RecordDeleteEvent) error {
return func(e *core.RecordDeleteEvent) error {
trailId := e.Record.GetString("trail")
return util.UpdateTrailShares(trailId, []string{}, client)
}
}
func createListHandler(app *pocketbase.PocketBase) func(e *core.RecordCreateEvent) error {
return func(e *core.RecordCreateEvent) error {
if !e.Record.GetBool("public") {
return nil
}
notification := util.Notification{
Type: util.ListCreate,
Metadata: map[string]string{
"id": e.Record.Id,
"list": e.Record.GetString("name"),
},
Seen: false,
Author: e.Record.GetString("author"),
}
return util.SendNotificationToFollowers(app, notification)
listId := e.Record.GetString("list")
return util.UpdateListShares(listId, []string{}, client)
}
}
@@ -293,7 +343,9 @@ func onBeforeServeHandler(app *pocketbase.PocketBase, client meilisearch.Service
func registerRoutes(e *core.ServeEvent, app *pocketbase.PocketBase, client meilisearch.ServiceManager) {
e.Router.GET("/public/search/token", func(c echo.Context) error {
searchRules := map[string]interface{}{
"cities500": map[string]string{},
"lists": map[string]string{
"filter": "public = true",
},
"trails": map[string]string{
"filter": "public = true",
},

View File

@@ -0,0 +1,117 @@
package migrations
import (
"os"
"pocketbase/util"
"github.com/meilisearch/meilisearch-go"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
client := meilisearch.New(os.Getenv("MEILI_URL"), meilisearch.WithAPIKey(os.Getenv("MEILI_MASTER_KEY")))
m.Register(func(db dbx.Builder) error {
_, err := client.CreateIndex(&meilisearch.IndexConfig{
Uid: "lists",
PrimaryKey: "id",
})
if err != nil {
return err
}
_, err = client.Index("lists").UpdateSortableAttributes(&[]string{
"created", "name",
})
if err != nil {
return err
}
_, err = client.Index("lists").UpdateFilterableAttributes(&[]string{
"author", "public", "shares",
})
if err != nil {
return err
}
dao := daos.New(db)
lists, err := dao.FindRecordsByExpr("lists", dbx.NewExp("true"))
if err != nil {
return err
}
for _, l := range lists {
err = util.IndexList(l, client)
if err != nil {
return err
}
shares, err := dao.FindRecordsByExpr("list_share",
dbx.NewExp("list = {:listId}", dbx.Params{"listId": l.Id}),
)
if err != nil {
return err
}
userIds := make([]string, len(shares))
for i, r := range shares {
userIds[i] = r.GetString("user")
}
err = util.UpdateListShares(l.Id, userIds, client)
if err != nil {
return err
}
}
var usernames []string
err = db.NewQuery("SELECT username FROM users").Column(&usernames)
if err != nil {
return err
}
for _, username := range usernames {
record, err := dao.FindAuthRecordByUsername("users", username)
if err != nil {
return err
}
searchRules := map[string]interface{}{
"lists": map[string]string{
"filter": "public = true OR author = " + record.Id + " OR shares = " + record.Id,
},
"trails": map[string]string{
"filter": "public = true OR author = " + record.Id + " OR shares = " + record.Id,
},
}
if token, err := util.GenerateMeilisearchToken(searchRules, client); err != nil {
return err
} else {
record.Set("token", token)
if err := dao.SaveRecord(record); err != nil {
return err
}
}
}
_, err = client.DeleteIndex("cities500")
if err != nil {
return err
}
return nil
}, func(db dbx.Builder) error {
_, err := client.DeleteIndex("lists")
if err != nil {
return err
}
return nil
})
}

View File

@@ -38,6 +38,24 @@ func documentFromTrailRecord(r *models.Record, includeShares bool) map[string]in
return document
}
func documentFromListRecord(r *models.Record, includeShares bool) map[string]interface{} {
document := map[string]interface{}{
"id": r.Id,
"author": r.GetString("author"),
"name": r.GetString("name"),
"description": r.GetString("description"),
"public": r.GetBool("public"),
"created": r.GetDateTime("created").Time().Unix(),
"trails": r.GetStringSlice("trails"),
}
if includeShares {
document["shares"] = []string{}
}
return document
}
func IndexTrail(r *models.Record, client meilisearch.ServiceManager) error {
documents := []map[string]interface{}{documentFromTrailRecord(r, true)}
@@ -71,6 +89,39 @@ func UpdateTrailShares(trailId string, shares []string, client meilisearch.Servi
return nil
}
func IndexList(r *models.Record, client meilisearch.ServiceManager) error {
documents := []map[string]interface{}{documentFromListRecord(r, true)}
if _, err := client.Index("lists").AddDocuments(documents); err != nil {
return err
}
return nil
}
func UpdateList(r *models.Record, client meilisearch.ServiceManager) error {
documents := documentFromListRecord(r, false)
if _, err := client.Index("lists").UpdateDocuments(documents); err != nil {
return err
}
return nil
}
func UpdateListShares(listId string, shares []string, client meilisearch.ServiceManager) error {
documents := []map[string]interface{}{
{
"id": listId,
"shares": shares,
},
}
if _, err := client.Index("lists").UpdateDocuments(documents); err != nil {
return err
}
return nil
}
func GenerateMeilisearchToken(rules map[string]interface{}, client meilisearch.ServiceManager) (resp string, err error) {
apiKeyUid := ""
apiKey := ""