From ea497f828f0df394a91c98bbbd761944c2340d30 Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Thu, 26 Sep 2024 12:49:00 +0800 Subject: [PATCH] feat: endpoint management --- api/controllers/console/workspace/endpoint.py | 86 +++++++++++++-- api/core/plugin/entities/base.py | 9 ++ api/core/plugin/entities/endpoint.py | 11 ++ api/core/plugin/entities/plugin.py | 10 ++ api/core/plugin/manager/endpoint.py | 101 +++++++++++++++++- api/core/plugin/manager/plugin.py | 9 ++ api/services/plugin/endpoint_service.py | 52 ++++++++- 7 files changed, 268 insertions(+), 10 deletions(-) create mode 100644 api/core/plugin/entities/base.py create mode 100644 api/core/plugin/entities/endpoint.py create mode 100644 api/core/plugin/entities/plugin.py diff --git a/api/controllers/console/workspace/endpoint.py b/api/controllers/console/workspace/endpoint.py index 668e4ea953..44e35f32bd 100644 --- a/api/controllers/console/workspace/endpoint.py +++ b/api/controllers/console/workspace/endpoint.py @@ -1,9 +1,12 @@ -from flask_restful import Resource +from flask_login import current_user +from flask_restful import Resource, reqparse +from werkzeug.exceptions import Forbidden from controllers.console import api from controllers.console.setup import setup_required from controllers.console.wraps import account_initialization_required from libs.login import login_required +from services.plugin.endpoint_service import EndpointService class EndpointCreateApi(Resource): @@ -11,7 +14,24 @@ class EndpointCreateApi(Resource): @login_required @account_initialization_required def post(self): - pass + user = current_user + if not user.is_admin_or_owner: + raise Forbidden() + + parser = reqparse.RequestParser() + parser.add_argument("plugin_unique_identifier", type=str, required=True) + parser.add_argument("settings", type=dict, required=True) + args = parser.parse_args() + + plugin_unique_identifier = args["plugin_unique_identifier"] + settings = args["settings"] + + return EndpointService.create_endpoint( + tenant_id=user.current_tenant_id, + user_id=user.id, + plugin_unique_identifier=plugin_unique_identifier, + settings=settings, + ) class EndpointListApi(Resource): @@ -19,7 +39,12 @@ class EndpointListApi(Resource): @login_required @account_initialization_required def get(self): - pass + user = current_user + + return EndpointService.list_endpoints( + tenant_id=user.current_tenant_id, + user_id=user.id, + ) class EndpointDeleteApi(Resource): @@ -27,7 +52,17 @@ class EndpointDeleteApi(Resource): @login_required @account_initialization_required def post(self): - pass + user = current_user + + parser = reqparse.RequestParser() + parser.add_argument("endpoint_id", type=str, required=True) + args = parser.parse_args() + + endpoint_id = args["endpoint_id"] + + return EndpointService.delete_endpoint( + tenant_id=user.current_tenant_id, user_id=user.id, endpoint_id=endpoint_id + ) class EndpointUpdateApi(Resource): @@ -35,7 +70,22 @@ class EndpointUpdateApi(Resource): @login_required @account_initialization_required def post(self): - pass + user = current_user + + parser = reqparse.RequestParser() + parser.add_argument("endpoint_id", type=str, required=True) + parser.add_argument("settings", type=dict, required=True) + args = parser.parse_args() + + endpoint_id = args["endpoint_id"] + settings = args["settings"] + + return EndpointService.update_endpoint( + tenant_id=user.current_tenant_id, + user_id=user.id, + endpoint_id=endpoint_id, + settings=settings, + ) class EndpointEnableApi(Resource): @@ -43,7 +93,17 @@ class EndpointEnableApi(Resource): @login_required @account_initialization_required def post(self): - pass + user = current_user + + parser = reqparse.RequestParser() + parser.add_argument("endpoint_id", type=str, required=True) + args = parser.parse_args() + + endpoint_id = args["endpoint_id"] + + return EndpointService.enable_endpoint( + tenant_id=user.current_tenant_id, user_id=user.id, endpoint_id=endpoint_id + ) class EndpointDisableApi(Resource): @@ -51,7 +111,17 @@ class EndpointDisableApi(Resource): @login_required @account_initialization_required def post(self): - pass + user = current_user + + parser = reqparse.RequestParser() + parser.add_argument("endpoint_id", type=str, required=True) + args = parser.parse_args() + + endpoint_id = args["endpoint_id"] + + return EndpointService.disable_endpoint( + tenant_id=user.current_tenant_id, user_id=user.id, endpoint_id=endpoint_id + ) api.add_resource(EndpointCreateApi, "/workspaces/current/endpoints/create") @@ -59,4 +129,4 @@ api.add_resource(EndpointListApi, "/workspaces/current/endpoints/list") api.add_resource(EndpointDeleteApi, "/workspaces/current/endpoints/delete") api.add_resource(EndpointUpdateApi, "/workspaces/current/endpoints/update") api.add_resource(EndpointEnableApi, "/workspaces/current/endpoints/enable") -api.add_resource(EndpointDisableApi, "/workspaces/current/endpoints/disable") \ No newline at end of file +api.add_resource(EndpointDisableApi, "/workspaces/current/endpoints/disable") diff --git a/api/core/plugin/entities/base.py b/api/core/plugin/entities/base.py new file mode 100644 index 0000000000..bfec0d4302 --- /dev/null +++ b/api/core/plugin/entities/base.py @@ -0,0 +1,9 @@ +from datetime import datetime + +from pydantic import BaseModel + + +class BasePluginEntity(BaseModel): + id: str + created_at: datetime + updated_at: datetime diff --git a/api/core/plugin/entities/endpoint.py b/api/core/plugin/entities/endpoint.py new file mode 100644 index 0000000000..54d718fd5b --- /dev/null +++ b/api/core/plugin/entities/endpoint.py @@ -0,0 +1,11 @@ +from datetime import datetime + +from core.plugin.entities.base import BasePluginEntity + + +class EndpointEntity(BasePluginEntity): + settings: dict + hook_id: str + tenant_id: str + plugin_id: str + expired_at: datetime diff --git a/api/core/plugin/entities/plugin.py b/api/core/plugin/entities/plugin.py new file mode 100644 index 0000000000..8098ade025 --- /dev/null +++ b/api/core/plugin/entities/plugin.py @@ -0,0 +1,10 @@ +from core.plugin.entities.base import BasePluginEntity + + +class PluginEntity(BasePluginEntity): + name: str + plugin_id: str + plugin_unique_identifier: str + tenant_id: str + endpoints_setups: int + endpoints_active: int diff --git a/api/core/plugin/manager/endpoint.py b/api/core/plugin/manager/endpoint.py index a3f49903fd..1c48f8200f 100644 --- a/api/core/plugin/manager/endpoint.py +++ b/api/core/plugin/manager/endpoint.py @@ -1,5 +1,104 @@ +from core.plugin.entities.endpoint import EndpointEntity from core.plugin.manager.base import BasePluginManager class PluginEndpointManager(BasePluginManager): - pass \ No newline at end of file + def create_endpoint(self, tenant_id: str, user_id: str, plugin_unique_identifier: str, settings: dict): + """ + Create an endpoint for the given plugin. + + Errors will be raised if any error occurs. + """ + self._request_with_plugin_daemon_response( + "POST", + f"plugin/{tenant_id}/endpoint/setup", + dict, + headers={ + "Content-Type": "application/json", + }, + data={ + "user_id": user_id, + "plugin_unique_identifier": plugin_unique_identifier, + "settings": settings, + }, + ) + + def list_endpoints(self, tenant_id: str, user_id: str): + """ + List all endpoints for the given tenant and user. + """ + return self._request_with_plugin_daemon_response( + "GET", + f"plugin/{tenant_id}/endpoint/list", + list[EndpointEntity], + params={"page": 1, "page_size": 256}, + ) + + def list_plugin_endpoints(self, tenant_id: str, user_id: str, plugin_unique_identifier: str): + """ + List all endpoints for the given tenant, user and plugin. + """ + return self._request_with_plugin_daemon_response( + "GET", + f"plugin/{tenant_id}/endpoint/list/plugin", + list[EndpointEntity], + headers={ + "Content-Type": "application/json", + }, + data={ + "plugin_unique_identifier": plugin_unique_identifier, + }, + ) + + def update_endpoint(self, tenant_id: str, user_id: str, endpoint_id: str, settings: dict): + """ + Update the settings of the given endpoint. + """ + self._request_with_plugin_daemon_response( + "POST", + f"plugin/{tenant_id}/endpoint/update", + dict, + data={ + "endpoint_id": endpoint_id, + "settings": settings, + }, + ) + + def delete_endpoint(self, tenant_id: str, user_id: str, endpoint_id: str): + """ + Delete the given endpoint. + """ + self._request_with_plugin_daemon_response( + "DELETE", + f"plugin/{tenant_id}/endpoint/remove", + dict, + data={ + "endpoint_id": endpoint_id, + }, + ) + + def enable_endpoint(self, tenant_id: str, user_id: str, endpoint_id: str): + """ + Enable the given endpoint. + """ + self._request_with_plugin_daemon_response( + "POST", + f"plugin/{tenant_id}/endpoint/enable", + dict, + data={ + "endpoint_id": endpoint_id, + }, + ) + + def disable_endpoint(self, tenant_id: str, user_id: str, endpoint_id: str): + """ + Disable the given endpoint. + """ + self._request_with_plugin_daemon_response( + "POST", + f"plugin/{tenant_id}/endpoint/disable", + dict, + data={ + "endpoint_id": endpoint_id, + }, + ) diff --git a/api/core/plugin/manager/plugin.py b/api/core/plugin/manager/plugin.py index cabe028ff3..5a9eb336c5 100644 --- a/api/core/plugin/manager/plugin.py +++ b/api/core/plugin/manager/plugin.py @@ -1,5 +1,6 @@ from collections.abc import Generator +from core.plugin.entities.plugin import PluginEntity from core.plugin.entities.plugin_daemon import InstallPluginMessage from core.plugin.manager.base import BasePluginManager @@ -12,6 +13,14 @@ class PluginInstallationManager(BasePluginManager): "GET", f"plugin/{tenant_id}/fetch/identifier", bool, params={"plugin_unique_identifier": identifier} ) + def list_plugins(self, tenant_id: str) -> list[PluginEntity]: + return self._request_with_plugin_daemon_response( + "GET", + f"plugin/{tenant_id}/management/list", + list[PluginEntity], + params={"page": 1, "page_size": 256}, + ) + def install_from_pkg(self, tenant_id: str, pkg: bytes) -> Generator[InstallPluginMessage, None, None]: """ Install a plugin from a package. diff --git a/api/services/plugin/endpoint_service.py b/api/services/plugin/endpoint_service.py index e9b395efcc..4b3258ef6e 100644 --- a/api/services/plugin/endpoint_service.py +++ b/api/services/plugin/endpoint_service.py @@ -1,2 +1,52 @@ +from core.plugin.manager.endpoint import PluginEndpointManager + + class EndpointService: - pass \ No newline at end of file + @classmethod + def create_endpoint(cls, tenant_id: str, user_id: str, plugin_unique_identifier: str, settings: dict): + return PluginEndpointManager().create_endpoint( + tenant_id=tenant_id, + user_id=user_id, + plugin_unique_identifier=plugin_unique_identifier, + settings=settings, + ) + + @classmethod + def list_endpoints(cls, tenant_id: str, user_id: str): + return PluginEndpointManager().list_endpoints( + tenant_id=tenant_id, + user_id=user_id, + ) + + @classmethod + def update_endpoint(cls, tenant_id: str, user_id: str, endpoint_id: str, settings: dict): + return PluginEndpointManager().update_endpoint( + tenant_id=tenant_id, + user_id=user_id, + endpoint_id=endpoint_id, + settings=settings, + ) + + @classmethod + def delete_endpoint(cls, tenant_id: str, user_id: str, endpoint_id: str): + return PluginEndpointManager().delete_endpoint( + tenant_id=tenant_id, + user_id=user_id, + endpoint_id=endpoint_id, + ) + + @classmethod + def enable_endpoint(cls, tenant_id: str, user_id: str, endpoint_id: str): + return PluginEndpointManager().enable_endpoint( + tenant_id=tenant_id, + user_id=user_id, + endpoint_id=endpoint_id, + ) + + @classmethod + def disable_endpoint(cls, tenant_id: str, user_id: str, endpoint_id: str): + return PluginEndpointManager().disable_endpoint( + tenant_id=tenant_id, + user_id=user_id, + endpoint_id=endpoint_id, + )