eigent/server/app/controller/trigger/slack_controller.py
Ahmed Awelkair A 4fb2e5db9a
feat: schedule and webhook triggers (#823)
Co-authored-by: Douglas <douglas.ym.lai@gmail.com>
Co-authored-by: a7m-1st <ahmed.jimi.awelkair500@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Tong Chen <web_chentong@163.com>
2026-03-02 20:38:02 +08:00

135 lines
4.5 KiB
Python

# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
# 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.
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select, and_
from typing import Optional, List
import logging
from pydantic import BaseModel
from app.model.config.config import Config
from app.type.config_group import ConfigGroup
from app.component.auth import Auth, auth_must
from app.component.database import session
logger = logging.getLogger("server_slack_controller")
class SlackChannelOut(BaseModel):
"""Output model for Slack channels."""
id: str
name: str
is_private: bool = False
is_member: bool = False
num_members: Optional[int] = None
class SlackChannelsResponse(BaseModel):
"""Response model for Slack channels list."""
channels: List[SlackChannelOut]
has_credentials: bool
router = APIRouter(prefix="/trigger/slack", tags=["Slack Integration"])
@router.get("/channels", name="get slack channels")
def get_slack_channels(
session: Session = Depends(session),
auth: Auth = Depends(auth_must)
) -> SlackChannelsResponse:
"""
Get list of Slack channels for the authenticated user.
This endpoint fetches channels from the user's Slack workspace using their
stored credentials. Requires SLACK_BOT_TOKEN to be configured in user configs.
"""
user_id = auth.user.id
# Get Slack credentials from config
configs = session.exec(
select(Config).where(
and_(
Config.user_id == int(user_id),
Config.config_group == ConfigGroup.SLACK.value
)
)
).all()
credentials = {config.config_name: config.config_value for config in configs}
bot_token = credentials.get("SLACK_BOT_TOKEN")
if not bot_token:
logger.warning("Slack credentials not found", extra={"user_id": user_id})
return SlackChannelsResponse(channels=[], has_credentials=False)
try:
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
client = WebClient(token=bot_token)
# Fetch all channels (public and private the bot has access to)
channels = []
cursor = None
while True:
response = client.conversations_list(
types="public_channel,private_channel",
cursor=cursor,
limit=200
)
for channel in response.get("channels", []):
channels.append(SlackChannelOut(
id=channel.get("id"),
name=channel.get("name"),
is_private=channel.get("is_private", False),
is_member=channel.get("is_member", False),
num_members=channel.get("num_members")
))
# Check for pagination
cursor = response.get("response_metadata", {}).get("next_cursor")
if not cursor:
break
logger.info("Slack channels fetched", extra={
"user_id": user_id,
"channel_count": len(channels)
})
return SlackChannelsResponse(channels=channels, has_credentials=True)
except ImportError:
logger.error("slack_sdk not installed")
raise HTTPException(
status_code=500,
detail="Slack SDK not installed on server"
)
except SlackApiError as e:
logger.error("Slack API error", extra={
"user_id": user_id,
"error": str(e)
})
raise HTTPException(
status_code=400,
detail=f"Slack API error: {e.response.get('error', 'Unknown error')}"
)
except Exception as e:
logger.error("Error fetching Slack channels", extra={
"user_id": user_id,
"error": str(e)
}, exc_info=True)
raise HTTPException(status_code=500, detail="Failed to fetch Slack channels")