From 3f8e3c437433052f24b067ed433df8e83b98ec12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Tikvi=C4=87?= Date: Wed, 27 Jun 2018 09:15:42 +0200 Subject: [PATCH] minor changes --- auth.go | 26 +++--- list_config.go | 279 ++++++++++++++++++++++++++++++++++----------------------- middleware.go | 26 ++++-- 3 files changed, 197 insertions(+), 134 deletions(-) diff --git a/auth.go b/auth.go index 05bbb33..23ae118 100644 --- a/auth.go +++ b/auth.go @@ -135,39 +135,35 @@ func RefreshAuthToken(tok string) (TokenClaims, error) { return CreateAuthToken(claims.Username, Role{claims.Role, claims.RoleID}) } -// AuthCheck returns JWT claims and boolean result of a check if req contains any role from roles. -// It checks if role extracted from reqest's Authorization header (JWT claims) matches any of -// provided comma-separated roles in roles. If roles is empty string check is skipped, -// otherwise role is extracted from token claims and compared against roles. -// If roles is "*" the check is automatically validated. -func AuthCheck(req *http.Request, roles string) (*TokenClaims, bool) { - if roles == "" { - return nil, true - } - +func AuthCheck(req *http.Request, roles string) (*TokenClaims, error) { // validate token and check expiration date claims, err := GetTokenClaims(req) if err != nil { - return claims, false + return claims, err + } + + if roles == "" { + return claims, nil } + // check if token has expired if claims.ExpiresAt < (time.Now()).Unix() { - return claims, false + return claims, errors.New("token has expired") } if roles == "*" { - return claims, true + return claims, nil } parts := strings.Split(roles, ",") for i, _ := range parts { r := strings.Trim(parts[i], " ") if claims.Role == r { - return claims, true + return claims, nil } } - return claims, false + return claims, nil } // GetTokenClaims extracts JWT claims from Authorization header of req. diff --git a/list_config.go b/list_config.go index 941f1b9..f4fe809 100644 --- a/list_config.go +++ b/list_config.go @@ -49,6 +49,8 @@ type ListActions struct { Print bool `json:"print"` Graph bool `json:"graph"` LiveGraph bool `json:"liveGraph"` + SaveFile bool `json:"saveFile"` + ShowFile bool `json:"showFile"` } type ListNavNode struct { @@ -105,25 +107,24 @@ type ListConfig struct { // GetListConfig returns list configuration for the provided object type for the front-end application // or an error if it fails. func GetListConfig(db *sql.DB, objType string) (ListConfig, error) { - resp := newDefaultList(objType) - var err error - - err = setListParams(db, &resp, objType) - resp.Navigation, err = getListNavigation(db, objType) - resp.Actions, err = getListActions(db, objType) - resp.Filters, err = getListFilters(db, objType) - resp.Options, err = getListOptions(db, objType) - resp.Parent, err = getListParent(db, objType) - resp.Graphs, err = getListGraph(db, objType) - resp.Pivots, err = getListPivot(db, objType) - resp.Details, err = getListDetails(db, objType) - resp.LiveGraph, err = getListLiveGraph(db, objType) + list := NewListConfig(objType) + + err := list.setParams(db, objType) + err = list.SetNavigation(db, objType) + err = list.SetActions(db, objType) + err = list.SetFilters(db, objType) + err = list.SetOptions(db, objType) + err = list.SetParent(db, objType) + err = list.SetPivot(db, objType) + err = list.SetGraph(db, objType) + err = list.SetDetails(db, objType) + err = list.SetLiveGraph(db, objType) if err != nil { - return ListConfig{}, err + return list, err } - return resp, nil + return list, nil } // GetListConfigObjectIDField takes in database connection and an object type and it returns the @@ -152,7 +153,7 @@ func GetListConfigObjectIDField(db *sql.DB, otype string) string { } // newDefaultList returns default configuration for the provided object type. -func newDefaultList(objType string) ListConfig { +func NewListConfig(objType string) ListConfig { list := ListConfig{ ObjectType: objType, Title: objType, @@ -182,9 +183,12 @@ func newDefaultList(objType string) ListConfig { } // setListParams sets the default parameters of the provided configuration list for the provided object type. -func setListParams(db *sql.DB, list *ListConfig, objType string) error { +func (list *ListConfig) setParams(db *sql.DB, objType string) error { rows, err := db.Query(`SELECT - OBJECT_TYPE, TITLE, LAZY_LOAD, INLINE_EDIT + OBJECT_TYPE, + TITLE, + LAZY_LOAD, + INLINE_EDIT FROM LIST_CONFIG WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { @@ -211,17 +215,22 @@ func setListParams(db *sql.DB, list *ListConfig, objType string) error { return nil } -// getListNavigation returns list navigation node slice for the provided objectType. -func getListNavigation(db *sql.DB, listObjType string) ([]ListNavNode, error) { - resp := make([]ListNavNode, 0) +// ListNavigation returns list navigation node slice for the provided objectType. +func (list *ListConfig) SetNavigation(db *sql.DB, listObjType string) error { + list.Navigation = make([]ListNavNode, 0) rows, err := db.Query(`SELECT - a.OBJECT_TYPE, a.PARENT_OBJECT_TYPE, a.LABEL, a.ICON, a.PARENT_FILTER_FIELD, b.PARENT_ID_FIELD + a.OBJECT_TYPE, + a.PARENT_OBJECT_TYPE, + a.LABEL, + a.ICON, + a.PARENT_FILTER_FIELD, + b.PARENT_ID_FIELD FROM LIST_CONFIG_NAVIGATION b JOIN LIST_CONFIG_CHILD a ON b.PARENT_CHILD_ID = a.PARENT_CHILD_ID WHERE b.LIST_OBJECT_TYPE = ` + fmt.Sprintf("'%s'", listObjType) + ` ORDER BY b.RB ASC`) if err != nil { - return resp, err + return err } defer rows.Close() @@ -229,54 +238,63 @@ func getListNavigation(db *sql.DB, listObjType string) ([]ListNavNode, error) { for rows.Next() { rows.Scan(&node.ObjectType, &node.ParentObjectType, &node.LabelField, &node.Icon, &node.ParentFilterField, &node.ParentIDField) - resp = append(resp, node) + list.Navigation = append(list.Navigation, node) } if rows.Err() != nil { - return nil, rows.Err() + return rows.Err() } - return resp, nil + return nil } // getListActions returns list actions for the provided object type. -func getListActions(db *sql.DB, objType string) (ListActions, error) { - var resp ListActions +func (list *ListConfig) SetActions(db *sql.DB, objType string) error { rows, err := db.Query(`SELECT - ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE, ACTION_EXPORT, - ACTION_PRINT, ACTION_GRAPH, ACTION_LIVE_GRAPH + ACTION_CREATE, + ACTION_UPDATE, + ACTION_DELETE, + ACTION_EXPORT, + ACTION_PRINT, + ACTION_GRAPH, + ACTION_LIVE_GRAPH, + ACTION_SAVE_FILE, + ACTION_SHOW_FILE FROM LIST_CONFIG WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { - return ListActions{}, err + return err } defer rows.Close() - var create, update, delete, export, print, graph, liveGraph uint32 + var create, update, delete, export, print, graph, liveGraph, saveFile, showFile uint32 if rows.Next() { - rows.Scan(&create, &update, &delete, &export, &print, &graph, &liveGraph) - resp.Create = create != 0 - resp.Update = update != 0 - resp.Delete = delete != 0 - resp.Export = export != 0 - resp.Print = print != 0 - resp.Graph = graph != 0 - resp.LiveGraph = liveGraph != 0 + rows.Scan(&create, &update, &delete, &export, &print, &graph, &liveGraph, &saveFile, &showFile) + list.Actions.Create = create != 0 + list.Actions.Update = update != 0 + list.Actions.Delete = delete != 0 + list.Actions.Export = export != 0 + list.Actions.Print = print != 0 + list.Actions.Graph = graph != 0 + list.Actions.LiveGraph = liveGraph != 0 + list.Actions.SaveFile = saveFile != 0 + list.Actions.ShowFile = showFile != 0 } if rows.Err() != nil { - return ListActions{}, rows.Err() + return rows.Err() } - return resp, nil + + return nil } // getListFiters returns list filter slice for the provided object type. -func getListFilters(db *sql.DB, objType string) ([]ListFilter, error) { - resp := make([]ListFilter, 0) - filtersFields, err := getFilterFieldsAndPosition(db, objType) +func (list *ListConfig) SetFilters(db *sql.DB, objType string) error { + list.Filters = make([]ListFilter, 0) + filtersFields, err := list.GetFilterFieldsAndPosition(db, objType) if err != nil { - return nil, err + return err } for field, pos := range filtersFields { - filters, _ := getFiltersByFilterField(db, field) + filters, _ := list.GetFiltersByFilterField(db, field) for _, filter := range filters { var f ListFilter f.Position = pos @@ -286,25 +304,26 @@ func getListFilters(db *sql.DB, objType string) ([]ListFilter, error) { f.FiltersLabel = filter.Label f.FiltersType = filter.Type if filter.Type == "dropdown" { - f.DropdownConfig, err = getFilterDropdownConfig(db, field) + err := f.SetDropdownConfig(db, field) if err != nil { - return nil, err + return err } } - resp = append(resp, f) + list.Filters = append(list.Filters, f) } } - sortFilters(resp) + list.sortFilters() - return resp, nil + return nil } // getFilterFieldsAndPosition returns a map of filter fields and their respective position in the menu. -func getFilterFieldsAndPosition(db *sql.DB, objType string) (map[string]uint32, error) { +func (list *ListConfig) GetFilterFieldsAndPosition(db *sql.DB, objType string) (map[string]uint32, error) { filtersField := make(map[string]uint32, 0) rows, err := db.Query(`SELECT - FILTERS_FIELD, RB + FILTERS_FIELD, + RB FROM LIST_CONFIG_FILTERS WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { @@ -331,10 +350,12 @@ type _filter struct { } // getFiltersByFilterField returns filter slice for the provided filter field. -func getFiltersByFilterField(db *sql.DB, filtersField string) ([]_filter, error) { +func (list *ListConfig) GetFiltersByFilterField(db *sql.DB, filtersField string) ([]_filter, error) { resp := make([]_filter, 0) rows, err := db.Query(`SELECT - FILTERS_TYPE, FILTERS_LABEL, DEFAULT_VALUES + FILTERS_TYPE, + FILTERS_LABEL, + DEFAULT_VALUES FROM LIST_FILTERS_FIELD WHERE FILTERS_FIELD = ` + fmt.Sprintf("'%s'", filtersField)) if err != nil { @@ -354,152 +375,178 @@ func getFiltersByFilterField(db *sql.DB, filtersField string) ([]_filter, error) } // getFilterDropdownConfig returns dropdown menu for the provided filter field. -func getFilterDropdownConfig(db *sql.DB, filtersField string) (Dropdown, error) { +func (f *ListFilter) SetDropdownConfig(db *sql.DB, filtersField string) error { var resp Dropdown rows, err := db.Query(`SELECT - FILTERS_FIELD, OBJECT_TYPE, ID_FIELD, LABEL_FIELD + FILTERS_FIELD, + OBJECT_TYPE, + ID_FIELD, + LABEL_FIELD FROM LIST_DROPDOWN_FILTER WHERE FILTERS_FIELD = ` + fmt.Sprintf("'%s'", filtersField)) if err != nil { - return resp, err + return err } defer rows.Close() if rows.Next() { rows.Scan(&resp.FiltersField, &resp.ObjectType, &resp.IDField, &resp.LabelField) } if rows.Err() != nil { - return resp, rows.Err() + return rows.Err() } - return resp, nil + + f.DropdownConfig = resp + + return nil } // sortFilters bubble sorts provided filters slice by position field. -func sortFilters(filters []ListFilter) { +func (list *ListConfig) sortFilters() { done := false var temp ListFilter for !done { done = true - for i := 0; i < len(filters)-1; i++ { - if filters[i].Position > filters[i+1].Position { + for i := 0; i < len(list.Filters)-1; i++ { + if list.Filters[i].Position > list.Filters[i+1].Position { done = false - temp = filters[i] - filters[i] = filters[i+1] - filters[i+1] = temp + temp = list.Filters[i] + list.Filters[i] = list.Filters[i+1] + list.Filters[i+1] = temp } } } } // getListGraph return list graph slice for the provided object type. -func getListGraph(db *sql.DB, objType string) ([]ListGraph, error) { - resp := make([]ListGraph, 0) +func (list *ListConfig) SetGraph(db *sql.DB, objType string) error { + list.Graphs = make([]ListGraph, 0) rows, err := db.Query(`SELECT - OBJECT_TYPE, X_FIELD, Y_FIELD, GROUP_FIELD, LABEL + OBJECT_TYPE, + X_FIELD, + Y_FIELD, + GROUP_FIELD, + LABEL FROM LIST_GRAPHS WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { - return resp, err + return err } defer rows.Close() var lg ListGraph for rows.Next() { rows.Scan(&lg.ObjectType, &lg.X, &lg.Y, &lg.GroupField, &lg.Label) - resp = append(resp, lg) + list.Graphs = append(list.Graphs, lg) } if rows.Err() != nil { - return resp, rows.Err() + return rows.Err() } - return resp, nil + + return nil } // getListOptions returns list options for the provided object type. -func getListOptions(db *sql.DB, objType string) (ListOptions, error) { - var resp ListOptions +func (list *ListConfig) SetOptions(db *sql.DB, objType string) error { rows, err := db.Query(`SELECT - GLOBAL_FILTER, LOCAL_FILTER, REMOTE_FILTER, PAGINATION, - PAGE_SIZE, PIVOT, DETAIL, TOTAL + GLOBAL_FILTER, + LOCAL_FILTER, + REMOTE_FILTER, + PAGINATION, + PAGE_SIZE, + PIVOT, + DETAIL, + TOTAL FROM LIST_CONFIG WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { - return ListOptions{}, err + return err } defer rows.Close() + if rows.Next() { var gfilter, lfilters, rfilters, pagination, pageSize, pivot, detail, total uint32 rows.Scan(&gfilter, &lfilters, &rfilters, &pagination, &pageSize, &pivot, &detail, &total) - resp.GlobalFilter = gfilter != 0 - resp.LocalFilters = lfilters != 0 - resp.RemoteFilters = rfilters != 0 - resp.Pagination = pagination != 0 - resp.PageSize = pageSize - resp.Pivot = pivot != 0 - resp.Detail = detail != 0 - resp.Total = total != 0 + list.Options.GlobalFilter = gfilter != 0 + list.Options.LocalFilters = lfilters != 0 + list.Options.RemoteFilters = rfilters != 0 + list.Options.Pagination = pagination != 0 + list.Options.PageSize = pageSize + list.Options.Pivot = pivot != 0 + list.Options.Detail = detail != 0 + list.Options.Total = total != 0 } if rows.Err() != nil { - return ListOptions{}, rows.Err() + return rows.Err() } - return resp, nil + + return nil } // getListParent returns list parent node slice for the provided object type. -func getListParent(db *sql.DB, objType string) ([]ListParentNode, error) { - resp := make([]ListParentNode, 0) +func (list *ListConfig) SetParent(db *sql.DB, objType string) error { + list.Parent = make([]ListParentNode, 0) rows, err := db.Query(`SELECT - PARENT_OBJECT_TYPE, PARENT_LABEL_FIELD, PARENT_FILTER_FIELD + PARENT_OBJECT_TYPE, + PARENT_LABEL_FIELD, + PARENT_FILTER_FIELD FROM LIST_CONFIG_CHILD WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { - return resp, err + return err } defer rows.Close() var pnode ListParentNode for rows.Next() { rows.Scan(&pnode.ObjectType, &pnode.LabelField, &pnode.FilterField) - resp = append(resp, pnode) + list.Parent = append(list.Parent, pnode) } if rows.Err() != nil { - return nil, rows.Err() + return rows.Err() } - return resp, nil + return nil } // getListPivot list pivot slice for the provided object type. -func getListPivot(db *sql.DB, objType string) ([]ListPivot, error) { - resp := make([]ListPivot, 0) +func (list *ListConfig) SetPivot(db *sql.DB, objType string) error { + list.Pivots = make([]ListPivot, 0) rows, err := db.Query(`SELECT - OBJECT_TYPE, GROUP_FIELD, DISTINCT_FIELD, VALUE_FIELD + OBJECT_TYPE, + GROUP_FIELD, + DISTINCT_FIELD, + VALUE_FIELD FROM LIST_PIVOTS WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { - return resp, err + return err } defer rows.Close() var p ListPivot for rows.Next() { rows.Scan(&p.ObjectType, &p.GroupField, &p.DistinctField, &p.Value) - resp = append(resp, p) + list.Pivots = append(list.Pivots, p) } if rows.Err() != nil { - return nil, rows.Err() + return rows.Err() } - return resp, nil + return nil } // getListDetails returns list details for the provided object type. -func getListDetails(db *sql.DB, objType string) (ListDetails, error) { +func (list *ListConfig) SetDetails(db *sql.DB, objType string) error { var resp ListDetails rows, err := db.Query(`SELECT - OBJECT_TYPE, PARENT_OBJECT_TYPE, PARENT_FILTER_FIELD, SINGLE_DETAIL + OBJECT_TYPE, + PARENT_OBJECT_TYPE, + PARENT_FILTER_FIELD, + SINGLE_DETAIL FROM LIST_CONFIG_DETAIL WHERE PARENT_OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { - return resp, err + return err } defer rows.Close() if rows.Next() { @@ -508,29 +555,35 @@ func getListDetails(db *sql.DB, objType string) (ListDetails, error) { resp.SingleDetail = singleDetail != 0 } if rows.Err() != nil { - return resp, rows.Err() + return rows.Err() } - return resp, nil + list.Details = resp + + return nil } // getListLiveGraph returns live graph for the provided object type. -func getListLiveGraph(db *sql.DB, objType string) (ListLiveGraph, error) { +func (list *ListConfig) SetLiveGraph(db *sql.DB, objType string) error { var resp ListLiveGraph rows, err := db.Query(`SELECT - OBJECT_TYPE, VALUE_FIELDS, LABEL_FIELDS + OBJECT_TYPE, + VALUE_FIELDS, + LABEL_FIELDS FROM LIST_LIVE_GRAPH WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) if err != nil { - return resp, err + return err } defer rows.Close() if rows.Next() { rows.Scan(&resp.ObjectType, &resp.ValueFields, &resp.LabelFields) } if rows.Err() != nil { - return resp, rows.Err() + return rows.Err() } - return resp, nil + list.LiveGraph = resp + + return nil } diff --git a/middleware.go b/middleware.go index 1ba932f..f4f09d6 100644 --- a/middleware.go +++ b/middleware.go @@ -28,6 +28,17 @@ func ParseForm(h http.HandlerFunc) http.HandlerFunc { } } +func ParseMultipartForm(h http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + err := req.ParseMultipartForm(32 << 20) + if err != nil { + BadRequest(w, req, err.Error()) + return + } + h(w, req) + } +} + var trafficLogger *gologger.Logger func EnableLogging(log string) error { @@ -38,22 +49,25 @@ func EnableLogging(log string) error { func Log(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { + t1 := time.Now() + in := trafficLogger.RequestLog(req, "") - w2 := WrapWithStatusRecorder(w) - t1 := time.Now() - h(w2, req) + wRec := WrapWithStatusRecorder(w) + h(wRec, req) + t2 := time.Now() - out := trafficLogger.ResponseLog(w2.Status(), t2.Sub(t1)) + out := trafficLogger.ResponseLog(wRec.Status(), t2.Sub(t1), 0) + trafficLogger.LogHTTPTraffic(in, out) } } func Auth(roles string, h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { - if _, ok := AuthCheck(req, roles); !ok { - Unauthorized(w, req, "") + if _, err := AuthCheck(req, roles); err != nil { + Unauthorized(w, req, err.Error()) return } h(w, req) -- 1.8.1.2