mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-11 22:25:41 +08:00
close #16132 ## Summary This PR completes the Go-side merge and cleanup for chat channel APIs, including handler/service wiring, route registration, and test coverage. Implemented and aligned 5 chat channel APIs: ``` - POST `/api/v1/chat-channels` - GET `/api/v1/chat-channels` - GET `/api/v1/chat-channels/:channel_id` - PATCH `/api/v1/chat-channels/:channel_id` - DELETE `/api/v1/chat-channels/:channel_id` ``` Co-authored-by: Haruko386 <tryeverypossible@163.com>
234 lines
6.3 KiB
Go
234 lines
6.3 KiB
Go
// Copyright 2026 The InfiniFlow Authors. 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.
|
|
|
|
package service
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"ragflow/internal/common"
|
|
"ragflow/internal/dao"
|
|
"ragflow/internal/entity"
|
|
)
|
|
|
|
type ChatChannelService struct {
|
|
chatChannelDAO *dao.ChatChannelDAO
|
|
chatDAO *dao.ChatDAO
|
|
userTenantDAO *dao.UserTenantDAO
|
|
}
|
|
|
|
func NewChatChannelService() *ChatChannelService {
|
|
return &ChatChannelService{
|
|
chatChannelDAO: dao.NewChatChannel(),
|
|
chatDAO: dao.NewChatDAO(),
|
|
userTenantDAO: dao.NewUserTenantDAO(),
|
|
}
|
|
}
|
|
|
|
func (s *ChatChannelService) Insert(channel *entity.ChatChannel) error {
|
|
if channel == nil {
|
|
return errors.New("channel is nil")
|
|
}
|
|
if channel.ID == "" {
|
|
channel.ID = common.GenerateUUID()
|
|
}
|
|
if channel.Status == 0 {
|
|
channel.Status = 1
|
|
}
|
|
return s.chatChannelDAO.Create(channel)
|
|
}
|
|
|
|
func (s *ChatChannelService) GetByID(id string) (*entity.ChatChannel, error) {
|
|
if id == "" {
|
|
return nil, errors.New("id is empty")
|
|
}
|
|
return s.chatChannelDAO.GetByIDOnly(id)
|
|
}
|
|
|
|
func (s *ChatChannelService) List(tenantID string) ([]*entity.ChatChannelListResponse, error) {
|
|
return s.chatChannelDAO.ListByTenantID(tenantID)
|
|
}
|
|
|
|
func (s *ChatChannelService) CreateChatChannel(tenantID, name, channelType string, config entity.JSONMap, chatID *string) (*entity.ChatChannel, error) {
|
|
if chatID != nil && *chatID != "" {
|
|
dialog, err := s.chatDAO.GetByID(*chatID)
|
|
if err != nil {
|
|
if dao.IsNotFoundErr(err) {
|
|
return nil, errors.New("Can't find this chat assistant!")
|
|
}
|
|
return nil, err
|
|
}
|
|
if dialog.TenantID != tenantID {
|
|
return nil, errors.New("No authorization.")
|
|
}
|
|
}
|
|
row := &entity.ChatChannel{
|
|
ID: common.GenerateUUID(),
|
|
TenantID: tenantID,
|
|
Name: name,
|
|
Channel: channelType,
|
|
Config: config,
|
|
ChatID: chatID,
|
|
Status: 1,
|
|
}
|
|
|
|
if err := s.Insert(row); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
created, err := s.GetByID(row.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load created chat channel: %w", err)
|
|
}
|
|
return created, nil
|
|
}
|
|
|
|
func (s *ChatChannelService) accessible(userID, channelID string) (*entity.ChatChannel, bool, error) {
|
|
channel, err := s.chatChannelDAO.GetByIDOnly(channelID)
|
|
if err != nil {
|
|
if dao.IsNotFoundErr(err) {
|
|
return nil, false, nil
|
|
}
|
|
return nil, false, err
|
|
}
|
|
|
|
if channel.TenantID == userID {
|
|
return channel, true, nil
|
|
}
|
|
|
|
tenantIDs, err := s.userTenantDAO.GetTenantIDsByUserID(userID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
for _, tenantID := range tenantIDs {
|
|
if tenantID == channel.TenantID {
|
|
return channel, true, nil
|
|
}
|
|
}
|
|
|
|
return channel, false, nil
|
|
}
|
|
|
|
func (s *ChatChannelService) GetChatChannel(userID, channelID string) (*entity.ChatChannel, common.ErrorCode, error) {
|
|
_, ok, err := s.accessible(userID, channelID)
|
|
if err != nil {
|
|
return nil, common.CodeServerError, err
|
|
}
|
|
if !ok {
|
|
return nil, common.CodeAuthenticationError, errors.New("No authorization.")
|
|
}
|
|
|
|
channel, err := s.chatChannelDAO.GetByIDOnly(channelID)
|
|
if err != nil {
|
|
if dao.IsNotFoundErr(err) {
|
|
return nil, common.CodeDataError, errors.New("Can't find this chat channel!")
|
|
}
|
|
return nil, common.CodeServerError, err
|
|
}
|
|
return channel, common.CodeSuccess, nil
|
|
}
|
|
|
|
func (s *ChatChannelService) UpdateChatChannel(userID, channelID string, req map[string]interface{}) (*entity.ChatChannel, common.ErrorCode, error) {
|
|
channel, ok, err := s.accessible(userID, channelID)
|
|
if err != nil {
|
|
return nil, common.CodeServerError, err
|
|
}
|
|
if !ok {
|
|
return nil, common.CodeAuthenticationError, errors.New("No authorization.")
|
|
}
|
|
if channel == nil {
|
|
return nil, common.CodeDataError, errors.New("Can't find this chat channel!")
|
|
}
|
|
|
|
updates := map[string]interface{}{}
|
|
|
|
if value, exists := req["name"]; exists {
|
|
name, ok := value.(string)
|
|
if !ok {
|
|
return nil, common.CodeDataError, errors.New("name must be string")
|
|
}
|
|
updates["name"] = name
|
|
}
|
|
|
|
if value, exists := req["config"]; exists {
|
|
if value == nil {
|
|
updates["config"] = nil
|
|
} else {
|
|
config, ok := value.(map[string]interface{})
|
|
if !ok {
|
|
return nil, common.CodeDataError, errors.New("config must be object")
|
|
}
|
|
updates["config"] = entity.JSONMap(config)
|
|
}
|
|
}
|
|
|
|
if value, exists := req["chat_id"]; exists {
|
|
if value == nil {
|
|
updates["chat_id"] = nil
|
|
} else {
|
|
chatID, ok := value.(string)
|
|
if !ok {
|
|
return nil, common.CodeDataError, errors.New("chat_id must be string or null")
|
|
}
|
|
if chatID != "" {
|
|
dialog, err := s.chatDAO.GetByID(chatID)
|
|
if err != nil {
|
|
if dao.IsNotFoundErr(err) {
|
|
return nil, common.CodeDataError, errors.New("Can't find this chat assistant!")
|
|
}
|
|
return nil, common.CodeServerError, err
|
|
}
|
|
if dialog.TenantID != channel.TenantID {
|
|
return nil, common.CodeAuthenticationError, errors.New("No authorization.")
|
|
}
|
|
}
|
|
updates["chat_id"] = chatID
|
|
}
|
|
}
|
|
|
|
if len(updates) > 0 {
|
|
if err := s.chatChannelDAO.UpdateByID(channelID, channel.TenantID, updates); err != nil {
|
|
return nil, common.CodeDataError, err
|
|
}
|
|
}
|
|
|
|
updated, err := s.chatChannelDAO.GetByIDOnly(channelID)
|
|
if err != nil {
|
|
if dao.IsNotFoundErr(err) {
|
|
return nil, common.CodeDataError, errors.New("Can't find this chat channel!")
|
|
}
|
|
return nil, common.CodeServerError, err
|
|
}
|
|
return updated, common.CodeSuccess, nil
|
|
}
|
|
|
|
func (s *ChatChannelService) DeleteChatChannel(userID, channelID string) (bool, common.ErrorCode, error) {
|
|
channel, ok, err := s.accessible(userID, channelID)
|
|
if err != nil {
|
|
return false, common.CodeServerError, err
|
|
}
|
|
if !ok {
|
|
return false, common.CodeAuthenticationError, errors.New("No authorization.")
|
|
}
|
|
if channel == nil {
|
|
return false, common.CodeAuthenticationError, errors.New("No authorization.")
|
|
}
|
|
|
|
if err := s.chatChannelDAO.DeleteByID(channelID, channel.TenantID); err != nil {
|
|
return false, common.CodeDataError, err
|
|
}
|
|
return true, common.CodeSuccess, nil
|
|
}
|