mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-01 16:25:44 +08:00
### 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)
135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
//
|
|
// 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)
|
|
}
|