diff --git a/apps/entities/flow.py b/apps/entities/flow.py index 554cefb9f7fb5e230528c0e5b29c03c1ab1ffe17..5b2075b6c6949ac584a718f2653220bcbaa4431e 100644 --- a/apps/entities/flow.py +++ b/apps/entities/flow.py @@ -122,7 +122,7 @@ class AppLink(BaseModel): """App的相关链接""" title: str = Field(description="链接标题") - url: HttpUrl = Field(..., description="链接地址") + url: str = Field(..., description="链接地址", pattern=r"^(https|http)://.*$") class Permission(BaseModel): @@ -151,8 +151,10 @@ class ServiceApiSpec(BaseModel): path: str = Field(description="OpenAPI文件路径") hash: str = Field(description="OpenAPI文件的hash值") + class FlowConfig(BaseModel): """Flow的配置信息 用于前期调试使用""" + app_id: str flow_id: str - flow_config: Flow \ No newline at end of file + flow_config: Flow diff --git a/apps/entities/response_data.py b/apps/entities/response_data.py index b3d26bf1ab99fc248a18231bd6bc6902b3271b29..cc685823ab0222f763ef872853a7c2ff6ad88c41 100644 --- a/apps/entities/response_data.py +++ b/apps/entities/response_data.py @@ -289,7 +289,7 @@ class GetAppListMsg(BaseModel): """GET /api/app Result数据结构""" page_number: int = Field(..., alias="currentPage", description="当前页码") - app_count: int = Field(..., alias="total", description="总页数") + app_count: int = Field(..., alias="totalApps", description="总应用数") applications: list[AppCenterCardItem] = Field(..., description="应用列表") diff --git a/apps/manager/appcenter.py b/apps/manager/appcenter.py index aa2289676c5997a7c32f9b89ca0e23a5e4aad034..92683afd660ba17bd05aae543066dc3ab69efad6 100644 --- a/apps/manager/appcenter.py +++ b/apps/manager/appcenter.py @@ -2,7 +2,6 @@ Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved. """ -from datetime import datetime, timezone import uuid from datetime import datetime, timezone from enum import Enum @@ -39,7 +38,15 @@ class AppCenterManager: page: int, page_size: int, ) -> tuple[list[AppCenterCardItem], int]: - """获取所有应用列表""" + """获取所有应用列表 + + :param user_sub: 用户唯一标识 + :param search_type: 搜索类型 + :param keyword: 搜索关键字 + :param page: 页码 + :param page_size: 每页条数 + :return: 应用列表, 总应用数 + """ try: # 构建基础搜索条件 filters: dict[str, Any] = {} @@ -56,15 +63,15 @@ class AppCenterManager: filters = { "$or": [ {"author": user_sub}, - {"published": True} - ] + {"published": True}, + ], } # 如果有关键词且是按作者搜索,额外添加关键词过滤 if keyword and search_type == SearchType.AUTHOR: filters["$and"] = [ filters["$or"], - {"author": {"$regex": keyword, "$options": "i"}} + {"author": {"$regex": keyword, "$options": "i"}}, ] # 执行应用搜索 @@ -96,7 +103,15 @@ class AppCenterManager: page: int, page_size: int, ) -> tuple[list[AppCenterCardItem], int]: - """获取用户应用列表""" + """获取用户应用列表 + + :param user_sub: 用户唯一标识 + :param search_type: 搜索类型 + :param keyword: 搜索关键词 + :param page: 页码 + :param page_size: 每页数量 + :return: 应用列表, 总应用数 + """ try: # 搜索条件 base_filter = {"author": user_sub} @@ -130,7 +145,15 @@ class AppCenterManager: page: int, page_size: int, ) -> tuple[list[AppCenterCardItem], int]: - """获取用户收藏的应用列表""" + """获取用户收藏的应用列表 + + :param user_sub: 用户唯一标识 + :param search_type: 搜索类型 + :param keyword: 搜索关键词 + :param page: 页码 + :param page_size: 每页数量 + :return: 应用列表,总应用数 + """ try: fav_app = await AppCenterManager._get_favorite_app_ids_by_user(user_sub) # 搜索条件 @@ -138,7 +161,6 @@ class AppCenterManager: "_id": {"$in": fav_app}, "published": True, } - print(base_filter) filters: dict[str, Any] = AppCenterManager._build_filters( base_filter, search_type, @@ -163,11 +185,16 @@ class AppCenterManager: @staticmethod async def fetch_app_data_by_id(app_id: str) -> Optional[AppPool]: - """根据应用ID获取应用元数据""" + """根据应用ID获取应用元数据 + + :param app_id: 应用ID + :return: 应用元数据 + """ try: app_collection = MongoDB.get_collection("app") db_data = await app_collection.find_one({"_id": app_id}) if not db_data: + LOGGER.warning(f"[AppCenterManager] No data found for app_id: {app_id}") return None return AppPool.model_validate(db_data) except Exception as e: @@ -176,7 +203,12 @@ class AppCenterManager: @staticmethod async def create_app(user_sub: str, data: AppData) -> Optional[str]: - """创建应用""" + """创建应用 + + :param user_sub: 用户唯一标识 + :param data: 应用数据 + :return: 应用ID + """ app_id = str(uuid.uuid4()) app = AppPool( _id=app_id, @@ -202,7 +234,12 @@ class AppCenterManager: @staticmethod async def update_app(app_id: str, data: AppData) -> bool: - """更新应用""" + """更新应用 + + :param app_id: 应用唯一标识 + :param data: 应用数据 + :return: 是否成功 + """ try: app_collection = MongoDB.get_collection("app") app_data = AppPool.model_validate(await app_collection.find_one({"_id": app_id})) @@ -232,7 +269,11 @@ class AppCenterManager: @staticmethod async def publish_app(app_id: str) -> bool: - """发布应用""" + """发布应用 + + :param app_id: 应用唯一标识 + :return: 是否成功 + """ try: app_collection = MongoDB.get_collection("app") await app_collection.update_one( @@ -246,7 +287,13 @@ class AppCenterManager: @staticmethod async def modify_favorite_app(app_id: str, user_sub: str, *, favorited: bool) -> ModFavAppFlag: - """修改收藏状态""" + """修改收藏状态 + + :param app_id: 应用唯一标识 + :param user_sub: 用户唯一标识 + :param favorited: 是否收藏 + :return: 修改结果 + """ try: app_collection = MongoDB.get_collection("app") db_data = await app_collection.find_one({"_id": app_id}) @@ -281,7 +328,12 @@ class AppCenterManager: @staticmethod async def get_recently_used_apps(count: int, user_sub: str) -> Optional[RecentAppList]: - """获取用户最近使用的应用列表""" + """获取用户最近使用的应用列表 + + :param count: 应用数量 + :param user_sub: 用户唯一标识 + :return: 最近使用的应用列表 + """ try: user_collection = MongoDB.get_collection("user") app_collection = MongoDB.get_collection("app") @@ -308,7 +360,12 @@ class AppCenterManager: @staticmethod async def delete_app(app_id: str, user_sub: str) -> bool: - """删除应用""" + """删除应用 + + :param app_id: 应用唯一标识 + :param user_sub: 用户唯一标识 + :return: 删除是否成功 + """ try: async with MongoDB.get_session() as session, await session.start_transaction(): app_collection = MongoDB.get_collection("app") @@ -325,6 +382,38 @@ class AppCenterManager: LOGGER.error(f"[AppCenterManager] Delete app failed: {e}") return False + @staticmethod + async def update_recent_app(user_sub: str, app_id: str) -> bool: + """更新用户的最近使用应用列表 + + :param user_sub: 用户唯一标识 + :param app_id: 应用唯一标识 + :return: 更新是否成功 + """ + try: + user_collection = MongoDB.get_collection("user") + current_time = round(datetime.now(tz=timezone.utc).timestamp(), 3) + result = await user_collection.update_one( + {"_id": user_sub}, # 查询条件 + { + "$set": { + f"app_usage.{app_id}.last_used": current_time, # 更新最后使用时间 + }, + "$inc": { + f"app_usage.{app_id}.count": 1, # 增加使用次数 + }, + }, + upsert=True, # 如果 app_usage 字段或 app_id 不存在,则创建 + ) + if result.modified_count > 0 or result.upserted_id is not None: + LOGGER.info(f"[AppCenterManager] Updated recent app for user {user_sub}: {app_id}") + return True + LOGGER.warning(f"[AppCenterManager] No changes made for user {user_sub}") + return False + except Exception as e: + LOGGER.error(f"[AppCenterManager] Failed to update recent app: {e}") + return False + @staticmethod def _build_filters( base_filters: dict[str, Any], @@ -372,49 +461,8 @@ class AppCenterManager: """获取用户收藏的应用ID""" try: app_collection = MongoDB.get_collection("app") - cursor = app_collection.find({"favorites": user_sub}) + cursor = app_collection.find({"favorites": {"$in": [user_sub]}}) return [AppPool.model_validate(doc).id async for doc in cursor] except Exception as e: LOGGER.info(f"[AppCenterManager] Get favorite app ids by user_sub failed: {e}") return [] - - @staticmethod - async def update_recent_app(user_sub: str, app_id: str) -> bool: - """更新用户的最近使用应用列表 - - :param user_sub: 用户唯一标识 - :param app_id: 应用唯一标识 - :return: 更新是否成功 - """ - try: - # 获取 user 集合 - user_collection = MongoDB.get_collection("user") - - # 获取当前时间戳 - current_time = round(datetime.now(tz=timezone.utc).timestamp(), 3) - - # 更新用户的 app_usage 字段 - result = await user_collection.update_one( - {"_id": user_sub}, # 查询条件 - { - "$set": { - f"app_usage.{app_id}.last_used": current_time, # 更新最后使用时间 - }, - "$inc": { - f"app_usage.{app_id}.count": 1, # 增加使用次数 - }, - }, - upsert=True, # 如果 app_usage 字段或 app_id 不存在,则创建 - ) - - # 检查更新是否成功 - if result.modified_count > 0 or result.upserted_id is not None: - LOGGER.info(f"[AppCenterManager] Updated recent app for user {user_sub}: {app_id}") - return True - else: - LOGGER.warning(f"[AppCenterManager] No changes made for user {user_sub}") - return False - - except Exception as e: - LOGGER.error(f"[AppCenterManager] Failed to update recent app: {e}") - return False \ No newline at end of file diff --git a/apps/manager/flow.py b/apps/manager/flow.py index 29be1d234058b89342df6eb5f1a9aa2e6a363153..d2b302a8f48b454ea2db6b1d7010f66f07cd8a1b 100644 --- a/apps/manager/flow.py +++ b/apps/manager/flow.py @@ -217,7 +217,7 @@ class FlowManager: nodes=[], edges=[], createdAt=flow_record["created_at"], - debug=flow_config['debug'], + debug=flow_config["debug"], ) for node_config in flow_config["steps"]: node_item = NodeItem( @@ -230,7 +230,7 @@ class FlowManager: type=node_config["type"], parameters=node_config["params"], position=PositionItem( - x=node_config['pos']['x'], y=node_config['pos']['y']), + x=node_config["pos"]["x"], y=node_config["pos"]["y"]), ) flow_item.nodes.append(node_item) diff --git a/apps/routers/appcenter.py b/apps/routers/appcenter.py index d32c75597d94cfd0a1abb319c67fa69a7805a046..630daf03c72412fda5b9f36b80a62c3309e1d669 100644 --- a/apps/routers/appcenter.py +++ b/apps/routers/appcenter.py @@ -5,7 +5,6 @@ Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved. from typing import Annotated, Optional, Union from fastapi import APIRouter, Body, Depends, Path, Query, status -from fastapi.requests import HTTPConnection from fastapi.responses import JSONResponse from apps.dependency.csrf import verify_csrf_token @@ -75,7 +74,7 @@ async def get_applications( # noqa: ANN201, PLR0913 message="查询成功", result=GetAppListMsg( currentPage=page, - total=total_apps, + totalApps=total_apps, applications=app_cards, ), ).model_dump(exclude_none=True, by_alias=True))