userId is nested inside body.data, and event types are
ApplicationInstalled / ApplicationUninstalled (not install/uninstall).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Evotor sends user fields (email, phone_number, first_name, last_name)
at the top level of the webhook body, not inside customField. Now we
check both locations with top-level taking precedence. Also store the
full body in evotor_meta instead of just the customField subset.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add POST /user/install endpoint handling Evotor app install/uninstall
events: uninstall suspends the user and marks connection offline;
reinstall reactivates a suspended account
- Exclude admin and system role users from refresh_catalog,
refresh_vk_catalog, and mirror_to_vk periodic tasks by joining users
table and filtering role = 'user'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove /register route and nav links (users created via Evotor webhook)
- Fix evotor_webhooks.py: use phone=None instead of phone="" to avoid unique constraint
- Add admin "view as user" feature: POST /admin/users/{id}/view-as sets viewed_user_id
in session; POST /admin/view-as/stop clears it
- catalog, vk_catalog, sync, connections GET routes use get_viewed_user() so admins
see another user's data while browsing
- Orange banner shown at top when admin is viewing as another user
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>