Commit 2d79a4120f3102793bf2694a02c815b33ee308b5

Authored by Marko Tikvić
1 parent bc3671b260
Exists in master and in 1 other branch v2

Responses contain full URI

1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "crypto/rand" 4 "crypto/rand"
5 "crypto/sha256" 5 "crypto/sha256"
6 "encoding/hex" 6 "encoding/hex"
7 "errors" 7 "errors"
8 "net/http" 8 "net/http"
9 "strings" 9 "strings"
10 "time" 10 "time"
11 11
12 "github.com/dgrijalva/jwt-go" 12 "github.com/dgrijalva/jwt-go"
13 ) 13 )
14 14
15 const OneDay = time.Hour * 24 15 const OneDay = time.Hour * 24
16 const OneWeek = OneDay * 7 16 const OneWeek = OneDay * 7
17 const saltSize = 32 17 const saltSize = 32
18 const appName = "korisnicki-centar" 18 const appName = "korisnicki-centar"
19 const secret = "korisnicki-centar-api" 19 const secret = "korisnicki-centar-api"
20 20
21 type Role struct { 21 type Role struct {
22 Name string `json:"name"` 22 Name string `json:"name"`
23 ID uint32 `json:"id"` 23 ID uint32 `json:"id"`
24 } 24 }
25 25
26 // TokenClaims are JWT token claims. 26 // TokenClaims are JWT token claims.
27 type TokenClaims struct { 27 type TokenClaims struct {
28 Token string `json:"access_token"` 28 Token string `json:"access_token"`
29 TokenType string `json:"token_type"` 29 TokenType string `json:"token_type"`
30 Username string `json:"username"` 30 Username string `json:"username"`
31 Role string `json:"role"` 31 Role string `json:"role"`
32 RoleID uint32 `json:"role_id"` 32 RoleID uint32 `json:"role_id"`
33 ExpiresIn int64 `json:"expires_in"` 33 ExpiresIn int64 `json:"expires_in"`
34 jwt.StandardClaims // extending a struct 34 jwt.StandardClaims // extending a struct
35 } 35 }
36 36
37 // CredentialsStruct is an instace of username/password values. 37 // CredentialsStruct is an instace of username/password values.
38 type CredentialsStruct struct { 38 type CredentialsStruct struct {
39 Username string `json:"username"` 39 Username string `json:"username"`
40 Password string `json:"password"` 40 Password string `json:"password"`
41 } 41 }
42 42
43 // ValidateCredentials hashes pass and salt and returns comparison result with resultHash 43 // ValidateCredentials hashes pass and salt and returns comparison result with resultHash
44 func ValidateCredentials(pass, salt, resultHash string) bool { 44 func ValidateCredentials(pass, salt, resultHash string) bool {
45 hash, _, err := CreateHash(pass, salt) 45 hash, _, err := CreateHash(pass, salt)
46 if err != nil { 46 if err != nil {
47 return false 47 return false
48 } 48 }
49 return hash == resultHash 49 return hash == resultHash
50 } 50 }
51 51
52 // CreateHash hashes str using SHA256. 52 // CreateHash hashes str using SHA256.
53 // If the presalt parameter is not provided CreateHash will generate new salt string. 53 // If the presalt parameter is not provided CreateHash will generate new salt string.
54 // Returns hash and salt strings or an error if it fails. 54 // Returns hash and salt strings or an error if it fails.
55 func CreateHash(str, presalt string) (hash, salt string, err error) { 55 func CreateHash(str, presalt string) (hash, salt string, err error) {
56 // chech if message is presalted 56 // chech if message is presalted
57 if presalt == "" { 57 if presalt == "" {
58 salt, err = randomSalt() 58 salt, err = randomSalt()
59 if err != nil { 59 if err != nil {
60 return "", "", err 60 return "", "", err
61 } 61 }
62 } else { 62 } else {
63 salt = presalt 63 salt = presalt
64 } 64 }
65 65
66 // convert strings to raw byte slices 66 // convert strings to raw byte slices
67 rawstr := []byte(str) 67 rawstr := []byte(str)
68 rawsalt, err := hex.DecodeString(salt) 68 rawsalt, err := hex.DecodeString(salt)
69 if err != nil { 69 if err != nil {
70 return "", "", err 70 return "", "", err
71 } 71 }
72 72
73 rawdata := make([]byte, len(rawstr)+len(rawsalt)) 73 rawdata := make([]byte, len(rawstr)+len(rawsalt))
74 rawdata = append(rawdata, rawstr...) 74 rawdata = append(rawdata, rawstr...)
75 rawdata = append(rawdata, rawsalt...) 75 rawdata = append(rawdata, rawsalt...)
76 76
77 // hash message + salt 77 // hash message + salt
78 hasher := sha256.New() 78 hasher := sha256.New()
79 hasher.Write(rawdata) 79 hasher.Write(rawdata)
80 rawhash := hasher.Sum(nil) 80 rawhash := hasher.Sum(nil)
81 81
82 hash = hex.EncodeToString(rawhash) 82 hash = hex.EncodeToString(rawhash)
83 return hash, salt, nil 83 return hash, salt, nil
84 } 84 }
85 85
86 // CreateAuthToken returns JWT token with encoded username, role, expiration date and issuer claims. 86 // CreateAuthToken returns JWT token with encoded username, role, expiration date and issuer claims.
87 // It returns an error if it fails. 87 // It returns an error if it fails.
88 func CreateAuthToken(username string, role Role) (TokenClaims, error) { 88 func CreateAuthToken(username string, role Role) (TokenClaims, error) {
89 t0 := (time.Now()).Unix() 89 t0 := (time.Now()).Unix()
90 t1 := (time.Now().Add(OneWeek)).Unix() 90 t1 := (time.Now().Add(OneWeek)).Unix()
91 claims := TokenClaims{ 91 claims := TokenClaims{
92 TokenType: "Bearer", 92 TokenType: "Bearer",
93 Username: username, 93 Username: username,
94 Role: role.Name, 94 Role: role.Name,
95 RoleID: role.ID, 95 RoleID: role.ID,
96 ExpiresIn: t1 - t0, 96 ExpiresIn: t1 - t0,
97 } 97 }
98 // initialize jwt.StandardClaims fields (anonymous struct) 98 // initialize jwt.StandardClaims fields (anonymous struct)
99 claims.IssuedAt = t0 99 claims.IssuedAt = t0
100 claims.ExpiresAt = t1 100 claims.ExpiresAt = t1
101 claims.Issuer = appName 101 claims.Issuer = appName
102 102
103 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 103 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
104 token, err := jwtToken.SignedString([]byte(secret)) 104 token, err := jwtToken.SignedString([]byte(secret))
105 if err != nil { 105 if err != nil {
106 return TokenClaims{}, err 106 return TokenClaims{}, err
107 } 107 }
108 claims.Token = token 108 claims.Token = token
109 return claims, nil 109 return claims, nil
110 } 110 }
111 111
112 // RefreshAuthToken prolongs JWT token's expiration date for one week. 112 // RefreshAuthToken prolongs JWT token's expiration date for one week.
113 // It returns new JWT token or an error if it fails. 113 // It returns new JWT token or an error if it fails.
114 func RefreshAuthToken(req *http.Request) (TokenClaims, error) { 114 func RefreshAuthToken(req *http.Request) (TokenClaims, error) {
115 authHead := req.Header.Get("Authorization") 115 authHead := req.Header.Get("Authorization")
116 tokenstr := strings.TrimPrefix(authHead, "Bearer ") 116 tokenstr := strings.TrimPrefix(authHead, "Bearer ")
117 token, err := jwt.ParseWithClaims(tokenstr, &TokenClaims{}, secretFunc) 117 token, err := jwt.ParseWithClaims(tokenstr, &TokenClaims{}, secretFunc)
118 if err != nil { 118 if err != nil {
119 return TokenClaims{}, err 119 return TokenClaims{}, err
120 } 120 }
121 121
122 // type assertion 122 // type assertion
123 claims, ok := token.Claims.(*TokenClaims) 123 claims, ok := token.Claims.(*TokenClaims)
124 if !ok || !token.Valid { 124 if !ok || !token.Valid {
125 return TokenClaims{}, errors.New("token is not valid") 125 return TokenClaims{}, errors.New("token is not valid")
126 } 126 }
127 127
128 // extend token expiration date 128 // extend token expiration date
129 return CreateAuthToken(claims.Username, Role{claims.Role, claims.RoleID}) 129 return CreateAuthToken(claims.Username, Role{claims.Role, claims.RoleID})
130 } 130 }
131 131
132 // RbacCheck returns true if role that made HTTP request is authorized to 132 // RbacCheck returns true if role that made HTTP request is authorized to
133 // access the resource it is targeting. 133 // access the resource it is targeting.
134 // It exctracts user's role from the JWT token located in Authorization header of 134 // It exctracts user's role from the JWT token located in Authorization header of
135 // http.Request and then compares it with the list of supplied roles and returns 135 // http.Request and then compares it with the list of supplied roles and returns
136 // true if there's a match, if "*" is provided or if the authRoles is nil. 136 // true if there's a match, if "*" is provided or if the authRoles is nil.
137 // Otherwise it returns false. 137 // Otherwise it returns false.
138 func RbacCheck(req *http.Request, authRoles []string) (*TokenClaims, error) { 138 func RbacCheck(req *http.Request, authRoles []string) bool {
139 if authRoles == nil {
140 return true
141 }
142
143 // validate token and check expiration date
144 claims, err := GetTokenClaims(req)
145 if err != nil {
146 return false
147 }
148 // check if token has expired
149 if claims.ExpiresAt < (time.Now()).Unix() {
150 return false
151 }
152
153 // check if role extracted from token matches
154 // any of the provided (allowed) ones
155 for _, r := range authRoles {
156 if claims.Role == r || r == "*" {
157 return true
158 }
159 }
160
161 return false
162 }
163
164 // TODO
165 func AuthCheck(req *http.Request, authRoles []string) (*TokenClaims, error) {
139 if authRoles == nil { 166 if authRoles == nil {
140 return &TokenClaims{}, nil 167 return &TokenClaims{}, nil
141 } 168 }
142 169
143 // validate token and check expiration date 170 // validate token and check expiration date
144 claims, err := GetTokenClaims(req) 171 claims, err := GetTokenClaims(req)
145 if err != nil { 172 if err != nil {
146 return &TokenClaims{}, err 173 return &TokenClaims{}, err
147 } 174 }
148 // check if token has expired 175 // check if token has expired
149 if claims.ExpiresAt < (time.Now()).Unix() { 176 if claims.ExpiresAt < (time.Now()).Unix() {
150 return &TokenClaims{}, errors.New("token has expired") 177 return &TokenClaims{}, errors.New("token has expired")
151 } 178 }
152 179
153 // check if role extracted from token matches 180 // check if role extracted from token matches
154 // any of the provided (allowed) ones 181 // any of the provided (allowed) ones
155 for _, r := range authRoles { 182 for _, r := range authRoles {
156 if claims.Role == r || r == "*" { 183 if claims.Role == r || r == "*" {
157 return claims, nil 184 return claims, nil
158 } 185 }
159 } 186 }
160 187
161 return &TokenClaims{}, errors.New("role is not authorized") 188 return claims, errors.New("role is not authorized")
162 } 189 }
163 190
164 // GetTokenClaims extracts JWT claims from Authorization header of the request. 191 // GetTokenClaims extracts JWT claims from Authorization header of the request.
165 // Returns token claims or an error. 192 // Returns token claims or an error.
166 func GetTokenClaims(req *http.Request) (*TokenClaims, error) { 193 func GetTokenClaims(req *http.Request) (*TokenClaims, error) {
167 // check for and strip 'Bearer' prefix 194 // check for and strip 'Bearer' prefix
168 var tokstr string 195 var tokstr string
169 authHead := req.Header.Get("Authorization") 196 authHead := req.Header.Get("Authorization")
170 if ok := strings.HasPrefix(authHead, "Bearer "); ok { 197 if ok := strings.HasPrefix(authHead, "Bearer "); ok {
171 tokstr = strings.TrimPrefix(tokstr, "Bearer ") 198 tokstr = strings.TrimPrefix(authHead, "Bearer ")
172 } else { 199 } else {
173 return &TokenClaims{}, errors.New("authorization header in incomplete") 200 return &TokenClaims{}, errors.New("authorization header in incomplete")
174 } 201 }
175 202
176 token, err := jwt.ParseWithClaims(tokstr, &TokenClaims{}, secretFunc) 203 token, err := jwt.ParseWithClaims(tokstr, &TokenClaims{}, secretFunc)
177 if err != nil { 204 if err != nil {
178 return &TokenClaims{}, err 205 return &TokenClaims{}, err
179 } 206 }
180 207
181 // type assertion 208 // type assertion
182 claims, ok := token.Claims.(*TokenClaims) 209 claims, ok := token.Claims.(*TokenClaims)
183 if !ok || !token.Valid { 210 if !ok || !token.Valid {
184 return &TokenClaims{}, errors.New("token is not valid") 211 return &TokenClaims{}, errors.New("token is not valid")
185 } 212 }
186 213
187 return claims, nil 214 return claims, nil
188 } 215 }
189 216
190 // randomSalt returns a string of random characters of 'saltSize' length. 217 // randomSalt returns a string of random characters of 'saltSize' length.
191 func randomSalt() (s string, err error) { 218 func randomSalt() (s string, err error) {
192 rawsalt := make([]byte, saltSize) 219 rawsalt := make([]byte, saltSize)
193 220
194 _, err = rand.Read(rawsalt) 221 _, err = rand.Read(rawsalt)
195 if err != nil { 222 if err != nil {
196 return "", err 223 return "", err
197 } 224 }
198 225
199 s = hex.EncodeToString(rawsalt) 226 s = hex.EncodeToString(rawsalt)
200 return s, nil 227 return s, nil
201 } 228 }
202 229
203 // secretFunc returns byte slice of API secret keyword. 230 // secretFunc returns byte slice of API secret keyword.
204 func secretFunc(token *jwt.Token) (interface{}, error) { 231 func secretFunc(token *jwt.Token) (interface{}, error) {
205 return []byte(secret), nil 232 return []byte(secret), nil
206 } 233 }
207 234
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "encoding/json" 4 "encoding/json"
5 "net/http" 5 "net/http"
6 ) 6 )
7 7
8 const ( 8 const (
9 templateHttpErr500_EN = "An internal server error has occurred." 9 templateHttpErr500_EN = "An internal server error has occurred."
10 templateHttpErr500_RS = "Došlo je do greške na serveru." 10 templateHttpErr500_RS = "Došlo je do greške na serveru."
11 templateHttpErr400_EN = "Bad request: invalid request body." 11 templateHttpErr400_EN = "Bad request: invalid request body."
12 templateHttpErr400_RS = "Neispravan zahtev." 12 templateHttpErr400_RS = "Neispravan zahtev."
13 templateHttpErr401_EN = "Unauthorized request." 13 templateHttpErr401_EN = "Unauthorized request."
14 templateHttpErr401_RS = "Neautorizovan zahtev." 14 templateHttpErr401_RS = "Neautorizovan zahtev."
15 ) 15 )
16 16
17 type httpError struct { 17 type httpError struct {
18 Error []HttpErrorDesc `json:"error"` 18 Error []HttpErrorDesc `json:"error"`
19 Request string `json:"request"` 19 Request string `json:"request"`
20 } 20 }
21 21
22 type HttpErrorDesc struct { 22 type HttpErrorDesc struct {
23 Lang string `json:"lang"` 23 Lang string `json:"lang"`
24 Desc string `json:"description"` 24 Desc string `json:"description"`
25 } 25 }
26 26
27 // ErrorResponse writes HTTP error to w. 27 // ErrorResponse writes HTTP error to w.
28 func ErrorResponse(w http.ResponseWriter, r *http.Request, code int, desc []HttpErrorDesc) { 28 func ErrorResponse(w http.ResponseWriter, r *http.Request, code int, desc []HttpErrorDesc) {
29 err := httpError{desc, r.Method + " " + r.URL.Path} 29 //err := httpError{desc, r.Method + " " + r.URL.Path}
30 err := httpError{desc, r.Method + " " + r.RequestURI}
30 w.WriteHeader(code) 31 w.WriteHeader(code)
31 json.NewEncoder(w).Encode(err) 32 json.NewEncoder(w).Encode(err)
32 } 33 }
33 34
34 // BadRequestResponse writes HTTP error 400 to w. 35 // BadRequestResponse writes HTTP error 400 to w.
35 func BadRequestResponse(w http.ResponseWriter, req *http.Request) { 36 func BadRequestResponse(w http.ResponseWriter, req *http.Request) {
36 ErrorResponse(w, req, http.StatusBadRequest, []HttpErrorDesc{ 37 ErrorResponse(w, req, http.StatusBadRequest, []HttpErrorDesc{
37 {"en", templateHttpErr400_EN}, 38 {"en", templateHttpErr400_EN},
38 {"rs", templateHttpErr400_RS}, 39 {"rs", templateHttpErr400_RS},
39 }) 40 })
40 } 41 }
41 42
42 // InternalSeverErrorResponse writes HTTP error 500 to w. 43 // InternalSeverErrorResponse writes HTTP error 500 to w.
43 func InternalServerErrorResponse(w http.ResponseWriter, req *http.Request) { 44 func InternalServerErrorResponse(w http.ResponseWriter, req *http.Request) {
44 ErrorResponse(w, req, http.StatusInternalServerError, []HttpErrorDesc{ 45 ErrorResponse(w, req, http.StatusInternalServerError, []HttpErrorDesc{
45 {"en", templateHttpErr500_EN}, 46 {"en", templateHttpErr500_EN},
46 {"rs", templateHttpErr500_RS}, 47 {"rs", templateHttpErr500_RS},
47 }) 48 })
48 } 49 }
49 50
50 // UnauthorizedError writes HTTP error 401 to w. 51 // UnauthorizedError writes HTTP error 401 to w.
51 func UnauthorizedResponse(w http.ResponseWriter, req *http.Request) { 52 func UnauthorizedResponse(w http.ResponseWriter, req *http.Request) {
52 w.Header().Set("WWW-Authenticate", "Bearer") 53 w.Header().Set("WWW-Authenticate", "Bearer")
53 ErrorResponse(w, req, http.StatusUnauthorized, []HttpErrorDesc{ 54 ErrorResponse(w, req, http.StatusUnauthorized, []HttpErrorDesc{
54 {"en", templateHttpErr401_EN}, 55 {"en", templateHttpErr401_EN},
55 {"rs", templateHttpErr401_RS}, 56 {"rs", templateHttpErr401_RS},
56 }) 57 })
57 } 58 }
58 59
59 // NotFoundHandler writes HTTP error 404 to w. 60 // NotFoundHandler writes HTTP error 404 to w.
60 func NotFoundHandler(w http.ResponseWriter, req *http.Request) { 61 func NotFoundHandler(w http.ResponseWriter, req *http.Request) {
61 SetDefaultHeaders(w) 62 SetDefaultHeaders(w)
62 if req.Method == "OPTIONS" { 63 if req.Method == "OPTIONS" {
63 return 64 return
64 } 65 }
65 ErrorResponse(w, req, http.StatusNotFound, []HttpErrorDesc{ 66 ErrorResponse(w, req, http.StatusNotFound, []HttpErrorDesc{
66 {"en", "Not found."}, 67 {"en", "Not found."},
67 {"rs", "Traženi resurs ne postoji."}, 68 {"rs", "Traženi resurs ne postoji."},
68 }) 69 })
69 } 70 }
70 71
71 // SetDefaultHeaders set's default headers for an HTTP response. 72 // SetDefaultHeaders set's default headers for an HTTP response.
72 func SetDefaultHeaders(w http.ResponseWriter) { 73 func SetDefaultHeaders(w http.ResponseWriter) {
73 w.Header().Set("Access-Control-Allow-Origin", "*") 74 w.Header().Set("Access-Control-Allow-Origin", "*")
74 w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS") 75 w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS")
75 w.Header().Set("Access-Control-Allow-Headers", `Accept, Content-Type, 76 w.Header().Set("Access-Control-Allow-Headers", `Accept, Content-Type,
76 Content-Length, Accept-Encoding, X-CSRF-Token, Authorization`) 77 Content-Length, Accept-Encoding, X-CSRF-Token, Authorization`)
77 w.Header().Set("Content-Type", "application/json; charset=utf-8") 78 w.Header().Set("Content-Type", "application/json; charset=utf-8")
78 } 79 }
79 80
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "encoding/json" 4 "encoding/json"
5 "errors" 5 "errors"
6 "io" 6 "io"
7 "net/http" 7 "net/http"
8 "sync" 8 "sync"
9 9
10 "gopkg.in/rana/ora.v4" 10 "gopkg.in/rana/ora.v4"
11 ) 11 )
12 12
13 var mu = &sync.Mutex{} 13 var mu = &sync.Mutex{}
14 var payloads []payloadBuff 14 var payloads []payloadBuff
15 15
16 type LangMap map[string]map[string]string 16 type LangMap map[string]map[string]string
17 17
18 type Field struct { 18 type Field struct {
19 Parameter string `json:"param"` 19 Parameter string `json:"param"`
20 Type string `json:"type"` 20 Type string `json:"type"`
21 Visible bool `json:"visible"` 21 Visible bool `json:"visible"`
22 Editable bool `json:"editable"` 22 Editable bool `json:"editable"`
23 } 23 }
24 24
25 type CorrelationField struct { 25 type CorrelationField struct {
26 Result string `json:"result"` 26 Result string `json:"result"`
27 Elements []string `json:"elements"` 27 Elements []string `json:"elements"`
28 Type string `json:"type"` 28 Type string `json:"type"`
29 } 29 }
30 30
31 type Translation struct { 31 type Translation struct {
32 Language string `json:"language"` 32 Language string `json:"language"`
33 FieldsLabels map[string]string `json:"fieldsLabels"` 33 FieldsLabels map[string]string `json:"fieldsLabels"`
34 } 34 }
35 35
36 type payloadBuff struct { 36 type payloadBuff struct {
37 Type string `json:"tableType"` 37 Type string `json:"tableType"`
38 Method string `json:"method"` 38 Method string `json:"method"`
39 Params map[string]string `json:"params"` 39 Params map[string]string `json:"params"`
40 Lang []Translation `json:"lang"` 40 Lang []Translation `json:"lang"`
41 Fields []Field `json:"fields"` 41 Fields []Field `json:"fields"`
42 Correlations []CorrelationField `json:"correlationFields"` 42 Correlations []CorrelationField `json:"correlationFields"`
43 IdField string `json:"idField"` 43 IdField string `json:"idField"`
44 44
45 // Data can only hold slices of any type. It can't be used for itteration 45 // Data can only hold slices of any type. It can't be used for itteration
46 Data interface{} `json:"data"` 46 Data interface{} `json:"data"`
47 } 47 }
48 48
49 type Payload struct { 49 type Payload struct {
50 Method string `json:"method"` 50 Method string `json:"method"`
51 Params map[string]string `json:"params"` 51 Params map[string]string `json:"params"`
52 Lang []Translation `json:"lang"` 52 Lang []Translation `json:"lang"`
53 Fields []Field `json:"fields"` 53 Fields []Field `json:"fields"`
54 Correlations []CorrelationField `json:"correlationFields"` 54 Correlations []CorrelationField `json:"correlationFields"`
55 IdField string `json:"idField"` 55 IdField string `json:"idField"`
56 56
57 // Data contains JSON payload. 57 // Data contains JSON payload.
58 // It can't be used for itteration 58 // It can't be used for itteration
59 Data interface{} `json:"data"` 59 Data interface{} `json:"data"`
60 } 60 }
61 61
62 // InitTables loads all payloads in the payloads variable. 62 // InitTables loads all payloads in the payloads variable.
63 // Returns an error if it fails. 63 // Returns an error if it fails.
64 func InitTables(db *ora.Ses, project string) error { 64 func InitTables(db *ora.Ses, project string) error {
65 jsonbuf, err := fetchJSON(db, project) 65 jsonbuf, err := fetchJSON(db, project)
66 if err != nil { 66 if err != nil {
67 return err 67 return err
68 } 68 }
69 69
70 mu.Lock() 70 mu.Lock()
71 defer mu.Unlock() 71 defer mu.Unlock()
72 json.Unmarshal(jsonbuf, &payloads) 72 json.Unmarshal(jsonbuf, &payloads)
73 if len(payloads) == 0 { 73 if len(payloads) == 0 {
74 return errors.New("tables config is corrupt") 74 return errors.New("tables config is corrupt")
75 } 75 }
76 return nil 76 return nil
77 } 77 }
78 78
79 // DecodeJSON decodes JSON data from r to v. 79 // DecodeJSON decodes JSON data from r to v.
80 // Returns an error if it fails. 80 // Returns an error if it fails.
81 func DecodeJSON(r io.Reader, v interface{}) error { 81 func DecodeJSON(r io.Reader, v interface{}) error {
82 return json.NewDecoder(r).Decode(v) 82 return json.NewDecoder(r).Decode(v)
83 } 83 }
84 84
85 // NewPayload returs a payload sceleton for provided table. 85 // NewPayload returs a payload sceleton for provided table.
86 func NewPayload(r *http.Request, table string) Payload { 86 func NewPayload(r *http.Request, table string) Payload {
87 var pload Payload 87 var pload Payload
88 88
89 pload.Method = r.Method + " " + r.URL.Path 89 //pload.Method = r.Method + " " + r.URL.Path
90 pload.Method = r.Method + " " + r.RequestURI
90 if table != "" { 91 if table != "" {
91 pload.Params = make(map[string]string, 0) 92 pload.Params = make(map[string]string, 0)
92 pload.Lang = translations(table) 93 pload.Lang = translations(table)
93 pload.Fields = fields(table) 94 pload.Fields = fields(table)
94 pload.IdField = id(table) 95 pload.IdField = id(table)
95 pload.Correlations = correlations(table) 96 pload.Correlations = correlations(table)
96 } 97 }
97 return pload 98 return pload
98 } 99 }
99 100
100 // DeliverPayload encodes payload to w. 101 // DeliverPayload encodes payload to w.
101 func DeliverPayload(w http.ResponseWriter, payload Payload) { 102 func DeliverPayload(w http.ResponseWriter, payload Payload) {
102 json.NewEncoder(w).Encode(payload) 103 json.NewEncoder(w).Encode(payload)
103 payload.Data = nil 104 payload.Data = nil
104 } 105 }
105 106
106 // translations returns a slice of translations for a payload/table of ptype type. 107 // translations returns a slice of translations for a payload/table of ptype type.
107 func translations(ptype string) []Translation { 108 func translations(ptype string) []Translation {
108 var translations []Translation 109 var translations []Translation
109 110
110 for _, pload := range payloads { 111 for _, pload := range payloads {
111 if pload.Type == ptype { 112 if pload.Type == ptype {
112 for _, t := range pload.Lang { 113 for _, t := range pload.Lang {
113 translations = append(translations, Translation{ 114 translations = append(translations, Translation{
114 Language: t.Language, 115 Language: t.Language,
115 FieldsLabels: t.FieldsLabels, 116 FieldsLabels: t.FieldsLabels,
116 }) 117 })
117 } 118 }
118 } 119 }
119 } 120 }
120 121
121 return translations 122 return translations
122 } 123 }
123 124
124 // fields returns a slice of fields for a payload/table of ptype type. 125 // fields returns a slice of fields for a payload/table of ptype type.
125 func fields(ptype string) []Field { 126 func fields(ptype string) []Field {
126 var fields []Field 127 var fields []Field
127 128
128 for _, pload := range payloads { 129 for _, pload := range payloads {
129 if pload.Type == ptype { 130 if pload.Type == ptype {
130 for _, f := range pload.Fields { 131 for _, f := range pload.Fields {
131 fields = append(fields, f) 132 fields = append(fields, f)
132 } 133 }
133 } 134 }
134 } 135 }
135 136
136 return fields 137 return fields
137 } 138 }
138 139
139 // id returns the name of ID field of a payload/table of ptype type. 140 // id returns the name of ID field of a payload/table of ptype type.
140 func id(ptype string) string { 141 func id(ptype string) string {
141 for _, pload := range payloads { 142 for _, pload := range payloads {
142 if pload.Type == ptype { 143 if pload.Type == ptype {
143 return pload.IdField 144 return pload.IdField
144 } 145 }
145 } 146 }
146 return "" 147 return ""
147 } 148 }
148 149
149 // correlations returns a slice of correlation fields for a payload/table of ptype type. 150 // correlations returns a slice of correlation fields for a payload/table of ptype type.
150 func correlations(ptype string) []CorrelationField { 151 func correlations(ptype string) []CorrelationField {
151 var corr []CorrelationField 152 var corr []CorrelationField
152 153
153 for _, pload := range payloads { 154 for _, pload := range payloads {
154 if pload.Type == ptype { 155 if pload.Type == ptype {
155 for _, c := range pload.Correlations { 156 for _, c := range pload.Correlations {
156 corr = append(corr, c) 157 corr = append(corr, c)
157 } 158 }
158 } 159 }
159 } 160 }
160 161
161 return corr 162 return corr
162 } 163 }
163 164
164 // fetchJSON returns a byte slice of JSON configuration file from TABLES_CONFIG table. 165 // fetchJSON returns a byte slice of JSON configuration file from TABLES_CONFIG table.
165 // Returns an error if it fails. 166 // Returns an error if it fails.
166 func fetchJSON(db *ora.Ses, project string) ([]byte, error) { 167 func fetchJSON(db *ora.Ses, project string) ([]byte, error) {
167 db.SetCfg(db.Cfg().SetClob(ora.S)) 168 db.SetCfg(db.Cfg().SetClob(ora.S))
168 stmt, err := db.Prep(`SELECT JSON_NCLOB FROM TABLES_CONFIG WHERE PROJEKAT`+EqualQuotes(project), ora.S) 169 stmt, err := db.Prep(`SELECT JSON_NCLOB FROM TABLES_CONFIG WHERE PROJEKAT`+EqualQuotes(project), ora.S)
169 defer stmt.Close() 170 defer stmt.Close()
170 if err != nil { 171 if err != nil {
171 return nil, err 172 return nil, err
172 } 173 }
173 174
174 rset, err := stmt.Qry() 175 rset, err := stmt.Qry()
175 if err != nil { 176 if err != nil {
176 return nil, err 177 return nil, err
177 } 178 }
178 179
179 var data string 180 var data string
180 if rset.Next() { 181 if rset.Next() {
181 data = rset.Row[0].(string) 182 data = rset.Row[0].(string)
182 } 183 }
183 184
184 //fmt.Println(data) 185 //fmt.Println(data)
185 return []byte(data), nil 186 return []byte(data), nil
186 } 187 }
187 188