From c09cd8364aaeed7e0ccf020f528baaef5bd16c73 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Wed, 9 Oct 2024 11:51:03 +0300 Subject: [PATCH] added explicit errors when trying to truncate view collections or deleting view records --- CHANGELOG.md | 8 ++++++++ apis/collection.go | 4 ++++ apis/collection_test.go | 11 +++++++++++ core/collection_query.go | 4 ++++ core/collection_query_test.go | 12 ++++++++++++ core/record_model.go | 8 +++++++- core/record_model_test.go | 18 +++++++++++++++--- 7 files changed, 61 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a678e8f..679fc474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## v0.23.0-rc4 (WIP) + +> [!CAUTION] +> **This is a prerelease intended for test and experimental purposes only!** + +- Added more user friendly view collection truncate error message. + + ## v0.23.0-rc3 > [!CAUTION] diff --git a/apis/collection.go b/apis/collection.go index e49da210..b25972b6 100644 --- a/apis/collection.go +++ b/apis/collection.go @@ -169,6 +169,10 @@ func collectionTruncate(e *core.RequestEvent) error { return e.NotFoundError("", err) } + if collection.IsView() { + return e.BadRequestError("View collections cannot be truncated since they don't store their own records.", nil) + } + err = e.App.TruncateCollection(collection) if err != nil { return e.BadRequestError("Failed to truncate collection (most likely due to required cascade delete record references).", err) diff --git a/apis/collection_test.go b/apis/collection_test.go index d1224a73..c8d2cdda 100644 --- a/apis/collection_test.go +++ b/apis/collection_test.go @@ -1493,6 +1493,17 @@ func TestCollectionTruncate(t *testing.T) { "OnRecordAfterUpdateError": 2, }, }, + { + Name: "authorized as superuser trying to truncate view collection", + Method: http.MethodDelete, + URL: "/api/collections/view2/truncate", + Headers: map[string]string{ + "Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg", + }, + ExpectedStatus: 400, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{"*": 0}, + }, } for _, scenario := range scenarios { diff --git a/core/collection_query.go b/core/collection_query.go index f5019899..a7318938 100644 --- a/core/collection_query.go +++ b/core/collection_query.go @@ -176,6 +176,10 @@ func (app *BaseApp) FindCollectionReferences(collection *Collection, excludeIds // Note that this method will also trigger the records related // cascade and file delete actions. func (app *BaseApp) TruncateCollection(collection *Collection) error { + if collection.IsView() { + return errors.New("view collections cannot be truncated since they don't store their own records.") + } + return app.RunInTransaction(func(txApp App) error { records := make([]*Record, 0, 500) diff --git a/core/collection_query_test.go b/core/collection_query_test.go index f612ff96..f6d35a37 100644 --- a/core/collection_query_test.go +++ b/core/collection_query_test.go @@ -299,6 +299,18 @@ func TestFindCollectionTruncate(t *testing.T) { return len(entries), err } + t.Run("truncate view", func(t *testing.T) { + view2, err := app.FindCollectionByNameOrId("view2") + if err != nil { + t.Fatal(err) + } + + err = app.TruncateCollection(view2) + if err == nil { + t.Fatalf("Expected truncate to fail because view collections can't be truncated") + } + }) + t.Run("truncate failure", func(t *testing.T) { demo3, err := app.FindCollectionByNameOrId("demo3") if err != nil { diff --git a/core/record_model.go b/core/record_model.go index e06599bf..65477e68 100644 --- a/core/record_model.go +++ b/core/record_model.go @@ -378,7 +378,13 @@ func (app *BaseApp) registerRecordHooks() { e.Context, e.App, InterceptorActionDelete, - e.Next, + func() error { + if e.Record.Collection().IsView() { + return errors.New("view records cannot be deleted") + } + + return e.Next() + }, ) }, Priority: -99, diff --git a/core/record_model_test.go b/core/record_model_test.go index d19c7a43..0f5e3ade 100644 --- a/core/record_model_test.go +++ b/core/record_model_test.go @@ -1841,9 +1841,21 @@ func TestRecordDelete(t *testing.T) { // delete unsaved record // --- - rec0 := core.NewRecord(demoCollection) - if err := app.Delete(rec0); err == nil { - t.Fatal("(rec0) Didn't expect to succeed deleting unsaved record") + newRec := core.NewRecord(demoCollection) + if err := app.Delete(newRec); err == nil { + t.Fatal("(newRec) Didn't expect to succeed deleting unsaved record") + } + + // delete view record + // --- + viewRec, _ := app.FindRecordById("view2", "84nmscqy84lsi1t") + if err := app.Delete(viewRec); err == nil { + t.Fatal("(viewRec) Didn't expect to succeed deleting view record") + } + // check if it still exists + viewRec, _ = app.FindRecordById(viewRec.Collection().Id, viewRec.Id) + if viewRec == nil { + t.Fatal("(viewRec) Expected view record to still exists") } // delete existing record + external auths