diff --git a/README.md b/README.md index a8c6631..da563ef 100644 --- a/README.md +++ b/README.md @@ -110,4 +110,4 @@ docker compose exec postgres pg_dump -U miem miem_workers > backup.sql docker compose down ``` -Версия сервиса: `0.2.2`. Админка всегда показывает версии backend и frontend в footer. +Версия сервиса: `0.2.3`. Админка всегда показывает версии backend и frontend в footer. diff --git a/app/services/admin_data.py b/app/services/admin_data.py index aa0c3d4..64f747b 100644 --- a/app/services/admin_data.py +++ b/app/services/admin_data.py @@ -20,18 +20,19 @@ EMPLOYEE_SORTS = { def employee_display_payload(employee: Employee) -> dict[str, Any]: - data = employee.current_data or {} - contacts = data.get("contacts") or {} - sections = data.get("sections") or [] - emails = contacts.get("emails") or [] - phones = contacts.get("phones") or [] + data = _as_dict(employee.current_data) + contacts = _as_dict(data.get("contacts")) + sections = _as_list(data.get("sections")) + positions = _clean_list(data.get("positions")) + emails = _clean_list(contacts.get("emails")) + phones = _clean_list(contacts.get("phones")) return { "id": employee.id, "full_name": employee.full_name, "status": employee.status, "canonical_url": employee.canonical_url, - "positions": data.get("positions") or [], - "positions_text": "; ".join(data.get("positions") or []), + "positions": positions, + "positions_text": "; ".join(positions), "hse_start_year": data.get("hse_start_year"), "emails": emails, "email_text": ", ".join(emails), @@ -47,8 +48,8 @@ def employee_display_payload(employee: Employee) -> dict[str, Any]: def employee_detail_payload(employee: Employee) -> dict[str, Any]: - data = employee.current_data or {} - contacts = data.get("contacts") or {} + data = _as_dict(employee.current_data) + contacts = _as_dict(data.get("contacts")) return { **employee_display_payload(employee), "profile_type": employee.profile_type or data.get("profile_type"), @@ -61,7 +62,7 @@ def employee_detail_payload(employee: Employee) -> dict[str, Any]: "items": _normalize_contact_items(contacts.get("items")), }, "external_ids": _normalize_external_ids(data.get("external_ids")), - "sections": [_normalize_section(section) for section in data.get("sections") or []], + "sections": [_normalize_section(section) for section in _as_list(data.get("sections"))], } @@ -179,11 +180,23 @@ def _count_section_items(sections: list[dict[str, Any]], section_type: str) -> i def _clean_list(values: Any) -> list[str]: - if not isinstance(values, list): + if values is None: return [] + if not isinstance(values, list): + values = [values] return [str(value).strip() for value in values if str(value or "").strip()] +def _as_dict(value: Any) -> dict[str, Any]: + return value if isinstance(value, dict) else {} + + +def _as_list(value: Any) -> list[Any]: + if value is None: + return [] + return value if isinstance(value, list) else [value] + + def _normalize_contact_items(items: Any) -> list[str]: normalized = [] if not isinstance(items, list): diff --git a/app/version.py b/app/version.py index d5c9b77..8a15179 100644 --- a/app/version.py +++ b/app/version.py @@ -1,3 +1,3 @@ -APP_VERSION = "0.2.2" -FRONTEND_VERSION = "0.2.2" -BACKEND_VERSION = "0.2.2" +APP_VERSION = "0.2.3" +FRONTEND_VERSION = "0.2.3" +BACKEND_VERSION = "0.2.3" diff --git a/tests/test_admin_data.py b/tests/test_admin_data.py index 03deb49..49062c8 100644 --- a/tests/test_admin_data.py +++ b/tests/test_admin_data.py @@ -94,6 +94,26 @@ def test_employee_detail_payload_normalizes_human_readable_sections(db_session): assert payload["sections"][3]["paragraphs"] == ["Fallback text"] +def test_employee_payloads_tolerate_malformed_current_data(db_session): + employee = Employee( + profile_key="staff:broken", + canonical_url="https://www.hse.ru/staff/broken", + full_name="Broken Data", + status="active", + first_seen_at=datetime.now(timezone.utc), + last_seen_at=datetime.now(timezone.utc), + current_data="not-a-dict", + ) + + display = employee_display_payload(employee) + detail = employee_detail_payload(employee) + + assert display["positions"] == [] + assert display["email_text"] == "" + assert detail["contacts"]["emails"] == [] + assert detail["sections"] == [] + + def test_list_employees_page_filters_sorts_and_paginates(db_session): db_session.add( Employee( diff --git a/tests/test_api_mcp.py b/tests/test_api_mcp.py index 72ebd21..1433858 100644 --- a/tests/test_api_mcp.py +++ b/tests/test_api_mcp.py @@ -18,7 +18,7 @@ def test_health_returns_versions(): response = client.get("/api/health") assert response.status_code == 200 - assert response.json()["backend_version"] == "0.2.2" + assert response.json()["backend_version"] == "0.2.3" def test_mcp_requires_token_and_lists_tools():