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>
This commit is contained in:
mguschin
2026-05-24 16:41:08 +03:00
parent 9f87458e0c
commit 175f1f4c27

View File

@@ -4,6 +4,7 @@ Evotor webhook endpoints.
POST /user/create — Evotor creates a new subscriber; we create/link a local user and return a token.
POST /user/verify — Evotor verifies credentials for a user trying to log in via the Evotor interface.
POST /user/token — Evotor sends us its own API token for the user.
POST /user/install — Evotor notifies about app install or uninstall for a user.
"""
import json
import logging
@@ -267,3 +268,51 @@ async def user_token(request: Request, db: Session = Depends(get_db)):
db.commit()
return JSONResponse({})
@router.post("/user/install")
async def user_install(request: Request, db: Session = Depends(get_db)):
"""Handle app install / uninstall events from Evotor."""
if not _verify_secret(request):
return JSONResponse({"error": "Unauthorized"}, status_code=401)
try:
body = await request.json()
except Exception:
return JSONResponse({"error": "Invalid JSON"}, status_code=400)
evotor_user_id: str = body.get("userId", "")
event_type: str = body.get("type", "").lower() # "install" or "uninstall"
if not evotor_user_id:
return JSONResponse({"error": "userId required"}, status_code=400)
logger.info("user/install event type=%s userId=%s", event_type, evotor_user_id)
user = db.query(User).filter(User.evotor_user_id == evotor_user_id).first()
if not user:
# Unknown user — nothing to act on, but acknowledge the event
return JSONResponse({})
now = datetime.now(timezone.utc).replace(tzinfo=None)
if event_type == "uninstall":
user.status = UserStatusEnum.suspended
user.updated_at = now
conn = db.query(EvotorConnection).filter(
EvotorConnection.evotor_user_id == evotor_user_id
).first()
if conn:
conn.is_online = False
conn.updated_at = now
db.commit()
logger.info("user suspended on uninstall: userId=%s", evotor_user_id)
elif event_type == "install":
if user.status == UserStatusEnum.suspended:
user.status = UserStatusEnum.active
user.updated_at = now
db.commit()
logger.info("user reactivated on reinstall: userId=%s", evotor_user_id)
return JSONResponse({})