2026.06.05 frontend javítgatás és új belépési logika megvalósítva
This commit is contained in:
@@ -93,7 +93,7 @@ class AuthService:
|
||||
new_person = Person(
|
||||
first_name=user_in.first_name,
|
||||
last_name=user_in.last_name,
|
||||
is_active=False,
|
||||
is_active=False, # Email verification required before activation
|
||||
identity_docs={}, # EXPLICIT BEÁLLÍTÁS A DB HIBA ELKERÜLÉSÉRE
|
||||
ice_contact={}, # EXPLICIT BEÁLLÍTÁS A DB HIBA ELKERÜLÉSÉRE
|
||||
lifetime_xp=0, # default -1, de explicit 0
|
||||
@@ -117,7 +117,7 @@ class AuthService:
|
||||
hashed_password=get_password_hash(user_in.password),
|
||||
person_id=new_person.id,
|
||||
role=assigned_role,
|
||||
is_active=False,
|
||||
is_active=False, # Email verification required before activation
|
||||
is_deleted=False,
|
||||
region_code=user_in.region_code,
|
||||
preferred_language=user_in.lang,
|
||||
@@ -217,6 +217,8 @@ class AuthService:
|
||||
user.person_id = shadow_person.id
|
||||
|
||||
# Frissítjük a megtalált Person rekordot a KYC adatokkal
|
||||
if kyc_in.first_name: shadow_person.first_name = kyc_in.first_name
|
||||
if kyc_in.last_name: shadow_person.last_name = kyc_in.last_name
|
||||
shadow_person.mothers_last_name = kyc_in.mothers_last_name
|
||||
shadow_person.mothers_first_name = kyc_in.mothers_first_name
|
||||
shadow_person.birth_place = kyc_in.birth_place
|
||||
@@ -231,6 +233,8 @@ class AuthService:
|
||||
|
||||
p = shadow_person
|
||||
else:
|
||||
if kyc_in.first_name: p.first_name = kyc_in.first_name
|
||||
if kyc_in.last_name: p.last_name = kyc_in.last_name
|
||||
p.mothers_last_name = kyc_in.mothers_last_name
|
||||
p.mothers_first_name = kyc_in.mothers_first_name
|
||||
p.birth_place = kyc_in.birth_place
|
||||
@@ -314,7 +318,10 @@ class AuthService:
|
||||
|
||||
@staticmethod
|
||||
async def verify_email(db: AsyncSession, token_str: str):
|
||||
""" Email megerősítés. """
|
||||
"""
|
||||
Email megerősítés.
|
||||
Visszaadja az aktivált User objektumot sikeres verifikáció után (Magic Link támogatás).
|
||||
"""
|
||||
try:
|
||||
token_uuid = uuid.UUID(token_str)
|
||||
stmt = select(VerificationToken).where(and_(
|
||||
@@ -323,25 +330,28 @@ class AuthService:
|
||||
VerificationToken.expires_at > datetime.now(timezone.utc)
|
||||
))
|
||||
token = (await db.execute(stmt)).scalar_one_or_none()
|
||||
if not token: return False
|
||||
if not token: return None
|
||||
|
||||
token.is_used = True
|
||||
|
||||
# Activate user
|
||||
user_stmt = select(User).where(User.id == token.user_id)
|
||||
user = (await db.execute(user_stmt)).scalar_one_or_none()
|
||||
if user:
|
||||
user.is_active = True
|
||||
|
||||
# Activate person
|
||||
person_stmt = select(Person).where(Person.user_id == user.id)
|
||||
person = (await db.execute(person_stmt)).scalar_one_or_none()
|
||||
if person:
|
||||
person.is_active = True
|
||||
if not user: return None
|
||||
|
||||
user.is_active = True
|
||||
|
||||
# Activate person
|
||||
person_stmt = select(Person).where(Person.user_id == user.id)
|
||||
person = (await db.execute(person_stmt)).scalar_one_or_none()
|
||||
if person:
|
||||
person.is_active = True
|
||||
|
||||
await db.commit()
|
||||
return True
|
||||
except: return False
|
||||
return user # Return the activated User object
|
||||
except Exception as e:
|
||||
logger.error(f"Email verification error: {e}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
async def initiate_password_reset(db: AsyncSession, email: str):
|
||||
@@ -349,23 +359,43 @@ class AuthService:
|
||||
stmt = select(User).where(and_(User.email == email, User.is_deleted == False))
|
||||
user = (await db.execute(stmt)).scalar_one_or_none()
|
||||
|
||||
if user:
|
||||
# Dinamikus lejárat az adminból
|
||||
reset_h = await config.get_setting(db, "auth_password_reset_hours", region_code=user.region_code, default=2)
|
||||
token_val = uuid.uuid4()
|
||||
db.add(VerificationToken(
|
||||
token=token_val, user_id=user.id, token_type="password_reset",
|
||||
expires_at=datetime.now(timezone.utc) + timedelta(hours=int(reset_h))
|
||||
))
|
||||
|
||||
link = f"{settings.FRONTEND_BASE_URL}/reset-password?token={token_val}"
|
||||
await email_manager.send_email(
|
||||
recipient=email, template_key="pwd_reset",
|
||||
variables={"link": link}, lang=user.preferred_language
|
||||
if not user:
|
||||
return "not_found"
|
||||
|
||||
# Ha a felhasználó létezik, de inaktív, dobjunk hibát
|
||||
if not user.is_active:
|
||||
logger.warning(f"Password reset requested for inactive user: {email}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="AUTH.USER_INACTIVE"
|
||||
)
|
||||
await db.commit()
|
||||
return "success"
|
||||
return "not_found"
|
||||
|
||||
# Dinamikus lejárat az adminból
|
||||
reset_h = await config.get_setting(db, "auth_password_reset_hours", region_code=user.region_code, default=2)
|
||||
token_val = uuid.uuid4()
|
||||
db.add(VerificationToken(
|
||||
token=token_val, user_id=user.id, token_type="password_reset",
|
||||
expires_at=datetime.now(timezone.utc) + timedelta(hours=int(reset_h))
|
||||
))
|
||||
|
||||
link = f"{settings.FRONTEND_BASE_URL}/reset-password?token={token_val}"
|
||||
logger.info(f"Email küldés indítása (password reset) ide: {email}...")
|
||||
result = await email_manager.send_email(
|
||||
recipient=email, template_key="pwd_reset",
|
||||
variables={"link": link}, lang=user.preferred_language
|
||||
)
|
||||
logger.info(f"Email küldés eredménye (password reset): {result}")
|
||||
|
||||
# Ha az email küldés hibát dobott, ne titkoljuk el
|
||||
if result.get("status") == "error":
|
||||
logger.error(f"Password reset email FAILED for {email}: {result.get('message')}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Email küldési hiba: {result.get('message')}"
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
return "success"
|
||||
|
||||
@staticmethod
|
||||
async def reset_password(db: AsyncSession, email: str, token_str: str, new_password: str):
|
||||
@@ -396,6 +426,57 @@ class AuthService:
|
||||
raise
|
||||
except: return False
|
||||
|
||||
@staticmethod
|
||||
async def resend_verification(db: AsyncSession, email: str):
|
||||
"""
|
||||
Aktiváló e-mail újraküldése.
|
||||
Ellenőrzi, hogy a felhasználó létezik, de még nem aktív (is_active == False),
|
||||
generál egy új verifikációs tokent, és kiküldi az e-mailt.
|
||||
"""
|
||||
# Eager load person relationship to avoid async lazy-load issue
|
||||
stmt = select(User).options(joinedload(User.person)).where(
|
||||
and_(User.email == email, User.is_deleted == False)
|
||||
)
|
||||
user = (await db.execute(stmt)).unique().scalar_one_or_none()
|
||||
|
||||
if not user:
|
||||
# Ne áruljuk el, hogy létezik-e az email — biztonsági okokból mindig sikert adunk
|
||||
logger.info(f"Resend verification requested for non-existent email: {email}")
|
||||
return "not_found"
|
||||
|
||||
if user.is_active:
|
||||
logger.info(f"Resend verification requested for already active user: {email}")
|
||||
return "already_active"
|
||||
|
||||
# Dinamikus lejárat az adminból
|
||||
reg_token_hours = await config.get_setting(db, "auth_registration_hours", region_code=user.region_code, default=48)
|
||||
token_val = uuid.uuid4()
|
||||
|
||||
db.add(VerificationToken(
|
||||
token=token_val,
|
||||
user_id=user.id,
|
||||
token_type="registration",
|
||||
expires_at=datetime.now(timezone.utc) + timedelta(hours=int(reg_token_hours))
|
||||
))
|
||||
|
||||
# Email küldés — user.person már eager-loaded, így nem okoz MissingGreenlet hibát
|
||||
verification_link = f"{settings.FRONTEND_BASE_URL}/verify?token={token_val}"
|
||||
person = user.person
|
||||
first_name = person.first_name if person else user.email
|
||||
|
||||
logger.info(f"Email küldés indítása (resend verification) ide: {email}...")
|
||||
result = await email_manager.send_email(
|
||||
recipient=email,
|
||||
template_key="reg",
|
||||
variables={"first_name": first_name, "link": verification_link},
|
||||
lang=user.preferred_language
|
||||
)
|
||||
logger.info(f"Email küldés eredménye (resend verification): {result}")
|
||||
|
||||
await db.commit()
|
||||
logger.info(f"Resend verification email sent to {email}")
|
||||
return "success"
|
||||
|
||||
@staticmethod
|
||||
async def soft_delete_user(db: AsyncSession, user_id: int, reason: str, actor_id: int):
|
||||
""" Felhasználó törlése (Soft-Delete) auditálással. """
|
||||
|
||||
Reference in New Issue
Block a user