fix: get team's search in own search-list (#16599)

### Summary

As title:
This commit is contained in:
Haruko386
2026-07-03 18:26:03 +08:00
committed by GitHub
parent 226d0ff77c
commit dde8b6d54c
3 changed files with 79 additions and 17 deletions

View File

@@ -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 != "" {

View File

@@ -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,

View File

@@ -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{}{