mirror of https://github.com/kortix-ai/suna.git
198 lines
7.0 KiB
Python
198 lines
7.0 KiB
Python
from fastapi import APIRouter, HTTPException, Depends, Query
|
|
from fastapi.responses import RedirectResponse
|
|
from typing import Optional
|
|
from pydantic import BaseModel
|
|
|
|
from .providers.slack_oauth import SlackOAuthManager
|
|
from services.supabase import DBConnection
|
|
from utils.auth_utils import get_current_user_id_from_jwt
|
|
from utils.logger import logger
|
|
|
|
router = APIRouter(prefix="/api/integrations/slack", tags=["slack-oauth"])
|
|
|
|
slack_oauth_manager: Optional[SlackOAuthManager] = None
|
|
db = None
|
|
|
|
def initialize(database: DBConnection):
|
|
"""Initialize the Slack OAuth API with database connection."""
|
|
global db, slack_oauth_manager
|
|
db = database
|
|
slack_oauth_manager = SlackOAuthManager(db)
|
|
|
|
class SlackInstallRequest(BaseModel):
|
|
agent_id: str
|
|
|
|
class SlackInstallResponse(BaseModel):
|
|
install_url: str
|
|
state: str
|
|
|
|
class SlackCallbackResponse(BaseModel):
|
|
success: bool
|
|
trigger_id: Optional[str] = None
|
|
workspace_name: Optional[str] = None
|
|
bot_name: Optional[str] = None
|
|
webhook_url: Optional[str] = None
|
|
error: Optional[str] = None
|
|
|
|
@router.post("/install", response_model=SlackInstallResponse)
|
|
async def initiate_slack_install(
|
|
request: SlackInstallRequest,
|
|
user_id: str = Depends(get_current_user_id_from_jwt)
|
|
):
|
|
"""Initiate Slack OAuth flow for agent installation."""
|
|
if not slack_oauth_manager:
|
|
raise HTTPException(status_code=500, detail="Slack OAuth not initialized")
|
|
|
|
try:
|
|
await verify_agent_access(request.agent_id, user_id)
|
|
|
|
install_url = slack_oauth_manager.generate_install_url(request.agent_id, user_id)
|
|
|
|
from urllib.parse import urlparse, parse_qs
|
|
parsed_url = urlparse(install_url)
|
|
state = parse_qs(parsed_url.query).get('state', [''])[0]
|
|
|
|
return SlackInstallResponse(
|
|
install_url=install_url,
|
|
state=state
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error initiating Slack install: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.get("/callback")
|
|
async def handle_slack_callback(
|
|
code: str = Query(..., description="OAuth authorization code"),
|
|
state: str = Query(..., description="State parameter"),
|
|
error: Optional[str] = Query(None, description="OAuth error")
|
|
):
|
|
"""Handle Slack OAuth callback."""
|
|
if not slack_oauth_manager:
|
|
raise HTTPException(status_code=500, detail="Slack OAuth not initialized")
|
|
|
|
if error:
|
|
logger.error(f"Slack OAuth error: {error}")
|
|
return RedirectResponse(
|
|
url=f"http://localhost:3000/agents?slack_error={error}",
|
|
status_code=302
|
|
)
|
|
|
|
try:
|
|
result = await slack_oauth_manager.handle_oauth_callback(code, state)
|
|
|
|
if result["success"]:
|
|
redirect_url = (
|
|
f"http://localhost:3000/agents?"
|
|
f"slack_success=true&"
|
|
f"trigger_id={result['trigger_id']}&"
|
|
f"workspace={result.get('workspace_name', '')}&"
|
|
f"bot_name={result.get('bot_name', '')}"
|
|
)
|
|
return RedirectResponse(url=redirect_url, status_code=302)
|
|
else:
|
|
# Redirect to frontend with error
|
|
return RedirectResponse(
|
|
url=f"http://localhost:3000/agents?slack_error={result['error']}",
|
|
status_code=302
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error handling Slack callback: {e}")
|
|
return RedirectResponse(
|
|
url=f"http://localhost:3000/agents?slack_error=callback_failed",
|
|
status_code=302
|
|
)
|
|
|
|
@router.get("/status/{agent_id}")
|
|
async def get_slack_status(
|
|
agent_id: str,
|
|
user_id: str = Depends(get_current_user_id_from_jwt)
|
|
):
|
|
"""Get Slack integration status for an agent."""
|
|
try:
|
|
await verify_agent_access(agent_id, user_id)
|
|
|
|
client = await db.client
|
|
result = await client.table('agent_triggers')\
|
|
.select('trigger_id, name, is_active')\
|
|
.eq('agent_id', agent_id)\
|
|
.eq('trigger_type', 'slack')\
|
|
.execute()
|
|
|
|
slack_triggers = []
|
|
for trigger in result.data:
|
|
oauth_result = await client.table('slack_oauth_installations')\
|
|
.select('team_name, bot_name, installed_at')\
|
|
.eq('trigger_id', trigger['trigger_id'])\
|
|
.execute()
|
|
|
|
oauth_data = oauth_result.data[0] if oauth_result.data else {}
|
|
|
|
slack_triggers.append({
|
|
"trigger_id": trigger["trigger_id"],
|
|
"name": trigger["name"],
|
|
"is_active": trigger["is_active"],
|
|
"workspace_name": oauth_data.get("team_name"),
|
|
"bot_name": oauth_data.get("bot_name"),
|
|
"installed_at": oauth_data.get("installed_at")
|
|
})
|
|
|
|
return {
|
|
"agent_id": agent_id,
|
|
"has_slack_integration": len(slack_triggers) > 0,
|
|
"slack_triggers": slack_triggers
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting Slack status: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.delete("/uninstall/{trigger_id}")
|
|
async def uninstall_slack_integration(
|
|
trigger_id: str,
|
|
user_id: str = Depends(get_current_user_id_from_jwt)
|
|
):
|
|
"""Uninstall Slack integration for a trigger."""
|
|
try:
|
|
client = await db.client
|
|
trigger_result = await client.table('agent_triggers')\
|
|
.select('agent_id')\
|
|
.eq('trigger_id', trigger_id)\
|
|
.execute()
|
|
|
|
if not trigger_result.data:
|
|
raise HTTPException(status_code=404, detail="Trigger not found")
|
|
|
|
agent_id = trigger_result.data[0]['agent_id']
|
|
await verify_agent_access(agent_id, user_id)
|
|
|
|
from .core import TriggerManager
|
|
trigger_manager = TriggerManager(db)
|
|
success = await trigger_manager.delete_trigger(trigger_id)
|
|
|
|
if success:
|
|
await client.table('slack_oauth_installations')\
|
|
.delete()\
|
|
.eq('trigger_id', trigger_id)\
|
|
.execute()
|
|
|
|
return {"success": True, "message": "Slack integration uninstalled"}
|
|
else:
|
|
raise HTTPException(status_code=500, detail="Failed to uninstall integration")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error uninstalling Slack integration: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
async def verify_agent_access(agent_id: str, user_id: str):
|
|
"""Verify that the user has access to the agent."""
|
|
client = await db.client
|
|
result = await client.table('agents').select('account_id').eq('agent_id', agent_id).execute()
|
|
|
|
if not result.data:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
|
|
agent = result.data[0]
|
|
if agent['account_id'] != user_id:
|
|
raise HTTPException(status_code=403, detail="Access denied") |