1aaef71f52
Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack. Co-authored-by: Cursor <cursoragent@cursor.com>
50 lines
1.6 KiB
Python
50 lines
1.6 KiB
Python
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.config import settings
|
|
from app.core.security import create_access_token, hash_phone, mask_phone
|
|
from app.db.models import Tenant, User
|
|
from app.schemas.models import LoginRequest, LoginType
|
|
|
|
|
|
def authenticate(db: Session, body: LoginRequest) -> tuple[User, str]:
|
|
if body.login_type == LoginType.phone_code:
|
|
if body.code != settings.demo_sms_code:
|
|
raise ValueError("invalid_code")
|
|
phone = body.credential
|
|
phone_hash = hash_phone(phone)
|
|
user = db.scalar(select(User).where(User.phone_hash == phone_hash))
|
|
if not user:
|
|
tenant = db.scalar(select(Tenant).where(Tenant.name == "Demo Organization"))
|
|
if not tenant:
|
|
tenant = Tenant(name="Demo Organization", type="organization", status="active")
|
|
db.add(tenant)
|
|
db.flush()
|
|
user = User(
|
|
tenant_id=tenant.id,
|
|
phone=phone,
|
|
phone_hash=phone_hash,
|
|
role="parent",
|
|
status="active",
|
|
consent_signed=True,
|
|
)
|
|
db.add(user)
|
|
db.flush()
|
|
user.last_login_at = datetime.now(timezone.utc)
|
|
db.commit()
|
|
db.refresh(user)
|
|
token = create_access_token(user.id, user.role)
|
|
return user, token
|
|
|
|
raise ValueError("unsupported_login_type")
|
|
|
|
|
|
def user_to_dict(user: User) -> dict:
|
|
return {
|
|
"id": user.id,
|
|
"phoneMasked": mask_phone(user.phone or ""),
|
|
"role": user.role,
|
|
}
|