79 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			79 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
| package ws
 | |
| 
 | |
| import (
 | |
| 	"crypto/rand"
 | |
| 	"encoding/base64"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 
 | |
| 	"sectorinf.com/emilis/fupie/ws/route"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	base64Stripper = strings.NewReplacer("/", "", "+", "", "=", "")
 | |
| )
 | |
| 
 | |
| func Upload(rootDir, redirect string, maxBytes int64) (route.HandlerFunc, error) {
 | |
| 	stat, err := os.Stat(rootDir)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("stat [%s]: %w", rootDir, err)
 | |
| 	}
 | |
| 	if !stat.IsDir() {
 | |
| 		return nil, fmt.Errorf("root path [%s] is not a directory", rootDir)
 | |
| 	}
 | |
| 	rootDir, err = filepath.Abs(rootDir)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("abs filepath [%s]: %w", rootDir, err)
 | |
| 	}
 | |
| 	redirect = strings.TrimRight(redirect, "/")
 | |
| 	return func(ctx route.Context) {
 | |
| 		if err := ctx.Request.ParseMultipartForm(maxBytes); err != nil {
 | |
| 			ctx.Status(http.StatusBadRequest)
 | |
| 			return
 | |
| 		}
 | |
| 		uploads := ctx.Request.MultipartForm.File["upload"]
 | |
| 		if len(uploads) != 1 {
 | |
| 			ctx.Status(http.StatusBadRequest)
 | |
| 			return
 | |
| 		}
 | |
| 		header := uploads[0]
 | |
| 		file, err := header.Open()
 | |
| 		if err != nil {
 | |
| 			ctx.InternalServerErrorf("header.Open: %s", err.Error())
 | |
| 			return
 | |
| 		}
 | |
| 		newFilename := rename(header.Filename)
 | |
| 		path := filepath.Join(rootDir, newFilename)
 | |
| 		fsFile, err := os.Create(path)
 | |
| 		if err != nil {
 | |
| 			ctx.InternalServerErrorf("creating file at [%s]: %s", path, err.Error())
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if _, err := io.CopyBuffer(fsFile, file, nil); err != nil {
 | |
| 			ctx.InternalServerErrorf("writing file at [%s]: %s", path, err.Error())
 | |
| 			return
 | |
| 		}
 | |
| 		fsFile.Close()
 | |
| 		ctx.SeeOther(fmt.Sprintf("%s/%s", redirect, newFilename))
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func rename(name string) string {
 | |
| 	return fmt.Sprintf("%s_%s", randName(4), name)
 | |
| }
 | |
| 
 | |
| func randName(bytes int) string {
 | |
| 	buffer := make([]byte, bytes)
 | |
| 	_, err := rand.Read(buffer)
 | |
| 	if err != nil {
 | |
| 		panic(err)
 | |
| 	}
 | |
| 
 | |
| 	return base64Stripper.Replace(base64.StdEncoding.EncodeToString(buffer))
 | |
| }
 |