mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-09-08 02:08:01 +08:00
Fix: hide skills folder in REST API (#18859)
This commit is contained in:
@@ -164,11 +164,12 @@ def list_files(tenant_id: str, args: dict):
|
||||
FileService.init_knowledgebase_docs(pf_id, tenant_id)
|
||||
FileService.init_skills_folder(pf_id, tenant_id)
|
||||
|
||||
e, _ = FileService.get_by_id(pf_id)
|
||||
e, folder = FileService.get_by_id(pf_id)
|
||||
if not e:
|
||||
return False, "Folder not found!"
|
||||
|
||||
files, total = FileService.get_by_pf_id(tenant_id, pf_id, page_number, items_per_page, orderby, desc, keywords)
|
||||
exclude_skills = folder.id == folder.parent_id
|
||||
files, total = FileService.get_by_pf_id(tenant_id, pf_id, page_number, items_per_page, orderby, desc, keywords, exclude_skills)
|
||||
|
||||
parent_folder = FileService.get_parent_folder(pf_id)
|
||||
if not parent_folder:
|
||||
|
||||
@@ -51,7 +51,7 @@ class FileService(CommonService):
|
||||
|
||||
@classmethod
|
||||
@DB.connection_context()
|
||||
def get_by_pf_id(cls, tenant_id, pf_id, page_number, items_per_page, orderby, desc, keywords):
|
||||
def get_by_pf_id(cls, tenant_id, pf_id, page_number, items_per_page, orderby, desc, keywords, exclude_skills):
|
||||
# Get files by parent folder ID with pagination and filtering
|
||||
# Args:
|
||||
# tenant_id: ID of the tenant
|
||||
@@ -61,6 +61,7 @@ class FileService(CommonService):
|
||||
# orderby: Field to order by
|
||||
# desc: Boolean indicating descending order
|
||||
# keywords: Search keywords
|
||||
# exclude_skills: Whether to exclude the skills folder directly under pf_id
|
||||
# Returns:
|
||||
# Tuple of (file_list, total_count)
|
||||
if keywords:
|
||||
@@ -72,6 +73,8 @@ class FileService(CommonService):
|
||||
)
|
||||
else:
|
||||
files = cls.model.select().where((cls.model.tenant_id == tenant_id), (cls.model.parent_id == pf_id), ~(cls.model.id == pf_id))
|
||||
if exclude_skills:
|
||||
files = files.where(~((cls.model.parent_id == pf_id) & (cls.model.name == SKILLS_FOLDER_NAME)))
|
||||
count = files.count()
|
||||
if desc:
|
||||
files = files.order_by(cls.model.getter_by(orderby).desc())
|
||||
|
||||
@@ -49,7 +49,7 @@ func (dao *FileDAO) GetByID(ctx context.Context, db *gorm.DB, id string) (*entit
|
||||
// When keywords is empty, only direct children of pfID are listed; when
|
||||
// keywords is non-empty, the search covers the whole subtree under pfID so
|
||||
// files and folders nested in sub-folders can be found too.
|
||||
func (dao *FileDAO) GetByPfID(ctx context.Context, db *gorm.DB, tenantID, pfID string, page, pageSize int, orderBy string, desc bool, keywords string) ([]*entity.File, int64, error) {
|
||||
func (dao *FileDAO) GetByPfID(ctx context.Context, db *gorm.DB, tenantID, pfID string, page, pageSize int, orderBy string, desc bool, keywords string, excludeSkills bool) ([]*entity.File, int64, error) {
|
||||
var files []*entity.File
|
||||
var total int64
|
||||
|
||||
@@ -66,6 +66,9 @@ func (dao *FileDAO) GetByPfID(ctx context.Context, db *gorm.DB, tenantID, pfID s
|
||||
} else {
|
||||
query = query.Where("parent_id = ?", pfID)
|
||||
}
|
||||
if excludeSkills {
|
||||
query = query.Where("NOT (parent_id = ? AND name = ?)", pfID, SkillsFolderName)
|
||||
}
|
||||
|
||||
// Count total
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
@@ -436,6 +439,9 @@ func reparentAndDeleteFolder(ctx context.Context, db *gorm.DB, dupID, keepID str
|
||||
// DatasetFolderName is the folder name for dataset
|
||||
const DatasetFolderName = ".knowledgebase"
|
||||
|
||||
// SkillsFolderName is the folder name for skills
|
||||
const SkillsFolderName = "skills"
|
||||
|
||||
// InitDatasetDocs initializes dataset documents for tenant.
|
||||
// This matches Python's FileService.init_dataset_docs method.
|
||||
// Deduplicates duplicate entries that may have been created by
|
||||
|
||||
@@ -76,7 +76,7 @@ func TestFileDAO_GetByPfID_KeywordsSearchesSubtree(t *testing.T) {
|
||||
d := NewFileDAO()
|
||||
ctx := t.Context()
|
||||
|
||||
files, total, err := d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "report")
|
||||
files, total, err := d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "report", false)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByPfID failed: %v", err)
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func TestFileDAO_GetByPfID_KeywordsSearchesSubtree(t *testing.T) {
|
||||
}
|
||||
|
||||
// Nested file two levels down must be found from the root folder.
|
||||
files, total, err = d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "notes")
|
||||
files, total, err = d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "notes", false)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByPfID failed: %v", err)
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func TestFileDAO_GetByPfID_KeywordsSearchesSubtree(t *testing.T) {
|
||||
}
|
||||
|
||||
// Folders themselves are searchable by name.
|
||||
files, total, err = d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "sub")
|
||||
files, total, err = d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "sub", false)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByPfID failed: %v", err)
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func TestFileDAO_GetByPfID_KeywordsScopedToSubtree(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
|
||||
// Searching inside dirA must not match files outside that subtree.
|
||||
files, total, err := d.GetByPfID(ctx, db, "t1", "dirA", 1, 15, "create_time", true, "report")
|
||||
files, total, err := d.GetByPfID(ctx, db, "t1", "dirA", 1, 15, "create_time", true, "report", false)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByPfID failed: %v", err)
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func TestFileDAO_GetByPfID_KeywordsScopedToSubtree(t *testing.T) {
|
||||
}
|
||||
|
||||
// Tenant isolation still applies.
|
||||
files, total, err = d.GetByPfID(ctx, db, "t2", "root", 1, 15, "create_time", true, "report")
|
||||
files, total, err = d.GetByPfID(ctx, db, "t2", "root", 1, 15, "create_time", true, "report", false)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByPfID failed: %v", err)
|
||||
}
|
||||
@@ -134,7 +134,7 @@ func TestFileDAO_GetByPfID_NoKeywordsListsDirectChildren(t *testing.T) {
|
||||
d := NewFileDAO()
|
||||
ctx := t.Context()
|
||||
|
||||
files, total, err := d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "")
|
||||
files, total, err := d.GetByPfID(ctx, db, "t1", "root", 1, 15, "create_time", true, "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByPfID failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -45,12 +45,14 @@ func (s *FileService) ListFiles(ctx context.Context, tenantID, pfID string, page
|
||||
}
|
||||
|
||||
// Check if parent folder exists
|
||||
if _, err := s.fileDAO.GetByID(ctx, dao.DB, pfID); err != nil {
|
||||
folder, err := s.fileDAO.GetByID(ctx, dao.DB, pfID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("folder not found")
|
||||
}
|
||||
|
||||
// Get files by parent folder ID
|
||||
files, total, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, pfID, page, pageSize, orderby, desc, keywords)
|
||||
excludeSkills := folder.ID == folder.ParentID
|
||||
files, total, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, pfID, page, pageSize, orderby, desc, keywords, excludeSkills)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ func (s *SkillIndexerService) getSpaceFolderIDByName(ctx context.Context, tenant
|
||||
}
|
||||
|
||||
// Find skills folder under root
|
||||
files, _, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, rootFolder.ID, 0, 0, "name", false, "")
|
||||
files, _, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, rootFolder.ID, 0, 0, "name", false, "", false)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to list root folder contents: %w", err)
|
||||
}
|
||||
@@ -699,7 +699,7 @@ func (s *SkillIndexerService) getSpaceFolderIDByName(ctx context.Context, tenant
|
||||
}
|
||||
|
||||
// Find space folder by name under skills folder
|
||||
spaceFolders, _, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, skillsFolderID, 0, 0, "name", false, "")
|
||||
spaceFolders, _, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, skillsFolderID, 0, 0, "name", false, "", false)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to list skills folder contents: %w", err)
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func (s *SkillSpaceService) getSkillsFolderID(ctx context.Context, tenantID stri
|
||||
}
|
||||
|
||||
// Look for skills folder under root
|
||||
files, _, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, rootFolder.ID, 0, 0, "name", false, "")
|
||||
files, _, err := s.fileDAO.GetByPfID(ctx, dao.DB, tenantID, rootFolder.ID, 0, 0, "name", false, "", false)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to list root folder contents: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user