feat(modules): 帮助中心、工单、工作流与多渠道接入
补齐 FAQ、帮助中心、工单、可视化工作流及 Telegram/WhatsApp/Slack 等渠道模块。
This commit is contained in:
1 parent
ba91abc4b2
commit
83a16ed07d
225 files changed
+59337
No files matched your search
@@ -0,0 +1,185 @@
|
||||
"""
|
||||
Copyright 2024-2026 ChatterMate
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
from sqlalchemy.orm import Session
|
||||
from app.repositories.workflow import WorkflowRepository
|
||||
from app.repositories.agent import AgentRepository
|
||||
from app.models.workflow import Workflow
|
||||
from app.models.schemas.workflow import WorkflowCreate
|
||||
from app.core.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class WorkflowService:
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
self.workflow_repo = WorkflowRepository(db)
|
||||
self.agent_repo = AgentRepository(db)
|
||||
|
||||
def create_workflow(self, workflow_data: WorkflowCreate, created_by: UUID, organization_id: UUID) -> Workflow:
|
||||
"""Create a new workflow with validation"""
|
||||
|
||||
# Validate agent exists and belongs to organization
|
||||
agent = self.agent_repo.get_by_id(workflow_data.agent_id)
|
||||
if not agent:
|
||||
raise ValueError("Agent not found")
|
||||
|
||||
if agent.organization_id != organization_id:
|
||||
raise ValueError("Agent does not belong to your organization")
|
||||
|
||||
# Check if workflow already exists for this agent
|
||||
existing_workflow = self.workflow_repo.get_workflows_by_agent(workflow_data.agent_id)
|
||||
if existing_workflow:
|
||||
raise ValueError("Agent already has a workflow. Only one workflow per agent is allowed.")
|
||||
|
||||
# Check if workflow name already exists in organization
|
||||
existing_workflow_name = self.workflow_repo.get_by_name(
|
||||
workflow_data.name,
|
||||
organization_id
|
||||
)
|
||||
if existing_workflow_name:
|
||||
raise ValueError(f"Workflow with name '{workflow_data.name}' already exists")
|
||||
|
||||
# Create workflow data
|
||||
workflow_dict = workflow_data.model_dump()
|
||||
workflow_dict.update({
|
||||
"created_by": created_by,
|
||||
"organization_id": organization_id
|
||||
})
|
||||
|
||||
# Create workflow
|
||||
workflow = self.workflow_repo.create_workflow(**workflow_dict)
|
||||
|
||||
logger.info(f"Created workflow {workflow.id} for agent {workflow_data.agent_id}")
|
||||
return workflow
|
||||
|
||||
def get_workflow_by_agent_id(self, agent_id: UUID, organization_id: UUID) -> Optional[Workflow]:
|
||||
"""Get workflow by agent ID with organization validation"""
|
||||
|
||||
# Validate agent exists and belongs to organization
|
||||
agent = self.agent_repo.get_by_id(agent_id)
|
||||
if not agent:
|
||||
raise ValueError("Agent not found")
|
||||
|
||||
if agent.organization_id != organization_id:
|
||||
raise ValueError("Agent does not belong to your organization")
|
||||
|
||||
# Get workflows for this agent
|
||||
workflows = self.workflow_repo.get_workflows_by_agent(agent_id)
|
||||
|
||||
# Return the first workflow (should be only one due to our constraint)
|
||||
return workflows[0] if workflows else None
|
||||
|
||||
def update_workflow(self, workflow_id: UUID, workflow_data: dict, organization_id: UUID) -> Optional[Workflow]:
|
||||
"""Update workflow with validation"""
|
||||
|
||||
# Get existing workflow
|
||||
workflow = self.workflow_repo.get_by_id(workflow_id)
|
||||
if not workflow:
|
||||
raise ValueError("Workflow not found")
|
||||
|
||||
# Verify organization access
|
||||
if workflow.organization_id != organization_id:
|
||||
raise ValueError("Workflow does not belong to your organization")
|
||||
|
||||
# If name is being updated, check for duplicates
|
||||
if 'name' in workflow_data and workflow_data['name'] != workflow.name:
|
||||
existing_workflow = self.workflow_repo.get_by_name(
|
||||
workflow_data['name'],
|
||||
organization_id
|
||||
)
|
||||
if existing_workflow and existing_workflow.id != workflow_id:
|
||||
raise ValueError(f"Workflow with name '{workflow_data['name']}' already exists")
|
||||
|
||||
# If agent_id is being updated, validate the new agent and check constraint
|
||||
if 'agent_id' in workflow_data and workflow_data['agent_id'] != workflow.agent_id:
|
||||
# Validate new agent exists and belongs to organization
|
||||
agent = self.agent_repo.get_by_id(workflow_data['agent_id'])
|
||||
if not agent:
|
||||
raise ValueError("Agent not found")
|
||||
|
||||
if agent.organization_id != organization_id:
|
||||
raise ValueError("Agent does not belong to your organization")
|
||||
|
||||
# Check if new agent already has a workflow
|
||||
existing_workflows = self.workflow_repo.get_workflows_by_agent(workflow_data['agent_id'])
|
||||
if existing_workflows:
|
||||
raise ValueError("Agent already has a workflow. Only one workflow per agent is allowed.")
|
||||
|
||||
# Check if status is being updated to published
|
||||
if 'status' in workflow_data and workflow_data['status'] == 'published':
|
||||
# When publishing, update the agent's active_workflow_id and use_workflow
|
||||
agent = self.agent_repo.get_by_id(workflow.agent_id)
|
||||
if agent:
|
||||
self.agent_repo.update_agent(
|
||||
workflow.agent_id,
|
||||
active_workflow_id=workflow_id,
|
||||
use_workflow=True
|
||||
)
|
||||
logger.info(f"Updated agent {workflow.agent_id} active_workflow_id to {workflow_id}")
|
||||
|
||||
# Check if status is being updated to draft (unpublished)
|
||||
if 'status' in workflow_data and workflow_data['status'] == 'draft':
|
||||
# When unpublishing, clear the agent's active_workflow_id and disable workflow
|
||||
agent = self.agent_repo.get_by_id(workflow.agent_id)
|
||||
if agent and agent.active_workflow_id == workflow_id:
|
||||
self.agent_repo.update_agent(
|
||||
workflow.agent_id,
|
||||
active_workflow_id=None,
|
||||
use_workflow=False
|
||||
)
|
||||
logger.info(f"Cleared agent {workflow.agent_id} active_workflow_id")
|
||||
|
||||
# Update workflow
|
||||
updated_workflow = self.workflow_repo.update_workflow(workflow_id, **workflow_data)
|
||||
|
||||
logger.info(f"Updated workflow {workflow_id}")
|
||||
return updated_workflow
|
||||
|
||||
def delete_workflow(self, workflow_id: UUID, organization_id: UUID) -> bool:
|
||||
"""Delete workflow with validation"""
|
||||
|
||||
# Get existing workflow
|
||||
workflow = self.workflow_repo.get_by_id(workflow_id)
|
||||
if not workflow:
|
||||
raise ValueError("Workflow not found")
|
||||
|
||||
# Verify organization access
|
||||
if workflow.organization_id != organization_id:
|
||||
raise ValueError("Workflow does not belong to your organization")
|
||||
|
||||
# Clear agent's active_workflow_id if this workflow is active
|
||||
agent = self.agent_repo.get_by_id(workflow.agent_id)
|
||||
if agent and agent.active_workflow_id == workflow_id:
|
||||
self.agent_repo.update_agent(
|
||||
workflow.agent_id,
|
||||
active_workflow_id=None,
|
||||
use_workflow=False
|
||||
)
|
||||
logger.info(f"Cleared agent {workflow.agent_id} active_workflow_id before deleting workflow")
|
||||
|
||||
# Delete workflow
|
||||
success = self.workflow_repo.delete_workflow(workflow_id)
|
||||
|
||||
if success:
|
||||
logger.info(f"Deleted workflow {workflow_id}")
|
||||
|
||||
return success
|
||||
|
||||
|
||||
Reference in new issue
Block a user