teljes backend_mentés

This commit is contained in:
Roo
2026-03-22 18:59:27 +00:00
parent 5d44339f21
commit 5d96b00f81
34 changed files with 2575 additions and 977 deletions

View 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())