[#80] fixed before hooks data and added optional interceptor to upsert submit
This commit is contained in:
parent
ce857985be
commit
05a4071eba
|
@ -166,7 +166,7 @@ func (api *adminApi) create(c echo.Context) error {
|
|||
|
||||
// load request
|
||||
if err := c.Bind(form); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.AdminCreateEvent{
|
||||
|
@ -174,20 +174,24 @@ func (api *adminApi) create(c echo.Context) error {
|
|||
Admin: admin,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnAdminBeforeCreateRequest().Trigger(event, func(e *core.AdminCreateEvent) error {
|
||||
// create the admin
|
||||
if err := form.Submit(); err != nil {
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnAdminBeforeCreateRequest().Trigger(event, func(e *core.AdminCreateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to create admin.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.Admin)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnAdminAfterCreateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *adminApi) update(c echo.Context) error {
|
||||
|
@ -205,7 +209,7 @@ func (api *adminApi) update(c echo.Context) error {
|
|||
|
||||
// load request
|
||||
if err := c.Bind(form); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.AdminUpdateEvent{
|
||||
|
@ -213,20 +217,24 @@ func (api *adminApi) update(c echo.Context) error {
|
|||
Admin: admin,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnAdminBeforeUpdateRequest().Trigger(event, func(e *core.AdminUpdateEvent) error {
|
||||
// update the admin
|
||||
if err := form.Submit(); err != nil {
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnAdminBeforeUpdateRequest().Trigger(event, func(e *core.AdminUpdateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to update admin.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.Admin)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnAdminAfterUpdateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *adminApi) delete(c echo.Context) error {
|
||||
|
|
|
@ -507,9 +507,6 @@ func TestAdminCreate(t *testing.T) {
|
|||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{`"data":{"email":{"code":"validation_required","message":"Cannot be blank."},"password":{"code":"validation_required","message":"Cannot be blank."}}`},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnAdminBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "authorized as admin + invalid data format",
|
||||
|
@ -532,9 +529,6 @@ func TestAdminCreate(t *testing.T) {
|
|||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{`"data":{"avatar":{"code":"validation_max_less_equal_than_required","message":"Must be no greater than 9."},"email":{"code":"validation_admin_email_exists","message":"Admin email already exists."},"password":{"code":"validation_length_out_of_range","message":"The length must be between 10 and 100."},"passwordConfirm":{"code":"validation_values_mismatch","message":"Values don't match."}}`},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnAdminBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "authorized as admin + valid data",
|
||||
|
@ -647,9 +641,6 @@ func TestAdminUpdate(t *testing.T) {
|
|||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{`"data":{"avatar":{"code":"validation_max_less_equal_than_required","message":"Must be no greater than 9."},"email":{"code":"validation_admin_email_exists","message":"Admin email already exists."},"password":{"code":"validation_length_out_of_range","message":"The length must be between 10 and 100."},"passwordConfirm":{"code":"validation_values_mismatch","message":"Values don't match."}}`},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnAdminBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Method: http.MethodPatch,
|
||||
|
|
|
@ -76,9 +76,9 @@ func (api *collectionApi) create(c echo.Context) error {
|
|||
|
||||
form := forms.NewCollectionUpsert(api.app, collection)
|
||||
|
||||
// read
|
||||
// load request
|
||||
if err := c.Bind(form); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.CollectionCreateEvent{
|
||||
|
@ -86,20 +86,24 @@ func (api *collectionApi) create(c echo.Context) error {
|
|||
Collection: collection,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnCollectionBeforeCreateRequest().Trigger(event, func(e *core.CollectionCreateEvent) error {
|
||||
// submit
|
||||
if err := form.Submit(); err != nil {
|
||||
// create the collection
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnCollectionBeforeCreateRequest().Trigger(event, func(e *core.CollectionCreateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to create the collection.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.Collection)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnCollectionAfterCreateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *collectionApi) update(c echo.Context) error {
|
||||
|
@ -110,9 +114,9 @@ func (api *collectionApi) update(c echo.Context) error {
|
|||
|
||||
form := forms.NewCollectionUpsert(api.app, collection)
|
||||
|
||||
// read
|
||||
// load request
|
||||
if err := c.Bind(form); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.CollectionUpdateEvent{
|
||||
|
@ -120,20 +124,24 @@ func (api *collectionApi) update(c echo.Context) error {
|
|||
Collection: collection,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnCollectionBeforeUpdateRequest().Trigger(event, func(e *core.CollectionUpdateEvent) error {
|
||||
// submit
|
||||
if err := form.Submit(); err != nil {
|
||||
// update the collection
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnCollectionBeforeUpdateRequest().Trigger(event, func(e *core.CollectionUpdateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to update the collection.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.Collection)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnCollectionAfterUpdateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *collectionApi) delete(c echo.Context) error {
|
||||
|
|
|
@ -297,9 +297,6 @@ func TestCollectionCreate(t *testing.T) {
|
|||
`"name":{"code":"validation_required"`,
|
||||
`"schema":{"code":"validation_required"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnCollectionBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "authorized as admin + invalid data (eg. existing name)",
|
||||
|
@ -315,9 +312,6 @@ func TestCollectionCreate(t *testing.T) {
|
|||
`"name":{"code":"validation_collection_name_exists"`,
|
||||
`"schema":{"0":{"name":{"code":"validation_required"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnCollectionBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "authorized as admin + valid data",
|
||||
|
@ -399,9 +393,6 @@ func TestCollectionUpdate(t *testing.T) {
|
|||
`"data":{`,
|
||||
`"name":{"code":"validation_collection_name_exists"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnCollectionBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "authorized as admin + valid data",
|
||||
|
|
|
@ -193,7 +193,7 @@ func (api *recordApi) create(c echo.Context) error {
|
|||
testRecord := models.NewRecord(collection)
|
||||
testForm := forms.NewRecordUpsert(api.app, testRecord)
|
||||
if err := testForm.LoadData(c.Request()); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
testErr := testForm.DrySubmit(func(txDao *daos.Dao) error {
|
||||
|
@ -210,7 +210,7 @@ func (api *recordApi) create(c echo.Context) error {
|
|||
|
||||
// load request
|
||||
if err := form.LoadData(c.Request()); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.RecordCreateEvent{
|
||||
|
@ -218,20 +218,24 @@ func (api *recordApi) create(c echo.Context) error {
|
|||
Record: record,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnRecordBeforeCreateRequest().Trigger(event, func(e *core.RecordCreateEvent) error {
|
||||
// create the record
|
||||
if err := form.Submit(); err != nil {
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnRecordBeforeCreateRequest().Trigger(event, func(e *core.RecordCreateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to create record.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.Record)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnRecordAfterCreateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *recordApi) update(c echo.Context) error {
|
||||
|
@ -276,7 +280,7 @@ func (api *recordApi) update(c echo.Context) error {
|
|||
|
||||
// load request
|
||||
if err := form.LoadData(c.Request()); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.RecordUpdateEvent{
|
||||
|
@ -284,20 +288,24 @@ func (api *recordApi) update(c echo.Context) error {
|
|||
Record: record,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnRecordBeforeUpdateRequest().Trigger(event, func(e *core.RecordUpdateEvent) error {
|
||||
// update the record
|
||||
if err := form.Submit(); err != nil {
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnRecordBeforeUpdateRequest().Trigger(event, func(e *core.RecordUpdateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to update record.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.Record)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnRecordAfterUpdateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *recordApi) delete(c echo.Context) error {
|
||||
|
|
|
@ -40,6 +40,8 @@ func (api *settingsApi) list(c echo.Context) error {
|
|||
|
||||
func (api *settingsApi) set(c echo.Context) error {
|
||||
form := forms.NewSettingsUpsert(api.app)
|
||||
|
||||
// load request
|
||||
if err := c.Bind(form); err != nil {
|
||||
return rest.NewBadRequestError("An error occurred while reading the submitted data.", err)
|
||||
}
|
||||
|
@ -50,8 +52,11 @@ func (api *settingsApi) set(c echo.Context) error {
|
|||
NewSettings: form.Settings,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnSettingsBeforeUpdateRequest().Trigger(event, func(e *core.SettingsUpdateEvent) error {
|
||||
if err := form.Submit(); err != nil {
|
||||
// update the settings
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnSettingsBeforeUpdateRequest().Trigger(event, func(e *core.SettingsUpdateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("An error occurred while submitting the form.", err)
|
||||
}
|
||||
|
||||
|
@ -62,10 +67,12 @@ func (api *settingsApi) set(c echo.Context) error {
|
|||
|
||||
return e.HttpContext.JSON(http.StatusOK, redactedSettings)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnSettingsAfterUpdateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
|
|
@ -139,9 +139,6 @@ func TestSettingsSet(t *testing.T) {
|
|||
`"emailAuth":{"minPasswordLength":{"code":"validation_min_greater_equal_than_required","message":"Must be no less than 5."}}`,
|
||||
`"meta":{"appName":{"code":"validation_required","message":"Cannot be blank."}}`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnSettingsBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "authorized as admin submitting valid data",
|
||||
|
|
28
apis/user.go
28
apis/user.go
|
@ -348,7 +348,7 @@ func (api *userApi) create(c echo.Context) error {
|
|||
|
||||
// load request
|
||||
if err := c.Bind(form); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.UserCreateEvent{
|
||||
|
@ -356,20 +356,24 @@ func (api *userApi) create(c echo.Context) error {
|
|||
User: user,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnUserBeforeCreateRequest().Trigger(event, func(e *core.UserCreateEvent) error {
|
||||
// create the user
|
||||
if err := form.Submit(); err != nil {
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnUserBeforeCreateRequest().Trigger(event, func(e *core.UserCreateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to create user.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.User)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnUserAfterCreateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *userApi) update(c echo.Context) error {
|
||||
|
@ -387,7 +391,7 @@ func (api *userApi) update(c echo.Context) error {
|
|||
|
||||
// load request
|
||||
if err := c.Bind(form); err != nil {
|
||||
return rest.NewBadRequestError("Failed to read the submitted data due to invalid formatting.", err)
|
||||
return rest.NewBadRequestError("Failed to load the submitted data due to invalid formatting.", err)
|
||||
}
|
||||
|
||||
event := &core.UserUpdateEvent{
|
||||
|
@ -395,20 +399,24 @@ func (api *userApi) update(c echo.Context) error {
|
|||
User: user,
|
||||
}
|
||||
|
||||
handlerErr := api.app.OnUserBeforeUpdateRequest().Trigger(event, func(e *core.UserUpdateEvent) error {
|
||||
// update the user
|
||||
if err := form.Submit(); err != nil {
|
||||
submitErr := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
return api.app.OnUserBeforeUpdateRequest().Trigger(event, func(e *core.UserUpdateEvent) error {
|
||||
if err := next(); err != nil {
|
||||
return rest.NewBadRequestError("Failed to update user.", err)
|
||||
}
|
||||
|
||||
return e.HttpContext.JSON(http.StatusOK, e.User)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if handlerErr == nil {
|
||||
if submitErr == nil {
|
||||
api.app.OnUserAfterUpdateRequest().Trigger(event)
|
||||
}
|
||||
|
||||
return handlerErr
|
||||
return submitErr
|
||||
}
|
||||
|
||||
func (api *userApi) delete(c echo.Context) error {
|
||||
|
|
|
@ -748,9 +748,6 @@ func TestUserCreate(t *testing.T) {
|
|||
`"email":{"code":"validation_required"`,
|
||||
`"password":{"code":"validation_required"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnUserBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "invalid data",
|
||||
|
@ -764,9 +761,6 @@ func TestUserCreate(t *testing.T) {
|
|||
`"password":{"code":"validation_length_out_of_range"`,
|
||||
`"passwordConfirm":{"code":"validation_values_mismatch"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnUserBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "valid data but with disabled email/pass auth",
|
||||
|
@ -868,9 +862,6 @@ func TestUserUpdate(t *testing.T) {
|
|||
`"data":{`,
|
||||
`"email":{"code":"validation_user_email_exists"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnUserBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "authorized as admin - valid data",
|
||||
|
|
|
@ -74,8 +74,11 @@ func (form *AdminUpsert) checkUniqueEmail(value any) error {
|
|||
return validation.NewError("validation_admin_email_exists", "Admin email already exists.")
|
||||
}
|
||||
|
||||
// Submit validates the form and upserts the form's admin model.
|
||||
func (form *AdminUpsert) Submit() error {
|
||||
// Submit validates the form and upserts the form admin model.
|
||||
//
|
||||
// You can optionally provide a list of InterceptorFunc to further
|
||||
// modify the form behavior before persisting it.
|
||||
func (form *AdminUpsert) Submit(interceptors ...InterceptorFunc) error {
|
||||
if err := form.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -87,5 +90,7 @@ func (form *AdminUpsert) Submit() error {
|
|||
form.admin.SetPassword(form.Password)
|
||||
}
|
||||
|
||||
return runInterceptors(func() error {
|
||||
return form.app.Dao().SaveAdmin(form.admin)
|
||||
}, interceptors...)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package forms_test
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||
|
@ -252,7 +253,14 @@ func TestAdminUpsertSubmit(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
err := form.Submit()
|
||||
interceptorCalls := 0
|
||||
|
||||
err := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorCalls++
|
||||
return next()
|
||||
}
|
||||
})
|
||||
|
||||
hasErr := err != nil
|
||||
if hasErr != s.expectError {
|
||||
|
@ -266,6 +274,14 @@ func TestAdminUpsertSubmit(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
expectInterceptorCall := 1
|
||||
if s.expectError {
|
||||
expectInterceptorCall = 0
|
||||
}
|
||||
if interceptorCalls != expectInterceptorCall {
|
||||
t.Errorf("(%d) Expected interceptor to be called %d, got %d", i, expectInterceptorCall, interceptorCalls)
|
||||
}
|
||||
|
||||
if s.expectError {
|
||||
continue // skip persistence check
|
||||
}
|
||||
|
@ -283,3 +299,51 @@ func TestAdminUpsertSubmit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminUpsertSubmitInterceptors(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
admin := &models.Admin{}
|
||||
form := forms.NewAdminUpsert(app, admin)
|
||||
form.Email = "test_new@example.com"
|
||||
form.Password = "1234567890"
|
||||
form.PasswordConfirm = form.Password
|
||||
|
||||
testErr := errors.New("test_error")
|
||||
interceptorAdminEmail := ""
|
||||
|
||||
interceptor1Called := false
|
||||
interceptor1 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptor1Called = true
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
interceptor2Called := false
|
||||
interceptor2 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorAdminEmail = admin.Email // to check if the record was filled
|
||||
interceptor2Called = true
|
||||
return testErr
|
||||
}
|
||||
}
|
||||
|
||||
err := form.Submit(interceptor1, interceptor2)
|
||||
if err != testErr {
|
||||
t.Fatalf("Expected error %v, got %v", testErr, err)
|
||||
}
|
||||
|
||||
if !interceptor1Called {
|
||||
t.Fatalf("Expected interceptor1 to be called")
|
||||
}
|
||||
|
||||
if !interceptor2Called {
|
||||
t.Fatalf("Expected interceptor2 to be called")
|
||||
}
|
||||
|
||||
if interceptorAdminEmail != form.Email {
|
||||
t.Fatalf("Expected the form model to be filled before calling the interceptors")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Package models implements various services used for request data
|
||||
// validation and applying changes to existing DB models through the app Dao.
|
||||
package forms
|
||||
|
||||
// InterceptorNextFunc is a interceptor handler function.
|
||||
// Usually used in combination with InterceptorFunc.
|
||||
type InterceptorNextFunc = func() error
|
||||
|
||||
// InterceptorFunc defines a single interceptor function that will execute the provided next func handler.
|
||||
type InterceptorFunc func(next InterceptorNextFunc) InterceptorNextFunc
|
||||
|
||||
// runInterceptors executes the provided list of interceptors.
|
||||
func runInterceptors(next InterceptorNextFunc, interceptors ...InterceptorFunc) error {
|
||||
for i := len(interceptors) - 1; i >= 0; i-- {
|
||||
next = interceptors[i](next)
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
|
@ -189,7 +189,10 @@ func (form *CollectionUpsert) checkRule(value any) error {
|
|||
// Submit validates the form and upserts the form's Collection model.
|
||||
//
|
||||
// On success the related record table schema will be auto updated.
|
||||
func (form *CollectionUpsert) Submit() error {
|
||||
//
|
||||
// You can optionally provide a list of InterceptorFunc to further
|
||||
// modify the form behavior before persisting it.
|
||||
func (form *CollectionUpsert) Submit(interceptors ...InterceptorFunc) error {
|
||||
if err := form.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -211,5 +214,7 @@ func (form *CollectionUpsert) Submit() error {
|
|||
form.collection.UpdateRule = form.UpdateRule
|
||||
form.collection.DeleteRule = form.DeleteRule
|
||||
|
||||
return runInterceptors(func() error {
|
||||
return form.app.Dao().SaveCollection(form.collection)
|
||||
}, interceptors...)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package forms_test
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||
|
@ -387,14 +388,31 @@ func TestCollectionUpsertSubmit(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
interceptorCalls := 0
|
||||
interceptor := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorCalls++
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
// parse errors
|
||||
result := form.Submit()
|
||||
result := form.Submit(interceptor)
|
||||
errs, ok := result.(validation.Errors)
|
||||
if !ok && result != nil {
|
||||
t.Errorf("(%d) Failed to parse errors %v", i, result)
|
||||
continue
|
||||
}
|
||||
|
||||
// check interceptor calls
|
||||
expectInterceptorCall := 1
|
||||
if len(s.expectedErrors) > 0 {
|
||||
expectInterceptorCall = 0
|
||||
}
|
||||
if interceptorCalls != expectInterceptorCall {
|
||||
t.Errorf("(%d) Expected interceptor to be called %d, got %d", i, expectInterceptorCall, interceptorCalls)
|
||||
}
|
||||
|
||||
// check errors
|
||||
if len(errs) > len(s.expectedErrors) {
|
||||
t.Errorf("(%d) Expected error keys %v, got %v", i, s.expectedErrors, errs)
|
||||
|
@ -450,3 +468,53 @@ func TestCollectionUpsertSubmit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectionUpsertSubmitInterceptors(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
collection, err := app.Dao().FindCollectionByNameOrId("demo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
form := forms.NewCollectionUpsert(app, collection)
|
||||
form.Name = "test_new"
|
||||
|
||||
testErr := errors.New("test_error")
|
||||
interceptorCollectionName := ""
|
||||
|
||||
interceptor1Called := false
|
||||
interceptor1 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptor1Called = true
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
interceptor2Called := false
|
||||
interceptor2 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorCollectionName = collection.Name // to check if the record was filled
|
||||
interceptor2Called = true
|
||||
return testErr
|
||||
}
|
||||
}
|
||||
|
||||
submitErr := form.Submit(interceptor1, interceptor2)
|
||||
if submitErr != testErr {
|
||||
t.Fatalf("Expected submitError %v, got %v", testErr, submitErr)
|
||||
}
|
||||
|
||||
if !interceptor1Called {
|
||||
t.Fatalf("Expected interceptor1 to be called")
|
||||
}
|
||||
|
||||
if !interceptor2Called {
|
||||
t.Fatalf("Expected interceptor2 to be called")
|
||||
}
|
||||
|
||||
if interceptorCollectionName != form.Name {
|
||||
t.Fatalf("Expected the form model to be filled before calling the interceptors")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,7 +271,10 @@ func (form *RecordUpsert) DrySubmit(callback func(txDao *daos.Dao) error) error
|
|||
}
|
||||
|
||||
// Submit validates the form and upserts the form Record model.
|
||||
func (form *RecordUpsert) Submit() error {
|
||||
//
|
||||
// You can optionally provide a list of InterceptorFunc to further
|
||||
// modify the form behavior before persisting it.
|
||||
func (form *RecordUpsert) Submit(interceptors ...InterceptorFunc) error {
|
||||
if err := form.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -281,6 +284,7 @@ func (form *RecordUpsert) Submit() error {
|
|||
return err
|
||||
}
|
||||
|
||||
return runInterceptors(func() error {
|
||||
return form.app.Dao().RunInTransaction(func(txDao *daos.Dao) error {
|
||||
// persist record model
|
||||
if err := txDao.SaveRecord(form.record); err != nil {
|
||||
|
@ -300,6 +304,7 @@ func (form *RecordUpsert) Submit() error {
|
|||
|
||||
return nil
|
||||
})
|
||||
}, interceptors...)
|
||||
}
|
||||
|
||||
func (form *RecordUpsert) processFilesToUpload() error {
|
||||
|
|
|
@ -3,6 +3,7 @@ package forms_test
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
|
@ -400,13 +401,27 @@ func TestRecordUpsertSubmitFailure(t *testing.T) {
|
|||
req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
|
||||
form.LoadData(req)
|
||||
|
||||
interceptorCalls := 0
|
||||
interceptor := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorCalls++
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that validate is triggered
|
||||
// ---
|
||||
result := form.Submit()
|
||||
result := form.Submit(interceptor)
|
||||
if result == nil {
|
||||
t.Fatal("Expected error, got nil")
|
||||
}
|
||||
|
||||
// check interceptor calls
|
||||
// ---
|
||||
if interceptorCalls != 0 {
|
||||
t.Fatalf("Expected interceptor to be called 0 times, got %d", interceptorCalls)
|
||||
}
|
||||
|
||||
// ensure that the record changes weren't persisted
|
||||
// ---
|
||||
recordAfter, err := app.Dao().FindFirstRecordByData(collection, "id", recordBefore.Id)
|
||||
|
@ -451,11 +466,25 @@ func TestRecordUpsertSubmitSuccess(t *testing.T) {
|
|||
req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
|
||||
form.LoadData(req)
|
||||
|
||||
result := form.Submit()
|
||||
interceptorCalls := 0
|
||||
interceptor := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorCalls++
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
result := form.Submit(interceptor)
|
||||
if result != nil {
|
||||
t.Fatalf("Expected nil, got error %v", result)
|
||||
}
|
||||
|
||||
// check interceptor calls
|
||||
// ---
|
||||
if interceptorCalls != 1 {
|
||||
t.Fatalf("Expected interceptor to be called 1 time, got %d", interceptorCalls)
|
||||
}
|
||||
|
||||
// ensure that the record changes were persisted
|
||||
// ---
|
||||
recordAfter, err := app.Dao().FindFirstRecordByData(collection, "id", recordBefore.Id)
|
||||
|
@ -482,6 +511,57 @@ func TestRecordUpsertSubmitSuccess(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRecordUpsertSubmitInterceptors(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
|
||||
record, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
form := forms.NewRecordUpsert(app, record)
|
||||
form.Data["title"] = "test_new"
|
||||
|
||||
testErr := errors.New("test_error")
|
||||
interceptorRecordTitle := ""
|
||||
|
||||
interceptor1Called := false
|
||||
interceptor1 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptor1Called = true
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
interceptor2Called := false
|
||||
interceptor2 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorRecordTitle = record.GetStringDataValue("title") // to check if the record was filled
|
||||
interceptor2Called = true
|
||||
return testErr
|
||||
}
|
||||
}
|
||||
|
||||
submitErr := form.Submit(interceptor1, interceptor2)
|
||||
if submitErr != testErr {
|
||||
t.Fatalf("Expected submitError %v, got %v", testErr, submitErr)
|
||||
}
|
||||
|
||||
if !interceptor1Called {
|
||||
t.Fatalf("Expected interceptor1 to be called")
|
||||
}
|
||||
|
||||
if !interceptor2Called {
|
||||
t.Fatalf("Expected interceptor2 to be called")
|
||||
}
|
||||
|
||||
if interceptorRecordTitle != form.Data["title"].(string) {
|
||||
t.Fatalf("Expected the form model to be filled before calling the interceptors")
|
||||
}
|
||||
}
|
||||
|
||||
func hasRecordFile(app core.App, record *models.Record, filename string) bool {
|
||||
fs, _ := app.NewFilesystem()
|
||||
defer fs.Close()
|
||||
|
|
|
@ -33,13 +33,17 @@ func (form *SettingsUpsert) Validate() error {
|
|||
// Submit validates the form and upserts the loaded settings.
|
||||
//
|
||||
// On success the app settings will be refreshed with the form ones.
|
||||
func (form *SettingsUpsert) Submit() error {
|
||||
//
|
||||
// You can optionally provide a list of InterceptorFunc to further
|
||||
// modify the form behavior before persisting it.
|
||||
func (form *SettingsUpsert) Submit(interceptors ...InterceptorFunc) error {
|
||||
if err := form.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encryptionKey := os.Getenv(form.app.EncryptionEnv())
|
||||
|
||||
return runInterceptors(func() error {
|
||||
saveErr := form.app.Dao().SaveParam(
|
||||
models.ParamAppSettings,
|
||||
form.Settings,
|
||||
|
@ -56,4 +60,5 @@ func (form *SettingsUpsert) Submit() error {
|
|||
|
||||
// merge the application settings with the form ones
|
||||
return form.app.Settings().Merge(form.Settings)
|
||||
}, interceptors...)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package forms_test
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
|
@ -98,14 +99,31 @@ func TestSettingsUpsertSubmit(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
interceptorCalls := 0
|
||||
interceptor := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorCalls++
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
// parse errors
|
||||
result := form.Submit()
|
||||
result := form.Submit(interceptor)
|
||||
errs, ok := result.(validation.Errors)
|
||||
if !ok && result != nil {
|
||||
t.Errorf("(%d) Failed to parse errors %v", i, result)
|
||||
continue
|
||||
}
|
||||
|
||||
// check interceptor calls
|
||||
expectInterceptorCall := 1
|
||||
if len(s.expectedErrors) > 0 {
|
||||
expectInterceptorCall = 0
|
||||
}
|
||||
if interceptorCalls != expectInterceptorCall {
|
||||
t.Errorf("(%d) Expected interceptor to be called %d, got %d", i, expectInterceptorCall, interceptorCalls)
|
||||
}
|
||||
|
||||
// check errors
|
||||
if len(errs) > len(s.expectedErrors) {
|
||||
t.Errorf("(%d) Expected error keys %v, got %v", i, s.expectedErrors, errs)
|
||||
|
@ -128,3 +146,42 @@ func TestSettingsUpsertSubmit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingsUpsertSubmitInterceptors(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
form := forms.NewSettingsUpsert(app)
|
||||
form.Meta.AppName = "test_new"
|
||||
|
||||
testErr := errors.New("test_error")
|
||||
|
||||
interceptor1Called := false
|
||||
interceptor1 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptor1Called = true
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
interceptor2Called := false
|
||||
interceptor2 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptor2Called = true
|
||||
return testErr
|
||||
}
|
||||
}
|
||||
|
||||
submitErr := form.Submit(interceptor1, interceptor2)
|
||||
if submitErr != testErr {
|
||||
t.Fatalf("Expected submitError %v, got %v", testErr, submitErr)
|
||||
}
|
||||
|
||||
if !interceptor1Called {
|
||||
t.Fatalf("Expected interceptor1 to be called")
|
||||
}
|
||||
|
||||
if !interceptor2Called {
|
||||
t.Fatalf("Expected interceptor2 to be called")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,10 @@ func (form *UserUpsert) checkEmailDomain(value any) error {
|
|||
}
|
||||
|
||||
// Submit validates the form and upserts the form user model.
|
||||
func (form *UserUpsert) Submit() error {
|
||||
//
|
||||
// You can optionally provide a list of InterceptorFunc to further
|
||||
// modify the form behavior before persisting it.
|
||||
func (form *UserUpsert) Submit(interceptors ...InterceptorFunc) error {
|
||||
if err := form.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -114,5 +117,7 @@ func (form *UserUpsert) Submit() error {
|
|||
|
||||
form.user.Email = form.Email
|
||||
|
||||
return runInterceptors(func() error {
|
||||
return form.app.Dao().SaveUser(form.user)
|
||||
}, interceptors...)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package forms_test
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||
|
@ -212,13 +213,28 @@ func TestUserUpsertSubmit(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
err := form.Submit()
|
||||
interceptorCalls := 0
|
||||
|
||||
err := form.Submit(func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorCalls++
|
||||
return next()
|
||||
}
|
||||
})
|
||||
|
||||
hasErr := err != nil
|
||||
if hasErr != s.expectError {
|
||||
t.Errorf("(%d) Expected hasErr to be %v, got %v (%v)", i, s.expectError, hasErr, err)
|
||||
}
|
||||
|
||||
expectInterceptorCall := 1
|
||||
if s.expectError {
|
||||
expectInterceptorCall = 0
|
||||
}
|
||||
if interceptorCalls != expectInterceptorCall {
|
||||
t.Errorf("(%d) Expected interceptor to be called %d, got %d", i, expectInterceptorCall, interceptorCalls)
|
||||
}
|
||||
|
||||
if s.expectError {
|
||||
continue
|
||||
}
|
||||
|
@ -240,3 +256,51 @@ func TestUserUpsertSubmit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserUpsertSubmitInterceptors(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
user := &models.User{}
|
||||
form := forms.NewUserUpsert(app, user)
|
||||
form.Email = "test_new@example.com"
|
||||
form.Password = "1234567890"
|
||||
form.PasswordConfirm = form.Password
|
||||
|
||||
testErr := errors.New("test_error")
|
||||
interceptorUserEmail := ""
|
||||
|
||||
interceptor1Called := false
|
||||
interceptor1 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptor1Called = true
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
interceptor2Called := false
|
||||
interceptor2 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
|
||||
return func() error {
|
||||
interceptorUserEmail = user.Email // to check if the record was filled
|
||||
interceptor2Called = true
|
||||
return testErr
|
||||
}
|
||||
}
|
||||
|
||||
err := form.Submit(interceptor1, interceptor2)
|
||||
if err != testErr {
|
||||
t.Fatalf("Expected error %v, got %v", testErr, err)
|
||||
}
|
||||
|
||||
if !interceptor1Called {
|
||||
t.Fatalf("Expected interceptor1 to be called")
|
||||
}
|
||||
|
||||
if !interceptor2Called {
|
||||
t.Fatalf("Expected interceptor2 to be called")
|
||||
}
|
||||
|
||||
if interceptorUserEmail != form.Email {
|
||||
t.Fatalf("Expected the form model to be filled before calling the interceptors")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue