replace web/file by web/file2
This commit is contained in:
		
							parent
							
								
									b8acc5f8af
								
							
						
					
					
						commit
						6db99dd2bb
					
				|  | @ -3,8 +3,8 @@ package file | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 
 | 
 | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file2/fs" | 	"dev.sum7.eu/genofire/golang-lib/web/file/fs" | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file2/s3" | 	"dev.sum7.eu/genofire/golang-lib/web/file/s3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // fsType represents a type of file store.
 | // fsType represents a type of file store.
 | ||||||
|  | @ -1,8 +0,0 @@ | ||||||
| package file |  | ||||||
| 
 |  | ||||||
| import "errors" |  | ||||||
| 
 |  | ||||||
| // Error Messages
 |  | ||||||
| var ( |  | ||||||
| 	ErrUnsupportedStorageType = errors.New("storage type invalid") |  | ||||||
| ) |  | ||||||
|  | @ -1,12 +0,0 @@ | ||||||
| package file |  | ||||||
| 
 |  | ||||||
| import "github.com/google/uuid" |  | ||||||
| 
 |  | ||||||
| // File to store information in database
 |  | ||||||
| type File struct { |  | ||||||
| 	ID          uuid.UUID `json:"id" gorm:"type:uuid;default:gen_random_uuid()" example:"32466d63-efa4-4f27-9f2b-a1f06c8e2e1d"` |  | ||||||
| 	StorageType string    `json:"storage_type,omitempty"` |  | ||||||
| 	Path        string    `json:"path,omitempty"` |  | ||||||
| 	Filename    string    `json:"filename"` |  | ||||||
| 	ContentType string    `json:"content-type"` |  | ||||||
| } |  | ||||||
|  | @ -9,8 +9,8 @@ import ( | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 
 | 
 | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file2" | 	"dev.sum7.eu/genofire/golang-lib/web/file" | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file2/fs" | 	"dev.sum7.eu/genofire/golang-lib/web/file/fs" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestOpenStat(t *testing.T) { | func TestOpenStat(t *testing.T) { | ||||||
|  | @ -1,63 +0,0 @@ | ||||||
| package fs |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"io" |  | ||||||
| 	"mime/multipart" |  | ||||||
| 	"os" |  | ||||||
| 	"path" |  | ||||||
| 
 |  | ||||||
| 	"github.com/google/uuid" |  | ||||||
| 
 |  | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // consts for filemanager
 |  | ||||||
| const ( |  | ||||||
| 	StorageTypeFS = "fs" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // error messages
 |  | ||||||
| var ( |  | ||||||
| 	ErrPathNotExistsOrNoDirectory = errors.New("path invalid: not exists or not an directory") |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // FileManager to handle data on disk
 |  | ||||||
| type FileManager struct { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Check if filemanager could be used
 |  | ||||||
| func (m *FileManager) Check(s *file.Service) error { |  | ||||||
| 	info, err := os.Stat(s.Path) |  | ||||||
| 	if os.IsNotExist(err) || !info.IsDir() { |  | ||||||
| 		return ErrPathNotExistsOrNoDirectory |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Save a file on disk and update file db
 |  | ||||||
| func (m *FileManager) Save(s *file.Service, file *file.File, src multipart.File) error { |  | ||||||
| 	file.ID = uuid.New() |  | ||||||
| 	file.Path = path.Join(file.ID.String(), file.Filename) |  | ||||||
| 
 |  | ||||||
| 	directory := path.Join(s.Path, file.ID.String()) |  | ||||||
| 	os.Mkdir(directory, 0750) |  | ||||||
| 
 |  | ||||||
| 	out, err := os.Create(path.Join(s.Path, file.Path)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	defer out.Close() |  | ||||||
| 
 |  | ||||||
| 	_, err = io.Copy(out, src) |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Read get an reader of an file
 |  | ||||||
| func (m *FileManager) Read(s *file.Service, file *file.File) (io.Reader, error) { |  | ||||||
| 	return os.Open(path.Join(s.Path, file.Path)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func init() { |  | ||||||
| 	file.AddManager(StorageTypeFS, &FileManager{}) |  | ||||||
| } |  | ||||||
|  | @ -1,92 +0,0 @@ | ||||||
| package fs |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"io" |  | ||||||
| 	"os" |  | ||||||
| 	"strings" |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| 
 |  | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web" |  | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestCheck(t *testing.T) { |  | ||||||
| 	assert := assert.New(t) |  | ||||||
| 
 |  | ||||||
| 	service := file.Service{ |  | ||||||
| 		StorageType: StorageTypeFS, |  | ||||||
| 		Path:        "./test", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	assert.NoError(service.Check()) |  | ||||||
| 
 |  | ||||||
| 	service.StorageType = "s3" |  | ||||||
| 	assert.ErrorIs(file.ErrUnsupportedStorageType, service.Check()) |  | ||||||
| 
 |  | ||||||
| 	service.StorageType = StorageTypeFS |  | ||||||
| 	service.Path = "./main_test.go" |  | ||||||
| 	assert.ErrorIs(ErrPathNotExistsOrNoDirectory, service.Check()) |  | ||||||
| 
 |  | ||||||
| 	/* TODO no write permission |  | ||||||
| 	service.Path = "/dev" |  | ||||||
| 	assert.ErrorIs(ErrPathNotExistsOrNoDirectory, service.Check()) |  | ||||||
| 	*/ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestSave(t *testing.T) { |  | ||||||
| 	assert := assert.New(t) |  | ||||||
| 
 |  | ||||||
| 	service := file.Service{ |  | ||||||
| 		StorageType: "s3", |  | ||||||
| 		Path:        "./test", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	_, err := service.Upload(nil) |  | ||||||
| 	assert.ErrorIs(file.ErrUnsupportedStorageType, err) |  | ||||||
| 
 |  | ||||||
| 	service.StorageType = StorageTypeFS |  | ||||||
| 	req, err := web.NewRequestWithFile("localhost", "./test/00000000-0000-0000-0000-000000000000/a.txt") |  | ||||||
| 	assert.NoError(err) |  | ||||||
| 	assert.NotNil(req) |  | ||||||
| 
 |  | ||||||
| 	_, err = service.Upload(req) |  | ||||||
| 	assert.NoError(err) |  | ||||||
| 
 |  | ||||||
| 	service.Path = "/dev" |  | ||||||
| 	_, err = service.Upload(req) |  | ||||||
| 	assert.True(os.IsNotExist(err)) |  | ||||||
| 	//assert.True(os.IsPermission(err))
 |  | ||||||
| 
 |  | ||||||
| 	// TODO no write permission
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestRead(t *testing.T) { |  | ||||||
| 	assert := assert.New(t) |  | ||||||
| 
 |  | ||||||
| 	service := file.Service{ |  | ||||||
| 		StorageType: "s3", |  | ||||||
| 		Path:        "./test", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	_, err := service.Read(nil) |  | ||||||
| 	assert.ErrorIs(file.ErrUnsupportedStorageType, err) |  | ||||||
| 
 |  | ||||||
| 	service.StorageType = StorageTypeFS |  | ||||||
| 
 |  | ||||||
| 	file := &file.File{ |  | ||||||
| 		Path: "00000000-0000-0000-0000-000000000000/a.txt", |  | ||||||
| 	} |  | ||||||
| 	r, err := service.Read(file) |  | ||||||
| 	assert.NoError(err) |  | ||||||
| 	buf := &strings.Builder{} |  | ||||||
| 	_, err = io.Copy(buf, r) |  | ||||||
| 	assert.Equal("Hello world\n", buf.String()) |  | ||||||
| 
 |  | ||||||
| 	service.Path = "/dev" |  | ||||||
| 	_, err = service.Read(file) |  | ||||||
| 	assert.True(os.IsNotExist(err)) |  | ||||||
| 
 |  | ||||||
| 	// TODO no write permission
 |  | ||||||
| } |  | ||||||
|  | @ -1 +0,0 @@ | ||||||
| Hello world |  | ||||||
|  | @ -15,7 +15,7 @@ import ( | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 
 | 
 | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file2" | 	"dev.sum7.eu/genofire/golang-lib/web/file" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type TestFS struct { | type TestFS struct { | ||||||
|  | @ -1,98 +0,0 @@ | ||||||
| package file |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"errors" |  | ||||||
| 	"io" |  | ||||||
| 	"mime/multipart" |  | ||||||
| 	"net/http" |  | ||||||
| 	"strings" |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web" |  | ||||||
| 	"github.com/gin-gonic/gin" |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| const storageTypeDummy = "dummy" |  | ||||||
| 
 |  | ||||||
| type dummyManager struct { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (m *dummyManager) Check(s *Service) error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| func (m *dummyManager) Save(s *Service, file *File, src multipart.File) error { |  | ||||||
| 	if src == nil { |  | ||||||
| 		return errors.New("nothing to fill") |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| func (m *dummyManager) Read(s *Service, file *File) (io.Reader, error) { |  | ||||||
| 	b := bytes.Buffer{} |  | ||||||
| 	b.WriteString("Hello world\n") |  | ||||||
| 	return &b, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func init() { |  | ||||||
| 	AddManager(storageTypeDummy, &dummyManager{}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestCheck(t *testing.T) { |  | ||||||
| 	assert := assert.New(t) |  | ||||||
| 
 |  | ||||||
| 	service := Service{ |  | ||||||
| 		StorageType: storageTypeDummy, |  | ||||||
| 		Path:        "./fs/test", |  | ||||||
| 	} |  | ||||||
| 	assert.NoError(service.Check()) |  | ||||||
| 
 |  | ||||||
| 	service.StorageType = "s3" |  | ||||||
| 	assert.ErrorIs(ErrUnsupportedStorageType, service.Check()) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestSave(t *testing.T) { |  | ||||||
| 	assert := assert.New(t) |  | ||||||
| 
 |  | ||||||
| 	service := Service{ |  | ||||||
| 		StorageType: "fs", |  | ||||||
| 		Path:        "./fs/test", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	_, err := service.Upload(nil) |  | ||||||
| 	assert.ErrorIs(ErrUnsupportedStorageType, err) |  | ||||||
| 
 |  | ||||||
| 	service.StorageType = storageTypeDummy |  | ||||||
| 	_, err = service.GINUpload(&gin.Context{Request: &http.Request{}}) |  | ||||||
| 	assert.ErrorIs(err, http.ErrNotMultipart) |  | ||||||
| 
 |  | ||||||
| 	req, err := web.NewRequestWithFile("http://localhost/upload", "./fs/test/00000000-0000-0000-0000-000000000000/a.txt") |  | ||||||
| 	assert.NoError(err) |  | ||||||
| 	assert.NotNil(req) |  | ||||||
| 
 |  | ||||||
| 	_, err = service.Upload(req) |  | ||||||
| 	assert.NoError(err) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestRead(t *testing.T) { |  | ||||||
| 	assert := assert.New(t) |  | ||||||
| 
 |  | ||||||
| 	service := Service{ |  | ||||||
| 		StorageType: "fs", |  | ||||||
| 		Path:        "./fs/test", |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	_, err := service.Read(nil) |  | ||||||
| 	assert.ErrorIs(ErrUnsupportedStorageType, err) |  | ||||||
| 
 |  | ||||||
| 	service.StorageType = "dummy" |  | ||||||
| 
 |  | ||||||
| 	file := &File{ |  | ||||||
| 		Path: "00000000-0000-0000-0000-000000000000/a.txt", |  | ||||||
| 	} |  | ||||||
| 	r, err := service.Read(file) |  | ||||||
| 	assert.NoError(err) |  | ||||||
| 	buf := &strings.Builder{} |  | ||||||
| 	_, err = io.Copy(buf, r) |  | ||||||
| 	assert.Equal("Hello world\n", buf.String()) |  | ||||||
| } |  | ||||||
|  | @ -1,20 +0,0 @@ | ||||||
| package file |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"io" |  | ||||||
| 	"mime/multipart" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type FileManager interface { |  | ||||||
| 	Check(s *Service) error |  | ||||||
| 	Save(s *Service, fileObj *File, file multipart.File) error |  | ||||||
| 	Read(s *Service, fileObj *File) (io.Reader, error) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var ( |  | ||||||
| 	managers = make(map[string]FileManager) |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func AddManager(typ string, m FileManager) { |  | ||||||
| 	managers[typ] = m |  | ||||||
| } |  | ||||||
|  | @ -1,57 +0,0 @@ | ||||||
| package s3 |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"net/url" |  | ||||||
| 
 |  | ||||||
| 	"github.com/minio/minio-go/v7" |  | ||||||
| 	"github.com/minio/minio-go/v7/pkg/credentials" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // Error Messages during connect
 |  | ||||||
| var ( |  | ||||||
| 	ErrNoPassword = errors.New("no secret access key found") |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // Connect try to use a path to setup a connection to s3 server
 |  | ||||||
| func Connect(path string) (*minio.Client, string, error) { |  | ||||||
| 	u, err := url.Parse(path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, "", err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	tls := u.Scheme[len(u.Scheme)-1] == 's' |  | ||||||
| 	accessKeyID := u.User.Username() |  | ||||||
| 	secretAccessKey, ok := u.User.Password() |  | ||||||
| 	if !ok { |  | ||||||
| 		return nil, "", ErrNoPassword |  | ||||||
| 	} |  | ||||||
| 	query := u.Query() |  | ||||||
| 	bucketName := query.Get("bucket") |  | ||||||
| 	location := query.Get("location") |  | ||||||
| 
 |  | ||||||
| 	u.User = nil |  | ||||||
| 	u.RawQuery = "" |  | ||||||
| 
 |  | ||||||
| 	ctx := context.Background() |  | ||||||
| 
 |  | ||||||
| 	// Initialize minio client object.
 |  | ||||||
| 	minioClient, err := minio.New(u.String(), &minio.Options{ |  | ||||||
| 		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), |  | ||||||
| 		Secure: tls, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, "", err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// create and check for bucket
 |  | ||||||
| 	err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		if exists, err := minioClient.BucketExists(ctx, bucketName); err != nil || !exists { |  | ||||||
| 			return nil, "", err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return minioClient, bucketName, err |  | ||||||
| } |  | ||||||
|  | @ -5,7 +5,8 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 
 | 
 | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/file2" | 	"dev.sum7.eu/genofire/golang-lib/web/file" | ||||||
|  | 	"dev.sum7.eu/genofire/golang-lib/web/file/s3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // TODO: actually test, either using little dummies or using sth like play.min.io
 | // TODO: actually test, either using little dummies or using sth like play.min.io
 | ||||||
|  | @ -1,69 +0,0 @@ | ||||||
| package file |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"io" |  | ||||||
| 	"net/http" |  | ||||||
| 	"path/filepath" |  | ||||||
| 
 |  | ||||||
| 	"github.com/gin-gonic/gin" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // A Service to handle file-uploads in golang
 |  | ||||||
| type Service struct { |  | ||||||
| 	StorageType string `toml:"storage_type"` |  | ||||||
| 	Path        string `toml:"path"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Check if Service is configurated and useable
 |  | ||||||
| func (s *Service) Check() error { |  | ||||||
| 	mgmt, ok := managers[s.StorageType] |  | ||||||
| 	if !ok { |  | ||||||
| 		return ErrUnsupportedStorageType |  | ||||||
| 	} |  | ||||||
| 	return mgmt.Check(s) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Upload a file to storage
 |  | ||||||
| func (s *Service) Upload(request *http.Request) (*File, error) { |  | ||||||
| 	mgmt, ok := managers[s.StorageType] |  | ||||||
| 	if !ok { |  | ||||||
| 		return nil, ErrUnsupportedStorageType |  | ||||||
| 	} |  | ||||||
| 	file, fileRequest, err := request.FormFile("file") |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	fileObj := File{ |  | ||||||
| 		Filename: filepath.Base(fileRequest.Filename), |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// detect contenttype
 |  | ||||||
| 	buffer := make([]byte, 512) |  | ||||||
| 	n, err := file.Read(buffer) |  | ||||||
| 	if err != nil && err != io.EOF { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	fileObj.ContentType = http.DetectContentType(buffer[:n]) |  | ||||||
| 
 |  | ||||||
| 	// Reset the read pointer
 |  | ||||||
| 	file.Seek(0, io.SeekStart) |  | ||||||
| 	if err := mgmt.Save(s, &fileObj, file); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &fileObj, nil |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GINUpload a file to storage using gin-gonic
 |  | ||||||
| func (s *Service) GINUpload(c *gin.Context) (*File, error) { |  | ||||||
| 	return s.Upload(c.Request) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Read a file to storage
 |  | ||||||
| func (s *Service) Read(file *File) (io.Reader, error) { |  | ||||||
| 	mgmt, ok := managers[s.StorageType] |  | ||||||
| 	if !ok { |  | ||||||
| 		return nil, ErrUnsupportedStorageType |  | ||||||
| 	} |  | ||||||
| 	return mgmt.Read(s, file) |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Lennart
						Lennart