mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-31 04:59:24 +08:00
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:
134
internal/util/file.go
Normal file
134
internal/util/file.go
Normal file
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// 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 util
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
FileTypePDF = "pdf"
|
||||
FileTypeDOC = "doc"
|
||||
FileTypeVISUAL = "visual"
|
||||
FileTypeAURAL = "aural"
|
||||
FileTypeFOLDER = "folder"
|
||||
FileTypeOTHER = "other"
|
||||
)
|
||||
|
||||
var (
|
||||
filenameLenLimit = 255
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func normalizeFilename(filename string) (string, bool) {
|
||||
if filename == "" {
|
||||
return "", false
|
||||
}
|
||||
base := filepath.Base(filename)
|
||||
base = strings.TrimSpace(base)
|
||||
if base == "" || len(base) > filenameLenLimit {
|
||||
return "", false
|
||||
}
|
||||
return strings.ToLower(base), true
|
||||
}
|
||||
|
||||
func FilenameType(filename string) string {
|
||||
normalized, ok := normalizeFilename(filename)
|
||||
if !ok {
|
||||
return FileTypeOTHER
|
||||
}
|
||||
|
||||
if matched, _ := regexp.MatchString(`.*\.pdf$`, normalized); matched {
|
||||
return FileTypePDF
|
||||
}
|
||||
|
||||
docExtensions := []string{
|
||||
"msg", "eml", "doc", "docx", "ppt", "pptx", "yml", "xml", "htm", "json", "jsonl", "ldjson",
|
||||
"csv", "txt", "ini", "xls", "xlsx", "wps", "rtf", "hlp", "pages", "numbers", "key",
|
||||
"md", "mdx", "py", "js", "java", "c", "cpp", "h", "php", "go", "ts", "sh", "cs", "kt",
|
||||
"html", "sql", "epub",
|
||||
}
|
||||
for _, ext := range docExtensions {
|
||||
if strings.HasSuffix(normalized, "."+ext) {
|
||||
return FileTypeDOC
|
||||
}
|
||||
}
|
||||
|
||||
audioExtensions := []string{
|
||||
"wav", "flac", "ape", "alac", "wv", "mp3", "aac", "ogg", "vorbis", "opus",
|
||||
}
|
||||
for _, ext := range audioExtensions {
|
||||
if strings.HasSuffix(normalized, "."+ext) {
|
||||
return FileTypeAURAL
|
||||
}
|
||||
}
|
||||
|
||||
visualExtensions := []string{
|
||||
"jpg", "jpeg", "png", "tif", "gif", "pcx", "tga", "exif", "fpx", "svg", "psd", "cdr",
|
||||
"pcd", "dxf", "ufo", "eps", "ai", "raw", "WMF", "webp", "avif", "apng", "icon", "ico",
|
||||
"mpg", "mpeg", "avi", "rm", "rmvb", "mov", "wmv", "asf", "dat", "asx", "wvx", "mpe",
|
||||
"mpa", "mp4", "mkv",
|
||||
}
|
||||
for _, ext := range visualExtensions {
|
||||
if strings.HasSuffix(normalized, "."+ext) {
|
||||
return FileTypeVISUAL
|
||||
}
|
||||
}
|
||||
|
||||
return FileTypeOTHER
|
||||
}
|
||||
|
||||
func SanitizeFilename(filename string) string {
|
||||
if filename == "" {
|
||||
return ""
|
||||
}
|
||||
filename = strings.TrimSpace(filename)
|
||||
if filename == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
filename = strings.ReplaceAll(filename, "\\", "/")
|
||||
filename = strings.Trim(filename, "/")
|
||||
|
||||
parts := strings.Split(filename, "/")
|
||||
var sanitizedParts []string
|
||||
for _, part := range parts {
|
||||
if part != "" && part != "." && part != ".." {
|
||||
sanitizedParts = append(sanitizedParts, part)
|
||||
}
|
||||
}
|
||||
|
||||
unsafeRegex := regexp.MustCompile(`[^A-Za-z0-9_\-/]`)
|
||||
for i, part := range sanitizedParts {
|
||||
sanitizedParts[i] = unsafeRegex.ReplaceAllString(part, "")
|
||||
}
|
||||
|
||||
result := strings.Join(sanitizedParts, "/")
|
||||
return result
|
||||
}
|
||||
|
||||
func GetFileExtension(filename string) string {
|
||||
ext := filepath.Ext(filename)
|
||||
if len(ext) > 0 && ext[0] == '.' {
|
||||
return strings.ToLower(ext[1:])
|
||||
}
|
||||
return strings.ToLower(ext)
|
||||
}
|
||||
Reference in New Issue
Block a user