Commit ecec68b180e9b45dbd74f8a2f423a94e0b174b27

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

updated todo list

Showing 3 changed files with 4 additions and 2 deletions   Show diff stats
1 TODO: 1 TODO:
2 * list config 2 * http utility:
3 1. add parameters to the ProcessHeaders to enable/disable token/role-access-rights checks
3 4
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 //// 61 ////
62 //// HANDLER FUNC WRAPPER 62 //// HANDLER FUNC WRAPPER
63 //// 63 ////
64 64
65 //TODO: Add parameters to enable/disable token and roles authorization checks
65 // Sets common headers and checks for token validity. 66 // Sets common headers and checks for token validity.
66 func ProcessHeaders(fn http.HandlerFunc) http.HandlerFunc { 67 func ProcessHeaders(fn http.HandlerFunc) http.HandlerFunc {
67 return func(w http.ResponseWriter, req *http.Request) { 68 return func(w http.ResponseWriter, req *http.Request) {
68 // @TODO: check Content-type header (must be application/json) 69 // @TODO: check Content-type header (must be application/json)
69 // ctype := w.Header.Get("Content-Type") 70 // ctype := w.Header.Get("Content-Type")
70 // if req.Method != "GET" && ctype != "application/json" { 71 // if req.Method != "GET" && ctype != "application/json" {
71 // replyWithHttpError(w, req, http.StatusBadRequest, 72 // replyWithHttpError(w, req, http.StatusBadRequest,
72 // "Not a supported content type: " + ctype) 73 // "Not a supported content type: " + ctype)
73 // } 74 // }
74 75
75 w.Header().Set("Access-Control-Allow-Origin", "*") 76 w.Header().Set("Access-Control-Allow-Origin", "*")
76 w.Header().Set("Access-Control-Allow-Methods", 77 w.Header().Set("Access-Control-Allow-Methods",
77 `POST, 78 `POST,
78 GET, 79 GET,
79 PUT, 80 PUT,
80 DELETE, 81 DELETE,
81 OPTIONS`) 82 OPTIONS`)
82 w.Header().Set("Access-Control-Allow-Headers", 83 w.Header().Set("Access-Control-Allow-Headers",
83 `Accept, 84 `Accept,
84 Content-Type, 85 Content-Type,
85 Content-Length, 86 Content-Length,
86 Accept-Encoding, 87 Accept-Encoding,
87 X-CSRF-Token, 88 X-CSRF-Token,
88 Authorization`) 89 Authorization`)
89 w.Header().Set("Content-Type", "application/json; charset=utf-8") 90 w.Header().Set("Content-Type", "application/json; charset=utf-8")
90 91
91 if req.Method == "OPTIONS" { 92 if req.Method == "OPTIONS" {
92 return 93 return
93 } 94 }
94 95
95 if req.URL.Path != _apiVersion + "/token/new" { 96 if req.URL.Path != _apiVersion + "/token/new" {
96 token := req.Header.Get("Authorization") 97 token := req.Header.Get("Authorization")
97 if _, err := ParseAPIToken(token); err != nil { 98 if _, err := ParseAPIToken(token); err != nil {
98 RespondWithHttpError(w, req, http.StatusUnauthorized, 99 RespondWithHttpError(w, req, http.StatusUnauthorized,
99 []HttpErrorDesc{ 100 []HttpErrorDesc{
100 {Lang: "en", Desc: "Unauthorized request."}, 101 {Lang: "en", Desc: "Unauthorized request."},
101 {Lang: "rs", Desc: "Neautorizovani zahtev."}, 102 {Lang: "rs", Desc: "Neautorizovani zahtev."},
102 }) 103 })
103 return 104 return
104 } 105 }
105 } 106 }
106 107
107 err := req.ParseForm() 108 err := req.ParseForm()
108 if err != nil { 109 if err != nil {
109 RespondWithHttpError(w, req, http.StatusBadRequest, 110 RespondWithHttpError(w, req, http.StatusBadRequest,
110 []HttpErrorDesc{ 111 []HttpErrorDesc{
111 {Lang: "en", Desc: templateHttpErr400_EN}, 112 {Lang: "en", Desc: templateHttpErr400_EN},
112 {Lang: "rs", Desc: templateHttpErr400_RS}, 113 {Lang: "rs", Desc: templateHttpErr400_RS},
113 }) 114 })
114 return 115 return
115 } 116 }
116 fn(w, req) 117 fn(w, req)
117 } 118 }
118 } 119 }
119 120
120 //// 121 ////
121 //// NOT FOUND HANDLER 122 //// NOT FOUND HANDLER
122 //// 123 ////
123 124
124 func NotFoundHandler(w http.ResponseWriter, req *http.Request) { 125 func NotFoundHandler(w http.ResponseWriter, req *http.Request) {
125 RespondWithHttpError(w, req, http.StatusNotFound, []HttpErrorDesc{ 126 RespondWithHttpError(w, req, http.StatusNotFound, []HttpErrorDesc{
126 {Lang: "en", Desc: "Not found."}, 127 {Lang: "en", Desc: "Not found."},
127 {Lang: "rs", Desc: "Traženi resurs ne postoji."}, 128 {Lang: "rs", Desc: "Traženi resurs ne postoji."},
128 }) 129 })
129 } 130 }
130 131
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" 6 "encoding/json"
7 "errors" 7 "errors"
8 "gopkg.in/rana/ora.v3" 8 "gopkg.in/rana/ora.v3"
9 "io" 9 "io"
10 "io/ioutil" 10 "io/ioutil"
11 "fmt" 11 "fmt"
12 ) 12 )
13 13
14 var allPayloads []Payload 14 var allPayloads []Payload
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 Payload struct { 36 type Payload 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 // 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
45 Data interface{} `json:"data"` 45 Data interface{} `json:"data"`
46 } 46 }
47 47
48 func NewPayload(r *http.Request, table string) Payload { 48 func NewPayload(r *http.Request, table string) Payload {
49 var pload Payload 49 var pload Payload
50 50
51 pload.Method = strings.ToLower(r.Method + " " + r.URL.Path) 51 pload.Method = strings.ToLower(r.Method + " " + r.URL.Path)
52 pload.Params = make(map[string]string, 0) 52 pload.Params = make(map[string]string, 0)
53 pload.Lang = loadTranslations(allPayloads, table) 53 pload.Lang = loadTranslations(allPayloads, table)
54 pload.Fields = loadFields(allPayloads, table) 54 pload.Fields = loadFields(allPayloads, table)
55 pload.IdField = loadIdField(allPayloads, table) 55 pload.IdField = loadIdField(allPayloads, table)
56 pload.Correlations = loadCorrelations(allPayloads, table) 56 pload.Correlations = loadCorrelations(allPayloads, table)
57 57
58 return pload 58 return pload
59 } 59 }
60 60
61 func DeliverPayload(w http.ResponseWriter, payload Payload) { 61 func DeliverPayload(w http.ResponseWriter, payload Payload) {
62 json.NewEncoder(w).Encode(payload) 62 json.NewEncoder(w).Encode(payload)
63 payload.Data = nil 63 payload.Data = nil
64 } 64 }
65 65
66 func loadTranslations(payloads []Payload, id string) []Translation { 66 func loadTranslations(payloads []Payload, id string) []Translation {
67 translations := make([]Translation, 0) 67 translations := make([]Translation, 0)
68 68
69 for _, pload := range payloads { 69 for _, pload := range payloads {
70 if pload.Type == id { 70 if pload.Type == id {
71 for _, t := range pload.Lang { 71 for _, t := range pload.Lang {
72 //translations[t.Language] = t.FieldsLabels 72 //translations[t.Language] = t.FieldsLabels
73 translations = append(translations, Translation{ 73 translations = append(translations, Translation{
74 Language: t.Language, 74 Language: t.Language,
75 FieldsLabels: t.FieldsLabels, 75 FieldsLabels: t.FieldsLabels,
76 }) 76 })
77 } 77 }
78 } 78 }
79 } 79 }
80 80
81 return translations 81 return translations
82 } 82 }
83 83
84 func loadFields(payloads []Payload, id string) []Field { 84 func loadFields(payloads []Payload, id string) []Field {
85 fields := make([]Field, 0) 85 fields := make([]Field, 0)
86 86
87 for _, pload := range payloads { 87 for _, pload := range payloads {
88 if pload.Type == id{ 88 if pload.Type == id{
89 for _, f := range pload.Fields { 89 for _, f := range pload.Fields {
90 fields = append(fields, f) 90 fields = append(fields, f)
91 } 91 }
92 } 92 }
93 } 93 }
94 94
95 return fields 95 return fields
96 } 96 }
97 97
98 func loadIdField(payloads []Payload, id string) string { 98 func loadIdField(payloads []Payload, id string) string {
99 for _, pload := range payloads { 99 for _, pload := range payloads {
100 if pload.Type == id { 100 if pload.Type == id {
101 return pload.IdField 101 return pload.IdField
102 } 102 }
103 } 103 }
104 return "" 104 return ""
105 } 105 }
106 106
107 func loadCorrelations(payloads []Payload, id string) []CorrelationField { 107 func loadCorrelations(payloads []Payload, id string) []CorrelationField {
108 resp := make([]CorrelationField, 0) 108 resp := make([]CorrelationField, 0)
109 109
110 for _, pload := range payloads { 110 for _, pload := range payloads {
111 if pload.Type == id { 111 if pload.Type == id {
112 for _, f := range pload.Correlations { 112 for _, f := range pload.Correlations {
113 resp = append(resp, f) 113 resp = append(resp, f)
114 } 114 }
115 } 115 }
116 } 116 }
117 117
118 return resp 118 return resp
119 } 119 }
120 120
121 func InitTables(db *ora.Ses, project string) error { 121 func InitTables(db *ora.Ses, project string) error {
122 jsonbuf, _ := fetchTablesConfig(db, EqualQuotes(project)) 122 jsonbuf, _ := fetchTablesConfig(db, EqualQuotes(project))
123 json.Unmarshal(jsonbuf, &allPayloads) 123 json.Unmarshal(jsonbuf, &allPayloads)
124 if len(allPayloads) == 0 { 124 if len(allPayloads) == 0 {
125 return errors.New("tables config is corrupt") 125 return errors.New("tables config is corrupt")
126 } 126 }
127 fmt.Printf("broj ucitanih tabela: %d\n", len(allPayloads)) 127 fmt.Printf("broj ucitanih tabela: %d\n", len(allPayloads))
128 return nil 128 return nil
129 } 129 }
130 130
131 func fetchTablesConfig(db *ora.Ses, project string) ([]byte, error) { 131 func fetchTablesConfig(db *ora.Ses, project string) ([]byte, error) {
132 stmt, err := db.Prep(`SELECT 132 stmt, err := db.Prep(`SELECT
133 JSON_CLOB 133 JSON_CLOB
134 FROM TABLES_CONFIG 134 FROM TABLES_CONFIG
135 WHERE PROJEKAT` + project, ora.S) 135 WHERE PROJEKAT` + project, ora.S)
136 defer stmt.Close() 136 defer stmt.Close()
137 137
138 if err != nil { 138 if err != nil {
139 return nil, err 139 return nil, err
140 } 140 }
141 141
142 rset, err := stmt.Qry() 142 rset, err := stmt.Qry()
143 if err != nil { 143 if err != nil {
144 return nil, err 144 return nil, err
145 } 145 }
146 146
147 bytes := make([]byte, 0) 147 bytes := make([]byte, 0)
148 if rset.Next() { 148 if rset.Next() {
149 lob := rset.Row[0].(io.Reader) 149 lob := rset.Row[0].(io.Reader)
150 bytes, err = ioutil.ReadAll(lob) 150 bytes, err = ioutil.ReadAll(lob)
151 if err != nil { 151 if err != nil {
152 fmt.Printf("mega error: %v\n", err) 152 fmt.Printf("mega error: %v\n", err)
153 } 153 }
154 } 154 }
155 155
156 return bytes, nil 156 return bytes, nil
157 } 157 }
158 158
159 159