Commit Graph

14 Commits

Author SHA1 Message Date
mguschin
cd777d2bc1 fix: always update password on re-registration in /user/create
When Evotor sends a new /user/create for an existing userId, the new
password should replace the old one so /user/verify stays in sync.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:43:05 +03:00
mguschin
41280fad45 fix: look up user by evotor_user_id first in /user/verify
Evotor sends userId but not necessarily a matching phone/email.
Now tries evotor_user_id first, then falls back to email/phone.
Also removed the requirement for username/phone when userId is present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:27:34 +03:00
mguschin
e5a55a02d1 debug: log user/verify request fields (excluding password)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:25:33 +03:00
mguschin
5b82f1bc02 fix: upsert evotor_connection by user_id fallback to prevent duplicate insert
When a connection row exists for the user but with a different/null
evotor_user_id, the lookup by evotor_user_id alone missed it and tried
to INSERT, hitting the unique constraint on user_id. Now looks up by
either evotor_user_id or user_id, and always syncs both fields on update.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:04:33 +03:00
mguschin
fa8167af4d feat: accept phone + password in /user/verify webhook
- Accept phone as an alternative to username for user lookup
- On first auth when user has no password set, save the provided
  password and activate the account (same logic as /user/create)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:00:16 +03:00
mguschin
5a67be2c81 feat: support password field in /user/create webhook
When Evotor sends a password in the payload, hash and store it
immediately and set the user to active — skipping the invite flow.
Without a password, behaviour is unchanged (pending status + invite email).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:57:58 +03:00
mguschin
74f613a4c3 fix: parse Evotor install/uninstall event structure correctly
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>
2026-05-24 16:53:34 +03:00
mguschin
052c3b610f feat: add middle_name field and map all three Evotor name fields
- Add middle_name column to users table (migration 0012)
- Map Evotor's second_name → last_name, middle_name → middle_name
  in /user/create webhook handler
- Update name fields on existing users when Evotor sends them

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:51:11 +03:00
mguschin
dc32bef7e8 fix: read email/phone from top-level body fields in /user/create
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>
2026-05-24 16:48:15 +03:00
mguschin
a3f6697bc4 debug: log raw body on /user/install to identify Evotor payload structure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:45:55 +03:00
mguschin
175f1f4c27 feat: add /user/install webhook + exclude admins from third-party API tasks
- 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>
2026-05-24 16:41:08 +03:00
mguschin
5e7be16755 feat: remove register, add evo webhooks, admin view-as user
- 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>
2026-05-13 20:44:25 +03:00
mguschin
fc65e591b3 test: add test suite with 65 tests, 73% coverage
- Unit tests: password hashing, notification providers, webhook field parsing
- Integration tests: auth routes (register/login/confirm-email/logout),
  invite flow, Evotor webhooks (/user/create, /user/verify, /user/token),
  admin panel (access control, activate/suspend/delete/reset-password)
- conftest: SQLite in-memory engine, transactional sessions, factory-boy
  factories (UserFactory with UserRoleEnum variants)
- Fix bcrypt: replace passlib (broken on Python 3.14 + bcrypt 5.x) with
  direct bcrypt calls; drop passlib from requirements.txt
- Fix datetime.utcnow() deprecation across routes and tests
- Fix Jinja2 TemplateResponse signature (request as first positional arg)
- Add coverage config to pyproject.toml

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 12:27:42 +03:00
mguschin
5ead89e0cf feat: Evotor user lifecycle, RBAC, admin panel
- Receive Evotor webhooks: POST /user/create, /user/verify, /user/token
- Create users in pending status; match to existing users by email/phone
- Send invite link via Celery notification task; user sets password at /invite
- Abstract EmailProvider/SMSProvider with ConsoleEmailProvider default
- Role-based access control: role enum on users + roles/permissions tables
- Admin panel: /admin/users (list, filter, search, paginate), user detail card
  with activate/suspend/reset-password/send-invite/edit/delete actions
- Admin roles management: /admin/roles with per-role permission assignment
- Extend user profile card: role, status, Evotor ID, email confirmation badge
- Auth routes: register, login, logout, confirm-email, forgot/reset password
- Alembic migrations 0002 (full schema + new fields) and 0003 (RBAC + seeds)
- Port Pico CSS + Bootstrap Icons UI from Node.js commit (854c912)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 12:01:36 +03:00