Broadleaf Microservices
  • v1.0.0-latest-prod

Release Notes for 1.1.0

Features & Enhancements

  • Allow CustomerRef to be populated by caller of the Content Resolver Endpoint since the caller could be another service like Catalog Browse.

Content Field Migration

ContentField now has its own schema, BLC_CONTENT_FIELD, instead of being embedded on ContentModel. This requires a migration that copies the embedded fields from the BLC_CONTENT_MODEL table into the new one which is included in the content.postgres.changelog-master.yaml or content.oracle.changelog-master.yaml and will be automatically run like other liquibase changesets. This is a non-destructive migration, meaning the old column on BLC_CONTENT_MODEL is not removed.

Important
From an Admin UI perspective, ContentFields are still managed as if there were embedded on ContentModel so that users should not notice any difference despite the schema change.

Reason for Change

This is to fix mismatches that can occur when a user adds a new Field to a Content Model in a child Profile but another new Content Field is added in the parent Profile.

ContentFields were stored as a collection on the ContentModel domain, so the whole collection was overridden by the single change. That is to say, when one ContentField is added at the Application level, the whole collection is overridden, so any new fields added at the Tenant level will not be present on the ContentModel at the Application level. This caused a UI error because no matching ContentField was found for a FieldData since the new Field was added at the Tenant level after an override was made at the Application level.

A patch was applied in the 1.0.x line of Content Services that would avoid the error but did not fix the root of the problem.

Migration Scripts

Tip
These scripts will be automatically run similar to schema changesets, so users should not need to do anything besides upgrade the dependency version to include these on the next app start.

For convenience, the migration scripts are listed below in case they should be rerun or debugged.

Postgres
-- liquibase formatted sql
-- changeset broadleaf:content-fields-migration

INSERT INTO BLC_CONTENT_FIELD
SELECT
    substr(content_fields.id || cm.trk_catalog_context_id, 0, 36),
    content_fields."allowedModels",
    content_fields.attributes,
    CASE WHEN content_fields.collection = true THEN 'Y' ELSE 'N' END,
    cm.context_id,
    substr(content_fields.id || cm.trk_catalog_context_id, 0, 36),
    content_fields."displayOrder",
    content_fields."helpText",
    content_fields.hint,
    content_fields.label,
    content_fields.name,
    content_fields."referenceType",
    CASE WHEN content_fields.required = true THEN 'Y' ELSE 'N' END,
    cm.trk_archived,
    CURRENT_TIMESTAMP,
    cm.audit_creator,
    cm.audit_update_time,
    cm.audit_updater,
    cm.trk_catalog_context_id,
    cm.trk_catalog_level,
    cm.trk_catalog_locale,
    cm.trk_catalog_name,
    cm.trk_parent_cat_context_id,
    cm.trk_parent_cat_level,
    cm.trk_parent_cat_locale,
    cm.trk_parent_cat_name,
    cm.trk_change_details,
    cm.trk_composite_sort_level,
    cm.trk_creating_application_id,
    cm.trk_current_message,
    cm.trk_field_overrides,
    cm.trk_level,
    cm.trk_max_field_versions,
    cm.trk_sandbox_archived,
    cm.trk_sub_container_catalog,
    cm.trk_change_container_id,
    cm.trk_change_container_name,
    cm.trk_change_container_route_key,
    cm.trk_sub_container_name,
    cm.trk_sandbox_change_type,
    cm.trk_sandbox_context_id,
    cm.trk_sandbox_name,
    cm.trk_sandbox_owner,
    cm.trk_sandbox_stage,
    cm.trk_tenant_id,
    'N',
    content_fields.type
FROM BLC_CONTENT_MODEL cm,
     json_to_recordset((cm.fields)::json) AS content_fields(id TEXT, "allowedModels" TEXT, attributes TEXT, collection BOOLEAN, "displayOrder" INT, "helpText" TEXT, hint TEXT, label TEXT, name TEXT, "referenceType" TEXT, required BOOLEAN, type TEXT)
ON CONFLICT DO NOTHING;
Oracle
-- liquibase formatted sql
-- changeset broadleaf:content-fields-migration-oracle

INSERT INTO "BLC_CONTENT_FIELD"
SELECT
    substr(cf.id || cm.trk_catalog_context_id, 0, 36),
    cf.allowed_models,
    cf.attributes,
    CASE WHEN cf.collection = 'true' THEN 'Y' ELSE 'N' END as collection,
    cm.context_id as model_context_id,
    substr(cf.id || cm.trk_catalog_context_id, 0, 36),
    cf.display_order,
    cf.help_text,
    cf.hint,
    cf.label,
    cf.name,
    cf.reference_type,
    CASE WHEN cf.required = 'true' THEN 'Y' ELSE 'N' END as required,
    cm.trk_archived,
    CURRENT_TIMESTAMP,
    cm.audit_creator,
    cm.audit_update_time,
    cm.audit_updater,
    cm.trk_catalog_context_id,
    cm.trk_catalog_level,
    cm.trk_catalog_locale,
    cm.trk_catalog_name,
    cm.trk_parent_cat_context_id,
    cm.trk_parent_cat_level,
    cm.trk_parent_cat_locale,
    cm.trk_parent_cat_name,
    cm.trk_change_details,
    cm.trk_composite_sort_level,
    cm.trk_creating_application_id,
    cm.trk_current_message,
    cm.trk_field_overrides,
    cm.trk_level,
    cm.trk_max_field_versions,
    cm.trk_sandbox_archived,
    cm.trk_sub_container_catalog,
    cm.trk_change_container_id,
    cm.trk_change_container_name,
    cm.trk_change_container_route_key,
    cm.trk_sub_container_name,
    cm.trk_sandbox_change_type,
    cm.trk_sandbox_context_id,
    cm.trk_sandbox_name,
    cm.trk_sandbox_owner,
    cm.trk_sandbox_stage,
    cm.trk_tenant_id,
    'N',
    cf.type
FROM "BLC_CONTENT_MODEL" cm,
     JSON_TABLE (cm.FIELDS, '$[*]'
         COLUMNS "ID" VARCHAR2(36) PATH '$.id',
                 "ALLOWED_MODELS" CLOB PATH '$.allowedModels',
                 "ATTRIBUTES" CLOB PATH '$.attributes',
                 "COLLECTION" VARCHAR2(1 CHAR) PATH '$.collection',
                 "DISPLAY_ORDER" NUMBER(10,0) PATH '$.displayOrder',
                 "HELP_TEXT" VARCHAR2(255) PATH '$.helpText',
                 "HINT" VARCHAR2(255) PATH '$.hint',
                 "LABEL" VARCHAR2(255) PATH '$.label',
                 "NAME" VARCHAR2(255) PATH '$.name',
                 "REFERENCE_TYPE" VARCHAR2(60) PATH '$.referenceType',
                 "REQUIRED" VARCHAR2(1 CHAR) PATH '$.required',
                 "TRANSLATABLE" VARCHAR2(1 CHAR) PATH '$.translatable',
                 "TYPE" VARCHAR2(60) PATH '$.type'
         ) AS cf
WHERE NOT EXISTS (SELECT id FROM "BLC_CONTENT_FIELD" WHERE id = cf.id);

Bug Fixes

  • Fixed incorrect matcher config for caching. Needs to match against the proper field, in this case name vs id