Files
aiagent/backend/app/models/user.py
renjianbo 41ffd31923 feat: P0 commercial readiness — password security, legal, account management
Backend changes for Phase A of v1.0 commercial launch:

P0-3: Password Security
- Remove hardcoded admin/123456 defaults from 34+ bootstrap scripts
- Add PLATFORM_USERNAME/PLATFORM_PASSWORD env vars to config
- Add PUT /api/v1/auth/change-password endpoint (requires old password)

P0-1: User Agreement & Privacy Policy
- Add agreed_terms/agreed_terms_version/agreed_terms_at to User model
- New GET /api/v1/legal/privacy and GET /api/v1/legal/terms endpoints
- New POST /api/v1/legal/agree endpoint to record consent
- Register endpoint now validates agreed_terms must be True

P0-6: Account Management
- Add phone/status/is_email_verified to User model
- Add DELETE /api/v1/auth/account for account deletion (with password confirmation)
- Add PUT /api/v1/auth/phone for phone binding
- Reject authentication for deleted accounts (status=deleted)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-01 22:01:54 +08:00

56 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
用户模型
"""
from sqlalchemy import Boolean, Column, String, DateTime, func
from sqlalchemy.dialects.mysql import CHAR
from sqlalchemy.orm import relationship
from app.core.database import Base
import uuid
class User(Base):
"""用户表"""
__tablename__ = "users"
id = Column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()), comment="用户ID")
username = Column(String(50), unique=True, nullable=False, comment="用户名")
email = Column(String(100), unique=True, nullable=False, comment="邮箱")
password_hash = Column(String(255), nullable=False, comment="密码哈希")
role = Column(String(20), default="user", comment="角色: admin/user保留字段用于向后兼容")
feishu_open_id = Column(String(64), nullable=True, comment="飞书用户 open_id用于推送通知")
feishu_default_agent_id = Column(CHAR(36), nullable=True, comment="飞书对话默认 Agent ID")
phone = Column(String(20), nullable=True, comment="手机号")
status = Column(String(20), default="active", comment="账号状态: active/disabled/deleted")
is_email_verified = Column(Boolean, default=False, comment="邮箱是否已验证")
agreed_terms = Column(Boolean, default=False, comment="是否同意用户协议")
agreed_terms_version = Column(String(20), nullable=True, comment="同意的协议版本")
agreed_terms_at = Column(DateTime, nullable=True, comment="同意协议的时间")
created_at = Column(DateTime, default=func.now(), comment="创建时间")
updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
# RBAC关系多对多
roles = relationship("Role", secondary="user_roles", back_populates="users")
def __repr__(self):
return f"<User(id={self.id}, username={self.username})>"
def has_permission(self, permission_code: str) -> bool:
"""检查用户是否有指定权限"""
# 如果是admin拥有所有权限
if self.role == "admin":
return True
# 检查用户的所有角色是否包含该权限
for role in self.roles:
for permission in role.permissions:
if permission.code == permission_code:
return True
return False
def has_role(self, role_name: str) -> bool:
"""检查用户是否有指定角色"""
# 如果是admin拥有所有角色
if self.role == "admin":
return True
return any(role.name == role_name for role in self.roles)