restore crc32 checksum for the colelction and field ids

This commit is contained in:
Gani Georgiev 2024-11-04 10:51:32 +02:00
parent 83d91b3dd5
commit 8d0e4a0460
3 changed files with 81 additions and 36 deletions

View File

@ -3,8 +3,10 @@ package core
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv"
"strings" "strings"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/tools/dbutils" "github.com/pocketbase/pocketbase/tools/dbutils"
"github.com/pocketbase/pocketbase/tools/hook" "github.com/pocketbase/pocketbase/tools/hook"
"github.com/pocketbase/pocketbase/tools/security" "github.com/pocketbase/pocketbase/tools/security"
@ -309,6 +311,7 @@ type baseCollection struct {
BaseModel BaseModel
disableIntegrityChecks bool disableIntegrityChecks bool
autogeneratedId string
ListRule *string `db:"listRule" json:"listRule" form:"listRule"` ListRule *string `db:"listRule" json:"listRule" form:"listRule"`
ViewRule *string `db:"viewRule" json:"viewRule" form:"viewRule"` ViewRule *string `db:"viewRule" json:"viewRule" form:"viewRule"`
@ -364,6 +367,7 @@ func NewBaseCollection(name string, optId ...string) *Collection {
m.Name = name m.Name = name
m.Type = CollectionTypeBase m.Type = CollectionTypeBase
// @todo consider removing once inferred composite literals are supported
if len(optId) > 0 { if len(optId) > 0 {
m.Id = optId[0] m.Id = optId[0]
} }
@ -383,6 +387,7 @@ func NewViewCollection(name string, optId ...string) *Collection {
m.Name = name m.Name = name
m.Type = CollectionTypeView m.Type = CollectionTypeView
// @todo consider removing once inferred composite literals are supported
if len(optId) > 0 { if len(optId) > 0 {
m.Id = optId[0] m.Id = optId[0]
} }
@ -402,6 +407,7 @@ func NewAuthCollection(name string, optId ...string) *Collection {
m.Name = name m.Name = name
m.Type = CollectionTypeAuth m.Type = CollectionTypeAuth
// @todo consider removing once inferred composite literals are supported
if len(optId) > 0 { if len(optId) > 0 {
m.Id = optId[0] m.Id = optId[0]
} }
@ -689,49 +695,82 @@ func onCollectionDeleteExecute(e *CollectionEvent) error {
// save hook // save hook
// ------------------------------------------------------------------- // -------------------------------------------------------------------
func (c *Collection) initDefaultId() { func (c *Collection) idChecksum() string {
if c.Id != "" { return "pbc_" + crc32Checksum(c.Type+c.Name)
return // already set }
}
if c.System && c.Name != "" { func (c *Collection) initDefaultId() {
// for system collections we use crc32 checksum for consistency because they cannot be renamed if c.Id == "" {
c.Id = "pbc_" + crc32Checksum(c.Name) c.Id = c.idChecksum()
} else { c.autogeneratedId = c.Id
c.Id = "pbc_" + security.RandomStringWithAlphabet(11, DefaultIdAlphabet)
} }
} }
func (c *Collection) savePrepare() error { func (c *Collection) updateGeneratedIdIfExists(app App) {
if c.Type == "" { if !c.IsNew() ||
c.Type = CollectionTypeBase // the id was explicitly cleared
c.Id == "" ||
// the id was manually set
c.Id != c.autogeneratedId {
return
} }
if c.IsNew() { // generate an up-to-date checksum
c.initDefaultId() newId := c.idChecksum()
c.Created = types.NowDateTime()
// add a number to the current id (if already exists)
for i := 2; i < 1000; i++ {
var exists bool
_ = app.CollectionQuery().Select("(1)").AndWhere(dbx.HashExp{"id": newId}).Limit(1).Row(&exists)
if !exists {
break
}
newId = c.idChecksum() + strconv.Itoa(i)
} }
c.Updated = types.NowDateTime() // no change
if c.Id == newId {
// recreate the fields list to ensure that all normalizations return
// like default field id are applied
c.Fields = NewFieldsList(c.Fields...)
c.initDefaultFields()
if c.IsAuth() {
c.unsetMissingOAuth2MappedFields()
} }
return nil // replace the old id in the index names (if any)
for i, idx := range c.Indexes {
parsed := dbutils.ParseIndex(idx)
original := parsed.IndexName
parsed.IndexName = strings.ReplaceAll(parsed.IndexName, c.Id, newId)
if parsed.IndexName != original {
c.Indexes[i] = parsed.Build()
}
}
// update model id
c.Id = newId
} }
func onCollectionSave(e *CollectionEvent) error { func onCollectionSave(e *CollectionEvent) error {
if err := e.Collection.savePrepare(); err != nil { if e.Collection.Type == "" {
return err e.Collection.Type = CollectionTypeBase
} }
if e.Collection.IsNew() {
e.Collection.initDefaultId()
e.Collection.Created = types.NowDateTime()
}
e.Collection.Updated = types.NowDateTime()
// recreate the fields list to ensure that all normalizations
// like default field id are applied
e.Collection.Fields = NewFieldsList(e.Collection.Fields...)
e.Collection.initDefaultFields()
if e.Collection.IsAuth() {
e.Collection.unsetMissingOAuth2MappedFields()
}
e.Collection.updateGeneratedIdIfExists(e.App)
return e.Next() return e.Next()
} }

View File

@ -65,6 +65,10 @@ type optionsValidator interface {
} }
func (validator *collectionValidator) run() error { func (validator *collectionValidator) run() error {
if validator.original.IsNew() {
validator.new.updateGeneratedIdIfExists(validator.app)
}
// generate fields from the query (overwriting any explicit user defined fields) // generate fields from the query (overwriting any explicit user defined fields)
if validator.new.IsView() { if validator.new.IsView() {
validator.new.Fields, _ = validator.app.CreateViewFields(validator.new.ViewQuery) validator.new.Fields, _ = validator.app.CreateViewFields(validator.new.ViewQuery)

View File

@ -4,8 +4,7 @@ import (
"database/sql/driver" "database/sql/driver"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv"
"github.com/pocketbase/pocketbase/tools/security"
) )
// NewFieldsList creates a new FieldsList instance with the provided fields. // NewFieldsList creates a new FieldsList instance with the provided fields.
@ -171,12 +170,16 @@ func (l *FieldsList) add(newField Field) {
// set default id // set default id
if newFieldId == "" { if newFieldId == "" {
replaceByName = true replaceByName = true
if newField.GetSystem() && newField.GetName() != "" {
// for system fields we use crc32 checksum for consistency because they cannot be renamed baseId := newField.Type() + crc32Checksum(newField.GetName())
newFieldId = newField.Type() + crc32Checksum(newField.GetName()) newFieldId = baseId
} else { for i := 2; i < 1000; i++ {
newFieldId = newField.Type() + security.RandomString(7) if l.GetById(newFieldId) == nil {
break // already unique
} }
newFieldId = baseId + strconv.Itoa(i)
}
newField.SetId(newFieldId)
} }
// replace existing // replace existing
@ -196,7 +199,6 @@ func (l *FieldsList) add(newField Field) {
} }
// add new field // add new field
newField.SetId(newFieldId)
*l = append(fields, newField) *l = append(fields, newField)
} }