Register CPA group if it hasn't been initialized

This commit is contained in:
David Krauser 2026-02-03 10:33:54 -05:00
parent 59df5ecbc5
commit b734d73d1c
2 changed files with 75 additions and 25 deletions

View file

@ -21,14 +21,18 @@ const (
var cpaGroupID string
func (a *App) CpaGroupID() (string, error) {
return getCpaGroupID(a.Srv().propertyAccessService)
}
// ToDo: we should explore moving this to the database cache layer
// instead of maintaining the ID cached at the application level
func (a *App) CpaGroupID() (string, error) {
func getCpaGroupID(service *PropertyAccessService) (string, error) {
if cpaGroupID != "" {
return cpaGroupID, nil
}
cpaGroup, err := a.Srv().propertyAccessService.RegisterPropertyGroup(model.CustomProfileAttributesPropertyGroupName)
cpaGroup, err := service.RegisterPropertyGroup(model.CustomProfileAttributesPropertyGroupName)
if err != nil {
return "", errors.Wrap(err, "cannot register Custom Profile Attributes property group")
}

View file

@ -68,7 +68,9 @@ func (pas *PropertyAccessService) GetPropertyGroup(name string) (*model.Property
// CreatePropertyField creates a new property field.
// This method rejects any attempt to set source_plugin_id - only plugins can set this via CreatePropertyFieldForPlugin.
func (pas *PropertyAccessService) CreatePropertyField(callerID string, field *model.PropertyField) (*model.PropertyField, error) {
if !groupHasAccessRestrictions(field.GroupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(field.GroupID); err != nil {
return nil, fmt.Errorf("CreatePropertyField: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.CreatePropertyField(field)
}
@ -98,7 +100,9 @@ func (pas *PropertyAccessService) CreatePropertyField(callerID string, field *mo
// This method automatically sets the source_plugin_id to the provided pluginID.
// Only use this method when creating fields through the Plugin API.
func (pas *PropertyAccessService) CreatePropertyFieldForPlugin(pluginID string, field *model.PropertyField) (*model.PropertyField, error) {
if !groupHasAccessRestrictions(field.GroupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(field.GroupID); err != nil {
return nil, fmt.Errorf("CreatePropertyFieldForPlugin: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.CreatePropertyField(field)
}
@ -129,7 +133,9 @@ func (pas *PropertyAccessService) CreatePropertyFieldForPlugin(pluginID string,
// GetPropertyField retrieves a property field by group and field ID.
// Field details are filtered based on the caller's access permissions.
func (pas *PropertyAccessService) GetPropertyField(callerID string, groupID, id string) (*model.PropertyField, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("GetPropertyField: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.GetPropertyField(groupID, id)
}
@ -144,7 +150,9 @@ func (pas *PropertyAccessService) GetPropertyField(callerID string, groupID, id
// GetPropertyFields retrieves multiple property fields by their IDs.
// Field details are filtered based on the caller's access permissions.
func (pas *PropertyAccessService) GetPropertyFields(callerID string, groupID string, ids []string) ([]*model.PropertyField, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("GetPropertyFields: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.GetPropertyFields(groupID, ids)
}
@ -159,7 +167,9 @@ func (pas *PropertyAccessService) GetPropertyFields(callerID string, groupID str
// GetPropertyFieldByName retrieves a property field by name.
// Field details are filtered based on the caller's access permissions.
func (pas *PropertyAccessService) GetPropertyFieldByName(callerID string, groupID, targetID, name string) (*model.PropertyField, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("GetPropertyFieldByName: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.GetPropertyFieldByName(groupID, targetID, name)
}
@ -194,7 +204,9 @@ func (pas *PropertyAccessService) CountAllPropertyFieldsForTarget(groupID, targe
// SearchPropertyFields searches for property fields based on the given options.
// Field details are filtered based on the caller's access permissions.
func (pas *PropertyAccessService) SearchPropertyFields(callerID string, groupID string, opts model.PropertyFieldSearchOpts) ([]*model.PropertyField, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("SearchPropertyFields: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.SearchPropertyFields(groupID, opts)
}
@ -209,7 +221,9 @@ func (pas *PropertyAccessService) SearchPropertyFields(callerID string, groupID
// UpdatePropertyField updates a property field.
// Checks write access and ensures source_plugin_id is not changed.
func (pas *PropertyAccessService) UpdatePropertyField(callerID string, groupID string, field *model.PropertyField) (*model.PropertyField, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("UpdatePropertyField: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.UpdatePropertyField(groupID, field)
}
@ -244,7 +258,9 @@ func (pas *PropertyAccessService) UpdatePropertyField(callerID string, groupID s
// UpdatePropertyFields updates multiple property fields.
// Checks write access for all fields atomically before updating any.
func (pas *PropertyAccessService) UpdatePropertyFields(callerID string, groupID string, fields []*model.PropertyField) ([]*model.PropertyField, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("UpdatePropertyFields: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.UpdatePropertyFields(groupID, fields)
}
@ -304,7 +320,9 @@ func (pas *PropertyAccessService) UpdatePropertyFields(callerID string, groupID
// DeletePropertyField deletes a property field and all its values.
// Checks write access before allowing deletion.
func (pas *PropertyAccessService) DeletePropertyField(callerID string, groupID, id string) error {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return fmt.Errorf("DeletePropertyField: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.DeletePropertyField(groupID, id)
}
@ -330,7 +348,9 @@ func (pas *PropertyAccessService) DeletePropertyField(callerID string, groupID,
// CreatePropertyValue creates a new property value.
// Checks write access before allowing the creation.
func (pas *PropertyAccessService) CreatePropertyValue(callerID string, value *model.PropertyValue) (*model.PropertyValue, error) {
if !groupHasAccessRestrictions(value.GroupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(value.GroupID); err != nil {
return nil, fmt.Errorf("CreatePropertyValue: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.CreatePropertyValue(value)
}
@ -357,7 +377,9 @@ func (pas *PropertyAccessService) CreatePropertyValue(callerID string, value *mo
func (pas *PropertyAccessService) CreatePropertyValues(callerID string, values []*model.PropertyValue) ([]*model.PropertyValue, error) {
shouldApplyAccessControl := false
for _, value := range values {
if groupHasAccessRestrictions(value.GroupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(value.GroupID); err != nil {
return nil, fmt.Errorf("CreatePropertyValues: cannot determine access restrictions: %w", err)
} else if hasRestrictions {
shouldApplyAccessControl = true
break
}
@ -394,7 +416,9 @@ func (pas *PropertyAccessService) CreatePropertyValues(callerID string, values [
// GetPropertyValue retrieves a property value by ID.
// Returns (nil, nil) if the value exists but the caller doesn't have access.
func (pas *PropertyAccessService) GetPropertyValue(callerID string, groupID, id string) (*model.PropertyValue, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("GetPropertyValue: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.GetPropertyValue(groupID, id)
}
@ -420,7 +444,9 @@ func (pas *PropertyAccessService) GetPropertyValue(callerID string, groupID, id
// GetPropertyValues retrieves multiple property values by their IDs.
// Values the caller doesn't have access to are silently filtered out.
func (pas *PropertyAccessService) GetPropertyValues(callerID string, groupID string, ids []string) ([]*model.PropertyValue, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("GetPropertyValues: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.GetPropertyValues(groupID, ids)
}
@ -440,7 +466,9 @@ func (pas *PropertyAccessService) GetPropertyValues(callerID string, groupID str
// SearchPropertyValues searches for property values based on the given options.
// Values the caller doesn't have access to are silently filtered out.
func (pas *PropertyAccessService) SearchPropertyValues(callerID string, groupID string, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("SearchPropertyValues: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.SearchPropertyValues(groupID, opts)
}
@ -460,7 +488,9 @@ func (pas *PropertyAccessService) SearchPropertyValues(callerID string, groupID
// UpdatePropertyValue updates a property value.
// Checks write access before allowing the update.
func (pas *PropertyAccessService) UpdatePropertyValue(callerID string, groupID string, value *model.PropertyValue) (*model.PropertyValue, error) {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return nil, fmt.Errorf("UpdatePropertyValue: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.UpdatePropertyValue(groupID, value)
}
@ -487,7 +517,9 @@ func (pas *PropertyAccessService) UpdatePropertyValue(callerID string, groupID s
func (pas *PropertyAccessService) UpdatePropertyValues(callerID string, groupID string, values []*model.PropertyValue) ([]*model.PropertyValue, error) {
shouldApplyAccessControl := false
for _, value := range values {
if groupHasAccessRestrictions(value.GroupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(value.GroupID); err != nil {
return nil, fmt.Errorf("UpdatePropertyValues: cannot determine access restrictions: %w", err)
} else if hasRestrictions {
shouldApplyAccessControl = true
break
}
@ -528,7 +560,9 @@ func (pas *PropertyAccessService) UpdatePropertyValues(callerID string, groupID
// UpsertPropertyValue creates or updates a property value.
// Checks write access before allowing the upsert.
func (pas *PropertyAccessService) UpsertPropertyValue(callerID string, value *model.PropertyValue) (*model.PropertyValue, error) {
if !groupHasAccessRestrictions(value.GroupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(value.GroupID); err != nil {
return nil, fmt.Errorf("UpsertPropertyValue cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.UpsertPropertyValue(value)
}
@ -555,7 +589,9 @@ func (pas *PropertyAccessService) UpsertPropertyValue(callerID string, value *mo
func (pas *PropertyAccessService) UpsertPropertyValues(callerID string, values []*model.PropertyValue) ([]*model.PropertyValue, error) {
shouldApplyAccessControl := false
for _, value := range values {
if groupHasAccessRestrictions(value.GroupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(value.GroupID); err != nil {
return nil, fmt.Errorf("UpsertPropertyValues: cannot determine access restrictions: %w", err)
} else if hasRestrictions {
shouldApplyAccessControl = true
break
}
@ -596,7 +632,9 @@ func (pas *PropertyAccessService) UpsertPropertyValues(callerID string, values [
// DeletePropertyValue deletes a property value.
// Checks write access before allowing deletion.
func (pas *PropertyAccessService) DeletePropertyValue(callerID string, groupID, id string) error {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return fmt.Errorf("DeletePropertyValue: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.DeletePropertyValue(groupID, id)
}
@ -627,7 +665,9 @@ func (pas *PropertyAccessService) DeletePropertyValue(callerID string, groupID,
// DeletePropertyValuesForTarget deletes all property values for a specific target.
// Checks write access for all affected fields atomically before deleting.
func (pas *PropertyAccessService) DeletePropertyValuesForTarget(callerID string, groupID string, targetType string, targetID string) error {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return fmt.Errorf("DeletePropertyValuesForTarget: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.DeletePropertyValuesForTarget(groupID, targetType, targetID)
}
@ -709,7 +749,9 @@ func (pas *PropertyAccessService) DeletePropertyValuesForTarget(callerID string,
// DeletePropertyValuesForField deletes all property values for a specific field.
// Checks write access before allowing deletion.
func (pas *PropertyAccessService) DeletePropertyValuesForField(callerID string, groupID, fieldID string) error {
if !groupHasAccessRestrictions(groupID) {
if hasRestrictions, err := pas.groupHasAccessRestrictions(groupID); err != nil {
return fmt.Errorf("DeletePropertyValuesForField: cannot determine access restrictions: %w", err)
} else if !hasRestrictions {
return pas.propertyService.DeletePropertyValuesForField(groupID, fieldID)
}
@ -1185,6 +1227,10 @@ func (pas *PropertyAccessService) applyValueReadAccessControl(values []*model.Pr
return filtered, nil
}
func groupHasAccessRestrictions(groupId string) bool {
return cpaGroupID != "" && groupId == cpaGroupID
func (pas *PropertyAccessService) groupHasAccessRestrictions(groupId string) (bool, error) {
cpaID, err := getCpaGroupID(pas)
if err != nil {
return false, err
}
return groupId == cpaID, nil
}