Commit 90fd36e9b6905db92e6323daa89e0474e8d060c7
1 parent
514fa9dd68
Exists in
master
and in
1 other branch
resolved some dependency issues
Showing
5 changed files
with
170 additions
and
49 deletions
Show diff stats
auth_utility.go
File was created | 1 | package restutility | |
2 | |||
3 | import ( | ||
4 | // "fmt" | ||
5 | "errors" | ||
6 | // "os" | ||
7 | "time" | ||
8 | "crypto/sha256" | ||
9 | "crypto/rand" | ||
10 | "encoding/hex" | ||
11 | "strings" | ||
12 | "github.com/dgrijalva/jwt-go" | ||
13 | // "github.com/SermoDigital/jose/jwt" | ||
14 | ) | ||
15 | |||
16 | const OneDay = time.Hour*24 | ||
17 | const OneWeek = OneDay*7 | ||
18 | const saltSize = 32 | ||
19 | const appName = "korisnicki-centar" | ||
20 | const secret = "korisnicki-centar-api" | ||
21 | |||
22 | type Token struct { | ||
23 | TokenString string `json:"token"` | ||
24 | } | ||
25 | |||
26 | type TokenClaims struct { | ||
27 | Username string `json:"username"` | ||
28 | Role string `json:"role"` | ||
29 | jwt.StandardClaims | ||
30 | } | ||
31 | |||
32 | type CredentialsStruct struct { | ||
33 | Username string `json:"username"` | ||
34 | Password string `json:"password"` | ||
35 | } | ||
36 | |||
37 | func generateSalt() (string, error) { | ||
38 | salt := "" | ||
39 | |||
40 | rawsalt := make([]byte, saltSize) | ||
41 | _, err := rand.Read(rawsalt) | ||
42 | if err != nil { | ||
43 | return "", err | ||
44 | } | ||
45 | salt = hex.EncodeToString(rawsalt) | ||
46 | return salt, nil | ||
47 | } | ||
48 | |||
49 | func hashMessage(message string, presalt string) (string, string, error) { | ||
50 | hash, salt := "", "" | ||
51 | var err error | ||
52 | |||
53 | // chech if message is presalted | ||
54 | if presalt == "" { | ||
55 | salt, err = generateSalt() | ||
56 | if err != nil { | ||
57 | return "", "", err | ||
58 | } | ||
59 | } else { | ||
60 | salt = presalt | ||
61 | } | ||
62 | |||
63 | // convert strings to raw byte slices | ||
64 | rawmessage := []byte(message) | ||
65 | rawsalt, err := hex.DecodeString(salt) | ||
66 | if err != nil { | ||
67 | return "", "", err | ||
68 | } | ||
69 | rawdata := make([]byte, len(rawmessage) + len(rawsalt)) | ||
70 | rawdata = append(rawdata, rawmessage...) | ||
71 | rawdata = append(rawdata, rawsalt...) | ||
72 | |||
73 | // hash message + salt | ||
74 | hasher := sha256.New() | ||
75 | hasher.Write(rawdata) | ||
76 | rawhash := hasher.Sum(nil) | ||
77 | hash = hex.EncodeToString(rawhash) | ||
78 | return hash, salt, nil | ||
79 | } | ||
80 | |||
81 | func issueAPIToken(username, role string) (Token, error) { | ||
82 | var apiToken Token | ||
83 | var err error | ||
84 | |||
85 | if err != nil { | ||
86 | return Token{}, err | ||
87 | } | ||
88 | |||
89 | claims := TokenClaims{ | ||
90 | username, | ||
91 | role, | ||
92 | jwt.StandardClaims{ | ||
93 | ExpiresAt: (time.Now().Add(OneWeek)).Unix(), | ||
94 | Issuer: appName, | ||
95 | }, | ||
96 | } | ||
97 | |||
98 | jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) | ||
99 | apiToken.TokenString, err = jwtToken.SignedString([]byte(secret)) | ||
100 | if err != nil { | ||
101 | return Token{}, err | ||
102 | } | ||
103 | return apiToken, nil | ||
104 | } | ||
105 | |||
106 | func refreshAPIToken(tokenString string) (Token, error) { | ||
107 | var newToken Token | ||
108 | tokenString = strings.TrimPrefix(tokenString, "Bearer ") | ||
109 | token, err := parseTokenFunc(tokenString) | ||
110 | if err != nil { | ||
111 | return Token{}, err | ||
112 | } | ||
113 | |||
114 | // type assertion | ||
115 | claims, ok := token.Claims.(*TokenClaims) | ||
116 | if !ok || !token.Valid { | ||
117 | return Token{}, errors.New("token is not valid") | ||
118 | } | ||
119 | |||
120 | claims.ExpiresAt = (time.Now().Add(OneWeek)).Unix() | ||
121 | jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) | ||
122 | |||
123 | newToken.TokenString, err = jwtToken.SignedString([]byte(secret)) | ||
124 | if err != nil { | ||
125 | return Token{}, err | ||
126 | } | ||
127 | |||
128 | return newToken, nil | ||
129 | } | ||
130 | |||
131 | func parseAPIToken(tokenString string) (*TokenClaims, error) { | ||
132 | if ok := strings.HasPrefix(tokenString, "Bearer"); ok { | ||
133 | tokenString = strings.TrimPrefix(tokenString, "Bearer ") | ||
134 | } else { | ||
135 | return &TokenClaims{}, errors.New("Authorization header is incomplete") | ||
136 | } | ||
137 | |||
138 | token, err := parseTokenFunc(tokenString) | ||
139 | if err != nil { | ||
140 | return &TokenClaims{}, err | ||
141 | } | ||
142 | |||
143 | // type assertion | ||
144 | claims, ok := token.Claims.(*TokenClaims) | ||
145 | if !ok || !token.Valid { | ||
146 | return &TokenClaims{}, errors.New("token is not valid") | ||
147 | } | ||
148 | return claims, nil | ||
149 | } | ||
150 | |||
151 | func parseTokenFunc(tokenString string) (*jwt.Token, error) { | ||
152 | token, err := jwt.ParseWithClaims(tokenString, | ||
153 | &TokenClaims{}, | ||
154 | func(token *jwt.Token) (interface{}, error) { | ||
155 | return []byte(secret), nil | ||
156 | }, | ||
157 | ) | ||
158 | return token, err | ||
159 | } | ||
160 | |||
161 | func authMinRegReq(uname, pword string) (bool, error) { | ||
162 | return true, nil | ||
163 | } | ||
164 | |||
165 |
format_utility.go
1 | package main | 1 | package restutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "strings" | 4 | "strings" |
5 | "time" | 5 | "time" |
6 | "strconv" | 6 | "strconv" |
7 | ) | 7 | ) |
8 | 8 | ||
9 | //// | 9 | //// |
10 | //// TIME FORMAT UTILITY | 10 | //// TIME FORMAT UTILITY |
11 | //// | 11 | //// |
12 | 12 | ||
13 | func unixToDate(input int64) time.Time { | 13 | func unixToDate(input int64) time.Time { |
14 | return time.Unix(input, 0) | 14 | return time.Unix(input, 0) |
15 | } | 15 | } |
16 | 16 | ||
17 | func dateToUnix(input interface{}) int64 { | 17 | func dateToUnix(input interface{}) int64 { |
18 | if input != nil { | 18 | if input != nil { |
19 | t := input.(time.Time) | 19 | t := input.(time.Time) |
20 | return t.Unix() | 20 | return t.Unix() |
21 | 21 | ||
22 | } | 22 | } |
23 | return 0 | 23 | return 0 |
24 | } | 24 | } |
25 | 25 | ||
26 | func aersDate(unixString string) (string, error) { | 26 | func aersDate(unixString string) (string, error) { |
27 | unixTime, err := strconv.ParseInt(unixString, 10, 64) | 27 | unixTime, err := strconv.ParseInt(unixString, 10, 64) |
28 | if err != nil { | 28 | if err != nil { |
29 | return "", err | 29 | return "", err |
30 | } | 30 | } |
31 | 31 | ||
32 | date := unixToDate(unixTime).String() | 32 | date := unixToDate(unixTime).String() |
33 | tokens := strings.Split(date, "-") | 33 | tokens := strings.Split(date, "-") |
34 | dateString := tokens[0] + tokens[1] + strings.Split(tokens[2], " ")[0] | 34 | dateString := tokens[0] + tokens[1] + strings.Split(tokens[2], " ")[0] |
35 | 35 | ||
36 | return dateString, nil | 36 | return dateString, nil |
37 | } | 37 | } |
38 | 38 | ||
39 | //// | 39 | //// |
40 | //// STRING UTILITY | 40 | //// STRING UTILITY |
41 | //// | 41 | //// |
42 | 42 | ||
43 | // surrondWithSingleQuotes is used when url param is of type string | 43 | // surrondWithSingleQuotes is used when url param is of type string |
44 | func putQuotes(input string) string { | 44 | func putQuotes(input string) string { |
45 | if input != "" { | 45 | if input != "" { |
46 | return " = '" + input + "'" | 46 | return " = '" + input + "'" |
47 | } | 47 | } |
48 | return "" | 48 | return "" |
49 | } | 49 | } |
50 | 50 | ||
51 | func putLikeQuotes(input string) string { | 51 | func putLikeQuotes(input string) string { |
52 | if input != "" { | 52 | if input != "" { |
53 | return " LIKE UPPER('%" + input + "%')" | 53 | return " LIKE UPPER('%" + input + "%')" |
54 | } | 54 | } |
55 | return "" | 55 | return "" |
56 | } | 56 | } |
57 | 57 | ||
58 | 58 |
http_utility.go
1 | package restutility | 1 | package restutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "net/http" | 4 | "net/http" |
5 | "encoding/json" | 5 | "encoding/json" |
6 | ) | 6 | ) |
7 | 7 | ||
8 | const APIVersion = "/api/v1" | ||
9 | |||
8 | //// | 10 | //// |
9 | //// ERROR UTILITY | 11 | //// ERROR UTILITY |
10 | //// | 12 | //// |
11 | 13 | ||
12 | const templateHttpErr500_EN = "An internal server error has occurred." | 14 | const templateHttpErr500_EN = "An internal server error has occurred." |
13 | const templateHttpErr500_RS = "Došlo je do greške na serveru." | 15 | const templateHttpErr500_RS = "Došlo je do greške na serveru." |
14 | const templateHttpErr400_EN = "Bad request: invalid request body." | 16 | const templateHttpErr400_EN = "Bad request: invalid request body." |
15 | const templateHttpErr400_RS = "Neispravan zahtev." | 17 | const templateHttpErr400_RS = "Neispravan zahtev." |
16 | 18 | ||
17 | type HttpError struct { | 19 | type HttpError struct { |
18 | Error []HttpErrorDesc `json:"error"` | 20 | Error []HttpErrorDesc `json:"error"` |
19 | Request string `json:"request"` | 21 | Request string `json:"request"` |
20 | } | 22 | } |
21 | 23 | ||
22 | type HttpErrorDesc struct { | 24 | type HttpErrorDesc struct { |
23 | Lang string `json:"lang"` | 25 | Lang string `json:"lang"` |
24 | Desc string `json:"description"` | 26 | Desc string `json:"description"` |
25 | } | 27 | } |
26 | 28 | ||
27 | func respondWithHttpError(w http.ResponseWriter, | 29 | func respondWithHttpError(w http.ResponseWriter, |
28 | req *http.Request, | 30 | req *http.Request, |
29 | code int, | 31 | code int, |
30 | httpErr []HttpErrorDesc) { | 32 | httpErr []HttpErrorDesc) { |
31 | 33 | ||
32 | err := HttpError{ | 34 | err := HttpError{ |
33 | Error: httpErr, | 35 | Error: httpErr, |
34 | Request: req.Method + " " + req.URL.Path, | 36 | Request: req.Method + " " + req.URL.Path, |
35 | } | 37 | } |
36 | w.WriteHeader(code) | 38 | w.WriteHeader(code) |
37 | json.NewEncoder(w).Encode(err) | 39 | json.NewEncoder(w).Encode(err) |
38 | } | 40 | } |
39 | 41 | ||
40 | func respondWithHttpError400(w http.ResponseWriter, req *http.Request) { | 42 | func respondWithHttpError400(w http.ResponseWriter, req *http.Request) { |
41 | respondWithHttpError(w, req, http.StatusBadRequest, | 43 | respondWithHttpError(w, req, http.StatusBadRequest, |
42 | []HttpErrorDesc{ | 44 | []HttpErrorDesc{ |
43 | { | 45 | { |
44 | Lang: "en", | 46 | Lang: "en", |
45 | Desc: templateHttpErr400_EN, | 47 | Desc: templateHttpErr400_EN, |
46 | }, | 48 | }, |
47 | { | 49 | { |
48 | Lang: "rs", | 50 | Lang: "rs", |
49 | Desc: templateHttpErr400_RS, | 51 | Desc: templateHttpErr400_RS, |
50 | }, | 52 | }, |
51 | }) | 53 | }) |
52 | } | 54 | } |
53 | 55 | ||
54 | func respondWithHttpError500(w http.ResponseWriter, req *http.Request) { | 56 | func respondWithHttpError500(w http.ResponseWriter, req *http.Request) { |
55 | respondWithHttpError(w, req, http.StatusInternalServerError, | 57 | respondWithHttpError(w, req, http.StatusInternalServerError, |
56 | []HttpErrorDesc{ | 58 | []HttpErrorDesc{ |
57 | { | 59 | { |
58 | Lang: "en", | 60 | Lang: "en", |
59 | Desc: templateHttpErr500_EN, | 61 | Desc: templateHttpErr500_EN, |
60 | }, | 62 | }, |
61 | { | 63 | { |
62 | Lang: "rs", | 64 | Lang: "rs", |
63 | Desc: templateHttpErr500_RS, | 65 | Desc: templateHttpErr500_RS, |
64 | }, | 66 | }, |
65 | }) | 67 | }) |
66 | } | 68 | } |
67 | 69 | ||
68 | func deliverPayload(w http.ResponseWriter, payload JSONPayload) { | 70 | func deliverPayload(w http.ResponseWriter, payload JSONPayload) { |
69 | json.NewEncoder(w).Encode(payload) | 71 | json.NewEncoder(w).Encode(payload) |
70 | payload.Data = nil | 72 | payload.Data = nil |
71 | } | 73 | } |
72 | 74 | ||
73 | //// | 75 | //// |
74 | //// HANDLER FUNC WRAPPER | 76 | //// HANDLER FUNC WRAPPER |
75 | //// | 77 | //// |
76 | 78 | ||
77 | // wrapHandlerFunc is as wrapper function for route handlers. | 79 | // wrapHandlerFunc is as wrapper function for route handlers. |
78 | // Sets common headers and checks for token validity. | 80 | // Sets common headers and checks for token validity. |
79 | func commonHttpWrap(fn http.HandlerFunc) http.HandlerFunc { | 81 | func commonHttpWrap(fn http.HandlerFunc) http.HandlerFunc { |
80 | return func(w http.ResponseWriter, req *http.Request) { | 82 | return func(w http.ResponseWriter, req *http.Request) { |
81 | // @TODO: check Content-type header (must be application/json) | 83 | // @TODO: check Content-type header (must be application/json) |
82 | // ctype := w.Header.Get("Content-Type") | 84 | // ctype := w.Header.Get("Content-Type") |
83 | // if req.Method != "GET" && ctype != "application/json" { | 85 | // if req.Method != "GET" && ctype != "application/json" { |
84 | // replyWithHttpError(w, req, http.StatusBadRequest, | 86 | // replyWithHttpError(w, req, http.StatusBadRequest, |
85 | // "Not a supported content type: " + ctype) | 87 | // "Not a supported content type: " + ctype) |
86 | // } | 88 | // } |
87 | 89 | ||
88 | w.Header().Set("Access-Control-Allow-Origin", "*") | 90 | w.Header().Set("Access-Control-Allow-Origin", "*") |
89 | w.Header().Set("Access-Control-Allow-Methods", | 91 | w.Header().Set("Access-Control-Allow-Methods", |
90 | `POST, | 92 | `POST, |
91 | GET, | 93 | GET, |
92 | PUT, | 94 | PUT, |
93 | DELETE, | 95 | DELETE, |
94 | OPTIONS`) | 96 | OPTIONS`) |
95 | w.Header().Set("Access-Control-Allow-Headers", | 97 | w.Header().Set("Access-Control-Allow-Headers", |
96 | `Accept, | 98 | `Accept, |
97 | Content-Type, | 99 | Content-Type, |
98 | Content-Length, | 100 | Content-Length, |
99 | Accept-Encoding, | 101 | Accept-Encoding, |
100 | X-CSRF-Token, | 102 | X-CSRF-Token, |
101 | Authorization`) | 103 | Authorization`) |
102 | w.Header().Set("Content-Type", "application/json; charset=utf-8") | 104 | w.Header().Set("Content-Type", "application/json; charset=utf-8") |
103 | 105 | ||
104 | if req.Method == "OPTIONS" { | 106 | if req.Method == "OPTIONS" { |
105 | return | 107 | return |
106 | } | 108 | } |
107 | 109 | ||
108 | if req.URL.Path != APIVersion + "/token/new" { | 110 | if req.URL.Path != APIVersion + "/token/new" { |
109 | token := req.Header.Get("Authorization") | 111 | token := req.Header.Get("Authorization") |
110 | if _, err := parseAPIToken(token); err != nil { | 112 | if _, err := parseAPIToken(token); err != nil { |
111 | respondWithHttpError(w, req, http.StatusUnauthorized, | 113 | respondWithHttpError(w, req, http.StatusUnauthorized, |
112 | []HttpErrorDesc{ | 114 | []HttpErrorDesc{ |
113 | { | 115 | { |
114 | Lang: "en", | 116 | Lang: "en", |
115 | Desc: "Unauthorized request.", | 117 | Desc: "Unauthorized request.", |
116 | }, | 118 | }, |
117 | { | 119 | { |
118 | Lang: "rs", | 120 | Lang: "rs", |
119 | Desc: "Neautorizovani zahtev.", | 121 | Desc: "Neautorizovani zahtev.", |
120 | }, | 122 | }, |
121 | }) | 123 | }) |
122 | return | 124 | return |
123 | } | 125 | } |
124 | } | 126 | } |
125 | 127 | ||
126 | err := req.ParseForm() | 128 | err := req.ParseForm() |
127 | if err != nil { | 129 | if err != nil { |
128 | respondWithHttpError(w, req, http.StatusBadRequest, | 130 | respondWithHttpError(w, req, http.StatusBadRequest, |
129 | []HttpErrorDesc{ | 131 | []HttpErrorDesc{ |
130 | { | 132 | { |
131 | Lang: "en", | 133 | Lang: "en", |
132 | Desc: templateHttpErr400_EN, | 134 | Desc: templateHttpErr400_EN, |
133 | }, | 135 | }, |
134 | { | 136 | { |
135 | Lang: "rs", | 137 | Lang: "rs", |
136 | Desc: templateHttpErr400_RS, | 138 | Desc: templateHttpErr400_RS, |
137 | }, | 139 | }, |
138 | }) | 140 | }) |
139 | return | 141 | return |
140 | } | 142 | } |
141 | fn(w, req) | 143 | fn(w, req) |
142 | } | 144 | } |
143 | } | 145 | } |
144 | 146 | ||
145 | //// | 147 | //// |
146 | //// NOT FOUND HANDLER | 148 | //// NOT FOUND HANDLER |
147 | //// | 149 | //// |
148 | 150 | ||
149 | func notFoundHandler(w http.ResponseWriter, req *http.Request) { | 151 | func notFoundHandler(w http.ResponseWriter, req *http.Request) { |
150 | respondWithHttpError(w, req, http.StatusNotFound, | 152 | respondWithHttpError(w, req, http.StatusNotFound, |
151 | []HttpErrorDesc{ | 153 | []HttpErrorDesc{ |
152 | { | 154 | { |
153 | Lang: "en", | 155 | Lang: "en", |
154 | Desc: "Not found.", | 156 | Desc: "Not found.", |
155 | }, | 157 | }, |
156 | { | 158 | { |
157 | Lang: "rs", | 159 | Lang: "rs", |
158 | Desc: "Traženi resurs ne postoji.", | 160 | Desc: "Traženi resurs ne postoji.", |
159 | }, | 161 | }, |
160 | }) | 162 | }) |
161 | } | 163 | } |
162 | 164 |
json_utility.go
1 | package restutility | 1 | package restutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "net/http" | 4 | "net/http" |
5 | "strings" | 5 | "strings" |
6 | ) | 6 | ) |
7 | 7 | ||
8 | const APIVersion "/api/v1" | ||
9 | |||
10 | type LangMap map[string]map[string]string | 8 | type LangMap map[string]map[string]string |
11 | 9 | ||
12 | type Field struct { | 10 | type Field struct { |
13 | Parameter string `json:"param"` | 11 | Parameter string `json:"param"` |
14 | Type string `json:"type"` | 12 | Type string `json:"type"` |
15 | Visible bool `json:"visible"` | 13 | Visible bool `json:"visible"` |
16 | Editable bool `json:"editable"` | 14 | Editable bool `json:"editable"` |
17 | } | 15 | } |
18 | 16 | ||
19 | type JSONParams struct { | 17 | type JSONParams struct { |
20 | Lang LangMap | 18 | Lang LangMap |
21 | Fields []Field | 19 | Fields []Field |
22 | IdField string | 20 | IdField string |
23 | Correlations []CorrelationField `json:"correlation_fields"` | 21 | Correlations []CorrelationField `json:"correlation_fields"` |
24 | } | 22 | } |
25 | 23 | ||
26 | type JSONPayload struct { | 24 | type JSONPayload struct { |
27 | Method string `json:"method"` | 25 | Method string `json:"method"` |
28 | Params map[string]string `json:"params"` | 26 | Params map[string]string `json:"params"` |
29 | Lang LangMap `json:"lang"` | 27 | Lang LangMap `json:"lang"` |
30 | Fields []Field `json:"fields"` | 28 | Fields []Field `json:"fields"` |
31 | Correlations []CorrelationField `json:"correlation_fields"` | 29 | Correlations []CorrelationField `json:"correlation_fields"` |
32 | IdField string `json:"idField"` | 30 | IdField string `json:"idField"` |
33 | // Data can only hold slices of any type. It can't be used for itteration | 31 | // Data can only hold slices of any type. It can't be used for itteration |
34 | Data interface{} `json:"data"` | 32 | Data interface{} `json:"data"` |
35 | } | 33 | } |
36 | 34 | ||
37 | func NewJSONParams(lang LangMap, | 35 | func NewJSONParams(lang LangMap, |
38 | fields []Field, | 36 | fields []Field, |
39 | id string, | 37 | id string, |
40 | correlations []CorrelationField) JSONParams { | 38 | correlations []CorrelationField) JSONParams { |
41 | 39 | ||
42 | var jp JSONParams | 40 | var jp JSONParams |
43 | 41 | ||
44 | jp.Lang = lang | 42 | jp.Lang = lang |
45 | jp.Fields = fields | 43 | jp.Fields = fields |
46 | jp.IdField = id | 44 | jp.IdField = id |
47 | jp.Correlations = correlations | 45 | jp.Correlations = correlations |
48 | 46 | ||
49 | return jp | 47 | return jp |
50 | } | 48 | } |
51 | 49 | ||
52 | func NewJSONPayload(r *http.Request, params JSONParams) JSONPayload { | 50 | func NewJSONPayload(r *http.Request, params JSONParams) JSONPayload { |
53 | var obj JSONPayload | 51 | var obj JSONPayload |
54 | obj.Method = strings.ToLower(r.Method + " " + r.URL.Path) | 52 | obj.Method = strings.ToLower(r.Method + " " + r.URL.Path) |
55 | obj.Params = make(map[string]string, 0) | 53 | obj.Params = make(map[string]string, 0) |
56 | obj.Lang = make(map[string]map[string]string, 0) | 54 | obj.Lang = make(map[string]map[string]string, 0) |
57 | obj.Fields = make([]Field, 0) | 55 | obj.Fields = make([]Field, 0) |
58 | obj.IdField = params.IdField | 56 | obj.IdField = params.IdField |
59 | obj.Correlations = params.Correlations | 57 | obj.Correlations = params.Correlations |
60 | 58 | ||
61 | for k, m := range params.Lang { | 59 | for k, m := range params.Lang { |
62 | obj.Lang[k] = m | 60 | obj.Lang[k] = m |
63 | } | 61 | } |
64 | for _, f := range params.Fields { | 62 | for _, f := range params.Fields { |
65 | obj.Fields = append(obj.Fields, f) | 63 | obj.Fields = append(obj.Fields, f) |
66 | } | 64 | } |
67 | 65 | ||
68 | return obj | 66 | return obj |
69 | } | 67 | } |
70 | 68 | ||
71 | 69 |
tables_utility.go
1 | package restutility | 1 | package restutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/json" | 4 | "encoding/json" |
5 | "io" | ||
6 | "io/ioutil" | ||
7 | "errors" | 5 | "errors" |
8 | "fmt" | ||
9 | "gopkg.in/rana/ora.v3" | ||
10 | ) | 6 | ) |
11 | 7 | ||
12 | type TableConfig struct { | 8 | type TableConfig struct { |
13 | Tables []Table | 9 | Tables []Table |
14 | } | 10 | } |
15 | 11 | ||
16 | type Table struct { | 12 | type Table struct { |
17 | TableType string `json:"tableType"` | 13 | TableType string `json:"tableType"` |
18 | Translations []TableTranslation `json:"translations"` | 14 | Translations []TableTranslation `json:"translations"` |
19 | TableFields []Field `json:"tableFields"` | 15 | TableFields []Field `json:"tableFields"` |
20 | Correlations []CorrelationField `json:"correlation_fields"` | 16 | Correlations []CorrelationField `json:"correlation_fields"` |
21 | IdField string `json:"idField"` | 17 | IdField string `json:"idField"` |
22 | } | 18 | } |
23 | 19 | ||
24 | type CorrelationField struct { | 20 | type CorrelationField struct { |
25 | Result string `json:"result"` | 21 | Result string `json:"result"` |
26 | Elements []string `json:"elements"` | 22 | Elements []string `json:"elements"` |
27 | Type string `json:"type"` | 23 | Type string `json:"type"` |
28 | } | 24 | } |
29 | 25 | ||
30 | type TableTranslation struct { | 26 | type TableTranslation struct { |
31 | Language string `json:"language"` | 27 | Language string `json:"language"` |
32 | FieldsLabels map[string]string `json:"fieldsLabels"` | 28 | FieldsLabels map[string]string `json:"fieldsLabels"` |
33 | } | 29 | } |
34 | 30 | ||
35 | func (tl TableConfig) LoadTranslations(tableType string) LangMap { | 31 | func (tl TableConfig) LoadTranslations(tableType string) LangMap { |
36 | translations := make(LangMap, 0) | 32 | translations := make(LangMap, 0) |
37 | 33 | ||
38 | for _, table := range tl.Tables { | 34 | for _, table := range tl.Tables { |
39 | if tableType == table.TableType { | 35 | if tableType == table.TableType { |
40 | for _, t := range table.Translations { | 36 | for _, t := range table.Translations { |
41 | translations[t.Language] = t.FieldsLabels | 37 | translations[t.Language] = t.FieldsLabels |
42 | } | 38 | } |
43 | } | 39 | } |
44 | } | 40 | } |
45 | 41 | ||
46 | return translations | 42 | return translations |
47 | } | 43 | } |
48 | 44 | ||
49 | func (tl TableConfig) LoadFields(tableType string) []Field { | 45 | func (tl TableConfig) LoadFields(tableType string) []Field { |
50 | fields := make([]Field, 0) | 46 | fields := make([]Field, 0) |
51 | 47 | ||
52 | for _, table := range tl.Tables { | 48 | for _, table := range tl.Tables { |
53 | if tableType == table.TableType { | 49 | if tableType == table.TableType { |
54 | for _, f := range table.TableFields { | 50 | for _, f := range table.TableFields { |
55 | fields = append(fields, f) | 51 | fields = append(fields, f) |
56 | } | 52 | } |
57 | } | 53 | } |
58 | } | 54 | } |
59 | 55 | ||
60 | return fields | 56 | return fields |
61 | } | 57 | } |
62 | 58 | ||
63 | func (tl TableConfig) LoadIdField(tableType string) string { | 59 | func (tl TableConfig) LoadIdField(tableType string) string { |
64 | for _, table := range tl.Tables { | 60 | for _, table := range tl.Tables { |
65 | if tableType == table.TableType { | 61 | if tableType == table.TableType { |
66 | return table.IdField | 62 | return table.IdField |
67 | } | 63 | } |
68 | } | 64 | } |
69 | return "" | 65 | return "" |
70 | } | 66 | } |
71 | 67 | ||
72 | func (tl TableConfig) LoadCorrelations(tableType string) []CorrelationField { | 68 | func (tl TableConfig) LoadCorrelations(tableType string) []CorrelationField { |
73 | resp := make([]CorrelationField, 0) | 69 | resp := make([]CorrelationField, 0) |
74 | 70 | ||
75 | for _, table := range tl.Tables { | 71 | for _, table := range tl.Tables { |
76 | if tableType == table.TableType { | 72 | if tableType == table.TableType { |
77 | for _, f := range table.Correlations { | 73 | for _, f := range table.Correlations { |
78 | resp = append(resp, f) | 74 | resp = append(resp, f) |
79 | } | 75 | } |
80 | } | 76 | } |
81 | } | 77 | } |
82 | 78 | ||
83 | return resp | 79 | return resp |
84 | } | 80 | } |
85 | 81 | ||
86 | var _tables TableConfig | 82 | var _tables TableConfig |
87 | var _prevProject string | 83 | var _prevProject string |
88 | 84 | ||
89 | func getTablesConfigJSON(project string) error { | 85 | func loadTablesConfig(jsonbuf []byte) error { |
90 | _prevProject = project | 86 | json.Unmarshal(jsonbuf, &_tables.Tables) |
91 | stmt, err := Oracle.Ses.Prep(`SELECT | ||
92 | JSON_CLOB | ||
93 | FROM TABLES_CONFIG | ||
94 | WHERE PROJEKAT` + project, ora.S) | ||
95 | defer stmt.Close() | ||
96 | 87 | ||
97 | if err != nil { | 88 | if len(_tables.Tables) == 0 { |
98 | return err | ||
99 | } | ||
100 | |||
101 | rset, err := stmt.Qry() | ||
102 | if err != nil { | ||
103 | return err | ||
104 | } | ||
105 | |||
106 | if rset.Next() { | ||
107 | lob := rset.Row[0].(io.Reader) | ||
108 | bytes, err := ioutil.ReadAll(lob) | ||
109 | if err != nil { | ||
110 | fmt.Printf("mega error: %v\n", err) | ||
111 | } | ||
112 | json.Unmarshal(bytes, &_tables.Tables) | ||
113 | } | ||
114 | |||
115 | return nil | ||
116 | } | ||
117 | |||
118 | func loadTablesConfig(project string) error { | ||
119 | err := getTablesConfigJSON(putQuotes(project)) | ||
120 | //file, err := ioutil.ReadFile("./config/tables-config.json") | ||
121 | if err != nil { | ||
122 | fmt.Printf("%v\n", err); | ||
123 | return errors.New("unable to load tables config") | ||
124 | } | ||
125 | |||
126 | //json.Unmarshal(file, &_TABLES_CONFIG.Tables) | ||
127 | |||
128 | if len(_TABLES_CONFIG.Tables) == 0 { | ||
129 | return errors.New("tables config is corrupt") | 89 | return errors.New("tables config is corrupt") |
130 | } | 90 | } |
131 | 91 | ||
132 | return nil | 92 | return nil |
133 | } | 93 | } |
134 | 94 | ||
135 | func loadTable(table string) JSONParams { | 95 | func loadTable(table string) JSONParams { |
136 | return NewJSONParams(_tables.LoadTranslations(table), | 96 | return NewJSONParams(_tables.LoadTranslations(table), |
137 | _tables.LoadFields(table), | 97 | _tables.LoadFields(table), |
138 | _tables.LoadIdField(table), | 98 | _tables.LoadIdField(table), |
139 | _tables.LoadCorrelations(table)) | 99 | _tables.LoadCorrelations(table)) |
140 | } | 100 | } |
141 | 101 | ||
142 | func refreshTables() error { | ||
143 | return getTablesConfigJSON(_prevProject) | ||
144 | } | ||
145 | 102 |