From c2cac40710b59124309744bdbc1da50a56747944 Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 13:04:24 -0700 Subject: [PATCH 1/8] add: created likes --- migrations/1776715443_created_likes.go | 118 +++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 migrations/1776715443_created_likes.go diff --git a/migrations/1776715443_created_likes.go b/migrations/1776715443_created_likes.go new file mode 100644 index 0000000..f23436b --- /dev/null +++ b/migrations/1776715443_created_likes.go @@ -0,0 +1,118 @@ +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": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "cascadeDelete": true, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation2375276105", + "maxSelect": 1, + "minSelect": 0, + "name": "user", + "presentable": false, + "required": true, + "system": false, + "type": "relation" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text361630566", + "max": 0, + "min": 0, + "name": "target_id", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "select3466706339", + "maxSelect": 1, + "name": "target_collection", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "cps", + "ccharacters" + ] + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_2190274710", + "indexes": [ + "CREATE UNIQUE INDEX ` + "`" + `idx_unique_user_like` + "`" + ` ON ` + "`" + `likes` + "`" + ` (\n ` + "`" + `user` + "`" + `,\n ` + "`" + `target_id` + "`" + `,\n ` + "`" + `target_collection` + "`" + `\n)" + ], + "listRule": null, + "name": "likes", + "system": false, + "type": "base", + "updateRule": null, + "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_2190274710") + if err != nil { + return err + } + + return app.Delete(collection) + }) +} From 87fc9d40824eab5e18ead9ff6424fb283bbafe46 Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 13:07:42 -0700 Subject: [PATCH 2/8] add: new index --- migrations/1776715655_updated_likes.go | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 migrations/1776715655_updated_likes.go diff --git a/migrations/1776715655_updated_likes.go b/migrations/1776715655_updated_likes.go new file mode 100644 index 0000000..7de595b --- /dev/null +++ b/migrations/1776715655_updated_likes.go @@ -0,0 +1,45 @@ +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_2190274710") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "indexes": [ + "CREATE UNIQUE INDEX ` + "`" + `idx_unique_user_like` + "`" + ` ON ` + "`" + `likes` + "`" + ` (\n ` + "`" + `user` + "`" + `,\n ` + "`" + `target_id` + "`" + `,\n ` + "`" + `target_collection` + "`" + `\n)", + "CREATE INDEX ` + "`" + `idx_target_lookup` + "`" + ` ON ` + "`" + `likes` + "`" + ` (\n ` + "`" + `target_id` + "`" + `,\n ` + "`" + `target_collection` + "`" + `\n)" + ] + }`), &collection); err != nil { + return err + } + + return app.Save(collection) + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_2190274710") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "indexes": [ + "CREATE UNIQUE INDEX ` + "`" + `idx_unique_user_like` + "`" + ` ON ` + "`" + `likes` + "`" + ` (\n ` + "`" + `user` + "`" + `,\n ` + "`" + `target_id` + "`" + `,\n ` + "`" + `target_collection` + "`" + `\n)" + ] + }`), &collection); err != nil { + return err + } + + return app.Save(collection) + }) +} From 83db485330b4e5982b6d1058df32428b7dc8e405 Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 13:12:43 -0700 Subject: [PATCH 3/8] fix: wrong name for target_type --- migrations/1776715948_updated_likes.go | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 migrations/1776715948_updated_likes.go diff --git a/migrations/1776715948_updated_likes.go b/migrations/1776715948_updated_likes.go new file mode 100644 index 0000000..f213671 --- /dev/null +++ b/migrations/1776715948_updated_likes.go @@ -0,0 +1,60 @@ +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_2190274710") + if err != nil { + return err + } + + // update field + if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{ + "hidden": false, + "id": "select3466706339", + "maxSelect": 1, + "name": "target_collection", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "cps", + "characters" + ] + }`)); err != nil { + return err + } + + return app.Save(collection) + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_2190274710") + if err != nil { + return err + } + + // update field + if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{ + "hidden": false, + "id": "select3466706339", + "maxSelect": 1, + "name": "target_collection", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "cps", + "ccharacters" + ] + }`)); err != nil { + return err + } + + return app.Save(collection) + }) +} From 2fedb08dd6584d5faa6908c4bfd146f55a6b585d Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 13:44:14 -0700 Subject: [PATCH 4/8] feat: finish likes & use e. instead apis. --- main.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 76c17d7..c0b2f73 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,9 @@ package main import ( + "database/sql" "embed" + "errors" "io/fs" "log" @@ -41,6 +43,72 @@ func main() { app.OnServe().BindFunc(func(se *core.ServeEvent) error { Setup(se.App) + se.Router.POST("/{type}/{id}/toggle-like", func(e *core.RequestEvent) error { + requestCollection := e.Request.PathValue("type") + id := e.Request.PathValue("id") + + if requestCollection != "cps" && requestCollection != "characters" { + return e.Error(400, "Invalid request data", map[string]validation.Error{ + "type": validation.NewError("validation_collection_type", "Invalid collection type."), + }) + } + + collection, err := app.FindCollectionByNameOrId(requestCollection) + if err != nil { + return e.InternalServerError("Internal Server Error", map[string]any{"message": "Cannot find collection", "err": err}) + } + + record, err := app.FindRecordById(requestCollection, id) + + if err != nil { + if !errors.Is(err, sql.ErrNoRows) { + return e.InternalServerError("Internal Server Error", map[string]any{ + "message": "Cannot find record", + "err": err, + }) + } + } + + if record != nil { + + err = app.Delete(record) + if err != nil { + return e.InternalServerError("Internal Server Error", map[string]any{ + "message": "Cannot delete record", + "err": err, + }) + } + + return e.JSON(200, map[string]any{ + "message": "Success", + "like": false, + "data": record, + }) + } + + record = core.NewRecord(collection) + + record.Set("target_id", id) + record.Set("target_collection", requestCollection) + record.Set("owner", e.Auth.Id) + + err = app.Save(record) + + if err != nil { + return e.InternalServerError("Internal Server Error", map[string]any{ + "message": "Cannot save record", + "err": err, + }) + } + + return e.JSON(200, map[string]any{ + "message": "Success", + "like": true, + "data": record, + }) + + }).Bind(apis.RequireAuth()) + publicFS, err := fs.Sub(embeddedFiles, "pb_public") if err != nil { return err @@ -82,7 +150,7 @@ func validateIdImmutable(e *core.RecordRequestEvent) error { // 检查用户有没有传入id if e.Record.Id != "" { - return apis.NewBadRequestError("Invalid request data", map[string]validation.Error{ + return e.BadRequestError("Invalid request data", map[string]validation.Error{ "id": validation.NewError("validation_id_immutable", "Custom record IDs are not allowed."), }) } @@ -94,7 +162,7 @@ func validateIdImmutable(e *core.RecordRequestEvent) error { func validateCharactersOwnership(e *core.RecordRequestEvent) error { if e.Auth == nil { - return apis.NewUnauthorizedError("Unauthorized", nil) + return e.UnauthorizedError("Unauthorized", nil) } // Superuser 绕过 @@ -125,12 +193,12 @@ func validateCharactersOwnership(e *core.RecordRequestEvent) error { Row(&count) if err != nil { - return apis.NewInternalServerError("Database query failed", err) + return e.InternalServerError("Database query failed", err) } // 如果发现有角色不属于该用户,拦截请求 if count > 0 { - return apis.NewBadRequestError("Illegal association", map[string]validation.Error{ + return e.Error(403, "Illegal association", map[string]validation.Error{ "characters": validation.NewError("invalid_character_owner", "One or more selected characters do not belong to you."), }) } From 731ec2e7baf9e715798bfbe3b5ddedf66fe26399 Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 16:28:18 -0700 Subject: [PATCH 5/8] fix: wrong route --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index c0b2f73..95bcfe7 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,7 @@ func main() { app.OnServe().BindFunc(func(se *core.ServeEvent) error { Setup(se.App) - se.Router.POST("/{type}/{id}/toggle-like", func(e *core.RequestEvent) error { + se.Router.POST("/api/{type}/{id}/toggle-like", func(e *core.RequestEvent) error { requestCollection := e.Request.PathValue("type") id := e.Request.PathValue("id") From f9aaa4a9da0acd74e1c8a8340cc88da653788c62 Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 16:39:38 -0700 Subject: [PATCH 6/8] update: API Rules --- migrations/1776728364_updated_likes.go | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 migrations/1776728364_updated_likes.go diff --git a/migrations/1776728364_updated_likes.go b/migrations/1776728364_updated_likes.go new file mode 100644 index 0000000..05c4c6f --- /dev/null +++ b/migrations/1776728364_updated_likes.go @@ -0,0 +1,42 @@ +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_2190274710") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "listRule": "", + "viewRule": "" + }`), &collection); err != nil { + return err + } + + return app.Save(collection) + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("pbc_2190274710") + if err != nil { + return err + } + + // update collection data + if err := json.Unmarshal([]byte(`{ + "listRule": null, + "viewRule": null + }`), &collection); err != nil { + return err + } + + return app.Save(collection) + }) +} From 2a9250e9e39cfaf748f82eacd87dc0bec7c8a411 Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 17:11:25 -0700 Subject: [PATCH 7/8] fix: is existing bug --- main.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/main.go b/main.go index 95bcfe7..5d3293c 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "database/sql" "embed" "errors" + "fmt" "io/fs" "log" @@ -45,7 +46,8 @@ func main() { se.Router.POST("/api/{type}/{id}/toggle-like", func(e *core.RequestEvent) error { requestCollection := e.Request.PathValue("type") - id := e.Request.PathValue("id") + targetId := e.Request.PathValue("id") // 被点赞物体的 ID + userId := e.Auth.Id if requestCollection != "cps" && requestCollection != "characters" { return e.Error(400, "Invalid request data", map[string]validation.Error{ @@ -53,12 +55,14 @@ func main() { }) } - collection, err := app.FindCollectionByNameOrId(requestCollection) + collection, err := app.FindCollectionByNameOrId("likes") if err != nil { return e.InternalServerError("Internal Server Error", map[string]any{"message": "Cannot find collection", "err": err}) } - record, err := app.FindRecordById(requestCollection, id) + existingRecord, err := app.FindFirstRecordByFilter("likes", + fmt.Sprintf("user = '%s' && target_id = '%s'", userId, targetId), + ) if err != nil { if !errors.Is(err, sql.ErrNoRows) { @@ -69,9 +73,9 @@ func main() { } } - if record != nil { + if existingRecord != nil { - err = app.Delete(record) + err = app.Delete(existingRecord) if err != nil { return e.InternalServerError("Internal Server Error", map[string]any{ "message": "Cannot delete record", @@ -82,15 +86,15 @@ func main() { return e.JSON(200, map[string]any{ "message": "Success", "like": false, - "data": record, + "data": existingRecord, }) } - record = core.NewRecord(collection) + record := core.NewRecord(collection) - record.Set("target_id", id) + record.Set("target_id", targetId) record.Set("target_collection", requestCollection) - record.Set("owner", e.Auth.Id) + record.Set("user", e.Auth.Id) err = app.Save(record) From bdf6489e3de6d328c3833580396d7b1318b61167 Mon Sep 17 00:00:00 2001 From: BretRen Date: Mon, 20 Apr 2026 17:11:35 -0700 Subject: [PATCH 8/8] Finish frontend & Base --- website/src/routes/explore/+page.svelte | 106 +++++++++++++++++++----- 1 file changed, 83 insertions(+), 23 deletions(-) diff --git a/website/src/routes/explore/+page.svelte b/website/src/routes/explore/+page.svelte index 36522b2..ba86193 100644 --- a/website/src/routes/explore/+page.svelte +++ b/website/src/routes/explore/+page.svelte @@ -1,4 +1,5 @@