Files
service-finder/backend/scripts/repair_kyc_user.py

250 lines
9.9 KiB
Python

#!/usr/bin/env python3
"""
Repair script for user gy.krisztina76@gmail.com (ID 100).
This user went through light registration + email verification but the KYC
completion failed because of two bugs:
1. verify_email() used Person.user_id (NULL) instead of User.person_id
2. GamificationService.award_points() did internal commit conflicting with outer transaction
This script manually creates all the missing infrastructure that should have
been created by complete_kyc():
- Activate Person
- Create Organization (personal)
- Create Branch
- Create OrganizationMember
- Create Wallet
- Create UserStats
- Set user.scope_id
"""
import asyncio
import logging
import sys
from datetime import datetime, timezone
# Add the backend directory to the path
sys.path.insert(0, '/app/backend')
from sqlalchemy import select, and_
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from app.core.config import settings
# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
logger = logging.getLogger("repair_kyc")
# Database URL from settings
DATABASE_URL = settings.DATABASE_URL
logger.info(f"Using database: {DATABASE_URL}")
# Create engine and session
engine = create_async_engine(DATABASE_URL, echo=False)
AsyncSessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def repair_user():
async with AsyncSessionLocal() as db:
try:
# 1. Find the user
from app.models.identity.identity import User, Person, Wallet
from app.models.marketplace.organization import Organization, OrganizationMember, Branch
from app.models.gamification.gamification import UserStats, PointsLedger
stmt = select(User).where(User.email == 'gy.krisztina76@gmail.com')
user = (await db.execute(stmt)).scalar_one_or_none()
if not user:
logger.error("User not found!")
return
logger.info(f"Found user: ID={user.id}, email={user.email}, person_id={user.person_id}")
logger.info(f" is_active={user.is_active}, scope_id={user.scope_id}")
# 2. Find and activate Person
person_stmt = select(Person).where(Person.id == user.person_id)
person = (await db.execute(person_stmt)).scalar_one_or_none()
if person:
logger.info(f"Found Person: ID={person.id}, is_active={person.is_active}, user_id={person.user_id}")
person.is_active = True
person.user_id = user.id
logger.info(f" -> Activated Person, set user_id={user.id}")
else:
logger.warning(f"Person with id={user.person_id} not found!")
# 3. Check if Organization already exists
org_stmt = select(Organization).where(Organization.owner_id == user.id)
existing_org = (await db.execute(org_stmt)).scalar_one_or_none()
if existing_org:
logger.info(f"Organization already exists: ID={existing_org.id}, name={existing_org.name}")
new_org = existing_org
else:
# Create personal Organization
from app.core.security import generate_secure_slug
org_name = f"{person.last_name} Flotta" if person else "Personal Flotta"
folder_slug = generate_secure_slug(12)
new_org = Organization(
name=org_name,
full_name=org_name,
display_name=org_name,
folder_slug=folder_slug,
org_type="individual",
status="ACTIVE",
is_deleted=False,
is_active=True,
is_verified=False,
is_anonymized=False,
default_currency="HUF",
country_code="HU",
language="hu",
subscription_plan="FREE",
base_asset_limit=3,
purchased_extra_slots=0,
notification_settings={},
external_integration_config={},
visual_settings={},
is_ownership_transferable=False,
owner_id=user.id,
first_registered_at=datetime.now(timezone.utc),
current_lifecycle_started_at=datetime.now(timezone.utc),
lifecycle_index=1,
created_at=datetime.now(timezone.utc)
)
db.add(new_org)
await db.flush()
logger.info(f"Created Organization: ID={new_org.id}, name={org_name}")
# 4. Check if Branch already exists
branch_stmt = select(Branch).where(Branch.organization_id == new_org.id)
existing_branch = (await db.execute(branch_stmt)).scalar_one_or_none()
if existing_branch:
logger.info(f"Branch already exists: ID={existing_branch.id}, name={existing_branch.name}")
else:
import uuid
branch = Branch(
id=uuid.uuid4(),
organization_id=new_org.id,
name="Home Base",
is_main=True,
opening_hours={},
branch_rating=0.0,
status="ACTIVE",
is_deleted=False,
created_at=datetime.now(timezone.utc)
)
db.add(branch)
await db.flush()
logger.info(f"Created Branch: ID={branch.id}")
# 5. Check if OrganizationMember already exists
member_stmt = select(OrganizationMember).where(
and_(
OrganizationMember.organization_id == new_org.id,
OrganizationMember.user_id == user.id
)
)
existing_member = (await db.execute(member_stmt)).scalar_one_or_none()
if existing_member:
logger.info(f"OrganizationMember already exists: ID={existing_member.id}")
else:
member = OrganizationMember(
organization_id=new_org.id,
user_id=user.id,
role="OWNER",
permissions={},
is_permanent=True,
is_verified=True
)
db.add(member)
await db.flush()
logger.info(f"Created OrganizationMember: user_id={user.id}, org_id={new_org.id}")
# 6. Check if Wallet already exists
wallet_stmt = select(Wallet).where(Wallet.user_id == user.id)
existing_wallet = (await db.execute(wallet_stmt)).scalar_one_or_none()
if existing_wallet:
logger.info(f"Wallet already exists: ID={existing_wallet.id}")
else:
wallet = Wallet(
user_id=user.id,
earned_credits=0,
purchased_credits=0,
service_coins=0,
currency="HUF"
)
db.add(wallet)
await db.flush()
logger.info(f"Created Wallet for user_id={user.id}")
# 7. Check if UserStats already exists
stats_stmt = select(UserStats).where(UserStats.user_id == user.id)
existing_stats = (await db.execute(stats_stmt)).scalar_one_or_none()
if existing_stats:
logger.info(f"UserStats already exists: user_id={existing_stats.user_id}")
else:
stats = UserStats(
user_id=user.id,
total_xp=500, # KYC bonus
social_points=0,
current_level=1,
penalty_points=0,
restriction_level=0,
updated_at=datetime.now(timezone.utc),
penalty_quota_remaining=0,
places_discovered=0,
places_validated=0
)
db.add(stats)
# Add PointsLedger entry for KYC bonus
ledger = PointsLedger(
user_id=user.id,
points=500,
reason="KYC_VERIFICATION_REPAIR"
)
db.add(ledger)
await db.flush()
logger.info(f"Created UserStats and PointsLedger for user_id={user.id}")
# 8. Set user.scope_id if not set
if not user.scope_id:
user.scope_id = str(new_org.id)
logger.info(f"Set user.scope_id = {new_org.id}")
# 9. Ensure user.is_active is True
if not user.is_active:
user.is_active = True
logger.info("Activated user")
await db.commit()
logger.info("=" * 50)
logger.info("REPAIR COMPLETED SUCCESSFULLY!")
logger.info("=" * 50)
# Verify
logger.info("\n--- Verification ---")
logger.info(f"User: ID={user.id}, is_active={user.is_active}, scope_id={user.scope_id}")
if person:
logger.info(f"Person: ID={person.id}, is_active={person.is_active}, user_id={person.user_id}")
logger.info(f"Organization: ID={new_org.id}, name={new_org.name}")
except Exception as e:
await db.rollback()
logger.error(f"Repair failed: {e}")
import traceback
traceback.print_exc()
finally:
await db.close()
await engine.dispose()
if __name__ == "__main__":
asyncio.run(repair_user())