teljes backend_mentés
This commit is contained in:
263
backend/app/scripts/seed_v2_0.py
Normal file
263
backend/app/scripts/seed_v2_0.py
Normal file
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Service Finder v2.0 Seed Script (Gamification 2.0 + Mock Service Profiles)
|
||||
Modern, asynchronous SQLAlchemy 2.0 seed script for development and testing.
|
||||
Includes: Superadmin user, Gamification levels (-3 to +10), 15 mock service profiles.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from typing import List, Tuple
|
||||
|
||||
from sqlalchemy import select, delete, text
|
||||
from sqlalchemy.dialects.postgresql import insert
|
||||
from geoalchemy2 import WKTElement
|
||||
|
||||
from app.db.session import SessionLocal
|
||||
from app.models.identity.identity import User
|
||||
from app.models.gamification.gamification import LevelConfig
|
||||
from app.models.marketplace.service import ServiceProfile, ServiceStatus
|
||||
from app.core.security import get_password_hash
|
||||
|
||||
# Environment safety check
|
||||
ENVIRONMENT = "development" # Change to 'production' in production deployments
|
||||
|
||||
|
||||
async def cleanup_existing_seeds(db):
|
||||
"""Clean up previously seeded data (only in non-production environments)."""
|
||||
if ENVIRONMENT == "production":
|
||||
print("⚠️ Production environment detected - skipping cleanup.")
|
||||
return
|
||||
|
||||
print("🧹 Cleaning up previously seeded data...")
|
||||
|
||||
# Delete mock service profiles (fingerprint starts with 'MOCK-')
|
||||
result = await db.execute(
|
||||
delete(ServiceProfile).where(ServiceProfile.fingerprint.like("MOCK-%"))
|
||||
)
|
||||
print(f" Deleted {result.rowcount} mock service profiles")
|
||||
|
||||
# Delete gamification levels we're about to insert (levels -3 to +10)
|
||||
result = await db.execute(
|
||||
delete(LevelConfig).where(LevelConfig.level_number.between(-3, 10))
|
||||
)
|
||||
print(f" Deleted {result.rowcount} gamification level configs")
|
||||
|
||||
# Delete superadmin user if exists (by email)
|
||||
result = await db.execute(
|
||||
delete(User).where(User.email == "admin@servicefinder.hu")
|
||||
)
|
||||
print(f" Deleted {result.rowcount} superadmin users")
|
||||
|
||||
await db.commit()
|
||||
|
||||
|
||||
async def create_superadmin(db):
|
||||
"""Create superadmin user with admin@servicefinder.hu / admin123 credentials."""
|
||||
stmt = select(User).where(User.email == "admin@servicefinder.hu")
|
||||
existing = (await db.execute(stmt)).scalar_one_or_none()
|
||||
|
||||
if existing:
|
||||
print("✅ Superadmin user already exists")
|
||||
return existing
|
||||
|
||||
hashed_password = get_password_hash("admin123")
|
||||
admin = User(
|
||||
email="admin@servicefinder.hu",
|
||||
hashed_password=hashed_password,
|
||||
full_name="System Administrator",
|
||||
is_active=True,
|
||||
is_superuser=True,
|
||||
is_verified=True,
|
||||
email_verified_at=datetime.utcnow(),
|
||||
)
|
||||
db.add(admin)
|
||||
await db.commit()
|
||||
await db.refresh(admin)
|
||||
print("✅ Superadmin user created: admin@servicefinder.hu / admin123")
|
||||
return admin
|
||||
|
||||
|
||||
async def seed_gamification_levels(db):
|
||||
"""Create Gamification 2.0 levels from -3 (penalty) to +10 (prestige)."""
|
||||
levels = [
|
||||
# Penalty levels (is_penalty = True)
|
||||
(-3, 0, "Börtönviselt", True),
|
||||
(-2, 10, "Büntetőszint 2", True),
|
||||
(-1, 25, "Büntetőszint 1", True),
|
||||
|
||||
# Regular levels (is_penalty = False)
|
||||
(0, 0, "Újonc", False),
|
||||
(1, 50, "Felfedező", False),
|
||||
(2, 150, "Gyakornok", False),
|
||||
(3, 300, "Szakképzett", False),
|
||||
(4, 500, "Szakértő", False),
|
||||
(5, 750, "Mester", False),
|
||||
(6, 1050, "Legenda", False),
|
||||
(7, 1400, "Hős", False),
|
||||
(8, 1800, "Elit", False),
|
||||
(9, 2250, "Zsoldos", False),
|
||||
(10, 2750, "Kalandor", False),
|
||||
]
|
||||
|
||||
inserted = 0
|
||||
for level_num, min_points, rank_name, is_penalty in levels:
|
||||
# Use PostgreSQL upsert to avoid duplicates
|
||||
insert_stmt = insert(LevelConfig).values(
|
||||
level_number=level_num,
|
||||
min_points=min_points,
|
||||
rank_name=rank_name,
|
||||
is_penalty=is_penalty
|
||||
)
|
||||
upsert_stmt = insert_stmt.on_conflict_do_update(
|
||||
index_elements=['level_number'],
|
||||
set_=dict(
|
||||
min_points=min_points,
|
||||
rank_name=rank_name,
|
||||
is_penalty=is_penalty
|
||||
)
|
||||
)
|
||||
await db.execute(upsert_stmt)
|
||||
inserted += 1
|
||||
|
||||
await db.commit()
|
||||
print(f"✅ {inserted} gamification levels seeded (-3 to +10)")
|
||||
return inserted
|
||||
|
||||
|
||||
def generate_hungarian_coordinates(index: int) -> Tuple[float, float]:
|
||||
"""Generate realistic Hungarian coordinates for mock service profiles."""
|
||||
# Major Hungarian cities with their coordinates
|
||||
cities = [
|
||||
(47.4979, 19.0402), # Budapest
|
||||
(46.2530, 20.1482), # Szeged
|
||||
(47.5316, 21.6273), # Debrecen
|
||||
(46.0759, 18.2280), # Pécs
|
||||
(47.2300, 16.6216), # Szombathely
|
||||
(47.9025, 20.3772), # Eger
|
||||
(47.1890, 18.4103), # Székesfehérvár
|
||||
(46.8412, 16.8416), # Zalaegerszeg
|
||||
(48.1033, 20.7786), # Miskolc
|
||||
(46.3833, 18.1333), # Kaposvár
|
||||
(47.4980, 19.0399), # Budapest (different district)
|
||||
(47.5300, 21.6200), # Debrecen (slightly offset)
|
||||
(46.2600, 20.1500), # Szeged (slightly offset)
|
||||
(47.1900, 18.4200), # Székesfehérvár (slightly offset)
|
||||
(46.8400, 16.8500), # Zalaegerszeg (slightly offset)
|
||||
]
|
||||
|
||||
# Add small random offset to make each location unique
|
||||
import random
|
||||
base_lat, base_lon = cities[index % len(cities)]
|
||||
offset_lat = random.uniform(-0.01, 0.01)
|
||||
offset_lon = random.uniform(-0.01, 0.01)
|
||||
|
||||
return (base_lat + offset_lat, base_lon + offset_lon)
|
||||
|
||||
|
||||
async def seed_service_profiles(db, admin_user):
|
||||
"""Create 15 mock service profiles with different statuses and Hungarian coordinates."""
|
||||
statuses = [ServiceStatus.ghost, ServiceStatus.active, ServiceStatus.flagged]
|
||||
status_distribution = [5, 7, 3] # 5 ghost, 7 active, 3 flagged
|
||||
|
||||
service_names = [
|
||||
"AutoCenter Budapest",
|
||||
"Speedy Garage Szeged",
|
||||
"MesterMűhely Debrecen",
|
||||
"First Class Autószerviz Pécs",
|
||||
"Profik Szerviz Szombathely",
|
||||
"TopGear Eger",
|
||||
"Gold Service Székesfehérvár",
|
||||
"Zala Autó Zalaegerszeg",
|
||||
"Borsodi Műhely Miskolc",
|
||||
"Kaposvári Autó Centrum",
|
||||
"Budapest East Garage",
|
||||
"Debrecen North Workshop",
|
||||
"Szeged South Auto",
|
||||
"Fehérvári Speedy",
|
||||
"Zala Pro Motors"
|
||||
]
|
||||
|
||||
inserted = 0
|
||||
status_idx = 0
|
||||
|
||||
for i in range(15):
|
||||
# Determine status based on distribution
|
||||
if i < status_distribution[0]:
|
||||
status = ServiceStatus.ghost
|
||||
elif i < status_distribution[0] + status_distribution[1]:
|
||||
status = ServiceStatus.active
|
||||
else:
|
||||
status = ServiceStatus.flagged
|
||||
|
||||
# Generate coordinates
|
||||
lat, lon = generate_hungarian_coordinates(i)
|
||||
|
||||
# Create WKT element for PostGIS
|
||||
location = WKTElement(f'POINT({lon} {lat})', srid=4326)
|
||||
|
||||
# Create service profile
|
||||
service = ServiceProfile(
|
||||
fingerprint=f"MOCK-{i:03d}-{datetime.utcnow().timestamp():.0f}",
|
||||
location=location,
|
||||
status=status,
|
||||
trust_score=30 if status == ServiceStatus.ghost else 75,
|
||||
is_verified=(status == ServiceStatus.active),
|
||||
contact_phone=f"+36 30 {1000 + i} {2000 + i}",
|
||||
contact_email=f"info@{service_names[i].replace(' ', '').lower()}.hu",
|
||||
website=f"https://{service_names[i].replace(' ', '').lower()}.hu",
|
||||
bio=f"{service_names[i]} - Profi autószerviz Magyarországon.",
|
||||
rating=4.0 + (i % 5) * 0.2,
|
||||
user_ratings_total=10 + i * 5,
|
||||
last_audit_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
db.add(service)
|
||||
inserted += 1
|
||||
|
||||
# Commit in batches
|
||||
if inserted % 5 == 0:
|
||||
await db.commit()
|
||||
|
||||
await db.commit()
|
||||
print(f"✅ {inserted} mock service profiles created (ghost:5, active:7, flagged:3)")
|
||||
return inserted
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main seed function."""
|
||||
print("🚀 Service Finder v2.0 Seed Script")
|
||||
print("=" * 50)
|
||||
|
||||
async with SessionLocal() as db:
|
||||
try:
|
||||
# 1. Cleanup (only in non-production)
|
||||
await cleanup_existing_seeds(db)
|
||||
|
||||
# 2. Create superadmin user
|
||||
admin = await create_superadmin(db)
|
||||
|
||||
# 3. Seed gamification levels
|
||||
await seed_gamification_levels(db)
|
||||
|
||||
# 4. Seed service profiles
|
||||
await seed_service_profiles(db, admin)
|
||||
|
||||
print("=" * 50)
|
||||
print("🎉 Seed completed successfully!")
|
||||
print(" - Superadmin: admin@servicefinder.hu / admin123")
|
||||
print(" - Gamification: Levels -3 to +10 configured")
|
||||
print(" - Service Profiles: 15 mock profiles with Hungarian coordinates")
|
||||
print(" - Status distribution: 5 ghost, 7 active, 3 flagged")
|
||||
|
||||
except Exception as e:
|
||||
await db.rollback()
|
||||
print(f"❌ Seed failed: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user