diff --git a/.gitignore b/.gitignore index 1269488..9de6f55 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ data +.DS_Store \ No newline at end of file diff --git a/internal/photos/api/account.go b/internal/photos/api/account.go index ebd7228..992cb2d 100644 --- a/internal/photos/api/account.go +++ b/internal/photos/api/account.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "gitlab.celogeek.com/photos/api/internal/photos/models" + "gitlab.celogeek.com/photos/api/internal/photoserrors" "gopkg.in/validator.v2" "gorm.io/gorm" ) @@ -33,7 +34,7 @@ func (s *Service) Signup(c *gin.Context) { return } if accountExists > 0 { - s.Error(c, http.StatusConflict, ErrAccountExists) + s.Error(c, http.StatusConflict, photoserrors.ErrAccountExists) return } if err := s.DB.Create(models.NewAccount(account.Login, account.Password)).Error; err != nil { @@ -57,7 +58,7 @@ func (s *Service) Login(c *gin.Context) { session, err := models.NewSession(s.DB, account.Login, account.Password) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - s.Error(c, http.StatusNotFound, ErrAccountAuth) + s.Error(c, http.StatusNotFound, photoserrors.ErrAccountAuth) } else { s.Error(c, http.StatusInternalServerError, err) } @@ -77,7 +78,7 @@ func (s *Service) Logout(c *gin.Context) { return } if res.RowsAffected == 0 { - s.Error(c, http.StatusNotFound, ErrSessionNotFound) + s.Error(c, http.StatusNotFound, photoserrors.ErrSessionNotFound) return } c.JSON(http.StatusOK, gin.H{ diff --git a/internal/photos/api/check_body.go b/internal/photos/api/check_body.go index 039a58c..82f0b24 100644 --- a/internal/photos/api/check_body.go +++ b/internal/photos/api/check_body.go @@ -4,11 +4,12 @@ import ( "net/http" "github.com/gin-gonic/gin" + "gitlab.celogeek.com/photos/api/internal/photoserrors" ) func (s *Service) RequireBody(c *gin.Context) { if c.Request.Method == "POST" && c.Request.ContentLength == 0 { - s.Error(c, http.StatusBadRequest, ErrReqMissingBody) + s.Error(c, http.StatusBadRequest, photoserrors.ErrReqMissingBody) return } } diff --git a/internal/photos/api/errors.go b/internal/photos/api/errors.go index 52c6b6c..eddc7f1 100644 --- a/internal/photos/api/errors.go +++ b/internal/photos/api/errors.go @@ -1,39 +1,9 @@ package api import ( - "errors" - "github.com/gin-gonic/gin" ) -var ( - // Session - ErrSessionNotFound = errors.New("session not found") - ErrSessionInvalid = errors.New("session invalid") - ErrTokenMissing = errors.New("token missing") - - // Request - ErrReqMissingBody = errors.New("missing body") - ErrReqNotFound = errors.New("this route doesn't exists") - - // Account - ErrAccountExists = errors.New("account exists") - ErrAccountAuth = errors.New("login or password incorrect") - - // Panic - ErrUnexpected = errors.New("an unexpected error occur") - - // Album - ErrAlbumDontExists = errors.New("album doesn't exists") - - // Store - ErrStorePathNotADirectory = errors.New("store path is not a directory") - ErrStoreBadChecksum = errors.New("checksum should be sha1 in hex format") - ErrStoreBadChunkSize = errors.New("part file size should be 1MB max") - ErrStoreMissingChunks = errors.New("part checksum missing") - ErrStoreMismatchChecksum = errors.New("part files doesn't match the original checksum") -) - func (s *Service) Error(c *gin.Context, code int, err error) { c.AbortWithStatusJSON(code, gin.H{ "status": "failed", diff --git a/internal/photos/api/file.go b/internal/photos/api/file.go index 84cad5d..302523b 100644 --- a/internal/photos/api/file.go +++ b/internal/photos/api/file.go @@ -5,8 +5,10 @@ import ( "fmt" "io" "net/http" + "path/filepath" "github.com/gin-gonic/gin" + "gitlab.celogeek.com/photos/api/internal/photoserrors" ) var CHUNK_SIZE int64 = 1 << 20 @@ -24,17 +26,17 @@ func (s *Service) FileCreate(c *gin.Context) { } if len(file.Sum) != 40 { - s.Error(c, http.StatusBadRequest, ErrStoreBadChecksum) + s.Error(c, http.StatusBadRequest, photoserrors.ErrStoreBadChecksum) return } if len(file.Chunks) == 0 { - s.Error(c, http.StatusBadRequest, ErrStoreMissingChunks) + s.Error(c, http.StatusBadRequest, photoserrors.ErrStoreMissingChunks) return } for _, chunk := range file.Chunks { if len(chunk) != 40 { - s.Error(c, http.StatusBadRequest, ErrStoreBadChecksum) + s.Error(c, http.StatusBadRequest, photoserrors.ErrStoreBadChecksum) return } } @@ -47,7 +49,7 @@ func (s *Service) FileCreate(c *gin.Context) { if r != file.Sum { fmt.Printf("R=%s, O=%s\n", r, file.Sum) - s.Error(c, http.StatusExpectationFailed, ErrStoreMismatchChecksum) + s.Error(c, http.StatusExpectationFailed, photoserrors.ErrStoreMismatchChecksum) return } @@ -70,12 +72,19 @@ func (s *Service) FileCreateTemp(c *gin.Context) { sumb = c.Param("sum") ) if len(origsum) != 40 || len(sumb) != 40 { - s.Error(c, http.StatusBadRequest, ErrStoreBadChecksum) + s.Error(c, http.StatusBadRequest, photoserrors.ErrStoreBadChecksum) + return + } + + originaldir := s.Store.Dir("original", origsum) + originalname := filepath.Join(originaldir, origsum) + if s.Store.FileExists(originalname) { + s.Error(c, http.StatusBadRequest, photoserrors.ErrStoreAlreadyExists) return } if c.Request.ContentLength > CHUNK_SIZE { - s.Error(c, http.StatusBadRequest, ErrStoreBadChunkSize) + s.Error(c, http.StatusBadRequest, photoserrors.ErrStoreBadChunkSize) return } diff --git a/internal/photos/api/main.go b/internal/photos/api/main.go index 053cd51..07f4d8e 100644 --- a/internal/photos/api/main.go +++ b/internal/photos/api/main.go @@ -10,6 +10,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-sql-driver/mysql" + "gitlab.celogeek.com/photos/api/internal/photoserrors" "gitlab.celogeek.com/photos/api/internal/store" "gorm.io/gorm" ) @@ -62,7 +63,7 @@ func (s *Service) SetupRoutes() { album.POST("/tmp/:origsum/:sum", s.FileCreateTemp) s.Gin.NoRoute(func(c *gin.Context) { - s.Error(c, http.StatusNotFound, ErrReqNotFound) + s.Error(c, http.StatusNotFound, photoserrors.ErrReqNotFound) }) } @@ -72,7 +73,7 @@ func (s *Service) PrepareStore() { s.LogErr.Fatal("Store", err) } if !d.IsDir() { - s.LogErr.Fatal("Store", ErrStorePathNotADirectory) + s.LogErr.Fatal("Store", photoserrors.ErrStorePathNotADirectory) } if err := s.Store.MkDirs([]string{"tmp", "original"}); err != nil { s.LogErr.Fatal("Store", err) diff --git a/internal/photos/api/recovery.go b/internal/photos/api/recovery.go index 508ddd5..7a5e4e7 100644 --- a/internal/photos/api/recovery.go +++ b/internal/photos/api/recovery.go @@ -4,13 +4,14 @@ import ( "net/http" "github.com/gin-gonic/gin" + "gitlab.celogeek.com/photos/api/internal/photoserrors" ) func (s *Service) Recovery(c *gin.Context) { defer func() { if err := recover(); err != nil { s.LogErr.Print("PANIC", err) - s.Error(c, http.StatusInternalServerError, ErrUnexpected) + s.Error(c, http.StatusInternalServerError, photoserrors.ErrUnexpected) } }() c.Next() diff --git a/internal/photos/api/session.go b/internal/photos/api/session.go index 2f15f61..802b707 100644 --- a/internal/photos/api/session.go +++ b/internal/photos/api/session.go @@ -8,13 +8,14 @@ import ( "github.com/gin-gonic/gin" "gitlab.celogeek.com/photos/api/internal/photos/models" + "gitlab.celogeek.com/photos/api/internal/photoserrors" "gorm.io/gorm" ) func (s *Service) RequireAuthToken(c *gin.Context) { token := c.GetHeader("Authorization") if !strings.HasPrefix(token, "Private ") { - s.Error(c, http.StatusForbidden, ErrTokenMissing) + s.Error(c, http.StatusForbidden, photoserrors.ErrTokenMissing) return } token = token[8:] @@ -30,14 +31,14 @@ func (s *Service) RequireSession(c *gin.Context) { sess := &models.Session{} if err := s.DB.Preload("Account").Where("token = ?", c.GetString("token")).First(sess).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - s.Error(c, http.StatusForbidden, ErrSessionNotFound) + s.Error(c, http.StatusForbidden, photoserrors.ErrSessionNotFound) } else { s.Error(c, http.StatusForbidden, err) } return } if sess.Account == nil { - s.Error(c, http.StatusInternalServerError, ErrSessionInvalid) + s.Error(c, http.StatusInternalServerError, photoserrors.ErrSessionInvalid) return } s.DB.Select("updated_at").Save(sess) diff --git a/internal/photoserrors/accounts.go b/internal/photoserrors/accounts.go new file mode 100644 index 0000000..e1a277e --- /dev/null +++ b/internal/photoserrors/accounts.go @@ -0,0 +1,9 @@ +package photoserrors + +import "errors" + +var ( + // Account + ErrAccountExists = errors.New("account exists") + ErrAccountAuth = errors.New("login or password incorrect") +) diff --git a/internal/photoserrors/albums.go b/internal/photoserrors/albums.go new file mode 100644 index 0000000..1cf28b4 --- /dev/null +++ b/internal/photoserrors/albums.go @@ -0,0 +1,9 @@ +package photoserrors + +import "errors" + +var ( + + // Album + ErrAlbumDontExists = errors.New("album doesn't exists") +) diff --git a/internal/photoserrors/panic.go b/internal/photoserrors/panic.go new file mode 100644 index 0000000..082b5a0 --- /dev/null +++ b/internal/photoserrors/panic.go @@ -0,0 +1,9 @@ +package photoserrors + +import "errors" + +var ( + + // Panic + ErrUnexpected = errors.New("an unexpected error occur") +) diff --git a/internal/photoserrors/requests.go b/internal/photoserrors/requests.go new file mode 100644 index 0000000..5ff6913 --- /dev/null +++ b/internal/photoserrors/requests.go @@ -0,0 +1,9 @@ +package photoserrors + +import "errors" + +var ( + // Request + ErrReqMissingBody = errors.New("missing body") + ErrReqNotFound = errors.New("this route doesn't exists") +) diff --git a/internal/photoserrors/session.go b/internal/photoserrors/session.go new file mode 100644 index 0000000..353f868 --- /dev/null +++ b/internal/photoserrors/session.go @@ -0,0 +1,10 @@ +package photoserrors + +import "errors" + +var ( + // Session + ErrSessionNotFound = errors.New("session not found") + ErrSessionInvalid = errors.New("session invalid") + ErrTokenMissing = errors.New("token missing") +) diff --git a/internal/photoserrors/store.go b/internal/photoserrors/store.go new file mode 100644 index 0000000..36dfe93 --- /dev/null +++ b/internal/photoserrors/store.go @@ -0,0 +1,14 @@ +package photoserrors + +import "errors" + +var ( + // Store + ErrStorePathNotADirectory = errors.New("store path is not a directory") + ErrStoreBadChecksum = errors.New("checksum should be sha1 in hex format") + ErrStoreBadChunkSize = errors.New("part file size should be 1MB max") + ErrStoreMissingChunks = errors.New("part checksum missing") + ErrStoreWrongChecksum = errors.New("wrong checksum") + ErrStoreMismatchChecksum = errors.New("part files doesn't match the original checksum") + ErrStoreAlreadyExists = errors.New("original file already exists") +) diff --git a/internal/store/core.go b/internal/store/core.go index e41d5df..13b9616 100644 --- a/internal/store/core.go +++ b/internal/store/core.go @@ -7,6 +7,8 @@ import ( "fmt" "os" "path/filepath" + + "gitlab.celogeek.com/photos/api/internal/photoserrors" ) type Store struct { @@ -40,7 +42,7 @@ func (s *Store) SaveTemp(path string, sumb string, b []byte) error { sumString := hex.EncodeToString(sum.Sum(nil)) if sumb != sumString { - return errors.New("wrong checksum") + return photoserrors.ErrStoreWrongChecksum } dir := s.Dir(path, sumString) @@ -89,7 +91,7 @@ func (s *Store) CommitTemp(path string, sumb []string) error { originalname := filepath.Join(originaldir, path) if s.FileExists(originalname) { - return fmt.Errorf("original file already exists") + return photoserrors.ErrStoreAlreadyExists } os.MkdirAll(originaldir, 0755)