Initial commit: Happy Up monorepo through Sprint 5.
Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user