mirror of
				https://github.com/photoprism/photoprism.git
				synced 2025-10-31 20:22:55 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			116 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package api
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"path"
 | |
| 	"path/filepath"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/gin-gonic/gin"
 | |
| 	"github.com/photoprism/photoprism/internal/acl"
 | |
| 	"github.com/photoprism/photoprism/internal/event"
 | |
| 	"github.com/photoprism/photoprism/internal/i18n"
 | |
| 	"github.com/photoprism/photoprism/internal/service"
 | |
| 	"github.com/photoprism/photoprism/pkg/sanitize"
 | |
| )
 | |
| 
 | |
| // POST /api/v1/upload/:path
 | |
| func Upload(router *gin.RouterGroup) {
 | |
| 	router.POST("/upload/:path", func(c *gin.Context) {
 | |
| 		conf := service.Config()
 | |
| 		if conf.ReadOnly() || !conf.Settings().Features.Upload {
 | |
| 			Abort(c, http.StatusForbidden, i18n.ErrReadOnly)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		s := Auth(SessionID(c), acl.ResourcePhotos, acl.ActionUpload)
 | |
| 
 | |
| 		if s.Invalid() {
 | |
| 			AbortUnauthorized(c)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		start := time.Now()
 | |
| 		subPath := sanitize.Path(c.Param("path"))
 | |
| 
 | |
| 		f, err := c.MultipartForm()
 | |
| 
 | |
| 		if err != nil {
 | |
| 			log.Errorf("upload: %s", err)
 | |
| 			AbortBadRequest(c)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		event.Publish("upload.start", event.Data{"time": start})
 | |
| 
 | |
| 		files := f.File["files"]
 | |
| 		uploaded := len(files)
 | |
| 		var uploads []string
 | |
| 
 | |
| 		p := path.Join(conf.ImportPath(), "upload", subPath)
 | |
| 
 | |
| 		if err := os.MkdirAll(p, os.ModePerm); err != nil {
 | |
| 			log.Errorf("upload: failed creating folder %s", sanitize.Log(subPath))
 | |
| 			AbortBadRequest(c)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		for _, file := range files {
 | |
| 			filename := path.Join(p, filepath.Base(file.Filename))
 | |
| 
 | |
| 			log.Debugf("upload: saving file %s", sanitize.Log(file.Filename))
 | |
| 
 | |
| 			if err := c.SaveUploadedFile(file, filename); err != nil {
 | |
| 				log.Errorf("upload: failed saving file %s", sanitize.Log(filepath.Base(file.Filename)))
 | |
| 				AbortBadRequest(c)
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			uploads = append(uploads, filename)
 | |
| 		}
 | |
| 
 | |
| 		if !conf.UploadNSFW() {
 | |
| 			nd := service.NsfwDetector()
 | |
| 
 | |
| 			containsNSFW := false
 | |
| 
 | |
| 			for _, filename := range uploads {
 | |
| 				labels, err := nd.File(filename)
 | |
| 
 | |
| 				if err != nil {
 | |
| 					log.Debug(err)
 | |
| 					continue
 | |
| 				}
 | |
| 
 | |
| 				if labels.IsSafe() {
 | |
| 					continue
 | |
| 				}
 | |
| 
 | |
| 				log.Infof("nsfw: %s might be offensive", sanitize.Log(filename))
 | |
| 
 | |
| 				containsNSFW = true
 | |
| 			}
 | |
| 
 | |
| 			if containsNSFW {
 | |
| 				for _, filename := range uploads {
 | |
| 					if err := os.Remove(filename); err != nil {
 | |
| 						log.Errorf("nsfw: could not delete %s", sanitize.Log(filename))
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				Abort(c, http.StatusForbidden, i18n.ErrOffensiveUpload)
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		elapsed := int(time.Since(start).Seconds())
 | |
| 
 | |
| 		msg := i18n.Msg(i18n.MsgFilesUploadedIn, uploaded, elapsed)
 | |
| 
 | |
| 		log.Info(msg)
 | |
| 
 | |
| 		c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Msg: msg})
 | |
| 	})
 | |
| }
 | 
