Some checks failed
CI / Build & Test (push) Failing after 1m31s
- Add user management endpoints (list/create/get/update/delete) with pagination and search - Add dashboard stats endpoint with tenant/user/online counts and growth metrics - Add tenant resolver middleware for multi-tenant request scoping - Add i18n kernel with zh/en message files and AcceptLanguage middleware - Add WebSocket hub/handler for real-time communication - Add job scheduler kernel with cron support - Add plugin sandbox for isolated execution - Add storage kernel (local filesystem) - Add event bus kernel for pub/sub - Add cache kernel abstraction - Add database migration runner and version upgrade checker - Add rate limiting middleware with Redis backend - Add SQL migrations for rbac, audit_logs, settings, notifications, examples - Extend user repository with list/delete/count operations - Register all module routes with tenant resolver
72 lines
1.5 KiB
Go
72 lines
1.5 KiB
Go
package storage
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
var defaultAllowedTypes = map[string]bool{
|
|
"image/jpeg": true,
|
|
"image/png": true,
|
|
"image/gif": true,
|
|
"image/webp": true,
|
|
"image/svg+xml": true,
|
|
"application/pdf": true,
|
|
}
|
|
|
|
var defaultMaxSize int64 = 10 << 20
|
|
|
|
type UploadConfig struct {
|
|
FieldName string
|
|
MaxSize int64
|
|
AllowedTypes map[string]bool
|
|
}
|
|
|
|
func UploadMiddleware(cfg UploadConfig) gin.HandlerFunc {
|
|
if cfg.FieldName == "" {
|
|
cfg.FieldName = "file"
|
|
}
|
|
if cfg.MaxSize <= 0 {
|
|
cfg.MaxSize = defaultMaxSize
|
|
}
|
|
if cfg.AllowedTypes == nil {
|
|
cfg.AllowedTypes = defaultAllowedTypes
|
|
}
|
|
|
|
return func(c *gin.Context) {
|
|
file, header, err := c.Request.FormFile(cfg.FieldName)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "file field required"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
if header.Size > cfg.MaxSize {
|
|
file.Close()
|
|
c.JSON(http.StatusRequestEntityTooLarge, gin.H{"error": fmt.Sprintf("file too large (max %d bytes)", cfg.MaxSize)})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
contentType := header.Header.Get("Content-Type")
|
|
if len(cfg.AllowedTypes) > 0 && !cfg.AllowedTypes[contentType] {
|
|
file.Close()
|
|
c.JSON(http.StatusUnsupportedMediaType, gin.H{"error": fmt.Sprintf("file type not allowed: %s", contentType)})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
c.Set("upload_file", &File{
|
|
Name: header.Filename,
|
|
ContentType: contentType,
|
|
Size: header.Size,
|
|
Reader: file,
|
|
})
|
|
|
|
c.Next()
|
|
file.Close()
|
|
}
|
|
}
|