From 0fa5edb0b1c2a3ce88c2b491d31fcee469fd5dc1 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Wed, 30 Nov 2022 17:23:00 +0200 Subject: [PATCH] added custom goja field mapper to handle all caps identifiers and allowed errors unwrapping --- CHANGELOG.md | 2 ++ apis/record_auth.go | 2 +- apis/record_crud.go | 2 +- apis/record_helpers.go | 2 +- daos/record.go | 2 +- forms/record_upsert.go | 4 ++-- plugins/jsvm/vm.go | 40 ++++++++++++++++++++++++++++++- plugins/migratecmd/automigrate.go | 6 ++--- plugins/migratecmd/templates.go | 12 +++++----- 9 files changed, 56 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf84f794..11839c3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,8 @@ - Fixed concurrent multi-relation cascade update/delete ([#1138](https://github.com/pocketbase/pocketbase/issues/1138)). +- Added the raw OAuth2 user data (`meta.rawUser`) and OAuth2 access token (`meta.accessToken`) to the auth response ([#654](https://github.com/pocketbase/pocketbase/discussions/654)). + ## v0.8.0 diff --git a/apis/record_auth.go b/apis/record_auth.go index 3f48ead2..d4c7574c 100644 --- a/apis/record_auth.go +++ b/apis/record_auth.go @@ -231,7 +231,7 @@ func (api *recordAuthApi) authWithOAuth2(c echo.Context) error { } if _, err := txDao.FindRecordById(collection.Id, createForm.Id, createRuleFunc); err != nil { - return fmt.Errorf("Failed create rule constraint: %v", err) + return fmt.Errorf("Failed create rule constraint: %w", err) } return nil diff --git a/apis/record_crud.go b/apis/record_crud.go index 42585ac2..5d25f8f7 100644 --- a/apis/record_crud.go +++ b/apis/record_crud.go @@ -191,7 +191,7 @@ func (api *recordApi) create(c echo.Context) error { testErr := testForm.DrySubmit(func(txDao *daos.Dao) error { foundRecord, err := txDao.FindRecordById(collection.Id, testRecord.Id, createRuleFunc) if err != nil { - return fmt.Errorf("DrySubmit create rule failure: %v", err) + return fmt.Errorf("DrySubmit create rule failure: %w", err) } hasFullManageAccess = hasAuthManageAccess(txDao, foundRecord, requestData) return nil diff --git a/apis/record_helpers.go b/apis/record_helpers.go index e42f69be..35d68d24 100644 --- a/apis/record_helpers.go +++ b/apis/record_helpers.go @@ -62,7 +62,7 @@ func EnrichRecords(c echo.Context, dao *daos.Dao, records []*models.Record, defa requestData := RequestData(c) if err := autoIgnoreAuthRecordsEmailVisibility(dao, records, requestData); err != nil { - return fmt.Errorf("Failed to resolve email visibility: %v", err) + return fmt.Errorf("Failed to resolve email visibility: %w", err) } expands := defaultExpands diff --git a/daos/record.go b/daos/record.go index 29c9221e..a8275b7a 100644 --- a/daos/record.go +++ b/daos/record.go @@ -324,7 +324,7 @@ func (dao *Dao) SaveRecord(record *models.Record) error { // This is to make sure that the filter `@request.auth.id` always returns a unique id. authCollections, err := dao.FindCollectionsByType(models.CollectionTypeAuth) if err != nil { - return fmt.Errorf("Unable to fetch the auth collections for cross-id unique check: %v", err) + return fmt.Errorf("Unable to fetch the auth collections for cross-id unique check: %w", err) } for _, collection := range authCollections { if record.Collection().Id == collection.Id { diff --git a/forms/record_upsert.go b/forms/record_upsert.go index 4c95f659..006e6ad4 100644 --- a/forms/record_upsert.go +++ b/forms/record_upsert.go @@ -651,12 +651,12 @@ func (form *RecordUpsert) Submit(interceptors ...InterceptorFunc) error { return form.dao.RunInTransaction(func(txDao *daos.Dao) error { // persist record model if err := txDao.SaveRecord(form.record); err != nil { - return fmt.Errorf("Failed to save the record: %v", err) + return fmt.Errorf("Failed to save the record: %w", err) } // upload new files (if any) if err := form.processFilesToUpload(); err != nil { - return fmt.Errorf("Failed to process the upload files: %v", err) + return fmt.Errorf("Failed to process the upload files: %w", err) } // delete old files (if any) diff --git a/plugins/jsvm/vm.go b/plugins/jsvm/vm.go index 915a7428..e945fa6b 100644 --- a/plugins/jsvm/vm.go +++ b/plugins/jsvm/vm.go @@ -2,6 +2,9 @@ package jsvm import ( "encoding/json" + "reflect" + "strings" + "unicode" "github.com/dop251/goja" "github.com/pocketbase/dbx" @@ -14,7 +17,7 @@ import ( func NewBaseVM(app core.App) *goja.Runtime { vm := goja.New() - vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) + vm.SetFieldNameMapper(fieldMapper{}) vm.Set("$app", app) baseBind(vm) @@ -137,3 +140,38 @@ func apisBind(vm *goja.Runtime) { obj.Set("enrichRecord", apis.EnrichRecord) obj.Set("enrichRecords", apis.EnrichRecords) } + +// fieldMapper provides custom mapping between Go and JavaScript property names. +// +// It is similar to the builtin "uncapFieldNameMapper" but also converts +// all uppercase identifiers to their lowercase equivalent (eg. "GET" -> "get"). +type fieldMapper struct { +} + +// FieldName implements the [FieldNameMapper.FieldName] interface method. +func (u fieldMapper) FieldName(_ reflect.Type, f reflect.StructField) string { + return convertGoToJSName(f.Name) +} + +// MethodName implements the [FieldNameMapper.MethodName] interface method. +func (u fieldMapper) MethodName(_ reflect.Type, m reflect.Method) string { + return convertGoToJSName(m.Name) +} + +func convertGoToJSName(name string) string { + allUppercase := true + for _, c := range name { + if !unicode.IsUpper(c) { + allUppercase = false + break + } + } + + // eg. "JSON" -> "json" + if allUppercase { + return strings.ToLower(name) + } + + // eg. "GetField" -> "getField" + return strings.ToLower(name[0:1]) + name[1:] +} diff --git a/plugins/migratecmd/automigrate.go b/plugins/migratecmd/automigrate.go index a31ef3f2..f6ba5f5f 100644 --- a/plugins/migratecmd/automigrate.go +++ b/plugins/migratecmd/automigrate.go @@ -43,7 +43,7 @@ func (p *plugin) afterCollectionChange() func(*core.ModelEvent) error { template, templateErr = p.goDiffTemplate(new, old) } if templateErr != nil { - return fmt.Errorf("failed to resolve template: %v", templateErr) + return fmt.Errorf("failed to resolve template: %w", templateErr) } var action string @@ -61,11 +61,11 @@ func (p *plugin) afterCollectionChange() func(*core.ModelEvent) error { // ensure that the local migrations dir exist if err := os.MkdirAll(p.options.Dir, os.ModePerm); err != nil { - return fmt.Errorf("failed to create migration dir: %v", err) + return fmt.Errorf("failed to create migration dir: %w", err) } if err := os.WriteFile(fileDest, []byte(template), 0644); err != nil { - return fmt.Errorf("failed to save automigrate file: %v", err) + return fmt.Errorf("failed to save automigrate file: %w", err) } p.refreshCachedCollections() diff --git a/plugins/migratecmd/templates.go b/plugins/migratecmd/templates.go index 7665bf16..dfeb425a 100644 --- a/plugins/migratecmd/templates.go +++ b/plugins/migratecmd/templates.go @@ -35,7 +35,7 @@ func (p *plugin) jsBlankTemplate() (string, error) { func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, error) { jsonData, err := marhshalWithoutEscape(collections, " ", " ") if err != nil { - return "", fmt.Errorf("failed to serialize collections list: %v", err) + return "", fmt.Errorf("failed to serialize collections list: %w", err) } const template = `migrate((db) => { @@ -55,7 +55,7 @@ func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, e func (p *plugin) jsCreateTemplate(collection *models.Collection) (string, error) { jsonData, err := marhshalWithoutEscape(collection, " ", " ") if err != nil { - return "", fmt.Errorf("failed to serialize collections list: %v", err) + return "", fmt.Errorf("failed to serialize collections list: %w", err) } const template = `migrate((db) => { @@ -76,7 +76,7 @@ func (p *plugin) jsCreateTemplate(collection *models.Collection) (string, error) func (p *plugin) jsDeleteTemplate(collection *models.Collection) (string, error) { jsonData, err := marhshalWithoutEscape(collection, " ", " ") if err != nil { - return "", fmt.Errorf("failed to serialize collections list: %v", err) + return "", fmt.Errorf("failed to serialize collections list: %w", err) } const template = `migrate((db) => { @@ -329,7 +329,7 @@ func init() { func (p *plugin) goSnapshotTemplate(collections []*models.Collection) (string, error) { jsonData, err := marhshalWithoutEscape(collections, "\t\t", "\t") if err != nil { - return "", fmt.Errorf("failed to serialize collections list: %v", err) + return "", fmt.Errorf("failed to serialize collections list: %w", err) } const template = `package %s @@ -368,7 +368,7 @@ func init() { func (p *plugin) goCreateTemplate(collection *models.Collection) (string, error) { jsonData, err := marhshalWithoutEscape(collection, "\t\t", "\t") if err != nil { - return "", fmt.Errorf("failed to serialize collections list: %v", err) + return "", fmt.Errorf("failed to serialize collections list: %w", err) } const template = `package %s @@ -416,7 +416,7 @@ func init() { func (p *plugin) goDeleteTemplate(collection *models.Collection) (string, error) { jsonData, err := marhshalWithoutEscape(collection, "\t\t", "\t") if err != nil { - return "", fmt.Errorf("failed to serialize collections list: %v", err) + return "", fmt.Errorf("failed to serialize collections list: %w", err) } const template = `package %s