feat: Implement file upload and folder creation features by GO (#13903)

### What problem does this PR solve?

feat: Implement file upload and folder creation features

- Add file upload route in router.go
- Add file operation methods in dao/file.go
- Add util/file.go for file type detection and filename handling
- Implement file upload and folder creation endpoints in handler/file.go
- Implement file upload and folder creation logic in service/file.go
- Modify response message format in memory.go
- Add document count method in dao/document.go

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
chanx
2026-04-02 20:21:04 +08:00
committed by GitHub
parent 6c29128de1
commit bbb9b1df85
7 changed files with 596 additions and 5 deletions

View File

@@ -20,6 +20,7 @@ import (
"net/http"
"ragflow/internal/common"
"strconv"
"strings"
"github.com/gin-gonic/gin"
@@ -226,3 +227,147 @@ func (h *FileHandler) GetAllParentFolders(c *gin.Context) {
"message": "success",
})
}
type CreateFolderRequest struct {
Name string `json:"name" binding:"required"`
ParentID string `json:"parent_id"`
Type string `json:"type"`
}
// UploadFile handles file upload and folder creation
// @Summary Upload Files or Create Folder
// @Description Upload files or create a folder based on content type
// @Tags file
// @Accept multipart/form-data, application/json
// @Produce json
// @Param parent_id query string false "parent folder ID (for multipart/form-data)"
// @Param file formData file false "file to upload (for multipart/form-data)"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /v1/file/upload [post]
func (h *FileHandler) UploadFile(c *gin.Context) {
user, errorCode, errorMessage := GetUser(c)
if errorCode != common.CodeSuccess {
c.JSON(http.StatusBadRequest, gin.H{
"code": errorCode,
"message": errorMessage,
})
return
}
userID := user.ID
contentType := c.ContentType()
if strings.Contains(contentType, "multipart/form-data") {
if err := c.Request.ParseMultipartForm(32 << 20); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Failed to parse multipart form: " + err.Error(),
})
return
}
form := c.Request.MultipartForm
if form == nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "No file part!",
})
return
}
parentID := c.PostForm("parent_id")
if parentID == "" {
rootFolder, err := h.fileService.GetRootFolder(userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": err.Error(),
})
return
}
parentID = rootFolder["id"].(string)
}
files := form.File["file"]
if len(files) == 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "No file selected!",
})
return
}
for _, fileHeader := range files {
if fileHeader.Filename == "" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "No file selected!",
})
return
}
}
result, err := h.fileService.UploadFile(userID, parentID, files)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": result,
"message": "success",
})
return
}
if strings.Contains(contentType, "application/json") {
var req CreateFolderRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": err.Error(),
})
return
}
parentID := req.ParentID
if parentID == "" {
rootFolder, err := h.fileService.GetRootFolder(userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": err.Error(),
})
return
}
parentID = rootFolder["id"].(string)
}
result, err := h.fileService.CreateFolder(userID, req.Name, parentID, req.Type)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": result,
"message": "success",
})
return
}
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "Unsupported content type",
})
return
}

View File

@@ -194,7 +194,7 @@ func (h *MemoryHandler) CreateMemory(c *gin.Context) {
// Return success response
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"message": true,
"message": "success",
"data": result,
})
}
@@ -293,7 +293,7 @@ func (h *MemoryHandler) UpdateMemory(c *gin.Context) {
// Return success response
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"message": true,
"message": "success",
"data": result,
})
}
@@ -347,7 +347,7 @@ func (h *MemoryHandler) DeleteMemory(c *gin.Context) {
// Return success response
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"message": true,
"message": "success",
"data": nil,
})
}
@@ -436,7 +436,7 @@ func (h *MemoryHandler) ListMemories(c *gin.Context) {
// Return success response
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"message": true,
"message": "success",
"data": result,
})
}
@@ -490,7 +490,7 @@ func (h *MemoryHandler) GetMemoryConfig(c *gin.Context) {
// Return success response
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"message": true,
"message": "success",
"data": result,
})
}