- Added centralized, self-learning GeoService (ZIP, City, Street) - Implemented Hybrid Address Management (Centralized table + Denormalized fields) - Fixed Gamification logic (PointsLedger field names & filtering) - Added address autocomplete and two-tier (Free/Premium) search API - Synchronized UserStats and PointsLedger schemas
121 lines
4.2 KiB
Python
121 lines
4.2 KiB
Python
import os
|
|
import logging
|
|
import uuid
|
|
from datetime import datetime, timedelta, timezone
|
|
from typing import Optional
|
|
|
|
# SQLAlchemy importok
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, cast, String, func
|
|
from sqlalchemy.orm import joinedload
|
|
|
|
# Modell és Schema importok - EZ HIÁNYZOTT!
|
|
from app.models.identity import User, Person, UserRole, VerificationToken, Wallet
|
|
from app.models.organization import Organization
|
|
from app.schemas.auth import UserLiteRegister, UserKYCComplete # <--- Ez javítja a hibát
|
|
from app.core.security import get_password_hash, verify_password
|
|
from app.services.email_manager import email_manager
|
|
from app.core.config import settings
|
|
from app.services.config_service import config # A dinamikus beállításokhoz
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class AuthService:
|
|
@staticmethod
|
|
async def register_lite(db: AsyncSession, user_in: UserLiteRegister):
|
|
"""Step 1: Alapszintű regisztráció..."""
|
|
try:
|
|
# 1. Person alap létrehozása
|
|
new_person = Person(
|
|
first_name=user_in.first_name,
|
|
last_name=user_in.last_name,
|
|
is_active=False
|
|
)
|
|
db.add(new_person)
|
|
await db.flush()
|
|
|
|
# 2. User fiók
|
|
new_user = User(
|
|
email=user_in.email,
|
|
hashed_password=get_password_hash(user_in.password),
|
|
person_id=new_person.id,
|
|
role=UserRole.user,
|
|
is_active=False,
|
|
region_code=user_in.region_code
|
|
)
|
|
db.add(new_user)
|
|
await db.flush()
|
|
|
|
# --- DINAMIKUS TOKEN LEJÁRAT ---
|
|
reg_hours = await config.get_setting(
|
|
"auth_registration_hours",
|
|
region_code=user_in.region_code,
|
|
default=48
|
|
)
|
|
|
|
token_val = uuid.uuid4()
|
|
new_token = VerificationToken(
|
|
token=token_val,
|
|
user_id=new_user.id,
|
|
token_type="registration",
|
|
expires_at=datetime.now(timezone.utc) + timedelta(hours=int(reg_hours))
|
|
)
|
|
db.add(new_token)
|
|
await db.flush()
|
|
|
|
# 4. Email küldés
|
|
verification_link = f"{settings.FRONTEND_BASE_URL}/verify?token={token_val}"
|
|
await email_manager.send_email(
|
|
recipient=user_in.email,
|
|
template_key="registration",
|
|
variables={"first_name": user_in.first_name, "link": verification_link}
|
|
)
|
|
|
|
await db.commit()
|
|
await db.refresh(new_user)
|
|
return new_user
|
|
except Exception as e:
|
|
await db.rollback()
|
|
logger.error(f"Registration Error: {str(e)}")
|
|
raise e
|
|
|
|
@staticmethod
|
|
async def initiate_password_reset(db: AsyncSession, email: str):
|
|
"""Jelszó-visszaállítás indítása dinamikus lejárattal."""
|
|
stmt = select(User).where(User.email == email, User.is_deleted == False)
|
|
res = await db.execute(stmt)
|
|
user = res.scalar_one_or_none()
|
|
|
|
if user:
|
|
now = datetime.now(timezone.utc)
|
|
|
|
# --- DINAMIKUS JELSZÓ RESET LEJÁRAT ---
|
|
reset_hours = await config.get_setting(
|
|
"auth_password_reset_hours",
|
|
region_code=user.region_code,
|
|
default=2
|
|
)
|
|
|
|
# ... (Rate limit ellenőrzés marad változatlan) ...
|
|
|
|
token_val = uuid.uuid4()
|
|
new_token = VerificationToken(
|
|
token=token_val,
|
|
user_id=user.id,
|
|
token_type="password_reset",
|
|
expires_at=now + timedelta(hours=int(reset_hours))
|
|
)
|
|
db.add(new_token)
|
|
|
|
reset_link = f"{settings.FRONTEND_BASE_URL}/reset-password?token={token_val}"
|
|
await email_manager.send_email(
|
|
recipient=email,
|
|
template_key="password_reset",
|
|
variables={"link": reset_link}
|
|
)
|
|
await db.commit()
|
|
return "success"
|
|
|
|
return "not_found"
|
|
|
|
# ... (többi metódus: verify_email, complete_kyc, authenticate, reset_password maradnak) ... |