Commit 4a51e54d7e426f07551271cb1a96f69a991992c8

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

simplified

Showing 2 changed files with 49 additions and 30 deletions   Show diff stats
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
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