diff --git a/infrastructure/sysStorage/sysStorage.go b/infrastructure/sysStorage/sysStorage.go index e931f3a..1536f4d 100644 --- a/infrastructure/sysStorage/sysStorage.go +++ b/infrastructure/sysStorage/sysStorage.go @@ -2,10 +2,13 @@ package sysStorage import ( "bytes" + "fmt" "io" "mime/multipart" "os" + "path/filepath" "strconv" + "strings" ) type LocalStorage struct { @@ -30,35 +33,38 @@ func NewLocalStorage(basePath string) *LocalStorage { func (ls *LocalStorage) Upload( file *multipart.FileHeader, streamerID int, -) error { +) (string, error) { dirPath := ls.basePath + "/" + strconv.Itoa(streamerID) if _, err := os.Stat(dirPath); os.IsNotExist(err) { if err := os.MkdirAll(dirPath, os.ModePerm); err != nil { - return err + return "", err } } - f, err := os.Create(dirPath + "/" + file.Filename) + fileName := ls.ensureUniqueFileName( + dirPath, + file.Filename, + ) + + f, err := os.Create(dirPath + "/" + fileName) if err != nil { - return err + return "", err } defer f.Close() - // Открываем загруженный файл srcFile, err := file.Open() if err != nil { - return err + return "", err } defer srcFile.Close() - // Копируем содержимое в новый файл _, err = io.Copy(f, srcFile) if err != nil { - return err + return "", err } - return nil + return fileName, nil } func (ls *LocalStorage) Download( @@ -95,3 +101,23 @@ func (ls *LocalStorage) Delete( return nil } + +func (ls *LocalStorage) ensureUniqueFileName( + dirPath, fileName string, +) string { + ext := filepath.Ext(fileName) + name := strings.TrimSuffix(fileName, ext) // Имя файла без расширения + newFileName := fileName // Начальное имя файла + counter := 1 // Счётчик для уникальности + + for { + filePath := filepath.Join(dirPath, newFileName) + if _, err := os.Stat(filePath); os.IsNotExist(err) { + break + } + newFileName = fmt.Sprintf("%s(%d)%s", name, counter, ext) + counter++ + } + + return newFileName +} diff --git a/internal/model/interfaces.go b/internal/model/interfaces.go index 32f39fd..243ad9a 100644 --- a/internal/model/interfaces.go +++ b/internal/model/interfaces.go @@ -117,7 +117,7 @@ type Error interface { } type Storage interface { - Upload(file *multipart.FileHeader, streamerID int) error + Upload(file *multipart.FileHeader, streamerID int) (string, error) Download(filename, extension, filePath string) ([]byte, error) Delete(filename, extension, filePath string) error } @@ -145,8 +145,13 @@ type FileRepo interface { ctx context.Context, streamerID int, file multipart.FileHeader, - fileName, extension, fileType string, + extension, fileType string, ) (string, error) + CheckFileExists( + ctx context.Context, + streamerID int, + fileName, extension, fileType string, + ) (bool, error) } type FileService interface { diff --git a/internal/model/sql/query.go b/internal/model/sql/query.go index 2be2b92..ad3adc6 100644 --- a/internal/model/sql/query.go +++ b/internal/model/sql/query.go @@ -120,5 +120,9 @@ INSERT INTO files (streamer_id, file_name, file_type, extension) VALUES (@streamer_id, @file_name, @file_type, @extension) RETURNING id; -; -` +;` + +var GetFileExists = `SELECT id FROM files WHERE ( + streamer_id = @streamer_id AND + file_name = @file_name AND file_type = @file_type AND extension = @extension +;` diff --git a/internal/repository/file/file.go b/internal/repository/file/file.go index dbb5f40..7a139cd 100644 --- a/internal/repository/file/file.go +++ b/internal/repository/file/file.go @@ -5,6 +5,7 @@ import ( "donat-widget/internal/model" "donat-widget/internal/model/sql" "fmt" + "github.com/georgysavva/scany/v2/pgxscan" "github.com/google/uuid" "github.com/jackc/pgx/v5" "mime/multipart" @@ -29,8 +30,13 @@ func (fileRepo *RepoFile) AddNew( ctx context.Context, streamerID int, file multipart.FileHeader, - fileName, extension, fileType string, + extension, fileType string, ) (string, error) { + fileName, err := fileRepo.storage.Upload(&file, streamerID) + if err != nil { + return "", err + } + args := pgx.NamedArgs{ "streamer_id": streamerID, "file_name": fileName, @@ -47,13 +53,34 @@ func (fileRepo *RepoFile) AddNew( if !ok { return "", fmt.Errorf("unexpected fileID type: %T", fileIDRaw) } - fileID := uuid.UUID(fileIDBytes).String() - err = fileRepo.storage.Upload(&file, streamerID) - if err != nil { - return "", err - } - return fileID, nil } + +func (fileRepo *RepoFile) CheckFileExists( + ctx context.Context, + streamerID int, + fileName, extension, fileType string, +) (bool, error) { + args := pgx.NamedArgs{ + "streamer_id": streamerID, + "file_name": fileName, + "file_type": fileType, + "extension": extension, + } + + rows, err := fileRepo.db.Select(ctx, sql.GetFileExists, args) + if err != nil { + return false, err + } + + var fileId [][16]uint8 + err = pgxscan.ScanOne(fileId, rows) + if err != nil { + return false, nil + } + + return true, nil + +} diff --git a/internal/service/file/file.go b/internal/service/file/file.go index c77a85c..83ec297 100644 --- a/internal/service/file/file.go +++ b/internal/service/file/file.go @@ -46,7 +46,6 @@ func (fileService *ServiceFile) AddNewFile( ctx, streamerID, file, - file.Filename, fileExt, mimeType, )