卸载app时自动卸载包含的package扩展包
This commit is contained in:
parent
ac4eb3bd0f
commit
c1e4150a83
@ -57,31 +57,21 @@ def _import_app_package_and_pagetypes(app_name: str, install_result: Dict[str, A
|
||||
app_dir = str(backend_dir)
|
||||
|
||||
if not os.path.exists(app_dir):
|
||||
log_info(f"应用目录不存在: {app_dir},跳过导入")
|
||||
return
|
||||
|
||||
# 调用 jingrow whitelist API 导入
|
||||
try:
|
||||
api_url = f"{Config.jingrow_server_url}/api/action/jingrow.ai.utils.jlocal.sync_app_files"
|
||||
headers = get_jingrow_api_headers()
|
||||
|
||||
response = requests.post(
|
||||
api_url,
|
||||
json={'app_name': app_name, 'app_path': app_dir, 'force': True},
|
||||
headers=headers,
|
||||
headers=get_jingrow_api_headers(),
|
||||
timeout=60
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if response.status_code == 200:
|
||||
result_data = response.json()
|
||||
log_info(f"导入结果: {result_data}")
|
||||
else:
|
||||
log_error(f"导入失败: HTTP {response.status_code}")
|
||||
except Exception as api_error:
|
||||
log_error(f"调用导入 API 失败: {str(api_error)}")
|
||||
|
||||
except Exception as e:
|
||||
log_error(f"导入应用数据失败: {str(e)}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@router.post("/jingrow/install/upload")
|
||||
@ -92,40 +82,30 @@ async def install_app_from_upload(
|
||||
):
|
||||
|
||||
try:
|
||||
log_info(f"开始处理上传的应用包: {file.filename}")
|
||||
|
||||
# 验证文件类型
|
||||
if not file.filename.lower().endswith('.zip'):
|
||||
raise HTTPException(status_code=400, detail="只支持ZIP格式的安装包")
|
||||
|
||||
# 保存上传文件到临时目录
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
|
||||
try:
|
||||
content = await file.read()
|
||||
temp_file.write(content)
|
||||
temp_file.close()
|
||||
|
||||
# 安装应用
|
||||
result = install_app(temp_file.name, app_name)
|
||||
|
||||
if result.get('success'):
|
||||
app_name_result = result.get('app_name')
|
||||
log_info(f"应用安装成功: {app_name_result}")
|
||||
|
||||
# 导入 Package 和 PageTypes 到数据库
|
||||
try:
|
||||
_import_app_package_and_pagetypes(app_name_result, result)
|
||||
log_info(f"应用 {app_name_result} 的 Package 和 PageTypes 已导入")
|
||||
except Exception as import_error:
|
||||
log_error(f"导入 Package 和 PageTypes 失败: {str(import_error)}")
|
||||
# 不阻止安装成功,只是警告
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return result
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail=result.get('error'))
|
||||
|
||||
finally:
|
||||
# 清理临时文件
|
||||
try:
|
||||
os.unlink(temp_file.name)
|
||||
except:
|
||||
@ -134,7 +114,6 @@ async def install_app_from_upload(
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log_error(f"安装应用失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@ -224,7 +203,6 @@ async def get_local_apps(request: Request):
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
log_error(f"扫描本地App失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@ -243,8 +221,7 @@ async def install_local_app(request: Request, app_name: str):
|
||||
raise HTTPException(status_code=404, detail=f"App '{app_name}' not found")
|
||||
|
||||
if not backend_dir.exists():
|
||||
log_info(f"后端目录不存在: {backend_dir},跳过导入")
|
||||
backend_dir = app_dir # 使用应用根目录
|
||||
backend_dir = app_dir
|
||||
|
||||
# 检查是否已经安装 - 通过get_single API检查
|
||||
from jingrow.utils.jingrow_api import get_single_pagetype
|
||||
@ -268,13 +245,10 @@ async def install_local_app(request: Request, app_name: str):
|
||||
else:
|
||||
apps_list = []
|
||||
|
||||
# 检查是否已存在
|
||||
for app in apps_list:
|
||||
if app.get('app_name', '') == app_name:
|
||||
log_info(f"应用 {app_name} 已存在于数据库中")
|
||||
break
|
||||
else:
|
||||
# 添加新应用
|
||||
new_app = {
|
||||
'app_name': app_name,
|
||||
'app_version': "1.0.0",
|
||||
@ -283,30 +257,18 @@ async def install_local_app(request: Request, app_name: str):
|
||||
apps_list.append(new_app)
|
||||
|
||||
if await _update_local_installed_apps(apps_list):
|
||||
log_info(f"应用 {app_name} 已注册到数据库")
|
||||
|
||||
# 同步应用到数据库(导入 Package 和 PageTypes)
|
||||
try:
|
||||
api_url = f"{Config.jingrow_server_url}/api/action/jingrow.ai.utils.jlocal.sync_app_files"
|
||||
response = requests.post(
|
||||
requests.post(
|
||||
api_url,
|
||||
json={'app_name': app_name, 'app_path': str(backend_dir), 'force': True},
|
||||
headers=get_jingrow_api_headers(),
|
||||
timeout=60
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
log_info(f"应用 {app_name} 的 Package 和 PageTypes 已成功同步到数据库")
|
||||
else:
|
||||
log_error(f"同步应用 {app_name} 失败: HTTP {response.status_code}")
|
||||
except Exception as sync_error:
|
||||
log_error(f"同步应用 {app_name} 时出错: {str(sync_error)}")
|
||||
# 不阻止安装成功,只是记录错误
|
||||
else:
|
||||
log_error("更新数据库失败")
|
||||
except Exception as e:
|
||||
log_error(f"注册应用到数据库失败: {str(e)}")
|
||||
# 数据库操作失败不应该阻止安装,但需要记录错误
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
@ -317,7 +279,6 @@ async def install_local_app(request: Request, app_name: str):
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log_error(f"安装本地App失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@ -349,21 +310,14 @@ async def ensure_jingrow_registered():
|
||||
|
||||
apps = result.get('config', {}).get('local_installed_apps', [])
|
||||
|
||||
# 检查jingrow是否已存在
|
||||
if not any(app.get('app_name') == JINGROW_APP_NAME for app in apps):
|
||||
apps.append({'app_name': JINGROW_APP_NAME, 'app_version': DEFAULT_VERSION, 'git_branch': DEFAULT_BRANCH})
|
||||
if await _update_local_installed_apps(apps):
|
||||
log_info("jingrow应用已自动注册到数据库")
|
||||
_jingrow_registered_cache = True
|
||||
else:
|
||||
log_error("注册jingrow应用失败")
|
||||
_jingrow_registered_cache = False
|
||||
await _update_local_installed_apps(apps)
|
||||
_jingrow_registered_cache = True
|
||||
else:
|
||||
log_info("jingrow应用已在数据库中")
|
||||
_jingrow_registered_cache = True
|
||||
|
||||
except Exception as e:
|
||||
log_error(f"检查jingrow应用注册状态失败: {str(e)}")
|
||||
except Exception:
|
||||
_jingrow_registered_cache = False
|
||||
|
||||
|
||||
@ -411,7 +365,6 @@ async def get_installed_apps(request: Request):
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
log_error(f"获取已安装应用列表失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@ -419,13 +372,9 @@ async def get_installed_apps(request: Request):
|
||||
async def uninstall_app(request: Request, app_name: str):
|
||||
"""卸载应用 - 直接删除整个app目录"""
|
||||
try:
|
||||
log_info(f"开始卸载应用: {app_name}")
|
||||
|
||||
# 禁止卸载系统应用
|
||||
if app_name == JINGROW_APP_NAME:
|
||||
raise HTTPException(status_code=403, detail=f"系统应用 '{JINGROW_APP_NAME}' 不允许卸载")
|
||||
|
||||
# 获取应用目录
|
||||
apps_dir, _ = get_app_directories()
|
||||
app_dir = apps_dir / app_name
|
||||
|
||||
@ -433,12 +382,19 @@ async def uninstall_app(request: Request, app_name: str):
|
||||
if not app_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"应用 {app_name} 不存在")
|
||||
|
||||
# 删除整个app目录
|
||||
shutil.rmtree(app_dir)
|
||||
log_info(f"应用目录删除成功: {app_dir}")
|
||||
try:
|
||||
api_url = f"{Config.jingrow_server_url}/api/action/jingrow.core.pagetype.package.package.uninstall_package"
|
||||
response = requests.post(
|
||||
api_url,
|
||||
json={'package_name': app_name},
|
||||
headers=get_jingrow_api_headers(),
|
||||
timeout=60
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 从数据库中删除记录
|
||||
db_result = await _remove_from_database(app_name)
|
||||
shutil.rmtree(app_dir)
|
||||
await _remove_from_database(app_name)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
@ -448,7 +404,6 @@ async def uninstall_app(request: Request, app_name: str):
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log_error(f"卸载应用 {app_name} 失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@ -499,7 +454,6 @@ async def get_app_info(request: Request, app_name: str):
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
log_error(f"获取应用信息失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@ -509,22 +463,11 @@ async def _install_extension_package_in_api(package_path: str, original_filename
|
||||
import requests
|
||||
|
||||
try:
|
||||
log_info(f"保存扩展包文件: {original_filename}")
|
||||
|
||||
# 复制文件到 public/files 目录
|
||||
# 从 jingrow-framework/apps/jingrow/jingrow/api/local_app_installer.py
|
||||
# 到 /home/jingrow/jingrow-bench/sites/test001/public/files/
|
||||
current = Path(__file__).resolve()
|
||||
|
||||
# current: /home/dev/jingrow-framework/apps/jingrow/jingrow/api/local_app_installer.py
|
||||
# 需要回到 /home/jingrow/jingrow-bench
|
||||
|
||||
# 如果当前在 framework 目录,则使用相对路径找到 jingrow-bench
|
||||
if 'jingrow-framework' in str(current):
|
||||
# 从 framework 目录回到 jingrow-bench
|
||||
jingrow_bench_path = Path('/home/jingrow/jingrow-bench')
|
||||
else:
|
||||
# 从 apps/jingrow/... 到 jingrow-bench
|
||||
project_root = current.parents[6] if current.parts.count('apps') > 1 else current.parents[5]
|
||||
jingrow_bench_path = project_root
|
||||
|
||||
@ -532,12 +475,8 @@ async def _install_extension_package_in_api(package_path: str, original_filename
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
target_path = target_dir / original_filename
|
||||
|
||||
# 复制文件
|
||||
shutil.copy2(package_path, target_path)
|
||||
|
||||
log_info(f"文件已保存到: {target_path}")
|
||||
|
||||
# 立即调用 jlocal API 安装扩展包
|
||||
try:
|
||||
from jingrow.utils.jingrow_api import get_jingrow_api_headers
|
||||
@ -557,7 +496,6 @@ async def _install_extension_package_in_api(package_path: str, original_filename
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get('message', {}).get('success'):
|
||||
log_info(f"扩展包安装成功: {result.get('message', {}).get('package_name')}")
|
||||
return {
|
||||
'success': True,
|
||||
'message': f'扩展包安装成功',
|
||||
@ -567,15 +505,11 @@ async def _install_extension_package_in_api(package_path: str, original_filename
|
||||
'file_count': result.get('message', {}).get('file_count', 0)
|
||||
}
|
||||
else:
|
||||
error_msg = result.get('message', {}).get('error', '未知错误')
|
||||
log_error(f"安装失败: {error_msg}")
|
||||
return {'success': False, 'error': error_msg}
|
||||
return {'success': False, 'error': result.get('message', {}).get('error', '未知错误')}
|
||||
else:
|
||||
log_error(f"API调用失败: HTTP {response.status_code}")
|
||||
return {'success': False, 'error': f'API调用失败: HTTP {response.status_code}'}
|
||||
|
||||
except Exception as api_error:
|
||||
log_error(f"调用安装API失败: {str(api_error)}")
|
||||
except Exception:
|
||||
return {
|
||||
'success': True,
|
||||
'message': f'扩展包已保存到 public/files 目录',
|
||||
@ -585,8 +519,7 @@ async def _install_extension_package_in_api(package_path: str, original_filename
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
log_error(f"保存扩展包失败: {str(e)}")
|
||||
return {'success': False, 'error': f'保存文件失败: {str(e)}'}
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
|
||||
async def _remove_from_database(app_name: str) -> Dict[str, Any]:
|
||||
@ -602,16 +535,11 @@ async def _remove_from_database(app_name: str) -> Dict[str, Any]:
|
||||
|
||||
config = result.get('config', {})
|
||||
local_installed_apps = config.get('local_installed_apps', [])
|
||||
|
||||
log_info(f"当前应用列表: {local_installed_apps}")
|
||||
|
||||
# 查找要删除的应用
|
||||
original_count = len(local_installed_apps)
|
||||
local_installed_apps = [app for app in local_installed_apps if app.get('app_name', '') != app_name]
|
||||
|
||||
if len(local_installed_apps) < original_count:
|
||||
if await _update_local_installed_apps(local_installed_apps):
|
||||
log_info(f"应用 {app_name} 已从Local Installed Apps删除")
|
||||
return {'success': True, 'message': '数据库记录删除成功'}
|
||||
else:
|
||||
return {'success': False, 'error': '更新数据库失败'}
|
||||
@ -619,8 +547,7 @@ async def _remove_from_database(app_name: str) -> Dict[str, Any]:
|
||||
return {'success': True, 'message': '未找到要删除的应用记录'}
|
||||
|
||||
except Exception as e:
|
||||
log_error(f"从数据库删除应用记录失败: {str(e)}")
|
||||
return {'success': False, 'error': f'数据库操作异常: {str(e)}'}
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
|
||||
@router.get("/jingrow/app-marketplace")
|
||||
@ -742,8 +669,6 @@ async def install_extension_package_api(request: Request, file: UploadFile = Fil
|
||||
if not content:
|
||||
raise HTTPException(status_code=400, detail="文件内容为空")
|
||||
|
||||
log_info(f"读取文件完成,大小: {len(content)} 字节")
|
||||
|
||||
# 使用标准文件上传接口
|
||||
from jingrow.utils.jingrow_api import upload_file_to_jingrow, get_jingrow_api_headers
|
||||
import requests
|
||||
@ -754,9 +679,6 @@ async def install_extension_package_api(request: Request, file: UploadFile = Fil
|
||||
raise HTTPException(status_code=400, detail=upload_result.get('error', '文件上传失败'))
|
||||
|
||||
file_url = upload_result['file_url']
|
||||
log_info(f"文件上传成功: {file_url}")
|
||||
|
||||
# 调用 install_package API 安装
|
||||
api_url = f"{Config.jingrow_server_url}/api/action/jingrow.ai.utils.jlocal.install_package"
|
||||
headers = get_jingrow_api_headers()
|
||||
|
||||
@ -770,7 +692,6 @@ async def install_extension_package_api(request: Request, file: UploadFile = Fil
|
||||
if response.status_code == 200:
|
||||
result_data = response.json()
|
||||
if result_data.get('message', {}).get('success'):
|
||||
log_info(f"扩展包安装成功: {result_data['message'].get('package_name')}")
|
||||
return {
|
||||
'success': True,
|
||||
'package_name': result_data['message']['package_name'],
|
||||
@ -778,18 +699,14 @@ async def install_extension_package_api(request: Request, file: UploadFile = Fil
|
||||
'file_count': result_data['message'].get('file_count', 0)
|
||||
}
|
||||
else:
|
||||
error_msg = result_data.get('message', {}).get('error', '未知错误')
|
||||
log_error(f"安装失败: {error_msg}")
|
||||
raise HTTPException(status_code=400, detail=error_msg)
|
||||
raise HTTPException(status_code=400, detail=result_data.get('message', {}).get('error', '未知错误'))
|
||||
else:
|
||||
log_error(f"API调用失败: HTTP {response.status_code}")
|
||||
raise HTTPException(status_code=500, detail=f'安装API调用失败: HTTP {response.status_code}')
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log_error(f"安装扩展包失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"安装扩展包失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/jingrow/upload-image")
|
||||
@ -846,8 +763,7 @@ async def upload_image(file: UploadFile = File(...)):
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log_error(f"图片上传失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"图片上传失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user