Commit 8dbe745c3c68225cda3bf800460592e7f6184038
1 parent
39765a4304
Exists in
master
and in
1 other branch
merged tables utility into JSON utility
Showing
3 changed files
with
122 additions
and
171 deletions
Show diff stats
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 | var _apiVersion = "/api/v1" | 8 | var _apiVersion = "/api/v1" |
9 | 9 | ||
10 | func SetApiVersion(ver string) string { | 10 | func SetApiVersion(ver string) string { |
11 | _apiVersion = ver | 11 | _apiVersion = ver |
12 | return _apiVersion | 12 | return _apiVersion |
13 | } | 13 | } |
14 | 14 | ||
15 | //// | 15 | //// |
16 | //// ERROR UTILITY | 16 | //// ERROR UTILITY |
17 | //// | 17 | //// |
18 | 18 | ||
19 | const templateHttpErr500_EN = "An internal server error has occurred." | 19 | const templateHttpErr500_EN = "An internal server error has occurred." |
20 | const templateHttpErr500_RS = "Došlo je do greške na serveru." | 20 | const templateHttpErr500_RS = "Došlo je do greške na serveru." |
21 | const templateHttpErr400_EN = "Bad request: invalid request body." | 21 | const templateHttpErr400_EN = "Bad request: invalid request body." |
22 | const templateHttpErr400_RS = "Neispravan zahtev." | 22 | const templateHttpErr400_RS = "Neispravan zahtev." |
23 | 23 | ||
24 | type HttpError struct { | 24 | type HttpError struct { |
25 | Error []HttpErrorDesc `json:"error"` | 25 | Error []HttpErrorDesc `json:"error"` |
26 | Request string `json:"request"` | 26 | Request string `json:"request"` |
27 | } | 27 | } |
28 | 28 | ||
29 | type HttpErrorDesc struct { | 29 | type HttpErrorDesc struct { |
30 | Lang string `json:"lang"` | 30 | Lang string `json:"lang"` |
31 | Desc string `json:"description"` | 31 | Desc string `json:"description"` |
32 | } | 32 | } |
33 | 33 | ||
34 | func RespondWithHttpError(w http.ResponseWriter, | 34 | func RespondWithHttpError(w http.ResponseWriter, |
35 | req *http.Request, | 35 | req *http.Request, |
36 | code int, | 36 | code int, |
37 | httpErr []HttpErrorDesc) { | 37 | httpErr []HttpErrorDesc) { |
38 | 38 | ||
39 | err := HttpError{ | 39 | err := HttpError{ |
40 | Error: httpErr, | 40 | Error: httpErr, |
41 | Request: req.Method + " " + req.URL.Path, | 41 | Request: req.Method + " " + req.URL.Path, |
42 | } | 42 | } |
43 | w.WriteHeader(code) | 43 | w.WriteHeader(code) |
44 | json.NewEncoder(w).Encode(err) | 44 | json.NewEncoder(w).Encode(err) |
45 | } | 45 | } |
46 | 46 | ||
47 | func RespondWithHttpError400(w http.ResponseWriter, req *http.Request) { | 47 | func RespondWithHttpError400(w http.ResponseWriter, req *http.Request) { |
48 | RespondWithHttpError(w, req, http.StatusBadRequest, []HttpErrorDesc{ | 48 | RespondWithHttpError(w, req, http.StatusBadRequest, []HttpErrorDesc{ |
49 | {Lang: "en", Desc: templateHttpErr400_EN}, | 49 | {Lang: "en", Desc: templateHttpErr400_EN}, |
50 | {Lang: "rs", Desc: templateHttpErr400_RS}, | 50 | {Lang: "rs", Desc: templateHttpErr400_RS}, |
51 | }) | 51 | }) |
52 | } | 52 | } |
53 | 53 | ||
54 | func RespondWithHttpError500(w http.ResponseWriter, req *http.Request) { | 54 | func RespondWithHttpError500(w http.ResponseWriter, req *http.Request) { |
55 | RespondWithHttpError(w, req, http.StatusInternalServerError, []HttpErrorDesc{ | 55 | RespondWithHttpError(w, req, http.StatusInternalServerError, []HttpErrorDesc{ |
56 | {Lang: "en", Desc: templateHttpErr500_EN}, | 56 | {Lang: "en", Desc: templateHttpErr500_EN}, |
57 | {Lang: "rs", Desc: templateHttpErr500_RS}, | 57 | {Lang: "rs", Desc: templateHttpErr500_RS}, |
58 | }) | 58 | }) |
59 | } | 59 | } |
60 | 60 | ||
61 | func DeliverPayload(w http.ResponseWriter, payload JSONPayload) { | ||
62 | json.NewEncoder(w).Encode(payload) | ||
63 | payload.Data = nil | ||
64 | } | ||
65 | |||
66 | //// | 61 | //// |
67 | //// HANDLER FUNC WRAPPER | 62 | //// HANDLER FUNC WRAPPER |
68 | //// | 63 | //// |
69 | 64 | ||
70 | // wrapHandlerFunc is as wrapper function for route handlers. | ||
71 | // Sets common headers and checks for token validity. | 65 | // Sets common headers and checks for token validity. |
72 | func HandleFuncWrap(fn http.HandlerFunc) http.HandlerFunc { | 66 | func ProcessHeaders(fn http.HandlerFunc) http.HandlerFunc { |
73 | return func(w http.ResponseWriter, req *http.Request) { | 67 | return func(w http.ResponseWriter, req *http.Request) { |
74 | // @TODO: check Content-type header (must be application/json) | 68 | // @TODO: check Content-type header (must be application/json) |
75 | // ctype := w.Header.Get("Content-Type") | 69 | // ctype := w.Header.Get("Content-Type") |
76 | // if req.Method != "GET" && ctype != "application/json" { | 70 | // if req.Method != "GET" && ctype != "application/json" { |
77 | // replyWithHttpError(w, req, http.StatusBadRequest, | 71 | // replyWithHttpError(w, req, http.StatusBadRequest, |
78 | // "Not a supported content type: " + ctype) | 72 | // "Not a supported content type: " + ctype) |
79 | // } | 73 | // } |
80 | 74 | ||
81 | w.Header().Set("Access-Control-Allow-Origin", "*") | 75 | w.Header().Set("Access-Control-Allow-Origin", "*") |
82 | w.Header().Set("Access-Control-Allow-Methods", | 76 | w.Header().Set("Access-Control-Allow-Methods", |
83 | `POST, | 77 | `POST, |
84 | GET, | 78 | GET, |
85 | PUT, | 79 | PUT, |
86 | DELETE, | 80 | DELETE, |
87 | OPTIONS`) | 81 | OPTIONS`) |
88 | w.Header().Set("Access-Control-Allow-Headers", | 82 | w.Header().Set("Access-Control-Allow-Headers", |
89 | `Accept, | 83 | `Accept, |
90 | Content-Type, | 84 | Content-Type, |
91 | Content-Length, | 85 | Content-Length, |
92 | Accept-Encoding, | 86 | Accept-Encoding, |
93 | X-CSRF-Token, | 87 | X-CSRF-Token, |
94 | Authorization`) | 88 | Authorization`) |
95 | w.Header().Set("Content-Type", "application/json; charset=utf-8") | 89 | w.Header().Set("Content-Type", "application/json; charset=utf-8") |
96 | 90 | ||
97 | if req.Method == "OPTIONS" { | 91 | if req.Method == "OPTIONS" { |
98 | return | 92 | return |
99 | } | 93 | } |
100 | 94 | ||
101 | if req.URL.Path != _apiVersion + "/token/new" { | 95 | if req.URL.Path != _apiVersion + "/token/new" { |
102 | token := req.Header.Get("Authorization") | 96 | token := req.Header.Get("Authorization") |
103 | if _, err := ParseAPIToken(token); err != nil { | 97 | if _, err := ParseAPIToken(token); err != nil { |
104 | RespondWithHttpError(w, req, http.StatusUnauthorized, | 98 | RespondWithHttpError(w, req, http.StatusUnauthorized, |
105 | []HttpErrorDesc{ | 99 | []HttpErrorDesc{ |
106 | {Lang: "en", Desc: "Unauthorized request."}, | 100 | {Lang: "en", Desc: "Unauthorized request."}, |
107 | {Lang: "rs", Desc: "Neautorizovani zahtev."}, | 101 | {Lang: "rs", Desc: "Neautorizovani zahtev."}, |
108 | }) | 102 | }) |
109 | return | 103 | return |
110 | } | 104 | } |
111 | } | 105 | } |
112 | 106 | ||
113 | err := req.ParseForm() | 107 | err := req.ParseForm() |
114 | if err != nil { | 108 | if err != nil { |
115 | RespondWithHttpError(w, req, http.StatusBadRequest, | 109 | RespondWithHttpError(w, req, http.StatusBadRequest, |
116 | []HttpErrorDesc{ | 110 | []HttpErrorDesc{ |
117 | {Lang: "en", Desc: templateHttpErr400_EN}, | 111 | {Lang: "en", Desc: templateHttpErr400_EN}, |
118 | {Lang: "rs", Desc: templateHttpErr400_RS}, | 112 | {Lang: "rs", Desc: templateHttpErr400_RS}, |
119 | }) | 113 | }) |
120 | return | 114 | return |
121 | } | 115 | } |
122 | fn(w, req) | 116 | fn(w, req) |
123 | } | 117 | } |
124 | } | 118 | } |
125 | 119 | ||
126 | //// | 120 | //// |
127 | //// NOT FOUND HANDLER | 121 | //// NOT FOUND HANDLER |
128 | //// | 122 | //// |
129 | 123 | ||
130 | func NotFoundHandler(w http.ResponseWriter, req *http.Request) { | 124 | func NotFoundHandler(w http.ResponseWriter, req *http.Request) { |
131 | RespondWithHttpError(w, req, http.StatusNotFound, []HttpErrorDesc{ | 125 | RespondWithHttpError(w, req, http.StatusNotFound, []HttpErrorDesc{ |
132 | {Lang: "en", Desc: "Not found."}, | 126 | {Lang: "en", Desc: "Not found."}, |
133 | {Lang: "rs", Desc: "Traženi resurs ne postoji."}, | 127 | {Lang: "rs", Desc: "Traženi resurs ne postoji."}, |
134 | }) | 128 | }) |
135 | } | 129 | } |
136 | 130 |
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 | "encoding/json" | ||
7 | "errors" | ||
8 | "gopkg.in/rana/ora.v3" | ||
9 | "io" | ||
10 | "io/ioutil" | ||
11 | "fmt" | ||
6 | ) | 12 | ) |
7 | 13 | ||
14 | var allPayloads []Payload | ||
15 | |||
8 | type LangMap map[string]map[string]string | 16 | type LangMap map[string]map[string]string |
9 | 17 | ||
10 | type Field struct { | 18 | type Field struct { |
11 | Parameter string `json:"param"` | 19 | Parameter string `json:"param"` |
12 | Type string `json:"type"` | 20 | Type string `json:"type"` |
13 | Visible bool `json:"visible"` | 21 | Visible bool `json:"visible"` |
14 | Editable bool `json:"editable"` | 22 | Editable bool `json:"editable"` |
15 | } | 23 | } |
16 | 24 | ||
17 | type JSONParams struct { | 25 | type CorrelationField struct { |
18 | Lang LangMap | 26 | Result string `json:"result"` |
19 | Fields []Field | 27 | Elements []string `json:"elements"` |
20 | IdField string | 28 | Type string `json:"type"` |
21 | Correlations []CorrelationField `json:"correlation_fields"` | 29 | } |
30 | |||
31 | type Translation struct { | ||
32 | Language string `json:"language"` | ||
33 | FieldsLabels map[string]string `json:"fieldsLabels"` | ||
22 | } | 34 | } |
23 | 35 | ||
24 | type JSONPayload struct { | 36 | type Payload struct { |
37 | Type string `json:"tableType"` | ||
25 | Method string `json:"method"` | 38 | Method string `json:"method"` |
26 | Params map[string]string `json:"params"` | 39 | Params map[string]string `json:"params"` |
27 | Lang LangMap `json:"lang"` | 40 | Lang []Translation `json:"lang"` |
28 | Fields []Field `json:"fields"` | 41 | Fields []Field `json:"fields"` |
29 | Correlations []CorrelationField `json:"correlationFields"` | 42 | Correlations []CorrelationField `json:"correlationFields"` |
30 | IdField string `json:"idField"` | 43 | IdField string `json:"idField"` |
31 | // Data can only hold slices of any type. It can't be used for itteration | 44 | // Data can only hold slices of any type. It can't be used for itteration |
32 | Data interface{} `json:"data"` | 45 | Data interface{} `json:"data"` |
33 | } | 46 | } |
34 | 47 | ||
35 | func NewJSONParams(lang LangMap, | 48 | func NewPayload(r *http.Request, table string) Payload { |
36 | fields []Field, | 49 | var pload Payload |
37 | id string, | ||
38 | correlations []CorrelationField) JSONParams { | ||
39 | 50 | ||
40 | var jp JSONParams | 51 | pload.Method = strings.ToLower(r.Method + " " + r.URL.Path) |
52 | pload.Params = make(map[string]string, 0) | ||
53 | pload.Lang = loadTranslations(allPayloads, table) | ||
54 | pload.Fields = loadFields(allPayloads, table) | ||
55 | pload.IdField = loadIdField(allPayloads, table) | ||
56 | pload.Correlations = loadCorrelations(allPayloads, table) | ||
41 | 57 | ||
42 | jp.Lang = lang | 58 | return pload |
43 | jp.Fields = fields | 59 | } |
44 | jp.IdField = id | ||
45 | jp.Correlations = correlations | ||
46 | 60 | ||
47 | return jp | 61 | func DeliverPayload(w http.ResponseWriter, payload Payload) { |
62 | json.NewEncoder(w).Encode(payload) | ||
63 | payload.Data = nil | ||
48 | } | 64 | } |
49 | 65 | ||
50 | func NewJSONPayload(r *http.Request, table string) JSONPayload { | 66 | func loadTranslations(payloads []Payload, id string) []Translation { |
51 | var obj JSONPayload | 67 | translations := make([]Translation, 0) |
52 | params := loadTable(table) | 68 | |
53 | obj.Method = strings.ToLower(r.Method + " " + r.URL.Path) | 69 | for _, pload := range payloads { |
54 | obj.Params = make(map[string]string, 0) | 70 | if pload.Type == id { |
55 | obj.Lang = make(map[string]map[string]string, 0) | 71 | for _, t := range pload.Lang { |
56 | obj.Fields = make([]Field, 0) | 72 | //translations[t.Language] = t.FieldsLabels |
57 | obj.IdField = params.IdField | 73 | translations = append(translations, Translation{ |
58 | obj.Correlations = params.Correlations | 74 | Language: t.Language, |
59 | 75 | FieldsLabels: t.FieldsLabels, | |
60 | for k, m := range params.Lang { | 76 | }) |
61 | obj.Lang[k] = m | 77 | } |
78 | } | ||
62 | } | 79 | } |
63 | for _, f := range params.Fields { | 80 | |
64 | obj.Fields = append(obj.Fields, f) | 81 | return translations |
82 | } | ||
83 | |||
84 | func loadFields(payloads []Payload, id string) []Field { | ||
85 | fields := make([]Field, 0) | ||
86 | |||
87 | for _, pload := range payloads { | ||
88 | if pload.Type == id{ | ||
89 | for _, f := range pload.Fields { | ||
90 | fields = append(fields, f) | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | return fields | ||
96 | } | ||
97 | |||
98 | func loadIdField(payloads []Payload, id string) string { | ||
99 | for _, pload := range payloads { | ||
100 | if pload.Type == id { | ||
101 | return pload.IdField | ||
102 | } | ||
103 | } | ||
104 | return "" | ||
105 | } | ||
106 | |||
107 | func loadCorrelations(payloads []Payload, id string) []CorrelationField { | ||
108 | resp := make([]CorrelationField, 0) | ||
109 | |||
110 | for _, pload := range payloads { | ||
111 | if pload.Type == id { | ||
112 | for _, f := range pload.Correlations { | ||
113 | resp = append(resp, f) | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | return resp | ||
119 | } | ||
120 | |||
121 | func InitTables(db *ora.Ses, project string) error { | ||
122 | jsonbuf, _ := fetchTablesConfig(db, EqualQuotes(project)) | ||
123 | json.Unmarshal(jsonbuf, &allPayloads) | ||
124 | if len(allPayloads) == 0 { | ||
125 | return errors.New("tables config is corrupt") | ||
126 | } | ||
127 | fmt.Printf("broj ucitanih tabela: %d\n", len(allPayloads)) | ||
128 | return nil | ||
129 | } | ||
130 | |||
131 | func fetchTablesConfig(db *ora.Ses, project string) ([]byte, error) { | ||
132 | stmt, err := db.Prep(`SELECT | ||
133 | JSON_CLOB | ||
134 | FROM TABLES_CONFIG | ||
135 | WHERE PROJEKAT` + project, ora.S) | ||
136 | defer stmt.Close() | ||
137 | |||
138 | if err != nil { | ||
139 | return nil, err | ||
140 | } | ||
141 | |||
142 | rset, err := stmt.Qry() | ||
143 | if err != nil { | ||
144 | return nil, err | ||
145 | } | ||
146 | |||
147 | bytes := make([]byte, 0) | ||
148 | if rset.Next() { | ||
149 | lob := rset.Row[0].(io.Reader) | ||
150 | bytes, err = ioutil.ReadAll(lob) | ||
151 | if err != nil { | ||
152 | fmt.Printf("mega error: %v\n", err) | ||
153 | } | ||
65 | } | 154 | } |
66 | 155 |
tables_utility.go
1 | package restutility | File was deleted | |
2 | |||
3 | import ( | ||
4 | "encoding/json" | ||
5 | "errors" | ||
6 | "gopkg.in/rana/ora.v3" | ||
7 | "io" | ||
8 | "io/ioutil" | ||
9 | "fmt" | ||
10 | ) | ||
11 | |||
12 | type TableConfig struct { | ||
13 | Tables []Table | ||
14 | } | ||
15 | |||
16 | type Table struct { | ||
17 | TableType string `json:"tableType"` | ||
18 | Translations []TableTranslation `json:"translations"` | ||
19 | TableFields []Field `json:"tableFields"` | ||
20 | Correlations []CorrelationField `json:"correlationFields"` | ||
21 | IdField string `json:"idField"` | ||
22 | } | ||
23 | |||
24 | type CorrelationField struct { | ||
25 | Result string `json:"result"` | ||
26 | Elements []string `json:"elements"` | ||
27 | Type string `json:"type"` | ||
28 | } | ||
29 | |||
30 | type TableTranslation struct { | ||
31 | Language string `json:"language"` | ||
32 | FieldsLabels map[string]string `json:"fieldsLabels"` | ||
33 | } | ||
34 | |||
35 | func (tl TableConfig) LoadTranslations(tableType string) LangMap { | ||
36 | translations := make(LangMap, 0) | ||
37 | |||
38 | for _, table := range tl.Tables { | ||
39 | if tableType == table.TableType { | ||
40 | for _, t := range table.Translations { | ||
41 | translations[t.Language] = t.FieldsLabels | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | return translations | ||
47 | } | ||
48 | |||
49 | func (tl TableConfig) LoadFields(tableType string) []Field { | ||
50 | fields := make([]Field, 0) | ||
51 | |||
52 | for _, table := range tl.Tables { | ||
53 | if tableType == table.TableType { | ||
54 | for _, f := range table.TableFields { | ||
55 | fields = append(fields, f) | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | return fields | ||
61 | } | ||
62 | |||
63 | func (tl TableConfig) LoadIdField(tableType string) string { | ||
64 | for _, table := range tl.Tables { | ||
65 | if tableType == table.TableType { | ||
66 | return table.IdField | ||
67 | } | ||
68 | } | ||
69 | return "" | ||
70 | } | ||
71 | |||
72 | func (tl TableConfig) LoadCorrelations(tableType string) []CorrelationField { | ||
73 | resp := make([]CorrelationField, 0) | ||
74 | |||
75 | for _, table := range tl.Tables { | ||
76 | if tableType == table.TableType { | ||
77 | for _, f := range table.Correlations { | ||
78 | resp = append(resp, f) | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return resp | ||
84 | } | ||
85 | |||
86 | var _tables TableConfig | ||
87 | var _prevProject string | ||
88 | |||
89 | func InitTables(db *ora.Ses, project string) error { | ||
90 | jsonbuf, _ := fetchTablesConfig(db, EqualQuotes(project)) | ||
91 | json.Unmarshal(jsonbuf, &_tables.Tables) | ||
92 | if len(_tables.Tables) == 0 { | ||
93 | return errors.New("tables config is corrupt") | ||
94 | } | ||
95 | return nil | ||
96 | } | ||
97 | |||
98 | func fetchTablesConfig(db *ora.Ses, project string) ([]byte, error) { | ||
99 | stmt, err := db.Prep(`SELECT | ||
100 | JSON_CLOB | ||
101 | FROM TABLES_CONFIG | ||
102 | WHERE PROJEKAT` + project, ora.S) | ||
103 | defer stmt.Close() | ||
104 | |||
105 | if err != nil { | ||
106 | return nil, err | ||
107 | } | ||
108 | |||
109 | rset, err := stmt.Qry() | ||
110 | if err != nil { | ||
111 | return nil, err | ||
112 | } | ||
113 | |||
114 | bytes := make([]byte, 0) | ||
115 | if rset.Next() { | ||
116 | lob := rset.Row[0].(io.Reader) | ||
117 | bytes, err = ioutil.ReadAll(lob) | ||
118 | if err != nil { | ||
119 | fmt.Printf("mega error: %v\n", err) | ||
120 | } | ||
121 | } | ||
122 | |||
123 | return bytes, nil | ||
124 | } | ||
125 | |||
126 | func loadTable(table string) JSONParams { | ||
127 | return NewJSONParams(_tables.LoadTranslations(table), | ||
128 | _tables.LoadFields(table), | ||
129 | _tables.LoadIdField(table), | ||
130 | _tables.LoadCorrelations(table)) | ||
131 | } | ||
132 | |||
133 | 1 | package restutility |