Skip to content

Commit

Permalink
Feat: [#133] Add some methods to contracts/filesystem::File (#119)
Browse files Browse the repository at this point in the history
* Add some methods to contracts/filesystem::File

* Optimize unit tests
  • Loading branch information
hwbrzzl authored May 24, 2023
1 parent 9d7896d commit 889aef1
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 84 deletions.
9 changes: 6 additions & 3 deletions contracts/filesystem/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ type Driver interface {
//go:generate mockery --name=File
type File interface {
Disk(disk string) File
Extension() (string, error)
File() string
Store(path string) (string, error)
StoreAs(path string, name string) (string, error)
GetClientOriginalName() string
GetClientOriginalExtension() string
HashName(path ...string) string
Extension() (string, error)
LastModified() (time.Time, error)
MimeType() (string, error)
Size() (int64, error)
Store(path string) (string, error)
StoreAs(path string, name string) (string, error)
}
49 changes: 31 additions & 18 deletions filesystem/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"path"
"strings"
"time"

"github.com/goravel/framework/contracts/filesystem"
"github.com/goravel/framework/facades"
Expand All @@ -17,9 +18,9 @@ import (
)

type File struct {
disk string
file string
filename string
disk string
path string
name string
}

func NewFile(file string) (*File, error) {
Expand All @@ -29,7 +30,7 @@ func NewFile(file string) (*File, error) {

disk := facades.Config.GetString("filesystems.default")

return &File{disk: disk, file: file, filename: path.Base(file)}, nil
return &File{disk: disk, path: file, name: path.Base(file)}, nil
}

func NewFileFromRequest(fileHeader *multipart.FileHeader) (*File, error) {
Expand All @@ -53,7 +54,7 @@ func NewFileFromRequest(fileHeader *multipart.FileHeader) (*File, error) {

disk := facades.Config.GetString("filesystems.default")

return &File{disk: disk, file: tempFile.Name(), filename: fileHeader.Filename}, nil
return &File{disk: disk, path: tempFile.Name(), name: fileHeader.Filename}, nil
}

func (f *File) Disk(disk string) filesystem.File {
Expand All @@ -62,24 +63,20 @@ func (f *File) Disk(disk string) filesystem.File {
return f
}

func (f *File) File() string {
return f.file
}

func (f *File) Store(path string) (string, error) {
return facades.Storage.Disk(f.disk).PutFile(path, f)
func (f *File) Extension() (string, error) {
return supportfile.Extension(f.path)
}

func (f *File) StoreAs(path string, name string) (string, error) {
return facades.Storage.Disk(f.disk).PutFileAs(path, f, name)
func (f *File) File() string {
return f.path
}

func (f *File) GetClientOriginalName() string {
return f.filename
return f.name
}

func (f *File) GetClientOriginalExtension() string {
return supportfile.ClientOriginalExtension(f.filename)
return supportfile.ClientOriginalExtension(f.name)
}

func (f *File) HashName(path ...string) string {
Expand All @@ -88,14 +85,30 @@ func (f *File) HashName(path ...string) string {
realPath = strings.TrimRight(path[0], "/") + "/"
}

extension, _ := supportfile.Extension(f.file, true)
extension, _ := supportfile.Extension(f.path, true)
if extension == "" {
return realPath + str.Random(40)
}

return realPath + str.Random(40) + "." + extension
}

func (f *File) Extension() (string, error) {
return supportfile.Extension(f.file)
func (f *File) LastModified() (time.Time, error) {
return supportfile.LastModified(f.path, facades.Config.GetString("app.timezone"))
}

func (f *File) MimeType() (string, error) {
return supportfile.MimeType(f.path)
}

func (f *File) Size() (int64, error) {
return supportfile.Size(f.path)
}

func (f *File) Store(path string) (string, error) {
return facades.Storage.Disk(f.disk).PutFile(path, f)
}

func (f *File) StoreAs(path string, name string) (string, error) {
return facades.Storage.Disk(f.disk).PutFileAs(path, f, name)
}
2 changes: 1 addition & 1 deletion filesystem/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestNewFileFromRequest(t *testing.T) {
assert.Nil(t, err)
file, err := NewFileFromRequest(f)
assert.Nil(t, err)
assert.Equal(t, ".txt", path.Ext(file.file))
assert.Equal(t, ".txt", path.Ext(file.path))

mockConfig.AssertExpectations(t)
}
34 changes: 4 additions & 30 deletions filesystem/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import (
"strings"
"time"

"github.com/gabriel-vasile/mimetype"

"github.com/goravel/framework/contracts/filesystem"
"github.com/goravel/framework/facades"
supportfile "github.com/goravel/framework/support/file"
"github.com/goravel/framework/support/str"
)

Expand Down Expand Up @@ -143,30 +142,15 @@ func (r *Local) Get(file string) (string, error) {
}

func (r *Local) LastModified(file string) (time.Time, error) {
fileInfo, err := os.Stat(r.fullPath(file))
if err != nil {
return time.Time{}, err
}

l, err := time.LoadLocation(facades.Config.GetString("app.timezone"))
if err != nil {
return time.Time{}, err
}

return fileInfo.ModTime().In(l), nil
return supportfile.LastModified(r.fullPath(file), facades.Config.GetString("app.timezone"))
}

func (r *Local) MakeDirectory(directory string) error {
return os.MkdirAll(filepath.Dir(r.fullPath(directory)+string(filepath.Separator)), os.ModePerm)
}

func (r *Local) MimeType(file string) (string, error) {
mtype, err := mimetype.DetectFile(r.fullPath(file))
if err != nil {
return "", err
}

return mtype.String(), nil
return supportfile.MimeType(r.fullPath(file))
}

func (r *Local) Missing(file string) bool {
Expand Down Expand Up @@ -232,17 +216,7 @@ func (r *Local) PutFileAs(filePath string, source filesystem.File, name string)
}

func (r *Local) Size(file string) (int64, error) {
fileInfo, err := os.Open(r.fullPath(file))
if err != nil {
return 0, err
}

fi, err := fileInfo.Stat()
if err != nil {
return 0, err
}

return fi.Size(), nil
return supportfile.Size(r.fullPath(file))
}

func (r *Local) TemporaryUrl(file string, time time.Time) (string, error) {
Expand Down
2 changes: 1 addition & 1 deletion http/gin_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (r *GinRequest) All() map[string]any {
}
}
r.instance.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
} else if contentType == "multipart/form-data" {
} else if contentType == "multipart/form-data" && r.instance.Request.ContentLength > 0 {
if r.instance.Request.PostForm == nil {
if err := r.instance.Request.ParseMultipartForm(defaultMemory); err != nil {
facades.Log.Errorf("when calling request all method, parse multipart form error: %v", err)
Expand Down
74 changes: 74 additions & 0 deletions route/gin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,27 @@ func TestGinRequest(t *testing.T) {
expectCode: http.StatusOK,
expectBody: "{\"all\":{\"a\":\"1,2\",\"b\":\"4\",\"e\":\"e\",\"file\":{\"Filename\":\"logo.png\",\"Header\":{\"Content-Disposition\":[\"form-data; name=\\\"file\\\"; filename=\\\"logo.png\\\"\"],\"Content-Type\":[\"application/octet-stream\"]},\"Size\":16438}}}",
},
{
name: "All with empty form when Post",
method: "POST",
url: "/all?a=1&a=2&b=3",
setup: func(method, url string) error {
mock.Log()

gin.Post("/all", func(ctx contractshttp.Context) {
ctx.Response().Success().Json(contractshttp.Json{
"all": ctx.Request().All(),
})
})

req, _ = http.NewRequest(method, url, nil)
req.Header.Set("Content-Type", "multipart/form-data;boundary=0")

return nil
},
expectCode: http.StatusOK,
expectBody: "{\"all\":{\"a\":\"1,2\",\"b\":\"3\"}}",
},
{
name: "All with json when Post",
method: "POST",
Expand Down Expand Up @@ -495,6 +516,59 @@ func TestGinRequest(t *testing.T) {
expectCode: http.StatusOK,
expectBody: "{\"age\":1,\"all\":{\"Age\":1,\"Name\":\"goravel\",\"a\":\"1,2\",\"name\":\"3\"},\"name\":\"goravel\"}",
},
{
name: "All with error json when Post",
method: "POST",
url: "/all?a=1&a=2&name=3",
setup: func(method, url string) error {
mock.Log()
gin.Post("/all", func(ctx contractshttp.Context) {
all := ctx.Request().All()
type Test struct {
Name string
Age int
}
var test Test
_ = ctx.Request().Bind(&test)

ctx.Response().Success().Json(contractshttp.Json{
"all": all,
"name": test.Name,
"age": test.Age,
})
})

payload := strings.NewReader(`{
"Name": "goravel",
"Age": 1,
}`)
req, _ = http.NewRequest(method, url, payload)
req.Header.Set("Content-Type", "application/json")

return nil
},
expectCode: http.StatusOK,
expectBody: "{\"age\":0,\"all\":null,\"name\":\"\"}",
},
{
name: "All with empty json when Post",
method: "POST",
url: "/all?a=1&a=2&name=3",
setup: func(method, url string) error {
gin.Post("/all", func(ctx contractshttp.Context) {
ctx.Response().Success().Json(contractshttp.Json{
"all": ctx.Request().All(),
})
})

req, _ = http.NewRequest(method, url, nil)
req.Header.Set("Content-Type", "application/json")

return nil
},
expectCode: http.StatusOK,
expectBody: "{\"all\":{\"a\":\"1,2\",\"name\":\"3\"}}",
},
{
name: "All with json when Put",
method: "PUT",
Expand Down
Loading

0 comments on commit 889aef1

Please sign in to comment.