mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-18 13:47:21 +08:00
feat: implement Slack data source connector (#15188)
### What problem does this PR solve? Closes #15187. RAGFlow shipped a Slack connector (`common/data_source/slack_connector.py`) but it was never usable: `Slack._generate()` in the sync worker was a `pass` stub, the connector's document-generating code was incompatible with the current data model, and Slack was commented out of the data-source settings UI. As a result, teams had no way to index Slack channels/threads into a knowledge base. This PR completes the connector end to end. **Backend** - `common/data_source/slack_connector.py` - Rewrote `thread_to_doc` to produce a blob-based `Document` (`extension`/`blob`/`size_bytes`). The previous implementation built the doc with a `sections=[...]` argument and omitted the now-required `blob`/`extension`/ `size_bytes` fields, so it raised a validation error against the current `Document` model. Thread messages are now cleaned and flattened into a single UTF-8 text blob. - Added `load_from_state()` / `poll_source(start, end)` generators. The connector's checkpoint interface is a no-op stub, so both full and incremental syncs run through a single channel-iterating generator built on the existing module helpers (`get_channels`, `filter_channels`, `get_channel_messages`, `_process_message`), with per-channel thread de-duplication. - `rag/svr/sync_data_source.py` - Implemented `Slack._generate()`. Credentials are loaded via `StaticCredentialsProvider` (the connector requires `slack_bot_token` and does not support `load_credentials`). Supports full reindex and incremental polling from `poll_range_start`, plus the optional channel filter. Modeled on the Confluence/Dropbox wrappers. - `SlackConnector` was already exported from `common/data_source/__init__.py`. **Frontend (`web/`)** - Enabled the `SLACK` data-source enum and added its form fields (Slack bot token + optional channel filter), default values, display metadata, and a Slack icon. - Added `slackDescription` / `slackBotTokenTip` / `slackChannelsTip` strings to `en.ts` and `zh.ts`. **Tests** - `test/unit_test/data_source/test_slack_connector_unit.py`: unit tests covering credential loading (`load_credentials` raises, `set_credentials_provider` initializes clients, missing credentials raises) and document generation (standalone message + flattened thread, blob/extension/size_bytes/metadata, and the incremental poll time window). All 5 pass; `ruff check` is clean. Required Slack scopes: `channels:read`, `channels:history`, `users:read`. ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@@ -43,9 +43,9 @@ export enum DataSourceKey {
|
||||
POSTGRESQL = 'postgresql',
|
||||
REST_API = 'rest_api',
|
||||
RSS = 'rss',
|
||||
SLACK = 'slack',
|
||||
SHAREPOINT = 'sharepoint',
|
||||
|
||||
// SLACK = 'slack',
|
||||
// TEAMS = 'teams',
|
||||
}
|
||||
|
||||
@@ -130,6 +130,12 @@ export const DataSourceFeatureVisibilityMap: Partial<
|
||||
[DataSourceKey.MOODLE]: {
|
||||
syncDeletedFiles: true,
|
||||
},
|
||||
[DataSourceKey.SLACK]: {
|
||||
syncDeletedFiles: true,
|
||||
},
|
||||
[DataSourceKey.SHAREPOINT]: {
|
||||
syncDeletedFiles: true,
|
||||
},
|
||||
[DataSourceKey.MYSQL]: {
|
||||
syncDeletedFiles: true,
|
||||
},
|
||||
@@ -213,6 +219,11 @@ export const generateDataSourceInfo = (t: TFunction) => {
|
||||
description: t(`setting.${DataSourceKey.MOODLE}Description`),
|
||||
icon: <SvgIcon name={'data-source/moodle'} width={38} />,
|
||||
},
|
||||
[DataSourceKey.SLACK]: {
|
||||
name: 'Slack',
|
||||
description: t(`setting.${DataSourceKey.SLACK}Description`),
|
||||
icon: <SvgIcon name={'data-source/slack'} width={38} />,
|
||||
},
|
||||
[DataSourceKey.SHAREPOINT]: {
|
||||
name: 'SharePoint',
|
||||
description: t(`setting.${DataSourceKey.SHAREPOINT}Description`),
|
||||
@@ -659,6 +670,22 @@ export const DataSourceFormFields = {
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
[DataSourceKey.SLACK]: [
|
||||
{
|
||||
label: 'Slack Bot Token',
|
||||
name: 'config.credentials.slack_bot_token',
|
||||
type: FormFieldType.Password,
|
||||
required: true,
|
||||
tooltip: t('setting.slackBotTokenTip'),
|
||||
},
|
||||
{
|
||||
label: 'Channels',
|
||||
name: 'config.channels',
|
||||
type: FormFieldType.Tag,
|
||||
required: false,
|
||||
tooltip: t('setting.slackChannelsTip'),
|
||||
},
|
||||
],
|
||||
[DataSourceKey.SHAREPOINT]: [
|
||||
{
|
||||
label: 'Site URL',
|
||||
@@ -1542,6 +1569,16 @@ export const DataSourceFormDefaultValues = {
|
||||
},
|
||||
},
|
||||
},
|
||||
[DataSourceKey.SLACK]: {
|
||||
name: '',
|
||||
source: DataSourceKey.SLACK,
|
||||
config: {
|
||||
channels: [],
|
||||
credentials: {
|
||||
slack_bot_token: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
[DataSourceKey.SHAREPOINT]: {
|
||||
name: '',
|
||||
source: DataSourceKey.SHAREPOINT,
|
||||
|
||||
Reference in New Issue
Block a user