dify/api/controllers/console/explore/installed_app.py

125 lines
4.6 KiB
Python
Raw Normal View History

from datetime import datetime, timezone
2023-05-25 15:54:45 +08:00
from flask_login import current_user
from flask_restful import Resource, inputs, marshal_with, reqparse
from sqlalchemy import and_
from werkzeug.exceptions import BadRequest, Forbidden, NotFound
2023-05-25 15:54:45 +08:00
from controllers.console import api
from controllers.console.explore.wraps import InstalledAppResource
from controllers.console.wraps import account_initialization_required, cloud_edition_billing_resource_check
2023-05-25 15:54:45 +08:00
from extensions.ext_database import db
from fields.installed_app_fields import installed_app_list_fields
from libs.login import login_required
from models import App, InstalledApp, RecommendedApp
2023-05-25 15:54:45 +08:00
from services.account_service import TenantService
class InstalledAppsListApi(Resource):
@login_required
@account_initialization_required
@marshal_with(installed_app_list_fields)
def get(self):
current_tenant_id = current_user.current_tenant_id
installed_apps = db.session.query(InstalledApp).filter(InstalledApp.tenant_id == current_tenant_id).all()
2023-05-25 15:54:45 +08:00
current_user.role = TenantService.get_user_role(current_user, current_user.current_tenant)
installed_apps = [
{
"id": installed_app.id,
"app": installed_app.app,
"app_owner_tenant_id": installed_app.app_owner_tenant_id,
"is_pinned": installed_app.is_pinned,
"last_used_at": installed_app.last_used_at,
"editable": current_user.role in {"owner", "admin"},
"uninstallable": current_tenant_id == installed_app.app_owner_tenant_id,
2023-05-25 15:54:45 +08:00
}
for installed_app in installed_apps
if installed_app.app is not None
2023-05-25 15:54:45 +08:00
]
installed_apps.sort(
key=lambda app: (
-app["is_pinned"],
app["last_used_at"] is None,
-app["last_used_at"].timestamp() if app["last_used_at"] is not None else 0,
)
)
2023-05-25 15:54:45 +08:00
return {"installed_apps": installed_apps}
2023-05-25 15:54:45 +08:00
@login_required
@account_initialization_required
@cloud_edition_billing_resource_check("apps")
2023-05-25 15:54:45 +08:00
def post(self):
parser = reqparse.RequestParser()
parser.add_argument("app_id", type=str, required=True, help="Invalid app_id")
2023-05-25 15:54:45 +08:00
args = parser.parse_args()
recommended_app = RecommendedApp.query.filter(RecommendedApp.app_id == args["app_id"]).first()
2023-05-25 15:54:45 +08:00
if recommended_app is None:
raise NotFound("App not found")
2023-05-25 15:54:45 +08:00
current_tenant_id = current_user.current_tenant_id
app = db.session.query(App).filter(App.id == args["app_id"]).first()
2023-05-25 15:54:45 +08:00
if app is None:
raise NotFound("App not found")
2023-05-25 15:54:45 +08:00
if not app.is_public:
raise Forbidden("You can't install a non-public app")
2023-05-25 15:54:45 +08:00
installed_app = InstalledApp.query.filter(
and_(InstalledApp.app_id == args["app_id"], InstalledApp.tenant_id == current_tenant_id)
).first()
2023-05-25 15:54:45 +08:00
if installed_app is None:
# todo: position
recommended_app.install_count += 1
new_installed_app = InstalledApp(
app_id=args["app_id"],
2023-05-25 15:54:45 +08:00
tenant_id=current_tenant_id,
app_owner_tenant_id=app.tenant_id,
is_pinned=False,
last_used_at=datetime.now(timezone.utc).replace(tzinfo=None),
2023-05-25 15:54:45 +08:00
)
db.session.add(new_installed_app)
db.session.commit()
return {"message": "App installed successfully"}
2023-05-25 15:54:45 +08:00
class InstalledAppApi(InstalledAppResource):
"""
update and delete an installed app
use InstalledAppResource to apply default decorators and get installed_app
"""
2023-05-25 15:54:45 +08:00
def delete(self, installed_app):
if installed_app.app_owner_tenant_id == current_user.current_tenant_id:
raise BadRequest("You can't uninstall an app owned by the current tenant")
2023-05-25 15:54:45 +08:00
db.session.delete(installed_app)
db.session.commit()
return {"result": "success", "message": "App uninstalled successfully"}
2023-05-25 15:54:45 +08:00
def patch(self, installed_app):
parser = reqparse.RequestParser()
parser.add_argument("is_pinned", type=inputs.boolean)
2023-05-25 15:54:45 +08:00
args = parser.parse_args()
commit_args = False
if "is_pinned" in args:
installed_app.is_pinned = args["is_pinned"]
2023-05-25 15:54:45 +08:00
commit_args = True
if commit_args:
db.session.commit()
return {"result": "success", "message": "App info updated successfully"}
2023-05-25 15:54:45 +08:00
api.add_resource(InstalledAppsListApi, "/installed-apps")
api.add_resource(InstalledAppApi, "/installed-apps/<uuid:installed_app_id>")