This repository has been archived by the owner on May 29, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
form.go
166 lines (146 loc) · 4.18 KB
/
form.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package form
import (
"bytes"
"encoding/json"
"fmt"
"github.com/cjtoolkit/i18n"
"io"
"net/http"
)
// Form Renderer and Validator interface!
type Form interface {
// Renders 'structPtr' to 'w', panic if structPtr is not a struct with pointer.
// Also renders validation errors if 'Validate' or 'MustValidate' was call before hand.
Render(structPtr StructPtrForm, w io.Writer)
// As Render but Return string
RenderStr(structPtr StructPtrForm) string
// Validate User Input and Populate Field in struct with pointers.
// Must use struct with pointers otherwise it will return an error.
// r cannot be 'nil'
Validate(r *http.Request, structPtrs ...StructPtrForm) (bool, error)
// Same as validate but panic on error.
MustValidate(r *http.Request, structPtrs ...StructPtrForm) bool
// Validate Single Field, won't work with must match.
ValidateSingle(structPtr StructPtrForm, name string, value []string) (err error)
// Encode JSON into 'w'
// {"valid": bool, "data":[{"valid":bool, "error":"", "warning":"", "name":"", "count":int}...]}
// Must call Validate or MustValidate first, otnilherwise it's print invalid data.
Json(w io.Writer)
}
// Create new form validator and renderer.
// Panic if unable to verify languageSources.
// To use Default Second Layer specify r as 'nil'.
//
// Note: Stick to one instant per user request,
// do not use it as a global variable, as it's not thread safe.
func New(r RenderSecondLayer, languageSources ...string) Form {
if r == nil {
r = DefaultRenderSecondLayer
}
return &form{
T: i18n.MustTfunc("cjtoolkit-form", languageSources...),
R: r,
Data: map[StructPtrForm]*formData{},
JsonData: []map[string]interface{}{},
}
}
type formData struct {
Errors map[string][]error
Warning map[string][]string
}
func newData() *formData {
return &formData{
Errors: map[string][]error{},
Warning: map[string][]string{},
}
}
func (f *formData) addError(name string, err error) {
f.Errors[name] = append(f.Errors[name], err)
}
func (f *formData) addWarning(name, warning string) {
f.Warning[name] = append(f.Warning[name], warning)
}
func (f *formData) shiftError(name string) (err error) {
if len(f.Errors[name]) > 0 {
if len(f.Errors[name]) <= 1 {
if len(f.Errors[name]) == 1 {
err = f.Errors[name][0]
}
delete(f.Errors, name)
} else {
err, f.Errors[name] = f.Errors[name][0], f.Errors[name][1:]
}
}
return
}
func (f *formData) shiftWarning(name string) (warning string) {
if len(f.Warning[name]) > 0 {
if len(f.Warning[name]) <= 1 {
if len(f.Warning[name]) == 1 {
warning = f.Warning[name][0]
}
delete(f.Warning, name)
} else {
warning, f.Warning[name] = f.Warning[name][0], f.Warning[name][1:]
}
}
return
}
type form struct {
T i18n.Translator
R RenderSecondLayer
Data map[StructPtrForm]*formData
JsonValid bool
JsonData []map[string]interface{}
Value *value
vcount int
rcount int
}
func (f *form) Render(structPtr StructPtrForm, w io.Writer) {
f.render(structPtr, w)
}
func (f *form) RenderStr(structPtr StructPtrForm) string {
w := &bytes.Buffer{}
defer w.Reset()
f.Render(structPtr, w)
return w.String()
}
func (f *form) Validate(r *http.Request, structPtrs ...StructPtrForm) (bool, error) {
if r == nil {
return false, fmt.Errorf("Form: 'r' cannot be 'nil'")
}
if f.Value == nil {
f.Value = newValue(r)
}
valid := true
for _, structPtr := range structPtrs {
b, err := f.validate(structPtr)
if err != nil {
return false, err
}
if !b {
valid = false
}
}
f.JsonValid = valid
return valid, nil
}
func (f *form) MustValidate(r *http.Request, structPtrs ...StructPtrForm) bool {
b, err := f.Validate(r, structPtrs...)
if err != nil {
panic(err)
}
return b
}
func (f *form) ValidateSingle(structPtr StructPtrForm, name string, value []string) (err error) {
err = f.validateSingle(structPtr, name, value)
return
}
func (f *form) Json(w io.Writer) {
v := map[string]interface{}{
"valid": f.JsonValid,
"data": f.JsonData,
}
enc := json.NewEncoder(w)
enc.Encode(v)
}