add apo user api

pull/17608/head
fuwx 1 year ago
parent 9735940185
commit 96657b65ee
No known key found for this signature in database
GPG Key ID: C8FA8C18DFB4702B

@ -190,6 +190,29 @@ class AccountPasswordApi(Resource):
raise CurrentPasswordIncorrectError() raise CurrentPasswordIncorrectError()
return {"result": "success"} return {"result": "success"}
class APOAccountPasswordApi(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument("username", type=str, required=True, location="json")
parser.add_argument("password", type=str, required=False, location="json")
parser.add_argument("new_password", type=str, required=True, location="json")
# parser.add_argument("repeat_new_password", type=str, required=True, location="json")
args = parser.parse_args()
current_user = AccountService.get_user_through_email(args["username"]+"@apo.com")
if not current_user:
return {"result": "failed", "message": "Account not found"}
# if args["new_password"] != args["repeat_new_password"]:
# raise RepeatPasswordNotMatchError()
try:
AccountService.update_account_password(current_user, args["password"], args["new_password"])
except ServiceCurrentPasswordIncorrectError:
return {"result": "failed", "message": "Current password incorrect"}
return {"result": "success"}
class AccountIntegrateApi(Resource): class AccountIntegrateApi(Resource):
@ -301,6 +324,7 @@ api.add_resource(AccountInterfaceLanguageApi, "/account/interface-language")
api.add_resource(AccountInterfaceThemeApi, "/account/interface-theme") api.add_resource(AccountInterfaceThemeApi, "/account/interface-theme")
api.add_resource(AccountTimezoneApi, "/account/timezone") api.add_resource(AccountTimezoneApi, "/account/timezone")
api.add_resource(AccountPasswordApi, "/account/password") api.add_resource(AccountPasswordApi, "/account/password")
api.add_resource(APOAccountPasswordApi, "/apo/account/password")
api.add_resource(AccountIntegrateApi, "/account/integrates") api.add_resource(AccountIntegrateApi, "/account/integrates")
api.add_resource(AccountDeleteVerifyApi, "/account/delete/verify") api.add_resource(AccountDeleteVerifyApi, "/account/delete/verify")
api.add_resource(AccountDeleteApi, "/account/delete") api.add_resource(AccountDeleteApi, "/account/delete")

@ -15,7 +15,7 @@ from extensions.ext_database import db
from fields.member_fields import account_with_role_list_fields from fields.member_fields import account_with_role_list_fields
from libs.login import login_required from libs.login import login_required
from models.account import Account, TenantAccountRole from models.account import Account, TenantAccountRole
from services.account_service import RegisterService, TenantService from services.account_service import RegisterService, TenantService, AccountService
from services.errors.account import AccountAlreadyInTenantError from services.errors.account import AccountAlreadyInTenantError
@ -30,6 +30,40 @@ class MemberListApi(Resource):
members = TenantService.get_tenant_members(current_user.current_tenant) members = TenantService.get_tenant_members(current_user.current_tenant)
return {"result": "success", "accounts": members}, 200 return {"result": "success", "accounts": members}, 200
class APOAddMemberApi(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument("username", type=str, required=True, location="json")
parser.add_argument("password", type=str, required=True, location="json")
parser.add_argument("role", type=str, required=True, default="admin", location="json")
parser.add_argument("language", type=str, required=False, location="json")
args = parser.parse_args()
invitee_email = args["username"]+"@apo.com"
password = args["password"]
invitee_role = args["role"]
interface_language = args["language"]
if not TenantAccountRole.is_non_owner_role(invitee_role):
return {"result": "failed", "message": "Invalid role"}, 400
# add member to admin tenant
inviter = AccountService.get_user_through_email("admin@apo.com")
tenant = TenantService.get_join_tenants(inviter)
add_result = {}
try:
RegisterService.apo_add_new_member(
tenant[0], invitee_email, password, interface_language, role=invitee_role, inviter=inviter
)
add_result = {"result": "success","email": invitee_email}
except AccountAlreadyInTenantError:
add_result = {"result": "success", "email": invitee_email}
except Exception as e:
add_result = {"result": "failed", "email": invitee_email, "message": str(e)}
return add_result, 201
class MemberInviteEmailApi(Resource): class MemberInviteEmailApi(Resource):
"""Invite a new member by email.""" """Invite a new member by email."""
@ -106,6 +140,33 @@ class MemberCancelInviteApi(Resource):
return {"result": "success"}, 204 return {"result": "success"}, 204
class APORemoveMemberApi(Resource):
"""remove member by username"""
def delete(self, username):
member = db.session.query(Account).filter(Account.email == str(username+'@apo.com')).first()
if member is None or member.email == "admin@apo.com":
abort(404)
else:
admin = AccountService.get_user_through_email("admin@apo.com")
tenant = TenantService.get_join_tenants(admin)
try:
TenantService.remove_member_from_tenant(tenant[0], member, admin)
except services.errors.account.CannotOperateSelfError as e:
return {"result": "failed", "code": "cannot-operate-self", "message": str(e)}, 400
except services.errors.account.NoPermissionError as e:
return {"result": "failed", "code": "forbidden", "message": str(e)}, 403
except services.errors.account.MemberNotInTenantError as e:
return {"result": "failed", "code": "member-not-found", "message": str(e)}, 404
except Exception as e:
return {"result": "failed", "message": str(e)}, 400
try:
AccountService.delete_apo_account(member)
except Exception as e:
return {"result": "failed", "message": str(e)}, 400
return {"result": "success", "message": "ok"}, 200
class MemberUpdateRoleApi(Resource): class MemberUpdateRoleApi(Resource):
"""Update member role.""" """Update member role."""
@ -147,7 +208,8 @@ class DatasetOperatorMemberListApi(Resource):
members = TenantService.get_dataset_operator_members(current_user.current_tenant) members = TenantService.get_dataset_operator_members(current_user.current_tenant)
return {"result": "success", "accounts": members}, 200 return {"result": "success", "accounts": members}, 200
api.add_resource(APOAddMemberApi, "/workspaces/apo/members/add")
api.add_resource(APORemoveMemberApi, "/workspaces/apo/members/<string:username>")
api.add_resource(MemberListApi, "/workspaces/current/members") api.add_resource(MemberListApi, "/workspaces/current/members")
api.add_resource(MemberInviteEmailApi, "/workspaces/current/members/invite-email") api.add_resource(MemberInviteEmailApi, "/workspaces/current/members/invite-email")
api.add_resource(MemberCancelInviteApi, "/workspaces/current/members/<uuid:member_id>") api.add_resource(MemberCancelInviteApi, "/workspaces/current/members/<uuid:member_id>")

@ -1,48 +0,0 @@
import json
from collections.abc import Generator
from typing import Any, Optional
import requests
from configs import dify_config
from core.tools.builtin_tool.tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage
from libs.apo_utils import APOUtils
class ContainerCpuThrottleContainerdSecondsTool(BuiltinTool):
def _invoke(
self,
user_id: str,
tool_parameters: dict[str, Any],
conversation_id: Optional[str] = None,
app_id: Optional[str] = None,
message_id: Optional[str] = None,
) -> Generator[ToolInvokeMessage, None, None]:
cadvisor_job_name = tool_parameters.get('cadvisor_job_name', '.*')
namespace = tool_parameters.get('namespace', '.*')
pod = tool_parameters.get('pod', '.*')
start_time = tool_parameters.get("startTime")
end_time = tool_parameters.get("endTime")
params = {
'metricName': '基础设施情况 - 容器CPU - 容器CPU节流时间 - Containerd',
'params': {
'cadvisor_job_name': cadvisor_job_name,
'namespace': namespace,
'pod': pod
},
'startTime': start_time,
'endTime': end_time,
'step': APOUtils.get_step(start_time, end_time),
}
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
list = resp.json()['result']
list = json.dumps({
'type': 'metric',
'display': True,
'unit': list['unit'],
'data': {
'timeseries': list['timeseries']
}
})
yield self.create_text_message(list)

@ -1,75 +0,0 @@
identity:
name: 容器CPU节流时长(使用Containerd容器运行时,按容器和Pod统计)
author: APO
label:
en_US: Container CPU throttling time (Containerd runtime, aggregated by container and Pod)
zh_Hans: 容器CPU节流时长(使用Containerd容器运行时,按容器和Pod统计)
description:
human:
en_US: Container CPU throttling time (Containerd runtime, aggregated by container and Pod)
zh_Hans: 容器CPU节流时长(使用Containerd容器运行时,按容器和Pod统计)
llm: Container CPU throttling time (Containerd runtime, aggregated by container and Pod)
display:
type: metric
title: 基础设施情况 - 容器CPU - 容器CPU节流时间 - Containerd
unit: "s"
parameters:
- name: cadvisor_job_name
type: string
required: False
label:
en_US: cAdvisor job name
zh_Hans: cAdvisor任务名称
human_description:
en_US: cAdvisor job name
zh_Hans: cAdvisor任务名称
llm_description: cAdvisor job name
form: llm
- name: namespace
type: string
required: False
label:
en_US: Namespace
zh_Hans: 命名空间
human_description:
en_US: Namespace
zh_Hans: 命名空间
llm_description: Namespace
form: llm
- name: pod
type: string
required: False
label:
en_US: Pod name
zh_Hans: Pod名称
human_description:
en_US: Pod name
zh_Hans: Pod名称
llm_description: Pod name
form: llm
- name: startTime
type: number
required: true
label:
en_US: startTime
zh_Hans: startTime
pt_BR: startTime
human_description:
en_US: Data query start time
zh_Hans: 开始时间 (微秒)
pt_BR: Data query start time
llm_description: Data query start time
form: llm
- name: endTime
type: number
required: true
label:
en_US: endTime
zh_Hans: endTime
pt_BR: endTime
human_description:
en_US: Data query end time
zh_Hans: 结束时间 (微秒)
pt_BR: Data query end time
llm_description: Data query start time
form: llm

@ -1,44 +0,0 @@
import json
from collections.abc import Generator
from typing import Any, Optional
import requests
from configs import dify_config
from core.tools.builtin_tool.tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage
from libs.apo_utils import APOUtils
class LinuxNetworkDroppedPacketsReceiveTool(BuiltinTool):
def _invoke(
self,
user_id: str,
tool_parameters: dict[str, Any],
conversation_id: Optional[str] = None,
app_id: Optional[str] = None,
message_id: Optional[str] = None,
) -> Generator[ToolInvokeMessage, None, None]:
cluster = tool_parameters.get('cluster', '.*')
start_time = tool_parameters.get("startTime")
end_time = tool_parameters.get("endTime")
params = {
'metricName': '集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (receive)',
'params': {
'cluster': cluster
},
'startTime': start_time,
'endTime': end_time,
'step': APOUtils.get_step(start_time, end_time),
}
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
list = resp.json()['result']
list = json.dumps({
'type': 'metric',
'display': True,
'unit': list['unit'],
'data': {
'timeseries': list['timeseries']
}
})
yield self.create_text_message(list)

@ -1,53 +0,0 @@
identity:
name: Linux集群网络接收丢包数
author: APO
label:
en_US: Linux cluster network receive packet drops
zh_Hans: Linux集群网络接收丢包数
description:
human:
en_US: Linux cluster network receive packet drops
zh_Hans: Linux集群网络接收丢包数
llm: Linux cluster network receive packet drops
display:
type: metric
title: 集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (receive)
unit: "short"
parameters:
- name: cluster
type: string
required: False
label:
en_US: Cluster name
zh_Hans: 集群名称
human_description:
en_US: Cluster name
zh_Hans: 集群名称
llm_description: Cluster name
form: llm
- name: startTime
type: number
required: true
label:
en_US: startTime
zh_Hans: startTime
pt_BR: startTime
human_description:
en_US: Data query start time
zh_Hans: 开始时间 (微秒)
pt_BR: Data query start time
llm_description: Data query start time
form: llm
- name: endTime
type: number
required: true
label:
en_US: endTime
zh_Hans: endTime
pt_BR: endTime
human_description:
en_US: Data query end time
zh_Hans: 结束时间 (微秒)
pt_BR: Data query end time
llm_description: Data query start time
form: llm

@ -1,44 +0,0 @@
import json
from collections.abc import Generator
from typing import Any, Optional
import requests
from configs import dify_config
from core.tools.builtin_tool.tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage
from libs.apo_utils import APOUtils
class LinuxNetworkDroppedPacketsTransmitTool(BuiltinTool):
def _invoke(
self,
user_id: str,
tool_parameters: dict[str, Any],
conversation_id: Optional[str] = None,
app_id: Optional[str] = None,
message_id: Optional[str] = None,
) -> Generator[ToolInvokeMessage, None, None]:
cluster = tool_parameters.get('cluster', '.*')
start_time = tool_parameters.get("startTime")
end_time = tool_parameters.get("endTime")
params = {
'metricName': '集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (transmit)',
'params': {
'cluster': cluster
},
'startTime': start_time,
'endTime': end_time,
'step': APOUtils.get_step(start_time, end_time),
}
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
list = resp.json()['result']
list = json.dumps({
'type': 'metric',
'display': True,
'unit': list['unit'],
'data': {
'timeseries': list['timeseries']
}
})
yield self.create_text_message(list)

@ -1,53 +0,0 @@
identity:
name: Linux集群网络发送丢包数
author: APO
label:
en_US: Linux cluster network transmit packet drops
zh_Hans: Linux集群网络发送丢包数
description:
human:
en_US: Linux cluster network transmit packet drops
zh_Hans: Linux集群网络发送丢包数
llm: Linux cluster network transmit packet drops
display:
type: metric
title: 集群总览 - 总览 - 网络饱和 - 丢包数 - Linux Packets dropped (transmit)
unit: "short"
parameters:
- name: cluster
type: string
required: False
label:
en_US: Cluster name
zh_Hans: 集群名称
human_description:
en_US: Cluster name
zh_Hans: 集群名称
llm_description: Cluster name
form: llm
- name: startTime
type: number
required: true
label:
en_US: startTime
zh_Hans: startTime
pt_BR: startTime
human_description:
en_US: Data query start time
zh_Hans: 开始时间 (微秒)
pt_BR: Data query start time
llm_description: Data query start time
form: llm
- name: endTime
type: number
required: true
label:
en_US: endTime
zh_Hans: endTime
pt_BR: endTime
human_description:
en_US: Data query end time
zh_Hans: 结束时间 (微秒)
pt_BR: Data query end time
llm_description: Data query start time
form: llm

@ -1,44 +0,0 @@
import json
from collections.abc import Generator
from typing import Any, Optional
import requests
from configs import dify_config
from core.tools.builtin_tool.tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage
from libs.apo_utils import APOUtils
class NodeCpuUtilizationLinuxTool(BuiltinTool):
def _invoke(
self,
user_id: str,
tool_parameters: dict[str, Any],
conversation_id: Optional[str] = None,
app_id: Optional[str] = None,
message_id: Optional[str] = None,
) -> Generator[ToolInvokeMessage, None, None]:
cluster = tool_parameters.get('cluster', '.*')
start_time = tool_parameters.get("startTime")
end_time = tool_parameters.get("endTime")
params = {
'metricName': '集群总览 - 节点资源使用 - 节点CPU使用率 - Linux',
'params': {
'cluster': cluster
},
'startTime': start_time,
'endTime': end_time,
'step': APOUtils.get_step(start_time, end_time),
}
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
list = resp.json()['result']
list = json.dumps({
'type': 'metric',
'display': True,
'unit': list['unit'],
'data': {
'timeseries': list['timeseries']
}
})
yield self.create_text_message(list)

@ -1,53 +0,0 @@
identity:
name: Linux节点CPU使用率
author: APO
label:
en_US: Linux node CPU utilization rate
zh_Hans: Linux节点CPU使用率
description:
human:
en_US: Linux node CPU utilization rate
zh_Hans: Linux节点CPU使用率
llm: Linux node CPU utilization rate
display:
type: metric
title: 集群总览 - 节点资源使用 - 节点CPU使用率 - Linux
unit: "percentunit"
parameters:
- name: cluster
type: string
required: False
label:
en_US: Cluster name
zh_Hans: 集群名称
human_description:
en_US: Cluster name
zh_Hans: 集群名称
llm_description: Cluster name
form: llm
- name: startTime
type: number
required: true
label:
en_US: startTime
zh_Hans: startTime
pt_BR: startTime
human_description:
en_US: Data query start time
zh_Hans: 开始时间 (微秒)
pt_BR: Data query start time
llm_description: Data query start time
form: llm
- name: endTime
type: number
required: true
label:
en_US: endTime
zh_Hans: endTime
pt_BR: endTime
human_description:
en_US: Data query end time
zh_Hans: 结束时间 (微秒)
pt_BR: Data query end time
llm_description: Data query start time
form: llm

@ -1,44 +0,0 @@
import json
from collections.abc import Generator
from typing import Any, Optional
import requests
from configs import dify_config
from core.tools.builtin_tool.tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage
from libs.apo_utils import APOUtils
class NodeMemoryUsageLinuxTool(BuiltinTool):
def _invoke(
self,
user_id: str,
tool_parameters: dict[str, Any],
conversation_id: Optional[str] = None,
app_id: Optional[str] = None,
message_id: Optional[str] = None,
) -> Generator[ToolInvokeMessage, None, None]:
cluster = tool_parameters.get('cluster', '.*')
start_time = tool_parameters.get("startTime")
end_time = tool_parameters.get("endTime")
params = {
'metricName': '集群总览 - 节点资源使用 - 节点内存使用量 - Linux',
'params': {
'cluster': cluster
},
'startTime': start_time,
'endTime': end_time,
'step': APOUtils.get_step(start_time, end_time),
}
resp = requests.post(dify_config.APO_BACKEND_URL + '/api/metric/query', json=params)
list = resp.json()['result']
list = json.dumps({
'type': 'metric',
'display': True,
'unit': list['unit'],
'data': {
'timeseries': list['timeseries']
}
})
yield self.create_text_message(list)

@ -1,53 +0,0 @@
identity:
name: Linux节点内存使用字节数
author: APO
label:
en_US: Linux node memory usage in bytes
zh_Hans: Linux节点内存使用字节数
description:
human:
en_US: Linux node memory usage in bytes
zh_Hans: Linux节点内存使用字节数
llm: Linux node memory usage in bytes
display:
type: metric
title: 集群总览 - 节点资源使用 - 节点内存使用量 - Linux
unit: "bytes"
parameters:
- name: cluster
type: string
required: False
label:
en_US: Cluster name
zh_Hans: 集群名称
human_description:
en_US: Cluster name
zh_Hans: 集群名称
llm_description: Cluster name
form: llm
- name: startTime
type: number
required: true
label:
en_US: startTime
zh_Hans: startTime
pt_BR: startTime
human_description:
en_US: Data query start time
zh_Hans: 开始时间 (微秒)
pt_BR: Data query start time
llm_description: Data query start time
form: llm
- name: endTime
type: number
required: true
label:
en_US: endTime
zh_Hans: endTime
pt_BR: endTime
human_description:
en_US: Data query end time
zh_Hans: 结束时间 (微秒)
pt_BR: Data query end time
llm_description: Data query start time
form: llm

@ -292,6 +292,11 @@ class AccountService:
def delete_account(account: Account) -> None: def delete_account(account: Account) -> None:
"""Delete account. This method only adds a task to the queue for deletion.""" """Delete account. This method only adds a task to the queue for deletion."""
delete_account_task.delay(account.id) delete_account_task.delay(account.id)
@staticmethod
def delete_apo_account(account: Account):
db.session.delete(account)
db.session.commit()
@staticmethod @staticmethod
def link_account_integrate(provider: str, open_id: str, account: Account) -> None: def link_account_integrate(provider: str, open_id: str, account: Account) -> None:
@ -968,6 +973,52 @@ class RegisterService:
return token return token
@classmethod
def apo_add_new_member(
cls, tenant: Tenant, email: str, password: str, language: str, role: str = "normal", inviter: Account | None = None
) -> str:
if not inviter:
raise ValueError("Inviter is required")
"""add a new member"""
with Session(db.engine) as session:
account = session.query(Account).filter_by(email=email).first()
if not account:
TenantService.check_member_permission(tenant, inviter, None, "add")
name = email.split("@")[0]
account = cls.register(
email=email, name=name, language=language, password=password, status=AccountStatus.ACTIVE, is_setup=True
)
# Create new tenant member for invited tenant
TenantService.create_tenant_member(tenant, account, role)
TenantService.switch_tenant(account, tenant.id)
else:
TenantService.check_member_permission(tenant, inviter, account, "add")
ta = TenantAccountJoin.query.filter_by(tenant_id=tenant.id, account_id=account.id).first()
if not ta:
TenantService.create_tenant_member(tenant, account, role)
# Support resend invitation email when the account is pending status
if account.status != AccountStatus.PENDING.value:
raise AccountAlreadyInTenantError("Account already in tenant.")
return ""
# token = cls.generate_invite_token(tenant, account)
# # send email
# send_invite_member_mail_task.delay(
# language=account.interface_language,
# to=email,
# token=token,
# inviter_name=inviter.name if inviter else "Dify",
# workspace_name=tenant.name,
# )
# return token
@classmethod @classmethod
def generate_invite_token(cls, tenant: Tenant, account: Account) -> str: def generate_invite_token(cls, tenant: Tenant, account: Account) -> str:
token = str(uuid.uuid4()) token = str(uuid.uuid4())

Loading…
Cancel
Save