feat: Step 1 Auth complete - Token generation and email loop verified
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import uuid
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, text
|
||||
from app.models.identity import User, Person, UserRole
|
||||
from app.models.identity import User, Person, UserRole, VerificationToken
|
||||
from app.models.organization import Organization
|
||||
from app.schemas.auth import UserLiteRegister
|
||||
from app.core.security import get_password_hash, verify_password
|
||||
from app.services.email_manager import email_manager # Importálva!
|
||||
from app.services.email_manager import email_manager
|
||||
from app.core.config import settings
|
||||
|
||||
class AuthService:
|
||||
@staticmethod
|
||||
async def register_lite(db: AsyncSession, user_in: UserLiteRegister):
|
||||
"""Step 1: Lite regisztráció + Email küldés."""
|
||||
"""Step 1: Lite regisztráció kormányozható token élettartammal."""
|
||||
try:
|
||||
# 1. Person shell
|
||||
new_person = Person(
|
||||
@@ -32,20 +35,34 @@ class AuthService:
|
||||
db.add(new_user)
|
||||
await db.flush()
|
||||
|
||||
# 3. Email kiküldése (Mester Könyv v1.4 szerint)
|
||||
# 3. Biztonsági Token (Beállítható élettartam)
|
||||
# Default: 48 óra, ha nincs megadva a settingsben
|
||||
expire_hours = getattr(settings, "REGISTRATION_TOKEN_EXPIRE_HOURS", 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=expire_hours)
|
||||
)
|
||||
db.add(new_token)
|
||||
await db.flush()
|
||||
|
||||
# 4. Email küldés
|
||||
verification_link = f"{settings.FRONTEND_BASE_URL}/verify?token={token_val}"
|
||||
|
||||
try:
|
||||
await email_manager.send_email(
|
||||
recipient=user_in.email,
|
||||
template_key="registration", # 'registration.html' sablon használata
|
||||
template_key="registration",
|
||||
variables={
|
||||
"first_name": user_in.first_name,
|
||||
"login_url": "http://192.168.100.10:3000/login"
|
||||
},
|
||||
user_id=new_user.id
|
||||
"link": verification_link
|
||||
}
|
||||
)
|
||||
except Exception as email_err:
|
||||
# Az email hiba nem állítja meg a regisztrációt, csak logoljuk
|
||||
print(f"Email hiba regisztrációkor: {str(email_err)}")
|
||||
print(f"CRITICAL: Email sending failed: {str(email_err)}")
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(new_user)
|
||||
@@ -54,6 +71,43 @@ class AuthService:
|
||||
await db.rollback()
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
async def verify_email(db: AsyncSession, token_str: str):
|
||||
"""Token ellenőrzése és regisztráció megerősítése."""
|
||||
try:
|
||||
# Token UUID-vá alakítása az összehasonlításhoz
|
||||
token_uuid = uuid.UUID(token_str)
|
||||
|
||||
stmt = select(VerificationToken).where(
|
||||
VerificationToken.token == token_uuid,
|
||||
VerificationToken.is_used == False,
|
||||
VerificationToken.expires_at > datetime.now(timezone.utc)
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
token_obj = result.scalar_one_or_none()
|
||||
|
||||
if not token_obj:
|
||||
return False
|
||||
|
||||
# Token elhasználása
|
||||
token_obj.is_used = True
|
||||
|
||||
# User keresése és aktiválása (Email megerősítve)
|
||||
user_stmt = select(User).where(User.id == token_obj.user_id)
|
||||
user_res = await db.execute(user_stmt)
|
||||
user = user_res.scalar_one_or_none()
|
||||
if user:
|
||||
# Figyelem: A Master Book szerint ez még nem teljes aktiválás (is_active: false)
|
||||
# de jelölhetjük, hogy az e-mail már OK.
|
||||
pass
|
||||
|
||||
await db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Verify error: {e}")
|
||||
await db.rollback()
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
async def authenticate(db: AsyncSession, email: str, password: str):
|
||||
stmt = select(User).where(User.email == email, User.is_deleted == False)
|
||||
@@ -66,17 +120,30 @@ class AuthService:
|
||||
|
||||
@staticmethod
|
||||
async def initiate_password_reset(db: AsyncSession, email: str):
|
||||
"""Jelszó-emlékeztető email küldése."""
|
||||
"""Jelszó-emlékeztető kormányozható élettartammal."""
|
||||
stmt = select(User).where(User.email == email, User.is_deleted == False)
|
||||
res = await db.execute(stmt)
|
||||
user = res.scalar_one_or_none()
|
||||
|
||||
if user:
|
||||
expire_hours = getattr(settings, "PASSWORD_RESET_TOKEN_EXPIRE_HOURS", 1)
|
||||
token_val = uuid.uuid4()
|
||||
new_token = VerificationToken(
|
||||
token=token_val,
|
||||
user_id=user.id,
|
||||
token_type="password_reset",
|
||||
expires_at=datetime.now(timezone.utc) + timedelta(hours=expire_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={"reset_token": "IDE_JÖN_MAJD_A_TOKEN"},
|
||||
variables={"link": reset_link},
|
||||
user_id=user.id
|
||||
)
|
||||
await db.commit()
|
||||
return True
|
||||
return False
|
||||
Reference in New Issue
Block a user