mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-04 09:39:32 +08:00
fix: get team's search in own search-list (#16599)
### Summary As title:
This commit is contained in:
@@ -56,8 +56,13 @@ func (dao *SearchDAO) ListByTenantIDs(tenantIDs []string, userID string, page, p
|
||||
user.nickname,
|
||||
user.avatar as tenant_avatar
|
||||
`).
|
||||
Joins("LEFT JOIN user ON search.tenant_id = user.id").
|
||||
Where("(search.tenant_id IN ? OR search.tenant_id = ?) AND search.status = ?", tenantIDs, userID, "1")
|
||||
Joins("LEFT JOIN user ON search.tenant_id = user.id")
|
||||
|
||||
if len(tenantIDs) > 0 {
|
||||
query = query.Where("(search.tenant_id IN ? OR search.tenant_id = ?) AND search.status = ?", tenantIDs, userID, "1")
|
||||
} else {
|
||||
query = query.Where("search.tenant_id = ? AND search.status = ?", userID, "1")
|
||||
}
|
||||
|
||||
// Apply keyword filter
|
||||
if keywords != "" {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"net/http"
|
||||
"ragflow/internal/common"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -50,6 +51,23 @@ func (h *SearchHandler) SetCompletionDependencies(streamLLM *service.ModelProvid
|
||||
h.askService = askService
|
||||
}
|
||||
|
||||
func getSearchOwnerIDs(c *gin.Context) []string {
|
||||
values := c.QueryArray("owner_ids")
|
||||
if len(values) == 0 {
|
||||
values = c.QueryArray("owner_id")
|
||||
}
|
||||
ownerIDs := make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
for _, ownerID := range strings.Split(value, ",") {
|
||||
ownerID = strings.TrimSpace(ownerID)
|
||||
if ownerID != "" {
|
||||
ownerIDs = append(ownerIDs, ownerID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ownerIDs
|
||||
}
|
||||
|
||||
// ListSearches list search apps
|
||||
// @Summary List Search Apps
|
||||
// @Description Get list of search apps for the current user with filtering, pagination and sorting
|
||||
@@ -61,9 +79,9 @@ func (h *SearchHandler) SetCompletionDependencies(streamLLM *service.ModelProvid
|
||||
// @Param page_size query int false "items per page"
|
||||
// @Param orderby query string false "order by field (default: create_time)"
|
||||
// @Param desc query bool false "descending order (default: true)"
|
||||
// @Param request body service.ListSearchAppsRequest true "filter options including owner_ids"
|
||||
// @Param owner_ids query []string false "owner IDs"
|
||||
// @Success 200 {object} service.ListSearchAppsResponse
|
||||
// @Router /api/v1/searches [post]
|
||||
// @Router /api/v1/searches [get]
|
||||
func (h *SearchHandler) ListSearches(c *gin.Context) {
|
||||
user, errorCode, errorMessage := GetUser(c)
|
||||
if errorCode != common.CodeSuccess {
|
||||
@@ -96,9 +114,12 @@ func (h *SearchHandler) ListSearches(c *gin.Context) {
|
||||
desc = descStr != "false"
|
||||
}
|
||||
|
||||
// Parse request body for owner_ids
|
||||
ownerIDs := getSearchOwnerIDs(c)
|
||||
|
||||
// Keep body parsing as a compatibility fallback for existing callers that
|
||||
// send owner_ids in a GET body. Python reads owner_ids from the query.
|
||||
var req service.ListSearchAppsRequest
|
||||
if c.Request.ContentLength > 0 {
|
||||
if len(ownerIDs) == 0 && c.Request.ContentLength > 0 {
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
@@ -106,10 +127,11 @@ func (h *SearchHandler) ListSearches(c *gin.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
ownerIDs = req.OwnerIDs
|
||||
}
|
||||
|
||||
// List search apps with filtering
|
||||
result, err := h.searchService.ListSearches(userID, keywords, page, pageSize, orderby, desc, req.OwnerIDs)
|
||||
result, err := h.searchService.ListSearches(userID, keywords, page, pageSize, orderby, desc, ownerIDs)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
|
||||
@@ -85,25 +85,27 @@ func (s *SearchService) ListSearches(userID string, keywords string, page, pageS
|
||||
var err error
|
||||
|
||||
if len(ownerIDs) == 0 {
|
||||
// Get tenant IDs by user ID (joined tenants)
|
||||
tenantIDs, err := s.userTenantDAO.GetTenantIDsByUserID(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Use database pagination
|
||||
searches, total, err = s.searchDAO.ListByTenantIDs(tenantIDs, userID, page, pageSize, orderby, desc, keywords)
|
||||
searches, total, err = s.searchDAO.ListByTenantIDs(nil, userID, page, pageSize, orderby, desc, keywords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Filter by owner IDs, manual pagination
|
||||
ownerIDs, err = s.filterAccessibleSearchOwnerIDs(userID, ownerIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ownerIDs) == 0 {
|
||||
return &ListSearchAppsResponse{
|
||||
SearchApps: []map[string]interface{}{},
|
||||
Total: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
searches, total, err = s.searchDAO.ListByOwnerIDs(ownerIDs, userID, orderby, desc, keywords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Manual pagination
|
||||
if page > 0 && pageSize > 0 {
|
||||
start := (page - 1) * pageSize
|
||||
end := start + pageSize
|
||||
@@ -130,6 +132,39 @@ func (s *SearchService) ListSearches(userID string, keywords string, page, pageS
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SearchService) filterAccessibleSearchOwnerIDs(userID string, ownerIDs []string) ([]string, error) {
|
||||
tenantIDs, err := s.userTenantDAO.GetTenantIDsByUserID(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allowed := map[string]struct{}{userID: {}}
|
||||
for _, tenantID := range tenantIDs {
|
||||
tenantID = strings.TrimSpace(tenantID)
|
||||
if tenantID != "" {
|
||||
allowed[tenantID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
filtered := make([]string, 0, len(ownerIDs))
|
||||
seen := make(map[string]struct{}, len(ownerIDs))
|
||||
for _, ownerID := range ownerIDs {
|
||||
ownerID = strings.TrimSpace(ownerID)
|
||||
if ownerID == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := allowed[ownerID]; !ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[ownerID]; ok {
|
||||
continue
|
||||
}
|
||||
seen[ownerID] = struct{}{}
|
||||
filtered = append(filtered, ownerID)
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
// toSearchAppResponse converts search model to response format
|
||||
func (s *SearchService) toSearchAppResponse(search *entity.Search) map[string]interface{} {
|
||||
result := map[string]interface{}{
|
||||
|
||||
Reference in New Issue
Block a user