250 lines
9.9 KiB
Python
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())
|