package storage import ( "context" "errors" "github.com/google/uuid" "io" "path/filepath" ) type FileType int const ( ProfileImage FileType = iota ) var ( ErrInvalidFileType = errors.New("invalid file type") ErrFileTooLarge = errors.New("file too large") ErrNoFileUploaded = errors.New("no file uploaded") ) type Storage interface { Upload(ctx context.Context, file io.ReadSeeker, path string) error GetURL(path string) string Delete(ctx context.Context, path string) error ValidateExtension(fileType FileType, filename string) bool GenerateFilename(originalName string) string GetPath(fileType FileType, identifier string, filename string) string } var ( _ Storage = (*LocalStorage)(nil) ) type BaseStorage struct { allowedExtensions map[FileType][]string } func NewBaseStorage() *BaseStorage { return &BaseStorage{ allowedExtensions: map[FileType][]string{ ProfileImage: {".jpg", ".jpeg", ".png", ".webp"}, }, } } func (bs *BaseStorage) ValidateExtension(fileType FileType, filename string) bool { ext := filepath.Ext(filename) for _, allowed := range bs.allowedExtensions[fileType] { if ext == allowed { return true } } return false } func (bs *BaseStorage) GenerateFilename(originalName string) string { ext := filepath.Ext(originalName) return uuid.New().String() + ext } func (bs *BaseStorage) GetPath(fileType FileType, identifier string, filename string) string { switch fileType { case ProfileImage: return filepath.Join("users", identifier, "profile", filename) default: return filepath.Join("misc", filename) } }