diff --git a/api/app/controllers/user_memory_controllers.py b/api/app/controllers/user_memory_controllers.py index 3ce1df6e..dbdc0a16 100644 --- a/api/app/controllers/user_memory_controllers.py +++ b/api/app/controllers/user_memory_controllers.py @@ -24,8 +24,9 @@ from app.schemas.response_schema import ApiResponse from app.schemas.memory_storage_schema import GenerateCacheRequest from app.repositories.workspace_repository import WorkspaceRepository from app.schemas.end_user_schema import ( - EndUserProfileResponse, - EndUserProfileUpdate, + UserAliasResponse, + UserAliasCreate, + UserAliasUpdate, ) from app.models.end_user_model import EndUser from app.dependencies import get_current_user @@ -336,103 +337,178 @@ async def get_community_graph_data_api( api_logger.error(f"社区图谱查询失败: end_user_id={end_user_id}, error={str(e)}") return fail(BizCode.INTERNAL_ERROR, "社区图谱查询失败", str(e)) +#=======================用户别名及信息接口======================= -@router.get("/read_end_user/profile", response_model=ApiResponse) -async def get_end_user_profile( - end_user_id: str, - current_user: User = Depends(get_current_user), - db: Session = Depends(get_db), +@router.get("/user_alias", response_model=ApiResponse) +async def get_user_alias( + user_alias_id: str, + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db), ) -> dict: - workspace_id = current_user.current_workspace_id - workspace_repo = WorkspaceRepository(db) - workspace_models = workspace_repo.get_workspace_models_configs(workspace_id) + """ + 查询用户别名记录 + + 根据 user_alias_id 查询单条用户别名记录。 + """ + workspace_id = current_user.current_workspace_id - if workspace_models: - model_id = workspace_models.get("llm", None) - else: - model_id = None - # 检查用户是否已选择工作空间 if workspace_id is None: - api_logger.warning(f"用户 {current_user.username} 尝试查询用户信息但未选择工作空间") + api_logger.warning(f"用户 {current_user.username} 尝试查询用户别名但未选择工作空间") return fail(BizCode.INVALID_PARAMETER, "请先切换到一个工作空间", "current_workspace_id is None") api_logger.info( - f"用户信息查询请求: end_user_id={end_user_id}, user={current_user.username}, " + f"查询用户别名请求: user_alias_id={user_alias_id}, user={current_user.username}, " f"workspace={workspace_id}" ) - try: - # 查询终端用户 - end_user = db.query(EndUser).filter(EndUser.id == end_user_id).first() - - if not end_user: - api_logger.warning(f"终端用户不存在: end_user_id={end_user_id}") - return fail(BizCode.INVALID_PARAMETER, "终端用户不存在", f"end_user_id={end_user_id}") - # 构建响应数据 - profile_data = EndUserProfileResponse( - id=end_user.id, - other_name=end_user.other_name, - position=end_user.position, - department=end_user.department, - contact=end_user.contact, - phone=end_user.phone, - hire_date=end_user.hire_date, - updatetime_profile=end_user.updatetime_profile - ) - - api_logger.info(f"成功获取用户信息: end_user_id={end_user_id}") - return success(data=UserMemoryService.convert_profile_to_dict_with_timestamp(profile_data), msg="查询成功") - - except Exception as e: - api_logger.error(f"用户信息查询失败: end_user_id={end_user_id}, error={str(e)}") - return fail(BizCode.INTERNAL_ERROR, "用户信息查询失败", str(e)) - - -@router.post("/updated_end_user/profile", response_model=ApiResponse) -async def update_end_user_profile( - profile_update: EndUserProfileUpdate, - current_user: User = Depends(get_current_user), - db: Session = Depends(get_db), -) -> dict: - """ - 更新终端用户的基本信息 - - 该接口可以更新用户的姓名、职位、部门、联系方式、电话和入职日期等信息。 - 所有字段都是可选的,只更新提供的字段。 - """ - workspace_id = current_user.current_workspace_id - end_user_id = profile_update.end_user_id - - # 验证工作空间 - if workspace_id is None: - api_logger.warning(f"用户 {current_user.username} 尝试更新用户信息但未选择工作空间") - return fail(BizCode.INVALID_PARAMETER, "请先切换到一个工作空间", "current_workspace_id is None") - - api_logger.info( - f"用户信息更新请求: end_user_id={end_user_id}, user={current_user.username}, " - f"workspace={workspace_id}" - ) - - # 调用 Service 层处理业务逻辑 - result = user_memory_service.update_end_user_profile(db, end_user_id, profile_update) + result = user_memory_service.get_user_alias(db, user_alias_id) if result["success"]: - api_logger.info(f"成功更新用户信息: end_user_id={end_user_id}") - return success(data=result["data"], msg="更新成功") + api_logger.info(f"成功查询用户别名: user_alias_id={user_alias_id}") + return success(data=result["data"], msg="查询成功") else: error_msg = result["error"] - api_logger.error(f"用户信息更新失败: end_user_id={end_user_id}, error={error_msg}") + api_logger.error(f"查询用户别名失败: user_alias_id={user_alias_id}, error={error_msg}") + + if error_msg == "用户别名记录不存在": + return fail(BizCode.USER_NOT_FOUND, "用户别名记录不存在", error_msg) + elif error_msg == "无效的用户别名记录ID格式": + return fail(BizCode.INVALID_USER_ID, "无效的用户别名记录ID格式", error_msg) + else: + return fail(BizCode.INTERNAL_ERROR, "查询用户别名失败", error_msg) - # 根据错误类型映射到合适的业务错误码 + +@router.post("/user_alias/create", response_model=ApiResponse) +async def create_user_alias( + alias_create: UserAliasCreate, + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db), +) -> dict: + """ + 创建用户别名记录 + + 为指定用户创建一条新的别名记录,支持多个别名。 + """ + workspace_id = current_user.current_workspace_id + end_user_id = alias_create.end_user_id + + if workspace_id is None: + api_logger.warning(f"用户 {current_user.username} 尝试创建别名但未选择工作空间") + return fail(BizCode.INVALID_PARAMETER, "请先切换到一个工作空间", "current_workspace_id is None") + + api_logger.info( + f"创建用户别名请求: end_user_id={end_user_id}, aliases={alias_create.aliases}, " + f"user={current_user.username}, workspace={workspace_id}" + ) + + result = user_memory_service.create_user_alias( + db, end_user_id, alias_create.other_name, alias_create.aliases, alias_create.meta_data + ) + + if result["success"]: + api_logger.info(f"成功创建用户别名: end_user_id={end_user_id}") + return success(data=result["data"], msg="创建成功") + else: + error_msg = result["error"] + api_logger.error(f"用户别名创建失败: end_user_id={end_user_id}, error={error_msg}") + if error_msg == "终端用户不存在": return fail(BizCode.USER_NOT_FOUND, "终端用户不存在", error_msg) elif error_msg == "无效的用户ID格式": return fail(BizCode.INVALID_USER_ID, "无效的用户ID格式", error_msg) else: - # 只有未预期的错误才使用 INTERNAL_ERROR - return fail(BizCode.INTERNAL_ERROR, "用户信息更新失败", error_msg) + return fail(BizCode.INTERNAL_ERROR, "用户别名创建失败", error_msg) +@router.post("/user_alias/updated", response_model=ApiResponse) +async def update_user_alias( + alias_update: UserAliasUpdate, + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db), +) -> dict: + """ + 更新用户别名记录 + + 根据 user_alias_id 更新用户别名记录,支持批量更新多个别名。 + + 示例请求体: + { + "user_alias_id": "2d4f57d4-639b-47aa-937a-d461bc2c2d53", + "other_name": "张三1", + "aliases": ["小张", "张工"], + "meta_data": {"position": "工程师", "department": "技术部"} + } + """ + workspace_id = current_user.current_workspace_id + user_alias_id = alias_update.user_alias_id + + if workspace_id is None: + api_logger.warning(f"用户 {current_user.username} 尝试更新用户别名但未选择工作空间") + return fail(BizCode.INVALID_PARAMETER, "请先切换到一个工作空间", "current_workspace_id is None") + + api_logger.info( + f"更新用户别名请求: user_alias_id={user_alias_id}, user={current_user.username}, " + f"workspace={workspace_id}" + ) + + # 获取更新数据(排除 user_alias_id) + update_data = alias_update.model_dump(exclude_unset=True, exclude={'user_alias_id'}) + + result = user_memory_service.update_user_alias(db, user_alias_id, update_data) + + if result["success"]: + api_logger.info(f"成功更新用户别名: user_alias_id={user_alias_id}") + return success(data=result["data"], msg="更新成功") + else: + error_msg = result["error"] + api_logger.error(f"用户别名更新失败: user_alias_id={user_alias_id}, error={error_msg}") + + if error_msg == "用户别名记录不存在": + return fail(BizCode.USER_NOT_FOUND, "用户别名记录不存在", error_msg) + elif error_msg == "无效的用户别名记录ID格式": + return fail(BizCode.INVALID_USER_ID, "无效的用户别名记录ID格式", error_msg) + else: + return fail(BizCode.INTERNAL_ERROR, "用户别名更新失败", error_msg) + + +@router.delete("/user_alias", response_model=ApiResponse) +async def delete_user_alias( + user_alias_id: str, + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db), +) -> dict: + """ + 删除用户别名记录 + + 根据 user_alias_id 删除指定的用户别名记录。 + """ + workspace_id = current_user.current_workspace_id + + if workspace_id is None: + api_logger.warning(f"用户 {current_user.username} 尝试删除别名但未选择工作空间") + return fail(BizCode.INVALID_PARAMETER, "请先切换到一个工作空间", "current_workspace_id is None") + + api_logger.info( + f"删除用户别名请求: user_alias_id={user_alias_id}, user={current_user.username}, " + f"workspace={workspace_id}" + ) + + result = user_memory_service.delete_user_alias(db, user_alias_id) + + if result["success"]: + api_logger.info(f"成功删除用户别名: user_alias_id={user_alias_id}") + return success(data=result["data"], msg="删除成功") + else: + error_msg = result["error"] + api_logger.error(f"用户别名删除失败: user_alias_id={user_alias_id}, error={error_msg}") + + if error_msg == "用户别名记录不存在": + return fail(BizCode.USER_NOT_FOUND, "用户别名记录不存在", error_msg) + elif error_msg == "无效的用户别名记录ID格式": + return fail(BizCode.INVALID_USER_ID, "无效的用户别名记录ID格式", error_msg) + else: + return fail(BizCode.INTERNAL_ERROR, "用户别名删除失败", error_msg) + @router.get("/memory_space/timeline_memories", response_model=ApiResponse) async def memory_space_timeline_of_shared_memories( id: str, label: str, diff --git a/api/app/models/__init__.py b/api/app/models/__init__.py index c6098a6d..22dd4851 100644 --- a/api/app/models/__init__.py +++ b/api/app/models/__init__.py @@ -16,6 +16,7 @@ from .agent_app_config_model import AgentConfig from .app_release_model import AppRelease from .memory_increment_model import MemoryIncrement from .end_user_model import EndUser +from .user_alias_model import UserAlias from .appshare_model import AppShare from .release_share_model import ReleaseShare from .conversation_model import Conversation, Message @@ -60,6 +61,7 @@ __all__ = [ "AppRelease", "MemoryIncrement", "EndUser", + "UserAlias", "AppShare", "ReleaseShare", "Conversation", diff --git a/api/app/models/end_user_model.py b/api/app/models/end_user_model.py index 60600fcf..a30e1dcb 100644 --- a/api/app/models/end_user_model.py +++ b/api/app/models/end_user_model.py @@ -30,14 +30,6 @@ class EndUser(Base): comment="关联的记忆配置ID" ) - # 用户基本信息字段 - position = Column(String, nullable=True, comment="职位") - department = Column(String, nullable=True, comment="部门") - contact = Column(String, nullable=True, comment="联系方式") - phone = Column(String, nullable=True, comment="电话") - hire_date = Column(DateTime, nullable=True, comment="入职日期") - updatetime_profile = Column(DateTime, nullable=True, comment="核心档案信息最后更新时间") - # 用户摘要四个维度 - User Summary Four Dimensions user_summary = Column(Text, nullable=True, comment="缓存的用户摘要(基本介绍)") personality_traits = Column(Text, nullable=True, comment="性格特点") @@ -65,4 +57,7 @@ class EndUser(Base): ) # 与 WorkSpace 的反向关系 - workspace = relationship("Workspace", back_populates="end_users") \ No newline at end of file + workspace = relationship("Workspace", back_populates="end_users") + + # 与 UserAlias 的反向关系 + aliases = relationship("UserAlias", back_populates="end_user", cascade="all, delete-orphan") \ No newline at end of file diff --git a/api/app/models/user_alias_model.py b/api/app/models/user_alias_model.py new file mode 100644 index 00000000..ad862ead --- /dev/null +++ b/api/app/models/user_alias_model.py @@ -0,0 +1,24 @@ +import datetime +import uuid + +from sqlalchemy import Column, DateTime, ForeignKey, String, Text +from sqlalchemy.dialects.postgresql import UUID, JSONB +from sqlalchemy.orm import relationship + +from app.db import Base + + +class UserAlias(Base): + """用户别名表 - 存储用户的别名信息""" + __tablename__ = "user_aliases" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False, index=True) + end_user_id = Column(UUID(as_uuid=True), ForeignKey("end_users.id"), nullable=False, index=True, comment="关联的终端用户ID") + other_name = Column(String, nullable=False, comment="关联的用户名称") + aliases = Column(JSONB, nullable=True, comment="用户别名列表(JSON数组)") + meta_data = Column(JSONB, nullable=True, comment="用户相关的扩展信息(JSON格式)") + created_at = Column(DateTime, default=datetime.datetime.now, comment="创建时间") + updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间") + + # 与 EndUser 的关系 + end_user = relationship("EndUser", back_populates="aliases") diff --git a/api/app/repositories/user_alias_repository.py b/api/app/repositories/user_alias_repository.py new file mode 100644 index 00000000..96f8a778 --- /dev/null +++ b/api/app/repositories/user_alias_repository.py @@ -0,0 +1,90 @@ +""" +用户别名仓储层 +""" +import uuid +from typing import List, Optional +from sqlalchemy.orm import Session + +from app.models.user_alias_model import UserAlias +from app.core.logging_config import get_logger + +logger = get_logger(__name__) + + +class UserAliasRepository: + """用户别名仓储类""" + + def __init__(self, db: Session): + self.db = db + + def create(self, end_user_id: uuid.UUID, other_name: str, alias: str = None, meta_data: dict = None) -> UserAlias: + """创建用户别名""" + user_alias = UserAlias( + end_user_id=end_user_id, + other_name=other_name, + alias=alias, + meta_data=meta_data + ) + self.db.add(user_alias) + self.db.commit() + self.db.refresh(user_alias) + logger.info(f"创建用户别名: end_user_id={end_user_id}, alias={alias}") + return user_alias + + def get_by_id(self, alias_id: uuid.UUID) -> Optional[UserAlias]: + """根据ID获取别名""" + return self.db.query(UserAlias).filter(UserAlias.id == alias_id).first() + + def get_by_end_user_id(self, end_user_id: uuid.UUID) -> List[UserAlias]: + """获取用户的所有别名""" + return self.db.query(UserAlias).filter(UserAlias.end_user_id == end_user_id).all() + + def update(self, alias_id: uuid.UUID, alias: str = None, meta_data: dict = None) -> Optional[UserAlias]: + """更新别名""" + user_alias = self.get_by_id(alias_id) + if user_alias: + if alias is not None: + user_alias.alias = alias + if meta_data is not None: + user_alias.meta_data = meta_data + self.db.commit() + self.db.refresh(user_alias) + logger.info(f"更新用户别名: alias_id={alias_id}") + return user_alias + + def delete(self, alias_id: uuid.UUID) -> bool: + """删除别名""" + user_alias = self.get_by_id(alias_id) + if user_alias: + self.db.delete(user_alias) + self.db.commit() + logger.info(f"删除用户别名: alias_id={alias_id}") + return True + return False + + def delete_by_end_user_id(self, end_user_id: uuid.UUID) -> int: + """删除用户的所有别名""" + count = self.db.query(UserAlias).filter(UserAlias.end_user_id == end_user_id).delete() + self.db.commit() + logger.info(f"删除用户所有别名: end_user_id={end_user_id}, count={count}") + return count + + def batch_create(self, end_user_id: uuid.UUID, other_name: str, aliases: List[str]) -> List[UserAlias]: + """批量创建别名""" + user_aliases = [] + for alias in aliases: + if alias and alias.strip(): + user_alias = UserAlias( + end_user_id=end_user_id, + other_name=other_name, + alias=alias.strip() + ) + self.db.add(user_alias) + user_aliases.append(user_alias) + + self.db.commit() + for user_alias in user_aliases: + self.db.refresh(user_alias) + + logger.info(f"批量创建用户别名: end_user_id={end_user_id}, count={len(user_aliases)}") + return user_aliases diff --git a/api/app/schemas/end_user_schema.py b/api/app/schemas/end_user_schema.py index 09671b91..d541ba47 100644 --- a/api/app/schemas/end_user_schema.py +++ b/api/app/schemas/end_user_schema.py @@ -17,41 +17,35 @@ class EndUser(BaseModel): created_at: datetime.datetime = Field(description="创建时间", default_factory=datetime.datetime.now) updated_at: datetime.datetime = Field(description="更新时间", default_factory=datetime.datetime.now) - # 用户基本信息字段 - position: Optional[str] = Field(description="职位", default=None) - department: Optional[str] = Field(description="部门", default=None) - contact: Optional[str] = Field(description="联系方式", default=None) - phone: Optional[str] = Field(description="电话", default=None) - hire_date: Optional[datetime.datetime] = Field(description="入职日期", default=None) - updatetime_profile: Optional[datetime.datetime] = Field(description="核心档案信息最后更新时间", default=None) - # 用户摘要和洞察更新时间 user_summary_updated_at: Optional[datetime.datetime] = Field(description="用户摘要最后更新时间", default=None) memory_insight_updated_at: Optional[datetime.datetime] = Field(description="洞察报告最后更新时间", default=None) -class EndUserProfileResponse(BaseModel): - """终端用户基本信息响应模型""" +class UserAliasResponse(BaseModel): + """用户别名响应模型""" model_config = ConfigDict(from_attributes=True) - id: uuid.UUID = Field(description="终端用户ID") - other_name: Optional[str] = Field(description="其他名称", default="") - position: Optional[str] = Field(description="职位", default=None) - department: Optional[str] = Field(description="部门", default=None) - contact: Optional[str] = Field(description="联系方式", default=None) - phone: Optional[str] = Field(description="电话", default=None) - hire_date: Optional[datetime.datetime] = Field(description="入职日期", default=None) - updatetime_profile: Optional[datetime.datetime] = Field(description="核心档案信息最后更新时间", default=None) - - - -class EndUserProfileUpdate(BaseModel): - """终端用户基本信息更新请求模型""" - end_user_id: str = Field(description="终端用户ID") - other_name: Optional[str] = Field(description="其他名称", default="") + user_alias_id: uuid.UUID = Field(description="用户别名记录ID") + end_user_id: uuid.UUID = Field(description="终端用户ID") + other_name: str = Field(description="用户名称") aliases: Optional[List[str]] = Field(description="别名列表", default=None) - position: Optional[str] = Field(description="职位", default=None) - department: Optional[str] = Field(description="部门", default=None) - contact: Optional[str] = Field(description="联系方式", default=None) - phone: Optional[str] = Field(description="电话", default=None) - hire_date: Optional[int] = Field(description="入职日期(时间戳,毫秒)", default=None) \ No newline at end of file + meta_data: Optional[dict] = Field(description="扩展信息", default=None) + created_at: datetime.datetime = Field(description="创建时间") + updated_at: datetime.datetime = Field(description="更新时间") + + +class UserAliasCreate(BaseModel): + """创建用户别名请求模型""" + end_user_id: str = Field(description="终端用户ID") + other_name: str = Field(description="用户名称") + aliases: Optional[List[str]] = Field(description="别名列表", default=None) + meta_data: Optional[dict] = Field(description="扩展信息", default=None) + + +class UserAliasUpdate(BaseModel): + """更新用户别名请求模型""" + user_alias_id: str = Field(description="用户别名记录ID") + other_name: Optional[str] = Field(description="用户名称", default=None) + aliases: Optional[List[str]] = Field(description="别名列表", default=None) + meta_data: Optional[dict] = Field(description="扩展信息", default=None) \ No newline at end of file diff --git a/api/app/schemas/user_alias_schema.py b/api/app/schemas/user_alias_schema.py new file mode 100644 index 00000000..847c5c5d --- /dev/null +++ b/api/app/schemas/user_alias_schema.py @@ -0,0 +1,33 @@ +import uuid +import datetime +from typing import Optional, Dict, Any +from pydantic import BaseModel, Field +from pydantic import ConfigDict + + +class UserAliasBase(BaseModel): + """用户别名基础模型""" + other_name: str = Field(description="关联的用户名称") + alias: Optional[str] = Field(description="用户别名", default=None) + meta_data: Optional[Dict[str, Any]] = Field(description="用户相关的扩展信息", default=None) + + +class UserAliasCreate(UserAliasBase): + """创建用户别名请求模型""" + end_user_id: uuid.UUID = Field(description="关联的终端用户ID") + + +class UserAliasUpdate(BaseModel): + """更新用户别名请求模型""" + alias: Optional[str] = Field(description="用户别名", default=None) + meta_data: Optional[Dict[str, Any]] = Field(description="用户相关的扩展信息", default=None) + + +class UserAliasResponse(UserAliasBase): + """用户别名响应模型""" + model_config = ConfigDict(from_attributes=True) + + id: uuid.UUID = Field(description="别名ID") + end_user_id: uuid.UUID = Field(description="关联的终端用户ID") + created_at: datetime.datetime = Field(description="创建时间") + updated_at: datetime.datetime = Field(description="更新时间") diff --git a/api/app/services/user_memory_service.py b/api/app/services/user_memory_service.py index 585fdd78..5aa589e8 100644 --- a/api/app/services/user_memory_service.py +++ b/api/app/services/user_memory_service.py @@ -361,29 +361,105 @@ class UserMemoryService: if hasattr(original_value, 'timestamp'): data[key] = UserMemoryService._datetime_to_timestamp(original_value) return data - - def update_end_user_profile( + # ======================== 用户别名及信息 ======================== + def get_user_alias( self, db: Session, - end_user_id: str, - profile_update: Any + user_alias_id: str ) -> Dict[str, Any]: """ - 更新终端用户的基本信息 + 查询单个用户别名记录 Args: db: 数据库会话 - end_user_id: 终端用户ID (UUID) - profile_update: 包含更新字段的 Pydantic 模型 + user_alias_id: 用户别名记录ID (UUID) Returns: { "success": bool, - "data": dict, # 更新后的用户档案数据 + "data": dict, "error": Optional[str] } """ try: + from app.models.user_alias_model import UserAlias + + # 转换为UUID并查询 + alias_uuid = uuid.UUID(user_alias_id) + user_alias_record = db.query(UserAlias).filter(UserAlias.id == alias_uuid).first() + + if not user_alias_record: + logger.warning(f"用户别名记录不存在: user_alias_id={user_alias_id}") + return { + "success": False, + "data": None, + "error": "用户别名记录不存在" + } + + # 构建响应数据 + from app.schemas.end_user_schema import UserAliasResponse + response_data = UserAliasResponse( + user_alias_id=user_alias_record.id, + end_user_id=user_alias_record.end_user_id, + other_name=user_alias_record.other_name, + aliases=user_alias_record.aliases, + meta_data=user_alias_record.meta_data, + created_at=user_alias_record.created_at, + updated_at=user_alias_record.updated_at + ) + + logger.info(f"成功查询用户别名记录: user_alias_id={user_alias_id}") + + return { + "success": True, + "data": response_data.model_dump(), + "error": None + } + + except ValueError: + logger.error(f"无效的 user_alias_id 格式: {user_alias_id}") + return { + "success": False, + "data": None, + "error": "无效的用户别名记录ID格式" + } + except Exception as e: + logger.error(f"查询用户别名记录失败: user_alias_id={user_alias_id}, error={str(e)}") + return { + "success": False, + "data": None, + "error": str(e) + } + + def create_user_alias( + self, + db: Session, + end_user_id: str, + other_name: str, + aliases: List[str] = None, + meta_data: dict = None + ) -> Dict[str, Any]: + """ + 创建用户别名记录 + + Args: + db: 数据库会话 + end_user_id: 终端用户ID (UUID) + other_name: 用户名称 + aliases: 别名列表 + meta_data: 扩展信息 + + Returns: + { + "success": bool, + "data": dict, + "error": Optional[str] + } + """ + try: + from app.models.user_alias_model import UserAlias + from app.repositories.end_user_repository import EndUserRepository + # 转换为UUID并查询用户 user_uuid = uuid.UUID(end_user_id) repo = EndUserRepository(db) @@ -397,47 +473,34 @@ class UserMemoryService: "error": "终端用户不存在" } - # 获取更新数据(排除 end_user_id 字段) - update_data = profile_update.model_dump(exclude_unset=True, exclude={'end_user_id'}) - - # 特殊处理 hire_date:如果提供了时间戳,转换为 DateTime - if 'hire_date' in update_data: - hire_date_timestamp = update_data['hire_date'] - if hire_date_timestamp is not None: - from app.core.api_key_utils import timestamp_to_datetime - update_data['hire_date'] = timestamp_to_datetime(hire_date_timestamp) - # 如果是 None,保持 None(允许清空) - - # 更新字段 - for field, value in update_data.items(): - setattr(end_user, field, value) - - # 更新时间戳 - end_user.updated_at = datetime.now() - end_user.updatetime_profile = datetime.now() - - # 提交更改 + # 创建新的别名记录 + new_alias = UserAlias( + end_user_id=user_uuid, + other_name=other_name, + aliases=aliases, + meta_data=meta_data + ) + db.add(new_alias) db.commit() - db.refresh(end_user) + db.refresh(new_alias) # 构建响应数据 - from app.schemas.end_user_schema import EndUserProfileResponse - profile_data = EndUserProfileResponse( - id=end_user.id, - other_name=end_user.other_name, - position=end_user.position, - department=end_user.department, - contact=end_user.contact, - phone=end_user.phone, - hire_date=end_user.hire_date, - updatetime_profile=end_user.updatetime_profile + from app.schemas.end_user_schema import UserAliasResponse + response_data = UserAliasResponse( + user_alias_id=new_alias.id, + end_user_id=new_alias.end_user_id, + other_name=new_alias.other_name, + aliases=new_alias.aliases, + meta_data=new_alias.meta_data, + created_at=new_alias.created_at, + updated_at=new_alias.updated_at ) - logger.info(f"成功更新用户信息: end_user_id={end_user_id}, updated_fields={list(update_data.keys())}") + logger.info(f"成功创建用户别名记录: end_user_id={end_user_id}") return { "success": True, - "data": self.convert_profile_to_dict_with_timestamp(profile_data), + "data": response_data.model_dump(), "error": None } @@ -450,7 +513,161 @@ class UserMemoryService: } except Exception as e: db.rollback() - logger.error(f"用户信息更新失败: end_user_id={end_user_id}, error={str(e)}") + logger.error(f"创建用户别名记录失败: end_user_id={end_user_id}, error={str(e)}") + return { + "success": False, + "data": None, + "error": str(e) + } + + def update_user_alias( + self, + db: Session, + user_alias_id: str, + update_data: Dict[str, Any] + ) -> Dict[str, Any]: + """ + 更新用户别名记录 + + Args: + db: 数据库会话 + user_alias_id: 用户别名记录ID (UUID) + update_data: 更新数据字典 + + Returns: + { + "success": bool, + "data": dict, + "error": Optional[str] + } + """ + try: + from app.models.user_alias_model import UserAlias + + # 转换为UUID并查询 + alias_uuid = uuid.UUID(user_alias_id) + user_alias_record = db.query(UserAlias).filter(UserAlias.id == alias_uuid).first() + + if not user_alias_record: + logger.warning(f"用户别名记录不存在: user_alias_id={user_alias_id}") + return { + "success": False, + "data": None, + "error": "用户别名记录不存在" + } + + # 更新字段 + for field, value in update_data.items(): + if hasattr(user_alias_record, field) and field != 'user_alias_id': + setattr(user_alias_record, field, value) + + # 更新时间戳 + user_alias_record.updated_at = datetime.now() + + # 提交更改 + db.commit() + db.refresh(user_alias_record) + + # 构建响应数据 + from app.schemas.end_user_schema import UserAliasResponse + response_data = UserAliasResponse( + user_alias_id=user_alias_record.id, + end_user_id=user_alias_record.end_user_id, + other_name=user_alias_record.other_name, + aliases=user_alias_record.aliases, + meta_data=user_alias_record.meta_data, + created_at=user_alias_record.created_at, + updated_at=user_alias_record.updated_at + ) + + logger.info(f"成功更新用户别名记录: user_alias_id={user_alias_id}, updated_fields={list(update_data.keys())}") + + return { + "success": True, + "data": response_data.model_dump(), + "error": None + } + + except ValueError: + logger.error(f"无效的 user_alias_id 格式: {user_alias_id}") + return { + "success": False, + "data": None, + "error": "无效的用户别名记录ID格式" + } + except Exception as e: + db.rollback() + logger.error(f"更新用户别名记录失败: user_alias_id={user_alias_id}, error={str(e)}") + return { + "success": False, + "data": None, + "error": str(e) + } + + def delete_user_alias( + self, + db: Session, + user_alias_id: str + ) -> Dict[str, Any]: + """ + 删除用户别名记录 + + Args: + db: 数据库会话 + user_alias_id: 用户别名记录ID (UUID) + + Returns: + { + "success": bool, + "data": dict, + "error": Optional[str] + } + """ + try: + from app.models.user_alias_model import UserAlias + + # 转换为UUID并查询 + alias_uuid = uuid.UUID(user_alias_id) + user_alias_record = db.query(UserAlias).filter(UserAlias.id == alias_uuid).first() + + if not user_alias_record: + logger.warning(f"用户别名记录不存在: user_alias_id={user_alias_id}") + return { + "success": False, + "data": None, + "error": "用户别名记录不存在" + } + + # 删除记录 + db.delete(user_alias_record) + db.commit() + + logger.info(f"成功删除用户别名记录: user_alias_id={user_alias_id}") + + return { + "success": True, + "data": {"user_alias_id": user_alias_id}, + "error": None + } + + except ValueError: + logger.error(f"无效的 user_alias_id 格式: {user_alias_id}") + return { + "success": False, + "data": None, + "error": "无效的用户别名记录ID格式" + } + except Exception as e: + db.rollback() + logger.error(f"删除用户别名记录失败: user_alias_id={user_alias_id}, error={str(e)}") + return { + "success": False, + "data": None, + "error": str(e) + } + except Exception as e: + db.rollback() + logger.error(f"用户别名记录更新失败: user_alias_id={user_alias_id}, error={str(e)}") return { "success": False, "data": None,