Ported the legacy '/hosted_file/hash/{hash}' endpoint to the V3 actions router.
The new endpoint '/v3/action/hosted_file/hash/{hosted_file_hash}' supports:
- ID Vision: returns random string IDs instead of internal integers
- Local Check: verifies physical file existence on disk (check_for_local=True)
- Deduplication: enables frontend to check for existing files before upload
Also added PROJECT document for AE Hosted Files migration tracking.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Newer gunicorn patch releases added _get_control_socket_path() which
crashes with TypeError when control_socket is None. Pin to the working
version until the gunicorn config fix propagates everywhere.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tags remaining live-but-deprecated routes so every call logs a warning,
giving visibility before the next round of removals.
- registry.py: add DeprecationParams to importing and user routers
- api.py: add DeprecationParams to /request_jwt and /temp_token individually
- user.py: inherits deprecation warning via registry router-level dependency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Disabled legacy routes that are superseded by V3 equivalents. Code is
commented out (not deleted) pending final verification and cleanup pass.
- registry.py: remove sql, lookup (/lu), websockets, websockets_redis;
clean up dead imports (contact, event_person, etc.)
- data_store.py: comment out legacy CRUD and code-lookup endpoints;
keep V3 code-lookup routes active; add TODO for action path rename
- api.py: comment out Api_Base CRUD, get_id (internal ID leak),
and sql_test (debug) endpoints
- aether_cfg.py: comment out legacy Flask cfg endpoint
- user.py: comment out legacy user endpoints
- util_email.py: minor cleanup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents the root cause of the timezone collapse bug and how to avoid it
in future data imports. Covers:
- group as the dedup identity key (not a display label), per lookup type
- correct way to add/update/remove account and object overrides
- hard invariant for time_zone: group must equal name
- verification query to catch bad seed data before it ships
- frontend keying guidance: use group, not id or name
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reverts the PARTITION BY name change — group is the correct dedup key.
Partitioning by name broke country deduplication (two US records both
survived, causing Svelte each_key_duplicate on alpha_2_code='US').
Root cause is bad seed data in lu_v3_time_zone: group='United States'
for 13 US/* zones and group='Europe' for 63 Europe/* zones instead of
group=name. A separate DB UPDATE is required to fix those rows.
Tests updated to assert:
- No duplicate alpha_2_code in country list (PARTITION BY group regression)
- All 13 US/* and Europe/* spot-check zones present (pending DB data fix)
- priority-only timezone count == 72 (pending DB data fix)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ROW_NUMBER() was partitioning by `group`, collapsing all 12 US/* timezones
(which share group="United States") down to a single record. Partitioning
by `name` correctly deduplicates by timezone identity while still preserving
the object > account > global override hierarchy.
Priority-only list now returns the expected 72 entries. Adds a regression
test asserting all 12 US/* timezones are present in the full list.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers the fix from 308a7f2 — verifies that MariaDB error 1364
is classified as database_schema and the field name is extracted
into a readable message.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parses the field name from the MariaDB error and returns a clear
"Schema mismatch: column 'X' is NOT NULL..." message instead of the
raw DB string. Consistent with how 1054/1146 (unknown column/table)
are already handled.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements a full proof-of-concept for syncing IDAA's Novi AMS membership
groups to Mailman 3 mailing lists via a cron-triggered reconciliation approach.
Key changes:
- methods: rewrote sync engine around confirmed Novi API shape — group-based
member fetch (/groups/{guid}/members + /customers/{uuid}), respects
Active=false and UnsubscribeFromEmails=true flags
- methods: mirror_novi_group_to_mailman_list() diffs Novi group against
Mailman roster and subscribes/unsubscribes accordingly (full mirror)
- methods: mirror_all_configured_mappings() iterates novi_mailman_sync
config array in IDAA site cfg_json — this is the cron target
- router: replaced old /sync endpoint with POST /sync (all mappings) and
POST /sync/group/{guid} (single mapping); removed webhook endpoint
(sync is cron-based, not event-driven)
- router: added GET/POST/DELETE endpoints for list member inspection
and manual subscribe/unsubscribe
- tests: two new e2e scripts covering connection checks and full member
lifecycle; old webhook integration test archived
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New router: app/routers/api_v3_actions_event_exhibit.py
- GET /v3/action/event_exhibit/{exhibit_id}/tracking_export
- Full V3 auth (x-aether-api-key + account context)
- Multi-tenant ownership check via check_account_access
- Permission gate: leads_api_access flag OR manager-level access
- Returns CSV or XLSX file attachment (return_file=false for JSON)
- Flattens responses_json custom Q&A columns; strips HTML from exhibitor_notes
- Exports all records regardless of hidden/enabled state
- Registered in registry.py under prefix /v3/action/event_exhibit
- New E2E test: tests/e2e/test_e2e_v3_action_event_exhibit_tracking_export.py
- 7/7 tests passing against dev-api.oneskyit.com
- Docs: GUIDE__AE_API_V3_for_Frontend.md — new Section 7 covering endpoint
usage, columns, leads_api_access dual-purpose (3rd-party API + UI export gate)
- Docs: tests/README.md — added test to table and when-to-run matrix
Root cause: child model root_validators (Vision ID anti-leakage guard) strip
integer IDs before they can be serialized into the INSERT dict, causing MariaDB
to reject the INSERT with 'Field does not have a default value' (1364).
Fix: re-inject resolved_parent_id into data_to_insert after validated_obj.dict()
in post_child_obj(). This is safe — the integer was already verified against the
DB before model validation.
Affected (were all broken since ~2026-01-27):
- journal/{id}/journal_entry/
- event/{id}/event_session/
- event/{id}/event_person/
- event/{id}/event_registration/
- event/{id}/event_presenter/
- event/{id}/event_presentation/
- event/{id}/event_location/
- event/{id}/event_track/
- event/{id}/event_device/
- event/{id}/event_abstract/
- event/{id}/event_badge/ (different symptom: NULL FK)
Tests: add nested create lifecycle regression tests to test_e2e_v3_demo_parity.py
- POST + Vision check + DELETE for journal/journal_entry and event/event_session
- All 9 checks passing (7s)
Docs: update tests/README.md with accurate demo_parity description and
a 'When to Run Tests' matrix to prevent future gaps in coverage.
- Add confirmed Novi API patterns (auth, field names, endpoints)
- List remaining unknowns and data_store credential setup requirements
- Add pydantic/SQLAlchemy migration notes
- Summarize completed operational hardening and BuildKit cache work
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Auth: ApiKey header → Authorization: Basic (confirmed from IDAA Jitsi code)
- Member fields: confirmed PascalCase (FirstName, LastName, Email) from Novi API
- email.replace(' ', '+') to match Jitsi's sanitization pattern
- Bulk member list endpoint marked TODO pending confirmation
- Response unwrapping handles Results/Members/value/array shapes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app/methods/e_novi_mailman_methods.py: full sync engine, per-member
sync helper, webhook handler, and Mailman 3 REST subscribe/unsubscribe
- app/routers/api_v3_actions_e_novi_mailman.py: test_connection, list
inspection, full sync trigger, and Novi webhook receiver endpoints
- registry.py: registered at /v3/action/e_novi_mailman
- TODO: marked as scaffolded, pending Novi field verification + data_store setup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed MarkupSafe, rfc3986, sniffio, starlette — all pulled in
automatically as transitive dependencies of fastapi/httpx/anyio.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: enable BuildKit syntax, use --mount=type=cache for pip to speed up rebuilds
- requirements.txt: relax fastapi==0.115.5 → fastapi>=0.115.5
- TODO: mark Locking task as complete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Modified 'sanitize_payload' to ignore 'external_person_id', preventing incorrect lookup attempts for email/passcode fields.
- Refined 'Event_Exhibit_Tracking_Base' to allow 'Union[int, str]' for relational IDs, bypassing string-length validation for internal integers.
- Adjusted root validator to preserve relational integers during POST/PUT operations while still stripping primary/account IDs for Vision-compliant READ views.
- Aligned model configuration with other V3 objects for consistency.
This commit introduces a new end-to-end test script to validate the recent model refactoring changes.
The test suite performs two primary checks for a list of target objects:
- **ID Vision Compliance:** Verifies that all primary and foreign key fields are returned as string IDs, ensuring adherence to the V3 ID Vision standard.
- **Excluded Fields Stripping:** Attempts a PATCH operation with fields explicitly listed in and verifies that these fields are not updated in the database, confirming the mechanism functions as intended.
This test is essential for ensuring the stability and correctness of the API's interaction with the refactored models.
This commit refactors numerous Pydantic models to align with the V3 ID Vision standard, ensuring that primary and foreign key fields are represented as clean string IDs in the API. It also introduces and populates the ClassVar in each model to prevent view-only fields and linked objects from being inadvertently written to the database during PATCH/POST operations.
Specifically, this includes:
- Adding to exclude view-derived or joined fields such as , , nested objects (e.g., , ), and convenience fields (e.g., ).
- Adjusting root validators to correctly map string IDs and strip internal integer IDs for API responses.
- Resolving a KeyError by adding to .
These changes are crucial for maintaining data integrity and consistency with the V3 API architecture.
- Adds fields_to_exclude_from_db to Archive_Content_Base to prevent SQL errors on non-existent columns.
- Updates documentation for V3 Create/Update patterns and the x-ae-ignore-extra-fields header.
- Propagates account_id_random to hosted file and media processing methods.