Skip to content

Commit fb1a764

Browse files
author
whitekernel
committed
[ADD] /api/v2/manage/custom-attributes/validate — dry-run schema validator so the SPA can surface per-field errors before paying the full update_all_attributes back-fill cost
1 parent e6e3388 commit fb1a764

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

source/app/blueprints/rest/v2/manage_routes/custom_attributes.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,36 @@ def update_custom_attribute(identifier: int) -> Response:
180180
)
181181

182182
return response_api_success(_serialize(row))
183+
184+
185+
@custom_attributes_blueprint.post('/validate')
186+
@ac_api_requires(Permissions.server_administrator)
187+
def validate_custom_attribute() -> Response:
188+
"""Dry-run the schema validator without mutating anything.
189+
190+
The SPA calls this from the edit modal so admins can see the
191+
exact per-field error list before committing (the PUT would run
192+
`update_all_attributes` and back-fill every existing row, which
193+
is expensive — surfacing validation errors early avoids paying
194+
that cost only to be rejected).
195+
196+
Body: `{"attribute_content": <object | JSON string>}`.
197+
Returns `{ok: bool, logs: [...]}` — `logs` is empty on success.
198+
"""
199+
if not request.is_json:
200+
return response_api_error('Invalid request')
201+
202+
body = request.get_json() or {}
203+
raw_content = body.get('attribute_content')
204+
if raw_content is None:
205+
return response_api_error('Missing attribute_content')
206+
207+
if isinstance(raw_content, (dict, list)):
208+
encoded = json.dumps(raw_content)
209+
elif isinstance(raw_content, str):
210+
encoded = raw_content
211+
else:
212+
return response_api_error('attribute_content must be a string or JSON object')
213+
214+
_parsed, logs = validate_attribute(encoded)
215+
return response_api_success({'ok': not logs, 'logs': logs})

0 commit comments

Comments
 (0)