diff --git a/main.go b/main.go index 76c17d7..5d3293c 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,10 @@ package main import ( + "database/sql" "embed" + "errors" + "fmt" "io/fs" "log" @@ -41,6 +44,75 @@ func main() { app.OnServe().BindFunc(func(se *core.ServeEvent) error { Setup(se.App) + se.Router.POST("/api/{type}/{id}/toggle-like", func(e *core.RequestEvent) error { + requestCollection := e.Request.PathValue("type") + 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{ + "type": validation.NewError("validation_collection_type", "Invalid collection type."), + }) + } + + collection, err := app.FindCollectionByNameOrId("likes") + if err != nil { + return e.InternalServerError("Internal Server Error", map[string]any{"message": "Cannot find collection", "err": err}) + } + + existingRecord, err := app.FindFirstRecordByFilter("likes", + fmt.Sprintf("user = '%s' && target_id = '%s'", userId, targetId), + ) + + 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 existingRecord != nil { + + err = app.Delete(existingRecord) + 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": existingRecord, + }) + } + + record := core.NewRecord(collection) + + record.Set("target_id", targetId) + record.Set("target_collection", requestCollection) + record.Set("user", 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 +154,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 +166,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 +197,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."), }) } 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) + }) +} 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) + }) +} 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) + }) +} 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) + }) +} 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 @@