fix(news): custom RSS feed save fails with validation error when no logo (#329)

_set_missing_booleans_to_false was unconditionally creating an empty
dict for every nested-object sub-property when processing array items.
For the news plugin's custom_feeds, this produced logo:{} on every feed
item that had no logo uploaded. jsonschema then validated that empty
object against logo's required:["id","path"] constraint and failed.

Fix: skip recursion into a sub-object when it isn't already present in
the array item. There's no reason to create an optional object like
logo just to look for boolean fields inside it.

Also extend _filter_config_by_schema to recurse into array items when
the items schema has properties. Previously arrays were passed through
unchanged, so any stray field on a feed item (legacy data, migration
artifacts) would survive to validation where additionalProperties:false
would reject it.

Co-authored-by: Chuck <chuck@example.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-05-13 15:51:17 -04:00
committed by GitHub
parent 3b45a75f75
commit 452afacd12

View File

@@ -4277,8 +4277,13 @@ def _set_missing_booleans_to_false(config, schema_props, form_keys, prefix='', c
elif prop_type == 'object' and 'properties' in prop_schema: elif prop_type == 'object' and 'properties' in prop_schema:
# Recurse into nested objects # Recurse into nested objects
if config_node is not None: if config_node is not None:
# Inside an array item — ensure nested dict exists in item # Inside an array item — only recurse if the sub-object already exists.
if prop_name not in node or not isinstance(node[prop_name], dict): # Never create optional sub-objects that weren't submitted; doing so
# produces e.g. logo:{} on feed items with no logo, which then fails
# schema validation when the object has required fields (id, path).
if prop_name not in node:
continue
if not isinstance(node[prop_name], dict):
node[prop_name] = {} node[prop_name] = {}
_set_missing_booleans_to_false( _set_missing_booleans_to_false(
config, prop_schema['properties'], form_keys, full_path, config, prop_schema['properties'], form_keys, full_path,
@@ -4418,10 +4423,22 @@ def _filter_config_by_schema(config, schema, prefix=''):
prop_schema = schema_props[key] prop_schema = schema_props[key]
# Handle nested objects recursively # Handle nested objects recursively
item_prefix = f"{prefix}.{key}" if prefix else key
if isinstance(value, dict) and prop_schema.get('type') == 'object' and 'properties' in prop_schema: if isinstance(value, dict) and prop_schema.get('type') == 'object' and 'properties' in prop_schema:
filtered[key] = _filter_config_by_schema(value, prop_schema, f"{prefix}.{key}" if prefix else key) filtered[key] = _filter_config_by_schema(value, prop_schema, item_prefix)
elif isinstance(value, list) and prop_schema.get('type') == 'array':
items_schema = prop_schema.get('items', {})
if isinstance(items_schema, dict) and items_schema.get('type') == 'object' and 'properties' in items_schema:
# Filter each item in the array so extra fields are stripped before
# schema validation (important when items has additionalProperties: false)
filtered[key] = [
_filter_config_by_schema(item, items_schema, item_prefix) if isinstance(item, dict) else item
for item in value
]
else: else:
# Keep the value as-is for non-object types filtered[key] = value
else:
# Keep the value as-is for non-object/non-array types
filtered[key] = value filtered[key] = value
return filtered return filtered