Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

v0.16.9 #1996

Merged
merged 66 commits into from
May 25, 2020
Merged

v0.16.9 #1996

Changes from 1 commit
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
f0fdd55
merge changes from buffalo-cli into main repo
markbates Jan 23, 2020
c36a985
cache deps before building and copying source (#1884)
drnic Jan 30, 2020
64d477e
Generator resource action test breaks with unused imports fixes #1893…
markbates Jan 31, 2020
56a56e0
update deps (#1896)
markbates Feb 1, 2020
b21df66
switch to tags/v3 for consistency (#1901)
hdm Feb 6, 2020
d0d04f8
update helpers/tags
markbates Feb 6, 2020
87c1bbb
update validate
markbates Feb 6, 2020
ef737c7
try to fix mismatched imports (#1921)
markbates Mar 18, 2020
edd47d2
Merge branch 'master' into development
markbates Mar 18, 2020
ae47f10
fixes more broken semantic import paths (#1925)
markbates Mar 23, 2020
1178ec4
adding a few packages to replace
paganotoni Mar 24, 2020
9f9d5f1
Replace Azure badge with Github actions badge (#1920)
stanislas-m Apr 2, 2020
d68f0c3
changing the packages to be replaced (#1928)
paganotoni Apr 2, 2020
5a69731
Merge branch 'master' into development
paganotoni Apr 2, 2020
5746d81
merging
paganotoni Apr 6, 2020
d456808
Merging master (#1936)
paganotoni Apr 6, 2020
5fb62d6
Merge branch 'development' of https://github.com/gobuffalo/buffalo in…
paganotoni Apr 7, 2020
ae54b4c
Merge branch 'master' of https://github.com/gobuffalo/buffalo into de…
paganotoni Apr 8, 2020
c6208b3
Update js template to support font awesome (#1933)
corylanou Apr 8, 2020
78fef36
Merge branch 'master' into development
paganotoni Apr 8, 2020
2ded73b
Fixes generated package.json and resources generator (#1944)
paganotoni Apr 9, 2020
2e79e76
Merge branch 'development' of https://github.com/gobuffalo/buffalo in…
paganotoni Apr 9, 2020
db223a7
updating dockerfile to use v0.16.3
paganotoni Apr 9, 2020
1a11a3b
packing
paganotoni Apr 9, 2020
db05487
Merge branch 'master' of https://github.com/gobuffalo/buffalo into de…
paganotoni Apr 9, 2020
763142a
Adding new template for codeclimate code analysis (#1946)
paganotoni Apr 12, 2020
997b8e1
Updates our coke app package.json and Yarn (#1947)
paganotoni Apr 12, 2020
bd173b1
Removes old buffalo-pop plugin (#1948)
paganotoni Apr 12, 2020
2089442
using filepath for auto render files (#1951)
paganotoni Apr 12, 2020
2c96f84
Bugfix c.Error http code (#1952)
paganotoni Apr 12, 2020
12758e6
Allows to set test timeout (#1953)
paganotoni Apr 12, 2020
0a8d59f
Fixes plush to use now plush/v4 (#1954)
paganotoni Apr 12, 2020
c335d58
Adding packr files (#1956)
paganotoni Apr 13, 2020
904f80b
Missing comments on the Plugins struct (#1958)
paganotoni Apr 13, 2020
b47d822
merging master
paganotoni Apr 14, 2020
22ba6f4
fixing mispell package (#1960)
paganotoni Apr 14, 2020
92a7563
Task #1941 (#1943)
paganotoni Apr 14, 2020
b96b2b5
bumping version
paganotoni Apr 15, 2020
9e207d6
Merge branch 'development' of https://github.com/gobuffalo/buffalo in…
paganotoni Apr 15, 2020
902bf5f
packing
paganotoni Apr 15, 2020
cfb2914
use go 1.14 for building goreleaser binaries (#1962)
markbates Apr 15, 2020
134744c
adds an extra file to our releases that will be pulled by our docker …
paganotoni Apr 15, 2020
219c16a
cleaning some docker issues (#1966)
paganotoni Apr 16, 2020
8977e91
Fix GO111MODULE value in build Docker images (#1970)
vladdy Apr 16, 2020
4a6755c
Add in GZIP compression to file serving (#1969)
vincentchu Apr 17, 2020
b3942fc
Added genny support for CircleCI as a CI provider. (#1972)
jamtur01 Apr 19, 2020
3d85cfb
removing helpers from the Go template Engine (#1971)
paganotoni Apr 19, 2020
0a04c7a
adding next version
paganotoni Apr 20, 2020
687b04e
packing
paganotoni Apr 20, 2020
198869f
making codeclimate ignore packr files
paganotoni Apr 20, 2020
5ebffe7
merging
paganotoni Apr 20, 2020
834c095
adding direct version on the docker build
paganotoni Apr 21, 2020
dea73d0
merging
paganotoni Apr 21, 2020
ef66b75
fixing plugin installation
paganotoni Apr 21, 2020
7829a5b
merging
paganotoni Apr 21, 2020
9abf1e5
bumping version
paganotoni Apr 21, 2020
f54ca9e
Merge branch 'master' of https://github.com/gobuffalo/buffalo
paganotoni May 8, 2020
be349fc
Merge branch 'master' into development
paganotoni May 8, 2020
a18966e
Binding refactoring (#1975)
paganotoni May 15, 2020
dd184e3
added autoprefixer for bootstrap compilation (#1990)
arunsworld May 24, 2020
b6ac769
Add batch mail sending (#1815)
Ilkrash May 25, 2020
253f0c7
Updates jQuery Dependency (#1995)
paganotoni May 25, 2020
dfe589b
removing extra file from the releaser
paganotoni May 25, 2020
c7cad27
Merge branch 'development' of https://github.com/gobuffalo/buffalo in…
paganotoni May 25, 2020
73c0353
adding some missing comments
paganotoni May 25, 2020
3694c5c
removing unused fields
paganotoni May 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Binding refactoring (#1975)
* refactoring binding a bit

* adding tests for null time decoder

* removing unneeded variable

* little bit of name changes

* moving RequestTypeBinder interface

* adding some missing comments

* advancing on Marks recommendations. 1st step is to reduce the indirect behavior on the interface

* back to locks

* adding lock on Exec

* adding those missing tests

* moving time formats to the decoders section
  • Loading branch information
paganotoni authored May 15, 2020
commit a18966ead68458660d4bd5e427bb00a606dae651
172 changes: 31 additions & 141 deletions binding/binding.go
Original file line number Diff line number Diff line change
@@ -1,71 +1,56 @@
package binding

import (
"encoding/json"
"encoding/xml"
"fmt"
"net/http"
"strings"
"sync"
"time"

"github.com/gobuffalo/buffalo/internal/httpx"
"github.com/gobuffalo/nulls"
"github.com/gobuffalo/buffalo/binding/decoders"
"github.com/monoculum/formam"
)

// Binder takes a request and binds it to an interface.
// If there is a problem it should return an error.
type Binder func(*http.Request, interface{}) error
var (
// MaxFileMemory can be used to set the maximum size, in bytes, for files to be
// stored in memory during uploaded for multipart requests.
// See https://golang.org/pkg/net/http/#Request.ParseMultipartForm for more
// information on how this impacts file uploads.
MaxFileMemory int64 = 5 * 1024 * 1024

// CustomTypeDecoder converts a custom type from the request insto its exact type.
type CustomTypeDecoder func([]string) (interface{}, error)

// binders is a map of the defined content-type related binders.
var binders = map[string]Binder{}
formDecoder = formam.NewDecoder(&formam.DecoderOptions{
TagName: "form",
IgnoreUnknownKeys: true,
})

var decoder *formam.Decoder
var lock = &sync.Mutex{}
var timeFormats = []string{
time.RFC3339,
"01/02/2006",
"2006-01-02",
"2006-01-02T15:04",
time.ANSIC,
time.UnixDate,
time.RubyDate,
time.RFC822,
time.RFC822Z,
time.RFC850,
time.RFC1123,
time.RFC1123Z,
time.RFC3339Nano,
time.Kitchen,
time.Stamp,
time.StampMilli,
time.StampMicro,
time.StampNano,
}
// BaseRequestBinder is an instance of the requeBinder, it comes with preconfigured
// content type binders for HTML, JSON, XML and Files, as well as custom types decoders
// for time.Time and nulls.Time
BaseRequestBinder = NewRequestBinder(
HTMLContentTypeBinder{
decoder: formDecoder,
},
JSONContentTypeBinder{},
XMLRequestTypeBinder{},
FileRequestTypeBinder{
decoder: formDecoder,
},
)
)

// RegisterTimeFormats allows to add custom time layouts that
// the binder will be able to use for decoding.
func RegisterTimeFormats(layouts ...string) {
timeFormats = append(layouts, timeFormats...)
decoders.RegisterTimeFormats(layouts...)
}

// RegisterCustomDecoder allows to define custom type decoders.
// RegisterCustomDecoder allows to define custom decoders for certain types
// In the request.
func RegisterCustomDecoder(fn CustomTypeDecoder, types []interface{}, fields []interface{}) {
rawFunc := (func([]string) (interface{}, error))(fn)
decoder.RegisterCustomType(rawFunc, types, fields)
formDecoder.RegisterCustomType(rawFunc, types, fields)
}

// Register maps a request Content-Type (application/json)
// to a Binder.
func Register(contentType string, fn Binder) {
lock.Lock()
defer lock.Unlock()

binders[strings.ToLower(contentType)] = fn
BaseRequestBinder.Register(contentType, fn)
}

// Exec will bind the interface to the request.Body. The type of binding
@@ -74,100 +59,5 @@ func Register(contentType string, fn Binder) {
// is "application/xml" it will use "xml.NewDecoder". The default
// binder is "https://github.com/monoculum/formam".
func Exec(req *http.Request, value interface{}) error {
if ba, ok := value.(Bindable); ok {
return ba.Bind(req)
}

ct := httpx.ContentType(req)
if ct == "" {
return fmt.Errorf("blank content type")
}
if b, ok := binders[ct]; ok {
return b(req, value)
}
return fmt.Errorf("could not find a binder for %s", ct)
}

func init() {
decoder = formam.NewDecoder(&formam.DecoderOptions{
TagName: "form",
IgnoreUnknownKeys: true,
})

decoder.RegisterCustomType(func(vals []string) (interface{}, error) {
return parseTime(vals)
}, []interface{}{time.Time{}}, nil)

decoder.RegisterCustomType(func(vals []string) (interface{}, error) {
var ti nulls.Time

t, err := parseTime(vals)
if err != nil {
return ti, err
}
ti.Time = t
ti.Valid = true

return ti, nil
}, []interface{}{nulls.Time{}}, nil)

sb := func(req *http.Request, i interface{}) error {
err := req.ParseForm()
if err != nil {
return err
}

if err := decoder.Decode(req.Form, i); err != nil {
return err
}
return nil
}

binders["application/html"] = sb
binders["text/html"] = sb
binders["application/x-www-form-urlencoded"] = sb
binders["html"] = sb
}

func init() {
jb := func(req *http.Request, value interface{}) error {
return json.NewDecoder(req.Body).Decode(value)
}

binders["application/json"] = jb
binders["text/json"] = jb
binders["json"] = jb
}

func init() {
xb := func(req *http.Request, value interface{}) error {
return xml.NewDecoder(req.Body).Decode(value)
}

binders["application/xml"] = xb
binders["text/xml"] = xb
binders["xml"] = xb
}

func parseTime(vals []string) (time.Time, error) {
var t time.Time
var err error

// don't try to parse empty time values, it will raise an error
if len(vals) == 0 || vals[0] == "" {
return t, nil
}

for _, layout := range timeFormats {
t, err = time.Parse(layout, vals[0])
if err == nil {
return t, nil
}
}

if err != nil {
return t, err
}

return t, nil
return BaseRequestBinder.Exec(req, value)
}
40 changes: 0 additions & 40 deletions binding/binding_custom_decoder_test.go

This file was deleted.

94 changes: 49 additions & 45 deletions binding/binding_test.go
Original file line number Diff line number Diff line change
@@ -2,69 +2,73 @@ package binding

import (
"net/http"
"net/url"
"testing"
"time"

"github.com/stretchr/testify/require"
)

type blogPost struct {
Tags []string
Dislikes int
Likes int32
}

func Test_Register(t *testing.T) {
r := require.New(t)
l := len(binders)

Register("foo/bar", func(*http.Request, interface{}) error {
return nil
})
r.Len(binders, l+1)
}

func TestParseTimeErrorParsing(t *testing.T) {
r := require.New(t)
_, err := parseTime([]string{"this is sparta"})
r.Error(err)
}

func TestParseTime(t *testing.T) {
r.NotNil(BaseRequestBinder.binders["foo/bar"])

r := require.New(t)
req, err := http.NewRequest("POST", "/", nil)
r.NoError(err)

testCases := []struct {
input string
expected time.Time
expectErr bool
}{
{
input: "2017-01-01",
expected: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC),
expectErr: false,
},
{
input: "2018-07-13T15:34",
expected: time.Date(2018, time.July, 13, 15, 34, 0, 0, time.UTC),
expectErr: false,
},
{
input: "2018-20-10T30:15",
expected: time.Time{},
expectErr: true,
},
req.Header.Set("Content-Type", "foo/bar")
req.Form = url.Values{
"Tags": []string{"AAA"},
"Likes": []string{"12"},
"Dislikes": []string{"1000"},
}

for _, tc := range testCases {
tt, err := parseTime([]string{tc.input})
if !tc.expectErr {
r.NoError(err)
}
r.Equal(tc.expected, tt)
}
}
req.ParseForm()

var post blogPost
r.NoError(Exec(req, &post))

func TestParseTimeConflicting(t *testing.T) {
RegisterTimeFormats("2006-02-01")
r.Equal([]string(nil), post.Tags)
r.Equal(int32(0), post.Likes)
r.Equal(0, post.Dislikes)

}

func Test_RegisterCustomDecoder(t *testing.T) {
r := require.New(t)
tt, err := parseTime([]string{"2017-01-10"})

RegisterCustomDecoder(func(vals []string) (interface{}, error) {
return []string{"X"}, nil
}, []interface{}{[]string{}}, nil)

RegisterCustomDecoder(func(vals []string) (interface{}, error) {
return 0, nil
}, []interface{}{int(0)}, nil)

post := blogPost{}
req, err := http.NewRequest("POST", "/", nil)
r.NoError(err)
expected := time.Date(2017, time.October, 1, 0, 0, 0, 0, time.UTC)
r.Equal(expected, tt)

req.Header.Set("Content-Type", "application/html")
req.Form = url.Values{
"Tags": []string{"AAA"},
"Likes": []string{"12"},
"Dislikes": []string{"1000"},
}
req.ParseForm()

r.NoError(Exec(req, &post))
r.Equal([]string{"X"}, post.Tags)
r.Equal(int32(12), post.Likes)
r.Equal(0, post.Dislikes)
}
Loading