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